@univerjs/docs 1.0.0-alpha.1 → 1.0.0-alpha.2

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