@univerjs/docs 1.0.0-alpha.1 → 1.0.0-alpha.2
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/lib/cjs/facade.js +458 -978
- package/lib/cjs/index.js +158 -9
- package/lib/es/facade.js +460 -977
- package/lib/es/index.js +156 -11
- package/lib/facade.js +460 -977
- package/lib/index.js +156 -11
- package/lib/types/commands/commands/create-header-footer.command.d.ts +41 -0
- package/lib/types/facade/f-document-paragraph.d.ts +73 -100
- package/lib/types/facade/f-document.d.ts +197 -26
- package/lib/types/facade/index.d.ts +4 -6
- package/lib/types/facade/utils.d.ts +15 -1
- package/lib/types/index.d.ts +3 -0
- package/lib/types/utils/util.d.ts +19 -0
- package/lib/umd/facade.js +3 -1
- package/lib/umd/index.js +2 -1
- package/package.json +4 -4
- package/lib/types/facade/f-document-block-range.d.ts +0 -132
- package/lib/types/facade/f-document-body.d.ts +0 -276
- package/lib/types/facade/f-document-custom-block.d.ts +0 -57
- package/lib/types/facade/f-document-element.d.ts +0 -193
- package/lib/types/facade/f-document-table.d.ts +0 -57
package/lib/es/facade.js
CHANGED
|
@@ -1,211 +1,7 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import { RichTextEditingMutation } from "@univerjs/docs";
|
|
1
|
+
import { BooleanNumber, DataStreamTreeTokenType, DocumentFlavor, ICommandService, IResourceLoaderService, IUniverInstanceService, Inject, Injector, JSONX, PresetListType, RESTORE_INSERTED_PARAGRAPH_IDS, RedoCommand, TextX, TextXActionType, UndoCommand, UniverInstanceType, UpdateDocsAttributeType, createParagraphId, generateRandomId, getRichTextEditPath } from "@univerjs/core";
|
|
2
|
+
import { FBaseInitialable, FUniver } from "@univerjs/core/facade";
|
|
3
|
+
import { CreateHeaderFooterCommand, HeaderFooterType, RichTextEditingMutation } from "@univerjs/docs";
|
|
4
4
|
|
|
5
|
-
//#region src/facade/f-document-element.ts
|
|
6
|
-
/**
|
|
7
|
-
* A generic top-level document body element.
|
|
8
|
-
*
|
|
9
|
-
* Use this wrapper when you need to inspect an element type first, navigate to
|
|
10
|
-
* neighboring elements, or cast the element to a more specific facade wrapper.
|
|
11
|
-
*
|
|
12
|
-
* Paragraph keys are persisted `paragraphId` values. Tables, block ranges, and
|
|
13
|
-
* custom blocks use their persisted ids.
|
|
14
|
-
*
|
|
15
|
-
* @hideconstructor
|
|
16
|
-
*/
|
|
17
|
-
var FDocumentElement = class extends FBase {
|
|
18
|
-
constructor(_body, _bodyEdit, _info, _injector) {
|
|
19
|
-
super();
|
|
20
|
-
this._body = _body;
|
|
21
|
-
this._bodyEdit = _bodyEdit;
|
|
22
|
-
this._info = _info;
|
|
23
|
-
this._injector = _injector;
|
|
24
|
-
}
|
|
25
|
-
/**
|
|
26
|
-
* Get the document element type.
|
|
27
|
-
* @returns {DocumentBlockType} The element type, such as `paragraph`, `table`, `blockRange`, or `customBlock`.
|
|
28
|
-
* @example
|
|
29
|
-
* ```ts
|
|
30
|
-
* const fDocument = univerAPI.getActiveDocument();
|
|
31
|
-
* const fDocumentBody = fDocument.getBody();
|
|
32
|
-
* const element = fDocumentBody.getElement(0);
|
|
33
|
-
* console.log(element?.getType());
|
|
34
|
-
* ```
|
|
35
|
-
*/
|
|
36
|
-
getType() {
|
|
37
|
-
return this._info.type;
|
|
38
|
-
}
|
|
39
|
-
/**
|
|
40
|
-
* Whether this element is a paragraph.
|
|
41
|
-
* @returns {boolean} `true` if this element is a paragraph.
|
|
42
|
-
* @example
|
|
43
|
-
* ```ts
|
|
44
|
-
* const fDocument = univerAPI.getActiveDocument();
|
|
45
|
-
* const fDocumentBody = fDocument.getBody();
|
|
46
|
-
* const element = fDocumentBody.getElement(0);
|
|
47
|
-
* console.log(element?.isParagraph());
|
|
48
|
-
* ```
|
|
49
|
-
*/
|
|
50
|
-
isParagraph() {
|
|
51
|
-
return this._info.type === DocumentBlockType.PARAGRAPH;
|
|
52
|
-
}
|
|
53
|
-
/**
|
|
54
|
-
* Whether this element is a table.
|
|
55
|
-
* @returns {boolean} `true` if this element is a table.
|
|
56
|
-
* @example
|
|
57
|
-
* ```ts
|
|
58
|
-
* const fDocument = univerAPI.getActiveDocument();
|
|
59
|
-
* const fDocumentBody = fDocument.getBody();
|
|
60
|
-
* const element = fDocumentBody.getElement(0);
|
|
61
|
-
* console.log(element?.isTable());
|
|
62
|
-
* ```
|
|
63
|
-
*/
|
|
64
|
-
isTable() {
|
|
65
|
-
return this._info.type === DocumentBlockType.TABLE;
|
|
66
|
-
}
|
|
67
|
-
/**
|
|
68
|
-
* Whether this element is a block range, such as a callout, quote, or code block.
|
|
69
|
-
* @returns {boolean} `true` if this element is a block range.
|
|
70
|
-
* @example
|
|
71
|
-
* ```ts
|
|
72
|
-
* const fDocument = univerAPI.getActiveDocument();
|
|
73
|
-
* const fDocumentBody = fDocument.getBody();
|
|
74
|
-
* const element = fDocumentBody.getElement(0);
|
|
75
|
-
* console.log(element?.isBlockRange());
|
|
76
|
-
* ```
|
|
77
|
-
*/
|
|
78
|
-
isBlockRange() {
|
|
79
|
-
return this._info.type === DocumentBlockType.BLOCK_RANGE;
|
|
80
|
-
}
|
|
81
|
-
/**
|
|
82
|
-
* Whether this element is a custom block.
|
|
83
|
-
* @returns {boolean} `true` if this element is a custom block.
|
|
84
|
-
* @example
|
|
85
|
-
* ```ts
|
|
86
|
-
* const fDocument = univerAPI.getActiveDocument();
|
|
87
|
-
* const fDocumentBody = fDocument.getBody();
|
|
88
|
-
* const element = fDocumentBody.getElement(0);
|
|
89
|
-
* console.log(element?.isCustomBlock());
|
|
90
|
-
* ```
|
|
91
|
-
*/
|
|
92
|
-
isCustomBlock() {
|
|
93
|
-
return this._info.type === DocumentBlockType.CUSTOM_BLOCK;
|
|
94
|
-
}
|
|
95
|
-
/**
|
|
96
|
-
* Get the facade key used to resolve this element.
|
|
97
|
-
* @returns {string} The paragraph `paragraphId` or persisted table/block/custom block id.
|
|
98
|
-
* @example
|
|
99
|
-
* ```ts
|
|
100
|
-
* const fDocument = univerAPI.getActiveDocument();
|
|
101
|
-
* const fDocumentBody = fDocument.getBody();
|
|
102
|
-
* const element = fDocumentBody.getElement(0);
|
|
103
|
-
* console.log(element?.getKey());
|
|
104
|
-
* ```
|
|
105
|
-
*/
|
|
106
|
-
getKey() {
|
|
107
|
-
return this._info.key;
|
|
108
|
-
}
|
|
109
|
-
/**
|
|
110
|
-
* Get the parent body facade that owns this element.
|
|
111
|
-
* @returns {FDocumentBody} The document body facade.
|
|
112
|
-
* @example
|
|
113
|
-
* ```ts
|
|
114
|
-
* const fDocument = univerAPI.getActiveDocument();
|
|
115
|
-
* const fDocumentBody = fDocument.getBody();
|
|
116
|
-
* const element = fDocumentBody.getElement(0);
|
|
117
|
-
* console.log(element?.getParent());
|
|
118
|
-
* ```
|
|
119
|
-
*/
|
|
120
|
-
getParent() {
|
|
121
|
-
return this._body;
|
|
122
|
-
}
|
|
123
|
-
/**
|
|
124
|
-
* Get the resolved element info for this wrapper.
|
|
125
|
-
* @returns {IFDocumentElementInfo} The resolved element info, including type, key, position, and priority.
|
|
126
|
-
* @example
|
|
127
|
-
* ```ts
|
|
128
|
-
* const fDocument = univerAPI.getActiveDocument();
|
|
129
|
-
* const fDocumentBody = fDocument.getBody();
|
|
130
|
-
* const element = fDocumentBody.getElement(0);
|
|
131
|
-
* console.log(element?.getResolvedInfo());
|
|
132
|
-
* ```
|
|
133
|
-
*/
|
|
134
|
-
getResolvedInfo() {
|
|
135
|
-
return this._info;
|
|
136
|
-
}
|
|
137
|
-
/**
|
|
138
|
-
* Get the next sibling element in the current body order.
|
|
139
|
-
* @returns {FDocumentElement | null} The next sibling wrapper, or `null` when this is the last child.
|
|
140
|
-
* @example
|
|
141
|
-
* ```ts
|
|
142
|
-
* const fDocument = univerAPI.getActiveDocument();
|
|
143
|
-
* const fDocumentBody = fDocument.getBody();
|
|
144
|
-
* const element = fDocumentBody.getElement(0);
|
|
145
|
-
* console.log(element?.getNextSibling());
|
|
146
|
-
* ```
|
|
147
|
-
*/
|
|
148
|
-
getNextSibling() {
|
|
149
|
-
return this._createSibling(1);
|
|
150
|
-
}
|
|
151
|
-
/**
|
|
152
|
-
* Get the previous sibling element in the current body order.
|
|
153
|
-
* @returns {FDocumentElement | null} The previous sibling wrapper, or `null` when this is the first child.
|
|
154
|
-
* @example
|
|
155
|
-
* ```ts
|
|
156
|
-
* const fDocument = univerAPI.getActiveDocument();
|
|
157
|
-
* const fDocumentBody = fDocument.getBody();
|
|
158
|
-
* const element = fDocumentBody.getElement(1);
|
|
159
|
-
* console.log(element?.getPreviousSibling());
|
|
160
|
-
* ```
|
|
161
|
-
*/
|
|
162
|
-
getPreviousSibling() {
|
|
163
|
-
return this._createSibling(-1);
|
|
164
|
-
}
|
|
165
|
-
/**
|
|
166
|
-
* Get the sibling element at a relative offset from this element.
|
|
167
|
-
* @param {number} offset The relative offset from this element. Use `1` for the next sibling, `-1` for the previous sibling, and so on.
|
|
168
|
-
* @returns {FDocumentElement | null} The sibling wrapper at the specified offset, or `null` when the offset is out of range.
|
|
169
|
-
* @example
|
|
170
|
-
* ```ts
|
|
171
|
-
* const fDocument = univerAPI.getActiveDocument();
|
|
172
|
-
* const fDocumentBody = fDocument.getBody();
|
|
173
|
-
* const element = fDocumentBody.getElement(0);
|
|
174
|
-
*
|
|
175
|
-
* // Get the third sibling after this element
|
|
176
|
-
* const nextThirdSibling = element?.getSibling(3);
|
|
177
|
-
* console.log(nextThirdSibling?.getType());
|
|
178
|
-
* ```
|
|
179
|
-
*/
|
|
180
|
-
getSibling(offset) {
|
|
181
|
-
return this._createSibling(offset);
|
|
182
|
-
}
|
|
183
|
-
/**
|
|
184
|
-
* Remove this element from its parent body.
|
|
185
|
-
* @returns {boolean} `true` if the element content was removed.
|
|
186
|
-
* @example
|
|
187
|
-
* ```ts
|
|
188
|
-
* const fDocument = univerAPI.getActiveDocument();
|
|
189
|
-
* const fDocumentBody = fDocument.getBody();
|
|
190
|
-
* const element = fDocumentBody.getElement(0);
|
|
191
|
-
* const removed = element?.remove();
|
|
192
|
-
* console.log(removed);
|
|
193
|
-
* ```
|
|
194
|
-
*/
|
|
195
|
-
remove() {
|
|
196
|
-
if (this.isParagraph()) return this._body.removeParagraph(this.asParagraph());
|
|
197
|
-
if (this.isBlockRange()) return this._body.removeBlockRange(this.asBlockRange());
|
|
198
|
-
if (this.isTable()) return this._body.removeTable(this.asTable());
|
|
199
|
-
return this._body.removeCustomBlock(this.asCustomBlock());
|
|
200
|
-
}
|
|
201
|
-
_createSibling(offset) {
|
|
202
|
-
if (offset === 0) throw new Error("Offset cannot be zero.");
|
|
203
|
-
const index = this._body.getElementIndex(this);
|
|
204
|
-
return this._body.getElement(index + offset);
|
|
205
|
-
}
|
|
206
|
-
};
|
|
207
|
-
|
|
208
|
-
//#endregion
|
|
209
5
|
//#region src/facade/utils.ts
|
|
210
6
|
function cloneParagraphStyle(paragraphStyle) {
|
|
211
7
|
return paragraphStyle == null ? paragraphStyle : JSON.parse(JSON.stringify(paragraphStyle));
|
|
@@ -236,6 +32,70 @@ function buildPlainTextInsertBody(dataStream, options = {}) {
|
|
|
236
32
|
if (paragraphs.length > 0) body.paragraphs = paragraphs;
|
|
237
33
|
return body;
|
|
238
34
|
}
|
|
35
|
+
function replaceBodyRange(range, insertBody, docDataModel, injector) {
|
|
36
|
+
const { startOffset, endOffset, segmentId } = range;
|
|
37
|
+
const textX = new TextX();
|
|
38
|
+
if (startOffset > 0) textX.push({
|
|
39
|
+
t: TextXActionType.RETAIN,
|
|
40
|
+
len: startOffset
|
|
41
|
+
});
|
|
42
|
+
if (endOffset > startOffset) textX.push({
|
|
43
|
+
t: TextXActionType.DELETE,
|
|
44
|
+
len: endOffset - startOffset
|
|
45
|
+
});
|
|
46
|
+
if (insertBody.dataStream.length > 0) textX.push({
|
|
47
|
+
t: TextXActionType.INSERT,
|
|
48
|
+
body: insertBody,
|
|
49
|
+
len: insertBody.dataStream.length
|
|
50
|
+
});
|
|
51
|
+
const actions = JSONX.getInstance().editOp(textX.serialize(), getRichTextEditPath(docDataModel, segmentId));
|
|
52
|
+
const result = injector.get(ICommandService).syncExecuteCommand(RichTextEditingMutation.id, {
|
|
53
|
+
unitId: docDataModel.getUnitId(),
|
|
54
|
+
segmentId,
|
|
55
|
+
actions,
|
|
56
|
+
textRanges: [],
|
|
57
|
+
isEditing: false
|
|
58
|
+
});
|
|
59
|
+
return Boolean((result === null || result === void 0 ? void 0 : result.actions) && result.actions.length > 0);
|
|
60
|
+
}
|
|
61
|
+
function retainBodyRange(range, updateBody, coverType, docDataModel, injector) {
|
|
62
|
+
var _updateBody$textRuns, _docDataModel$getSelf;
|
|
63
|
+
const { startOffset, endOffset, segmentId } = range;
|
|
64
|
+
const commandService = injector.get(ICommandService);
|
|
65
|
+
if (((_updateBody$textRuns = updateBody.textRuns) === null || _updateBody$textRuns === void 0 ? void 0 : _updateBody$textRuns.length) && ((_docDataModel$getSelf = docDataModel.getSelfOrHeaderFooterModel(segmentId)) === null || _docDataModel$getSelf === void 0 || (_docDataModel$getSelf = _docDataModel$getSelf.getBody()) === null || _docDataModel$getSelf === void 0 ? void 0 : _docDataModel$getSelf.textRuns) == null) {
|
|
66
|
+
const actions = JSONX.getInstance().replaceOp([...getRichTextEditPath(docDataModel, segmentId), "textRuns"], void 0, []);
|
|
67
|
+
commandService.syncExecuteCommand(RichTextEditingMutation.id, {
|
|
68
|
+
unitId: docDataModel.getUnitId(),
|
|
69
|
+
segmentId,
|
|
70
|
+
actions,
|
|
71
|
+
textRanges: [],
|
|
72
|
+
isEditing: false
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
const textX = new TextX();
|
|
76
|
+
if (startOffset > 0) textX.push({
|
|
77
|
+
t: TextXActionType.RETAIN,
|
|
78
|
+
len: startOffset
|
|
79
|
+
});
|
|
80
|
+
textX.push({
|
|
81
|
+
t: TextXActionType.RETAIN,
|
|
82
|
+
body: updateBody,
|
|
83
|
+
coverType,
|
|
84
|
+
len: endOffset - startOffset
|
|
85
|
+
});
|
|
86
|
+
const actions = JSONX.getInstance().editOp(textX.serialize(), getRichTextEditPath(docDataModel, segmentId));
|
|
87
|
+
const result = commandService.syncExecuteCommand(RichTextEditingMutation.id, {
|
|
88
|
+
unitId: docDataModel.getUnitId(),
|
|
89
|
+
segmentId,
|
|
90
|
+
actions,
|
|
91
|
+
textRanges: [],
|
|
92
|
+
isEditing: false
|
|
93
|
+
});
|
|
94
|
+
return Boolean((result === null || result === void 0 ? void 0 : result.actions) && result.actions.length > 0);
|
|
95
|
+
}
|
|
96
|
+
function stripBlockTokens(text) {
|
|
97
|
+
return Array.from(text).map((char) => char === DataStreamTreeTokenType.PARAGRAPH ? "\n" : char).filter((char) => char !== DataStreamTreeTokenType.BLOCK_START && char !== DataStreamTreeTokenType.BLOCK_END && char !== DataStreamTreeTokenType.SECTION_BREAK).join("").replace(/\n$/, "");
|
|
98
|
+
}
|
|
239
99
|
|
|
240
100
|
//#endregion
|
|
241
101
|
//#region src/facade/f-document-paragraph.ts
|
|
@@ -248,14 +108,12 @@ function buildPlainTextInsertBody(dataStream, options = {}) {
|
|
|
248
108
|
*
|
|
249
109
|
* @hideconstructor
|
|
250
110
|
*/
|
|
251
|
-
var FDocumentParagraph = class
|
|
252
|
-
constructor(
|
|
253
|
-
|
|
254
|
-
this.
|
|
255
|
-
this.
|
|
256
|
-
this.
|
|
257
|
-
this.injector = injector;
|
|
258
|
-
if (this.getType() !== DocumentBlockType.PARAGRAPH) throw new Error(`Element type is not a paragraph: ${this.getType()}`);
|
|
111
|
+
var FDocumentParagraph = class {
|
|
112
|
+
constructor(_document, _paragraphId, _segmentId = "", _injector) {
|
|
113
|
+
this._document = _document;
|
|
114
|
+
this._paragraphId = _paragraphId;
|
|
115
|
+
this._segmentId = _segmentId;
|
|
116
|
+
this._injector = _injector;
|
|
259
117
|
}
|
|
260
118
|
/**
|
|
261
119
|
* Get the persisted paragraph id.
|
|
@@ -263,41 +121,46 @@ var FDocumentParagraph = class extends FDocumentElement {
|
|
|
263
121
|
* @example
|
|
264
122
|
* ```ts
|
|
265
123
|
* const fDocument = univerAPI.getActiveDocument();
|
|
266
|
-
* const
|
|
267
|
-
*
|
|
268
|
-
*
|
|
269
|
-
* if (element?.isParagraph()) {
|
|
270
|
-
* const paragraph = element.asParagraph();
|
|
271
|
-
* console.log(paragraph.getParagraphId());
|
|
272
|
-
* }
|
|
124
|
+
* const paragraph = fDocument.getParagraphs()[0];
|
|
125
|
+
* console.log(paragraph?.getId());
|
|
273
126
|
* ```
|
|
274
127
|
*/
|
|
275
|
-
|
|
276
|
-
return this.
|
|
128
|
+
getId() {
|
|
129
|
+
return this._paragraphId;
|
|
277
130
|
}
|
|
278
131
|
/**
|
|
279
|
-
* Get the
|
|
280
|
-
*
|
|
132
|
+
* Get the segment id of this paragraph.
|
|
133
|
+
* The main body paragraphs have an empty string segment id.
|
|
134
|
+
* The header and footer paragraphs have a non-empty string segment id.
|
|
135
|
+
* @returns {string} The segment id.
|
|
281
136
|
* @example
|
|
282
137
|
* ```ts
|
|
283
138
|
* const fDocument = univerAPI.getActiveDocument();
|
|
284
|
-
* const
|
|
285
|
-
*
|
|
286
|
-
*
|
|
287
|
-
* if (element?.isParagraph()) {
|
|
288
|
-
* const paragraph = element.asParagraph();
|
|
289
|
-
* console.log(paragraph.getResolvedParagraphInfo());
|
|
290
|
-
* }
|
|
139
|
+
* const paragraph = fDocument.getParagraphs()[0];
|
|
140
|
+
* console.log(paragraph?.getSegmentId());
|
|
291
141
|
* ```
|
|
292
142
|
*/
|
|
293
|
-
|
|
294
|
-
|
|
143
|
+
getSegmentId() {
|
|
144
|
+
return this._segmentId;
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* Get this paragraph's metadata.
|
|
148
|
+
* @returns {IFDocumentParagraphInfo} The paragraph info.
|
|
149
|
+
* @example
|
|
150
|
+
* ```ts
|
|
151
|
+
* const fDocument = univerAPI.getActiveDocument();
|
|
152
|
+
* const paragraph = fDocument.getParagraphs()[0];
|
|
153
|
+
* console.log(paragraph?.getInfo());
|
|
154
|
+
* ```
|
|
155
|
+
*/
|
|
156
|
+
getInfo() {
|
|
157
|
+
const { paragraphs = [] } = this._document.getBody(this._segmentId);
|
|
295
158
|
const matches = paragraphs.map((paragraph, paragraphIndex) => ({
|
|
296
159
|
paragraph,
|
|
297
160
|
paragraphIndex
|
|
298
|
-
})).filter(({ paragraph }) => paragraph.paragraphId === this.
|
|
299
|
-
if (matches.length === 0) throw new Error(`Document paragraph with id ${this.
|
|
300
|
-
if (matches.length > 1) throw new Error(`Multiple document paragraphs with id ${this.
|
|
161
|
+
})).filter(({ paragraph }) => paragraph.paragraphId === this._paragraphId);
|
|
162
|
+
if (matches.length === 0) throw new Error(`Document paragraph with id ${this._paragraphId} not found`);
|
|
163
|
+
if (matches.length > 1) throw new Error(`Multiple document paragraphs with id ${this._paragraphId} found`);
|
|
301
164
|
const { paragraph, paragraphIndex } = matches[0];
|
|
302
165
|
return {
|
|
303
166
|
paragraph,
|
|
@@ -312,22 +175,16 @@ var FDocumentParagraph = class extends FDocumentElement {
|
|
|
312
175
|
* @example
|
|
313
176
|
* ```ts
|
|
314
177
|
* const fDocument = univerAPI.getActiveDocument();
|
|
315
|
-
* const
|
|
316
|
-
*
|
|
317
|
-
*
|
|
318
|
-
* if (element?.isParagraph()) {
|
|
319
|
-
* const paragraph = element.asParagraph();
|
|
320
|
-
* const range = paragraph.getRange();
|
|
321
|
-
* fDocumentBody.setTextStyle(range, { bl: 1 });
|
|
322
|
-
* }
|
|
178
|
+
* const paragraph = fDocument.getParagraphs()[0];
|
|
179
|
+
* console.log(paragraph?.getRange());
|
|
323
180
|
* ```
|
|
324
181
|
*/
|
|
325
182
|
getRange() {
|
|
326
|
-
const { startOffset, endOffset } = this.
|
|
183
|
+
const { startOffset, endOffset } = this.getInfo();
|
|
327
184
|
return {
|
|
328
185
|
startOffset,
|
|
329
186
|
endOffset,
|
|
330
|
-
segmentId: this.
|
|
187
|
+
segmentId: this._segmentId
|
|
331
188
|
};
|
|
332
189
|
}
|
|
333
190
|
/**
|
|
@@ -336,18 +193,13 @@ var FDocumentParagraph = class extends FDocumentElement {
|
|
|
336
193
|
* @example
|
|
337
194
|
* ```ts
|
|
338
195
|
* const fDocument = univerAPI.getActiveDocument();
|
|
339
|
-
* const
|
|
340
|
-
*
|
|
341
|
-
*
|
|
342
|
-
* if (element?.isParagraph()) {
|
|
343
|
-
* const paragraph = element.asParagraph();
|
|
344
|
-
* console.log(paragraph.getText());
|
|
345
|
-
* }
|
|
196
|
+
* const paragraph = fDocument.getParagraphs()[0];
|
|
197
|
+
* console.log(paragraph?.getText());
|
|
346
198
|
* ```
|
|
347
199
|
*/
|
|
348
200
|
getText() {
|
|
349
|
-
const { dataStream } = this.
|
|
350
|
-
const { startOffset, endOffset } = this.
|
|
201
|
+
const { dataStream } = this._document.getBody(this._segmentId);
|
|
202
|
+
const { startOffset, endOffset } = this.getInfo();
|
|
351
203
|
return dataStream.slice(startOffset, endOffset);
|
|
352
204
|
}
|
|
353
205
|
/**
|
|
@@ -357,22 +209,18 @@ var FDocumentParagraph = class extends FDocumentElement {
|
|
|
357
209
|
* @example
|
|
358
210
|
* ```ts
|
|
359
211
|
* const fDocument = univerAPI.getActiveDocument();
|
|
360
|
-
* const
|
|
361
|
-
*
|
|
362
|
-
*
|
|
363
|
-
* if (element?.isParagraph()) {
|
|
364
|
-
* const paragraph = element.asParagraph();
|
|
365
|
-
* const success = paragraph.setText('Updated title');
|
|
366
|
-
* console.log(success ? 'Text updated' : 'Failed to update text');
|
|
367
|
-
* }
|
|
212
|
+
* const paragraph = fDocument.getParagraphs()[0];
|
|
213
|
+
* paragraph?.setText('New text');
|
|
214
|
+
* console.log(paragraph?.getText());
|
|
368
215
|
* ```
|
|
369
216
|
*/
|
|
370
217
|
setText(text) {
|
|
371
|
-
const { startOffset, endOffset } = this.
|
|
372
|
-
return
|
|
218
|
+
const { startOffset, endOffset } = this.getInfo();
|
|
219
|
+
return replaceBodyRange({
|
|
373
220
|
startOffset,
|
|
374
|
-
endOffset
|
|
375
|
-
|
|
221
|
+
endOffset,
|
|
222
|
+
segmentId: this._segmentId
|
|
223
|
+
}, buildPlainTextInsertBody(text), this._document.getDocumentDataModel(), this._injector);
|
|
376
224
|
}
|
|
377
225
|
/**
|
|
378
226
|
* Append plain text before this paragraph's trailing paragraph break.
|
|
@@ -381,19 +229,14 @@ var FDocumentParagraph = class extends FDocumentElement {
|
|
|
381
229
|
* @example
|
|
382
230
|
* ```ts
|
|
383
231
|
* const fDocument = univerAPI.getActiveDocument();
|
|
384
|
-
* const
|
|
385
|
-
*
|
|
386
|
-
*
|
|
387
|
-
* if (element?.isParagraph()) {
|
|
388
|
-
* const paragraph = element.asParagraph();
|
|
389
|
-
* const success = paragraph.appendText(' Appended text');
|
|
390
|
-
* console.log(success ? 'Text appended' : 'Failed to append text');
|
|
391
|
-
* }
|
|
232
|
+
* const paragraph = fDocument.getParagraphs()[0];
|
|
233
|
+
* paragraph?.appendText(' Appended text');
|
|
234
|
+
* console.log(paragraph?.getText());
|
|
392
235
|
* ```
|
|
393
236
|
*/
|
|
394
237
|
appendText(text) {
|
|
395
|
-
const { endOffset } = this.
|
|
396
|
-
return this.
|
|
238
|
+
const { endOffset } = this.getInfo();
|
|
239
|
+
return this._document.insertText(endOffset, text, this._segmentId);
|
|
397
240
|
}
|
|
398
241
|
/**
|
|
399
242
|
* Apply paragraph style to a paragraph handle or text range.
|
|
@@ -402,17 +245,35 @@ var FDocumentParagraph = class extends FDocumentElement {
|
|
|
402
245
|
* @example
|
|
403
246
|
* ```ts
|
|
404
247
|
* const fDocument = univerAPI.getActiveDocument();
|
|
405
|
-
* const
|
|
406
|
-
*
|
|
407
|
-
*
|
|
408
|
-
*
|
|
409
|
-
*
|
|
410
|
-
*
|
|
411
|
-
*
|
|
248
|
+
* const paragraph = fDocument.getParagraphs()[0];
|
|
249
|
+
* paragraph?.setText('Styled text');
|
|
250
|
+
* paragraph?.setStyle({
|
|
251
|
+
* textStyle: {
|
|
252
|
+
* cl: {
|
|
253
|
+
* rgb: '#FF0000',
|
|
254
|
+
* },
|
|
255
|
+
* fs: 14,
|
|
256
|
+
* },
|
|
257
|
+
* horizontalAlign: 2,
|
|
258
|
+
* });
|
|
259
|
+
* console.log(paragraph?.getInfo().paragraph.paragraphStyle);
|
|
412
260
|
* ```
|
|
413
261
|
*/
|
|
414
262
|
setStyle(style) {
|
|
415
|
-
const { paragraph, endOffset } = this.
|
|
263
|
+
const { paragraph, startOffset, endOffset } = this.getInfo();
|
|
264
|
+
let result = true;
|
|
265
|
+
if (style.textStyle && startOffset < endOffset) result = retainBodyRange({
|
|
266
|
+
startOffset,
|
|
267
|
+
endOffset,
|
|
268
|
+
segmentId: this._segmentId
|
|
269
|
+
}, {
|
|
270
|
+
dataStream: "",
|
|
271
|
+
textRuns: [{
|
|
272
|
+
st: 0,
|
|
273
|
+
ed: endOffset - startOffset,
|
|
274
|
+
ts: style.textStyle
|
|
275
|
+
}]
|
|
276
|
+
}, UpdateDocsAttributeType.COVER, this._document.getDocumentDataModel(), this._injector);
|
|
416
277
|
const updateBody = {
|
|
417
278
|
dataStream: "",
|
|
418
279
|
paragraphs: [{
|
|
@@ -425,10 +286,11 @@ var FDocumentParagraph = class extends FDocumentElement {
|
|
|
425
286
|
}]
|
|
426
287
|
};
|
|
427
288
|
this._preserveExplicitParagraphIds(updateBody);
|
|
428
|
-
return
|
|
289
|
+
return retainBodyRange({
|
|
429
290
|
startOffset: endOffset,
|
|
430
|
-
endOffset: endOffset + 1
|
|
431
|
-
|
|
291
|
+
endOffset: endOffset + 1,
|
|
292
|
+
segmentId: this._segmentId
|
|
293
|
+
}, updateBody, UpdateDocsAttributeType.REPLACE, this._document.getDocumentDataModel(), this._injector) && result;
|
|
432
294
|
}
|
|
433
295
|
/**
|
|
434
296
|
* Check whether this paragraph is a bullet, ordered, or checklist item.
|
|
@@ -436,17 +298,12 @@ var FDocumentParagraph = class extends FDocumentElement {
|
|
|
436
298
|
* @example
|
|
437
299
|
* ```ts
|
|
438
300
|
* const fDocument = univerAPI.getActiveDocument();
|
|
439
|
-
* const
|
|
440
|
-
*
|
|
441
|
-
*
|
|
442
|
-
* if (element?.isParagraph()) {
|
|
443
|
-
* const paragraph = element.asParagraph();
|
|
444
|
-
* console.log(paragraph.isListItem() ? 'This is a list item' : 'This is not a list item');
|
|
445
|
-
* }
|
|
301
|
+
* const paragraph = fDocument.getParagraphs()[0];
|
|
302
|
+
* console.log(paragraph?.isListItem());
|
|
446
303
|
* ```
|
|
447
304
|
*/
|
|
448
305
|
isListItem() {
|
|
449
|
-
const { paragraph } = this.
|
|
306
|
+
const { paragraph } = this.getInfo();
|
|
450
307
|
return Boolean(paragraph.bullet);
|
|
451
308
|
}
|
|
452
309
|
/**
|
|
@@ -455,18 +312,13 @@ var FDocumentParagraph = class extends FDocumentElement {
|
|
|
455
312
|
* @example
|
|
456
313
|
* ```ts
|
|
457
314
|
* const fDocument = univerAPI.getActiveDocument();
|
|
458
|
-
* const
|
|
459
|
-
*
|
|
460
|
-
*
|
|
461
|
-
* if (element?.isParagraph()) {
|
|
462
|
-
* const paragraph = element.asParagraph();
|
|
463
|
-
* console.log(paragraph.isTask() ? 'This is a task item' : 'This is not a task item');
|
|
464
|
-
* }
|
|
315
|
+
* const paragraph = fDocument.getParagraphs()[0];
|
|
316
|
+
* console.log(paragraph?.isTask());
|
|
465
317
|
* ```
|
|
466
318
|
*/
|
|
467
319
|
isTask() {
|
|
468
320
|
var _paragraph$bullet;
|
|
469
|
-
const { paragraph } = this.
|
|
321
|
+
const { paragraph } = this.getInfo();
|
|
470
322
|
const listType = (_paragraph$bullet = paragraph.bullet) === null || _paragraph$bullet === void 0 ? void 0 : _paragraph$bullet.listType;
|
|
471
323
|
return listType === PresetListType.CHECK_LIST || listType === PresetListType.CHECK_LIST_CHECKED;
|
|
472
324
|
}
|
|
@@ -477,22 +329,17 @@ var FDocumentParagraph = class extends FDocumentElement {
|
|
|
477
329
|
* @example
|
|
478
330
|
* ```ts
|
|
479
331
|
* const fDocument = univerAPI.getActiveDocument();
|
|
480
|
-
* const
|
|
481
|
-
* const element = fDocumentBody.getElement(0);
|
|
482
|
-
*
|
|
483
|
-
* if (element?.isParagraph()) {
|
|
484
|
-
* const paragraph = element.asParagraph();
|
|
332
|
+
* const paragraph = fDocument.getParagraphs()[0];
|
|
485
333
|
*
|
|
486
|
-
*
|
|
487
|
-
*
|
|
488
|
-
*
|
|
489
|
-
* }
|
|
334
|
+
* if (paragraph.isTask()) {
|
|
335
|
+
* const success = paragraph.setTaskChecked(true);
|
|
336
|
+
* console.log(success ? 'Task checked' : 'Failed to check task');
|
|
490
337
|
* }
|
|
491
338
|
* ```
|
|
492
339
|
*/
|
|
493
340
|
setTaskChecked(checked) {
|
|
494
341
|
if (!this.isTask()) return false;
|
|
495
|
-
const { paragraph, endOffset } = this.
|
|
342
|
+
const { paragraph, endOffset } = this.getInfo();
|
|
496
343
|
const bullet = paragraph.bullet;
|
|
497
344
|
const updateBody = {
|
|
498
345
|
dataStream: "",
|
|
@@ -506,22 +353,39 @@ var FDocumentParagraph = class extends FDocumentElement {
|
|
|
506
353
|
}]
|
|
507
354
|
};
|
|
508
355
|
this._preserveExplicitParagraphIds(updateBody);
|
|
509
|
-
return
|
|
356
|
+
return retainBodyRange({
|
|
510
357
|
startOffset: endOffset,
|
|
511
|
-
endOffset: endOffset + 1
|
|
512
|
-
|
|
358
|
+
endOffset: endOffset + 1,
|
|
359
|
+
segmentId: this._segmentId
|
|
360
|
+
}, updateBody, UpdateDocsAttributeType.REPLACE, this._document.getDocumentDataModel(), this._injector);
|
|
361
|
+
}
|
|
362
|
+
/**
|
|
363
|
+
* Remove this paragraph.
|
|
364
|
+
* @returns {boolean} `true` if the paragraph was removed.
|
|
365
|
+
* @example
|
|
366
|
+
* ```ts
|
|
367
|
+
* const fDocument = univerAPI.getActiveDocument();
|
|
368
|
+
* const paragraph = fDocument.getParagraphs()[0];
|
|
369
|
+
* const success = paragraph?.remove();
|
|
370
|
+
* console.log(success ? 'Paragraph removed' : 'Failed to remove paragraph');
|
|
371
|
+
* ```
|
|
372
|
+
*/
|
|
373
|
+
remove() {
|
|
374
|
+
const { startOffset, endOffset } = this.getInfo();
|
|
375
|
+
return this._document.deleteRange({
|
|
376
|
+
startOffset,
|
|
377
|
+
endOffset: endOffset + 1,
|
|
378
|
+
segmentId: this._segmentId
|
|
379
|
+
});
|
|
513
380
|
}
|
|
514
381
|
_preserveExplicitParagraphIds(body) {
|
|
515
382
|
body[RESTORE_INSERTED_PARAGRAPH_IDS] = true;
|
|
516
383
|
}
|
|
517
384
|
};
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
}
|
|
523
|
-
};
|
|
524
|
-
FDocumentElement.extend(FDocumentParagraphMixin);
|
|
385
|
+
function isParagraphFacade(value) {
|
|
386
|
+
if (typeof value !== "object" || value === null) return false;
|
|
387
|
+
return typeof value.getId === "function" && typeof value.getSegmentId === "function" && typeof value.getInfo === "function" && typeof value.getRange === "function";
|
|
388
|
+
}
|
|
525
389
|
|
|
526
390
|
//#endregion
|
|
527
391
|
//#region \0@oxc-project+runtime@0.137.0/helpers/esm/typeof.js
|
|
@@ -565,435 +429,6 @@ function _defineProperty(e, r, t) {
|
|
|
565
429
|
}) : e[r] = t, e;
|
|
566
430
|
}
|
|
567
431
|
|
|
568
|
-
//#endregion
|
|
569
|
-
//#region src/facade/f-document-body.ts
|
|
570
|
-
/**
|
|
571
|
-
* A Facade API object bounded to a document body or header/footer segment.
|
|
572
|
-
* It provides Google Docs-like element access and range editing methods.
|
|
573
|
-
*
|
|
574
|
-
* Paragraph elements use their persisted `paragraphId`. Tables, block ranges, and
|
|
575
|
-
* custom blocks use their persisted ids.
|
|
576
|
-
*
|
|
577
|
-
* @hideconstructor
|
|
578
|
-
*/
|
|
579
|
-
var FDocumentBody = class {
|
|
580
|
-
constructor(_documentDataModel, _injector, _segmentId = "") {
|
|
581
|
-
this._documentDataModel = _documentDataModel;
|
|
582
|
-
this._injector = _injector;
|
|
583
|
-
this._segmentId = _segmentId;
|
|
584
|
-
_defineProperty(this, "_bodyEdit", void 0);
|
|
585
|
-
this._bodyEdit = {
|
|
586
|
-
replaceRange: this._replaceBodyRange.bind(this),
|
|
587
|
-
retainRange: this._retainBodyRange.bind(this)
|
|
588
|
-
};
|
|
589
|
-
}
|
|
590
|
-
/**
|
|
591
|
-
* Get the segment id of this document body facade.
|
|
592
|
-
* The main body has an empty string segment id.
|
|
593
|
-
* The header and footer FDocumentBody instances have their respective segment ids.
|
|
594
|
-
* @returns {string} The segment id of this document body facade.
|
|
595
|
-
* @example
|
|
596
|
-
* ```ts
|
|
597
|
-
* const fDocument = univerAPI.getActiveDocument();
|
|
598
|
-
* const fDocumentBody = fDocument.getBody();
|
|
599
|
-
* console.log(fDocumentBody.getSegmentId());
|
|
600
|
-
* ```
|
|
601
|
-
*/
|
|
602
|
-
getSegmentId() {
|
|
603
|
-
return this._segmentId;
|
|
604
|
-
}
|
|
605
|
-
/**
|
|
606
|
-
* Get the underlying document body snapshot.
|
|
607
|
-
* @returns {IDocumentBody} The document body snapshot.
|
|
608
|
-
* @example
|
|
609
|
-
* ```ts
|
|
610
|
-
* const fDocument = univerAPI.getActiveDocument();
|
|
611
|
-
* const fDocumentBody = fDocument.getBody();
|
|
612
|
-
* console.log(fDocumentBody.getBody());
|
|
613
|
-
* ```
|
|
614
|
-
*/
|
|
615
|
-
getBody() {
|
|
616
|
-
const body = this._documentDataModel.getSelfOrHeaderFooterModel(this._segmentId).getBody();
|
|
617
|
-
if (!body) throw new Error("The document body is empty");
|
|
618
|
-
return body;
|
|
619
|
-
}
|
|
620
|
-
/**
|
|
621
|
-
* Get a list of top-level child elements in the body.
|
|
622
|
-
* @returns {FDocumentElement[]} The list of top-level document elements.
|
|
623
|
-
* @example
|
|
624
|
-
* ```ts
|
|
625
|
-
* const fDocument = univerAPI.getActiveDocument();
|
|
626
|
-
* const fDocumentBody = fDocument.getBody();
|
|
627
|
-
* const elements = fDocumentBody.getElements();
|
|
628
|
-
* console.log(elements);
|
|
629
|
-
* ```
|
|
630
|
-
*/
|
|
631
|
-
getElements() {
|
|
632
|
-
return this._getChildren().map((child) => {
|
|
633
|
-
return this._injector.createInstance(FDocumentElement, this, this._bodyEdit, child, this._injector);
|
|
634
|
-
});
|
|
635
|
-
}
|
|
636
|
-
/**
|
|
637
|
-
* Get a top-level child element by child index.
|
|
638
|
-
* @param {number} index The zero-based child index.
|
|
639
|
-
* @returns {FDocumentElement} The top-level child element wrapper.
|
|
640
|
-
* @example
|
|
641
|
-
* ```ts
|
|
642
|
-
* const fDocument = univerAPI.getActiveDocument();
|
|
643
|
-
* const fDocumentBody = fDocument.getBody();
|
|
644
|
-
* const element = fDocumentBody.getElement(0);
|
|
645
|
-
* console.log(element);
|
|
646
|
-
* ```
|
|
647
|
-
*/
|
|
648
|
-
getElement(index) {
|
|
649
|
-
var _this$getElements$ind;
|
|
650
|
-
return (_this$getElements$ind = this.getElements()[index]) !== null && _this$getElements$ind !== void 0 ? _this$getElements$ind : null;
|
|
651
|
-
}
|
|
652
|
-
/**
|
|
653
|
-
* Get the current child index of an element handle.
|
|
654
|
-
* The index is resolved from the element key, so a paragraph handle keeps pointing
|
|
655
|
-
* to the same paragraph after facade edits insert content before it.
|
|
656
|
-
* @param {FDocumentElement} element The element handle to locate.
|
|
657
|
-
* @returns {number} The current zero-based child index.
|
|
658
|
-
* @example
|
|
659
|
-
* ```ts
|
|
660
|
-
* const fDocument = univerAPI.getActiveDocument();
|
|
661
|
-
* const fDocumentBody = fDocument.getBody();
|
|
662
|
-
* const element = fDocumentBody.getElement(0);
|
|
663
|
-
* console.log(fDocumentBody.getElementIndex(element));
|
|
664
|
-
* ```
|
|
665
|
-
*/
|
|
666
|
-
getElementIndex(element) {
|
|
667
|
-
const { type, key } = element.getResolvedInfo();
|
|
668
|
-
const index = this._getChildren().findIndex((child) => child.type === type && child.key === key);
|
|
669
|
-
if (index < 0) throw new Error("Doc element is stale");
|
|
670
|
-
return index;
|
|
671
|
-
}
|
|
672
|
-
/**
|
|
673
|
-
* Insert plain text at a document body offset.
|
|
674
|
-
* @param {number} index The zero-based insertion offset.
|
|
675
|
-
* @param {string} text The plain text to insert.
|
|
676
|
-
* @returns {boolean} `true` if the edit was applied.
|
|
677
|
-
* @example
|
|
678
|
-
* ```ts
|
|
679
|
-
* const fDocument = univerAPI.getActiveDocument();
|
|
680
|
-
* const fDocumentBody = fDocument.getBody();
|
|
681
|
-
* fDocumentBody.insertText(0, 'Hello ');
|
|
682
|
-
* ```
|
|
683
|
-
*/
|
|
684
|
-
insertText(index, text) {
|
|
685
|
-
return this._replaceBodyRange({
|
|
686
|
-
startOffset: index,
|
|
687
|
-
endOffset: index
|
|
688
|
-
}, buildPlainTextInsertBody(text));
|
|
689
|
-
}
|
|
690
|
-
/**
|
|
691
|
-
* Apply text style to a body range.
|
|
692
|
-
* @param {IFDocumentTextRange} range The range to style.
|
|
693
|
-
* @param {ITextStyle} style The Univer text style patch.
|
|
694
|
-
* @returns {boolean} `true` if the style was applied.
|
|
695
|
-
* @example
|
|
696
|
-
* ```ts
|
|
697
|
-
* const fDocument = univerAPI.getActiveDocument();
|
|
698
|
-
* const fDocumentBody = fDocument.getBody();
|
|
699
|
-
* fDocumentBody.setTextStyle({ startOffset: 0, endOffset: 5 }, { bl: 1 });
|
|
700
|
-
* ```
|
|
701
|
-
*/
|
|
702
|
-
setTextStyle(range, style) {
|
|
703
|
-
const updateBody = {
|
|
704
|
-
dataStream: "",
|
|
705
|
-
textRuns: [{
|
|
706
|
-
st: 0,
|
|
707
|
-
ed: range.endOffset - range.startOffset,
|
|
708
|
-
ts: style
|
|
709
|
-
}]
|
|
710
|
-
};
|
|
711
|
-
return this._retainBodyRange(range, updateBody, UpdateDocsAttributeType.COVER);
|
|
712
|
-
}
|
|
713
|
-
/**
|
|
714
|
-
* Insert a plain-text paragraph before the paragraph at the given paragraph index.
|
|
715
|
-
* @param {number} index The zero-based paragraph insertion index.
|
|
716
|
-
* @param {string} text The paragraph text. Defaults to an empty paragraph.
|
|
717
|
-
* @returns {FDocumentParagraph} The inserted paragraph wrapper.
|
|
718
|
-
* @example
|
|
719
|
-
* ```ts
|
|
720
|
-
* const fDocument = univerAPI.getActiveDocument();
|
|
721
|
-
* const fDocumentBody = fDocument.getBody();
|
|
722
|
-
* const paragraph = fDocumentBody.insertParagraph(0, 'Document title');
|
|
723
|
-
* paragraph.appendText(' suffix');
|
|
724
|
-
* ```
|
|
725
|
-
*/
|
|
726
|
-
insertParagraph(index, text = "") {
|
|
727
|
-
var _paragraphs;
|
|
728
|
-
const offset = this._getParagraphInsertOffset(index);
|
|
729
|
-
if (!this._replaceBodyRange({
|
|
730
|
-
startOffset: offset,
|
|
731
|
-
endOffset: offset
|
|
732
|
-
}, buildPlainTextInsertBody(`${text}\r`))) throw new Error("Failed to insert paragraph.");
|
|
733
|
-
const { paragraphs = [] } = this.getBody();
|
|
734
|
-
const paragraph = paragraphs[index];
|
|
735
|
-
if (!paragraph) throw new Error("Failed to insert paragraph.");
|
|
736
|
-
const info = this._resolveParagraphInfo(paragraph, index, (_paragraphs = paragraphs[index - 1]) === null || _paragraphs === void 0 ? void 0 : _paragraphs.startIndex);
|
|
737
|
-
return this._injector.createInstance(FDocumentParagraph, this, this._bodyEdit, info, this._injector);
|
|
738
|
-
}
|
|
739
|
-
/**
|
|
740
|
-
* Append a plain-text paragraph at the end of the body.
|
|
741
|
-
* @param {string} text The paragraph text. Defaults to an empty paragraph.
|
|
742
|
-
* @returns {FDocumentParagraph} The appended paragraph wrapper.
|
|
743
|
-
* @example
|
|
744
|
-
* ```ts
|
|
745
|
-
* const fDocument = univerAPI.getActiveDocument();
|
|
746
|
-
* const fDocumentBody = fDocument.getBody();
|
|
747
|
-
* const paragraph = fDocumentBody.appendParagraph('Summary');
|
|
748
|
-
* console.log(paragraph.getText());
|
|
749
|
-
* ```
|
|
750
|
-
*/
|
|
751
|
-
appendParagraph(text = "") {
|
|
752
|
-
const { paragraphs = [] } = this.getBody();
|
|
753
|
-
return this.insertParagraph(paragraphs.length, text);
|
|
754
|
-
}
|
|
755
|
-
/**
|
|
756
|
-
* Delete a range from the body.
|
|
757
|
-
* @param {IFDocumentTextRange} range The text range to delete.
|
|
758
|
-
* @returns {boolean} `true` if the range was deleted.
|
|
759
|
-
* @example
|
|
760
|
-
* ```ts
|
|
761
|
-
* const fDocument = univerAPI.getActiveDocument();
|
|
762
|
-
* const fDocumentBody = fDocument.getBody();
|
|
763
|
-
* fDocumentBody.deleteRange({ startOffset: 0, endOffset: 5 });
|
|
764
|
-
* ```
|
|
765
|
-
*/
|
|
766
|
-
deleteRange(range) {
|
|
767
|
-
return this._replaceBodyRange(range, { dataStream: "" });
|
|
768
|
-
}
|
|
769
|
-
/**
|
|
770
|
-
* Remove a paragraph by paragraph id.
|
|
771
|
-
* @param {FDocumentParagraph} paragraph The paragraph handle to remove.
|
|
772
|
-
* @returns {boolean} `true` if the paragraph was removed.
|
|
773
|
-
* @example
|
|
774
|
-
* ```ts
|
|
775
|
-
* const fDocument = univerAPI.getActiveDocument();
|
|
776
|
-
* const fDocumentBody = fDocument.getBody();
|
|
777
|
-
* const element = fDocumentBody.getElement(0);
|
|
778
|
-
*
|
|
779
|
-
* if (element?.isParagraph()) {
|
|
780
|
-
* const paragraph = element.asParagraph();
|
|
781
|
-
* const removed = fDocumentBody.removeParagraph(paragraph);
|
|
782
|
-
* console.log(removed ? 'Paragraph removed' : 'Failed to remove paragraph');
|
|
783
|
-
* }
|
|
784
|
-
* ```
|
|
785
|
-
*/
|
|
786
|
-
removeParagraph(paragraph) {
|
|
787
|
-
const { startOffset, endOffset } = paragraph.getResolvedParagraphInfo();
|
|
788
|
-
return this.deleteRange({
|
|
789
|
-
startOffset,
|
|
790
|
-
endOffset: endOffset + 1
|
|
791
|
-
});
|
|
792
|
-
}
|
|
793
|
-
/**
|
|
794
|
-
* Remove a callout, quote, or code block range and its content.
|
|
795
|
-
* @param {FDocumentBlockRange} blockRange The block range handle to remove.
|
|
796
|
-
* @returns {boolean} `true` if the block range content was removed.
|
|
797
|
-
* @example
|
|
798
|
-
* ```ts
|
|
799
|
-
* const fDocument = univerAPI.getActiveDocument();
|
|
800
|
-
* const fDocumentBody = fDocument.getBody();
|
|
801
|
-
* const element = fDocumentBody.getElement(0);
|
|
802
|
-
*
|
|
803
|
-
* if (element?.isBlockRange()) {
|
|
804
|
-
* const blockRange = element.asBlockRange();
|
|
805
|
-
* const removed = fDocumentBody.removeBlockRange(blockRange);
|
|
806
|
-
* console.log(removed ? 'Block range removed' : 'Failed to remove block range');
|
|
807
|
-
* }
|
|
808
|
-
* ```
|
|
809
|
-
*/
|
|
810
|
-
removeBlockRange(blockRange) {
|
|
811
|
-
const { startIndex, endIndex } = blockRange.getBlockRange();
|
|
812
|
-
return this.deleteRange({
|
|
813
|
-
startOffset: startIndex,
|
|
814
|
-
endOffset: endIndex + 1
|
|
815
|
-
});
|
|
816
|
-
}
|
|
817
|
-
/**
|
|
818
|
-
* Remove a table marker and its content range.
|
|
819
|
-
* @returns {boolean} `true` if the table range was removed.
|
|
820
|
-
* @example
|
|
821
|
-
* ```ts
|
|
822
|
-
* const fDocument = univerAPI.getActiveDocument();
|
|
823
|
-
* const fDocumentBody = fDocument.getBody();
|
|
824
|
-
* const element = fDocumentBody.getElement(0);
|
|
825
|
-
*
|
|
826
|
-
* if (element?.isTable()) {
|
|
827
|
-
* const table = element.asTable();
|
|
828
|
-
* const removed = fDocumentBody.removeTable(table);
|
|
829
|
-
* console.log(removed ? 'Table removed' : 'Failed to remove table');
|
|
830
|
-
* }
|
|
831
|
-
* ```
|
|
832
|
-
*/
|
|
833
|
-
removeTable(table) {
|
|
834
|
-
const { startIndex, endIndex } = table.getTable();
|
|
835
|
-
return this.deleteRange({
|
|
836
|
-
startOffset: startIndex,
|
|
837
|
-
endOffset: endIndex + 1
|
|
838
|
-
});
|
|
839
|
-
}
|
|
840
|
-
/**
|
|
841
|
-
* Remove a custom block marker and its placeholder character.
|
|
842
|
-
* @param {FDocumentCustomBlock} customBlock The custom block handle to remove.
|
|
843
|
-
* @returns {boolean} `true` if the custom block placeholder was removed.
|
|
844
|
-
* @example
|
|
845
|
-
* ```ts
|
|
846
|
-
* const fDocument = univerAPI.getActiveDocument();
|
|
847
|
-
* const fDocumentBody = fDocument.getBody();
|
|
848
|
-
* const element = fDocumentBody.getElement(0);
|
|
849
|
-
*
|
|
850
|
-
* if (element?.isCustomBlock()) {
|
|
851
|
-
* const customBlock = element.asCustomBlock();
|
|
852
|
-
* const removed = fDocumentBody.removeCustomBlock(customBlock);
|
|
853
|
-
* console.log(removed ? 'Custom block removed' : 'Failed to remove custom block');
|
|
854
|
-
* }
|
|
855
|
-
* ```
|
|
856
|
-
*/
|
|
857
|
-
removeCustomBlock(customBlock) {
|
|
858
|
-
const { startIndex } = customBlock.getCustomBlock();
|
|
859
|
-
return this.deleteRange({
|
|
860
|
-
startOffset: startIndex,
|
|
861
|
-
endOffset: startIndex + 1
|
|
862
|
-
});
|
|
863
|
-
}
|
|
864
|
-
/**
|
|
865
|
-
* Resolve an element key to its current child metadata.
|
|
866
|
-
* @param {FDocumentElement} element The element handle to resolve.
|
|
867
|
-
* @returns {IFDocumentElementInfo} The current child metadata used by the facade.
|
|
868
|
-
* @example
|
|
869
|
-
* ```ts
|
|
870
|
-
* const fDocument = univerAPI.getActiveDocument();
|
|
871
|
-
* const fDocumentBody = fDocument.getBody();
|
|
872
|
-
* const element = fDocumentBody.getElement(0);
|
|
873
|
-
* const resolved = fDocumentBody.resolveElement(element);
|
|
874
|
-
* console.log(resolved);
|
|
875
|
-
* ```
|
|
876
|
-
*/
|
|
877
|
-
resolveElement(element) {
|
|
878
|
-
const { type, key } = element.getResolvedInfo();
|
|
879
|
-
const child = this._getChildren().find((item) => item.type === type && item.key === key);
|
|
880
|
-
if (!child) throw new Error("Doc element is stale");
|
|
881
|
-
return child;
|
|
882
|
-
}
|
|
883
|
-
_getChildren() {
|
|
884
|
-
const { paragraphs, blockRanges, tables, customBlocks } = this.getBody();
|
|
885
|
-
const children = [];
|
|
886
|
-
if (paragraphs) for (let i = 0; i < paragraphs.length; i++) {
|
|
887
|
-
var _paragraphs2;
|
|
888
|
-
const paragraph = paragraphs[i];
|
|
889
|
-
const info = this._resolveParagraphInfo(paragraph, i, (_paragraphs2 = paragraphs[i - 1]) === null || _paragraphs2 === void 0 ? void 0 : _paragraphs2.startIndex);
|
|
890
|
-
children.push(info);
|
|
891
|
-
}
|
|
892
|
-
if (blockRanges) for (let i = 0; i < blockRanges.length; i++) {
|
|
893
|
-
const blockRange = blockRanges[i];
|
|
894
|
-
children.push({
|
|
895
|
-
type: DocumentBlockType.BLOCK_RANGE,
|
|
896
|
-
key: blockRange.blockId,
|
|
897
|
-
position: blockRange.startIndex,
|
|
898
|
-
priority: 0
|
|
899
|
-
});
|
|
900
|
-
}
|
|
901
|
-
if (tables) for (let i = 0; i < tables.length; i++) {
|
|
902
|
-
const table = tables[i];
|
|
903
|
-
children.push({
|
|
904
|
-
type: DocumentBlockType.TABLE,
|
|
905
|
-
key: table.tableId,
|
|
906
|
-
position: table.startIndex,
|
|
907
|
-
priority: 1
|
|
908
|
-
});
|
|
909
|
-
}
|
|
910
|
-
if (customBlocks) for (let i = 0; i < customBlocks.length; i++) {
|
|
911
|
-
const customBlock = customBlocks[i];
|
|
912
|
-
children.push({
|
|
913
|
-
type: DocumentBlockType.CUSTOM_BLOCK,
|
|
914
|
-
key: customBlock.blockId,
|
|
915
|
-
position: customBlock.startIndex,
|
|
916
|
-
priority: 2
|
|
917
|
-
});
|
|
918
|
-
}
|
|
919
|
-
return children.sort((a, b) => a.position - b.position || a.priority - b.priority);
|
|
920
|
-
}
|
|
921
|
-
_resolveParagraphInfo(paragraph, paragraphIndex, previousParagraphStartIndex) {
|
|
922
|
-
return {
|
|
923
|
-
type: DocumentBlockType.PARAGRAPH,
|
|
924
|
-
key: this._getParagraphId(paragraph, paragraphIndex),
|
|
925
|
-
position: paragraphIndex > 0 ? previousParagraphStartIndex + 1 : 0,
|
|
926
|
-
priority: 3
|
|
927
|
-
};
|
|
928
|
-
}
|
|
929
|
-
_getParagraphId(paragraph, paragraphIndex) {
|
|
930
|
-
if (!paragraph) throw new Error(`Paragraph index ${paragraphIndex} is out of range.`);
|
|
931
|
-
if (!paragraph.paragraphId) throw new Error(`Paragraph at index ${paragraphIndex} is missing paragraphId.`);
|
|
932
|
-
return paragraph.paragraphId;
|
|
933
|
-
}
|
|
934
|
-
_getParagraphInsertOffset(index) {
|
|
935
|
-
if (index <= 0) return 0;
|
|
936
|
-
const { dataStream, paragraphs = [] } = this.getBody();
|
|
937
|
-
if (paragraphs.length === 0) return Math.max(0, dataStream.length - 1);
|
|
938
|
-
if (index >= paragraphs.length) return paragraphs[paragraphs.length - 1].startIndex + 1;
|
|
939
|
-
return paragraphs[index - 1].startIndex + 1;
|
|
940
|
-
}
|
|
941
|
-
_replaceBodyRange(range, insertBody) {
|
|
942
|
-
const { startOffset, endOffset } = range;
|
|
943
|
-
const textX = new TextX();
|
|
944
|
-
if (startOffset > 0) textX.push({
|
|
945
|
-
t: TextXActionType.RETAIN,
|
|
946
|
-
len: startOffset
|
|
947
|
-
});
|
|
948
|
-
if (endOffset > startOffset) textX.push({
|
|
949
|
-
t: TextXActionType.DELETE,
|
|
950
|
-
len: endOffset - startOffset
|
|
951
|
-
});
|
|
952
|
-
if (insertBody.dataStream.length > 0) textX.push({
|
|
953
|
-
t: TextXActionType.INSERT,
|
|
954
|
-
body: insertBody,
|
|
955
|
-
len: insertBody.dataStream.length
|
|
956
|
-
});
|
|
957
|
-
return this._executeTextX(textX);
|
|
958
|
-
}
|
|
959
|
-
_retainBodyRange(range, body, coverType) {
|
|
960
|
-
var _body$textRuns;
|
|
961
|
-
if (((_body$textRuns = body.textRuns) === null || _body$textRuns === void 0 ? void 0 : _body$textRuns.length) && this.getBody().textRuns == null) this._ensureTextRuns();
|
|
962
|
-
const textX = new TextX();
|
|
963
|
-
if (range.startOffset > 0) textX.push({
|
|
964
|
-
t: TextXActionType.RETAIN,
|
|
965
|
-
len: range.startOffset
|
|
966
|
-
});
|
|
967
|
-
textX.push({
|
|
968
|
-
t: TextXActionType.RETAIN,
|
|
969
|
-
body,
|
|
970
|
-
coverType,
|
|
971
|
-
len: range.endOffset - range.startOffset
|
|
972
|
-
});
|
|
973
|
-
return this._executeTextX(textX);
|
|
974
|
-
}
|
|
975
|
-
_ensureTextRuns() {
|
|
976
|
-
const actions = JSONX.getInstance().replaceOp([...getRichTextEditPath(this._documentDataModel, this._segmentId), "textRuns"], void 0, []);
|
|
977
|
-
this._injector.get(ICommandService).syncExecuteCommand(RichTextEditingMutation.id, {
|
|
978
|
-
unitId: this._documentDataModel.getUnitId(),
|
|
979
|
-
segmentId: this._segmentId,
|
|
980
|
-
actions,
|
|
981
|
-
textRanges: [],
|
|
982
|
-
isEditing: false
|
|
983
|
-
});
|
|
984
|
-
}
|
|
985
|
-
_executeTextX(textX) {
|
|
986
|
-
const actions = JSONX.getInstance().editOp(textX.serialize(), getRichTextEditPath(this._documentDataModel, this._segmentId));
|
|
987
|
-
return this._injector.get(ICommandService).syncExecuteCommand(RichTextEditingMutation.id, {
|
|
988
|
-
unitId: this._documentDataModel.getUnitId(),
|
|
989
|
-
segmentId: this._segmentId,
|
|
990
|
-
actions,
|
|
991
|
-
textRanges: [],
|
|
992
|
-
isEditing: false
|
|
993
|
-
}) !== false;
|
|
994
|
-
}
|
|
995
|
-
};
|
|
996
|
-
|
|
997
432
|
//#endregion
|
|
998
433
|
//#region \0@oxc-project+runtime@0.137.0/helpers/esm/decorateParam.js
|
|
999
434
|
function __decorateParam(paramIndex, decorator) {
|
|
@@ -1026,42 +461,42 @@ let FDocument = class FDocument extends FBaseInitialable {
|
|
|
1026
461
|
}
|
|
1027
462
|
/**
|
|
1028
463
|
* Get the document data model of the document.
|
|
464
|
+
* @param {string} segmentId The segment id used to get the header/footer data model. Defaults to an empty string for the document data model of the document.
|
|
1029
465
|
* @returns {DocumentDataModel} The document data model.
|
|
1030
466
|
* @example
|
|
1031
467
|
* ```typescript
|
|
1032
468
|
* const fDocument = univerAPI.getActiveDocument();
|
|
1033
|
-
*
|
|
1034
|
-
*
|
|
469
|
+
* console.log(fDocument.getDocumentDataModel());
|
|
470
|
+
*
|
|
471
|
+
* const headerSegmentId = fDocument.ensurePageHeader();
|
|
472
|
+
* console.log(fDocument.getDocumentDataModel(headerSegmentId));
|
|
1035
473
|
* ```
|
|
1036
474
|
*/
|
|
1037
|
-
getDocumentDataModel() {
|
|
1038
|
-
|
|
475
|
+
getDocumentDataModel(segmentId = "") {
|
|
476
|
+
const documentDataModel = this._documentDataModel.getSelfOrHeaderFooterModel(segmentId);
|
|
477
|
+
if (!documentDataModel) throw new Error(segmentId === "" ? "Document data model is not found." : `Document data model is not found in the segment: ${segmentId}`);
|
|
478
|
+
return documentDataModel;
|
|
1039
479
|
}
|
|
1040
480
|
/**
|
|
1041
|
-
* Get the document body
|
|
1042
|
-
*
|
|
1043
|
-
* The
|
|
1044
|
-
*
|
|
1045
|
-
*
|
|
1046
|
-
* and custom blocks, use their existing ids.
|
|
1047
|
-
*
|
|
1048
|
-
* @returns {FDocumentBody} The document body API instance.
|
|
481
|
+
* Get the document body or header/footer body by the segment id.
|
|
482
|
+
* The main body has an empty segment id.
|
|
483
|
+
* The header and footer body have their respective segment ids.
|
|
484
|
+
* @param {string} segmentId The segment id of the body. Defaults to an empty string for the main body.
|
|
485
|
+
* @returns {IDocumentBody} The document body.
|
|
1049
486
|
* @example
|
|
1050
487
|
* ```typescript
|
|
1051
488
|
* const fDocument = univerAPI.getActiveDocument();
|
|
1052
|
-
*
|
|
1053
|
-
* console.log(fDocumentBody.getBody());
|
|
489
|
+
* console.log(fDocument.getBody()); // Get the main body
|
|
1054
490
|
*
|
|
1055
|
-
* const
|
|
1056
|
-
*
|
|
1057
|
-
* const paragraph = element.asParagraph();
|
|
1058
|
-
* paragraph.appendText(' updated');
|
|
1059
|
-
* console.log(paragraph.getText());
|
|
1060
|
-
* }
|
|
491
|
+
* const footerSegmentId = fDocument.ensurePageFooter();
|
|
492
|
+
* console.log(fDocument.getBody(footerSegmentId)); // Get the footer body
|
|
1061
493
|
* ```
|
|
1062
494
|
*/
|
|
1063
|
-
getBody() {
|
|
1064
|
-
|
|
495
|
+
getBody(segmentId = "") {
|
|
496
|
+
var _this$_documentDataMo;
|
|
497
|
+
const body = (_this$_documentDataMo = this._documentDataModel.getSelfOrHeaderFooterModel(segmentId)) === null || _this$_documentDataMo === void 0 ? void 0 : _this$_documentDataMo.getBody();
|
|
498
|
+
if (!body) throw new Error(segmentId === "" ? "Body is not found in the document." : `Body is not found in the segment: ${segmentId}`);
|
|
499
|
+
return body;
|
|
1065
500
|
}
|
|
1066
501
|
dispose() {
|
|
1067
502
|
super.dispose();
|
|
@@ -1072,8 +507,7 @@ let FDocument = class FDocument extends FBaseInitialable {
|
|
|
1072
507
|
* @example
|
|
1073
508
|
* ```typescript
|
|
1074
509
|
* const fDocument = univerAPI.getActiveDocument();
|
|
1075
|
-
*
|
|
1076
|
-
* console.log(unitId);
|
|
510
|
+
* console.log(fDocument.getId());
|
|
1077
511
|
* ```
|
|
1078
512
|
*/
|
|
1079
513
|
getId() {
|
|
@@ -1085,14 +519,25 @@ let FDocument = class FDocument extends FBaseInitialable {
|
|
|
1085
519
|
* @example
|
|
1086
520
|
* ```typescript
|
|
1087
521
|
* const fDocument = univerAPI.getActiveDocument();
|
|
1088
|
-
*
|
|
1089
|
-
* console.log(name);
|
|
522
|
+
* console.log(fDocument.getName());
|
|
1090
523
|
* ```
|
|
1091
524
|
*/
|
|
1092
525
|
getName() {
|
|
1093
526
|
return this._documentDataModel.getTitle() || "";
|
|
1094
527
|
}
|
|
1095
528
|
/**
|
|
529
|
+
* Whether the document is a modern document or not.
|
|
530
|
+
* @returns {boolean} `true` if the document is a modern document, or `false` if it is not.
|
|
531
|
+
* @example
|
|
532
|
+
* ```typescript
|
|
533
|
+
* const fDocument = univerAPI.getActiveDocument();
|
|
534
|
+
* console.log(fDocument.isModern());
|
|
535
|
+
* ```
|
|
536
|
+
*/
|
|
537
|
+
isModern() {
|
|
538
|
+
return this._documentDataModel.getSnapshot().documentStyle.documentFlavor === DocumentFlavor.MODERN;
|
|
539
|
+
}
|
|
540
|
+
/**
|
|
1096
541
|
* Save the document snapshot data, including the document content and resource data, etc.
|
|
1097
542
|
* @returns {IDocumentData} The document snapshot data.
|
|
1098
543
|
* @example
|
|
@@ -1133,264 +578,302 @@ let FDocument = class FDocument extends FBaseInitialable {
|
|
|
1133
578
|
this._univerInstanceService.focusUnit(this.id);
|
|
1134
579
|
return this._commandService.syncExecuteCommand(RedoCommand.id);
|
|
1135
580
|
}
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
return this._injector.createInstance(FDocument, document);
|
|
1150
|
-
}
|
|
1151
|
-
getActiveDocument() {
|
|
1152
|
-
const document = this._univerInstanceService.getCurrentUnitOfType(UniverInstanceType.UNIVER_DOC);
|
|
1153
|
-
if (!document) return null;
|
|
1154
|
-
return this._injector.createInstance(FDocument, document);
|
|
1155
|
-
}
|
|
1156
|
-
getDocument(id) {
|
|
1157
|
-
const document = this._univerInstanceService.getUnit(id, UniverInstanceType.UNIVER_DOC);
|
|
1158
|
-
if (!document) return null;
|
|
1159
|
-
return this._injector.createInstance(FDocument, document);
|
|
581
|
+
/**
|
|
582
|
+
* Ensure the page header segment exists and return its segment id.
|
|
583
|
+
* @param {number} pageIndex The zero-based page index. Defaults to the first page.
|
|
584
|
+
* @returns {string} The header segment id.
|
|
585
|
+
* @example
|
|
586
|
+
* ```ts
|
|
587
|
+
* const fDocument = univerAPI.getActiveDocument();
|
|
588
|
+
* const headerSegmentId = fDocument.ensurePageHeader();
|
|
589
|
+
* fDocument.insertText(0, 'Header text', headerSegmentId);
|
|
590
|
+
* ```
|
|
591
|
+
*/
|
|
592
|
+
ensurePageHeader(pageIndex = 0) {
|
|
593
|
+
return this._ensureHeaderFooter("header", pageIndex);
|
|
1160
594
|
}
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
*
|
|
1168
|
-
*
|
|
1169
|
-
*
|
|
1170
|
-
*
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
var FDocumentBlockRange = class extends FDocumentElement {
|
|
1175
|
-
constructor(body, bodyEdit, info, injector) {
|
|
1176
|
-
super(body, bodyEdit, info, injector);
|
|
1177
|
-
this.body = body;
|
|
1178
|
-
this.bodyEdit = bodyEdit;
|
|
1179
|
-
this.info = info;
|
|
1180
|
-
this.injector = injector;
|
|
1181
|
-
if (this.getType() !== DocumentBlockType.BLOCK_RANGE) throw new Error(`Element type is not a block range: ${this.getType()}`);
|
|
595
|
+
/**
|
|
596
|
+
* Ensure the page footer segment exists and return its segment id.
|
|
597
|
+
* @param {number} pageIndex The zero-based page index. Defaults to the first page.
|
|
598
|
+
* @returns {string} The footer segment id.
|
|
599
|
+
* @example
|
|
600
|
+
* ```ts
|
|
601
|
+
* const fDocument = univerAPI.getActiveDocument();
|
|
602
|
+
* const footerSegmentId = fDocument.ensurePageFooter();
|
|
603
|
+
* fDocument.insertText(0, 'Footer text', footerSegmentId);
|
|
604
|
+
* ```
|
|
605
|
+
*/
|
|
606
|
+
ensurePageFooter(pageIndex = 0) {
|
|
607
|
+
return this._ensureHeaderFooter("footer", pageIndex);
|
|
1182
608
|
}
|
|
1183
609
|
/**
|
|
1184
|
-
*
|
|
1185
|
-
* @
|
|
610
|
+
* Insert plain text at a document body offset.
|
|
611
|
+
* @param {number} index The zero-based insertion offset.
|
|
612
|
+
* @param {string} text The plain text to insert.
|
|
613
|
+
* @param {string} segmentId The segment id of the body. Defaults to an empty string for the main body.
|
|
614
|
+
* @returns {boolean} `true` if the edit was applied.
|
|
1186
615
|
* @example
|
|
1187
616
|
* ```ts
|
|
1188
617
|
* const fDocument = univerAPI.getActiveDocument();
|
|
1189
|
-
*
|
|
1190
|
-
* const element = fDocumentBody.getElement(0);
|
|
618
|
+
* fDocument.insertText(0, 'Hello ');
|
|
1191
619
|
*
|
|
1192
|
-
*
|
|
1193
|
-
*
|
|
1194
|
-
* console.log(blockRange.getBlockRange());
|
|
1195
|
-
* }
|
|
620
|
+
* const headerSegmentId = fDocument.ensurePageHeader();
|
|
621
|
+
* fDocument.insertText(0, 'Header text', headerSegmentId);
|
|
1196
622
|
* ```
|
|
1197
623
|
*/
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
624
|
+
insertText(index, text, segmentId = "") {
|
|
625
|
+
return replaceBodyRange({
|
|
626
|
+
startOffset: index,
|
|
627
|
+
endOffset: index,
|
|
628
|
+
segmentId
|
|
629
|
+
}, buildPlainTextInsertBody(text), this._documentDataModel, this._injector);
|
|
1203
630
|
}
|
|
1204
631
|
/**
|
|
1205
|
-
* Get the
|
|
1206
|
-
* @
|
|
632
|
+
* Get all paragraphs in the document body or header/footer body by the segment id.
|
|
633
|
+
* @param {string} segmentId The segment id of the body. Defaults to an empty string for the main body.
|
|
634
|
+
* @returns {FDocumentParagraph[]} An array of paragraph facade instances.
|
|
1207
635
|
* @example
|
|
1208
636
|
* ```ts
|
|
1209
637
|
* const fDocument = univerAPI.getActiveDocument();
|
|
1210
|
-
* const
|
|
1211
|
-
*
|
|
638
|
+
* const paragraphs = fDocument.getParagraphs();
|
|
639
|
+
* console.log(paragraphs);
|
|
1212
640
|
*
|
|
1213
|
-
*
|
|
1214
|
-
*
|
|
1215
|
-
*
|
|
1216
|
-
* }
|
|
641
|
+
* const headerSegmentId = fDocument.ensurePageHeader();
|
|
642
|
+
* const headerParagraphs = fDocument.getParagraphs(headerSegmentId);
|
|
643
|
+
* console.log(headerParagraphs);
|
|
1217
644
|
* ```
|
|
1218
645
|
*/
|
|
1219
|
-
|
|
1220
|
-
|
|
646
|
+
getParagraphs(segmentId = "") {
|
|
647
|
+
const { paragraphs = [] } = this.getBody(segmentId);
|
|
648
|
+
return paragraphs.map((paragraph) => this._createFDocumentParagraph(paragraph.paragraphId, segmentId));
|
|
1221
649
|
}
|
|
1222
650
|
/**
|
|
1223
|
-
* Get
|
|
1224
|
-
* @
|
|
651
|
+
* Get a paragraph by its paragraph id and segment id.
|
|
652
|
+
* @param {string} paragraphId The paragraph id.
|
|
653
|
+
* @param {string} segmentId The segment id of the body. Defaults to an empty string for the main body.
|
|
654
|
+
* @returns {FDocumentParagraph | null} The paragraph facade instance, or `null` if the paragraph is not found.
|
|
1225
655
|
* @example
|
|
1226
656
|
* ```ts
|
|
1227
657
|
* const fDocument = univerAPI.getActiveDocument();
|
|
1228
|
-
* const
|
|
1229
|
-
*
|
|
658
|
+
* const paragraph = fDocument.getParagraph('paragraph-01');
|
|
659
|
+
* console.log(paragraph);
|
|
1230
660
|
*
|
|
1231
|
-
*
|
|
1232
|
-
*
|
|
1233
|
-
*
|
|
1234
|
-
* }
|
|
661
|
+
* const headerSegmentId = fDocument.ensurePageHeader();
|
|
662
|
+
* const headerParagraph = fDocument.getParagraph('header-paragraph-01', headerSegmentId);
|
|
663
|
+
* console.log(headerParagraph);
|
|
1235
664
|
* ```
|
|
1236
665
|
*/
|
|
1237
|
-
|
|
1238
|
-
const {
|
|
1239
|
-
|
|
1240
|
-
return
|
|
666
|
+
getParagraph(paragraphId, segmentId = "") {
|
|
667
|
+
const { paragraphs = [] } = this.getBody(segmentId);
|
|
668
|
+
if (!paragraphs.find((paragraph) => paragraph.paragraphId === paragraphId)) return null;
|
|
669
|
+
return this._createFDocumentParagraph(paragraphId, segmentId);
|
|
1241
670
|
}
|
|
1242
671
|
/**
|
|
1243
|
-
*
|
|
1244
|
-
* @param {string} text The
|
|
1245
|
-
* @
|
|
672
|
+
* Find a paragraph by its text content and segment id.
|
|
673
|
+
* @param {string} text The text content to search for.
|
|
674
|
+
* @param {string} segmentId The segment id of the body. Defaults to an empty string for the main body.
|
|
675
|
+
* @returns {FDocumentParagraph | null} The paragraph facade instance, or `null` if the paragraph is not found.
|
|
1246
676
|
* @example
|
|
1247
677
|
* ```ts
|
|
1248
678
|
* const fDocument = univerAPI.getActiveDocument();
|
|
1249
|
-
* const
|
|
1250
|
-
*
|
|
679
|
+
* const paragraph = fDocument.findParagraphByText('Hello');
|
|
680
|
+
* console.log(paragraph);
|
|
1251
681
|
*
|
|
1252
|
-
*
|
|
1253
|
-
*
|
|
1254
|
-
*
|
|
1255
|
-
* console.log(blockRange.getText());
|
|
1256
|
-
* }
|
|
682
|
+
* const footerSegmentId = fDocument.ensurePageFooter();
|
|
683
|
+
* const footerParagraph = fDocument.findParagraphByText('Page', footerSegmentId);
|
|
684
|
+
* console.log(footerParagraph);
|
|
1257
685
|
* ```
|
|
1258
686
|
*/
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
...blockRange,
|
|
1265
|
-
startIndex: 0,
|
|
1266
|
-
endIndex: text.length
|
|
1267
|
-
}];
|
|
1268
|
-
return this._bodyEdit.replaceRange({
|
|
1269
|
-
startOffset: startIndex,
|
|
1270
|
-
endOffset: endIndex + 1
|
|
1271
|
-
}, updateBody);
|
|
687
|
+
findParagraphByText(text, segmentId = "") {
|
|
688
|
+
return this.findParagraphs({
|
|
689
|
+
text,
|
|
690
|
+
segmentId
|
|
691
|
+
})[0] || null;
|
|
1272
692
|
}
|
|
1273
693
|
/**
|
|
1274
|
-
*
|
|
694
|
+
* Find paragraphs by a query object, which can include text content, paragraph id, and segment id.
|
|
695
|
+
* @param {string | IFDocumentParagraphQuery} query The query object or text content to search for.
|
|
696
|
+
* @returns {FDocumentParagraph[]} An array of paragraph facade instances that match the query.
|
|
697
|
+
* @example
|
|
698
|
+
* ```ts
|
|
699
|
+
* const fDocument = univerAPI.getActiveDocument();
|
|
700
|
+
* const paragraphsWithText = fDocument.findParagraphs('Hello');
|
|
701
|
+
* console.log(paragraphsWithText);
|
|
1275
702
|
*
|
|
1276
|
-
*
|
|
1277
|
-
*
|
|
703
|
+
* const paragraphsWithId = fDocument.findParagraphs({ paragraphId: 'paragraph-01' });
|
|
704
|
+
* console.log(paragraphsWithId);
|
|
1278
705
|
*
|
|
1279
|
-
*
|
|
706
|
+
* const headerSegmentId = fDocument.ensurePageHeader();
|
|
707
|
+
* const paragraphsWithSegment = fDocument.findParagraphs({ segmentId: headerSegmentId });
|
|
708
|
+
* console.log(paragraphsWithSegment);
|
|
709
|
+
* ```
|
|
710
|
+
*/
|
|
711
|
+
findParagraphs(query) {
|
|
712
|
+
const { text, paragraphId, segmentId = "" } = typeof query === "string" ? { text: query } : query;
|
|
713
|
+
return this.getParagraphs(segmentId).filter((paragraph) => {
|
|
714
|
+
if (paragraphId && paragraph.getId() !== paragraphId) return false;
|
|
715
|
+
if (text && !paragraph.getText().includes(text)) return false;
|
|
716
|
+
return true;
|
|
717
|
+
});
|
|
718
|
+
}
|
|
719
|
+
/**
|
|
720
|
+
* Insert a plain-text paragraph before the paragraph at the given paragraph index.
|
|
721
|
+
* @param {number} index The zero-based paragraph insertion index.
|
|
722
|
+
* @param {string} text The paragraph text. Defaults to an empty paragraph.
|
|
723
|
+
* @param {string} segmentId The segment id of the body. Defaults to an empty string for the main body.
|
|
724
|
+
* @returns {FDocumentParagraph} The inserted paragraph facade instance.
|
|
1280
725
|
* @example
|
|
1281
726
|
* ```ts
|
|
1282
727
|
* const fDocument = univerAPI.getActiveDocument();
|
|
1283
|
-
* const
|
|
1284
|
-
*
|
|
728
|
+
* const paragraph = fDocument.insertParagraph(0, 'Document title');
|
|
729
|
+
* paragraph.appendText(' suffix');
|
|
1285
730
|
*
|
|
1286
|
-
*
|
|
1287
|
-
*
|
|
1288
|
-
*
|
|
1289
|
-
* console.log(removed ? 'Block range removed' : 'Failed to remove block range');
|
|
1290
|
-
* }
|
|
731
|
+
* const headerSegmentId = fDocument.ensurePageHeader();
|
|
732
|
+
* const headerParagraph = fDocument.insertParagraph(0, 'Header title', headerSegmentId);
|
|
733
|
+
* headerParagraph.appendText(' suffix');
|
|
1291
734
|
* ```
|
|
1292
735
|
*/
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
//#endregion
|
|
1306
|
-
//#region src/facade/f-document-custom-block.ts
|
|
1307
|
-
/**
|
|
1308
|
-
* A facade wrapper for document top-level custom blocks.
|
|
1309
|
-
* @hideconstructor
|
|
1310
|
-
*/
|
|
1311
|
-
var FDocumentCustomBlock = class extends FDocumentElement {
|
|
1312
|
-
constructor(body, bodyEdit, info, injector) {
|
|
1313
|
-
super(body, bodyEdit, info, injector);
|
|
1314
|
-
this.body = body;
|
|
1315
|
-
this.bodyEdit = bodyEdit;
|
|
1316
|
-
this.info = info;
|
|
1317
|
-
this.injector = injector;
|
|
1318
|
-
if (this.getType() !== DocumentBlockType.CUSTOM_BLOCK) throw new Error(`Element type is not a custom block: ${this.getType()}`);
|
|
736
|
+
insertParagraph(index, text = "", segmentId = "") {
|
|
737
|
+
const offset = this._getParagraphInsertOffset(index, segmentId);
|
|
738
|
+
if (!replaceBodyRange({
|
|
739
|
+
startOffset: offset,
|
|
740
|
+
endOffset: offset,
|
|
741
|
+
segmentId
|
|
742
|
+
}, buildPlainTextInsertBody(`${text}\r`), this._documentDataModel, this._injector)) throw new Error("Failed to insert paragraph.");
|
|
743
|
+
const { paragraphs = [] } = this.getBody(segmentId);
|
|
744
|
+
const paragraph = paragraphs[index];
|
|
745
|
+
if (!paragraph) throw new Error("Failed to insert paragraph.");
|
|
746
|
+
return this._createFDocumentParagraph(paragraph.paragraphId, segmentId);
|
|
1319
747
|
}
|
|
1320
748
|
/**
|
|
1321
|
-
*
|
|
1322
|
-
* @
|
|
749
|
+
* Append a plain-text paragraph at the end of the body.
|
|
750
|
+
* @param {string} text The paragraph text. Defaults to an empty paragraph.
|
|
751
|
+
* @returns {FDocumentParagraph} The appended paragraph wrapper.
|
|
1323
752
|
* @example
|
|
1324
753
|
* ```ts
|
|
1325
754
|
* const fDocument = univerAPI.getActiveDocument();
|
|
1326
|
-
* const
|
|
1327
|
-
*
|
|
755
|
+
* const paragraph = fDocument.appendParagraph('Summary');
|
|
756
|
+
* console.log(paragraph.getText());
|
|
1328
757
|
*
|
|
1329
|
-
*
|
|
1330
|
-
*
|
|
1331
|
-
*
|
|
1332
|
-
* }
|
|
758
|
+
* const footerSegmentId = fDocument.ensurePageFooter();
|
|
759
|
+
* const footerParagraph = fDocument.appendParagraph('Confidential', footerSegmentId);
|
|
760
|
+
* console.log(footerParagraph.getText());
|
|
1333
761
|
* ```
|
|
1334
762
|
*/
|
|
1335
|
-
|
|
1336
|
-
const {
|
|
1337
|
-
|
|
1338
|
-
if (!block) throw new Error("Doc custom block is stale");
|
|
1339
|
-
return block;
|
|
1340
|
-
}
|
|
1341
|
-
};
|
|
1342
|
-
var FDocumentCustomBlockMixin = class extends FDocumentElement {
|
|
1343
|
-
asCustomBlock() {
|
|
1344
|
-
if (this.getType() !== DocumentBlockType.CUSTOM_BLOCK) throw new Error(`Element type is not a custom block: ${this.getType()}`);
|
|
1345
|
-
return this._injector.createInstance(FDocumentCustomBlock, this._body, this._bodyEdit, this.getResolvedInfo(), this._injector);
|
|
1346
|
-
}
|
|
1347
|
-
};
|
|
1348
|
-
FDocumentElement.extend(FDocumentCustomBlockMixin);
|
|
1349
|
-
|
|
1350
|
-
//#endregion
|
|
1351
|
-
//#region src/facade/f-document-table.ts
|
|
1352
|
-
/**
|
|
1353
|
-
* A facade wrapper for document top-level tables.
|
|
1354
|
-
* @hideconstructor
|
|
1355
|
-
*/
|
|
1356
|
-
var FDocumentTable = class extends FDocumentElement {
|
|
1357
|
-
constructor(body, bodyEdit, info, injector) {
|
|
1358
|
-
super(body, bodyEdit, info, injector);
|
|
1359
|
-
this.body = body;
|
|
1360
|
-
this.bodyEdit = bodyEdit;
|
|
1361
|
-
this.info = info;
|
|
1362
|
-
this.injector = injector;
|
|
1363
|
-
if (this.getType() !== DocumentBlockType.TABLE) throw new Error(`Element type is not a table: ${this.getType()}`);
|
|
763
|
+
appendParagraph(text = "", segmentId = "") {
|
|
764
|
+
const { paragraphs = [] } = this.getBody(segmentId);
|
|
765
|
+
return this.insertParagraph(paragraphs.length, text, segmentId);
|
|
1364
766
|
}
|
|
1365
767
|
/**
|
|
1366
|
-
*
|
|
1367
|
-
* @
|
|
768
|
+
* Delete a range from the body.
|
|
769
|
+
* @param {IFDocumentTextRange} range The text range to delete.
|
|
770
|
+
* @returns {boolean} `true` if the range was deleted.
|
|
1368
771
|
* @example
|
|
1369
772
|
* ```ts
|
|
1370
773
|
* const fDocument = univerAPI.getActiveDocument();
|
|
1371
|
-
*
|
|
1372
|
-
* const element = fDocumentBody.getElement(0);
|
|
774
|
+
* fDocument.deleteRange({ startOffset: 0, endOffset: 5 });
|
|
1373
775
|
*
|
|
1374
|
-
*
|
|
1375
|
-
*
|
|
1376
|
-
* console.log(table.getTable());
|
|
1377
|
-
* }
|
|
776
|
+
* const headerSegmentId = fDocument.ensurePageHeader();
|
|
777
|
+
* fDocument.deleteRange({ startOffset: 0, endOffset: 5, segmentId: headerSegmentId });
|
|
1378
778
|
* ```
|
|
1379
779
|
*/
|
|
1380
|
-
|
|
1381
|
-
const
|
|
1382
|
-
|
|
1383
|
-
|
|
1384
|
-
|
|
780
|
+
deleteRange(range) {
|
|
781
|
+
const normalizedRange = this._normalizeDeleteRange(range);
|
|
782
|
+
if (normalizedRange.startOffset >= normalizedRange.endOffset) return false;
|
|
783
|
+
return replaceBodyRange(normalizedRange, { dataStream: "" }, this._documentDataModel, this._injector);
|
|
784
|
+
}
|
|
785
|
+
_createFDocumentParagraph(paragraphId, segmentId = "") {
|
|
786
|
+
return this._injector.createInstance(FDocumentParagraph, this, paragraphId, segmentId, this._injector);
|
|
787
|
+
}
|
|
788
|
+
_normalizeDeleteRange(range) {
|
|
789
|
+
const body = this.getBody(range.segmentId);
|
|
790
|
+
const protectedEndOffset = body.dataStream.endsWith("\r\n") ? Math.max(0, body.dataStream.length - 2) : body.dataStream.length;
|
|
791
|
+
const endOffset = Math.min(Math.max(range.endOffset, 0), protectedEndOffset);
|
|
792
|
+
return {
|
|
793
|
+
...range,
|
|
794
|
+
startOffset: Math.min(Math.max(range.startOffset, 0), endOffset),
|
|
795
|
+
endOffset
|
|
796
|
+
};
|
|
797
|
+
}
|
|
798
|
+
_getParagraphInsertOffset(index, segmentId = "") {
|
|
799
|
+
if (index <= 0) return 0;
|
|
800
|
+
const { dataStream, paragraphs = [] } = this.getBody(segmentId);
|
|
801
|
+
if (paragraphs.length === 0) return Math.max(0, dataStream.length - 1);
|
|
802
|
+
if (index >= paragraphs.length) return paragraphs[paragraphs.length - 1].startIndex + 1;
|
|
803
|
+
return paragraphs[index - 1].startIndex + 1;
|
|
804
|
+
}
|
|
805
|
+
_ensureHeaderFooter(kind, pageIndex) {
|
|
806
|
+
if (this.isModern()) throw new Error("The document is a modern document, header/footer is not supported.");
|
|
807
|
+
const { createType, segmentId: existingSegmentId } = this._getHeaderFooterCreateInfo(kind, pageIndex);
|
|
808
|
+
if (existingSegmentId) return existingSegmentId;
|
|
809
|
+
const segmentId = generateRandomId(6);
|
|
810
|
+
if (!this._commandService.syncExecuteCommand(CreateHeaderFooterCommand.id, {
|
|
811
|
+
unitId: this.getId(),
|
|
812
|
+
segmentId,
|
|
813
|
+
createType
|
|
814
|
+
})) throw new Error(`Failed to create page ${kind}.`);
|
|
815
|
+
return segmentId;
|
|
816
|
+
}
|
|
817
|
+
_getHeaderFooterCreateInfo(kind, pageIndex) {
|
|
818
|
+
var _documentStyle$defaul, _documentStyle$defaul2;
|
|
819
|
+
const { documentStyle } = this._documentDataModel.getSnapshot();
|
|
820
|
+
const isFirstPage = pageIndex === 0;
|
|
821
|
+
const isEvenPage = (pageIndex + 1) % 2 === 0;
|
|
822
|
+
if (isFirstPage && documentStyle.useFirstPageHeaderFooter === BooleanNumber.TRUE) {
|
|
823
|
+
var _documentStyle$firstP, _documentStyle$firstP2;
|
|
824
|
+
return kind === "header" ? {
|
|
825
|
+
createType: HeaderFooterType.FIRST_PAGE_HEADER,
|
|
826
|
+
segmentId: (_documentStyle$firstP = documentStyle.firstPageHeaderId) !== null && _documentStyle$firstP !== void 0 ? _documentStyle$firstP : ""
|
|
827
|
+
} : {
|
|
828
|
+
createType: HeaderFooterType.FIRST_PAGE_FOOTER,
|
|
829
|
+
segmentId: (_documentStyle$firstP2 = documentStyle.firstPageFooterId) !== null && _documentStyle$firstP2 !== void 0 ? _documentStyle$firstP2 : ""
|
|
830
|
+
};
|
|
831
|
+
}
|
|
832
|
+
if (isEvenPage && documentStyle.evenAndOddHeaders === BooleanNumber.TRUE) {
|
|
833
|
+
var _documentStyle$evenPa, _documentStyle$evenPa2;
|
|
834
|
+
return kind === "header" ? {
|
|
835
|
+
createType: HeaderFooterType.EVEN_PAGE_HEADER,
|
|
836
|
+
segmentId: (_documentStyle$evenPa = documentStyle.evenPageHeaderId) !== null && _documentStyle$evenPa !== void 0 ? _documentStyle$evenPa : ""
|
|
837
|
+
} : {
|
|
838
|
+
createType: HeaderFooterType.EVEN_PAGE_FOOTER,
|
|
839
|
+
segmentId: (_documentStyle$evenPa2 = documentStyle.evenPageFooterId) !== null && _documentStyle$evenPa2 !== void 0 ? _documentStyle$evenPa2 : ""
|
|
840
|
+
};
|
|
841
|
+
}
|
|
842
|
+
return kind === "header" ? {
|
|
843
|
+
createType: HeaderFooterType.DEFAULT_HEADER,
|
|
844
|
+
segmentId: (_documentStyle$defaul = documentStyle.defaultHeaderId) !== null && _documentStyle$defaul !== void 0 ? _documentStyle$defaul : ""
|
|
845
|
+
} : {
|
|
846
|
+
createType: HeaderFooterType.DEFAULT_FOOTER,
|
|
847
|
+
segmentId: (_documentStyle$defaul2 = documentStyle.defaultFooterId) !== null && _documentStyle$defaul2 !== void 0 ? _documentStyle$defaul2 : ""
|
|
848
|
+
};
|
|
1385
849
|
}
|
|
1386
850
|
};
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
|
|
1390
|
-
|
|
851
|
+
FDocument = __decorate([
|
|
852
|
+
__decorateParam(1, Inject(Injector)),
|
|
853
|
+
__decorateParam(2, IUniverInstanceService),
|
|
854
|
+
__decorateParam(3, Inject(IResourceLoaderService)),
|
|
855
|
+
__decorateParam(4, ICommandService)
|
|
856
|
+
], FDocument);
|
|
857
|
+
|
|
858
|
+
//#endregion
|
|
859
|
+
//#region src/facade/f-univer.ts
|
|
860
|
+
var FUniverDocsMixin = class extends FUniver {
|
|
861
|
+
createDocument(data) {
|
|
862
|
+
const document = this._injector.get(IUniverInstanceService).createUnit(UniverInstanceType.UNIVER_DOC, data);
|
|
863
|
+
return this._injector.createInstance(FDocument, document);
|
|
864
|
+
}
|
|
865
|
+
getActiveDocument() {
|
|
866
|
+
const document = this._univerInstanceService.getCurrentUnitOfType(UniverInstanceType.UNIVER_DOC);
|
|
867
|
+
if (!document) return null;
|
|
868
|
+
return this._injector.createInstance(FDocument, document);
|
|
869
|
+
}
|
|
870
|
+
getDocument(id) {
|
|
871
|
+
const document = this._univerInstanceService.getUnit(id, UniverInstanceType.UNIVER_DOC);
|
|
872
|
+
if (!document) return null;
|
|
873
|
+
return this._injector.createInstance(FDocument, document);
|
|
1391
874
|
}
|
|
1392
875
|
};
|
|
1393
|
-
|
|
876
|
+
FUniver.extend(FUniverDocsMixin);
|
|
1394
877
|
|
|
1395
878
|
//#endregion
|
|
1396
|
-
export { FDocument,
|
|
879
|
+
export { FDocument, FDocumentParagraph, isParagraphFacade, stripBlockTokens };
|