@docx4j/core-ts 0.4.0 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +5 -2
- package/dist/html/convert.mjs +38 -14
- package/dist/model/content/Body.d.mts +13 -1
- package/dist/model/content/Body.mjs +90 -19
- package/dist/model/content/Comment.mjs +7 -0
- package/dist/model/content/InlinePicture.d.mts +71 -7
- package/dist/model/content/InlinePicture.mjs +201 -28
- package/dist/model/content/List.mjs +10 -1
- package/dist/model/content/Paragraph.d.mts +28 -5
- package/dist/model/content/Paragraph.mjs +77 -37
- package/dist/model/content/Range.d.mts +18 -2
- package/dist/model/content/Range.mjs +194 -64
- package/dist/model/content/TrackedChange.d.mts +129 -3
- package/dist/model/content/TrackedChange.mjs +577 -12
- package/dist/model/content/binder.d.mts +2 -1
- package/dist/model/content/binder.mjs +48 -1
- package/dist/model/content/index.d.mts +2 -2
- package/dist/model/content/index.mjs +1 -1
- package/dist/model/content/relationships.d.mts +30 -0
- package/dist/model/content/relationships.mjs +133 -0
- package/dist/model/content/tree.d.mts +52 -2
- package/dist/model/content/tree.mjs +48 -3
- package/dist/model/customxml/pictures.d.mts +5 -2
- package/dist/model/customxml/pictures.mjs +13 -7
- package/dist/model/fonts/families.generated.mjs +2 -2
- package/dist/model/fonts/registry.mjs +7 -1
- package/dist/model/fonts/substitutions.generated.mjs +2 -2
- package/dist/model/fonts/themes.generated.mjs +1 -1
- package/dist/model/listnumbering/definitions.mjs +18 -0
- package/dist/model/properties/PropertyResolver.d.mts +27 -6
- package/dist/model/properties/PropertyResolver.mjs +83 -16
- package/dist/model/properties/catalogue.d.mts +15 -1
- package/dist/model/properties/catalogue.mjs +80 -27
- package/dist/model/properties/table.d.mts +16 -2
- package/dist/model/properties/table.mjs +13 -3
- package/dist/opc/Load.d.mts +9 -2
- package/dist/opc/index.d.mts +2 -2
- package/dist/opc/index.mjs +2 -2
- package/dist/opc/mce/preprocessor.d.mts +62 -6
- package/dist/opc/mce/preprocessor.mjs +142 -35
- package/dist/opc/mce/understood.d.mts +10 -0
- package/dist/opc/mce/understood.mjs +25 -3
- package/dist/packages/OpcPackage.d.mts +7 -0
- package/dist/packages/OpcPackage.mjs +15 -3
- package/dist/packages/WordprocessingMLPackage.d.mts +35 -2
- package/dist/packages/WordprocessingMLPackage.mjs +98 -2
- package/dist/parts/XmlPart.d.mts +26 -5
- package/dist/parts/XmlPart.mjs +67 -18
- package/package.json +2 -2
|
@@ -4,7 +4,9 @@ import { ContentTypes, IMAGE_CONTENT_TYPES_BY_EXTENSION } from '../../opc/Conten
|
|
|
4
4
|
import { base64Decode, base64Encode, decodeXmlText } from '../../xml/dom.mjs';
|
|
5
5
|
import { ImagePart } from '../../parts/BinaryPart.mjs';
|
|
6
6
|
import { PartName } from '../../opc/PartName.mjs';
|
|
7
|
-
import { find, runOf } from './tree.mjs';
|
|
7
|
+
import { find, runOf, linkParents, revisionKindOf, isElement, typeNameOf, isAlternateContent, selectedBranchOf } from './tree.mjs';
|
|
8
|
+
import { copyRPr } from './tracking.mjs';
|
|
9
|
+
import { relationshipIdsIn, queueRelationshipRemovals } from './relationships.mjs';
|
|
8
10
|
/** English Metric Units per inch, and per twip (docx4j UnitsOfMeasurement). */
|
|
9
11
|
const EMU_PER_INCH = 914400;
|
|
10
12
|
const EMU_PER_TWIP = 635;
|
|
@@ -248,6 +250,57 @@ export function writableWidthEmu(container) {
|
|
|
248
250
|
const twips = pgSz.w - left - right;
|
|
249
251
|
return twips > 0 ? twips * EMU_PER_TWIP : undefined;
|
|
250
252
|
}
|
|
253
|
+
/** The TYPE_NAME of `asvg:svgBlip`, Office 2016's SVG picture extension of an `a:blip`. */
|
|
254
|
+
const SVG_BLIP = 'org_docx4j_com_microsoft_schemas_office_drawing_x2016_SVG_main.CTSVGBlip';
|
|
255
|
+
/** The `a:ext` URI that `asvg:svgBlip` stands under, and its namespace. */
|
|
256
|
+
const SVG_BLIP_EXT_URI = '{96DAC541-7B7A-43D3-8B79-37D633B846F1}';
|
|
257
|
+
const SVG_NS = 'http://schemas.microsoft.com/office/drawing/2016/SVG/main';
|
|
258
|
+
/** The `asvg:svgBlip` in a blip's `a:extLst`, if any: an SVG picture's SVG (CR-002 section 52). */
|
|
259
|
+
export function svgBlipOf(blip) {
|
|
260
|
+
var _a, _b;
|
|
261
|
+
for (const ext of (_b = (_a = blip === null || blip === void 0 ? void 0 : blip.extLst) === null || _a === void 0 ? void 0 : _a.ext) !== null && _b !== void 0 ? _b : []) {
|
|
262
|
+
const any = ext.any;
|
|
263
|
+
if (isElement(any) && typeNameOf(any) === SVG_BLIP)
|
|
264
|
+
return any.value;
|
|
265
|
+
}
|
|
266
|
+
return undefined;
|
|
267
|
+
}
|
|
268
|
+
/**
|
|
269
|
+
* Points a blip at a new image the way Word's own picture binding does (test/README.md checks 46 and
|
|
270
|
+
* 47; CR-002 section 52). The blip's effects and other extensions stay.
|
|
271
|
+
* - A raster image goes in `r:embed`, and an `asvg:svgBlip` is taken away. Left in place, Word would go
|
|
272
|
+
* on drawing its old SVG, and would replace the new image with a PNG of that SVG when it saves.
|
|
273
|
+
* - An SVG goes under the `asvg:svgBlip`, and `r:embed` is taken away. Word puts a PNG of the SVG it
|
|
274
|
+
* makes itself in `r:embed`, which this package cannot make, and Word 365 draws the SVG without one.
|
|
275
|
+
* `r:link` is left as it was.
|
|
276
|
+
*/
|
|
277
|
+
export function setBlipImage(blip, relId, svg) {
|
|
278
|
+
var _a, _b;
|
|
279
|
+
if (!svg) {
|
|
280
|
+
blip.embed = relId;
|
|
281
|
+
const list = blip.extLst;
|
|
282
|
+
if (list === null || list === void 0 ? void 0 : list.ext) {
|
|
283
|
+
list.ext = list.ext.filter((ext) => !(isElement(ext.any) && typeNameOf(ext.any) === SVG_BLIP));
|
|
284
|
+
if (list.ext.length === 0)
|
|
285
|
+
delete blip.extLst;
|
|
286
|
+
}
|
|
287
|
+
return;
|
|
288
|
+
}
|
|
289
|
+
delete blip.embed;
|
|
290
|
+
const existing = svgBlipOf(blip);
|
|
291
|
+
if (existing) {
|
|
292
|
+
existing.embed = relId;
|
|
293
|
+
return;
|
|
294
|
+
}
|
|
295
|
+
const list = ((_a = blip.extLst) !== null && _a !== void 0 ? _a : (blip.extLst = { TYPE_NAME: 'org_docx4j_dml.CTOfficeArtExtensionList', ext: [] }));
|
|
296
|
+
const ext = {
|
|
297
|
+
TYPE_NAME: 'org_docx4j_dml.CTOfficeArtExtension',
|
|
298
|
+
uri: SVG_BLIP_EXT_URI,
|
|
299
|
+
any: { name: { namespaceURI: SVG_NS, localPart: 'svgBlip' }, value: { TYPE_NAME: SVG_BLIP, embed: relId } },
|
|
300
|
+
};
|
|
301
|
+
((_b = list.ext) !== null && _b !== void 0 ? _b : (list.ext = [])).push(ext);
|
|
302
|
+
linkParents(list, blip);
|
|
303
|
+
}
|
|
251
304
|
const FORMAT_BY_CONTENT_TYPE = {
|
|
252
305
|
[ContentTypes.IMAGE_PNG]: 'Png', [ContentTypes.IMAGE_X_PNG]: 'Png', [ContentTypes.IMAGE_JPEG]: 'Jpeg',
|
|
253
306
|
[ContentTypes.IMAGE_GIF]: 'Gif', [ContentTypes.IMAGE_BMP]: 'Bmp', [ContentTypes.IMAGE_TIFF]: 'Tiff',
|
|
@@ -255,18 +308,48 @@ const FORMAT_BY_CONTENT_TYPE = {
|
|
|
255
308
|
[ContentTypes.IMAGE_WMF]: 'Wmf',
|
|
256
309
|
};
|
|
257
310
|
/**
|
|
258
|
-
*
|
|
259
|
-
*
|
|
311
|
+
* The inline pictures a run's item holds: the item itself when it is a `w:drawing` whose `wp:inline`
|
|
312
|
+
* holds a `pic:pic`, and those in a kept `mc:AlternateContent`'s selected branch (`selectedBranchOf`,
|
|
313
|
+
* CR-010 phase 3). A drawing of anything else, such as a chart, a text box, a group or SmartArt, is no
|
|
314
|
+
* inline picture: Office JS lists none for an inline text box (CR-010 section 12.6, test/README.md
|
|
315
|
+
* check 42).
|
|
316
|
+
*/
|
|
317
|
+
export function picturesIn(item) {
|
|
318
|
+
var _a;
|
|
319
|
+
if (isAlternateContent(item)) {
|
|
320
|
+
return ((_a = selectedBranchOf(item.value)) !== null && _a !== void 0 ? _a : []).flatMap((child) => (isElement(child) ? picturesIn(child) : []));
|
|
321
|
+
}
|
|
322
|
+
return item.name.localPart === 'drawing' && holdsInlinePicture(item.value) ? [item] : [];
|
|
323
|
+
}
|
|
324
|
+
/** True for a drawing whose `wp:inline` holds a `pic:pic`. */
|
|
325
|
+
function holdsInlinePicture(drawing) {
|
|
326
|
+
var _a, _b, _c, _d;
|
|
327
|
+
const inline = (_a = drawing.anchorOrInline) === null || _a === void 0 ? void 0 : _a[0];
|
|
328
|
+
if (!inline || inline.TYPE_NAME !== 'org_docx4j_dml_wordprocessingDrawing.Inline')
|
|
329
|
+
return false;
|
|
330
|
+
const first = (_d = (_c = (_b = inline.graphic) === null || _b === void 0 ? void 0 : _b.graphicData) === null || _c === void 0 ? void 0 : _c.any) === null || _d === void 0 ? void 0 : _d[0];
|
|
331
|
+
return isElement(first) && typeNameOf(first) === 'org_docx4j_dml_picture.Pic';
|
|
332
|
+
}
|
|
333
|
+
/**
|
|
334
|
+
* A subset of Office JS `Word.InlinePicture` over a `w:drawing` holding a `wp:inline` with a `pic:pic`.
|
|
335
|
+
* A view: the drawing, the run it is in and the paragraph. Sizes are points, as Office JS reports them.
|
|
336
|
+
*
|
|
337
|
+
* A picture in a kept `mc:AlternateContent`'s selected branch has the element as its `holder`. Reads and
|
|
338
|
+
* the setters are the selected branch's drawing; `delete` removes the element whole, every branch with
|
|
339
|
+
* it (CR-010 phase 3).
|
|
260
340
|
*/
|
|
261
341
|
export class InlinePicture {
|
|
262
342
|
constructor(
|
|
263
343
|
/** The `w:drawing` element pair. */
|
|
264
344
|
element,
|
|
265
345
|
/** The run holding the drawing, and the array holding the run. */
|
|
266
|
-
run, paragraph
|
|
346
|
+
run, paragraph,
|
|
347
|
+
/** The run's item the drawing stands in, where that is not the drawing: a kept `mc:AlternateContent`. */
|
|
348
|
+
holder) {
|
|
267
349
|
this.element = element;
|
|
268
350
|
this.run = run;
|
|
269
351
|
this.paragraph = paragraph;
|
|
352
|
+
this.holder = holder;
|
|
270
353
|
}
|
|
271
354
|
/** The wp:inline; a floating picture (wp:anchor) is not an InlinePicture, and throws. */
|
|
272
355
|
get inline() {
|
|
@@ -309,20 +392,39 @@ export class InlinePicture {
|
|
|
309
392
|
set altTextTitle(text) {
|
|
310
393
|
this.inline.docPr.title = text;
|
|
311
394
|
}
|
|
312
|
-
/**
|
|
395
|
+
/**
|
|
396
|
+
* The kind of image, from the content type of the part `getBase64` reads: `Svg` for an SVG picture
|
|
397
|
+
* (`svgImagePart`), else the `a:blip`'s part's. Office JS gives `null` for an SVG picture, though its
|
|
398
|
+
* typings declare the property non-null and `Word.ImageFormat` has `Svg` (test/README.md check 45);
|
|
399
|
+
* this package gives `Svg`, a departure (CR-002 section 52).
|
|
400
|
+
*/
|
|
313
401
|
get imageFormat() {
|
|
314
|
-
var _a;
|
|
315
|
-
const part = this.imagePart();
|
|
316
|
-
return (
|
|
402
|
+
var _a, _b;
|
|
403
|
+
const part = (_a = this.svgImagePart()) !== null && _a !== void 0 ? _a : this.imagePart();
|
|
404
|
+
return (_b = (part && FORMAT_BY_CONTENT_TYPE[part.contentType])) !== null && _b !== void 0 ? _b : 'Unsupported';
|
|
317
405
|
}
|
|
318
406
|
/** The relationship id of the embedded image (r:embed), if any (extension). */
|
|
319
407
|
get relId() {
|
|
320
408
|
var _a, _b;
|
|
321
409
|
return (_b = (_a = this.pic()) === null || _a === void 0 ? void 0 : _a.blipFill.blip) === null || _b === void 0 ? void 0 : _b.embed;
|
|
322
410
|
}
|
|
323
|
-
/**
|
|
411
|
+
/**
|
|
412
|
+
* The relationship id of the SVG the picture embeds beside its image, if any (extension): the
|
|
413
|
+
* `r:embed` of an `asvg:svgBlip` in the `a:blip`'s `a:extLst`, as Office 2016 and later write an SVG
|
|
414
|
+
* picture, with the `a:blip`'s own image a PNG of it for readers that don't understand SVG.
|
|
415
|
+
*/
|
|
416
|
+
get svgRelId() {
|
|
417
|
+
var _a, _b;
|
|
418
|
+
const embed = (_b = svgBlipOf((_a = this.pic()) === null || _a === void 0 ? void 0 : _a.blipFill.blip)) === null || _b === void 0 ? void 0 : _b.embed;
|
|
419
|
+
return embed === undefined || embed === '' ? undefined : embed;
|
|
420
|
+
}
|
|
421
|
+
/**
|
|
422
|
+
* The image's bytes as base64 (Office JS getBase64ImageSrc). For an SVG picture, the SVG
|
|
423
|
+
* (`svgImagePart`), as Office JS gives it (test/README.md check 43); else the `a:blip`'s image.
|
|
424
|
+
*/
|
|
324
425
|
async getBase64() {
|
|
325
|
-
|
|
426
|
+
var _a;
|
|
427
|
+
const part = (_a = this.svgImagePart()) !== null && _a !== void 0 ? _a : this.imagePart();
|
|
326
428
|
if (!part)
|
|
327
429
|
throw new Docx4JException('This picture has no image part (a linked or missing image)');
|
|
328
430
|
return base64Encode(await part.getBytes());
|
|
@@ -331,29 +433,97 @@ export class InlinePicture {
|
|
|
331
433
|
getBase64ImageSrc() {
|
|
332
434
|
return this.getBase64();
|
|
333
435
|
}
|
|
334
|
-
/** The image part this picture embeds (extension). */
|
|
436
|
+
/** The image part this picture embeds: the `a:blip`'s, which is an SVG picture's PNG (extension). */
|
|
335
437
|
imagePart() {
|
|
438
|
+
return this.partFor(this.relId);
|
|
439
|
+
}
|
|
440
|
+
/** The SVG part an SVG picture embeds beside its image (`svgRelId`), if any (extension). */
|
|
441
|
+
svgImagePart() {
|
|
442
|
+
return this.partFor(this.svgRelId);
|
|
443
|
+
}
|
|
444
|
+
partFor(relId) {
|
|
336
445
|
var _a;
|
|
337
|
-
const relId = this.relId;
|
|
338
446
|
const source = this.paragraph.parentBody.part;
|
|
339
447
|
if (!relId || !source)
|
|
340
448
|
return undefined;
|
|
341
449
|
const part = (_a = source.relationshipsPart) === null || _a === void 0 ? void 0 : _a.getPart(relId);
|
|
342
450
|
return part instanceof ImagePart ? part : undefined;
|
|
343
451
|
}
|
|
344
|
-
/**
|
|
452
|
+
/**
|
|
453
|
+
* Removes the picture; the run goes too when the picture was all it held. A picture in a kept
|
|
454
|
+
* `mc:AlternateContent` takes the element with it, every branch (`holder`).
|
|
455
|
+
*
|
|
456
|
+
* While the package tracks changes it is marked deleted instead: its run goes into a `w:del`, and
|
|
457
|
+
* when the run held more than the picture, the picture is first given a run of its own with the
|
|
458
|
+
* same properties, so the deletion holds it alone. Accepting the deletion then takes it, and its
|
|
459
|
+
* image part with it (CR-002 section 46). A picture its author inserted under tracking is taken
|
|
460
|
+
* back, as `Paragraph.delete` takes back its own text, and one inside a deletion is refused.
|
|
461
|
+
*
|
|
462
|
+
* A picture removed outright (tracking off, or taken back) queues its image relationship on the
|
|
463
|
+
* package. On save the relationship goes if nothing then references it, and the image part with it
|
|
464
|
+
* when nothing else targets it. Waiting for the save lets a picture cut and pasted back keep its
|
|
465
|
+
* image.
|
|
466
|
+
*/
|
|
345
467
|
delete() {
|
|
346
|
-
var _a;
|
|
468
|
+
var _a, _b;
|
|
469
|
+
const place = placeOf(this.paragraph.p, this.run);
|
|
470
|
+
if (!place)
|
|
471
|
+
return;
|
|
472
|
+
const revision = place.revision;
|
|
473
|
+
const tracker = this.paragraph.changeTracker;
|
|
474
|
+
if (tracker && ((revision === null || revision === void 0 ? void 0 : revision.kind) === 'del' || (revision === null || revision === void 0 ? void 0 : revision.kind) === 'moveFrom')) {
|
|
475
|
+
throw new Docx4JException(`This picture is inside a w:${revision.kind} (deleted by ${revision.value.author}); reject the deletion first`);
|
|
476
|
+
}
|
|
477
|
+
if (tracker && !tracker.ownInsertion(revision)) {
|
|
478
|
+
this.markDeleted(tracker, place);
|
|
479
|
+
return;
|
|
480
|
+
}
|
|
481
|
+
const item = (_a = this.holder) !== null && _a !== void 0 ? _a : this.element;
|
|
347
482
|
const content = this.run.value.content;
|
|
348
|
-
const at = (
|
|
483
|
+
const at = (_b = content === null || content === void 0 ? void 0 : content.indexOf(item)) !== null && _b !== void 0 ? _b : -1;
|
|
349
484
|
if (content && at >= 0)
|
|
350
485
|
content.splice(at, 1);
|
|
351
486
|
if (!content || content.length === 0) {
|
|
352
|
-
const
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
487
|
+
const i = place.items.indexOf(this.run);
|
|
488
|
+
if (i >= 0)
|
|
489
|
+
place.items.splice(i, 1);
|
|
490
|
+
if (revision && revision.items.length === 0) { // an insertion left empty goes with it
|
|
491
|
+
const j = revision.owner.indexOf(revision.element);
|
|
492
|
+
if (j >= 0)
|
|
493
|
+
revision.owner.splice(j, 1);
|
|
494
|
+
}
|
|
495
|
+
}
|
|
496
|
+
const ids = new Set();
|
|
497
|
+
relationshipIdsIn(item, ids);
|
|
498
|
+
const pkg = this.paragraph.parentBody.package_;
|
|
499
|
+
queueRelationshipRemovals(pkg === null || pkg === void 0 ? void 0 : pkg.pendingRelationshipRemovals, this.paragraph.parentBody.part, ids);
|
|
500
|
+
}
|
|
501
|
+
/** The picture's run in a `w:del`, the picture split into a run of its own when the run held more. */
|
|
502
|
+
markDeleted(tracker, place) {
|
|
503
|
+
var _a, _b;
|
|
504
|
+
const run = this.run;
|
|
505
|
+
const at = place.items.indexOf(run);
|
|
506
|
+
const content = ((_a = run.value.content) !== null && _a !== void 0 ? _a : []);
|
|
507
|
+
const item = (_b = this.holder) !== null && _b !== void 0 ? _b : this.element;
|
|
508
|
+
const i = content.indexOf(item);
|
|
509
|
+
if (at < 0 || i < 0)
|
|
510
|
+
return;
|
|
511
|
+
const before = content.slice(0, i);
|
|
512
|
+
const after = content.slice(i + 1);
|
|
513
|
+
const pieces = [];
|
|
514
|
+
let alone = run;
|
|
515
|
+
if (before.length > 0 || after.length > 0) {
|
|
516
|
+
alone = runOf([item], copyRPr(run.value.rPr));
|
|
517
|
+
if (before.length > 0) {
|
|
518
|
+
run.value.content = before;
|
|
519
|
+
pieces.push(run);
|
|
520
|
+
}
|
|
356
521
|
}
|
|
522
|
+
pieces.push(tracker.del([alone]));
|
|
523
|
+
if (after.length > 0)
|
|
524
|
+
pieces.push(runOf(after, copyRPr(run.value.rPr)));
|
|
525
|
+
place.items.splice(at, 1, ...pieces);
|
|
526
|
+
linkParents(pieces, place.parent);
|
|
357
527
|
}
|
|
358
528
|
pic() {
|
|
359
529
|
const any = this.inline.graphic.graphicData.any;
|
|
@@ -375,24 +545,27 @@ export class InlinePicture {
|
|
|
375
545
|
}
|
|
376
546
|
}
|
|
377
547
|
}
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
var _a, _b, _c;
|
|
548
|
+
function placeOf(p, run) {
|
|
549
|
+
const seek = (items, parent, revision) => {
|
|
550
|
+
var _a, _b, _c, _d;
|
|
382
551
|
if (!items)
|
|
383
552
|
return undefined;
|
|
384
553
|
if (items.includes(run))
|
|
385
|
-
return items;
|
|
554
|
+
return revision ? { items, parent, revision } : { items, parent };
|
|
386
555
|
for (const item of items) {
|
|
387
556
|
const v = item.value;
|
|
388
557
|
if (typeof v !== 'object' || v === null)
|
|
389
558
|
continue;
|
|
390
|
-
const
|
|
391
|
-
|
|
392
|
-
|
|
559
|
+
const holder = (_a = v.sdtContent) !== null && _a !== void 0 ? _a : v;
|
|
560
|
+
const nested = (_c = (_b = v.content) !== null && _b !== void 0 ? _b : v.customXmlOrSmartTagOrSdt) !== null && _c !== void 0 ? _c : (_d = v.sdtContent) === null || _d === void 0 ? void 0 : _d.content;
|
|
561
|
+
const kind = revisionKindOf(item);
|
|
562
|
+
const inner = kind && nested ? { kind, element: item, value: v, items: nested, owner: items } : revision;
|
|
563
|
+
const found = seek(nested, holder, inner);
|
|
564
|
+
if (found)
|
|
565
|
+
return found;
|
|
393
566
|
}
|
|
394
567
|
return undefined;
|
|
395
568
|
};
|
|
396
|
-
return seek(p.content);
|
|
569
|
+
return seek(p.content, p, undefined);
|
|
397
570
|
}
|
|
398
571
|
export { IMAGE_CONTENT_TYPES_BY_EXTENSION };
|
|
@@ -5,7 +5,7 @@ import { Docx4JException } from '../../opc/exceptions.mjs';
|
|
|
5
5
|
import { DEFAULT_NUMBERING_XML } from '../../parts/wml/defaultNumbering.mjs';
|
|
6
6
|
import { NumberingState, storyKindOf } from '../listnumbering/state.mjs';
|
|
7
7
|
import { LEVELS } from '../listnumbering/definitions.mjs';
|
|
8
|
-
import { isElement, linkParents } from './tree.mjs';
|
|
8
|
+
import { isElement, linkParents, selectedBranchOf, ALTERNATE_CONTENT } from './tree.mjs';
|
|
9
9
|
import { Font } from './Font.mjs';
|
|
10
10
|
function packageOf(body) {
|
|
11
11
|
const pkg = body.package_;
|
|
@@ -60,6 +60,9 @@ function numRefOf(paragraph) {
|
|
|
60
60
|
* counts in. `test/parity.test.mjs`'s `walkNumbering`, which is the harness's own walk: a text
|
|
61
61
|
* box's paragraphs stay in this story's list (they are in the part, in document order) but
|
|
62
62
|
* count in a story of their own, which is docx4j's rule (CR-014 probe P7).
|
|
63
|
+
*
|
|
64
|
+
* A kept `mc:AlternateContent` is walked through its selected branch alone (`selectedBranchOf`,
|
|
65
|
+
* docx4j's `McMode.READ`), so a text box held in both branches counts once (CR-010 phase 3).
|
|
63
66
|
*/
|
|
64
67
|
function walkStory(root, state, emit) {
|
|
65
68
|
const walk = (value, current) => {
|
|
@@ -70,11 +73,17 @@ function walkStory(root, state, emit) {
|
|
|
70
73
|
}
|
|
71
74
|
if (typeof value !== 'object' || value === null)
|
|
72
75
|
return;
|
|
76
|
+
if (typeof value.nodeType === 'number')
|
|
77
|
+
return; // DOM the model does not type
|
|
73
78
|
if (isElement(value)) {
|
|
74
79
|
walk(value.value, current);
|
|
75
80
|
return;
|
|
76
81
|
}
|
|
77
82
|
const node = value;
|
|
83
|
+
if (node.TYPE_NAME === ALTERNATE_CONTENT) {
|
|
84
|
+
walk(selectedBranchOf(node), current);
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
78
87
|
let inner = current;
|
|
79
88
|
if (node.TYPE_NAME === 'org_docx4j_wml.P')
|
|
80
89
|
emit(node, current);
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type * as wml from '@docx4j/generated-objects-ts/modules/org_docx4j_wml';
|
|
2
2
|
import type { CellContext } from '../properties/table.mjs';
|
|
3
|
-
import { type Element, W_NS, type TextSegment, type TextViewOptions } from './tree.mjs';
|
|
3
|
+
import { type Element, W_NS, type SpanEdges, type SegmentOptions, type TextSegment, type TextViewOptions } from './tree.mjs';
|
|
4
4
|
import { Font, type FontTracking } from './Font.mjs';
|
|
5
5
|
import { Range } from './Range.mjs';
|
|
6
6
|
import { type SearchOptions } from './search.mjs';
|
|
@@ -160,7 +160,12 @@ export declare class Paragraph {
|
|
|
160
160
|
get parentTableCell(): TableCell | undefined;
|
|
161
161
|
/** The run-level content controls in this paragraph, in order, nested ones included. */
|
|
162
162
|
get contentControls(): ContentControl[];
|
|
163
|
-
/**
|
|
163
|
+
/**
|
|
164
|
+
* The inline pictures in this paragraph, in order (Office JS Paragraph.inlinePictures): each
|
|
165
|
+
* `w:drawing` whose `wp:inline` holds a `pic:pic`, in a run or in the selected branch of a kept
|
|
166
|
+
* `mc:AlternateContent` (`picturesIn`). An inline chart, text box or group is not one (CR-010
|
|
167
|
+
* section 12.6).
|
|
168
|
+
*/
|
|
164
169
|
get inlinePictures(): InlinePicture[];
|
|
165
170
|
/** Text inserted at the start, the end, or replacing the whole paragraph's text. */
|
|
166
171
|
insertText(text: string, location: 'Start' | 'End' | 'Replace'): Range;
|
|
@@ -198,6 +203,10 @@ export declare class Paragraph {
|
|
|
198
203
|
replaceText(find: string, replace: string, options?: SearchOptions): number;
|
|
199
204
|
/** The tracked changes in this paragraph, in document order (CR-002 phase F). */
|
|
200
205
|
getTrackedChanges(): TrackedChange[];
|
|
206
|
+
/**
|
|
207
|
+
* The paragraph's range: 'Whole' and 'Content' hold its whole content, the pictures at its start and
|
|
208
|
+
* end among them, so deleting it deletes them (CR-002 section 48); 'Start' and 'End' are collapsed.
|
|
209
|
+
*/
|
|
201
210
|
getRange(location?: 'Whole' | 'Start' | 'End' | 'Content'): Range;
|
|
202
211
|
/**
|
|
203
212
|
* Removes the paragraph from its container. While the package tracks changes, the content
|
|
@@ -214,6 +223,12 @@ export declare class Paragraph {
|
|
|
214
223
|
* Does nothing when the mark is already deleted.
|
|
215
224
|
*/
|
|
216
225
|
markDeletedInPlace(tracker: ChangeTracker): void;
|
|
226
|
+
/**
|
|
227
|
+
* Queues the relationships that content removed outright referenced (a picture's image, a link's
|
|
228
|
+
* target), to be settled when the package is saved: each goes then if nothing references it, and
|
|
229
|
+
* its part with it when nothing else targets that (CR-002 sections 47 and 48).
|
|
230
|
+
*/
|
|
231
|
+
releaseRelationships(removed: unknown): void;
|
|
217
232
|
/** The paragraph as XML (extension; Office JS getOoxml wraps it in a package). */
|
|
218
233
|
getXml(): Promise<string>;
|
|
219
234
|
/** docx4j: the P's content list. */
|
|
@@ -253,15 +268,19 @@ export declare class Paragraph {
|
|
|
253
268
|
get changeTracker(): ChangeTracker | undefined;
|
|
254
269
|
/** What `Font` needs to write `w:rPrChange`: the tracker, and the runs that are our own insertion (`Range` shares it). */
|
|
255
270
|
fontTracking(): FontTracking | undefined;
|
|
256
|
-
/** The text segments (w:t, w:tab, ...) with their offsets. */
|
|
257
|
-
segments(options?:
|
|
271
|
+
/** The text segments (w:t, w:tab, ...) with their offsets; `{ objects: true }` adds the pictures. */
|
|
272
|
+
segments(options?: SegmentOptions): TextSegment[];
|
|
258
273
|
/**
|
|
259
274
|
* Replaces the text in [start, end) with `text` and returns the range of the inserted text.
|
|
260
275
|
* Runs are edited in place: a w:t loses or gains characters, a tab or break inside the range
|
|
261
276
|
* is removed, a run left empty is removed. Text is inserted into the w:t at `start`,
|
|
262
277
|
* else into a new run with the formatting of the nearest run.
|
|
278
|
+
*
|
|
279
|
+
* The pictures in the span go with its text: those strictly inside it, and those at an edge `edges`
|
|
280
|
+
* says the span holds (`WHOLE` for a paragraph's whole content), so a span of no text can still
|
|
281
|
+
* delete a picture (CR-002 section 48).
|
|
263
282
|
*/
|
|
264
|
-
splice(start: number, end: number, text: string, prefer?: 'before' | 'after'): Range;
|
|
283
|
+
splice(start: number, end: number, text: string, prefer?: 'before' | 'after', edges?: SpanEdges): Range;
|
|
265
284
|
/**
|
|
266
285
|
* Inserts run-level items (runs, hyperlinks, content controls) at a text offset, splitting the
|
|
267
286
|
* run there when the offset falls inside one. PARENT is linked on what is inserted.
|
|
@@ -317,6 +336,8 @@ export declare class Paragraph {
|
|
|
317
336
|
* The text in [start, end) becomes a deletion: the runs holding it are isolated, their `w:t`
|
|
318
337
|
* turned into `w:delText`, and each run of consecutive ones moved into one `w:del`. Text this
|
|
319
338
|
* author had inserted is simply removed, as Word does, rather than nested in a `w:del`.
|
|
339
|
+
* The pictures in the span (`splice`'s `edges`) are deleted with the text, each in a run of its own
|
|
340
|
+
* where its run held more, as `InlinePicture.delete` gives it one (CR-002 section 48).
|
|
320
341
|
* Returns the `w:del` elements it made, in document order.
|
|
321
342
|
*/
|
|
322
343
|
private deleteText;
|
|
@@ -365,6 +386,8 @@ export declare class Paragraph {
|
|
|
365
386
|
* Splits runs so that every run holding text in [start, end) holds nothing else, and returns
|
|
366
387
|
* the segments inside the span. `splitAt` does the `w:t` boundaries; this also moves the items
|
|
367
388
|
* of a run that straddles a boundary (a tab, a break, a drawing) out into runs of their own.
|
|
389
|
+
* The pictures in the span (`splice`'s `edges`) are among the segments returned, and a run
|
|
390
|
+
* holding one holds nothing outside the span either.
|
|
368
391
|
*/
|
|
369
392
|
private isolate;
|
|
370
393
|
/** Moves the items before `seg` into a run of their own, in front of `seg`'s run. */
|