@docx4j/core-ts 0.1.4 → 0.1.5
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/List.d.mts +69 -1
- package/dist/model/content/List.mjs +98 -19
- package/dist/model/content/Range.d.mts +22 -0
- package/dist/model/content/Range.mjs +117 -0
- package/dist/model/content/index.d.mts +1 -1
- package/dist/model/content/index.mjs +1 -1
- package/dist/office-js/supported.generated.mjs +1 -0
- package/dist/packages/WordprocessingMLPackage.d.mts +9 -0
- package/dist/packages/WordprocessingMLPackage.mjs +11 -0
- package/package.json +1 -1
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type * as wml from '@docx4j/generated-objects-ts/modules/org_docx4j_wml';
|
|
2
|
-
import type { ListDefinition, LevelDefinition } from '../listnumbering/definitions.mjs';
|
|
2
|
+
import type { NumberingDefinitions, ListDefinition, LevelDefinition } from '../listnumbering/definitions.mjs';
|
|
3
3
|
import type { Emulator } from '../listnumbering/Emulator.mjs';
|
|
4
4
|
import { Font } from './Font.mjs';
|
|
5
5
|
import type { Body } from './Body.mjs';
|
|
@@ -31,6 +31,38 @@ export interface ListLabel {
|
|
|
31
31
|
/** Whether the level's `w:numFmt` is `bullet`. */
|
|
32
32
|
isBullet: boolean;
|
|
33
33
|
}
|
|
34
|
+
/**
|
|
35
|
+
* The content API must not import `WordprocessingMLPackage` or `parts/wml` at runtime (that
|
|
36
|
+
* would be a cycle, since `parts/wml` builds the `Body` views), so the numbering part is
|
|
37
|
+
* reached by shape, as `Body.propertyResolver` and `fonts/lookup` are.
|
|
38
|
+
*/
|
|
39
|
+
interface NumberingPartLike {
|
|
40
|
+
readonly isUnmarshalled: boolean;
|
|
41
|
+
readonly contents: wml.Numbering;
|
|
42
|
+
readonly definitions: NumberingDefinitions;
|
|
43
|
+
getEmulator(reset?: boolean): Emulator;
|
|
44
|
+
makeLive(): wml.Numbering;
|
|
45
|
+
getContents(): Promise<wml.Numbering>;
|
|
46
|
+
}
|
|
47
|
+
/** As much of an `XmlPart` as the story walk reads. */
|
|
48
|
+
interface StoryPartLike {
|
|
49
|
+
readonly contentType: string;
|
|
50
|
+
readonly isUnmarshalled: boolean;
|
|
51
|
+
readonly contents: unknown;
|
|
52
|
+
}
|
|
53
|
+
/** As much of a `MainDocumentPart` as the list views use. */
|
|
54
|
+
interface MainPartLike {
|
|
55
|
+
numberingDefinitionsPart?: NumberingPartLike;
|
|
56
|
+
readonly headerParts: StoryPartLike[];
|
|
57
|
+
readonly footerParts: StoryPartLike[];
|
|
58
|
+
addTargetPart(part: unknown): unknown;
|
|
59
|
+
}
|
|
60
|
+
/** As much of a `WordprocessingMLPackage` as the list views use. */
|
|
61
|
+
interface ListPackageLike {
|
|
62
|
+
getMainDocumentPart(): MainPartLike;
|
|
63
|
+
refreshPropertyResolver(): void;
|
|
64
|
+
refresh(): Promise<unknown>;
|
|
65
|
+
}
|
|
34
66
|
/**
|
|
35
67
|
* The package's numbering emulator, or undefined where the document has no lists (or nothing
|
|
36
68
|
* has read the numbering part: `await pkg.getBody()` builds the resolver, which reads it).
|
|
@@ -251,3 +283,39 @@ export declare function detachFromList(paragraph: Paragraph): void;
|
|
|
251
283
|
* be unmarshalled, and a document with no numbering part gets one here (CR-002 section 17).
|
|
252
284
|
*/
|
|
253
285
|
export declare function startNewList(paragraph: Paragraph, options?: StartListOptions): Promise<List>;
|
|
286
|
+
/**
|
|
287
|
+
* The document's list definitions, as verbs that need no paragraph (CR-002 section 19, at the
|
|
288
|
+
* editor's request): `pkg.numbering`.
|
|
289
|
+
*
|
|
290
|
+
* `Paragraph.startNewList()` and `List.restart()` are Office JS's shapes and stay as they are,
|
|
291
|
+
* but both build a definition first and touch a paragraph only at the end. An editor that keeps
|
|
292
|
+
* its own document model has the numbering part and a `w:numId` to write, and nothing else - and
|
|
293
|
+
* going through a paragraph would mean projecting a tree, running the verb and projecting back,
|
|
294
|
+
* a whole-body round trip for what is otherwise one attribute. So the definition half is here.
|
|
295
|
+
*/
|
|
296
|
+
export declare class NumberingFacade {
|
|
297
|
+
private readonly pkg;
|
|
298
|
+
constructor(pkg: ListPackageLike);
|
|
299
|
+
/**
|
|
300
|
+
* A new list definition, and its `w:numId` as a string for a `w:numPr` to name. The numbering
|
|
301
|
+
* part is created with docx4j's default definitions where the document has none, and an
|
|
302
|
+
* existing one is unmarshalled so that what is written to it is saved.
|
|
303
|
+
*
|
|
304
|
+
* Asynchronous for the same reasons `startNewList` is: the default definitions are XML to be
|
|
305
|
+
* unmarshalled, and the part may have to be created. Nothing is attached to anything; the
|
|
306
|
+
* caller writes `w:numPr` itself.
|
|
307
|
+
*/
|
|
308
|
+
newList(options?: {
|
|
309
|
+
bullet?: boolean;
|
|
310
|
+
}): Promise<string>;
|
|
311
|
+
/**
|
|
312
|
+
* A `w:num` that numbers as `numId` does but starts again, and its own `w:numId`:
|
|
313
|
+
* `List.restart()` without needing a `Body`. The counters are shared by abstract definition,
|
|
314
|
+
* so restarting means a new `w:num` with a `w:startOverride`, spent on its first use in a
|
|
315
|
+
* story (CR-001 section 15.2).
|
|
316
|
+
*
|
|
317
|
+
* Synchronous, so the numbering part must have been read: `await pkg.getPropertyResolver()`,
|
|
318
|
+
* `newList()` or any list read does it.
|
|
319
|
+
*/
|
|
320
|
+
restart(numId: string | number): string;
|
|
321
|
+
}
|
|
@@ -398,22 +398,10 @@ export class List {
|
|
|
398
398
|
* Extension name (Office JS has no restart verb); `Paragraph.restartList()` is the sugar.
|
|
399
399
|
*/
|
|
400
400
|
restart() {
|
|
401
|
-
var _a, _b
|
|
402
|
-
const
|
|
403
|
-
const num = this.element;
|
|
404
|
-
const start = (_b = (_a = this.level(0)) === null || _a === void 0 ? void 0 : _a.start) !== null && _b !== void 0 ? _b : 1;
|
|
405
|
-
const created = f.createNumberingNum({
|
|
406
|
-
numId: nextNumId(numbering),
|
|
407
|
-
abstractNumId: f.createNumberingNumAbstractNumId({ val: num.abstractNumId.val }),
|
|
408
|
-
lvlOverride: [f.createNumberingNumLvlOverride({
|
|
409
|
-
ilvl: 0,
|
|
410
|
-
startOverride: f.createNumberingNumLvlOverrideStartOverride({ val: start }),
|
|
411
|
-
})],
|
|
412
|
-
});
|
|
413
|
-
((_c = numbering.num) !== null && _c !== void 0 ? _c : (numbering.num = [])).push(created);
|
|
414
|
-
linkParents(created, numbering);
|
|
401
|
+
var _a, _b;
|
|
402
|
+
const numId = addRestartedNum(this.live(), this.element.abstractNumId.val, (_b = (_a = this.level(0)) === null || _a === void 0 ? void 0 : _a.start) !== null && _b !== void 0 ? _b : 1);
|
|
415
403
|
this.written();
|
|
416
|
-
return new List(String(
|
|
404
|
+
return new List(String(numId), this.body);
|
|
417
405
|
}
|
|
418
406
|
/**
|
|
419
407
|
* Gives this list a `w:abstractNum` of its own where another `w:num` shares the one it names
|
|
@@ -668,12 +656,24 @@ export function detachFromList(paragraph) {
|
|
|
668
656
|
* be unmarshalled, and a document with no numbering part gets one here (CR-002 section 17).
|
|
669
657
|
*/
|
|
670
658
|
export async function startNewList(paragraph, options) {
|
|
671
|
-
var _a, _b
|
|
659
|
+
var _a, _b;
|
|
672
660
|
const body = paragraph.parentBody;
|
|
673
661
|
const part = await ensureNumberingPart(body);
|
|
662
|
+
const numId = await addListDefinition(part, (options === null || options === void 0 ? void 0 : options.bullet) === true);
|
|
663
|
+
(_a = packageOf(body)) === null || _a === void 0 ? void 0 : _a.refreshPropertyResolver();
|
|
664
|
+
return attachToList(paragraph, numId, (_b = options === null || options === void 0 ? void 0 : options.level) !== null && _b !== void 0 ? _b : 0);
|
|
665
|
+
}
|
|
666
|
+
/**
|
|
667
|
+
* A `w:abstractNum` copied from docx4j's default definitions (its `numbering.xml` resource:
|
|
668
|
+
* `w:abstractNum` 1 is Word's decimal set and 0 its bullet set) and a `w:num` naming it; the new
|
|
669
|
+
* `w:numId`. The paragraph half of `startNewList` is separate because it is separable: nothing
|
|
670
|
+
* about building a list definition needs one.
|
|
671
|
+
*/
|
|
672
|
+
async function addListDefinition(part, bullet) {
|
|
673
|
+
var _a, _b, _c;
|
|
674
674
|
const numbering = await part.getContents();
|
|
675
675
|
const defaults = await defaultNumbering();
|
|
676
|
-
const template = ((_a = defaults.abstractNum) !== null && _a !== void 0 ? _a : [])[
|
|
676
|
+
const template = ((_a = defaults.abstractNum) !== null && _a !== void 0 ? _a : [])[bullet ? 0 : 1];
|
|
677
677
|
if (template === undefined)
|
|
678
678
|
throw new Docx4JException('The default numbering definitions are missing an abstractNum');
|
|
679
679
|
const abstract = deepCopy(template);
|
|
@@ -689,8 +689,27 @@ export async function startNewList(paragraph, options) {
|
|
|
689
689
|
});
|
|
690
690
|
((_c = numbering.num) !== null && _c !== void 0 ? _c : (numbering.num = [])).push(num);
|
|
691
691
|
linkParents(num, numbering);
|
|
692
|
-
|
|
693
|
-
|
|
692
|
+
return num.numId;
|
|
693
|
+
}
|
|
694
|
+
/**
|
|
695
|
+
* A `w:num` naming the same `w:abstractNum` as another, with a `w:startOverride` at level 0; the
|
|
696
|
+
* new `w:numId`. The counters are shared by abstract definition, so this is how Word restarts a
|
|
697
|
+
* list (CR-001 section 15.2), and it is what {@link List.restart} and
|
|
698
|
+
* {@link NumberingFacade.restart} both do.
|
|
699
|
+
*/
|
|
700
|
+
function addRestartedNum(numbering, abstractNumId, start) {
|
|
701
|
+
var _a;
|
|
702
|
+
const created = f.createNumberingNum({
|
|
703
|
+
numId: nextNumId(numbering),
|
|
704
|
+
abstractNumId: f.createNumberingNumAbstractNumId({ val: abstractNumId }),
|
|
705
|
+
lvlOverride: [f.createNumberingNumLvlOverride({
|
|
706
|
+
ilvl: 0,
|
|
707
|
+
startOverride: f.createNumberingNumLvlOverrideStartOverride({ val: start }),
|
|
708
|
+
})],
|
|
709
|
+
});
|
|
710
|
+
((_a = numbering.num) !== null && _a !== void 0 ? _a : (numbering.num = [])).push(created);
|
|
711
|
+
linkParents(created, numbering);
|
|
712
|
+
return created.numId;
|
|
694
713
|
}
|
|
695
714
|
/**
|
|
696
715
|
* The numbering part, created with docx4j's default numbering where the document has none
|
|
@@ -703,6 +722,14 @@ async function ensureNumberingPart(body) {
|
|
|
703
722
|
if (pkg === undefined || main === undefined) {
|
|
704
723
|
throw new Docx4JException('This body has no package, so a list cannot be added to it');
|
|
705
724
|
}
|
|
725
|
+
return ensureNumberingPartOf(pkg, main);
|
|
726
|
+
}
|
|
727
|
+
/**
|
|
728
|
+
* The same, reached from the package rather than from a body, which is what
|
|
729
|
+
* {@link NumberingFacade} uses: creating a list definition needs no paragraph and no body, and
|
|
730
|
+
* making one go through either costs a caller that holds neither (CR-002 section 19).
|
|
731
|
+
*/
|
|
732
|
+
async function ensureNumberingPartOf(pkg, main) {
|
|
706
733
|
const existing = main.numberingDefinitionsPart;
|
|
707
734
|
if (existing !== undefined) {
|
|
708
735
|
// the resolver read the part privately; unmarshalling it gives a second tree, so the
|
|
@@ -725,6 +752,58 @@ async function ensureNumberingPart(body) {
|
|
|
725
752
|
await pkg.refresh();
|
|
726
753
|
return created;
|
|
727
754
|
}
|
|
755
|
+
/**
|
|
756
|
+
* The document's list definitions, as verbs that need no paragraph (CR-002 section 19, at the
|
|
757
|
+
* editor's request): `pkg.numbering`.
|
|
758
|
+
*
|
|
759
|
+
* `Paragraph.startNewList()` and `List.restart()` are Office JS's shapes and stay as they are,
|
|
760
|
+
* but both build a definition first and touch a paragraph only at the end. An editor that keeps
|
|
761
|
+
* its own document model has the numbering part and a `w:numId` to write, and nothing else - and
|
|
762
|
+
* going through a paragraph would mean projecting a tree, running the verb and projecting back,
|
|
763
|
+
* a whole-body round trip for what is otherwise one attribute. So the definition half is here.
|
|
764
|
+
*/
|
|
765
|
+
export class NumberingFacade {
|
|
766
|
+
constructor(pkg) {
|
|
767
|
+
this.pkg = pkg;
|
|
768
|
+
}
|
|
769
|
+
/**
|
|
770
|
+
* A new list definition, and its `w:numId` as a string for a `w:numPr` to name. The numbering
|
|
771
|
+
* part is created with docx4j's default definitions where the document has none, and an
|
|
772
|
+
* existing one is unmarshalled so that what is written to it is saved.
|
|
773
|
+
*
|
|
774
|
+
* Asynchronous for the same reasons `startNewList` is: the default definitions are XML to be
|
|
775
|
+
* unmarshalled, and the part may have to be created. Nothing is attached to anything; the
|
|
776
|
+
* caller writes `w:numPr` itself.
|
|
777
|
+
*/
|
|
778
|
+
async newList(options) {
|
|
779
|
+
const main = this.pkg.getMainDocumentPart();
|
|
780
|
+
const part = await ensureNumberingPartOf(this.pkg, main);
|
|
781
|
+
const numId = await addListDefinition(part, (options === null || options === void 0 ? void 0 : options.bullet) === true);
|
|
782
|
+
this.pkg.refreshPropertyResolver();
|
|
783
|
+
return String(numId);
|
|
784
|
+
}
|
|
785
|
+
/**
|
|
786
|
+
* A `w:num` that numbers as `numId` does but starts again, and its own `w:numId`:
|
|
787
|
+
* `List.restart()` without needing a `Body`. The counters are shared by abstract definition,
|
|
788
|
+
* so restarting means a new `w:num` with a `w:startOverride`, spent on its first use in a
|
|
789
|
+
* story (CR-001 section 15.2).
|
|
790
|
+
*
|
|
791
|
+
* Synchronous, so the numbering part must have been read: `await pkg.getPropertyResolver()`,
|
|
792
|
+
* `newList()` or any list read does it.
|
|
793
|
+
*/
|
|
794
|
+
restart(numId) {
|
|
795
|
+
var _a, _b;
|
|
796
|
+
const part = this.pkg.getMainDocumentPart().numberingDefinitionsPart;
|
|
797
|
+
if (part === undefined)
|
|
798
|
+
throw new Docx4JException('This document has no numbering part, so there is no list to restart');
|
|
799
|
+
const definition = part.definitions.list(numId);
|
|
800
|
+
if (definition === undefined)
|
|
801
|
+
throw new ItemNotFound(`No w:num for numId ${numId}`);
|
|
802
|
+
const created = addRestartedNum(part.makeLive(), definition.num.abstractNumId.val, (_b = (_a = definition.level('0')) === null || _a === void 0 ? void 0 : _a.start) !== null && _b !== void 0 ? _b : 1);
|
|
803
|
+
this.pkg.refreshPropertyResolver();
|
|
804
|
+
return String(created);
|
|
805
|
+
}
|
|
806
|
+
}
|
|
728
807
|
// ----------------------------------------------------------------------------- the mechanics
|
|
729
808
|
const TWIPS_PER_POINT = 20;
|
|
730
809
|
/** Office JS `Word.ListNumbering` as `w:numFmt`. */
|
|
@@ -75,4 +75,26 @@ export declare class Range {
|
|
|
75
75
|
* span gets an empty control at its position. Returns the control.
|
|
76
76
|
*/
|
|
77
77
|
insertContentControl(kind?: ContentControlType): ContentControl;
|
|
78
|
+
/**
|
|
79
|
+
* Office JS `Range.hyperlink`: the address of the first hyperlink in this range, or a new
|
|
80
|
+
* hyperlink over it. `address#location` separates the address from an optional location within
|
|
81
|
+
* it, so `"#heading"` is a link inside this document (a `w:anchor`) and
|
|
82
|
+
* `"https://example.com"` an external one (a relationship). Reading gives `""` where the range
|
|
83
|
+
* is in no hyperlink.
|
|
84
|
+
*
|
|
85
|
+
* Setting removes the hyperlinks the range already carries and wraps its runs in one
|
|
86
|
+
* `w:hyperlink`, splitting runs at the boundaries as `font` and `insertContentControl` do;
|
|
87
|
+
* setting `""` removes them and wraps nothing. An external address becomes a relationship of
|
|
88
|
+
* this range's part, which is why the part must exist (CR-002 section 20).
|
|
89
|
+
*/
|
|
90
|
+
get hyperlink(): string;
|
|
91
|
+
set hyperlink(value: string);
|
|
92
|
+
/** The `w:hyperlink` this range's first run sits in, if any. */
|
|
93
|
+
private hyperlinkHolder;
|
|
94
|
+
/** Unwraps every `w:hyperlink` the range touches, keeping its runs where they are. */
|
|
95
|
+
private removeHyperlinks;
|
|
96
|
+
/** The target of a relationship of this range's part, for the getter. */
|
|
97
|
+
private relationshipTarget;
|
|
98
|
+
/** An external relationship of this range's part for the address, and its id. */
|
|
99
|
+
private addHyperlinkRelationship;
|
|
78
100
|
}
|
|
@@ -4,6 +4,8 @@ import { typeNameOf, linkParents, runItemsOf } from './tree.mjs';
|
|
|
4
4
|
import { Docx4JException } from '../../opc/exceptions.mjs';
|
|
5
5
|
import { ContentControl } from './ContentControl.mjs';
|
|
6
6
|
import { sdt as sdtOf, nextSdtId } from '@docx4j/generated-objects-ts/builders/wml';
|
|
7
|
+
import { hyperlink as hyperlinkOf } from '@docx4j/generated-objects-ts/el/org_docx4j_wml';
|
|
8
|
+
import { Namespaces } from '../../parts/Namespaces.mjs';
|
|
7
9
|
import { controlIdScope, sdtKindFor } from '../customxml/insert.mjs';
|
|
8
10
|
import { contentOf } from './ooxml.mjs';
|
|
9
11
|
import { searchPattern, findAll } from './search.mjs';
|
|
@@ -227,6 +229,121 @@ export class Range {
|
|
|
227
229
|
linkParents(sdt, (_a = segments[0].run.PARENT) !== null && _a !== void 0 ? _a : paragraph.p);
|
|
228
230
|
return new ContentControl(sdt, owner, body);
|
|
229
231
|
}
|
|
232
|
+
/**
|
|
233
|
+
* Office JS `Range.hyperlink`: the address of the first hyperlink in this range, or a new
|
|
234
|
+
* hyperlink over it. `address#location` separates the address from an optional location within
|
|
235
|
+
* it, so `"#heading"` is a link inside this document (a `w:anchor`) and
|
|
236
|
+
* `"https://example.com"` an external one (a relationship). Reading gives `""` where the range
|
|
237
|
+
* is in no hyperlink.
|
|
238
|
+
*
|
|
239
|
+
* Setting removes the hyperlinks the range already carries and wraps its runs in one
|
|
240
|
+
* `w:hyperlink`, splitting runs at the boundaries as `font` and `insertContentControl` do;
|
|
241
|
+
* setting `""` removes them and wraps nothing. An external address becomes a relationship of
|
|
242
|
+
* this range's part, which is why the part must exist (CR-002 section 20).
|
|
243
|
+
*/
|
|
244
|
+
get hyperlink() {
|
|
245
|
+
var _a;
|
|
246
|
+
const holder = this.hyperlinkHolder();
|
|
247
|
+
if (holder === undefined)
|
|
248
|
+
return '';
|
|
249
|
+
const anchor = (_a = holder.value.anchor) !== null && _a !== void 0 ? _a : '';
|
|
250
|
+
const address = holder.value.id === undefined ? '' : this.relationshipTarget(holder.value.id);
|
|
251
|
+
return anchor === '' ? address : `${address}#${anchor}`;
|
|
252
|
+
}
|
|
253
|
+
set hyperlink(value) {
|
|
254
|
+
var _a;
|
|
255
|
+
const paragraph = this.paragraph;
|
|
256
|
+
this.removeHyperlinks();
|
|
257
|
+
if (value === '')
|
|
258
|
+
return;
|
|
259
|
+
const hash = value.indexOf('#');
|
|
260
|
+
const address = hash === -1 ? value : value.slice(0, hash);
|
|
261
|
+
const location = hash === -1 ? '' : value.slice(hash + 1);
|
|
262
|
+
const holder = hyperlinkOf({ content: [] });
|
|
263
|
+
if (location !== '')
|
|
264
|
+
holder.value.anchor = location;
|
|
265
|
+
if (address !== '')
|
|
266
|
+
holder.value.id = this.addHyperlinkRelationship(address);
|
|
267
|
+
if (this.start === this.end) {
|
|
268
|
+
paragraph.insertItemsAt(this.start, [holder]);
|
|
269
|
+
return;
|
|
270
|
+
}
|
|
271
|
+
paragraph.splitAt(this.start);
|
|
272
|
+
paragraph.splitAt(this.end);
|
|
273
|
+
const segments = paragraph.segments().filter((seg) => seg.start >= this.start && seg.end <= this.end);
|
|
274
|
+
if (segments.length === 0)
|
|
275
|
+
throw new Docx4JException('This range covers no run');
|
|
276
|
+
const owner = segments[0].runOwner;
|
|
277
|
+
if (segments.some((seg) => seg.runOwner !== owner)) {
|
|
278
|
+
throw new Docx4JException('This range spans more than one run holder (a hyperlink or a tracked change); wrap a narrower span');
|
|
279
|
+
}
|
|
280
|
+
const items = [];
|
|
281
|
+
for (const segment of segments) {
|
|
282
|
+
const element = owner[segment.runIndex];
|
|
283
|
+
if (!items.includes(element))
|
|
284
|
+
items.push(element);
|
|
285
|
+
}
|
|
286
|
+
const at = owner.indexOf(items[0]);
|
|
287
|
+
holder.value.content = items;
|
|
288
|
+
owner.splice(at, items.length, holder);
|
|
289
|
+
linkParents(holder, (_a = segments[0].run.PARENT) !== null && _a !== void 0 ? _a : paragraph.p);
|
|
290
|
+
}
|
|
291
|
+
/** The `w:hyperlink` this range's first run sits in, if any. */
|
|
292
|
+
hyperlinkHolder() {
|
|
293
|
+
for (const segment of this.paragraph.segments()) {
|
|
294
|
+
if (segment.end <= this.start && this.start !== this.end)
|
|
295
|
+
continue;
|
|
296
|
+
if (segment.start >= this.end && this.start !== this.end)
|
|
297
|
+
break;
|
|
298
|
+
const parent = segment.run.PARENT;
|
|
299
|
+
const found = hyperlinkHolders(this.paragraph).find((h) => h.value === parent);
|
|
300
|
+
if (found)
|
|
301
|
+
return found;
|
|
302
|
+
}
|
|
303
|
+
return undefined;
|
|
304
|
+
}
|
|
305
|
+
/** Unwraps every `w:hyperlink` the range touches, keeping its runs where they are. */
|
|
306
|
+
removeHyperlinks() {
|
|
307
|
+
var _a, _b, _c;
|
|
308
|
+
for (const holder of hyperlinkHolders(this.paragraph)) {
|
|
309
|
+
const owner = containerOf(holder, this.paragraph);
|
|
310
|
+
const at = owner.indexOf(holder);
|
|
311
|
+
if (at === -1)
|
|
312
|
+
continue;
|
|
313
|
+
owner.splice(at, 1, ...((_a = holder.value.content) !== null && _a !== void 0 ? _a : []));
|
|
314
|
+
for (const item of ((_b = holder.value.content) !== null && _b !== void 0 ? _b : [])) {
|
|
315
|
+
linkParents(item, (_c = holder.PARENT) !== null && _c !== void 0 ? _c : this.paragraph.p);
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
/** The target of a relationship of this range's part, for the getter. */
|
|
320
|
+
relationshipTarget(id) {
|
|
321
|
+
var _a, _b, _c;
|
|
322
|
+
const part = this.paragraph.parentBody.part;
|
|
323
|
+
return (_c = (_b = (_a = part === null || part === void 0 ? void 0 : part.relationshipsPart) === null || _a === void 0 ? void 0 : _a.getRelationshipById(id)) === null || _b === void 0 ? void 0 : _b.target) !== null && _c !== void 0 ? _c : '';
|
|
324
|
+
}
|
|
325
|
+
/** An external relationship of this range's part for the address, and its id. */
|
|
326
|
+
addHyperlinkRelationship(address) {
|
|
327
|
+
const part = this.paragraph.parentBody.part;
|
|
328
|
+
if (!part)
|
|
329
|
+
throw new Docx4JException('This range has no part, so a hyperlink cannot be related to it');
|
|
330
|
+
return part.getRelationshipsPart(true).addExternalRelationship(Namespaces.HYPERLINK, address).id;
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
/** Every `w:hyperlink` of a paragraph, outermost first (they do not nest in practice). */
|
|
334
|
+
function hyperlinkHolders(paragraph) {
|
|
335
|
+
const out = [];
|
|
336
|
+
const visit = (items) => {
|
|
337
|
+
for (const item of items !== null && items !== void 0 ? items : []) {
|
|
338
|
+
if (typeNameOf(item) === 'org_docx4j_wml.P.Hyperlink')
|
|
339
|
+
out.push(item);
|
|
340
|
+
const value = item.value;
|
|
341
|
+
if (typeof value === 'object' && value !== null)
|
|
342
|
+
visit(runItemsOf(value));
|
|
343
|
+
}
|
|
344
|
+
};
|
|
345
|
+
visit(runItemsOf(paragraph.p));
|
|
346
|
+
return out;
|
|
230
347
|
}
|
|
231
348
|
/** The run-level array holding an element, after `insertItemsAt` put it somewhere in the paragraph. */
|
|
232
349
|
function containerOf(element, paragraph) {
|
|
@@ -3,7 +3,7 @@ export { Paragraph, type Alignment } from './Paragraph.mjs';
|
|
|
3
3
|
export { Range } from './Range.mjs';
|
|
4
4
|
export { BUILT_IN_STYLES, builtInOf, idOfBuiltIn, displayNameOf, styleNameOf, styleIdOf, type BuiltInStyle } from './styles.mjs';
|
|
5
5
|
export { Comment } from './Comment.mjs';
|
|
6
|
-
export { List, ListItem, ListItemNotFoundError, listsOf, listLabelsOf, numberingEmulatorOf, levelOf, type ListLevelType, type ListNumbering, type ListBullet, type StartListOptions, type ListLabel, } from './List.mjs';
|
|
6
|
+
export { List, ListItem, ListItemNotFoundError, NumberingFacade, listsOf, listLabelsOf, numberingEmulatorOf, levelOf, type ListLevelType, type ListNumbering, type ListBullet, type StartListOptions, type ListLabel, } from './List.mjs';
|
|
7
7
|
export { type Author, type CommentParts, type CommentPartsAccess, type CommentsExtensible, type CommentMarker, COMMENT_TEXT_STYLE, COMMENT_REFERENCE_STYLE, markersOf, markersOfParagraph, commentIdsOf } from './comments.mjs';
|
|
8
8
|
export { Font, type UnderlineType, type RPrHolder, type FontTracking } from './Font.mjs';
|
|
9
9
|
export { Table, TableRow, TableCell, cellOf } from './Table.mjs';
|
|
@@ -5,7 +5,7 @@ export { Range } from './Range.mjs';
|
|
|
5
5
|
export { BUILT_IN_STYLES, builtInOf, idOfBuiltIn, displayNameOf, styleNameOf, styleIdOf } from './styles.mjs';
|
|
6
6
|
export { Comment } from './Comment.mjs';
|
|
7
7
|
// lists (CR-002 phase H)
|
|
8
|
-
export { List, ListItem, ListItemNotFoundError, listsOf, listLabelsOf, numberingEmulatorOf, levelOf, } from './List.mjs';
|
|
8
|
+
export { List, ListItem, ListItemNotFoundError, NumberingFacade, listsOf, listLabelsOf, numberingEmulatorOf, levelOf, } from './List.mjs';
|
|
9
9
|
export { COMMENT_TEXT_STYLE, COMMENT_REFERENCE_STYLE, markersOf, markersOfParagraph, commentIdsOf } from './comments.mjs';
|
|
10
10
|
export { Font } from './Font.mjs';
|
|
11
11
|
export { Table, TableRow, TableCell, cellOf } from './Table.mjs';
|
|
@@ -9,6 +9,7 @@ import type { Author } from '../model/content/comments.mjs';
|
|
|
9
9
|
import { CustomXmlPartCollection } from '../model/customxml/CustomXmlPartCollection.mjs';
|
|
10
10
|
import { type XPathEngine } from '../model/customxml/xpath.mjs';
|
|
11
11
|
import { ChangeTracker, type ChangeTrackingMode, type TrackingHost } from '../model/content/tracking.mjs';
|
|
12
|
+
import { NumberingFacade } from '../model/content/List.mjs';
|
|
12
13
|
import { PropertyResolver } from '../model/properties/PropertyResolver.mjs';
|
|
13
14
|
import type { Emulator } from '../model/listnumbering/Emulator.mjs';
|
|
14
15
|
import type { TrackedChange } from '../model/content/TrackedChange.mjs';
|
|
@@ -161,6 +162,14 @@ export declare class WordprocessingMLPackage extends OpcPackage implements Track
|
|
|
161
162
|
* `customXmlParts.load()`; every node call is synchronous afterwards.
|
|
162
163
|
*/
|
|
163
164
|
xpathEngine: XPathEngine;
|
|
165
|
+
/**
|
|
166
|
+
* The document's list definitions as verbs that need no paragraph: `newList()` and
|
|
167
|
+
* `restart(numId)` (CR-002 section 19). `Paragraph.startNewList()` and `List.restart()` are
|
|
168
|
+
* Office JS's shapes and remain; this is for a caller that holds a `w:numId` rather than a
|
|
169
|
+
* paragraph - an editor with its own document model, writing `w:numPr` itself.
|
|
170
|
+
*/
|
|
171
|
+
get numbering(): NumberingFacade;
|
|
172
|
+
private numberingFacade;
|
|
164
173
|
/**
|
|
165
174
|
* Office JS `document.customXmlParts`: the custom XML data storage parts as views, with
|
|
166
175
|
* `add`, and docx4j's `applyBindings()` / `updateFromContentControls()` (CR-002 section 3.5).
|
|
@@ -13,6 +13,7 @@ import { HeaderPart, FooterPart } from '../parts/wml/index.mjs';
|
|
|
13
13
|
import { CustomXmlPartCollection } from '../model/customxml/CustomXmlPartCollection.mjs';
|
|
14
14
|
import { DefaultXPathEngine } from '../model/customxml/xpath.mjs';
|
|
15
15
|
import { ChangeTracker } from '../model/content/tracking.mjs';
|
|
16
|
+
import { NumberingFacade } from '../model/content/List.mjs';
|
|
16
17
|
import { PropertyResolver } from '../model/properties/PropertyResolver.mjs';
|
|
17
18
|
import { PropertyResolverNotCreatedException } from '../opc/exceptions.mjs';
|
|
18
19
|
import { XmlPart } from '../parts/XmlPart.mjs';
|
|
@@ -385,6 +386,16 @@ export class WordprocessingMLPackage extends OpcPackage {
|
|
|
385
386
|
all.push(await part.getBody());
|
|
386
387
|
return all;
|
|
387
388
|
}
|
|
389
|
+
/**
|
|
390
|
+
* The document's list definitions as verbs that need no paragraph: `newList()` and
|
|
391
|
+
* `restart(numId)` (CR-002 section 19). `Paragraph.startNewList()` and `List.restart()` are
|
|
392
|
+
* Office JS's shapes and remain; this is for a caller that holds a `w:numId` rather than a
|
|
393
|
+
* paragraph - an editor with its own document model, writing `w:numPr` itself.
|
|
394
|
+
*/
|
|
395
|
+
get numbering() {
|
|
396
|
+
var _a;
|
|
397
|
+
return ((_a = this.numberingFacade) !== null && _a !== void 0 ? _a : (this.numberingFacade = new NumberingFacade(this)));
|
|
398
|
+
}
|
|
388
399
|
/**
|
|
389
400
|
* Office JS `document.customXmlParts`: the custom XML data storage parts as views, with
|
|
390
401
|
* `add`, and docx4j's `applyBindings()` / `updateFromContentControls()` (CR-002 section 3.5).
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@docx4j/core-ts",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.5",
|
|
4
4
|
"description": "docx4j-core for TypeScript: Open Packaging (docx/pptx/xlsx zip and flat OPC), typed parts and relationships, style, numbering and font resolution over @docx4j/generated-objects-ts. Node, browsers, Word add-ins.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.mjs",
|