@univerjs/docs 1.0.0-alpha.0 → 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 +537 -1628
- package/lib/cjs/index.js +187 -9
- package/lib/es/facade.js +535 -1621
- package/lib/es/index.js +184 -11
- package/lib/facade.js +535 -1621
- package/lib/index.js +184 -11
- package/lib/types/commands/commands/create-header-footer.command.d.ts +41 -0
- package/lib/types/facade/f-document-paragraph.d.ts +204 -0
- package/lib/types/facade/f-document.d.ts +178 -89
- package/lib/types/facade/index.d.ts +4 -8
- package/lib/types/facade/utils.d.ts +16 -4
- package/lib/types/index.d.ts +5 -0
- package/lib/types/services/doc-block-move-validator.service.d.ts +46 -0
- package/lib/types/utils/util.d.ts +19 -0
- package/lib/umd/facade.js +3 -5
- package/lib/umd/index.js +2 -1
- package/package.json +4 -4
- package/lib/types/facade/doc-element-registry.d.ts +0 -84
- package/lib/types/facade/f-doc-block-range.d.ts +0 -139
- package/lib/types/facade/f-doc-body.d.ts +0 -535
- package/lib/types/facade/f-doc-custom-block.d.ts +0 -94
- package/lib/types/facade/f-doc-element.d.ts +0 -177
- package/lib/types/facade/f-doc-paragraph.d.ts +0 -194
- package/lib/types/facade/f-doc-table.d.ts +0 -94
package/lib/cjs/facade.js
CHANGED
|
@@ -3,87 +3,6 @@ let _univerjs_core = require("@univerjs/core");
|
|
|
3
3
|
let _univerjs_core_facade = require("@univerjs/core/facade");
|
|
4
4
|
let _univerjs_docs = require("@univerjs/docs");
|
|
5
5
|
|
|
6
|
-
//#region src/facade/doc-element-registry.ts
|
|
7
|
-
const PARAGRAPH_REGISTRY_MIGRATION_ERROR = "DocElementRegistry no longer tracks paragraph identity; use paragraphId.";
|
|
8
|
-
/**
|
|
9
|
-
* Error thrown when a facade element key can no longer be resolved uniquely.
|
|
10
|
-
*
|
|
11
|
-
* A stale paragraph usually means the paragraph was deleted, or the document no
|
|
12
|
-
* longer contains exactly one paragraph with the requested `paragraphId`.
|
|
13
|
-
*
|
|
14
|
-
* @example
|
|
15
|
-
* ```ts
|
|
16
|
-
* const doc = univerAPI.getActiveDocument();
|
|
17
|
-
* if (!doc) throw new Error('No active document');
|
|
18
|
-
*
|
|
19
|
-
* const paragraph = doc.getBody().getChild(0).asParagraph();
|
|
20
|
-
* paragraph.removeFromParent();
|
|
21
|
-
*
|
|
22
|
-
* try {
|
|
23
|
-
* paragraph.getText();
|
|
24
|
-
* } catch (error) {
|
|
25
|
-
* if (error instanceof DocElementStaleError) {
|
|
26
|
-
* console.log('The paragraph handle is stale.');
|
|
27
|
-
* }
|
|
28
|
-
* }
|
|
29
|
-
* ```
|
|
30
|
-
*/
|
|
31
|
-
var DocElementStaleError = class extends Error {
|
|
32
|
-
/**
|
|
33
|
-
* Create a stale element error.
|
|
34
|
-
* @param {string} message The error message.
|
|
35
|
-
*/
|
|
36
|
-
constructor(message = "Doc element is stale") {
|
|
37
|
-
super(message);
|
|
38
|
-
this.name = "DocElementStaleError";
|
|
39
|
-
}
|
|
40
|
-
};
|
|
41
|
-
/**
|
|
42
|
-
* @deprecated Paragraph facade identity is now resolved directly from persisted
|
|
43
|
-
* `paragraphId` values. This class remains as a compatibility shell for callers
|
|
44
|
-
* that constructed document facade internals directly.
|
|
45
|
-
*
|
|
46
|
-
* @hideconstructor
|
|
47
|
-
*/
|
|
48
|
-
var DocElementRegistry = class {
|
|
49
|
-
/**
|
|
50
|
-
* @deprecated Paragraph facade identity is now the persisted `paragraphId`.
|
|
51
|
-
* @throws {Error} Always throws; use `paragraph.paragraphId` instead.
|
|
52
|
-
*/
|
|
53
|
-
getParagraphKey(_segmentId, _body, _paragraphIndex) {
|
|
54
|
-
throw new Error(PARAGRAPH_REGISTRY_MIGRATION_ERROR);
|
|
55
|
-
}
|
|
56
|
-
/**
|
|
57
|
-
* @deprecated Paragraph facade identity is now the persisted `paragraphId`.
|
|
58
|
-
* @throws {Error} Always throws; resolve paragraph handles by `paragraphId` instead.
|
|
59
|
-
*/
|
|
60
|
-
resolveParagraphStartIndex(_segmentId, _key) {
|
|
61
|
-
throw new Error(PARAGRAPH_REGISTRY_MIGRATION_ERROR);
|
|
62
|
-
}
|
|
63
|
-
/**
|
|
64
|
-
* @deprecated Paragraph facade identity is now the persisted `paragraphId`.
|
|
65
|
-
* @throws {Error} Always throws; resolve paragraph handles by `paragraphId` instead.
|
|
66
|
-
*/
|
|
67
|
-
syncParagraph(_segmentId, _key, _body) {
|
|
68
|
-
throw new Error(PARAGRAPH_REGISTRY_MIGRATION_ERROR);
|
|
69
|
-
}
|
|
70
|
-
/**
|
|
71
|
-
* @deprecated Paragraph facade identity is now the persisted `paragraphId`.
|
|
72
|
-
* @throws {Error} Always throws; stale state is detected from live `paragraphId` lookups.
|
|
73
|
-
*/
|
|
74
|
-
markStale(_segmentId, _key) {
|
|
75
|
-
throw new Error(PARAGRAPH_REGISTRY_MIGRATION_ERROR);
|
|
76
|
-
}
|
|
77
|
-
/**
|
|
78
|
-
* @deprecated Paragraph facade identity is now the persisted `paragraphId`.
|
|
79
|
-
* @throws {Error} Always throws; text edits no longer need registry offset tracking.
|
|
80
|
-
*/
|
|
81
|
-
beforeTextEdit(_segmentId, _startOffset, _endOffset, _insertLength) {
|
|
82
|
-
throw new Error(PARAGRAPH_REGISTRY_MIGRATION_ERROR);
|
|
83
|
-
}
|
|
84
|
-
};
|
|
85
|
-
|
|
86
|
-
//#endregion
|
|
87
6
|
//#region src/facade/utils.ts
|
|
88
7
|
function cloneParagraphStyle(paragraphStyle) {
|
|
89
8
|
return paragraphStyle == null ? paragraphStyle : JSON.parse(JSON.stringify(paragraphStyle));
|
|
@@ -96,16 +15,6 @@ function getRemovedLeadingParagraphBreakLength(dataStream, removeLeadingParagrap
|
|
|
96
15
|
if (removeLeadingParagraphBreak && normalized.length > 1 && normalized.startsWith("\r")) return 1;
|
|
97
16
|
return 0;
|
|
98
17
|
}
|
|
99
|
-
function getNormalizedPlainTextCursorOffset(dataStream, cursorOffset, removeLeadingParagraphBreak) {
|
|
100
|
-
const normalizedPrefixLength = normalizePlainTextDataStream(dataStream.slice(0, cursorOffset)).length;
|
|
101
|
-
return Math.max(0, normalizedPrefixLength - getRemovedLeadingParagraphBreakLength(dataStream, removeLeadingParagraphBreak));
|
|
102
|
-
}
|
|
103
|
-
function getParagraphStyleAtOffset(body, offset) {
|
|
104
|
-
var _body$paragraphs, _paragraphs$find;
|
|
105
|
-
const paragraphs = (_body$paragraphs = body.paragraphs) !== null && _body$paragraphs !== void 0 ? _body$paragraphs : [];
|
|
106
|
-
const paragraph = (_paragraphs$find = paragraphs.find((item) => item.startIndex >= offset)) !== null && _paragraphs$find !== void 0 ? _paragraphs$find : paragraphs[paragraphs.length - 1];
|
|
107
|
-
return paragraph === null || paragraph === void 0 ? void 0 : paragraph.paragraphStyle;
|
|
108
|
-
}
|
|
109
18
|
function buildPlainTextInsertBody(dataStream, options = {}) {
|
|
110
19
|
const normalizedDataStream = normalizePlainTextDataStream(dataStream).slice(getRemovedLeadingParagraphBreakLength(dataStream, options.removeLeadingParagraphBreak));
|
|
111
20
|
const body = {
|
|
@@ -124,243 +33,73 @@ function buildPlainTextInsertBody(dataStream, options = {}) {
|
|
|
124
33
|
if (paragraphs.length > 0) body.paragraphs = paragraphs;
|
|
125
34
|
return body;
|
|
126
35
|
}
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
* const blockRange = doc.getBody().getChild(0).asBlockRange();
|
|
167
|
-
* console.log(blockRange.getKey());
|
|
168
|
-
* ```
|
|
169
|
-
*/
|
|
170
|
-
getKey() {
|
|
171
|
-
return this._key;
|
|
172
|
-
}
|
|
173
|
-
/**
|
|
174
|
-
* Get the parent body facade that owns this block range.
|
|
175
|
-
* @returns {FDocBody} The document body facade.
|
|
176
|
-
* @example
|
|
177
|
-
* ```ts
|
|
178
|
-
* const doc = univerAPI.getActiveDocument();
|
|
179
|
-
* if (!doc) throw new Error('No active document');
|
|
180
|
-
*
|
|
181
|
-
* const blockRange = doc.getBody().getChild(0).asBlockRange();
|
|
182
|
-
* console.log(blockRange.getParent().getChildIndex(blockRange));
|
|
183
|
-
* ```
|
|
184
|
-
*/
|
|
185
|
-
getParent() {
|
|
186
|
-
return this._body;
|
|
187
|
-
}
|
|
188
|
-
/**
|
|
189
|
-
* Remove this block range and its content from the parent body.
|
|
190
|
-
* @returns {boolean} `true` if the block range content was removed.
|
|
191
|
-
* @example
|
|
192
|
-
* ```ts
|
|
193
|
-
* const doc = univerAPI.getActiveDocument();
|
|
194
|
-
* if (!doc) throw new Error('No active document');
|
|
195
|
-
*
|
|
196
|
-
* const blockRange = doc.getBody().getChild(0).asBlockRange();
|
|
197
|
-
* blockRange.removeFromParent();
|
|
198
|
-
* ```
|
|
199
|
-
*/
|
|
200
|
-
removeFromParent() {
|
|
201
|
-
return this._body.removeBlockRange(this._key);
|
|
202
|
-
}
|
|
203
|
-
/**
|
|
204
|
-
* Get the block range type.
|
|
205
|
-
* @returns {DocumentBlockRangeType} The block type, such as callout, quote, or code.
|
|
206
|
-
* @example
|
|
207
|
-
* ```ts
|
|
208
|
-
* const doc = univerAPI.getActiveDocument();
|
|
209
|
-
* if (!doc) throw new Error('No active document');
|
|
210
|
-
*
|
|
211
|
-
* const blockRange = doc.getBody().getChild(0).asBlockRange();
|
|
212
|
-
* console.log(blockRange.getBlockType());
|
|
213
|
-
* ```
|
|
214
|
-
*/
|
|
215
|
-
getBlockType() {
|
|
216
|
-
return this._body.getBlockRange(this._key).blockType;
|
|
217
|
-
}
|
|
218
|
-
/**
|
|
219
|
-
* Get the plain text inside this block range.
|
|
220
|
-
* @returns {string} The block range text.
|
|
221
|
-
* @example
|
|
222
|
-
* ```ts
|
|
223
|
-
* const doc = univerAPI.getActiveDocument();
|
|
224
|
-
* if (!doc) throw new Error('No active document');
|
|
225
|
-
*
|
|
226
|
-
* const blockRange = doc.getBody().getChild(0).asBlockRange();
|
|
227
|
-
* console.log(blockRange.getText());
|
|
228
|
-
* ```
|
|
229
|
-
*/
|
|
230
|
-
getText() {
|
|
231
|
-
return this._body.getBlockRangeText(this._key);
|
|
232
|
-
}
|
|
233
|
-
/**
|
|
234
|
-
* Replace the plain text inside this block range.
|
|
235
|
-
* @param {string} text The replacement text.
|
|
236
|
-
* @returns {boolean} `true` if the block range text was replaced.
|
|
237
|
-
* @example
|
|
238
|
-
* ```ts
|
|
239
|
-
* const doc = univerAPI.getActiveDocument();
|
|
240
|
-
* if (!doc) throw new Error('No active document');
|
|
241
|
-
*
|
|
242
|
-
* const blockRange = doc.getBody().getChild(0).asBlockRange();
|
|
243
|
-
* blockRange.setText('Updated block text');
|
|
244
|
-
* ```
|
|
245
|
-
*/
|
|
246
|
-
setText(text) {
|
|
247
|
-
return this._body.setBlockRangeText(this._key, text);
|
|
248
|
-
}
|
|
249
|
-
/**
|
|
250
|
-
* Remove this block range wrapper from the body.
|
|
251
|
-
*
|
|
252
|
-
* This currently removes the block range and its content, matching
|
|
253
|
-
* `removeFromParent()`.
|
|
254
|
-
*
|
|
255
|
-
* @returns {boolean} `true` if the block range content was removed.
|
|
256
|
-
* @example
|
|
257
|
-
* ```ts
|
|
258
|
-
* const doc = univerAPI.getActiveDocument();
|
|
259
|
-
* if (!doc) throw new Error('No active document');
|
|
260
|
-
*
|
|
261
|
-
* const blockRange = doc.getBody().getChild(0).asBlockRange();
|
|
262
|
-
* blockRange.unwrap();
|
|
263
|
-
* ```
|
|
264
|
-
*/
|
|
265
|
-
unwrap() {
|
|
266
|
-
return this.removeFromParent();
|
|
267
|
-
}
|
|
268
|
-
};
|
|
269
|
-
|
|
270
|
-
//#endregion
|
|
271
|
-
//#region src/facade/f-doc-custom-block.ts
|
|
272
|
-
/**
|
|
273
|
-
* A facade wrapper for a document custom block, such as an embedded drawing or widget.
|
|
274
|
-
*
|
|
275
|
-
* Custom block identity is backed by the persisted `ICustomBlock.blockId`, so the
|
|
276
|
-
* wrapper can be re-resolved after text is inserted before the custom block.
|
|
277
|
-
*
|
|
278
|
-
* @hideconstructor
|
|
279
|
-
*/
|
|
280
|
-
var FDocCustomBlock = class {
|
|
281
|
-
constructor(_body, _key) {
|
|
282
|
-
this._body = _body;
|
|
283
|
-
this._key = _key;
|
|
284
|
-
}
|
|
285
|
-
/**
|
|
286
|
-
* Get the document element type.
|
|
287
|
-
* @returns {'customBlock'} The literal custom block element type.
|
|
288
|
-
* @example
|
|
289
|
-
* ```ts
|
|
290
|
-
* const doc = univerAPI.getActiveDocument();
|
|
291
|
-
* if (!doc) throw new Error('No active document');
|
|
292
|
-
*
|
|
293
|
-
* const customBlock = doc.getBody().getChild(0).asCustomBlock();
|
|
294
|
-
* console.log(customBlock.getType());
|
|
295
|
-
* ```
|
|
296
|
-
*/
|
|
297
|
-
getType() {
|
|
298
|
-
return "customBlock";
|
|
299
|
-
}
|
|
300
|
-
/**
|
|
301
|
-
* Get the custom block key.
|
|
302
|
-
* @returns {string} The persisted `blockId` for this custom block.
|
|
303
|
-
* @example
|
|
304
|
-
* ```ts
|
|
305
|
-
* const doc = univerAPI.getActiveDocument();
|
|
306
|
-
* if (!doc) throw new Error('No active document');
|
|
307
|
-
*
|
|
308
|
-
* const customBlock = doc.getBody().getChild(0).asCustomBlock();
|
|
309
|
-
* console.log(customBlock.getKey());
|
|
310
|
-
* ```
|
|
311
|
-
*/
|
|
312
|
-
getKey() {
|
|
313
|
-
return this._key;
|
|
314
|
-
}
|
|
315
|
-
/**
|
|
316
|
-
* Get the parent body facade that owns this custom block.
|
|
317
|
-
* @returns {FDocBody} The document body facade.
|
|
318
|
-
* @example
|
|
319
|
-
* ```ts
|
|
320
|
-
* const doc = univerAPI.getActiveDocument();
|
|
321
|
-
* if (!doc) throw new Error('No active document');
|
|
322
|
-
*
|
|
323
|
-
* const customBlock = doc.getBody().getChild(0).asCustomBlock();
|
|
324
|
-
* console.log(customBlock.getParent().getChildIndex(customBlock));
|
|
325
|
-
* ```
|
|
326
|
-
*/
|
|
327
|
-
getParent() {
|
|
328
|
-
return this._body;
|
|
329
|
-
}
|
|
330
|
-
/**
|
|
331
|
-
* Remove this custom block from the parent body.
|
|
332
|
-
* @returns {boolean} `true` if the custom block placeholder was removed.
|
|
333
|
-
* @example
|
|
334
|
-
* ```ts
|
|
335
|
-
* const doc = univerAPI.getActiveDocument();
|
|
336
|
-
* if (!doc) throw new Error('No active document');
|
|
337
|
-
*
|
|
338
|
-
* const customBlock = doc.getBody().getChild(0).asCustomBlock();
|
|
339
|
-
* customBlock.removeFromParent();
|
|
340
|
-
* ```
|
|
341
|
-
*/
|
|
342
|
-
removeFromParent() {
|
|
343
|
-
return this._body.removeCustomBlock(this._key);
|
|
344
|
-
}
|
|
345
|
-
/**
|
|
346
|
-
* Get the persisted custom block id.
|
|
347
|
-
* @returns {string} The `ICustomBlock.blockId` value.
|
|
348
|
-
* @example
|
|
349
|
-
* ```ts
|
|
350
|
-
* const doc = univerAPI.getActiveDocument();
|
|
351
|
-
* if (!doc) throw new Error('No active document');
|
|
352
|
-
*
|
|
353
|
-
* const customBlock = doc.getBody().getChild(0).asCustomBlock();
|
|
354
|
-
* console.log(customBlock.getBlockId());
|
|
355
|
-
* ```
|
|
356
|
-
*/
|
|
357
|
-
getBlockId() {
|
|
358
|
-
return this._body.getCustomBlock(this._key).blockId;
|
|
36
|
+
function replaceBodyRange(range, insertBody, docDataModel, injector) {
|
|
37
|
+
const { startOffset, endOffset, segmentId } = range;
|
|
38
|
+
const textX = new _univerjs_core.TextX();
|
|
39
|
+
if (startOffset > 0) textX.push({
|
|
40
|
+
t: _univerjs_core.TextXActionType.RETAIN,
|
|
41
|
+
len: startOffset
|
|
42
|
+
});
|
|
43
|
+
if (endOffset > startOffset) textX.push({
|
|
44
|
+
t: _univerjs_core.TextXActionType.DELETE,
|
|
45
|
+
len: endOffset - startOffset
|
|
46
|
+
});
|
|
47
|
+
if (insertBody.dataStream.length > 0) textX.push({
|
|
48
|
+
t: _univerjs_core.TextXActionType.INSERT,
|
|
49
|
+
body: insertBody,
|
|
50
|
+
len: insertBody.dataStream.length
|
|
51
|
+
});
|
|
52
|
+
const actions = _univerjs_core.JSONX.getInstance().editOp(textX.serialize(), (0, _univerjs_core.getRichTextEditPath)(docDataModel, segmentId));
|
|
53
|
+
const result = injector.get(_univerjs_core.ICommandService).syncExecuteCommand(_univerjs_docs.RichTextEditingMutation.id, {
|
|
54
|
+
unitId: docDataModel.getUnitId(),
|
|
55
|
+
segmentId,
|
|
56
|
+
actions,
|
|
57
|
+
textRanges: [],
|
|
58
|
+
isEditing: false
|
|
59
|
+
});
|
|
60
|
+
return Boolean((result === null || result === void 0 ? void 0 : result.actions) && result.actions.length > 0);
|
|
61
|
+
}
|
|
62
|
+
function retainBodyRange(range, updateBody, coverType, docDataModel, injector) {
|
|
63
|
+
var _updateBody$textRuns, _docDataModel$getSelf;
|
|
64
|
+
const { startOffset, endOffset, segmentId } = range;
|
|
65
|
+
const commandService = injector.get(_univerjs_core.ICommandService);
|
|
66
|
+
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) {
|
|
67
|
+
const actions = _univerjs_core.JSONX.getInstance().replaceOp([...(0, _univerjs_core.getRichTextEditPath)(docDataModel, segmentId), "textRuns"], void 0, []);
|
|
68
|
+
commandService.syncExecuteCommand(_univerjs_docs.RichTextEditingMutation.id, {
|
|
69
|
+
unitId: docDataModel.getUnitId(),
|
|
70
|
+
segmentId,
|
|
71
|
+
actions,
|
|
72
|
+
textRanges: [],
|
|
73
|
+
isEditing: false
|
|
74
|
+
});
|
|
359
75
|
}
|
|
360
|
-
|
|
76
|
+
const textX = new _univerjs_core.TextX();
|
|
77
|
+
if (startOffset > 0) textX.push({
|
|
78
|
+
t: _univerjs_core.TextXActionType.RETAIN,
|
|
79
|
+
len: startOffset
|
|
80
|
+
});
|
|
81
|
+
textX.push({
|
|
82
|
+
t: _univerjs_core.TextXActionType.RETAIN,
|
|
83
|
+
body: updateBody,
|
|
84
|
+
coverType,
|
|
85
|
+
len: endOffset - startOffset
|
|
86
|
+
});
|
|
87
|
+
const actions = _univerjs_core.JSONX.getInstance().editOp(textX.serialize(), (0, _univerjs_core.getRichTextEditPath)(docDataModel, segmentId));
|
|
88
|
+
const result = commandService.syncExecuteCommand(_univerjs_docs.RichTextEditingMutation.id, {
|
|
89
|
+
unitId: docDataModel.getUnitId(),
|
|
90
|
+
segmentId,
|
|
91
|
+
actions,
|
|
92
|
+
textRanges: [],
|
|
93
|
+
isEditing: false
|
|
94
|
+
});
|
|
95
|
+
return Boolean((result === null || result === void 0 ? void 0 : result.actions) && result.actions.length > 0);
|
|
96
|
+
}
|
|
97
|
+
function stripBlockTokens(text) {
|
|
98
|
+
return Array.from(text).map((char) => char === _univerjs_core.DataStreamTreeTokenType.PARAGRAPH ? "\n" : char).filter((char) => char !== _univerjs_core.DataStreamTreeTokenType.BLOCK_START && char !== _univerjs_core.DataStreamTreeTokenType.BLOCK_END && char !== _univerjs_core.DataStreamTreeTokenType.SECTION_BREAK).join("").replace(/\n$/, "");
|
|
99
|
+
}
|
|
361
100
|
|
|
362
101
|
//#endregion
|
|
363
|
-
//#region src/facade/f-
|
|
102
|
+
//#region src/facade/f-document-paragraph.ts
|
|
364
103
|
/**
|
|
365
104
|
* A paragraph facade wrapper.
|
|
366
105
|
*
|
|
@@ -370,1269 +109,284 @@ var FDocCustomBlock = class {
|
|
|
370
109
|
*
|
|
371
110
|
* @hideconstructor
|
|
372
111
|
*/
|
|
373
|
-
var
|
|
374
|
-
constructor(
|
|
375
|
-
this.
|
|
376
|
-
this.
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
* Get the document element type.
|
|
380
|
-
* @returns {'paragraph'} The literal paragraph element type.
|
|
381
|
-
* @example
|
|
382
|
-
* ```ts
|
|
383
|
-
* const doc = univerAPI.getActiveDocument();
|
|
384
|
-
* if (!doc) throw new Error('No active document');
|
|
385
|
-
*
|
|
386
|
-
* const paragraph = doc.getBody().getChild(0).asParagraph();
|
|
387
|
-
* console.log(paragraph.getType());
|
|
388
|
-
* ```
|
|
389
|
-
*/
|
|
390
|
-
getType() {
|
|
391
|
-
return "paragraph";
|
|
392
|
-
}
|
|
393
|
-
/**
|
|
394
|
-
* Get the persisted paragraph id.
|
|
395
|
-
* @returns {string} The paragraph id.
|
|
396
|
-
* @example
|
|
397
|
-
* ```ts
|
|
398
|
-
* const doc = univerAPI.getActiveDocument();
|
|
399
|
-
* if (!doc) throw new Error('No active document');
|
|
400
|
-
*
|
|
401
|
-
* const paragraph = doc.getBody().getChild(0).asParagraph();
|
|
402
|
-
* console.log(paragraph.getKey());
|
|
403
|
-
* ```
|
|
404
|
-
*/
|
|
405
|
-
getKey() {
|
|
406
|
-
return this._key;
|
|
112
|
+
var FDocumentParagraph = class {
|
|
113
|
+
constructor(_document, _paragraphId, _segmentId = "", _injector) {
|
|
114
|
+
this._document = _document;
|
|
115
|
+
this._paragraphId = _paragraphId;
|
|
116
|
+
this._segmentId = _segmentId;
|
|
117
|
+
this._injector = _injector;
|
|
407
118
|
}
|
|
408
119
|
/**
|
|
409
120
|
* Get the persisted paragraph id.
|
|
410
121
|
* @returns {string} The paragraph id.
|
|
411
122
|
* @example
|
|
412
123
|
* ```ts
|
|
413
|
-
* const
|
|
414
|
-
*
|
|
415
|
-
*
|
|
416
|
-
* const paragraph = doc.getBody().getChild(0).asParagraph();
|
|
417
|
-
* console.log(paragraph.getId());
|
|
124
|
+
* const fDocument = univerAPI.getActiveDocument();
|
|
125
|
+
* const paragraph = fDocument.getParagraphs()[0];
|
|
126
|
+
* console.log(paragraph?.getId());
|
|
418
127
|
* ```
|
|
419
128
|
*/
|
|
420
129
|
getId() {
|
|
421
|
-
return this.
|
|
422
|
-
}
|
|
423
|
-
/**
|
|
424
|
-
* Get the parent body facade that owns this paragraph.
|
|
425
|
-
* @returns {FDocBody} The document body facade.
|
|
426
|
-
* @example
|
|
427
|
-
* ```ts
|
|
428
|
-
* const doc = univerAPI.getActiveDocument();
|
|
429
|
-
* if (!doc) throw new Error('No active document');
|
|
430
|
-
*
|
|
431
|
-
* const paragraph = doc.getBody().getChild(0).asParagraph();
|
|
432
|
-
* console.log(paragraph.getParent().getChildIndex(paragraph));
|
|
433
|
-
* ```
|
|
434
|
-
*/
|
|
435
|
-
getParent() {
|
|
436
|
-
return this._body;
|
|
437
|
-
}
|
|
438
|
-
/**
|
|
439
|
-
* Remove this paragraph from its parent body.
|
|
440
|
-
* @returns {boolean} `true` if the paragraph was removed.
|
|
441
|
-
* @example
|
|
442
|
-
* ```ts
|
|
443
|
-
* const doc = univerAPI.getActiveDocument();
|
|
444
|
-
* if (!doc) throw new Error('No active document');
|
|
445
|
-
*
|
|
446
|
-
* const paragraph = doc.getBody().getChild(0).asParagraph();
|
|
447
|
-
* paragraph.removeFromParent();
|
|
448
|
-
* ```
|
|
449
|
-
*/
|
|
450
|
-
removeFromParent() {
|
|
451
|
-
return this._body.removeParagraph(this._key);
|
|
452
|
-
}
|
|
453
|
-
/**
|
|
454
|
-
* Get this paragraph's plain text.
|
|
455
|
-
* @returns {string} The paragraph text without the trailing paragraph break.
|
|
456
|
-
* @example
|
|
457
|
-
* ```ts
|
|
458
|
-
* const doc = univerAPI.getActiveDocument();
|
|
459
|
-
* if (!doc) throw new Error('No active document');
|
|
460
|
-
*
|
|
461
|
-
* const paragraph = doc.getBody().getChild(0).asParagraph();
|
|
462
|
-
* console.log(paragraph.getText());
|
|
463
|
-
* ```
|
|
464
|
-
*/
|
|
465
|
-
getText() {
|
|
466
|
-
return this._body.getParagraphText(this._key);
|
|
467
|
-
}
|
|
468
|
-
/**
|
|
469
|
-
* Replace this paragraph's plain text.
|
|
470
|
-
* @param {string} text The replacement text. Do not include the paragraph break.
|
|
471
|
-
* @returns {boolean} `true` if the paragraph text was replaced.
|
|
472
|
-
* @example
|
|
473
|
-
* ```ts
|
|
474
|
-
* const doc = univerAPI.getActiveDocument();
|
|
475
|
-
* if (!doc) throw new Error('No active document');
|
|
476
|
-
*
|
|
477
|
-
* const paragraph = doc.getBody().getChild(0).asParagraph();
|
|
478
|
-
* paragraph.setText('Updated title');
|
|
479
|
-
* ```
|
|
480
|
-
*/
|
|
481
|
-
setText(text) {
|
|
482
|
-
return this._body.setParagraphText(this._key, text);
|
|
483
|
-
}
|
|
484
|
-
/**
|
|
485
|
-
* Append plain text before this paragraph's trailing paragraph break.
|
|
486
|
-
* @param {string} text The plain text to append.
|
|
487
|
-
* @returns {boolean} `true` if the text was appended.
|
|
488
|
-
* @example
|
|
489
|
-
* ```ts
|
|
490
|
-
* const doc = univerAPI.getActiveDocument();
|
|
491
|
-
* if (!doc) throw new Error('No active document');
|
|
492
|
-
*
|
|
493
|
-
* const paragraph = doc.getBody().getChild(0).asParagraph();
|
|
494
|
-
* paragraph.appendText(' suffix');
|
|
495
|
-
* ```
|
|
496
|
-
*/
|
|
497
|
-
appendText(text) {
|
|
498
|
-
return this._body.appendParagraphText(this._key, text);
|
|
499
|
-
}
|
|
500
|
-
/**
|
|
501
|
-
* Get the current text range occupied by this paragraph.
|
|
502
|
-
* @returns {IFDocTextRange} The paragraph text range, excluding the trailing paragraph break.
|
|
503
|
-
* @example
|
|
504
|
-
* ```ts
|
|
505
|
-
* const doc = univerAPI.getActiveDocument();
|
|
506
|
-
* if (!doc) throw new Error('No active document');
|
|
507
|
-
*
|
|
508
|
-
* const paragraph = doc.getBody().getChild(0).asParagraph();
|
|
509
|
-
* const range = paragraph.getRange();
|
|
510
|
-
* doc.getBody().setTextStyle(range, { bl: 1 });
|
|
511
|
-
* ```
|
|
512
|
-
*/
|
|
513
|
-
getRange() {
|
|
514
|
-
return this._body.getParagraphRange(this._key);
|
|
515
|
-
}
|
|
516
|
-
/**
|
|
517
|
-
* Check whether this paragraph is a bullet, ordered, or checklist item.
|
|
518
|
-
* @returns {boolean} `true` if the paragraph has list metadata.
|
|
519
|
-
* @example
|
|
520
|
-
* ```ts
|
|
521
|
-
* const doc = univerAPI.getActiveDocument();
|
|
522
|
-
* if (!doc) throw new Error('No active document');
|
|
523
|
-
*
|
|
524
|
-
* const paragraph = doc.getBody().getChild(0).asParagraph();
|
|
525
|
-
* console.log(paragraph.isListItem());
|
|
526
|
-
* ```
|
|
527
|
-
*/
|
|
528
|
-
isListItem() {
|
|
529
|
-
return this._body.isListParagraph(this._key);
|
|
130
|
+
return this._paragraphId;
|
|
530
131
|
}
|
|
531
132
|
/**
|
|
532
|
-
*
|
|
533
|
-
*
|
|
133
|
+
* Get the segment id of this paragraph.
|
|
134
|
+
* The main body paragraphs have an empty string segment id.
|
|
135
|
+
* The header and footer paragraphs have a non-empty string segment id.
|
|
136
|
+
* @returns {string} The segment id.
|
|
534
137
|
* @example
|
|
535
138
|
* ```ts
|
|
536
|
-
* const
|
|
537
|
-
*
|
|
538
|
-
*
|
|
539
|
-
* const paragraph = doc.getBody().getChild(0).asParagraph();
|
|
540
|
-
* if (paragraph.isTask()) {
|
|
541
|
-
* paragraph.setTaskChecked(true);
|
|
542
|
-
* }
|
|
139
|
+
* const fDocument = univerAPI.getActiveDocument();
|
|
140
|
+
* const paragraph = fDocument.getParagraphs()[0];
|
|
141
|
+
* console.log(paragraph?.getSegmentId());
|
|
543
142
|
* ```
|
|
544
143
|
*/
|
|
545
|
-
|
|
546
|
-
return this.
|
|
547
|
-
}
|
|
548
|
-
/**
|
|
549
|
-
* Set the checked state of this task/checklist paragraph.
|
|
550
|
-
* @param {boolean} checked Whether the task item should be checked.
|
|
551
|
-
* @returns {boolean} `true` if the task state was updated, or `false` if this paragraph is not a task item.
|
|
552
|
-
* @example
|
|
553
|
-
* ```ts
|
|
554
|
-
* const doc = univerAPI.getActiveDocument();
|
|
555
|
-
* if (!doc) throw new Error('No active document');
|
|
556
|
-
*
|
|
557
|
-
* const paragraph = doc.getBody().getChild(0).asParagraph();
|
|
558
|
-
* if (paragraph.isTask()) {
|
|
559
|
-
* paragraph.setTaskChecked(false);
|
|
560
|
-
* }
|
|
561
|
-
* ```
|
|
562
|
-
*/
|
|
563
|
-
setTaskChecked(checked) {
|
|
564
|
-
return this._body.setTaskChecked(this._key, checked);
|
|
565
|
-
}
|
|
566
|
-
};
|
|
567
|
-
|
|
568
|
-
//#endregion
|
|
569
|
-
//#region src/facade/f-doc-table.ts
|
|
570
|
-
/**
|
|
571
|
-
* A facade wrapper for a document table marker.
|
|
572
|
-
*
|
|
573
|
-
* Table identity is backed by the persisted `ICustomTable.tableId`, so the
|
|
574
|
-
* wrapper can be re-resolved after text is inserted before the table.
|
|
575
|
-
*
|
|
576
|
-
* @hideconstructor
|
|
577
|
-
*/
|
|
578
|
-
var FDocTable = class {
|
|
579
|
-
constructor(_body, _key) {
|
|
580
|
-
this._body = _body;
|
|
581
|
-
this._key = _key;
|
|
582
|
-
}
|
|
583
|
-
/**
|
|
584
|
-
* Get the document element type.
|
|
585
|
-
* @returns {'table'} The literal table element type.
|
|
586
|
-
* @example
|
|
587
|
-
* ```ts
|
|
588
|
-
* const doc = univerAPI.getActiveDocument();
|
|
589
|
-
* if (!doc) throw new Error('No active document');
|
|
590
|
-
*
|
|
591
|
-
* const table = doc.getBody().getChild(0).asTable();
|
|
592
|
-
* console.log(table.getType());
|
|
593
|
-
* ```
|
|
594
|
-
*/
|
|
595
|
-
getType() {
|
|
596
|
-
return "table";
|
|
597
|
-
}
|
|
598
|
-
/**
|
|
599
|
-
* Get the table key.
|
|
600
|
-
* @returns {string} The persisted `tableId` for this table.
|
|
601
|
-
* @example
|
|
602
|
-
* ```ts
|
|
603
|
-
* const doc = univerAPI.getActiveDocument();
|
|
604
|
-
* if (!doc) throw new Error('No active document');
|
|
605
|
-
*
|
|
606
|
-
* const table = doc.getBody().getChild(0).asTable();
|
|
607
|
-
* console.log(table.getKey());
|
|
608
|
-
* ```
|
|
609
|
-
*/
|
|
610
|
-
getKey() {
|
|
611
|
-
return this._key;
|
|
612
|
-
}
|
|
613
|
-
/**
|
|
614
|
-
* Get the parent body facade that owns this table.
|
|
615
|
-
* @returns {FDocBody} The document body facade.
|
|
616
|
-
* @example
|
|
617
|
-
* ```ts
|
|
618
|
-
* const doc = univerAPI.getActiveDocument();
|
|
619
|
-
* if (!doc) throw new Error('No active document');
|
|
620
|
-
*
|
|
621
|
-
* const table = doc.getBody().getChild(0).asTable();
|
|
622
|
-
* console.log(table.getParent().getChildIndex(table));
|
|
623
|
-
* ```
|
|
624
|
-
*/
|
|
625
|
-
getParent() {
|
|
626
|
-
return this._body;
|
|
627
|
-
}
|
|
628
|
-
/**
|
|
629
|
-
* Remove this table from the parent body.
|
|
630
|
-
* @returns {boolean} `true` if the table range was removed.
|
|
631
|
-
* @example
|
|
632
|
-
* ```ts
|
|
633
|
-
* const doc = univerAPI.getActiveDocument();
|
|
634
|
-
* if (!doc) throw new Error('No active document');
|
|
635
|
-
*
|
|
636
|
-
* const table = doc.getBody().getChild(0).asTable();
|
|
637
|
-
* table.removeFromParent();
|
|
638
|
-
* ```
|
|
639
|
-
*/
|
|
640
|
-
removeFromParent() {
|
|
641
|
-
return this._body.removeTable(this._key);
|
|
642
|
-
}
|
|
643
|
-
/**
|
|
644
|
-
* Get the persisted table id.
|
|
645
|
-
* @returns {string} The `ICustomTable.tableId` value.
|
|
646
|
-
* @example
|
|
647
|
-
* ```ts
|
|
648
|
-
* const doc = univerAPI.getActiveDocument();
|
|
649
|
-
* if (!doc) throw new Error('No active document');
|
|
650
|
-
*
|
|
651
|
-
* const table = doc.getBody().getChild(0).asTable();
|
|
652
|
-
* console.log(table.getTableId());
|
|
653
|
-
* ```
|
|
654
|
-
*/
|
|
655
|
-
getTableId() {
|
|
656
|
-
return this._body.getTable(this._key).tableId;
|
|
657
|
-
}
|
|
658
|
-
};
|
|
659
|
-
|
|
660
|
-
//#endregion
|
|
661
|
-
//#region src/facade/f-doc-element.ts
|
|
662
|
-
/**
|
|
663
|
-
* A generic top-level document body element.
|
|
664
|
-
*
|
|
665
|
-
* Use this wrapper when you need to inspect an element type first, navigate to
|
|
666
|
-
* neighboring elements, or cast the element to a more specific facade wrapper.
|
|
667
|
-
*
|
|
668
|
-
* Paragraph keys are persisted `paragraphId` values. Tables, block ranges, and
|
|
669
|
-
* custom blocks use their persisted ids.
|
|
670
|
-
*
|
|
671
|
-
* @hideconstructor
|
|
672
|
-
*/
|
|
673
|
-
var FDocElement = class {
|
|
674
|
-
constructor(_body, _type, _key) {
|
|
675
|
-
this._body = _body;
|
|
676
|
-
this._type = _type;
|
|
677
|
-
this._key = _key;
|
|
678
|
-
}
|
|
679
|
-
/**
|
|
680
|
-
* Get the document element type.
|
|
681
|
-
* @returns {FDocElementType} The element type, such as `paragraph`, `table`, `blockRange`, or `customBlock`.
|
|
682
|
-
* @example
|
|
683
|
-
* ```ts
|
|
684
|
-
* const doc = univerAPI.getActiveDocument();
|
|
685
|
-
* if (!doc) throw new Error('No active document');
|
|
686
|
-
*
|
|
687
|
-
* const element = doc.getBody().getChild(0);
|
|
688
|
-
* console.log(element.getType());
|
|
689
|
-
* ```
|
|
690
|
-
*/
|
|
691
|
-
getType() {
|
|
692
|
-
return this._type;
|
|
693
|
-
}
|
|
694
|
-
/**
|
|
695
|
-
* Get the facade key used to resolve this element.
|
|
696
|
-
* @returns {string} The paragraph `paragraphId` or persisted table/block/custom block id.
|
|
697
|
-
* @example
|
|
698
|
-
* ```ts
|
|
699
|
-
* const doc = univerAPI.getActiveDocument();
|
|
700
|
-
* if (!doc) throw new Error('No active document');
|
|
701
|
-
*
|
|
702
|
-
* const body = doc.getBody();
|
|
703
|
-
* const element = body.getChild(0);
|
|
704
|
-
* console.log(element.getKey());
|
|
705
|
-
* ```
|
|
706
|
-
*/
|
|
707
|
-
getKey() {
|
|
708
|
-
return this._key;
|
|
709
|
-
}
|
|
710
|
-
/**
|
|
711
|
-
* Get the parent body facade that owns this element.
|
|
712
|
-
* @returns {FDocBody} The document body facade.
|
|
713
|
-
* @example
|
|
714
|
-
* ```ts
|
|
715
|
-
* const doc = univerAPI.getActiveDocument();
|
|
716
|
-
* if (!doc) throw new Error('No active document');
|
|
717
|
-
*
|
|
718
|
-
* const element = doc.getBody().getChild(0);
|
|
719
|
-
* console.log(element.getParent().getNumChildren());
|
|
720
|
-
* ```
|
|
721
|
-
*/
|
|
722
|
-
getParent() {
|
|
723
|
-
return this._body;
|
|
724
|
-
}
|
|
725
|
-
/**
|
|
726
|
-
* Get the next sibling element in the current body order.
|
|
727
|
-
* @returns {FDocElement | null} The next sibling wrapper, or `null` when this is the last child.
|
|
728
|
-
* @example
|
|
729
|
-
* ```ts
|
|
730
|
-
* const doc = univerAPI.getActiveDocument();
|
|
731
|
-
* if (!doc) throw new Error('No active document');
|
|
732
|
-
*
|
|
733
|
-
* const first = doc.getBody().getChild(0);
|
|
734
|
-
* const next = first.getNextSibling();
|
|
735
|
-
* console.log(next?.getType());
|
|
736
|
-
* ```
|
|
737
|
-
*/
|
|
738
|
-
getNextSibling() {
|
|
739
|
-
return this._body.createSibling(this._type, this._key, 1);
|
|
740
|
-
}
|
|
741
|
-
/**
|
|
742
|
-
* Get the previous sibling element in the current body order.
|
|
743
|
-
* @returns {FDocElement | null} The previous sibling wrapper, or `null` when this is the first child.
|
|
744
|
-
* @example
|
|
745
|
-
* ```ts
|
|
746
|
-
* const doc = univerAPI.getActiveDocument();
|
|
747
|
-
* if (!doc) throw new Error('No active document');
|
|
748
|
-
*
|
|
749
|
-
* const second = doc.getBody().getChild(1);
|
|
750
|
-
* const previous = second.getPreviousSibling();
|
|
751
|
-
* console.log(previous?.getType());
|
|
752
|
-
* ```
|
|
753
|
-
*/
|
|
754
|
-
getPreviousSibling() {
|
|
755
|
-
return this._body.createSibling(this._type, this._key, -1);
|
|
756
|
-
}
|
|
757
|
-
/**
|
|
758
|
-
* Remove this element from its parent body.
|
|
759
|
-
* @returns {boolean} `true` if the element content was removed.
|
|
760
|
-
* @example
|
|
761
|
-
* ```ts
|
|
762
|
-
* const doc = univerAPI.getActiveDocument();
|
|
763
|
-
* if (!doc) throw new Error('No active document');
|
|
764
|
-
*
|
|
765
|
-
* const body = doc.getBody();
|
|
766
|
-
* const element = body.getChild(0);
|
|
767
|
-
* element.removeFromParent();
|
|
768
|
-
* ```
|
|
769
|
-
*/
|
|
770
|
-
removeFromParent() {
|
|
771
|
-
if (this._type === "paragraph") return this._body.removeParagraph(this._key);
|
|
772
|
-
if (this._type === "blockRange") return this._body.removeBlockRange(this._key);
|
|
773
|
-
if (this._type === "table") return this._body.removeTable(this._key);
|
|
774
|
-
return this._body.removeCustomBlock(this._key);
|
|
775
|
-
}
|
|
776
|
-
/**
|
|
777
|
-
* Cast this generic element to a paragraph facade.
|
|
778
|
-
* @returns {FDocParagraph} The paragraph facade wrapper.
|
|
779
|
-
* @throws {TypeError} If the element is not a paragraph.
|
|
780
|
-
* @example
|
|
781
|
-
* ```ts
|
|
782
|
-
* const doc = univerAPI.getActiveDocument();
|
|
783
|
-
* if (!doc) throw new Error('No active document');
|
|
784
|
-
*
|
|
785
|
-
* const paragraph = doc.getBody().getChild(0).asParagraph();
|
|
786
|
-
* console.log(paragraph.getText());
|
|
787
|
-
* ```
|
|
788
|
-
*/
|
|
789
|
-
asParagraph() {
|
|
790
|
-
this._assertType("paragraph");
|
|
791
|
-
return new FDocParagraph(this._body, this._key);
|
|
792
|
-
}
|
|
793
|
-
/**
|
|
794
|
-
* Cast this generic element to a table facade.
|
|
795
|
-
* @returns {FDocTable} The table facade wrapper.
|
|
796
|
-
* @throws {TypeError} If the element is not a table.
|
|
797
|
-
* @example
|
|
798
|
-
* ```ts
|
|
799
|
-
* const doc = univerAPI.getActiveDocument();
|
|
800
|
-
* if (!doc) throw new Error('No active document');
|
|
801
|
-
*
|
|
802
|
-
* const table = doc.getBody().getChild(0).asTable();
|
|
803
|
-
* console.log(table.getTableId());
|
|
804
|
-
* ```
|
|
805
|
-
*/
|
|
806
|
-
asTable() {
|
|
807
|
-
this._assertType("table");
|
|
808
|
-
return new FDocTable(this._body, this._key);
|
|
809
|
-
}
|
|
810
|
-
/**
|
|
811
|
-
* Cast this generic element to a callout, quote, or code block range facade.
|
|
812
|
-
* @returns {FDocBlockRange} The block range facade wrapper.
|
|
813
|
-
* @throws {TypeError} If the element is not a block range.
|
|
814
|
-
* @example
|
|
815
|
-
* ```ts
|
|
816
|
-
* const doc = univerAPI.getActiveDocument();
|
|
817
|
-
* if (!doc) throw new Error('No active document');
|
|
818
|
-
*
|
|
819
|
-
* const blockRange = doc.getBody().getChild(0).asBlockRange();
|
|
820
|
-
* console.log(blockRange.getBlockType());
|
|
821
|
-
* ```
|
|
822
|
-
*/
|
|
823
|
-
asBlockRange() {
|
|
824
|
-
this._assertType("blockRange");
|
|
825
|
-
return new FDocBlockRange(this._body, this._key);
|
|
826
|
-
}
|
|
827
|
-
/**
|
|
828
|
-
* Cast this generic element to a custom block facade.
|
|
829
|
-
* @returns {FDocCustomBlock} The custom block facade wrapper.
|
|
830
|
-
* @throws {TypeError} If the element is not a custom block.
|
|
831
|
-
* @example
|
|
832
|
-
* ```ts
|
|
833
|
-
* const doc = univerAPI.getActiveDocument();
|
|
834
|
-
* if (!doc) throw new Error('No active document');
|
|
835
|
-
*
|
|
836
|
-
* const customBlock = doc.getBody().getChild(0).asCustomBlock();
|
|
837
|
-
* console.log(customBlock.getBlockId());
|
|
838
|
-
* ```
|
|
839
|
-
*/
|
|
840
|
-
asCustomBlock() {
|
|
841
|
-
this._assertType("customBlock");
|
|
842
|
-
return new FDocCustomBlock(this._body, this._key);
|
|
843
|
-
}
|
|
844
|
-
_assertType(type) {
|
|
845
|
-
if (this._type !== type) throw new TypeError(`Cannot cast ${this._type} to ${type}.`);
|
|
846
|
-
}
|
|
847
|
-
};
|
|
848
|
-
|
|
849
|
-
//#endregion
|
|
850
|
-
//#region src/facade/f-doc-body.ts
|
|
851
|
-
function isRichTextLike(value) {
|
|
852
|
-
return typeof value === "object" && value !== null && "getData" in value && typeof value.getData === "function";
|
|
853
|
-
}
|
|
854
|
-
const FACADE_TRIGGER = "doc-facade";
|
|
855
|
-
const RESTORE_INSERTED_PARAGRAPH_IDS = "__textXRestoreParagraphIds";
|
|
856
|
-
/**
|
|
857
|
-
* A Facade API object bounded to a document body or header/footer segment.
|
|
858
|
-
* It provides Google Docs-like element access and range editing methods.
|
|
859
|
-
*
|
|
860
|
-
* Paragraph elements use their persisted `paragraphId`. Tables, block ranges, and
|
|
861
|
-
* custom blocks use their persisted ids.
|
|
862
|
-
*
|
|
863
|
-
* @hideconstructor
|
|
864
|
-
*/
|
|
865
|
-
var FDocBody = class {
|
|
866
|
-
constructor(_documentDataModel, _commandService, _registry, _segmentId = "") {
|
|
867
|
-
this._documentDataModel = _documentDataModel;
|
|
868
|
-
this._commandService = _commandService;
|
|
869
|
-
this._segmentId = _segmentId;
|
|
870
|
-
}
|
|
871
|
-
/**
|
|
872
|
-
* Get the number of top-level child elements in the body.
|
|
873
|
-
* @returns {number} The number of child elements.
|
|
874
|
-
* @example
|
|
875
|
-
* ```ts
|
|
876
|
-
* const doc = univerAPI.getActiveDocument();
|
|
877
|
-
* if (!doc) throw new Error('No active document');
|
|
878
|
-
*
|
|
879
|
-
* const body = doc.getBody();
|
|
880
|
-
* console.log(body.getNumChildren());
|
|
881
|
-
* ```
|
|
882
|
-
*/
|
|
883
|
-
getNumChildren() {
|
|
884
|
-
return this._getChildren().length;
|
|
885
|
-
}
|
|
886
|
-
/**
|
|
887
|
-
* Get a top-level child element by child index.
|
|
888
|
-
* @param {number} index The zero-based child index.
|
|
889
|
-
* @returns {FDocElement} The child element wrapper.
|
|
890
|
-
* @example
|
|
891
|
-
* ```ts
|
|
892
|
-
* const doc = univerAPI.getActiveDocument();
|
|
893
|
-
* if (!doc) throw new Error('No active document');
|
|
894
|
-
*
|
|
895
|
-
* const body = doc.getBody();
|
|
896
|
-
* const firstChild = body.getChild(0);
|
|
897
|
-
* console.log(firstChild.getType());
|
|
898
|
-
* ```
|
|
899
|
-
*/
|
|
900
|
-
getChild(index) {
|
|
901
|
-
const child = this._getChildren()[index];
|
|
902
|
-
if (!child) throw new RangeError(`Child index ${index} is out of range.`);
|
|
903
|
-
return this._createElement(child.type, child.key);
|
|
904
|
-
}
|
|
905
|
-
/**
|
|
906
|
-
* Get the current child index of an element handle.
|
|
907
|
-
* The index is resolved from the element key, so a paragraph handle keeps pointing
|
|
908
|
-
* to the same paragraph after facade edits insert content before it.
|
|
909
|
-
* @param {IFDocElementHandle} element The element handle to locate.
|
|
910
|
-
* @returns {number} The current zero-based child index.
|
|
911
|
-
* @example
|
|
912
|
-
* ```ts
|
|
913
|
-
* const doc = univerAPI.getActiveDocument();
|
|
914
|
-
* if (!doc) throw new Error('No active document');
|
|
915
|
-
*
|
|
916
|
-
* const body = doc.getBody();
|
|
917
|
-
* const paragraph = body.getChild(1).asParagraph();
|
|
918
|
-
* body.insertParagraph(0, 'Intro');
|
|
919
|
-
* console.log(body.getChildIndex(paragraph));
|
|
920
|
-
* ```
|
|
921
|
-
*/
|
|
922
|
-
getChildIndex(element) {
|
|
923
|
-
const resolved = this.resolveElement(element.getType(), element.getKey());
|
|
924
|
-
const index = this._getChildren().findIndex((child) => child.type === resolved.type && child.key === resolved.key);
|
|
925
|
-
if (index < 0) throw new Error("Doc element is stale");
|
|
926
|
-
return index;
|
|
927
|
-
}
|
|
928
|
-
/**
|
|
929
|
-
* Insert plain text at a document body offset.
|
|
930
|
-
* @param {number} index The zero-based insertion offset.
|
|
931
|
-
* @param {string} text The plain text to insert.
|
|
932
|
-
* @returns {boolean} `true` if the edit was applied.
|
|
933
|
-
* @example
|
|
934
|
-
* ```ts
|
|
935
|
-
* const doc = univerAPI.getActiveDocument();
|
|
936
|
-
* if (!doc) throw new Error('No active document');
|
|
937
|
-
*
|
|
938
|
-
* const body = doc.getBody();
|
|
939
|
-
* body.insertText(0, 'Hello ');
|
|
940
|
-
* ```
|
|
941
|
-
*/
|
|
942
|
-
insertText(index, text) {
|
|
943
|
-
return this._replaceBodyRange({
|
|
944
|
-
startOffset: index,
|
|
945
|
-
endOffset: index
|
|
946
|
-
}, buildPlainTextInsertBody(text));
|
|
947
|
-
}
|
|
948
|
-
/**
|
|
949
|
-
* Insert a plain-text paragraph before the paragraph at the given paragraph index.
|
|
950
|
-
* @param {number} index The zero-based paragraph insertion index.
|
|
951
|
-
* @param {string} text The paragraph text. Defaults to an empty paragraph.
|
|
952
|
-
* @returns {FDocParagraph} The inserted paragraph wrapper.
|
|
953
|
-
* @example
|
|
954
|
-
* ```ts
|
|
955
|
-
* const doc = univerAPI.getActiveDocument();
|
|
956
|
-
* if (!doc) throw new Error('No active document');
|
|
957
|
-
*
|
|
958
|
-
* const body = doc.getBody();
|
|
959
|
-
* const paragraph = body.insertParagraph(0, 'Document title');
|
|
960
|
-
* paragraph.appendText(' suffix');
|
|
961
|
-
* ```
|
|
962
|
-
*/
|
|
963
|
-
insertParagraph(index, text = "") {
|
|
964
|
-
var _this$_getBody$paragr;
|
|
965
|
-
const offset = this._getParagraphInsertOffset(index);
|
|
966
|
-
if (!this._replaceBodyRange({
|
|
967
|
-
startOffset: offset,
|
|
968
|
-
endOffset: offset
|
|
969
|
-
}, buildPlainTextInsertBody(`${text}\r`))) throw new Error("Failed to insert paragraph.");
|
|
970
|
-
const paragraphIndex = this._normalizeInsertedParagraphIndex(index);
|
|
971
|
-
const paragraph = (_this$_getBody$paragr = this._getBody().paragraphs) === null || _this$_getBody$paragr === void 0 ? void 0 : _this$_getBody$paragr[paragraphIndex];
|
|
972
|
-
return new FDocParagraph(this, this._getParagraphId(paragraph, paragraphIndex));
|
|
973
|
-
}
|
|
974
|
-
/**
|
|
975
|
-
* Append a plain-text paragraph at the end of the body.
|
|
976
|
-
* @param {string} text The paragraph text. Defaults to an empty paragraph.
|
|
977
|
-
* @returns {FDocParagraph} The appended paragraph wrapper.
|
|
978
|
-
* @example
|
|
979
|
-
* ```ts
|
|
980
|
-
* const doc = univerAPI.getActiveDocument();
|
|
981
|
-
* if (!doc) throw new Error('No active document');
|
|
982
|
-
*
|
|
983
|
-
* const body = doc.getBody();
|
|
984
|
-
* const paragraph = body.appendParagraph('Summary');
|
|
985
|
-
* console.log(paragraph.getText());
|
|
986
|
-
* ```
|
|
987
|
-
*/
|
|
988
|
-
appendParagraph(text = "") {
|
|
989
|
-
var _this$_getBody$paragr2, _this$_getBody$paragr3;
|
|
990
|
-
return this.insertParagraph((_this$_getBody$paragr2 = (_this$_getBody$paragr3 = this._getBody().paragraphs) === null || _this$_getBody$paragr3 === void 0 ? void 0 : _this$_getBody$paragr3.length) !== null && _this$_getBody$paragr2 !== void 0 ? _this$_getBody$paragr2 : 0, text);
|
|
991
|
-
}
|
|
992
|
-
/**
|
|
993
|
-
* Delete a range from the body.
|
|
994
|
-
* @param {IFDocTextRange} range The text range to delete.
|
|
995
|
-
* @returns {boolean} `true` if the range was deleted.
|
|
996
|
-
* @example
|
|
997
|
-
* ```ts
|
|
998
|
-
* const doc = univerAPI.getActiveDocument();
|
|
999
|
-
* if (!doc) throw new Error('No active document');
|
|
1000
|
-
*
|
|
1001
|
-
* const body = doc.getBody();
|
|
1002
|
-
* body.deleteRange({ startOffset: 0, endOffset: 5 });
|
|
1003
|
-
* ```
|
|
1004
|
-
*/
|
|
1005
|
-
deleteRange(range) {
|
|
1006
|
-
return this._replaceBodyRange(range, { dataStream: "" });
|
|
1007
|
-
}
|
|
1008
|
-
/**
|
|
1009
|
-
* Replace a range with plain text or rich text body data.
|
|
1010
|
-
* @param {IFDocTextRange} range The text range to replace.
|
|
1011
|
-
* @param {string | IFDocRichTextLike | { body?: IDocumentBody }} value The replacement text or rich-text-like value.
|
|
1012
|
-
* @returns {boolean} `true` if the replacement was applied.
|
|
1013
|
-
* @example
|
|
1014
|
-
* ```ts
|
|
1015
|
-
* const doc = univerAPI.getActiveDocument();
|
|
1016
|
-
* if (!doc) throw new Error('No active document');
|
|
1017
|
-
*
|
|
1018
|
-
* const body = doc.getBody();
|
|
1019
|
-
* body.replaceRange({ startOffset: 0, endOffset: 5 }, 'Hello');
|
|
1020
|
-
* ```
|
|
1021
|
-
*/
|
|
1022
|
-
replaceRange(range, value) {
|
|
1023
|
-
let body;
|
|
1024
|
-
if (typeof value === "string") body = buildPlainTextInsertBody(value);
|
|
1025
|
-
else if (isRichTextLike(value)) {
|
|
1026
|
-
var _value$getData$body;
|
|
1027
|
-
body = (_value$getData$body = value.getData().body) !== null && _value$getData$body !== void 0 ? _value$getData$body : { dataStream: "" };
|
|
1028
|
-
} else {
|
|
1029
|
-
var _value$body;
|
|
1030
|
-
body = (_value$body = value.body) !== null && _value$body !== void 0 ? _value$body : { dataStream: "" };
|
|
1031
|
-
}
|
|
1032
|
-
return this._replaceBodyRange(range, body);
|
|
1033
|
-
}
|
|
1034
|
-
/**
|
|
1035
|
-
* Apply text style to a body range.
|
|
1036
|
-
* @param {IFDocTextRange} range The range to style.
|
|
1037
|
-
* @param {ITextStyle} style The Univer text style patch.
|
|
1038
|
-
* @returns {boolean} `true` if the style was applied.
|
|
1039
|
-
* @example
|
|
1040
|
-
* ```ts
|
|
1041
|
-
* const doc = univerAPI.getActiveDocument();
|
|
1042
|
-
* if (!doc) throw new Error('No active document');
|
|
1043
|
-
*
|
|
1044
|
-
* const body = doc.getBody();
|
|
1045
|
-
* body.setTextStyle({ startOffset: 0, endOffset: 5 }, { bl: 1 });
|
|
1046
|
-
* ```
|
|
1047
|
-
*/
|
|
1048
|
-
setTextStyle(range, style) {
|
|
1049
|
-
const updateBody = {
|
|
1050
|
-
dataStream: "",
|
|
1051
|
-
textRuns: [{
|
|
1052
|
-
st: 0,
|
|
1053
|
-
ed: range.endOffset - range.startOffset,
|
|
1054
|
-
ts: style
|
|
1055
|
-
}]
|
|
1056
|
-
};
|
|
1057
|
-
return this._retainBodyRange(range, updateBody, _univerjs_core.UpdateDocsAttributeType.COVER);
|
|
1058
|
-
}
|
|
1059
|
-
/**
|
|
1060
|
-
* Apply paragraph style to a paragraph handle or text range.
|
|
1061
|
-
* @param {FDocElement | FDocParagraph | IFDocTextRange} paragraph The paragraph handle or a range inside the paragraph.
|
|
1062
|
-
* @param {IParagraphStyle} style The Univer paragraph style patch.
|
|
1063
|
-
* @returns {boolean} `true` if the style was applied.
|
|
1064
|
-
* @example
|
|
1065
|
-
* ```ts
|
|
1066
|
-
* const doc = univerAPI.getActiveDocument();
|
|
1067
|
-
* if (!doc) throw new Error('No active document');
|
|
1068
|
-
*
|
|
1069
|
-
* const body = doc.getBody();
|
|
1070
|
-
* const paragraph = body.getChild(0).asParagraph();
|
|
1071
|
-
* body.setParagraphStyle(paragraph, { horizontalAlign: 2 });
|
|
1072
|
-
* ```
|
|
1073
|
-
*/
|
|
1074
|
-
setParagraphStyle(paragraph, style) {
|
|
1075
|
-
const resolved = paragraph instanceof FDocElement || paragraph instanceof FDocParagraph ? this.resolveParagraph(paragraph.getKey()) : this._findParagraphByRange(paragraph);
|
|
1076
|
-
const updateBody = {
|
|
1077
|
-
dataStream: "",
|
|
1078
|
-
paragraphs: [{
|
|
1079
|
-
...resolved.paragraph,
|
|
1080
|
-
startIndex: 0,
|
|
1081
|
-
paragraphStyle: {
|
|
1082
|
-
...resolved.paragraph.paragraphStyle,
|
|
1083
|
-
...style
|
|
1084
|
-
}
|
|
1085
|
-
}]
|
|
1086
|
-
};
|
|
1087
|
-
this._preserveExplicitParagraphIds(updateBody);
|
|
1088
|
-
return this._retainBodyRange({
|
|
1089
|
-
startOffset: resolved.endOffset,
|
|
1090
|
-
endOffset: resolved.endOffset + 1
|
|
1091
|
-
}, updateBody, _univerjs_core.UpdateDocsAttributeType.REPLACE);
|
|
1092
|
-
}
|
|
1093
|
-
/**
|
|
1094
|
-
* Get the text content of a paragraph by paragraph id.
|
|
1095
|
-
* @param {string} key The paragraph id.
|
|
1096
|
-
* @returns {string} The paragraph text without the trailing paragraph break.
|
|
1097
|
-
* @example
|
|
1098
|
-
* ```ts
|
|
1099
|
-
* const doc = univerAPI.getActiveDocument();
|
|
1100
|
-
* if (!doc) throw new Error('No active document');
|
|
1101
|
-
*
|
|
1102
|
-
* const paragraph = doc.getBody().getChild(0).asParagraph();
|
|
1103
|
-
* console.log(doc.getBody().getParagraphText(paragraph.getKey()));
|
|
1104
|
-
* ```
|
|
1105
|
-
*/
|
|
1106
|
-
getParagraphText(key) {
|
|
1107
|
-
const resolved = this.resolveParagraph(key);
|
|
1108
|
-
return this._getBody().dataStream.slice(resolved.startOffset, resolved.endOffset);
|
|
1109
|
-
}
|
|
1110
|
-
/**
|
|
1111
|
-
* Replace the text content of a paragraph by paragraph id.
|
|
1112
|
-
* @param {string} key The paragraph id.
|
|
1113
|
-
* @param {string} text The replacement paragraph text.
|
|
1114
|
-
* @returns {boolean} `true` if the paragraph text was replaced.
|
|
1115
|
-
* @example
|
|
1116
|
-
* ```ts
|
|
1117
|
-
* const doc = univerAPI.getActiveDocument();
|
|
1118
|
-
* if (!doc) throw new Error('No active document');
|
|
1119
|
-
*
|
|
1120
|
-
* const paragraph = doc.getBody().getChild(0).asParagraph();
|
|
1121
|
-
* doc.getBody().setParagraphText(paragraph.getKey(), 'Updated text');
|
|
1122
|
-
* ```
|
|
1123
|
-
*/
|
|
1124
|
-
setParagraphText(key, text) {
|
|
1125
|
-
const resolved = this.resolveParagraph(key);
|
|
1126
|
-
return this.replaceRange({
|
|
1127
|
-
startOffset: resolved.startOffset,
|
|
1128
|
-
endOffset: resolved.endOffset
|
|
1129
|
-
}, text);
|
|
1130
|
-
}
|
|
1131
|
-
/**
|
|
1132
|
-
* Append text to a paragraph by paragraph id.
|
|
1133
|
-
* @param {string} key The paragraph id.
|
|
1134
|
-
* @param {string} text The text to append before the paragraph break.
|
|
1135
|
-
* @returns {boolean} `true` if the text was appended.
|
|
1136
|
-
* @example
|
|
1137
|
-
* ```ts
|
|
1138
|
-
* const doc = univerAPI.getActiveDocument();
|
|
1139
|
-
* if (!doc) throw new Error('No active document');
|
|
1140
|
-
*
|
|
1141
|
-
* const paragraph = doc.getBody().getChild(0).asParagraph();
|
|
1142
|
-
* doc.getBody().appendParagraphText(paragraph.getKey(), ' suffix');
|
|
1143
|
-
* ```
|
|
1144
|
-
*/
|
|
1145
|
-
appendParagraphText(key, text) {
|
|
1146
|
-
const resolved = this.resolveParagraph(key);
|
|
1147
|
-
return this.insertText(resolved.endOffset, text);
|
|
1148
|
-
}
|
|
1149
|
-
/**
|
|
1150
|
-
* Remove a paragraph by paragraph id.
|
|
1151
|
-
* @param {string} key The paragraph id.
|
|
1152
|
-
* @returns {boolean} `true` if the paragraph was removed.
|
|
1153
|
-
* @example
|
|
1154
|
-
* ```ts
|
|
1155
|
-
* const doc = univerAPI.getActiveDocument();
|
|
1156
|
-
* if (!doc) throw new Error('No active document');
|
|
1157
|
-
*
|
|
1158
|
-
* const paragraph = doc.getBody().getChild(0).asParagraph();
|
|
1159
|
-
* doc.getBody().removeParagraph(paragraph.getKey());
|
|
1160
|
-
* ```
|
|
1161
|
-
*/
|
|
1162
|
-
removeParagraph(key) {
|
|
1163
|
-
const resolved = this.resolveParagraph(key);
|
|
1164
|
-
return this.deleteRange({
|
|
1165
|
-
startOffset: resolved.startOffset,
|
|
1166
|
-
endOffset: resolved.endOffset + 1
|
|
1167
|
-
});
|
|
1168
|
-
}
|
|
1169
|
-
/**
|
|
1170
|
-
* Get a paragraph text range by paragraph id.
|
|
1171
|
-
* @param {string} key The paragraph id.
|
|
1172
|
-
* @returns {IFDocTextRange} The paragraph range excluding the trailing paragraph break.
|
|
1173
|
-
* @example
|
|
1174
|
-
* ```ts
|
|
1175
|
-
* const doc = univerAPI.getActiveDocument();
|
|
1176
|
-
* if (!doc) throw new Error('No active document');
|
|
1177
|
-
*
|
|
1178
|
-
* const paragraph = doc.getBody().getChild(0).asParagraph();
|
|
1179
|
-
* const range = doc.getBody().getParagraphRange(paragraph.getKey());
|
|
1180
|
-
* console.log(range.startOffset, range.endOffset);
|
|
1181
|
-
* ```
|
|
1182
|
-
*/
|
|
1183
|
-
getParagraphRange(key) {
|
|
1184
|
-
const resolved = this.resolveParagraph(key);
|
|
1185
|
-
return {
|
|
1186
|
-
startOffset: resolved.startOffset,
|
|
1187
|
-
endOffset: resolved.endOffset,
|
|
1188
|
-
segmentId: this._segmentId
|
|
1189
|
-
};
|
|
1190
|
-
}
|
|
1191
|
-
/**
|
|
1192
|
-
* Check whether a paragraph has list metadata.
|
|
1193
|
-
* @param {string} key The paragraph id.
|
|
1194
|
-
* @returns {boolean} `true` if the paragraph is a list item.
|
|
1195
|
-
* @example
|
|
1196
|
-
* ```ts
|
|
1197
|
-
* const doc = univerAPI.getActiveDocument();
|
|
1198
|
-
* if (!doc) throw new Error('No active document');
|
|
1199
|
-
*
|
|
1200
|
-
* const paragraph = doc.getBody().getChild(0).asParagraph();
|
|
1201
|
-
* console.log(doc.getBody().isListParagraph(paragraph.getKey()));
|
|
1202
|
-
* ```
|
|
1203
|
-
*/
|
|
1204
|
-
isListParagraph(key) {
|
|
1205
|
-
return Boolean(this.resolveParagraph(key).paragraph.bullet);
|
|
1206
|
-
}
|
|
1207
|
-
/**
|
|
1208
|
-
* Check whether a paragraph is a task/checklist item.
|
|
1209
|
-
* @param {string} key The paragraph id.
|
|
1210
|
-
* @returns {boolean} `true` if the paragraph is an unchecked or checked task item.
|
|
1211
|
-
* @example
|
|
1212
|
-
* ```ts
|
|
1213
|
-
* const doc = univerAPI.getActiveDocument();
|
|
1214
|
-
* if (!doc) throw new Error('No active document');
|
|
1215
|
-
*
|
|
1216
|
-
* const paragraph = doc.getBody().getChild(0).asParagraph();
|
|
1217
|
-
* console.log(doc.getBody().isTaskParagraph(paragraph.getKey()));
|
|
1218
|
-
* ```
|
|
1219
|
-
*/
|
|
1220
|
-
isTaskParagraph(key) {
|
|
1221
|
-
var _this$resolveParagrap;
|
|
1222
|
-
const listType = (_this$resolveParagrap = this.resolveParagraph(key).paragraph.bullet) === null || _this$resolveParagrap === void 0 ? void 0 : _this$resolveParagrap.listType;
|
|
1223
|
-
return listType === _univerjs_core.PresetListType.CHECK_LIST || listType === _univerjs_core.PresetListType.CHECK_LIST_CHECKED;
|
|
1224
|
-
}
|
|
1225
|
-
/**
|
|
1226
|
-
* Set the checked state of a task/checklist paragraph.
|
|
1227
|
-
* @param {string} key The paragraph id.
|
|
1228
|
-
* @param {boolean} checked Whether the task should be checked.
|
|
1229
|
-
* @returns {boolean} `true` if the task state was updated, or `false` if the paragraph is not a task item.
|
|
1230
|
-
* @example
|
|
1231
|
-
* ```ts
|
|
1232
|
-
* const doc = univerAPI.getActiveDocument();
|
|
1233
|
-
* if (!doc) throw new Error('No active document');
|
|
1234
|
-
*
|
|
1235
|
-
* const paragraph = doc.getBody().getChild(0).asParagraph();
|
|
1236
|
-
* doc.getBody().setTaskChecked(paragraph.getKey(), true);
|
|
1237
|
-
* ```
|
|
1238
|
-
*/
|
|
1239
|
-
setTaskChecked(key, checked) {
|
|
1240
|
-
const resolved = this.resolveParagraph(key);
|
|
1241
|
-
const bullet = resolved.paragraph.bullet;
|
|
1242
|
-
if (!bullet || !this.isTaskParagraph(key)) return false;
|
|
1243
|
-
const updateBody = {
|
|
1244
|
-
dataStream: "",
|
|
1245
|
-
paragraphs: [{
|
|
1246
|
-
...resolved.paragraph,
|
|
1247
|
-
startIndex: 0,
|
|
1248
|
-
bullet: {
|
|
1249
|
-
...bullet,
|
|
1250
|
-
listType: checked ? _univerjs_core.PresetListType.CHECK_LIST_CHECKED : _univerjs_core.PresetListType.CHECK_LIST
|
|
1251
|
-
}
|
|
1252
|
-
}]
|
|
1253
|
-
};
|
|
1254
|
-
this._preserveExplicitParagraphIds(updateBody);
|
|
1255
|
-
return this._retainBodyRange({
|
|
1256
|
-
startOffset: resolved.endOffset,
|
|
1257
|
-
endOffset: resolved.endOffset + 1
|
|
1258
|
-
}, updateBody, _univerjs_core.UpdateDocsAttributeType.REPLACE);
|
|
144
|
+
getSegmentId() {
|
|
145
|
+
return this._segmentId;
|
|
1259
146
|
}
|
|
1260
147
|
/**
|
|
1261
|
-
*
|
|
1262
|
-
* @
|
|
1263
|
-
* @returns {IFDocResolvedParagraph} The current paragraph metadata.
|
|
148
|
+
* Get this paragraph's metadata.
|
|
149
|
+
* @returns {IFDocumentParagraphInfo} The paragraph info.
|
|
1264
150
|
* @example
|
|
1265
151
|
* ```ts
|
|
1266
|
-
* const
|
|
1267
|
-
*
|
|
1268
|
-
*
|
|
1269
|
-
* const paragraph = doc.getBody().getChild(0).asParagraph();
|
|
1270
|
-
* const resolved = doc.getBody().resolveParagraph(paragraph.getKey());
|
|
1271
|
-
* console.log(resolved.paragraphIndex);
|
|
152
|
+
* const fDocument = univerAPI.getActiveDocument();
|
|
153
|
+
* const paragraph = fDocument.getParagraphs()[0];
|
|
154
|
+
* console.log(paragraph?.getInfo());
|
|
1272
155
|
* ```
|
|
1273
156
|
*/
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
const
|
|
1277
|
-
const matches = ((_body$paragraphs = body.paragraphs) !== null && _body$paragraphs !== void 0 ? _body$paragraphs : []).map((paragraph, paragraphIndex) => ({
|
|
157
|
+
getInfo() {
|
|
158
|
+
const { paragraphs = [] } = this._document.getBody(this._segmentId);
|
|
159
|
+
const matches = paragraphs.map((paragraph, paragraphIndex) => ({
|
|
1278
160
|
paragraph,
|
|
1279
161
|
paragraphIndex
|
|
1280
|
-
})).filter(({ paragraph }) => paragraph.paragraphId ===
|
|
1281
|
-
if (matches.length
|
|
162
|
+
})).filter(({ paragraph }) => paragraph.paragraphId === this._paragraphId);
|
|
163
|
+
if (matches.length === 0) throw new Error(`Document paragraph with id ${this._paragraphId} not found`);
|
|
164
|
+
if (matches.length > 1) throw new Error(`Multiple document paragraphs with id ${this._paragraphId} found`);
|
|
1282
165
|
const { paragraph, paragraphIndex } = matches[0];
|
|
1283
166
|
return {
|
|
1284
167
|
paragraph,
|
|
1285
168
|
paragraphIndex,
|
|
1286
|
-
startOffset: paragraphIndex > 0 ?
|
|
169
|
+
startOffset: paragraphIndex > 0 ? paragraphs[paragraphIndex - 1].startIndex + 1 : 0,
|
|
1287
170
|
endOffset: paragraph.startIndex
|
|
1288
171
|
};
|
|
1289
172
|
}
|
|
1290
173
|
/**
|
|
1291
|
-
*
|
|
1292
|
-
* @
|
|
1293
|
-
* @param {string} key The persisted element key.
|
|
1294
|
-
* @returns {object} The current child metadata used by the facade.
|
|
174
|
+
* Get the current text range occupied by this paragraph.
|
|
175
|
+
* @returns {IFDocumentTextRange} The paragraph text range, excluding the trailing paragraph break.
|
|
1295
176
|
* @example
|
|
1296
177
|
* ```ts
|
|
1297
|
-
* const
|
|
1298
|
-
*
|
|
1299
|
-
*
|
|
1300
|
-
* const element = doc.getBody().getChild(0);
|
|
1301
|
-
* const resolved = doc.getBody().resolveElement(element.getType(), element.getKey());
|
|
1302
|
-
* console.log(resolved.position);
|
|
178
|
+
* const fDocument = univerAPI.getActiveDocument();
|
|
179
|
+
* const paragraph = fDocument.getParagraphs()[0];
|
|
180
|
+
* console.log(paragraph?.getRange());
|
|
1303
181
|
* ```
|
|
1304
182
|
*/
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
|
|
183
|
+
getRange() {
|
|
184
|
+
const { startOffset, endOffset } = this.getInfo();
|
|
185
|
+
return {
|
|
186
|
+
startOffset,
|
|
187
|
+
endOffset,
|
|
188
|
+
segmentId: this._segmentId
|
|
1311
189
|
};
|
|
1312
|
-
const child = this._getChildren().find((item) => item.type === type && item.key === key);
|
|
1313
|
-
if (!child) throw new Error("Doc element is stale");
|
|
1314
|
-
return child;
|
|
1315
190
|
}
|
|
1316
191
|
/**
|
|
1317
|
-
* Get
|
|
1318
|
-
* @
|
|
1319
|
-
* @returns {IDocumentBlockRange} The matching block range snapshot.
|
|
192
|
+
* Get this paragraph's plain text.
|
|
193
|
+
* @returns {string} The paragraph text without the trailing paragraph break.
|
|
1320
194
|
* @example
|
|
1321
195
|
* ```ts
|
|
1322
|
-
* const
|
|
1323
|
-
*
|
|
1324
|
-
*
|
|
1325
|
-
* const block = doc.getBody().getChild(0).asBlockRange();
|
|
1326
|
-
* console.log(doc.getBody().getBlockRange(block.getKey()).blockType);
|
|
196
|
+
* const fDocument = univerAPI.getActiveDocument();
|
|
197
|
+
* const paragraph = fDocument.getParagraphs()[0];
|
|
198
|
+
* console.log(paragraph?.getText());
|
|
1327
199
|
* ```
|
|
1328
200
|
*/
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
const
|
|
1332
|
-
|
|
1333
|
-
return blockRange;
|
|
201
|
+
getText() {
|
|
202
|
+
const { dataStream } = this._document.getBody(this._segmentId);
|
|
203
|
+
const { startOffset, endOffset } = this.getInfo();
|
|
204
|
+
return dataStream.slice(startOffset, endOffset);
|
|
1334
205
|
}
|
|
1335
206
|
/**
|
|
1336
|
-
*
|
|
1337
|
-
* @param {string}
|
|
1338
|
-
* @returns {
|
|
207
|
+
* Replace this paragraph's plain text.
|
|
208
|
+
* @param {string} text The replacement text. Do not include the paragraph break.
|
|
209
|
+
* @returns {boolean} `true` if the paragraph text was replaced.
|
|
1339
210
|
* @example
|
|
1340
211
|
* ```ts
|
|
1341
|
-
* const
|
|
1342
|
-
*
|
|
1343
|
-
*
|
|
1344
|
-
*
|
|
1345
|
-
* console.log(doc.getBody().getBlockRangeText(block.getKey()));
|
|
212
|
+
* const fDocument = univerAPI.getActiveDocument();
|
|
213
|
+
* const paragraph = fDocument.getParagraphs()[0];
|
|
214
|
+
* paragraph?.setText('New text');
|
|
215
|
+
* console.log(paragraph?.getText());
|
|
1346
216
|
* ```
|
|
1347
217
|
*/
|
|
1348
|
-
|
|
1349
|
-
const
|
|
1350
|
-
return
|
|
218
|
+
setText(text) {
|
|
219
|
+
const { startOffset, endOffset } = this.getInfo();
|
|
220
|
+
return replaceBodyRange({
|
|
221
|
+
startOffset,
|
|
222
|
+
endOffset,
|
|
223
|
+
segmentId: this._segmentId
|
|
224
|
+
}, buildPlainTextInsertBody(text), this._document.getDocumentDataModel(), this._injector);
|
|
1351
225
|
}
|
|
1352
226
|
/**
|
|
1353
|
-
*
|
|
1354
|
-
* @param {string}
|
|
1355
|
-
* @
|
|
1356
|
-
* @returns {boolean} `true` if the text was replaced.
|
|
227
|
+
* Append plain text before this paragraph's trailing paragraph break.
|
|
228
|
+
* @param {string} text The plain text to append.
|
|
229
|
+
* @returns {boolean} `true` if the text was appended.
|
|
1357
230
|
* @example
|
|
1358
231
|
* ```ts
|
|
1359
|
-
* const
|
|
1360
|
-
*
|
|
1361
|
-
*
|
|
1362
|
-
*
|
|
1363
|
-
* doc.getBody().setBlockRangeText(block.getKey(), 'Updated block');
|
|
232
|
+
* const fDocument = univerAPI.getActiveDocument();
|
|
233
|
+
* const paragraph = fDocument.getParagraphs()[0];
|
|
234
|
+
* paragraph?.appendText(' Appended text');
|
|
235
|
+
* console.log(paragraph?.getText());
|
|
1364
236
|
* ```
|
|
1365
237
|
*/
|
|
1366
|
-
|
|
1367
|
-
const
|
|
1368
|
-
|
|
1369
|
-
body.blockRanges = [{
|
|
1370
|
-
...blockRange,
|
|
1371
|
-
startIndex: 0,
|
|
1372
|
-
endIndex: text.length
|
|
1373
|
-
}];
|
|
1374
|
-
return this.replaceRange({
|
|
1375
|
-
startOffset: blockRange.startIndex,
|
|
1376
|
-
endOffset: blockRange.endIndex + 1
|
|
1377
|
-
}, { body });
|
|
238
|
+
appendText(text) {
|
|
239
|
+
const { endOffset } = this.getInfo();
|
|
240
|
+
return this._document.insertText(endOffset, text, this._segmentId);
|
|
1378
241
|
}
|
|
1379
242
|
/**
|
|
1380
|
-
*
|
|
1381
|
-
* @param {
|
|
1382
|
-
* @returns {boolean} `true` if the
|
|
243
|
+
* Apply paragraph style to a paragraph handle or text range.
|
|
244
|
+
* @param {IParagraphStyle} style The Univer paragraph style patch.
|
|
245
|
+
* @returns {boolean} `true` if the style was applied.
|
|
1383
246
|
* @example
|
|
1384
247
|
* ```ts
|
|
1385
|
-
* const
|
|
1386
|
-
*
|
|
1387
|
-
*
|
|
1388
|
-
*
|
|
1389
|
-
*
|
|
248
|
+
* const fDocument = univerAPI.getActiveDocument();
|
|
249
|
+
* const paragraph = fDocument.getParagraphs()[0];
|
|
250
|
+
* paragraph?.setText('Styled text');
|
|
251
|
+
* paragraph?.setStyle({
|
|
252
|
+
* textStyle: {
|
|
253
|
+
* cl: {
|
|
254
|
+
* rgb: '#FF0000',
|
|
255
|
+
* },
|
|
256
|
+
* fs: 14,
|
|
257
|
+
* },
|
|
258
|
+
* horizontalAlign: 2,
|
|
259
|
+
* });
|
|
260
|
+
* console.log(paragraph?.getInfo().paragraph.paragraphStyle);
|
|
1390
261
|
* ```
|
|
1391
262
|
*/
|
|
1392
|
-
|
|
1393
|
-
const
|
|
1394
|
-
|
|
1395
|
-
|
|
1396
|
-
|
|
1397
|
-
|
|
263
|
+
setStyle(style) {
|
|
264
|
+
const { paragraph, startOffset, endOffset } = this.getInfo();
|
|
265
|
+
let result = true;
|
|
266
|
+
if (style.textStyle && startOffset < endOffset) result = retainBodyRange({
|
|
267
|
+
startOffset,
|
|
268
|
+
endOffset,
|
|
269
|
+
segmentId: this._segmentId
|
|
270
|
+
}, {
|
|
271
|
+
dataStream: "",
|
|
272
|
+
textRuns: [{
|
|
273
|
+
st: 0,
|
|
274
|
+
ed: endOffset - startOffset,
|
|
275
|
+
ts: style.textStyle
|
|
276
|
+
}]
|
|
277
|
+
}, _univerjs_core.UpdateDocsAttributeType.COVER, this._document.getDocumentDataModel(), this._injector);
|
|
278
|
+
const updateBody = {
|
|
279
|
+
dataStream: "",
|
|
280
|
+
paragraphs: [{
|
|
281
|
+
...paragraph,
|
|
282
|
+
startIndex: 0,
|
|
283
|
+
paragraphStyle: {
|
|
284
|
+
...paragraph.paragraphStyle,
|
|
285
|
+
...style
|
|
286
|
+
}
|
|
287
|
+
}]
|
|
288
|
+
};
|
|
289
|
+
this._preserveExplicitParagraphIds(updateBody);
|
|
290
|
+
return retainBodyRange({
|
|
291
|
+
startOffset: endOffset,
|
|
292
|
+
endOffset: endOffset + 1,
|
|
293
|
+
segmentId: this._segmentId
|
|
294
|
+
}, updateBody, _univerjs_core.UpdateDocsAttributeType.REPLACE, this._document.getDocumentDataModel(), this._injector) && result;
|
|
1398
295
|
}
|
|
1399
296
|
/**
|
|
1400
|
-
*
|
|
1401
|
-
* @
|
|
1402
|
-
* @returns {ICustomTable} The matching table marker.
|
|
297
|
+
* Check whether this paragraph is a bullet, ordered, or checklist item.
|
|
298
|
+
* @returns {boolean} `true` if the paragraph has list metadata.
|
|
1403
299
|
* @example
|
|
1404
300
|
* ```ts
|
|
1405
|
-
* const
|
|
1406
|
-
*
|
|
1407
|
-
*
|
|
1408
|
-
* const table = doc.getBody().getChild(0).asTable();
|
|
1409
|
-
* console.log(doc.getBody().getTable(table.getTableId()));
|
|
301
|
+
* const fDocument = univerAPI.getActiveDocument();
|
|
302
|
+
* const paragraph = fDocument.getParagraphs()[0];
|
|
303
|
+
* console.log(paragraph?.isListItem());
|
|
1410
304
|
* ```
|
|
1411
305
|
*/
|
|
1412
|
-
|
|
1413
|
-
|
|
1414
|
-
|
|
1415
|
-
if (!table) throw new Error("Doc element is stale");
|
|
1416
|
-
return table;
|
|
306
|
+
isListItem() {
|
|
307
|
+
const { paragraph } = this.getInfo();
|
|
308
|
+
return Boolean(paragraph.bullet);
|
|
1417
309
|
}
|
|
1418
310
|
/**
|
|
1419
|
-
*
|
|
1420
|
-
* @
|
|
1421
|
-
* @returns {boolean} `true` if the table range was removed.
|
|
311
|
+
* Check whether this paragraph is a task/checklist item.
|
|
312
|
+
* @returns {boolean} `true` if this paragraph is an unchecked or checked task item.
|
|
1422
313
|
* @example
|
|
1423
314
|
* ```ts
|
|
1424
|
-
* const
|
|
1425
|
-
*
|
|
1426
|
-
*
|
|
1427
|
-
* const table = doc.getBody().getChild(0).asTable();
|
|
1428
|
-
* doc.getBody().removeTable(table.getTableId());
|
|
315
|
+
* const fDocument = univerAPI.getActiveDocument();
|
|
316
|
+
* const paragraph = fDocument.getParagraphs()[0];
|
|
317
|
+
* console.log(paragraph?.isTask());
|
|
1429
318
|
* ```
|
|
1430
319
|
*/
|
|
1431
|
-
|
|
1432
|
-
|
|
1433
|
-
|
|
1434
|
-
|
|
1435
|
-
|
|
1436
|
-
});
|
|
320
|
+
isTask() {
|
|
321
|
+
var _paragraph$bullet;
|
|
322
|
+
const { paragraph } = this.getInfo();
|
|
323
|
+
const listType = (_paragraph$bullet = paragraph.bullet) === null || _paragraph$bullet === void 0 ? void 0 : _paragraph$bullet.listType;
|
|
324
|
+
return listType === _univerjs_core.PresetListType.CHECK_LIST || listType === _univerjs_core.PresetListType.CHECK_LIST_CHECKED;
|
|
1437
325
|
}
|
|
1438
326
|
/**
|
|
1439
|
-
*
|
|
1440
|
-
* @param {
|
|
1441
|
-
* @returns {
|
|
327
|
+
* Set the checked state of this task/checklist paragraph.
|
|
328
|
+
* @param {boolean} checked Whether the task item should be checked.
|
|
329
|
+
* @returns {boolean} `true` if the task state was updated, or `false` if this paragraph is not a task item.
|
|
1442
330
|
* @example
|
|
1443
331
|
* ```ts
|
|
1444
|
-
* const
|
|
1445
|
-
*
|
|
332
|
+
* const fDocument = univerAPI.getActiveDocument();
|
|
333
|
+
* const paragraph = fDocument.getParagraphs()[0];
|
|
1446
334
|
*
|
|
1447
|
-
*
|
|
1448
|
-
*
|
|
335
|
+
* if (paragraph.isTask()) {
|
|
336
|
+
* const success = paragraph.setTaskChecked(true);
|
|
337
|
+
* console.log(success ? 'Task checked' : 'Failed to check task');
|
|
338
|
+
* }
|
|
1449
339
|
* ```
|
|
1450
340
|
*/
|
|
1451
|
-
|
|
1452
|
-
|
|
1453
|
-
const
|
|
1454
|
-
|
|
1455
|
-
|
|
341
|
+
setTaskChecked(checked) {
|
|
342
|
+
if (!this.isTask()) return false;
|
|
343
|
+
const { paragraph, endOffset } = this.getInfo();
|
|
344
|
+
const bullet = paragraph.bullet;
|
|
345
|
+
const updateBody = {
|
|
346
|
+
dataStream: "",
|
|
347
|
+
paragraphs: [{
|
|
348
|
+
...paragraph,
|
|
349
|
+
startIndex: 0,
|
|
350
|
+
bullet: {
|
|
351
|
+
...bullet,
|
|
352
|
+
listType: checked ? _univerjs_core.PresetListType.CHECK_LIST_CHECKED : _univerjs_core.PresetListType.CHECK_LIST
|
|
353
|
+
}
|
|
354
|
+
}]
|
|
355
|
+
};
|
|
356
|
+
this._preserveExplicitParagraphIds(updateBody);
|
|
357
|
+
return retainBodyRange({
|
|
358
|
+
startOffset: endOffset,
|
|
359
|
+
endOffset: endOffset + 1,
|
|
360
|
+
segmentId: this._segmentId
|
|
361
|
+
}, updateBody, _univerjs_core.UpdateDocsAttributeType.REPLACE, this._document.getDocumentDataModel(), this._injector);
|
|
1456
362
|
}
|
|
1457
363
|
/**
|
|
1458
|
-
* Remove
|
|
1459
|
-
* @
|
|
1460
|
-
* @returns {boolean} `true` if the custom block placeholder was removed.
|
|
364
|
+
* Remove this paragraph.
|
|
365
|
+
* @returns {boolean} `true` if the paragraph was removed.
|
|
1461
366
|
* @example
|
|
1462
367
|
* ```ts
|
|
1463
|
-
* const
|
|
1464
|
-
*
|
|
1465
|
-
*
|
|
1466
|
-
*
|
|
1467
|
-
* doc.getBody().removeCustomBlock(customBlock.getBlockId());
|
|
368
|
+
* const fDocument = univerAPI.getActiveDocument();
|
|
369
|
+
* const paragraph = fDocument.getParagraphs()[0];
|
|
370
|
+
* const success = paragraph?.remove();
|
|
371
|
+
* console.log(success ? 'Paragraph removed' : 'Failed to remove paragraph');
|
|
1468
372
|
* ```
|
|
1469
373
|
*/
|
|
1470
|
-
|
|
1471
|
-
const
|
|
1472
|
-
return this.deleteRange({
|
|
1473
|
-
startOffset
|
|
1474
|
-
endOffset:
|
|
374
|
+
remove() {
|
|
375
|
+
const { startOffset, endOffset } = this.getInfo();
|
|
376
|
+
return this._document.deleteRange({
|
|
377
|
+
startOffset,
|
|
378
|
+
endOffset: endOffset + 1,
|
|
379
|
+
segmentId: this._segmentId
|
|
1475
380
|
});
|
|
1476
381
|
}
|
|
1477
|
-
/**
|
|
1478
|
-
* Create a sibling element wrapper relative to the current element key.
|
|
1479
|
-
* @param {FDocElementType} type The current element type.
|
|
1480
|
-
* @param {string} key The current element key.
|
|
1481
|
-
* @param {-1 | 1} direction `-1` for previous sibling, `1` for next sibling.
|
|
1482
|
-
* @returns {FDocElement | null} The sibling wrapper, or `null` if none exists.
|
|
1483
|
-
* @example
|
|
1484
|
-
* ```ts
|
|
1485
|
-
* const doc = univerAPI.getActiveDocument();
|
|
1486
|
-
* if (!doc) throw new Error('No active document');
|
|
1487
|
-
*
|
|
1488
|
-
* const element = doc.getBody().getChild(0);
|
|
1489
|
-
* const next = doc.getBody().createSibling(element.getType(), element.getKey(), 1);
|
|
1490
|
-
* console.log(next?.getType());
|
|
1491
|
-
* ```
|
|
1492
|
-
*/
|
|
1493
|
-
createSibling(type, key, direction) {
|
|
1494
|
-
const index = this.getChildIndex(this._createElement(type, key));
|
|
1495
|
-
const child = this._getChildren()[index + direction];
|
|
1496
|
-
return child ? this._createElement(child.type, child.key) : null;
|
|
1497
|
-
}
|
|
1498
|
-
_getChildren() {
|
|
1499
|
-
var _body$paragraphs$leng, _body$paragraphs2, _body$blockRanges, _body$tables, _body$customBlocks;
|
|
1500
|
-
const body = this._getBody();
|
|
1501
|
-
const children = [];
|
|
1502
|
-
for (let index = 0; index < ((_body$paragraphs$leng = (_body$paragraphs2 = body.paragraphs) === null || _body$paragraphs2 === void 0 ? void 0 : _body$paragraphs2.length) !== null && _body$paragraphs$leng !== void 0 ? _body$paragraphs$leng : 0); index++) {
|
|
1503
|
-
const paragraph = body.paragraphs[index];
|
|
1504
|
-
children.push({
|
|
1505
|
-
type: "paragraph",
|
|
1506
|
-
key: this._getParagraphId(paragraph, index),
|
|
1507
|
-
position: index > 0 ? body.paragraphs[index - 1].startIndex + 1 : 0,
|
|
1508
|
-
priority: 3
|
|
1509
|
-
});
|
|
1510
|
-
}
|
|
1511
|
-
(_body$blockRanges = body.blockRanges) === null || _body$blockRanges === void 0 || _body$blockRanges.forEach((blockRange) => children.push({
|
|
1512
|
-
type: "blockRange",
|
|
1513
|
-
key: blockRange.blockId,
|
|
1514
|
-
position: blockRange.startIndex,
|
|
1515
|
-
priority: 0
|
|
1516
|
-
}));
|
|
1517
|
-
(_body$tables = body.tables) === null || _body$tables === void 0 || _body$tables.forEach((table) => children.push({
|
|
1518
|
-
type: "table",
|
|
1519
|
-
key: table.tableId,
|
|
1520
|
-
position: table.startIndex,
|
|
1521
|
-
priority: 1
|
|
1522
|
-
}));
|
|
1523
|
-
(_body$customBlocks = body.customBlocks) === null || _body$customBlocks === void 0 || _body$customBlocks.forEach((customBlock) => children.push({
|
|
1524
|
-
type: "customBlock",
|
|
1525
|
-
key: customBlock.blockId,
|
|
1526
|
-
position: customBlock.startIndex,
|
|
1527
|
-
priority: 2
|
|
1528
|
-
}));
|
|
1529
|
-
return children.sort((a, b) => a.position - b.position || a.priority - b.priority);
|
|
1530
|
-
}
|
|
1531
|
-
_createElement(type, key) {
|
|
1532
|
-
return new FDocElement(this, type, key);
|
|
1533
|
-
}
|
|
1534
|
-
_getBody() {
|
|
1535
|
-
const body = this._documentDataModel.getSelfOrHeaderFooterModel(this._segmentId).getBody();
|
|
1536
|
-
if (!body) throw new Error("The document body is empty");
|
|
1537
|
-
return body;
|
|
1538
|
-
}
|
|
1539
|
-
_getParagraphInsertOffset(index) {
|
|
1540
|
-
var _body$paragraphs3;
|
|
1541
|
-
const body = this._getBody();
|
|
1542
|
-
if (index <= 0) return 0;
|
|
1543
|
-
const paragraphs = (_body$paragraphs3 = body.paragraphs) !== null && _body$paragraphs3 !== void 0 ? _body$paragraphs3 : [];
|
|
1544
|
-
if (paragraphs.length === 0) return Math.max(0, body.dataStream.length - 1);
|
|
1545
|
-
if (index >= paragraphs.length) return paragraphs[paragraphs.length - 1].startIndex + 1;
|
|
1546
|
-
return paragraphs[index - 1].startIndex + 1;
|
|
1547
|
-
}
|
|
1548
|
-
_normalizeInsertedParagraphIndex(index) {
|
|
1549
|
-
var _this$_getBody$paragr4;
|
|
1550
|
-
const paragraphs = (_this$_getBody$paragr4 = this._getBody().paragraphs) !== null && _this$_getBody$paragr4 !== void 0 ? _this$_getBody$paragr4 : [];
|
|
1551
|
-
return Math.max(0, Math.min(index, paragraphs.length - 1));
|
|
1552
|
-
}
|
|
1553
|
-
_getParagraphId(paragraph, paragraphIndex) {
|
|
1554
|
-
if (!paragraph) throw new RangeError(`Paragraph index ${paragraphIndex} is out of range.`);
|
|
1555
|
-
if (!paragraph.paragraphId) throw new DocElementStaleError(`Paragraph at index ${paragraphIndex} is missing paragraphId.`);
|
|
1556
|
-
return paragraph.paragraphId;
|
|
1557
|
-
}
|
|
1558
382
|
_preserveExplicitParagraphIds(body) {
|
|
1559
|
-
body[RESTORE_INSERTED_PARAGRAPH_IDS] = true;
|
|
1560
|
-
}
|
|
1561
|
-
_findParagraphByRange(range) {
|
|
1562
|
-
var _this$_getBody$paragr5;
|
|
1563
|
-
const paragraphs = (_this$_getBody$paragr5 = this._getBody().paragraphs) !== null && _this$_getBody$paragr5 !== void 0 ? _this$_getBody$paragr5 : [];
|
|
1564
|
-
const paragraphIndex = paragraphs.findIndex((paragraph, index) => {
|
|
1565
|
-
return (index > 0 ? paragraphs[index - 1].startIndex + 1 : 0) <= range.startOffset && range.endOffset <= paragraph.startIndex;
|
|
1566
|
-
});
|
|
1567
|
-
if (paragraphIndex < 0) throw new RangeError("Range does not resolve to a paragraph.");
|
|
1568
|
-
const paragraph = paragraphs[paragraphIndex];
|
|
1569
|
-
return {
|
|
1570
|
-
paragraph,
|
|
1571
|
-
paragraphIndex,
|
|
1572
|
-
startOffset: paragraphIndex > 0 ? paragraphs[paragraphIndex - 1].startIndex + 1 : 0,
|
|
1573
|
-
endOffset: paragraph.startIndex
|
|
1574
|
-
};
|
|
1575
|
-
}
|
|
1576
|
-
_replaceBodyRange(range, insertBody) {
|
|
1577
|
-
const startOffset = range.startOffset;
|
|
1578
|
-
const endOffset = range.endOffset;
|
|
1579
|
-
const textX = new _univerjs_core.TextX();
|
|
1580
|
-
if (startOffset > 0) textX.push({
|
|
1581
|
-
t: _univerjs_core.TextXActionType.RETAIN,
|
|
1582
|
-
len: startOffset
|
|
1583
|
-
});
|
|
1584
|
-
if (endOffset > startOffset) textX.push({
|
|
1585
|
-
t: _univerjs_core.TextXActionType.DELETE,
|
|
1586
|
-
len: endOffset - startOffset
|
|
1587
|
-
});
|
|
1588
|
-
if (insertBody.dataStream.length > 0) textX.push({
|
|
1589
|
-
t: _univerjs_core.TextXActionType.INSERT,
|
|
1590
|
-
body: insertBody,
|
|
1591
|
-
len: insertBody.dataStream.length
|
|
1592
|
-
});
|
|
1593
|
-
return this._executeTextX(textX);
|
|
1594
|
-
}
|
|
1595
|
-
_retainBodyRange(range, body, coverType) {
|
|
1596
|
-
var _body$textRuns;
|
|
1597
|
-
if (((_body$textRuns = body.textRuns) === null || _body$textRuns === void 0 ? void 0 : _body$textRuns.length) && this._getBody().textRuns == null) this._ensureTextRuns();
|
|
1598
|
-
const textX = new _univerjs_core.TextX();
|
|
1599
|
-
if (range.startOffset > 0) textX.push({
|
|
1600
|
-
t: _univerjs_core.TextXActionType.RETAIN,
|
|
1601
|
-
len: range.startOffset
|
|
1602
|
-
});
|
|
1603
|
-
textX.push({
|
|
1604
|
-
t: _univerjs_core.TextXActionType.RETAIN,
|
|
1605
|
-
body,
|
|
1606
|
-
coverType,
|
|
1607
|
-
len: range.endOffset - range.startOffset
|
|
1608
|
-
});
|
|
1609
|
-
return this._executeTextX(textX);
|
|
1610
|
-
}
|
|
1611
|
-
_ensureTextRuns() {
|
|
1612
|
-
if (this._getBody().textRuns != null) return;
|
|
1613
|
-
const actions = _univerjs_core.JSONX.getInstance().replaceOp([...(0, _univerjs_core.getRichTextEditPath)(this._documentDataModel, this._segmentId), "textRuns"], void 0, []);
|
|
1614
|
-
this._commandService.syncExecuteCommand(_univerjs_docs.RichTextEditingMutation.id, {
|
|
1615
|
-
unitId: this._documentDataModel.getUnitId(),
|
|
1616
|
-
segmentId: this._segmentId,
|
|
1617
|
-
actions,
|
|
1618
|
-
textRanges: [],
|
|
1619
|
-
trigger: FACADE_TRIGGER,
|
|
1620
|
-
isEditing: false
|
|
1621
|
-
});
|
|
1622
|
-
}
|
|
1623
|
-
_executeTextX(textX) {
|
|
1624
|
-
const actions = _univerjs_core.JSONX.getInstance().editOp(textX.serialize(), (0, _univerjs_core.getRichTextEditPath)(this._documentDataModel, this._segmentId));
|
|
1625
|
-
const result = this._commandService.syncExecuteCommand(_univerjs_docs.RichTextEditingMutation.id, {
|
|
1626
|
-
unitId: this._documentDataModel.getUnitId(),
|
|
1627
|
-
segmentId: this._segmentId,
|
|
1628
|
-
actions,
|
|
1629
|
-
textRanges: [],
|
|
1630
|
-
trigger: FACADE_TRIGGER,
|
|
1631
|
-
isEditing: false
|
|
1632
|
-
});
|
|
1633
|
-
return Boolean(result);
|
|
383
|
+
body[_univerjs_core.RESTORE_INSERTED_PARAGRAPH_IDS] = true;
|
|
1634
384
|
}
|
|
1635
385
|
};
|
|
386
|
+
function isParagraphFacade(value) {
|
|
387
|
+
if (typeof value !== "object" || value === null) return false;
|
|
388
|
+
return typeof value.getId === "function" && typeof value.getSegmentId === "function" && typeof value.getInfo === "function" && typeof value.getRange === "function";
|
|
389
|
+
}
|
|
1636
390
|
|
|
1637
391
|
//#endregion
|
|
1638
392
|
//#region \0@oxc-project+runtime@0.137.0/helpers/esm/typeof.js
|
|
@@ -1704,43 +458,46 @@ let FDocument = class FDocument extends _univerjs_core_facade.FBaseInitialable {
|
|
|
1704
458
|
this._resourceLoaderService = _resourceLoaderService;
|
|
1705
459
|
this._commandService = _commandService;
|
|
1706
460
|
_defineProperty(this, "id", void 0);
|
|
1707
|
-
_defineProperty(this, "_docElementRegistry", new DocElementRegistry());
|
|
1708
461
|
this.id = this._documentDataModel.getUnitId();
|
|
1709
462
|
}
|
|
1710
463
|
/**
|
|
1711
464
|
* Get the document data model of the document.
|
|
465
|
+
* @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.
|
|
1712
466
|
* @returns {DocumentDataModel} The document data model.
|
|
1713
467
|
* @example
|
|
1714
468
|
* ```typescript
|
|
1715
469
|
* const fDocument = univerAPI.getActiveDocument();
|
|
1716
|
-
*
|
|
1717
|
-
*
|
|
470
|
+
* console.log(fDocument.getDocumentDataModel());
|
|
471
|
+
*
|
|
472
|
+
* const headerSegmentId = fDocument.ensurePageHeader();
|
|
473
|
+
* console.log(fDocument.getDocumentDataModel(headerSegmentId));
|
|
1718
474
|
* ```
|
|
1719
475
|
*/
|
|
1720
|
-
getDocumentDataModel() {
|
|
1721
|
-
|
|
476
|
+
getDocumentDataModel(segmentId = "") {
|
|
477
|
+
const documentDataModel = this._documentDataModel.getSelfOrHeaderFooterModel(segmentId);
|
|
478
|
+
if (!documentDataModel) throw new Error(segmentId === "" ? "Document data model is not found." : `Document data model is not found in the segment: ${segmentId}`);
|
|
479
|
+
return documentDataModel;
|
|
1722
480
|
}
|
|
1723
481
|
/**
|
|
1724
|
-
* Get the document body
|
|
1725
|
-
*
|
|
1726
|
-
* The
|
|
1727
|
-
*
|
|
1728
|
-
*
|
|
1729
|
-
* and custom blocks, use their existing ids.
|
|
1730
|
-
*
|
|
1731
|
-
* @returns {FDocBody} The document body API instance.
|
|
482
|
+
* Get the document body or header/footer body by the segment id.
|
|
483
|
+
* The main body has an empty segment id.
|
|
484
|
+
* The header and footer body have their respective segment ids.
|
|
485
|
+
* @param {string} segmentId The segment id of the body. Defaults to an empty string for the main body.
|
|
486
|
+
* @returns {IDocumentBody} The document body.
|
|
1732
487
|
* @example
|
|
1733
488
|
* ```typescript
|
|
1734
|
-
* const
|
|
1735
|
-
*
|
|
489
|
+
* const fDocument = univerAPI.getActiveDocument();
|
|
490
|
+
* console.log(fDocument.getBody()); // Get the main body
|
|
1736
491
|
*
|
|
1737
|
-
* const
|
|
1738
|
-
*
|
|
1739
|
-
* paragraph.appendText(' updated');
|
|
492
|
+
* const footerSegmentId = fDocument.ensurePageFooter();
|
|
493
|
+
* console.log(fDocument.getBody(footerSegmentId)); // Get the footer body
|
|
1740
494
|
* ```
|
|
1741
495
|
*/
|
|
1742
|
-
getBody() {
|
|
1743
|
-
|
|
496
|
+
getBody(segmentId = "") {
|
|
497
|
+
var _this$_documentDataMo;
|
|
498
|
+
const body = (_this$_documentDataMo = this._documentDataModel.getSelfOrHeaderFooterModel(segmentId)) === null || _this$_documentDataMo === void 0 ? void 0 : _this$_documentDataMo.getBody();
|
|
499
|
+
if (!body) throw new Error(segmentId === "" ? "Body is not found in the document." : `Body is not found in the segment: ${segmentId}`);
|
|
500
|
+
return body;
|
|
1744
501
|
}
|
|
1745
502
|
dispose() {
|
|
1746
503
|
super.dispose();
|
|
@@ -1751,8 +508,7 @@ let FDocument = class FDocument extends _univerjs_core_facade.FBaseInitialable {
|
|
|
1751
508
|
* @example
|
|
1752
509
|
* ```typescript
|
|
1753
510
|
* const fDocument = univerAPI.getActiveDocument();
|
|
1754
|
-
*
|
|
1755
|
-
* console.log(unitId);
|
|
511
|
+
* console.log(fDocument.getId());
|
|
1756
512
|
* ```
|
|
1757
513
|
*/
|
|
1758
514
|
getId() {
|
|
@@ -1764,14 +520,25 @@ let FDocument = class FDocument extends _univerjs_core_facade.FBaseInitialable {
|
|
|
1764
520
|
* @example
|
|
1765
521
|
* ```typescript
|
|
1766
522
|
* const fDocument = univerAPI.getActiveDocument();
|
|
1767
|
-
*
|
|
1768
|
-
* console.log(name);
|
|
523
|
+
* console.log(fDocument.getName());
|
|
1769
524
|
* ```
|
|
1770
525
|
*/
|
|
1771
526
|
getName() {
|
|
1772
527
|
return this._documentDataModel.getTitle() || "";
|
|
1773
528
|
}
|
|
1774
529
|
/**
|
|
530
|
+
* Whether the document is a modern document or not.
|
|
531
|
+
* @returns {boolean} `true` if the document is a modern document, or `false` if it is not.
|
|
532
|
+
* @example
|
|
533
|
+
* ```typescript
|
|
534
|
+
* const fDocument = univerAPI.getActiveDocument();
|
|
535
|
+
* console.log(fDocument.isModern());
|
|
536
|
+
* ```
|
|
537
|
+
*/
|
|
538
|
+
isModern() {
|
|
539
|
+
return this._documentDataModel.getSnapshot().documentStyle.documentFlavor === _univerjs_core.DocumentFlavor.MODERN;
|
|
540
|
+
}
|
|
541
|
+
/**
|
|
1775
542
|
* Save the document snapshot data, including the document content and resource data, etc.
|
|
1776
543
|
* @returns {IDocumentData} The document snapshot data.
|
|
1777
544
|
* @example
|
|
@@ -1813,127 +580,274 @@ let FDocument = class FDocument extends _univerjs_core_facade.FBaseInitialable {
|
|
|
1813
580
|
return this._commandService.syncExecuteCommand(_univerjs_core.RedoCommand.id);
|
|
1814
581
|
}
|
|
1815
582
|
/**
|
|
1816
|
-
*
|
|
1817
|
-
* @param {
|
|
1818
|
-
* @
|
|
583
|
+
* Ensure the page header segment exists and return its segment id.
|
|
584
|
+
* @param {number} pageIndex The zero-based page index. Defaults to the first page.
|
|
585
|
+
* @returns {string} The header segment id.
|
|
1819
586
|
* @example
|
|
1820
|
-
* ```
|
|
587
|
+
* ```ts
|
|
1821
588
|
* const fDocument = univerAPI.getActiveDocument();
|
|
1822
|
-
* const
|
|
1823
|
-
*
|
|
589
|
+
* const headerSegmentId = fDocument.ensurePageHeader();
|
|
590
|
+
* fDocument.insertText(0, 'Header text', headerSegmentId);
|
|
1824
591
|
* ```
|
|
1825
592
|
*/
|
|
1826
|
-
|
|
1827
|
-
|
|
1828
|
-
if (!body) throw new Error("The document body is empty");
|
|
1829
|
-
const lastPosition = body.dataStream.length - 2;
|
|
1830
|
-
return this.insertText(text, {
|
|
1831
|
-
startOffset: lastPosition,
|
|
1832
|
-
endOffset: lastPosition,
|
|
1833
|
-
segmentId: ""
|
|
1834
|
-
});
|
|
593
|
+
ensurePageHeader(pageIndex = 0) {
|
|
594
|
+
return this._ensureHeaderFooter("header", pageIndex);
|
|
1835
595
|
}
|
|
1836
596
|
/**
|
|
1837
|
-
*
|
|
1838
|
-
* @param {
|
|
1839
|
-
* @
|
|
1840
|
-
* @returns {boolean} `true` if the text was successfully inserted, or `false` if it failed.
|
|
597
|
+
* Ensure the page footer segment exists and return its segment id.
|
|
598
|
+
* @param {number} pageIndex The zero-based page index. Defaults to the first page.
|
|
599
|
+
* @returns {string} The footer segment id.
|
|
1841
600
|
* @example
|
|
1842
|
-
*
|
|
1843
|
-
* // Insert text at a specific range in the document body
|
|
1844
|
-
* ```typescript
|
|
601
|
+
* ```ts
|
|
1845
602
|
* const fDocument = univerAPI.getActiveDocument();
|
|
1846
|
-
* const
|
|
1847
|
-
*
|
|
1848
|
-
* endOffset: 5,
|
|
1849
|
-
* segmentId: '',
|
|
1850
|
-
* cursorOffset: 13,
|
|
1851
|
-
* });
|
|
1852
|
-
* console.log(success);
|
|
603
|
+
* const footerSegmentId = fDocument.ensurePageFooter();
|
|
604
|
+
* fDocument.insertText(0, 'Footer text', footerSegmentId);
|
|
1853
605
|
* ```
|
|
606
|
+
*/
|
|
607
|
+
ensurePageFooter(pageIndex = 0) {
|
|
608
|
+
return this._ensureHeaderFooter("footer", pageIndex);
|
|
609
|
+
}
|
|
610
|
+
/**
|
|
611
|
+
* Insert plain text at a document body offset.
|
|
612
|
+
* @param {number} index The zero-based insertion offset.
|
|
613
|
+
* @param {string} text The plain text to insert.
|
|
614
|
+
* @param {string} segmentId The segment id of the body. Defaults to an empty string for the main body.
|
|
615
|
+
* @returns {boolean} `true` if the edit was applied.
|
|
616
|
+
* @example
|
|
617
|
+
* ```ts
|
|
618
|
+
* const fDocument = univerAPI.getActiveDocument();
|
|
619
|
+
* fDocument.insertText(0, 'Hello ');
|
|
1854
620
|
*
|
|
1855
|
-
*
|
|
1856
|
-
*
|
|
621
|
+
* const headerSegmentId = fDocument.ensurePageHeader();
|
|
622
|
+
* fDocument.insertText(0, 'Header text', headerSegmentId);
|
|
623
|
+
* ```
|
|
624
|
+
*/
|
|
625
|
+
insertText(index, text, segmentId = "") {
|
|
626
|
+
return replaceBodyRange({
|
|
627
|
+
startOffset: index,
|
|
628
|
+
endOffset: index,
|
|
629
|
+
segmentId
|
|
630
|
+
}, buildPlainTextInsertBody(text), this._documentDataModel, this._injector);
|
|
631
|
+
}
|
|
632
|
+
/**
|
|
633
|
+
* Get all paragraphs in the document body or header/footer body by the segment id.
|
|
634
|
+
* @param {string} segmentId The segment id of the body. Defaults to an empty string for the main body.
|
|
635
|
+
* @returns {FDocumentParagraph[]} An array of paragraph facade instances.
|
|
636
|
+
* @example
|
|
637
|
+
* ```ts
|
|
1857
638
|
* const fDocument = univerAPI.getActiveDocument();
|
|
1858
|
-
* const
|
|
1859
|
-
*
|
|
639
|
+
* const paragraphs = fDocument.getParagraphs();
|
|
640
|
+
* console.log(paragraphs);
|
|
1860
641
|
*
|
|
1861
|
-
*
|
|
1862
|
-
*
|
|
1863
|
-
*
|
|
1864
|
-
*
|
|
1865
|
-
|
|
1866
|
-
|
|
1867
|
-
|
|
1868
|
-
|
|
1869
|
-
|
|
1870
|
-
|
|
1871
|
-
*
|
|
642
|
+
* const headerSegmentId = fDocument.ensurePageHeader();
|
|
643
|
+
* const headerParagraphs = fDocument.getParagraphs(headerSegmentId);
|
|
644
|
+
* console.log(headerParagraphs);
|
|
645
|
+
* ```
|
|
646
|
+
*/
|
|
647
|
+
getParagraphs(segmentId = "") {
|
|
648
|
+
const { paragraphs = [] } = this.getBody(segmentId);
|
|
649
|
+
return paragraphs.map((paragraph) => this._createFDocumentParagraph(paragraph.paragraphId, segmentId));
|
|
650
|
+
}
|
|
651
|
+
/**
|
|
652
|
+
* Get a paragraph by its paragraph id and segment id.
|
|
653
|
+
* @param {string} paragraphId The paragraph id.
|
|
654
|
+
* @param {string} segmentId The segment id of the body. Defaults to an empty string for the main body.
|
|
655
|
+
* @returns {FDocumentParagraph | null} The paragraph facade instance, or `null` if the paragraph is not found.
|
|
656
|
+
* @example
|
|
657
|
+
* ```ts
|
|
658
|
+
* const fDocument = univerAPI.getActiveDocument();
|
|
659
|
+
* const paragraph = fDocument.getParagraph('paragraph-01');
|
|
660
|
+
* console.log(paragraph);
|
|
1872
661
|
*
|
|
1873
|
-
*
|
|
1874
|
-
*
|
|
1875
|
-
*
|
|
1876
|
-
* fDocument.insertText('Hello, footer!', {
|
|
1877
|
-
* startOffset: 0,
|
|
1878
|
-
* endOffset: 0,
|
|
1879
|
-
* segmentId: footerId,
|
|
1880
|
-
* });
|
|
1881
|
-
* }
|
|
1882
|
-
* }
|
|
1883
|
-
* }
|
|
662
|
+
* const headerSegmentId = fDocument.ensurePageHeader();
|
|
663
|
+
* const headerParagraph = fDocument.getParagraph('header-paragraph-01', headerSegmentId);
|
|
664
|
+
* console.log(headerParagraph);
|
|
1884
665
|
* ```
|
|
1885
666
|
*/
|
|
1886
|
-
|
|
1887
|
-
|
|
1888
|
-
|
|
1889
|
-
|
|
1890
|
-
|
|
1891
|
-
|
|
1892
|
-
|
|
1893
|
-
|
|
1894
|
-
|
|
1895
|
-
|
|
1896
|
-
|
|
1897
|
-
|
|
667
|
+
getParagraph(paragraphId, segmentId = "") {
|
|
668
|
+
const { paragraphs = [] } = this.getBody(segmentId);
|
|
669
|
+
if (!paragraphs.find((paragraph) => paragraph.paragraphId === paragraphId)) return null;
|
|
670
|
+
return this._createFDocumentParagraph(paragraphId, segmentId);
|
|
671
|
+
}
|
|
672
|
+
/**
|
|
673
|
+
* Find a paragraph by its text content and segment id.
|
|
674
|
+
* @param {string} text The text content to search for.
|
|
675
|
+
* @param {string} segmentId The segment id of the body. Defaults to an empty string for the main body.
|
|
676
|
+
* @returns {FDocumentParagraph | null} The paragraph facade instance, or `null` if the paragraph is not found.
|
|
677
|
+
* @example
|
|
678
|
+
* ```ts
|
|
679
|
+
* const fDocument = univerAPI.getActiveDocument();
|
|
680
|
+
* const paragraph = fDocument.findParagraphByText('Hello');
|
|
681
|
+
* console.log(paragraph);
|
|
682
|
+
*
|
|
683
|
+
* const footerSegmentId = fDocument.ensurePageFooter();
|
|
684
|
+
* const footerParagraph = fDocument.findParagraphByText('Page', footerSegmentId);
|
|
685
|
+
* console.log(footerParagraph);
|
|
686
|
+
* ```
|
|
687
|
+
*/
|
|
688
|
+
findParagraphByText(text, segmentId = "") {
|
|
689
|
+
return this.findParagraphs({
|
|
690
|
+
text,
|
|
1898
691
|
segmentId
|
|
1899
|
-
};
|
|
1900
|
-
const removeLeadingParagraphBreak = startOffset === 0;
|
|
1901
|
-
const insertBody = buildPlainTextInsertBody(text, {
|
|
1902
|
-
paragraphStyle: getParagraphStyleAtOffset(body, startOffset),
|
|
1903
|
-
removeLeadingParagraphBreak
|
|
1904
|
-
});
|
|
1905
|
-
const cursorOffset = options.cursorOffset == null ? void 0 : getNormalizedPlainTextCursorOffset(text, options.cursorOffset, removeLeadingParagraphBreak);
|
|
1906
|
-
return this._commandService.syncExecuteCommand(_univerjs_docs.InsertTextCommand.id, {
|
|
1907
|
-
unitId,
|
|
1908
|
-
body: insertBody,
|
|
1909
|
-
range: activeRange,
|
|
1910
|
-
segmentId,
|
|
1911
|
-
...cursorOffset == null ? {} : { cursorOffset }
|
|
1912
|
-
});
|
|
692
|
+
})[0] || null;
|
|
1913
693
|
}
|
|
1914
694
|
/**
|
|
1915
|
-
*
|
|
1916
|
-
* @param {string}
|
|
1917
|
-
* @
|
|
1918
|
-
* @returns {boolean} `true` if the paragraphs were successfully inserted, or `false` if it failed.
|
|
695
|
+
* Find paragraphs by a query object, which can include text content, paragraph id, and segment id.
|
|
696
|
+
* @param {string | IFDocumentParagraphQuery} query The query object or text content to search for.
|
|
697
|
+
* @returns {FDocumentParagraph[]} An array of paragraph facade instances that match the query.
|
|
1919
698
|
* @example
|
|
1920
|
-
* ```
|
|
699
|
+
* ```ts
|
|
1921
700
|
* const fDocument = univerAPI.getActiveDocument();
|
|
1922
|
-
* const
|
|
1923
|
-
*
|
|
1924
|
-
*
|
|
1925
|
-
* });
|
|
1926
|
-
* console.log(
|
|
701
|
+
* const paragraphsWithText = fDocument.findParagraphs('Hello');
|
|
702
|
+
* console.log(paragraphsWithText);
|
|
703
|
+
*
|
|
704
|
+
* const paragraphsWithId = fDocument.findParagraphs({ paragraphId: 'paragraph-01' });
|
|
705
|
+
* console.log(paragraphsWithId);
|
|
706
|
+
*
|
|
707
|
+
* const headerSegmentId = fDocument.ensurePageHeader();
|
|
708
|
+
* const paragraphsWithSegment = fDocument.findParagraphs({ segmentId: headerSegmentId });
|
|
709
|
+
* console.log(paragraphsWithSegment);
|
|
1927
710
|
* ```
|
|
1928
711
|
*/
|
|
1929
|
-
|
|
1930
|
-
|
|
1931
|
-
|
|
1932
|
-
|
|
1933
|
-
|
|
1934
|
-
|
|
712
|
+
findParagraphs(query) {
|
|
713
|
+
const { text, paragraphId, segmentId = "" } = typeof query === "string" ? { text: query } : query;
|
|
714
|
+
return this.getParagraphs(segmentId).filter((paragraph) => {
|
|
715
|
+
if (paragraphId && paragraph.getId() !== paragraphId) return false;
|
|
716
|
+
if (text && !paragraph.getText().includes(text)) return false;
|
|
717
|
+
return true;
|
|
1935
718
|
});
|
|
1936
719
|
}
|
|
720
|
+
/**
|
|
721
|
+
* Insert a plain-text paragraph before the paragraph at the given paragraph index.
|
|
722
|
+
* @param {number} index The zero-based paragraph insertion index.
|
|
723
|
+
* @param {string} text The paragraph text. Defaults to an empty paragraph.
|
|
724
|
+
* @param {string} segmentId The segment id of the body. Defaults to an empty string for the main body.
|
|
725
|
+
* @returns {FDocumentParagraph} The inserted paragraph facade instance.
|
|
726
|
+
* @example
|
|
727
|
+
* ```ts
|
|
728
|
+
* const fDocument = univerAPI.getActiveDocument();
|
|
729
|
+
* const paragraph = fDocument.insertParagraph(0, 'Document title');
|
|
730
|
+
* paragraph.appendText(' suffix');
|
|
731
|
+
*
|
|
732
|
+
* const headerSegmentId = fDocument.ensurePageHeader();
|
|
733
|
+
* const headerParagraph = fDocument.insertParagraph(0, 'Header title', headerSegmentId);
|
|
734
|
+
* headerParagraph.appendText(' suffix');
|
|
735
|
+
* ```
|
|
736
|
+
*/
|
|
737
|
+
insertParagraph(index, text = "", segmentId = "") {
|
|
738
|
+
const offset = this._getParagraphInsertOffset(index, segmentId);
|
|
739
|
+
if (!replaceBodyRange({
|
|
740
|
+
startOffset: offset,
|
|
741
|
+
endOffset: offset,
|
|
742
|
+
segmentId
|
|
743
|
+
}, buildPlainTextInsertBody(`${text}\r`), this._documentDataModel, this._injector)) throw new Error("Failed to insert paragraph.");
|
|
744
|
+
const { paragraphs = [] } = this.getBody(segmentId);
|
|
745
|
+
const paragraph = paragraphs[index];
|
|
746
|
+
if (!paragraph) throw new Error("Failed to insert paragraph.");
|
|
747
|
+
return this._createFDocumentParagraph(paragraph.paragraphId, segmentId);
|
|
748
|
+
}
|
|
749
|
+
/**
|
|
750
|
+
* Append a plain-text paragraph at the end of the body.
|
|
751
|
+
* @param {string} text The paragraph text. Defaults to an empty paragraph.
|
|
752
|
+
* @returns {FDocumentParagraph} The appended paragraph wrapper.
|
|
753
|
+
* @example
|
|
754
|
+
* ```ts
|
|
755
|
+
* const fDocument = univerAPI.getActiveDocument();
|
|
756
|
+
* const paragraph = fDocument.appendParagraph('Summary');
|
|
757
|
+
* console.log(paragraph.getText());
|
|
758
|
+
*
|
|
759
|
+
* const footerSegmentId = fDocument.ensurePageFooter();
|
|
760
|
+
* const footerParagraph = fDocument.appendParagraph('Confidential', footerSegmentId);
|
|
761
|
+
* console.log(footerParagraph.getText());
|
|
762
|
+
* ```
|
|
763
|
+
*/
|
|
764
|
+
appendParagraph(text = "", segmentId = "") {
|
|
765
|
+
const { paragraphs = [] } = this.getBody(segmentId);
|
|
766
|
+
return this.insertParagraph(paragraphs.length, text, segmentId);
|
|
767
|
+
}
|
|
768
|
+
/**
|
|
769
|
+
* Delete a range from the body.
|
|
770
|
+
* @param {IFDocumentTextRange} range The text range to delete.
|
|
771
|
+
* @returns {boolean} `true` if the range was deleted.
|
|
772
|
+
* @example
|
|
773
|
+
* ```ts
|
|
774
|
+
* const fDocument = univerAPI.getActiveDocument();
|
|
775
|
+
* fDocument.deleteRange({ startOffset: 0, endOffset: 5 });
|
|
776
|
+
*
|
|
777
|
+
* const headerSegmentId = fDocument.ensurePageHeader();
|
|
778
|
+
* fDocument.deleteRange({ startOffset: 0, endOffset: 5, segmentId: headerSegmentId });
|
|
779
|
+
* ```
|
|
780
|
+
*/
|
|
781
|
+
deleteRange(range) {
|
|
782
|
+
const normalizedRange = this._normalizeDeleteRange(range);
|
|
783
|
+
if (normalizedRange.startOffset >= normalizedRange.endOffset) return false;
|
|
784
|
+
return replaceBodyRange(normalizedRange, { dataStream: "" }, this._documentDataModel, this._injector);
|
|
785
|
+
}
|
|
786
|
+
_createFDocumentParagraph(paragraphId, segmentId = "") {
|
|
787
|
+
return this._injector.createInstance(FDocumentParagraph, this, paragraphId, segmentId, this._injector);
|
|
788
|
+
}
|
|
789
|
+
_normalizeDeleteRange(range) {
|
|
790
|
+
const body = this.getBody(range.segmentId);
|
|
791
|
+
const protectedEndOffset = body.dataStream.endsWith("\r\n") ? Math.max(0, body.dataStream.length - 2) : body.dataStream.length;
|
|
792
|
+
const endOffset = Math.min(Math.max(range.endOffset, 0), protectedEndOffset);
|
|
793
|
+
return {
|
|
794
|
+
...range,
|
|
795
|
+
startOffset: Math.min(Math.max(range.startOffset, 0), endOffset),
|
|
796
|
+
endOffset
|
|
797
|
+
};
|
|
798
|
+
}
|
|
799
|
+
_getParagraphInsertOffset(index, segmentId = "") {
|
|
800
|
+
if (index <= 0) return 0;
|
|
801
|
+
const { dataStream, paragraphs = [] } = this.getBody(segmentId);
|
|
802
|
+
if (paragraphs.length === 0) return Math.max(0, dataStream.length - 1);
|
|
803
|
+
if (index >= paragraphs.length) return paragraphs[paragraphs.length - 1].startIndex + 1;
|
|
804
|
+
return paragraphs[index - 1].startIndex + 1;
|
|
805
|
+
}
|
|
806
|
+
_ensureHeaderFooter(kind, pageIndex) {
|
|
807
|
+
if (this.isModern()) throw new Error("The document is a modern document, header/footer is not supported.");
|
|
808
|
+
const { createType, segmentId: existingSegmentId } = this._getHeaderFooterCreateInfo(kind, pageIndex);
|
|
809
|
+
if (existingSegmentId) return existingSegmentId;
|
|
810
|
+
const segmentId = (0, _univerjs_core.generateRandomId)(6);
|
|
811
|
+
if (!this._commandService.syncExecuteCommand(_univerjs_docs.CreateHeaderFooterCommand.id, {
|
|
812
|
+
unitId: this.getId(),
|
|
813
|
+
segmentId,
|
|
814
|
+
createType
|
|
815
|
+
})) throw new Error(`Failed to create page ${kind}.`);
|
|
816
|
+
return segmentId;
|
|
817
|
+
}
|
|
818
|
+
_getHeaderFooterCreateInfo(kind, pageIndex) {
|
|
819
|
+
var _documentStyle$defaul, _documentStyle$defaul2;
|
|
820
|
+
const { documentStyle } = this._documentDataModel.getSnapshot();
|
|
821
|
+
const isFirstPage = pageIndex === 0;
|
|
822
|
+
const isEvenPage = (pageIndex + 1) % 2 === 0;
|
|
823
|
+
if (isFirstPage && documentStyle.useFirstPageHeaderFooter === _univerjs_core.BooleanNumber.TRUE) {
|
|
824
|
+
var _documentStyle$firstP, _documentStyle$firstP2;
|
|
825
|
+
return kind === "header" ? {
|
|
826
|
+
createType: _univerjs_docs.HeaderFooterType.FIRST_PAGE_HEADER,
|
|
827
|
+
segmentId: (_documentStyle$firstP = documentStyle.firstPageHeaderId) !== null && _documentStyle$firstP !== void 0 ? _documentStyle$firstP : ""
|
|
828
|
+
} : {
|
|
829
|
+
createType: _univerjs_docs.HeaderFooterType.FIRST_PAGE_FOOTER,
|
|
830
|
+
segmentId: (_documentStyle$firstP2 = documentStyle.firstPageFooterId) !== null && _documentStyle$firstP2 !== void 0 ? _documentStyle$firstP2 : ""
|
|
831
|
+
};
|
|
832
|
+
}
|
|
833
|
+
if (isEvenPage && documentStyle.evenAndOddHeaders === _univerjs_core.BooleanNumber.TRUE) {
|
|
834
|
+
var _documentStyle$evenPa, _documentStyle$evenPa2;
|
|
835
|
+
return kind === "header" ? {
|
|
836
|
+
createType: _univerjs_docs.HeaderFooterType.EVEN_PAGE_HEADER,
|
|
837
|
+
segmentId: (_documentStyle$evenPa = documentStyle.evenPageHeaderId) !== null && _documentStyle$evenPa !== void 0 ? _documentStyle$evenPa : ""
|
|
838
|
+
} : {
|
|
839
|
+
createType: _univerjs_docs.HeaderFooterType.EVEN_PAGE_FOOTER,
|
|
840
|
+
segmentId: (_documentStyle$evenPa2 = documentStyle.evenPageFooterId) !== null && _documentStyle$evenPa2 !== void 0 ? _documentStyle$evenPa2 : ""
|
|
841
|
+
};
|
|
842
|
+
}
|
|
843
|
+
return kind === "header" ? {
|
|
844
|
+
createType: _univerjs_docs.HeaderFooterType.DEFAULT_HEADER,
|
|
845
|
+
segmentId: (_documentStyle$defaul = documentStyle.defaultHeaderId) !== null && _documentStyle$defaul !== void 0 ? _documentStyle$defaul : ""
|
|
846
|
+
} : {
|
|
847
|
+
createType: _univerjs_docs.HeaderFooterType.DEFAULT_FOOTER,
|
|
848
|
+
segmentId: (_documentStyle$defaul2 = documentStyle.defaultFooterId) !== null && _documentStyle$defaul2 !== void 0 ? _documentStyle$defaul2 : ""
|
|
849
|
+
};
|
|
850
|
+
}
|
|
1937
851
|
};
|
|
1938
852
|
FDocument = __decorate([
|
|
1939
853
|
__decorateParam(1, (0, _univerjs_core.Inject)(_univerjs_core.Injector)),
|
|
@@ -1963,17 +877,12 @@ var FUniverDocsMixin = class extends _univerjs_core_facade.FUniver {
|
|
|
1963
877
|
_univerjs_core_facade.FUniver.extend(FUniverDocsMixin);
|
|
1964
878
|
|
|
1965
879
|
//#endregion
|
|
1966
|
-
exports.DocElementRegistry = DocElementRegistry;
|
|
1967
|
-
exports.DocElementStaleError = DocElementStaleError;
|
|
1968
|
-
exports.FDocBlockRange = FDocBlockRange;
|
|
1969
|
-
exports.FDocBody = FDocBody;
|
|
1970
|
-
exports.FDocCustomBlock = FDocCustomBlock;
|
|
1971
|
-
exports.FDocElement = FDocElement;
|
|
1972
|
-
exports.FDocParagraph = FDocParagraph;
|
|
1973
|
-
exports.FDocTable = FDocTable;
|
|
1974
880
|
Object.defineProperty(exports, 'FDocument', {
|
|
1975
881
|
enumerable: true,
|
|
1976
882
|
get: function () {
|
|
1977
883
|
return FDocument;
|
|
1978
884
|
}
|
|
1979
|
-
});
|
|
885
|
+
});
|
|
886
|
+
exports.FDocumentParagraph = FDocumentParagraph;
|
|
887
|
+
exports.isParagraphFacade = isParagraphFacade;
|
|
888
|
+
exports.stripBlockTokens = stripBlockTokens;
|