@univerjs/docs 0.25.1 → 1.0.0-alpha.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/lib/cjs/facade.js +1408 -0
- package/lib/cjs/index.js +401 -35
- package/lib/es/facade.js +1396 -0
- package/lib/es/index.js +388 -34
- package/lib/facade.js +1396 -0
- package/lib/index.js +388 -34
- package/lib/types/commands/commands/core-editing.command.d.ts +57 -0
- package/lib/types/facade/f-document-block-range.d.ts +132 -0
- package/lib/types/facade/f-document-body.d.ts +276 -0
- package/lib/types/facade/f-document-custom-block.d.ts +57 -0
- package/lib/types/facade/f-document-element.d.ts +193 -0
- package/lib/types/facade/f-document-paragraph.d.ts +231 -0
- package/lib/types/facade/f-document-table.d.ts +57 -0
- package/lib/types/facade/f-document.d.ts +123 -0
- package/lib/types/facade/f-univer.d.ts +64 -0
- package/lib/types/facade/index.d.ts +23 -0
- package/lib/types/facade/utils.d.ts +24 -0
- package/lib/types/index.d.ts +12 -3
- package/lib/types/services/doc-block-move-validator.service.d.ts +46 -0
- package/lib/types/services/doc-content-insert.service.d.ts +28 -0
- package/lib/types/services/doc-state-change-manager.service.d.ts +53 -0
- package/lib/types/utils/custom-range-factory.d.ts +1 -5
- package/lib/umd/facade.js +1 -0
- package/lib/umd/index.js +1 -1
- package/package.json +15 -5
package/lib/es/facade.js
ADDED
|
@@ -0,0 +1,1396 @@
|
|
|
1
|
+
import { DocumentBlockType, ICommandService, IResourceLoaderService, IUniverInstanceService, Inject, Injector, JSONX, PresetListType, RESTORE_INSERTED_PARAGRAPH_IDS, RedoCommand, TextX, TextXActionType, UndoCommand, UniverInstanceType, UpdateDocsAttributeType, createParagraphId, getRichTextEditPath } from "@univerjs/core";
|
|
2
|
+
import { FBase, FBaseInitialable, FUniver } from "@univerjs/core/facade";
|
|
3
|
+
import { RichTextEditingMutation } from "@univerjs/docs";
|
|
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
|
+
//#region src/facade/utils.ts
|
|
210
|
+
function cloneParagraphStyle(paragraphStyle) {
|
|
211
|
+
return paragraphStyle == null ? paragraphStyle : JSON.parse(JSON.stringify(paragraphStyle));
|
|
212
|
+
}
|
|
213
|
+
function normalizePlainTextDataStream(dataStream) {
|
|
214
|
+
return dataStream.replace(/\r\n/g, "\r").replace(/\n/g, "\r");
|
|
215
|
+
}
|
|
216
|
+
function getRemovedLeadingParagraphBreakLength(dataStream, removeLeadingParagraphBreak) {
|
|
217
|
+
const normalized = normalizePlainTextDataStream(dataStream);
|
|
218
|
+
if (removeLeadingParagraphBreak && normalized.length > 1 && normalized.startsWith("\r")) return 1;
|
|
219
|
+
return 0;
|
|
220
|
+
}
|
|
221
|
+
function buildPlainTextInsertBody(dataStream, options = {}) {
|
|
222
|
+
const normalizedDataStream = normalizePlainTextDataStream(dataStream).slice(getRemovedLeadingParagraphBreakLength(dataStream, options.removeLeadingParagraphBreak));
|
|
223
|
+
const body = {
|
|
224
|
+
dataStream: normalizedDataStream,
|
|
225
|
+
customDecorations: [],
|
|
226
|
+
customRanges: [],
|
|
227
|
+
textRuns: []
|
|
228
|
+
};
|
|
229
|
+
const paragraphs = [];
|
|
230
|
+
const existingParagraphIds = /* @__PURE__ */ new Set();
|
|
231
|
+
for (let index = 0; index < normalizedDataStream.length; index++) if (normalizedDataStream[index] === "\r") paragraphs.push({
|
|
232
|
+
startIndex: index,
|
|
233
|
+
paragraphId: createParagraphId(existingParagraphIds),
|
|
234
|
+
...options.paragraphStyle == null ? {} : { paragraphStyle: cloneParagraphStyle(options.paragraphStyle) }
|
|
235
|
+
});
|
|
236
|
+
if (paragraphs.length > 0) body.paragraphs = paragraphs;
|
|
237
|
+
return body;
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
//#endregion
|
|
241
|
+
//#region src/facade/f-document-paragraph.ts
|
|
242
|
+
/**
|
|
243
|
+
* A paragraph facade wrapper.
|
|
244
|
+
*
|
|
245
|
+
* Paragraph identity is backed by the persisted `paragraphId`. The id is
|
|
246
|
+
* re-resolved before each method call, so insertions before this paragraph do
|
|
247
|
+
* not break the wrapper.
|
|
248
|
+
*
|
|
249
|
+
* @hideconstructor
|
|
250
|
+
*/
|
|
251
|
+
var FDocumentParagraph = class extends FDocumentElement {
|
|
252
|
+
constructor(body, bodyEdit, info, injector) {
|
|
253
|
+
super(body, bodyEdit, info, injector);
|
|
254
|
+
this.body = body;
|
|
255
|
+
this.bodyEdit = bodyEdit;
|
|
256
|
+
this.info = info;
|
|
257
|
+
this.injector = injector;
|
|
258
|
+
if (this.getType() !== DocumentBlockType.PARAGRAPH) throw new Error(`Element type is not a paragraph: ${this.getType()}`);
|
|
259
|
+
}
|
|
260
|
+
/**
|
|
261
|
+
* Get the persisted paragraph id.
|
|
262
|
+
* @returns {string} The paragraph id.
|
|
263
|
+
* @example
|
|
264
|
+
* ```ts
|
|
265
|
+
* const fDocument = univerAPI.getActiveDocument();
|
|
266
|
+
* const fDocumentBody = fDocument.getBody();
|
|
267
|
+
* const element = fDocumentBody.getElement(0);
|
|
268
|
+
*
|
|
269
|
+
* if (element?.isParagraph()) {
|
|
270
|
+
* const paragraph = element.asParagraph();
|
|
271
|
+
* console.log(paragraph.getParagraphId());
|
|
272
|
+
* }
|
|
273
|
+
* ```
|
|
274
|
+
*/
|
|
275
|
+
getParagraphId() {
|
|
276
|
+
return this.getKey();
|
|
277
|
+
}
|
|
278
|
+
/**
|
|
279
|
+
* Get the resolved paragraph info for this wrapper.
|
|
280
|
+
* @returns {IFDocumentResolvedParagraph} The resolved paragraph info, including the paragraph object, its index, and its text range.
|
|
281
|
+
* @example
|
|
282
|
+
* ```ts
|
|
283
|
+
* const fDocument = univerAPI.getActiveDocument();
|
|
284
|
+
* const fDocumentBody = fDocument.getBody();
|
|
285
|
+
* const element = fDocumentBody.getElement(0);
|
|
286
|
+
*
|
|
287
|
+
* if (element?.isParagraph()) {
|
|
288
|
+
* const paragraph = element.asParagraph();
|
|
289
|
+
* console.log(paragraph.getResolvedParagraphInfo());
|
|
290
|
+
* }
|
|
291
|
+
* ```
|
|
292
|
+
*/
|
|
293
|
+
getResolvedParagraphInfo() {
|
|
294
|
+
const { paragraphs = [] } = this._body.getBody();
|
|
295
|
+
const matches = paragraphs.map((paragraph, paragraphIndex) => ({
|
|
296
|
+
paragraph,
|
|
297
|
+
paragraphIndex
|
|
298
|
+
})).filter(({ paragraph }) => paragraph.paragraphId === this.getKey());
|
|
299
|
+
if (matches.length === 0) throw new Error(`Document paragraph with id ${this.getKey()} not found`);
|
|
300
|
+
if (matches.length > 1) throw new Error(`Multiple document paragraphs with id ${this.getKey()} found`);
|
|
301
|
+
const { paragraph, paragraphIndex } = matches[0];
|
|
302
|
+
return {
|
|
303
|
+
paragraph,
|
|
304
|
+
paragraphIndex,
|
|
305
|
+
startOffset: paragraphIndex > 0 ? paragraphs[paragraphIndex - 1].startIndex + 1 : 0,
|
|
306
|
+
endOffset: paragraph.startIndex
|
|
307
|
+
};
|
|
308
|
+
}
|
|
309
|
+
/**
|
|
310
|
+
* Get the current text range occupied by this paragraph.
|
|
311
|
+
* @returns {IFDocumentTextRange} The paragraph text range, excluding the trailing paragraph break.
|
|
312
|
+
* @example
|
|
313
|
+
* ```ts
|
|
314
|
+
* const fDocument = univerAPI.getActiveDocument();
|
|
315
|
+
* const fDocumentBody = fDocument.getBody();
|
|
316
|
+
* const element = fDocumentBody.getElement(0);
|
|
317
|
+
*
|
|
318
|
+
* if (element?.isParagraph()) {
|
|
319
|
+
* const paragraph = element.asParagraph();
|
|
320
|
+
* const range = paragraph.getRange();
|
|
321
|
+
* fDocumentBody.setTextStyle(range, { bl: 1 });
|
|
322
|
+
* }
|
|
323
|
+
* ```
|
|
324
|
+
*/
|
|
325
|
+
getRange() {
|
|
326
|
+
const { startOffset, endOffset } = this.getResolvedParagraphInfo();
|
|
327
|
+
return {
|
|
328
|
+
startOffset,
|
|
329
|
+
endOffset,
|
|
330
|
+
segmentId: this._body.getSegmentId()
|
|
331
|
+
};
|
|
332
|
+
}
|
|
333
|
+
/**
|
|
334
|
+
* Get this paragraph's plain text.
|
|
335
|
+
* @returns {string} The paragraph text without the trailing paragraph break.
|
|
336
|
+
* @example
|
|
337
|
+
* ```ts
|
|
338
|
+
* const fDocument = univerAPI.getActiveDocument();
|
|
339
|
+
* const fDocumentBody = fDocument.getBody();
|
|
340
|
+
* const element = fDocumentBody.getElement(0);
|
|
341
|
+
*
|
|
342
|
+
* if (element?.isParagraph()) {
|
|
343
|
+
* const paragraph = element.asParagraph();
|
|
344
|
+
* console.log(paragraph.getText());
|
|
345
|
+
* }
|
|
346
|
+
* ```
|
|
347
|
+
*/
|
|
348
|
+
getText() {
|
|
349
|
+
const { dataStream } = this._body.getBody();
|
|
350
|
+
const { startOffset, endOffset } = this.getResolvedParagraphInfo();
|
|
351
|
+
return dataStream.slice(startOffset, endOffset);
|
|
352
|
+
}
|
|
353
|
+
/**
|
|
354
|
+
* Replace this paragraph's plain text.
|
|
355
|
+
* @param {string} text The replacement text. Do not include the paragraph break.
|
|
356
|
+
* @returns {boolean} `true` if the paragraph text was replaced.
|
|
357
|
+
* @example
|
|
358
|
+
* ```ts
|
|
359
|
+
* const fDocument = univerAPI.getActiveDocument();
|
|
360
|
+
* const fDocumentBody = fDocument.getBody();
|
|
361
|
+
* const element = fDocumentBody.getElement(0);
|
|
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
|
+
* }
|
|
368
|
+
* ```
|
|
369
|
+
*/
|
|
370
|
+
setText(text) {
|
|
371
|
+
const { startOffset, endOffset } = this.getResolvedParagraphInfo();
|
|
372
|
+
return this._bodyEdit.replaceRange({
|
|
373
|
+
startOffset,
|
|
374
|
+
endOffset
|
|
375
|
+
}, buildPlainTextInsertBody(text));
|
|
376
|
+
}
|
|
377
|
+
/**
|
|
378
|
+
* Append plain text before this paragraph's trailing paragraph break.
|
|
379
|
+
* @param {string} text The plain text to append.
|
|
380
|
+
* @returns {boolean} `true` if the text was appended.
|
|
381
|
+
* @example
|
|
382
|
+
* ```ts
|
|
383
|
+
* const fDocument = univerAPI.getActiveDocument();
|
|
384
|
+
* const fDocumentBody = fDocument.getBody();
|
|
385
|
+
* const element = fDocumentBody.getElement(0);
|
|
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
|
+
* }
|
|
392
|
+
* ```
|
|
393
|
+
*/
|
|
394
|
+
appendText(text) {
|
|
395
|
+
const { endOffset } = this.getResolvedParagraphInfo();
|
|
396
|
+
return this._body.insertText(endOffset, text);
|
|
397
|
+
}
|
|
398
|
+
/**
|
|
399
|
+
* Apply paragraph style to a paragraph handle or text range.
|
|
400
|
+
* @param {IParagraphStyle} style The Univer paragraph style patch.
|
|
401
|
+
* @returns {boolean} `true` if the style was applied.
|
|
402
|
+
* @example
|
|
403
|
+
* ```ts
|
|
404
|
+
* const fDocument = univerAPI.getActiveDocument();
|
|
405
|
+
* const fDocumentBody = fDocument.getBody();
|
|
406
|
+
* const element = fDocumentBody.getElement(0);
|
|
407
|
+
*
|
|
408
|
+
* if (element?.isParagraph()) {
|
|
409
|
+
* const paragraph = element.asParagraph();
|
|
410
|
+
* paragraph.setStyle({ horizontalAlign: 2 });
|
|
411
|
+
* }
|
|
412
|
+
* ```
|
|
413
|
+
*/
|
|
414
|
+
setStyle(style) {
|
|
415
|
+
const { paragraph, endOffset } = this.getResolvedParagraphInfo();
|
|
416
|
+
const updateBody = {
|
|
417
|
+
dataStream: "",
|
|
418
|
+
paragraphs: [{
|
|
419
|
+
...paragraph,
|
|
420
|
+
startIndex: 0,
|
|
421
|
+
paragraphStyle: {
|
|
422
|
+
...paragraph.paragraphStyle,
|
|
423
|
+
...style
|
|
424
|
+
}
|
|
425
|
+
}]
|
|
426
|
+
};
|
|
427
|
+
this._preserveExplicitParagraphIds(updateBody);
|
|
428
|
+
return this._bodyEdit.retainRange({
|
|
429
|
+
startOffset: endOffset,
|
|
430
|
+
endOffset: endOffset + 1
|
|
431
|
+
}, updateBody, UpdateDocsAttributeType.REPLACE);
|
|
432
|
+
}
|
|
433
|
+
/**
|
|
434
|
+
* Check whether this paragraph is a bullet, ordered, or checklist item.
|
|
435
|
+
* @returns {boolean} `true` if the paragraph has list metadata.
|
|
436
|
+
* @example
|
|
437
|
+
* ```ts
|
|
438
|
+
* const fDocument = univerAPI.getActiveDocument();
|
|
439
|
+
* const fDocumentBody = fDocument.getBody();
|
|
440
|
+
* const element = fDocumentBody.getElement(0);
|
|
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
|
+
* }
|
|
446
|
+
* ```
|
|
447
|
+
*/
|
|
448
|
+
isListItem() {
|
|
449
|
+
const { paragraph } = this.getResolvedParagraphInfo();
|
|
450
|
+
return Boolean(paragraph.bullet);
|
|
451
|
+
}
|
|
452
|
+
/**
|
|
453
|
+
* Check whether this paragraph is a task/checklist item.
|
|
454
|
+
* @returns {boolean} `true` if this paragraph is an unchecked or checked task item.
|
|
455
|
+
* @example
|
|
456
|
+
* ```ts
|
|
457
|
+
* const fDocument = univerAPI.getActiveDocument();
|
|
458
|
+
* const fDocumentBody = fDocument.getBody();
|
|
459
|
+
* const element = fDocumentBody.getElement(0);
|
|
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
|
+
* }
|
|
465
|
+
* ```
|
|
466
|
+
*/
|
|
467
|
+
isTask() {
|
|
468
|
+
var _paragraph$bullet;
|
|
469
|
+
const { paragraph } = this.getResolvedParagraphInfo();
|
|
470
|
+
const listType = (_paragraph$bullet = paragraph.bullet) === null || _paragraph$bullet === void 0 ? void 0 : _paragraph$bullet.listType;
|
|
471
|
+
return listType === PresetListType.CHECK_LIST || listType === PresetListType.CHECK_LIST_CHECKED;
|
|
472
|
+
}
|
|
473
|
+
/**
|
|
474
|
+
* Set the checked state of this task/checklist paragraph.
|
|
475
|
+
* @param {boolean} checked Whether the task item should be checked.
|
|
476
|
+
* @returns {boolean} `true` if the task state was updated, or `false` if this paragraph is not a task item.
|
|
477
|
+
* @example
|
|
478
|
+
* ```ts
|
|
479
|
+
* const fDocument = univerAPI.getActiveDocument();
|
|
480
|
+
* const fDocumentBody = fDocument.getBody();
|
|
481
|
+
* const element = fDocumentBody.getElement(0);
|
|
482
|
+
*
|
|
483
|
+
* if (element?.isParagraph()) {
|
|
484
|
+
* const paragraph = element.asParagraph();
|
|
485
|
+
*
|
|
486
|
+
* if (paragraph.isTask()) {
|
|
487
|
+
* const success = paragraph.setTaskChecked(true);
|
|
488
|
+
* console.log(success ? 'Task checked' : 'Failed to check task');
|
|
489
|
+
* }
|
|
490
|
+
* }
|
|
491
|
+
* ```
|
|
492
|
+
*/
|
|
493
|
+
setTaskChecked(checked) {
|
|
494
|
+
if (!this.isTask()) return false;
|
|
495
|
+
const { paragraph, endOffset } = this.getResolvedParagraphInfo();
|
|
496
|
+
const bullet = paragraph.bullet;
|
|
497
|
+
const updateBody = {
|
|
498
|
+
dataStream: "",
|
|
499
|
+
paragraphs: [{
|
|
500
|
+
...paragraph,
|
|
501
|
+
startIndex: 0,
|
|
502
|
+
bullet: {
|
|
503
|
+
...bullet,
|
|
504
|
+
listType: checked ? PresetListType.CHECK_LIST_CHECKED : PresetListType.CHECK_LIST
|
|
505
|
+
}
|
|
506
|
+
}]
|
|
507
|
+
};
|
|
508
|
+
this._preserveExplicitParagraphIds(updateBody);
|
|
509
|
+
return this._bodyEdit.retainRange({
|
|
510
|
+
startOffset: endOffset,
|
|
511
|
+
endOffset: endOffset + 1
|
|
512
|
+
}, updateBody, UpdateDocsAttributeType.REPLACE);
|
|
513
|
+
}
|
|
514
|
+
_preserveExplicitParagraphIds(body) {
|
|
515
|
+
body[RESTORE_INSERTED_PARAGRAPH_IDS] = true;
|
|
516
|
+
}
|
|
517
|
+
};
|
|
518
|
+
var FDocumentParagraphMixin = class extends FDocumentElement {
|
|
519
|
+
asParagraph() {
|
|
520
|
+
if (this.getType() !== DocumentBlockType.PARAGRAPH) throw new Error(`Element type is not a paragraph: ${this.getType()}`);
|
|
521
|
+
return this._injector.createInstance(FDocumentParagraph, this._body, this._bodyEdit, this.getResolvedInfo(), this._injector);
|
|
522
|
+
}
|
|
523
|
+
};
|
|
524
|
+
FDocumentElement.extend(FDocumentParagraphMixin);
|
|
525
|
+
|
|
526
|
+
//#endregion
|
|
527
|
+
//#region \0@oxc-project+runtime@0.137.0/helpers/esm/typeof.js
|
|
528
|
+
function _typeof(o) {
|
|
529
|
+
"@babel/helpers - typeof";
|
|
530
|
+
return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function(o) {
|
|
531
|
+
return typeof o;
|
|
532
|
+
} : function(o) {
|
|
533
|
+
return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o;
|
|
534
|
+
}, _typeof(o);
|
|
535
|
+
}
|
|
536
|
+
|
|
537
|
+
//#endregion
|
|
538
|
+
//#region \0@oxc-project+runtime@0.137.0/helpers/esm/toPrimitive.js
|
|
539
|
+
function toPrimitive(t, r) {
|
|
540
|
+
if ("object" != _typeof(t) || !t) return t;
|
|
541
|
+
var e = t[Symbol.toPrimitive];
|
|
542
|
+
if (void 0 !== e) {
|
|
543
|
+
var i = e.call(t, r || "default");
|
|
544
|
+
if ("object" != _typeof(i)) return i;
|
|
545
|
+
throw new TypeError("@@toPrimitive must return a primitive value.");
|
|
546
|
+
}
|
|
547
|
+
return ("string" === r ? String : Number)(t);
|
|
548
|
+
}
|
|
549
|
+
|
|
550
|
+
//#endregion
|
|
551
|
+
//#region \0@oxc-project+runtime@0.137.0/helpers/esm/toPropertyKey.js
|
|
552
|
+
function toPropertyKey(t) {
|
|
553
|
+
var i = toPrimitive(t, "string");
|
|
554
|
+
return "symbol" == _typeof(i) ? i : i + "";
|
|
555
|
+
}
|
|
556
|
+
|
|
557
|
+
//#endregion
|
|
558
|
+
//#region \0@oxc-project+runtime@0.137.0/helpers/esm/defineProperty.js
|
|
559
|
+
function _defineProperty(e, r, t) {
|
|
560
|
+
return (r = toPropertyKey(r)) in e ? Object.defineProperty(e, r, {
|
|
561
|
+
value: t,
|
|
562
|
+
enumerable: !0,
|
|
563
|
+
configurable: !0,
|
|
564
|
+
writable: !0
|
|
565
|
+
}) : e[r] = t, e;
|
|
566
|
+
}
|
|
567
|
+
|
|
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
|
+
//#endregion
|
|
998
|
+
//#region \0@oxc-project+runtime@0.137.0/helpers/esm/decorateParam.js
|
|
999
|
+
function __decorateParam(paramIndex, decorator) {
|
|
1000
|
+
return function(target, key) {
|
|
1001
|
+
decorator(target, key, paramIndex);
|
|
1002
|
+
};
|
|
1003
|
+
}
|
|
1004
|
+
|
|
1005
|
+
//#endregion
|
|
1006
|
+
//#region \0@oxc-project+runtime@0.137.0/helpers/esm/decorate.js
|
|
1007
|
+
function __decorate(decorators, target, key, desc) {
|
|
1008
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
1009
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
1010
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
1011
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
1012
|
+
}
|
|
1013
|
+
|
|
1014
|
+
//#endregion
|
|
1015
|
+
//#region src/facade/f-document.ts
|
|
1016
|
+
let FDocument = class FDocument extends FBaseInitialable {
|
|
1017
|
+
constructor(_documentDataModel, _injector, _univerInstanceService, _resourceLoaderService, _commandService) {
|
|
1018
|
+
super(_injector);
|
|
1019
|
+
this._documentDataModel = _documentDataModel;
|
|
1020
|
+
this._injector = _injector;
|
|
1021
|
+
this._univerInstanceService = _univerInstanceService;
|
|
1022
|
+
this._resourceLoaderService = _resourceLoaderService;
|
|
1023
|
+
this._commandService = _commandService;
|
|
1024
|
+
_defineProperty(this, "id", void 0);
|
|
1025
|
+
this.id = this._documentDataModel.getUnitId();
|
|
1026
|
+
}
|
|
1027
|
+
/**
|
|
1028
|
+
* Get the document data model of the document.
|
|
1029
|
+
* @returns {DocumentDataModel} The document data model.
|
|
1030
|
+
* @example
|
|
1031
|
+
* ```typescript
|
|
1032
|
+
* const fDocument = univerAPI.getActiveDocument();
|
|
1033
|
+
* const documentDataModel = fDocument.getDocumentDataModel();
|
|
1034
|
+
* console.log(documentDataModel);
|
|
1035
|
+
* ```
|
|
1036
|
+
*/
|
|
1037
|
+
getDocumentDataModel() {
|
|
1038
|
+
return this._documentDataModel;
|
|
1039
|
+
}
|
|
1040
|
+
/**
|
|
1041
|
+
* Get the document body facade.
|
|
1042
|
+
*
|
|
1043
|
+
* The returned body facade provides synchronous Google Docs-like element APIs
|
|
1044
|
+
* for reading and editing top-level document body elements. Paragraph elements
|
|
1045
|
+
* use their persisted `paragraphId` values. Persisted elements, such as tables
|
|
1046
|
+
* and custom blocks, use their existing ids.
|
|
1047
|
+
*
|
|
1048
|
+
* @returns {FDocumentBody} The document body API instance.
|
|
1049
|
+
* @example
|
|
1050
|
+
* ```typescript
|
|
1051
|
+
* const fDocument = univerAPI.getActiveDocument();
|
|
1052
|
+
* const fDocumentBody = fDocument.getBody();
|
|
1053
|
+
* console.log(fDocumentBody.getBody());
|
|
1054
|
+
*
|
|
1055
|
+
* const element = fDocumentBody.getElement(0);
|
|
1056
|
+
* if (element.isParagraph()) {
|
|
1057
|
+
* const paragraph = element.asParagraph();
|
|
1058
|
+
* paragraph.appendText(' updated');
|
|
1059
|
+
* console.log(paragraph.getText());
|
|
1060
|
+
* }
|
|
1061
|
+
* ```
|
|
1062
|
+
*/
|
|
1063
|
+
getBody() {
|
|
1064
|
+
return this._injector.createInstance(FDocumentBody, this._documentDataModel, this._injector);
|
|
1065
|
+
}
|
|
1066
|
+
dispose() {
|
|
1067
|
+
super.dispose();
|
|
1068
|
+
}
|
|
1069
|
+
/**
|
|
1070
|
+
* Get the document id.
|
|
1071
|
+
* @returns {string} The document id.
|
|
1072
|
+
* @example
|
|
1073
|
+
* ```typescript
|
|
1074
|
+
* const fDocument = univerAPI.getActiveDocument();
|
|
1075
|
+
* const unitId = fDocument.getId();
|
|
1076
|
+
* console.log(unitId);
|
|
1077
|
+
* ```
|
|
1078
|
+
*/
|
|
1079
|
+
getId() {
|
|
1080
|
+
return this.id;
|
|
1081
|
+
}
|
|
1082
|
+
/**
|
|
1083
|
+
* Get the document name.
|
|
1084
|
+
* @returns {string} The document name.
|
|
1085
|
+
* @example
|
|
1086
|
+
* ```typescript
|
|
1087
|
+
* const fDocument = univerAPI.getActiveDocument();
|
|
1088
|
+
* const name = fDocument.getName();
|
|
1089
|
+
* console.log(name);
|
|
1090
|
+
* ```
|
|
1091
|
+
*/
|
|
1092
|
+
getName() {
|
|
1093
|
+
return this._documentDataModel.getTitle() || "";
|
|
1094
|
+
}
|
|
1095
|
+
/**
|
|
1096
|
+
* Save the document snapshot data, including the document content and resource data, etc.
|
|
1097
|
+
* @returns {IDocumentData} The document snapshot data.
|
|
1098
|
+
* @example
|
|
1099
|
+
* ```typescript
|
|
1100
|
+
* const fDocument = univerAPI.getActiveDocument();
|
|
1101
|
+
* const snapshot = fDocument.save();
|
|
1102
|
+
* console.log(snapshot);
|
|
1103
|
+
* ```
|
|
1104
|
+
*/
|
|
1105
|
+
save() {
|
|
1106
|
+
return this._resourceLoaderService.saveUnit(this._documentDataModel.getUnitId());
|
|
1107
|
+
}
|
|
1108
|
+
/**
|
|
1109
|
+
* Undo the last operation in the document.
|
|
1110
|
+
* @returns {boolean} `true` if the undo operation was successful, or `false` if it failed.
|
|
1111
|
+
* @example
|
|
1112
|
+
* ```typescript
|
|
1113
|
+
* const fDocument = univerAPI.getActiveDocument();
|
|
1114
|
+
* const success = fDocument.undo();
|
|
1115
|
+
* console.log(success);
|
|
1116
|
+
* ```
|
|
1117
|
+
*/
|
|
1118
|
+
undo() {
|
|
1119
|
+
this._univerInstanceService.focusUnit(this.id);
|
|
1120
|
+
return this._commandService.syncExecuteCommand(UndoCommand.id);
|
|
1121
|
+
}
|
|
1122
|
+
/**
|
|
1123
|
+
* Redo the last undone operation in the document.
|
|
1124
|
+
* @returns {boolean} `true` if the redo operation was successful, or `false` if it failed.
|
|
1125
|
+
* @example
|
|
1126
|
+
* ```typescript
|
|
1127
|
+
* const fDocument = univerAPI.getActiveDocument();
|
|
1128
|
+
* const success = fDocument.redo();
|
|
1129
|
+
* console.log(success);
|
|
1130
|
+
* ```
|
|
1131
|
+
*/
|
|
1132
|
+
redo() {
|
|
1133
|
+
this._univerInstanceService.focusUnit(this.id);
|
|
1134
|
+
return this._commandService.syncExecuteCommand(RedoCommand.id);
|
|
1135
|
+
}
|
|
1136
|
+
};
|
|
1137
|
+
FDocument = __decorate([
|
|
1138
|
+
__decorateParam(1, Inject(Injector)),
|
|
1139
|
+
__decorateParam(2, IUniverInstanceService),
|
|
1140
|
+
__decorateParam(3, Inject(IResourceLoaderService)),
|
|
1141
|
+
__decorateParam(4, ICommandService)
|
|
1142
|
+
], FDocument);
|
|
1143
|
+
|
|
1144
|
+
//#endregion
|
|
1145
|
+
//#region src/facade/f-univer.ts
|
|
1146
|
+
var FUniverDocsMixin = class extends FUniver {
|
|
1147
|
+
createDocument(data) {
|
|
1148
|
+
const document = this._injector.get(IUniverInstanceService).createUnit(UniverInstanceType.UNIVER_DOC, data);
|
|
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);
|
|
1160
|
+
}
|
|
1161
|
+
};
|
|
1162
|
+
FUniver.extend(FUniverDocsMixin);
|
|
1163
|
+
|
|
1164
|
+
//#endregion
|
|
1165
|
+
//#region src/facade/f-document-block-range.ts
|
|
1166
|
+
/**
|
|
1167
|
+
* A facade wrapper for document block ranges, such as callout, quote, and code blocks.
|
|
1168
|
+
*
|
|
1169
|
+
* Block range identity is backed by the persisted `IDocumentBlockRange.blockId`,
|
|
1170
|
+
* so wrappers can be re-resolved after text is inserted before the block range.
|
|
1171
|
+
*
|
|
1172
|
+
* @hideconstructor
|
|
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()}`);
|
|
1182
|
+
}
|
|
1183
|
+
/**
|
|
1184
|
+
* Get the top-level block range data model.
|
|
1185
|
+
* @returns {IDocumentBlockRange} The block range data model.
|
|
1186
|
+
* @example
|
|
1187
|
+
* ```ts
|
|
1188
|
+
* const fDocument = univerAPI.getActiveDocument();
|
|
1189
|
+
* const fDocumentBody = fDocument.getBody();
|
|
1190
|
+
* const element = fDocumentBody.getElement(0);
|
|
1191
|
+
*
|
|
1192
|
+
* if (element?.isBlockRange()) {
|
|
1193
|
+
* const blockRange = element.asBlockRange();
|
|
1194
|
+
* console.log(blockRange.getBlockRange());
|
|
1195
|
+
* }
|
|
1196
|
+
* ```
|
|
1197
|
+
*/
|
|
1198
|
+
getBlockRange() {
|
|
1199
|
+
const { blockRanges = [] } = this._body.getBody();
|
|
1200
|
+
const blockRange = blockRanges.find((blockRange) => blockRange.blockId === this.getKey());
|
|
1201
|
+
if (!blockRange) throw new Error(`Block range not found: ${this.getKey()}`);
|
|
1202
|
+
return blockRange;
|
|
1203
|
+
}
|
|
1204
|
+
/**
|
|
1205
|
+
* Get the block range type.
|
|
1206
|
+
* @returns {DocumentBlockRangeType} The block type, such as callout, quote, or code.
|
|
1207
|
+
* @example
|
|
1208
|
+
* ```ts
|
|
1209
|
+
* const fDocument = univerAPI.getActiveDocument();
|
|
1210
|
+
* const fDocumentBody = fDocument.getBody();
|
|
1211
|
+
* const element = fDocumentBody.getElement(0);
|
|
1212
|
+
*
|
|
1213
|
+
* if (element?.isBlockRange()) {
|
|
1214
|
+
* const blockRange = element.asBlockRange();
|
|
1215
|
+
* console.log(blockRange.getBlockType());
|
|
1216
|
+
* }
|
|
1217
|
+
* ```
|
|
1218
|
+
*/
|
|
1219
|
+
getBlockType() {
|
|
1220
|
+
return this.getBlockRange().blockType;
|
|
1221
|
+
}
|
|
1222
|
+
/**
|
|
1223
|
+
* Get the plain text inside this block range.
|
|
1224
|
+
* @returns {string} The block range text.
|
|
1225
|
+
* @example
|
|
1226
|
+
* ```ts
|
|
1227
|
+
* const fDocument = univerAPI.getActiveDocument();
|
|
1228
|
+
* const fDocumentBody = fDocument.getBody();
|
|
1229
|
+
* const element = fDocumentBody.getElement(0);
|
|
1230
|
+
*
|
|
1231
|
+
* if (element?.isBlockRange()) {
|
|
1232
|
+
* const blockRange = element.asBlockRange();
|
|
1233
|
+
* console.log(blockRange.getText());
|
|
1234
|
+
* }
|
|
1235
|
+
* ```
|
|
1236
|
+
*/
|
|
1237
|
+
getText() {
|
|
1238
|
+
const { dataStream } = this._body.getBody();
|
|
1239
|
+
const { startIndex, endIndex } = this.getBlockRange();
|
|
1240
|
+
return dataStream.slice(startIndex, endIndex);
|
|
1241
|
+
}
|
|
1242
|
+
/**
|
|
1243
|
+
* Replace the plain text inside this block range.
|
|
1244
|
+
* @param {string} text The replacement text.
|
|
1245
|
+
* @returns {boolean} `true` if the block range text was replaced.
|
|
1246
|
+
* @example
|
|
1247
|
+
* ```ts
|
|
1248
|
+
* const fDocument = univerAPI.getActiveDocument();
|
|
1249
|
+
* const fDocumentBody = fDocument.getBody();
|
|
1250
|
+
* const element = fDocumentBody.getElement(0);
|
|
1251
|
+
*
|
|
1252
|
+
* if (element?.isBlockRange()) {
|
|
1253
|
+
* const blockRange = element.asBlockRange();
|
|
1254
|
+
* blockRange.setText('Updated block text');
|
|
1255
|
+
* console.log(blockRange.getText());
|
|
1256
|
+
* }
|
|
1257
|
+
* ```
|
|
1258
|
+
*/
|
|
1259
|
+
setText(text) {
|
|
1260
|
+
const blockRange = this.getBlockRange();
|
|
1261
|
+
const { startIndex, endIndex } = blockRange;
|
|
1262
|
+
const updateBody = buildPlainTextInsertBody(`${text}\r`);
|
|
1263
|
+
updateBody.blockRanges = [{
|
|
1264
|
+
...blockRange,
|
|
1265
|
+
startIndex: 0,
|
|
1266
|
+
endIndex: text.length
|
|
1267
|
+
}];
|
|
1268
|
+
return this._bodyEdit.replaceRange({
|
|
1269
|
+
startOffset: startIndex,
|
|
1270
|
+
endOffset: endIndex + 1
|
|
1271
|
+
}, updateBody);
|
|
1272
|
+
}
|
|
1273
|
+
/**
|
|
1274
|
+
* Remove this block range wrapper from the body.
|
|
1275
|
+
*
|
|
1276
|
+
* This currently removes the block range and its content, matching
|
|
1277
|
+
* `remove()`.
|
|
1278
|
+
*
|
|
1279
|
+
* @returns {boolean} `true` if the block range content was removed.
|
|
1280
|
+
* @example
|
|
1281
|
+
* ```ts
|
|
1282
|
+
* const fDocument = univerAPI.getActiveDocument();
|
|
1283
|
+
* const fDocumentBody = fDocument.getBody();
|
|
1284
|
+
* const element = fDocumentBody.getElement(0);
|
|
1285
|
+
*
|
|
1286
|
+
* if (element?.isBlockRange()) {
|
|
1287
|
+
* const blockRange = element.asBlockRange();
|
|
1288
|
+
* const removed = blockRange.unwrap();
|
|
1289
|
+
* console.log(removed ? 'Block range removed' : 'Failed to remove block range');
|
|
1290
|
+
* }
|
|
1291
|
+
* ```
|
|
1292
|
+
*/
|
|
1293
|
+
unwrap() {
|
|
1294
|
+
return this.remove();
|
|
1295
|
+
}
|
|
1296
|
+
};
|
|
1297
|
+
var FDocumentBlockRangeMixin = class extends FDocumentElement {
|
|
1298
|
+
asBlockRange() {
|
|
1299
|
+
if (this.getType() !== DocumentBlockType.BLOCK_RANGE) throw new Error(`Element type is not a block range: ${this.getType()}`);
|
|
1300
|
+
return this._injector.createInstance(FDocumentBlockRange, this._body, this._bodyEdit, this.getResolvedInfo(), this._injector);
|
|
1301
|
+
}
|
|
1302
|
+
};
|
|
1303
|
+
FDocumentElement.extend(FDocumentBlockRangeMixin);
|
|
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()}`);
|
|
1319
|
+
}
|
|
1320
|
+
/**
|
|
1321
|
+
* Get the custom block marker.
|
|
1322
|
+
* @returns {ICustomBlock} The custom block marker.
|
|
1323
|
+
* @example
|
|
1324
|
+
* ```ts
|
|
1325
|
+
* const fDocument = univerAPI.getActiveDocument();
|
|
1326
|
+
* const fDocumentBody = fDocument.getBody();
|
|
1327
|
+
* const element = fDocumentBody.getElement(0);
|
|
1328
|
+
*
|
|
1329
|
+
* if (element?.isCustomBlock()) {
|
|
1330
|
+
* const customBlock = element.asCustomBlock();
|
|
1331
|
+
* console.log(customBlock.getCustomBlock());
|
|
1332
|
+
* }
|
|
1333
|
+
* ```
|
|
1334
|
+
*/
|
|
1335
|
+
getCustomBlock() {
|
|
1336
|
+
const { customBlocks = [] } = this._body.getBody();
|
|
1337
|
+
const block = customBlocks.find((item) => item.blockId === this.getKey());
|
|
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()}`);
|
|
1364
|
+
}
|
|
1365
|
+
/**
|
|
1366
|
+
* Get the table marker.
|
|
1367
|
+
* @returns {ICustomTable} The table marker.
|
|
1368
|
+
* @example
|
|
1369
|
+
* ```ts
|
|
1370
|
+
* const fDocument = univerAPI.getActiveDocument();
|
|
1371
|
+
* const fDocumentBody = fDocument.getBody();
|
|
1372
|
+
* const element = fDocumentBody.getElement(0);
|
|
1373
|
+
*
|
|
1374
|
+
* if (element?.isTable()) {
|
|
1375
|
+
* const table = element.asTable();
|
|
1376
|
+
* console.log(table.getTable());
|
|
1377
|
+
* }
|
|
1378
|
+
* ```
|
|
1379
|
+
*/
|
|
1380
|
+
getTable() {
|
|
1381
|
+
const { tables = [] } = this._body.getBody();
|
|
1382
|
+
const table = tables.find((item) => item.tableId === this.getKey());
|
|
1383
|
+
if (!table) throw new Error("Doc table is stale");
|
|
1384
|
+
return table;
|
|
1385
|
+
}
|
|
1386
|
+
};
|
|
1387
|
+
var FDocumentTableMixin = class extends FDocumentElement {
|
|
1388
|
+
asTable() {
|
|
1389
|
+
if (this.getType() !== DocumentBlockType.TABLE) throw new Error(`Element type is not a table: ${this.getType()}`);
|
|
1390
|
+
return this._injector.createInstance(FDocumentTable, this._body, this._bodyEdit, this.getResolvedInfo(), this._injector);
|
|
1391
|
+
}
|
|
1392
|
+
};
|
|
1393
|
+
FDocumentElement.extend(FDocumentTableMixin);
|
|
1394
|
+
|
|
1395
|
+
//#endregion
|
|
1396
|
+
export { FDocument, FDocumentBlockRange, FDocumentBody, FDocumentCustomBlock, FDocumentElement, FDocumentParagraph, FDocumentTable };
|