@univerjs/docs 1.0.0-alpha.1 → 1.0.0-alpha.3
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 +1156 -868
- package/lib/cjs/index.js +723 -18
- package/lib/es/facade.js +1154 -867
- package/lib/es/index.js +701 -19
- package/lib/facade.js +1154 -867
- package/lib/index.js +701 -19
- package/lib/types/commands/commands/create-header-footer.command.d.ts +45 -0
- package/lib/types/commands/commands/set-document-default-paragraph-style.command.d.ts +24 -0
- package/lib/types/commands/commands/set-section-header-footer-link.command.d.ts +26 -0
- package/lib/types/commands/commands/update-document-section.command.d.ts +38 -0
- package/lib/types/embed-host-anchor.d.ts +61 -0
- package/lib/types/facade/f-document-paragraph.d.ts +87 -100
- package/lib/types/facade/f-document-section.d.ts +281 -0
- package/lib/types/facade/f-document-text-range.d.ts +136 -0
- package/lib/types/facade/f-document.d.ts +316 -26
- package/lib/types/facade/f-enum.d.ts +32 -0
- package/lib/types/facade/f-types.d.ts +16 -0
- package/lib/types/facade/index.d.ts +11 -6
- package/lib/types/facade/utils.d.ts +15 -1
- package/lib/types/index.d.ts +15 -1
- package/lib/types/utils/paragraphs.d.ts +18 -0
- package/lib/types/utils/section-columns.d.ts +18 -0
- package/lib/types/utils/sections.d.ts +18 -0
- package/lib/types/utils/util.d.ts +19 -0
- package/lib/umd/facade.js +3 -1
- package/lib/umd/index.js +2 -1
- package/package.json +5 -5
- package/lib/types/facade/f-document-block-range.d.ts +0 -132
- package/lib/types/facade/f-document-body.d.ts +0 -276
- package/lib/types/facade/f-document-custom-block.d.ts +0 -57
- package/lib/types/facade/f-document-element.d.ts +0 -193
- package/lib/types/facade/f-document-table.d.ts +0 -57
package/lib/facade.js
CHANGED
|
@@ -1,240 +1,278 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import { RichTextEditingMutation } from "@univerjs/docs";
|
|
1
|
+
import { BooleanNumber, ColumnSeparatorType, DashStyleType, DataStreamTreeTokenType, DocumentFlavor, ICommandService, IResourceLoaderService, IUniverInstanceService, Inject, Injector, JSONX, PresetListType, RESTORE_INSERTED_PARAGRAPH_IDS, RedoCommand, SectionType, TextX, TextXActionType, Tools, UndoCommand, UniverInstanceType, UpdateDocsAttributeType, createParagraphId, createSectionId, generateRandomId, getParagraphContentStartOffset, getRichTextEditPath, getSectionHeaderFooterReferenceKey, resolveSectionHeaderFooterReference } from "@univerjs/core";
|
|
2
|
+
import { FBaseInitialable, FEnum, FUniver } from "@univerjs/core/facade";
|
|
3
|
+
import { CreateHeaderFooterCommand, DeleteDocumentSectionBreakCommand, HeaderFooterType, InsertDocumentSectionBreakCommand, RichTextEditingMutation, SetSectionHeaderFooterLinkCommand, UpdateDocumentSectionCommand, createSectionColumnProperties, generateParagraphs, getTopLevelSectionBreaks } from "@univerjs/docs";
|
|
4
4
|
|
|
5
|
-
//#region src/facade/
|
|
5
|
+
//#region src/facade/utils.ts
|
|
6
|
+
function cloneParagraphStyle(paragraphStyle) {
|
|
7
|
+
return paragraphStyle == null ? paragraphStyle : JSON.parse(JSON.stringify(paragraphStyle));
|
|
8
|
+
}
|
|
9
|
+
function normalizePlainTextDataStream(dataStream) {
|
|
10
|
+
return dataStream.replace(/\r\n/g, "\r").replace(/\n/g, "\r");
|
|
11
|
+
}
|
|
12
|
+
function getRemovedLeadingParagraphBreakLength(dataStream, removeLeadingParagraphBreak) {
|
|
13
|
+
const normalized = normalizePlainTextDataStream(dataStream);
|
|
14
|
+
if (removeLeadingParagraphBreak && normalized.length > 1 && normalized.startsWith("\r")) return 1;
|
|
15
|
+
return 0;
|
|
16
|
+
}
|
|
17
|
+
function buildPlainTextInsertBody(dataStream, options = {}) {
|
|
18
|
+
const normalizedDataStream = normalizePlainTextDataStream(dataStream).slice(getRemovedLeadingParagraphBreakLength(dataStream, options.removeLeadingParagraphBreak));
|
|
19
|
+
const body = {
|
|
20
|
+
dataStream: normalizedDataStream,
|
|
21
|
+
customDecorations: [],
|
|
22
|
+
customRanges: [],
|
|
23
|
+
textRuns: []
|
|
24
|
+
};
|
|
25
|
+
const paragraphs = [];
|
|
26
|
+
const existingParagraphIds = /* @__PURE__ */ new Set();
|
|
27
|
+
for (let index = 0; index < normalizedDataStream.length; index++) if (normalizedDataStream[index] === "\r") paragraphs.push({
|
|
28
|
+
startIndex: index,
|
|
29
|
+
paragraphId: createParagraphId(existingParagraphIds),
|
|
30
|
+
...options.paragraphStyle == null ? {} : { paragraphStyle: cloneParagraphStyle(options.paragraphStyle) }
|
|
31
|
+
});
|
|
32
|
+
if (paragraphs.length > 0) body.paragraphs = paragraphs;
|
|
33
|
+
return body;
|
|
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
|
+
}
|
|
99
|
+
|
|
100
|
+
//#endregion
|
|
101
|
+
//#region src/facade/f-document-text-range.ts
|
|
6
102
|
/**
|
|
7
|
-
*
|
|
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.
|
|
103
|
+
* Facade wrapper for reading and styling a fixed document text range.
|
|
14
104
|
*
|
|
105
|
+
* Offsets are fixed when the wrapper is created. Create a new range after edits
|
|
106
|
+
* that insert or remove content before it.
|
|
15
107
|
* @hideconstructor
|
|
16
108
|
*/
|
|
17
|
-
var
|
|
18
|
-
constructor(
|
|
19
|
-
|
|
20
|
-
this.
|
|
21
|
-
this.
|
|
22
|
-
this.
|
|
109
|
+
var FDocumentTextRange = class {
|
|
110
|
+
constructor(_document, _startOffset, _endOffset, _segmentId, _injector) {
|
|
111
|
+
this._document = _document;
|
|
112
|
+
this._startOffset = _startOffset;
|
|
113
|
+
this._endOffset = _endOffset;
|
|
114
|
+
this._segmentId = _segmentId;
|
|
23
115
|
this._injector = _injector;
|
|
116
|
+
this._validateRange();
|
|
24
117
|
}
|
|
25
118
|
/**
|
|
26
|
-
*
|
|
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.
|
|
119
|
+
* Returns the serializable document range.
|
|
56
120
|
* @example
|
|
57
121
|
* ```ts
|
|
58
122
|
* const fDocument = univerAPI.getActiveDocument();
|
|
59
|
-
* const
|
|
60
|
-
*
|
|
61
|
-
* console.log(element?.isTable());
|
|
123
|
+
* const range = fDocument?.findParagraphByText('Launch')?.getTextRange();
|
|
124
|
+
* console.log(range?.getRange());
|
|
62
125
|
* ```
|
|
63
126
|
*/
|
|
64
|
-
|
|
65
|
-
return
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
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;
|
|
127
|
+
getRange() {
|
|
128
|
+
return {
|
|
129
|
+
startOffset: this._startOffset,
|
|
130
|
+
endOffset: this._endOffset,
|
|
131
|
+
segmentId: this._segmentId
|
|
132
|
+
};
|
|
80
133
|
}
|
|
81
134
|
/**
|
|
82
|
-
*
|
|
83
|
-
* @returns {boolean} `true` if this element is a custom block.
|
|
135
|
+
* Returns the plain data-stream text in this range.
|
|
84
136
|
* @example
|
|
85
137
|
* ```ts
|
|
86
138
|
* const fDocument = univerAPI.getActiveDocument();
|
|
87
|
-
* const
|
|
88
|
-
*
|
|
89
|
-
* console.log(element?.isCustomBlock());
|
|
139
|
+
* const range = fDocument?.findParagraphByText('Launch')?.getTextRange();
|
|
140
|
+
* console.log(range?.getText());
|
|
90
141
|
* ```
|
|
91
142
|
*/
|
|
92
|
-
|
|
93
|
-
return this.
|
|
143
|
+
getText() {
|
|
144
|
+
return this._document.getBody(this._segmentId).dataStream.slice(this._startOffset, this._endOffset);
|
|
94
145
|
}
|
|
95
146
|
/**
|
|
96
|
-
*
|
|
97
|
-
*
|
|
147
|
+
* Returns explicit text-style runs intersecting this range.
|
|
148
|
+
* Returned offsets are clipped to the range and remain document-relative.
|
|
98
149
|
* @example
|
|
99
150
|
* ```ts
|
|
100
151
|
* const fDocument = univerAPI.getActiveDocument();
|
|
101
|
-
* const
|
|
102
|
-
*
|
|
103
|
-
* console.log(element?.getKey());
|
|
152
|
+
* const range = fDocument?.findParagraphByText('Launch')?.getTextRange();
|
|
153
|
+
* console.log(range?.getExplicitTextStyleRuns());
|
|
104
154
|
* ```
|
|
105
155
|
*/
|
|
106
|
-
|
|
107
|
-
|
|
156
|
+
getExplicitTextStyleRuns() {
|
|
157
|
+
const { textRuns = [] } = this._document.getBody(this._segmentId);
|
|
158
|
+
return textRuns.filter((run) => run.st < this._endOffset && run.ed > this._startOffset).map((run) => {
|
|
159
|
+
var _run$ts;
|
|
160
|
+
return {
|
|
161
|
+
startOffset: Math.max(run.st, this._startOffset),
|
|
162
|
+
endOffset: Math.min(run.ed, this._endOffset),
|
|
163
|
+
textStyle: Tools.deepClone((_run$ts = run.ts) !== null && _run$ts !== void 0 ? _run$ts : {})
|
|
164
|
+
};
|
|
165
|
+
});
|
|
108
166
|
}
|
|
109
|
-
/**
|
|
110
|
-
|
|
111
|
-
|
|
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;
|
|
167
|
+
/** @deprecated Use `getExplicitTextStyleRuns()` to distinguish stored styles from effective styles. */
|
|
168
|
+
getTextStyleRuns() {
|
|
169
|
+
return this.getExplicitTextStyleRuns();
|
|
122
170
|
}
|
|
123
171
|
/**
|
|
124
|
-
*
|
|
125
|
-
*
|
|
172
|
+
* Returns top-level style properties that have the same explicit value
|
|
173
|
+
* across the complete range. Unstyled gaps make a property non-common.
|
|
126
174
|
* @example
|
|
127
175
|
* ```ts
|
|
128
176
|
* const fDocument = univerAPI.getActiveDocument();
|
|
129
|
-
* const
|
|
130
|
-
*
|
|
131
|
-
* console.log(element?.getResolvedInfo());
|
|
177
|
+
* const range = fDocument?.findParagraphByText('Launch')?.getTextRange();
|
|
178
|
+
* console.log(range?.getCommonExplicitTextStyle());
|
|
132
179
|
* ```
|
|
133
180
|
*/
|
|
134
|
-
|
|
135
|
-
|
|
181
|
+
getCommonExplicitTextStyle() {
|
|
182
|
+
if (this._startOffset === this._endOffset) return {};
|
|
183
|
+
const [first, ...rest] = this._getStyleSegments();
|
|
184
|
+
const common = Tools.deepClone(first.textStyle);
|
|
185
|
+
for (const key of Object.keys(common)) if (rest.some((run) => !isDeepEqual(run.textStyle[key], common[key]))) delete common[key];
|
|
186
|
+
return common;
|
|
136
187
|
}
|
|
137
|
-
/**
|
|
138
|
-
|
|
139
|
-
|
|
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);
|
|
188
|
+
/** @deprecated Use `getCommonExplicitTextStyle()` to distinguish stored styles from effective styles. */
|
|
189
|
+
getCommonTextStyle() {
|
|
190
|
+
return this.getCommonExplicitTextStyle();
|
|
150
191
|
}
|
|
151
192
|
/**
|
|
152
|
-
*
|
|
153
|
-
* @returns {FDocumentElement | null} The previous sibling wrapper, or `null` when this is the first child.
|
|
193
|
+
* Returns a serializable summary suitable for an agent/tool response.
|
|
154
194
|
* @example
|
|
155
195
|
* ```ts
|
|
156
196
|
* const fDocument = univerAPI.getActiveDocument();
|
|
157
|
-
* const
|
|
158
|
-
*
|
|
159
|
-
* console.log(element?.getPreviousSibling());
|
|
197
|
+
* const range = fDocument?.findParagraphByText('Launch')?.getTextRange();
|
|
198
|
+
* console.log(range?.describe());
|
|
160
199
|
* ```
|
|
161
200
|
*/
|
|
162
|
-
|
|
163
|
-
|
|
201
|
+
describe() {
|
|
202
|
+
const explicitTextStyleRuns = this.getExplicitTextStyleRuns();
|
|
203
|
+
const commonExplicitTextStyle = this.getCommonExplicitTextStyle();
|
|
204
|
+
return {
|
|
205
|
+
...this.getRange(),
|
|
206
|
+
text: this.getText(),
|
|
207
|
+
length: this._endOffset - this._startOffset,
|
|
208
|
+
explicitTextStyleRuns,
|
|
209
|
+
commonExplicitTextStyle,
|
|
210
|
+
textStyleRuns: explicitTextStyleRuns,
|
|
211
|
+
commonTextStyle: commonExplicitTextStyle
|
|
212
|
+
};
|
|
164
213
|
}
|
|
165
214
|
/**
|
|
166
|
-
*
|
|
167
|
-
*
|
|
168
|
-
*
|
|
215
|
+
* Merges a text-style patch into every character in the range.
|
|
216
|
+
* Existing text-run splitting, merging, and normalization are handled by
|
|
217
|
+
* the document mutation pipeline.
|
|
218
|
+
* `style.fs` is a font size in points (pt), not CSS pixels.
|
|
169
219
|
* @example
|
|
170
220
|
* ```ts
|
|
171
221
|
* const fDocument = univerAPI.getActiveDocument();
|
|
172
|
-
* const
|
|
173
|
-
*
|
|
174
|
-
*
|
|
175
|
-
* // Get the third sibling after this element
|
|
176
|
-
* const nextThirdSibling = element?.getSibling(3);
|
|
177
|
-
* console.log(nextThirdSibling?.getType());
|
|
222
|
+
* const range = fDocument?.findParagraphByText('Launch')?.getTextRange();
|
|
223
|
+
* range?.setTextStyle({ fs: 10.5, bl: univerAPI.Enum.BooleanNumber.TRUE });
|
|
178
224
|
* ```
|
|
179
225
|
*/
|
|
180
|
-
|
|
181
|
-
|
|
226
|
+
setTextStyle(style) {
|
|
227
|
+
if (this._startOffset === this._endOffset) return false;
|
|
228
|
+
return retainBodyRange(this.getRange(), {
|
|
229
|
+
dataStream: "",
|
|
230
|
+
textRuns: [{
|
|
231
|
+
st: 0,
|
|
232
|
+
ed: this._endOffset - this._startOffset,
|
|
233
|
+
ts: Tools.deepClone(style)
|
|
234
|
+
}]
|
|
235
|
+
}, UpdateDocsAttributeType.COVER, this._document.getDocumentDataModel(), this._injector);
|
|
182
236
|
}
|
|
183
237
|
/**
|
|
184
|
-
*
|
|
185
|
-
* @returns {boolean} `true` if the element content was removed.
|
|
238
|
+
* Replaces the range with plain text while preserving document mutation semantics.
|
|
186
239
|
* @example
|
|
187
240
|
* ```ts
|
|
188
241
|
* const fDocument = univerAPI.getActiveDocument();
|
|
189
|
-
* const
|
|
190
|
-
*
|
|
191
|
-
* const removed = element?.remove();
|
|
192
|
-
* console.log(removed);
|
|
242
|
+
* const range = fDocument?.findParagraphByText('Draft')?.getTextRange();
|
|
243
|
+
* range?.setText('Final');
|
|
193
244
|
* ```
|
|
194
245
|
*/
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
const
|
|
204
|
-
|
|
246
|
+
setText(text) {
|
|
247
|
+
return replaceBodyRange(this.getRange(), buildPlainTextInsertBody(text), this._document.getDocumentDataModel(), this._injector);
|
|
248
|
+
}
|
|
249
|
+
_validateRange() {
|
|
250
|
+
const bodyLength = this._document.getBody(this._segmentId).dataStream.length;
|
|
251
|
+
if (!Number.isInteger(this._startOffset) || !Number.isInteger(this._endOffset) || this._startOffset < 0 || this._endOffset < this._startOffset || this._endOffset > bodyLength) throw new RangeError(`Invalid document text range [${this._startOffset}, ${this._endOffset}) for body length ${bodyLength}.`);
|
|
252
|
+
}
|
|
253
|
+
_getStyleSegments() {
|
|
254
|
+
const explicitRuns = this.getExplicitTextStyleRuns();
|
|
255
|
+
const segments = [];
|
|
256
|
+
let offset = this._startOffset;
|
|
257
|
+
for (const run of explicitRuns) {
|
|
258
|
+
if (offset < run.startOffset) segments.push({
|
|
259
|
+
startOffset: offset,
|
|
260
|
+
endOffset: run.startOffset,
|
|
261
|
+
textStyle: {}
|
|
262
|
+
});
|
|
263
|
+
segments.push(run);
|
|
264
|
+
offset = run.endOffset;
|
|
265
|
+
}
|
|
266
|
+
if (offset < this._endOffset) segments.push({
|
|
267
|
+
startOffset: offset,
|
|
268
|
+
endOffset: this._endOffset,
|
|
269
|
+
textStyle: {}
|
|
270
|
+
});
|
|
271
|
+
return segments;
|
|
205
272
|
}
|
|
206
273
|
};
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
//#region src/facade/utils.ts
|
|
210
|
-
function cloneParagraphStyle(paragraphStyle) {
|
|
211
|
-
return paragraphStyle == null ? paragraphStyle : JSON.parse(JSON.stringify(paragraphStyle));
|
|
212
|
-
}
|
|
213
|
-
function normalizePlainTextDataStream(dataStream) {
|
|
214
|
-
return dataStream.replace(/\r\n/g, "\r").replace(/\n/g, "\r");
|
|
215
|
-
}
|
|
216
|
-
function getRemovedLeadingParagraphBreakLength(dataStream, removeLeadingParagraphBreak) {
|
|
217
|
-
const normalized = normalizePlainTextDataStream(dataStream);
|
|
218
|
-
if (removeLeadingParagraphBreak && normalized.length > 1 && normalized.startsWith("\r")) return 1;
|
|
219
|
-
return 0;
|
|
220
|
-
}
|
|
221
|
-
function buildPlainTextInsertBody(dataStream, options = {}) {
|
|
222
|
-
const normalizedDataStream = normalizePlainTextDataStream(dataStream).slice(getRemovedLeadingParagraphBreakLength(dataStream, options.removeLeadingParagraphBreak));
|
|
223
|
-
const body = {
|
|
224
|
-
dataStream: normalizedDataStream,
|
|
225
|
-
customDecorations: [],
|
|
226
|
-
customRanges: [],
|
|
227
|
-
textRuns: []
|
|
228
|
-
};
|
|
229
|
-
const paragraphs = [];
|
|
230
|
-
const existingParagraphIds = /* @__PURE__ */ new Set();
|
|
231
|
-
for (let index = 0; index < normalizedDataStream.length; index++) if (normalizedDataStream[index] === "\r") paragraphs.push({
|
|
232
|
-
startIndex: index,
|
|
233
|
-
paragraphId: createParagraphId(existingParagraphIds),
|
|
234
|
-
...options.paragraphStyle == null ? {} : { paragraphStyle: cloneParagraphStyle(options.paragraphStyle) }
|
|
235
|
-
});
|
|
236
|
-
if (paragraphs.length > 0) body.paragraphs = paragraphs;
|
|
237
|
-
return body;
|
|
274
|
+
function isDeepEqual(left, right) {
|
|
275
|
+
return JSON.stringify(left) === JSON.stringify(right);
|
|
238
276
|
}
|
|
239
277
|
|
|
240
278
|
//#endregion
|
|
@@ -248,14 +286,12 @@ function buildPlainTextInsertBody(dataStream, options = {}) {
|
|
|
248
286
|
*
|
|
249
287
|
* @hideconstructor
|
|
250
288
|
*/
|
|
251
|
-
var FDocumentParagraph = class
|
|
252
|
-
constructor(
|
|
253
|
-
|
|
254
|
-
this.
|
|
255
|
-
this.
|
|
256
|
-
this.
|
|
257
|
-
this.injector = injector;
|
|
258
|
-
if (this.getType() !== DocumentBlockType.PARAGRAPH) throw new Error(`Element type is not a paragraph: ${this.getType()}`);
|
|
289
|
+
var FDocumentParagraph = class {
|
|
290
|
+
constructor(_document, _paragraphId, _segmentId = "", _injector) {
|
|
291
|
+
this._document = _document;
|
|
292
|
+
this._paragraphId = _paragraphId;
|
|
293
|
+
this._segmentId = _segmentId;
|
|
294
|
+
this._injector = _injector;
|
|
259
295
|
}
|
|
260
296
|
/**
|
|
261
297
|
* Get the persisted paragraph id.
|
|
@@ -263,46 +299,52 @@ var FDocumentParagraph = class extends FDocumentElement {
|
|
|
263
299
|
* @example
|
|
264
300
|
* ```ts
|
|
265
301
|
* const fDocument = univerAPI.getActiveDocument();
|
|
266
|
-
* const
|
|
267
|
-
*
|
|
268
|
-
*
|
|
269
|
-
* if (element?.isParagraph()) {
|
|
270
|
-
* const paragraph = element.asParagraph();
|
|
271
|
-
* console.log(paragraph.getParagraphId());
|
|
272
|
-
* }
|
|
302
|
+
* const paragraph = fDocument.getParagraphs()[0];
|
|
303
|
+
* console.log(paragraph?.getId());
|
|
273
304
|
* ```
|
|
274
305
|
*/
|
|
275
|
-
|
|
276
|
-
return this.
|
|
306
|
+
getId() {
|
|
307
|
+
return this._paragraphId;
|
|
277
308
|
}
|
|
278
309
|
/**
|
|
279
|
-
* Get the
|
|
280
|
-
*
|
|
310
|
+
* Get the segment id of this paragraph.
|
|
311
|
+
* The main body paragraphs have an empty string segment id.
|
|
312
|
+
* The header and footer paragraphs have a non-empty string segment id.
|
|
313
|
+
* @returns {string} The segment id.
|
|
281
314
|
* @example
|
|
282
315
|
* ```ts
|
|
283
316
|
* const fDocument = univerAPI.getActiveDocument();
|
|
284
|
-
* const
|
|
285
|
-
*
|
|
286
|
-
*
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
317
|
+
* const paragraph = fDocument.getParagraphs()[0];
|
|
318
|
+
* console.log(paragraph?.getSegmentId());
|
|
319
|
+
* ```
|
|
320
|
+
*/
|
|
321
|
+
getSegmentId() {
|
|
322
|
+
return this._segmentId;
|
|
323
|
+
}
|
|
324
|
+
/**
|
|
325
|
+
* Get this paragraph's metadata.
|
|
326
|
+
* @returns {IFDocumentParagraphInfo} The paragraph info.
|
|
327
|
+
* @example
|
|
328
|
+
* ```ts
|
|
329
|
+
* const fDocument = univerAPI.getActiveDocument();
|
|
330
|
+
* const paragraph = fDocument.getParagraphs()[0];
|
|
331
|
+
* console.log(paragraph?.getInfo());
|
|
291
332
|
* ```
|
|
292
333
|
*/
|
|
293
|
-
|
|
294
|
-
const
|
|
334
|
+
getInfo() {
|
|
335
|
+
const body = this._document.getBody(this._segmentId);
|
|
336
|
+
const { paragraphs = [] } = body;
|
|
295
337
|
const matches = paragraphs.map((paragraph, paragraphIndex) => ({
|
|
296
338
|
paragraph,
|
|
297
339
|
paragraphIndex
|
|
298
|
-
})).filter(({ paragraph }) => paragraph.paragraphId === this.
|
|
299
|
-
if (matches.length === 0) throw new Error(`Document paragraph with id ${this.
|
|
300
|
-
if (matches.length > 1) throw new Error(`Multiple document paragraphs with id ${this.
|
|
340
|
+
})).filter(({ paragraph }) => paragraph.paragraphId === this._paragraphId);
|
|
341
|
+
if (matches.length === 0) throw new Error(`Document paragraph with id ${this._paragraphId} not found`);
|
|
342
|
+
if (matches.length > 1) throw new Error(`Multiple document paragraphs with id ${this._paragraphId} found`);
|
|
301
343
|
const { paragraph, paragraphIndex } = matches[0];
|
|
302
344
|
return {
|
|
303
345
|
paragraph,
|
|
304
346
|
paragraphIndex,
|
|
305
|
-
startOffset:
|
|
347
|
+
startOffset: getParagraphContentStartOffset(body, paragraph),
|
|
306
348
|
endOffset: paragraph.startIndex
|
|
307
349
|
};
|
|
308
350
|
}
|
|
@@ -312,42 +354,46 @@ var FDocumentParagraph = class extends FDocumentElement {
|
|
|
312
354
|
* @example
|
|
313
355
|
* ```ts
|
|
314
356
|
* const fDocument = univerAPI.getActiveDocument();
|
|
315
|
-
* const
|
|
316
|
-
*
|
|
317
|
-
*
|
|
318
|
-
* if (element?.isParagraph()) {
|
|
319
|
-
* const paragraph = element.asParagraph();
|
|
320
|
-
* const range = paragraph.getRange();
|
|
321
|
-
* fDocumentBody.setTextStyle(range, { bl: 1 });
|
|
322
|
-
* }
|
|
357
|
+
* const paragraph = fDocument.getParagraphs()[0];
|
|
358
|
+
* console.log(paragraph?.getRange());
|
|
323
359
|
* ```
|
|
324
360
|
*/
|
|
325
361
|
getRange() {
|
|
326
|
-
const { startOffset, endOffset } = this.
|
|
362
|
+
const { startOffset, endOffset } = this.getInfo();
|
|
327
363
|
return {
|
|
328
364
|
startOffset,
|
|
329
365
|
endOffset,
|
|
330
|
-
segmentId: this.
|
|
366
|
+
segmentId: this._segmentId
|
|
331
367
|
};
|
|
332
368
|
}
|
|
333
369
|
/**
|
|
370
|
+
* Returns an agent-friendly facade for reading and styling this paragraph's text.
|
|
371
|
+
* @returns {FDocumentTextRange} The paragraph text range, excluding the trailing paragraph break.
|
|
372
|
+
* @example
|
|
373
|
+
* ```ts
|
|
374
|
+
* const fDocument = univerAPI.getActiveDocument();
|
|
375
|
+
* const paragraph = fDocument?.findParagraphByText('Launch');
|
|
376
|
+
* const range = paragraph?.getTextRange();
|
|
377
|
+
* console.log(range?.describe());
|
|
378
|
+
* ```
|
|
379
|
+
*/
|
|
380
|
+
getTextRange() {
|
|
381
|
+
const { startOffset, endOffset } = this.getInfo();
|
|
382
|
+
return this._injector.createInstance(FDocumentTextRange, this._document, startOffset, endOffset, this._segmentId, this._injector);
|
|
383
|
+
}
|
|
384
|
+
/**
|
|
334
385
|
* Get this paragraph's plain text.
|
|
335
386
|
* @returns {string} The paragraph text without the trailing paragraph break.
|
|
336
387
|
* @example
|
|
337
388
|
* ```ts
|
|
338
389
|
* const fDocument = univerAPI.getActiveDocument();
|
|
339
|
-
* const
|
|
340
|
-
*
|
|
341
|
-
*
|
|
342
|
-
* if (element?.isParagraph()) {
|
|
343
|
-
* const paragraph = element.asParagraph();
|
|
344
|
-
* console.log(paragraph.getText());
|
|
345
|
-
* }
|
|
390
|
+
* const paragraph = fDocument.getParagraphs()[0];
|
|
391
|
+
* console.log(paragraph?.getText());
|
|
346
392
|
* ```
|
|
347
393
|
*/
|
|
348
394
|
getText() {
|
|
349
|
-
const { dataStream } = this.
|
|
350
|
-
const { startOffset, endOffset } = this.
|
|
395
|
+
const { dataStream } = this._document.getBody(this._segmentId);
|
|
396
|
+
const { startOffset, endOffset } = this.getInfo();
|
|
351
397
|
return dataStream.slice(startOffset, endOffset);
|
|
352
398
|
}
|
|
353
399
|
/**
|
|
@@ -357,22 +403,18 @@ var FDocumentParagraph = class extends FDocumentElement {
|
|
|
357
403
|
* @example
|
|
358
404
|
* ```ts
|
|
359
405
|
* const fDocument = univerAPI.getActiveDocument();
|
|
360
|
-
* const
|
|
361
|
-
*
|
|
362
|
-
*
|
|
363
|
-
* if (element?.isParagraph()) {
|
|
364
|
-
* const paragraph = element.asParagraph();
|
|
365
|
-
* const success = paragraph.setText('Updated title');
|
|
366
|
-
* console.log(success ? 'Text updated' : 'Failed to update text');
|
|
367
|
-
* }
|
|
406
|
+
* const paragraph = fDocument.getParagraphs()[0];
|
|
407
|
+
* paragraph?.setText('New text');
|
|
408
|
+
* console.log(paragraph?.getText());
|
|
368
409
|
* ```
|
|
369
410
|
*/
|
|
370
411
|
setText(text) {
|
|
371
|
-
const { startOffset, endOffset } = this.
|
|
372
|
-
return
|
|
412
|
+
const { startOffset, endOffset } = this.getInfo();
|
|
413
|
+
return replaceBodyRange({
|
|
373
414
|
startOffset,
|
|
374
|
-
endOffset
|
|
375
|
-
|
|
415
|
+
endOffset,
|
|
416
|
+
segmentId: this._segmentId
|
|
417
|
+
}, buildPlainTextInsertBody(text), this._document.getDocumentDataModel(), this._injector);
|
|
376
418
|
}
|
|
377
419
|
/**
|
|
378
420
|
* Append plain text before this paragraph's trailing paragraph break.
|
|
@@ -381,38 +423,52 @@ var FDocumentParagraph = class extends FDocumentElement {
|
|
|
381
423
|
* @example
|
|
382
424
|
* ```ts
|
|
383
425
|
* const fDocument = univerAPI.getActiveDocument();
|
|
384
|
-
* const
|
|
385
|
-
*
|
|
386
|
-
*
|
|
387
|
-
* if (element?.isParagraph()) {
|
|
388
|
-
* const paragraph = element.asParagraph();
|
|
389
|
-
* const success = paragraph.appendText(' Appended text');
|
|
390
|
-
* console.log(success ? 'Text appended' : 'Failed to append text');
|
|
391
|
-
* }
|
|
426
|
+
* const paragraph = fDocument.getParagraphs()[0];
|
|
427
|
+
* paragraph?.appendText(' Appended text');
|
|
428
|
+
* console.log(paragraph?.getText());
|
|
392
429
|
* ```
|
|
393
430
|
*/
|
|
394
431
|
appendText(text) {
|
|
395
|
-
const { endOffset } = this.
|
|
396
|
-
return this.
|
|
432
|
+
const { endOffset } = this.getInfo();
|
|
433
|
+
return this._document.insertText(endOffset, text, this._segmentId);
|
|
397
434
|
}
|
|
398
435
|
/**
|
|
399
436
|
* Apply paragraph style to a paragraph handle or text range.
|
|
437
|
+
* `style.textStyle.fs` is a font size in points (pt), not CSS pixels.
|
|
400
438
|
* @param {IParagraphStyle} style The Univer paragraph style patch.
|
|
401
439
|
* @returns {boolean} `true` if the style was applied.
|
|
402
440
|
* @example
|
|
403
441
|
* ```ts
|
|
404
442
|
* const fDocument = univerAPI.getActiveDocument();
|
|
405
|
-
* const
|
|
406
|
-
*
|
|
407
|
-
*
|
|
408
|
-
*
|
|
409
|
-
*
|
|
410
|
-
*
|
|
411
|
-
*
|
|
443
|
+
* const paragraph = fDocument.getParagraphs()[0];
|
|
444
|
+
* paragraph?.setText('Styled text');
|
|
445
|
+
* paragraph?.setStyle({
|
|
446
|
+
* textStyle: {
|
|
447
|
+
* cl: {
|
|
448
|
+
* rgb: '#FF0000',
|
|
449
|
+
* },
|
|
450
|
+
* fs: 14,
|
|
451
|
+
* },
|
|
452
|
+
* horizontalAlign: 2,
|
|
453
|
+
* });
|
|
454
|
+
* console.log(paragraph?.getInfo().paragraph.paragraphStyle);
|
|
412
455
|
* ```
|
|
413
456
|
*/
|
|
414
457
|
setStyle(style) {
|
|
415
|
-
const { paragraph, endOffset } = this.
|
|
458
|
+
const { paragraph, startOffset, endOffset } = this.getInfo();
|
|
459
|
+
let result = true;
|
|
460
|
+
if (style.textStyle && startOffset < endOffset) result = retainBodyRange({
|
|
461
|
+
startOffset,
|
|
462
|
+
endOffset,
|
|
463
|
+
segmentId: this._segmentId
|
|
464
|
+
}, {
|
|
465
|
+
dataStream: "",
|
|
466
|
+
textRuns: [{
|
|
467
|
+
st: 0,
|
|
468
|
+
ed: endOffset - startOffset,
|
|
469
|
+
ts: style.textStyle
|
|
470
|
+
}]
|
|
471
|
+
}, UpdateDocsAttributeType.COVER, this._document.getDocumentDataModel(), this._injector);
|
|
416
472
|
const updateBody = {
|
|
417
473
|
dataStream: "",
|
|
418
474
|
paragraphs: [{
|
|
@@ -425,10 +481,11 @@ var FDocumentParagraph = class extends FDocumentElement {
|
|
|
425
481
|
}]
|
|
426
482
|
};
|
|
427
483
|
this._preserveExplicitParagraphIds(updateBody);
|
|
428
|
-
return
|
|
484
|
+
return retainBodyRange({
|
|
429
485
|
startOffset: endOffset,
|
|
430
|
-
endOffset: endOffset + 1
|
|
431
|
-
|
|
486
|
+
endOffset: endOffset + 1,
|
|
487
|
+
segmentId: this._segmentId
|
|
488
|
+
}, updateBody, UpdateDocsAttributeType.REPLACE, this._document.getDocumentDataModel(), this._injector) && result;
|
|
432
489
|
}
|
|
433
490
|
/**
|
|
434
491
|
* Check whether this paragraph is a bullet, ordered, or checklist item.
|
|
@@ -436,17 +493,12 @@ var FDocumentParagraph = class extends FDocumentElement {
|
|
|
436
493
|
* @example
|
|
437
494
|
* ```ts
|
|
438
495
|
* const fDocument = univerAPI.getActiveDocument();
|
|
439
|
-
* const
|
|
440
|
-
*
|
|
441
|
-
*
|
|
442
|
-
* if (element?.isParagraph()) {
|
|
443
|
-
* const paragraph = element.asParagraph();
|
|
444
|
-
* console.log(paragraph.isListItem() ? 'This is a list item' : 'This is not a list item');
|
|
445
|
-
* }
|
|
496
|
+
* const paragraph = fDocument.getParagraphs()[0];
|
|
497
|
+
* console.log(paragraph?.isListItem());
|
|
446
498
|
* ```
|
|
447
499
|
*/
|
|
448
500
|
isListItem() {
|
|
449
|
-
const { paragraph } = this.
|
|
501
|
+
const { paragraph } = this.getInfo();
|
|
450
502
|
return Boolean(paragraph.bullet);
|
|
451
503
|
}
|
|
452
504
|
/**
|
|
@@ -455,18 +507,13 @@ var FDocumentParagraph = class extends FDocumentElement {
|
|
|
455
507
|
* @example
|
|
456
508
|
* ```ts
|
|
457
509
|
* const fDocument = univerAPI.getActiveDocument();
|
|
458
|
-
* const
|
|
459
|
-
*
|
|
460
|
-
*
|
|
461
|
-
* if (element?.isParagraph()) {
|
|
462
|
-
* const paragraph = element.asParagraph();
|
|
463
|
-
* console.log(paragraph.isTask() ? 'This is a task item' : 'This is not a task item');
|
|
464
|
-
* }
|
|
510
|
+
* const paragraph = fDocument.getParagraphs()[0];
|
|
511
|
+
* console.log(paragraph?.isTask());
|
|
465
512
|
* ```
|
|
466
513
|
*/
|
|
467
514
|
isTask() {
|
|
468
515
|
var _paragraph$bullet;
|
|
469
|
-
const { paragraph } = this.
|
|
516
|
+
const { paragraph } = this.getInfo();
|
|
470
517
|
const listType = (_paragraph$bullet = paragraph.bullet) === null || _paragraph$bullet === void 0 ? void 0 : _paragraph$bullet.listType;
|
|
471
518
|
return listType === PresetListType.CHECK_LIST || listType === PresetListType.CHECK_LIST_CHECKED;
|
|
472
519
|
}
|
|
@@ -477,22 +524,17 @@ var FDocumentParagraph = class extends FDocumentElement {
|
|
|
477
524
|
* @example
|
|
478
525
|
* ```ts
|
|
479
526
|
* const fDocument = univerAPI.getActiveDocument();
|
|
480
|
-
* const
|
|
481
|
-
* const element = fDocumentBody.getElement(0);
|
|
527
|
+
* const paragraph = fDocument.getParagraphs()[0];
|
|
482
528
|
*
|
|
483
|
-
* if (
|
|
484
|
-
* const
|
|
485
|
-
*
|
|
486
|
-
* if (paragraph.isTask()) {
|
|
487
|
-
* const success = paragraph.setTaskChecked(true);
|
|
488
|
-
* console.log(success ? 'Task checked' : 'Failed to check task');
|
|
489
|
-
* }
|
|
529
|
+
* if (paragraph.isTask()) {
|
|
530
|
+
* const success = paragraph.setTaskChecked(true);
|
|
531
|
+
* console.log(success ? 'Task checked' : 'Failed to check task');
|
|
490
532
|
* }
|
|
491
533
|
* ```
|
|
492
534
|
*/
|
|
493
535
|
setTaskChecked(checked) {
|
|
494
536
|
if (!this.isTask()) return false;
|
|
495
|
-
const { paragraph, endOffset } = this.
|
|
537
|
+
const { paragraph, endOffset } = this.getInfo();
|
|
496
538
|
const bullet = paragraph.bullet;
|
|
497
539
|
const updateBody = {
|
|
498
540
|
dataStream: "",
|
|
@@ -506,494 +548,488 @@ var FDocumentParagraph = class extends FDocumentElement {
|
|
|
506
548
|
}]
|
|
507
549
|
};
|
|
508
550
|
this._preserveExplicitParagraphIds(updateBody);
|
|
509
|
-
return
|
|
551
|
+
return retainBodyRange({
|
|
510
552
|
startOffset: endOffset,
|
|
511
|
-
endOffset: endOffset + 1
|
|
512
|
-
|
|
553
|
+
endOffset: endOffset + 1,
|
|
554
|
+
segmentId: this._segmentId
|
|
555
|
+
}, updateBody, UpdateDocsAttributeType.REPLACE, this._document.getDocumentDataModel(), this._injector);
|
|
556
|
+
}
|
|
557
|
+
/**
|
|
558
|
+
* Remove this paragraph.
|
|
559
|
+
* @returns {boolean} `true` if the paragraph was removed.
|
|
560
|
+
* @example
|
|
561
|
+
* ```ts
|
|
562
|
+
* const fDocument = univerAPI.getActiveDocument();
|
|
563
|
+
* const paragraph = fDocument.getParagraphs()[0];
|
|
564
|
+
* const success = paragraph?.remove();
|
|
565
|
+
* console.log(success ? 'Paragraph removed' : 'Failed to remove paragraph');
|
|
566
|
+
* ```
|
|
567
|
+
*/
|
|
568
|
+
remove() {
|
|
569
|
+
const { startOffset, endOffset } = this.getInfo();
|
|
570
|
+
return this._document.deleteRange({
|
|
571
|
+
startOffset,
|
|
572
|
+
endOffset: endOffset + 1,
|
|
573
|
+
segmentId: this._segmentId
|
|
574
|
+
});
|
|
513
575
|
}
|
|
514
576
|
_preserveExplicitParagraphIds(body) {
|
|
515
577
|
body[RESTORE_INSERTED_PARAGRAPH_IDS] = true;
|
|
516
578
|
}
|
|
517
579
|
};
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
return this._injector.createInstance(FDocumentParagraph, this._body, this._bodyEdit, this.getResolvedInfo(), this._injector);
|
|
522
|
-
}
|
|
523
|
-
};
|
|
524
|
-
FDocumentElement.extend(FDocumentParagraphMixin);
|
|
525
|
-
|
|
526
|
-
//#endregion
|
|
527
|
-
//#region \0@oxc-project+runtime@0.137.0/helpers/esm/typeof.js
|
|
528
|
-
function _typeof(o) {
|
|
529
|
-
"@babel/helpers - typeof";
|
|
530
|
-
return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function(o) {
|
|
531
|
-
return typeof o;
|
|
532
|
-
} : function(o) {
|
|
533
|
-
return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o;
|
|
534
|
-
}, _typeof(o);
|
|
580
|
+
function isParagraphFacade(value) {
|
|
581
|
+
if (typeof value !== "object" || value === null) return false;
|
|
582
|
+
return typeof value.getId === "function" && typeof value.getSegmentId === "function" && typeof value.getInfo === "function" && typeof value.getRange === "function";
|
|
535
583
|
}
|
|
536
584
|
|
|
537
585
|
//#endregion
|
|
538
|
-
//#region
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
if ("object" != _typeof(i)) return i;
|
|
545
|
-
throw new TypeError("@@toPrimitive must return a primitive value.");
|
|
586
|
+
//#region src/facade/f-document-section.ts
|
|
587
|
+
/** Error thrown when traditional section APIs are used to mutate a modern document. */
|
|
588
|
+
var DocsSectionUnsupportedDocumentFlavorError = class extends Error {
|
|
589
|
+
constructor() {
|
|
590
|
+
super("Section column APIs are supported only in traditional documents. Use ColumnGroup APIs for modern documents.");
|
|
591
|
+
this.name = "DocsSectionUnsupportedDocumentFlavorError";
|
|
546
592
|
}
|
|
547
|
-
|
|
548
|
-
}
|
|
549
|
-
|
|
550
|
-
//#endregion
|
|
551
|
-
//#region \0@oxc-project+runtime@0.137.0/helpers/esm/toPropertyKey.js
|
|
552
|
-
function toPropertyKey(t) {
|
|
553
|
-
var i = toPrimitive(t, "string");
|
|
554
|
-
return "symbol" == _typeof(i) ? i : i + "";
|
|
555
|
-
}
|
|
556
|
-
|
|
557
|
-
//#endregion
|
|
558
|
-
//#region \0@oxc-project+runtime@0.137.0/helpers/esm/defineProperty.js
|
|
559
|
-
function _defineProperty(e, r, t) {
|
|
560
|
-
return (r = toPropertyKey(r)) in e ? Object.defineProperty(e, r, {
|
|
561
|
-
value: t,
|
|
562
|
-
enumerable: !0,
|
|
563
|
-
configurable: !0,
|
|
564
|
-
writable: !0
|
|
565
|
-
}) : e[r] = t, e;
|
|
566
|
-
}
|
|
567
|
-
|
|
568
|
-
//#endregion
|
|
569
|
-
//#region src/facade/f-document-body.ts
|
|
593
|
+
};
|
|
570
594
|
/**
|
|
571
|
-
*
|
|
572
|
-
*
|
|
573
|
-
*
|
|
574
|
-
*
|
|
575
|
-
*
|
|
576
|
-
*
|
|
577
|
-
*
|
|
595
|
+
* Facade wrapper for an OOXML-compatible traditional document section.
|
|
596
|
+
* Modern documents use ColumnGroup APIs and cannot mutate this facade.
|
|
597
|
+
* @example
|
|
598
|
+
* ```ts
|
|
599
|
+
* const fDocument = univerAPI.getActiveDocument();
|
|
600
|
+
* if (fDocument && !fDocument.isModern()) {
|
|
601
|
+
* console.log(fDocument.getSection(0)?.describe());
|
|
602
|
+
* }
|
|
603
|
+
* ```
|
|
578
604
|
*/
|
|
579
|
-
var
|
|
580
|
-
constructor(
|
|
581
|
-
this.
|
|
605
|
+
var FDocumentSection = class {
|
|
606
|
+
constructor(_document, _sectionId, _injector) {
|
|
607
|
+
this._document = _document;
|
|
608
|
+
this._sectionId = _sectionId;
|
|
582
609
|
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
610
|
}
|
|
590
611
|
/**
|
|
591
|
-
*
|
|
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.
|
|
612
|
+
* Returns the persisted section id.
|
|
595
613
|
* @example
|
|
596
614
|
* ```ts
|
|
597
615
|
* const fDocument = univerAPI.getActiveDocument();
|
|
598
|
-
*
|
|
599
|
-
* console.log(fDocumentBody.getSegmentId());
|
|
616
|
+
* console.log(fDocument?.getSection(0)?.getId());
|
|
600
617
|
* ```
|
|
601
618
|
*/
|
|
602
|
-
|
|
603
|
-
return this.
|
|
619
|
+
getId() {
|
|
620
|
+
return this._sectionId;
|
|
604
621
|
}
|
|
605
622
|
/**
|
|
606
|
-
*
|
|
607
|
-
* @returns {IDocumentBody} The document body snapshot.
|
|
623
|
+
* Returns the current zero-based section index.
|
|
608
624
|
* @example
|
|
609
625
|
* ```ts
|
|
610
626
|
* const fDocument = univerAPI.getActiveDocument();
|
|
611
|
-
*
|
|
612
|
-
* console.log(fDocumentBody.getBody());
|
|
627
|
+
* console.log(fDocument?.getSection(0)?.getIndex());
|
|
613
628
|
* ```
|
|
614
629
|
*/
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
if (!body) throw new Error("The document body is empty");
|
|
618
|
-
return body;
|
|
630
|
+
getIndex() {
|
|
631
|
+
return this._resolve().index;
|
|
619
632
|
}
|
|
620
633
|
/**
|
|
621
|
-
*
|
|
622
|
-
* @returns {FDocumentElement[]} The list of top-level document elements.
|
|
634
|
+
* Returns the section break snapshot that terminates this section.
|
|
623
635
|
* @example
|
|
624
636
|
* ```ts
|
|
625
637
|
* const fDocument = univerAPI.getActiveDocument();
|
|
626
|
-
*
|
|
627
|
-
* const elements = fDocumentBody.getElements();
|
|
628
|
-
* console.log(elements);
|
|
638
|
+
* console.log(fDocument?.getSection(0)?.getConfig());
|
|
629
639
|
* ```
|
|
630
640
|
*/
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
});
|
|
641
|
+
getConfig() {
|
|
642
|
+
const { sectionBreak } = this._resolve();
|
|
643
|
+
return Tools.deepClone(sectionBreak);
|
|
635
644
|
}
|
|
636
645
|
/**
|
|
637
|
-
*
|
|
638
|
-
* @param {number} index The zero-based child index.
|
|
639
|
-
* @returns {FDocumentElement} The top-level child element wrapper.
|
|
646
|
+
* Returns the section content range, excluding its terminating section-break token.
|
|
640
647
|
* @example
|
|
641
648
|
* ```ts
|
|
642
649
|
* const fDocument = univerAPI.getActiveDocument();
|
|
643
|
-
*
|
|
644
|
-
* const element = fDocumentBody.getElement(0);
|
|
645
|
-
* console.log(element);
|
|
650
|
+
* console.log(fDocument?.getSection(0)?.getRange());
|
|
646
651
|
* ```
|
|
647
652
|
*/
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
653
|
+
getRange() {
|
|
654
|
+
const sectionBreaks = getTopLevelSectionBreaks(this._document.getBody());
|
|
655
|
+
const { index, sectionBreak } = this._resolve();
|
|
656
|
+
return {
|
|
657
|
+
startOffset: index === 0 ? 0 : sectionBreaks[index - 1].startIndex + 1,
|
|
658
|
+
endOffset: sectionBreak.startIndex,
|
|
659
|
+
segmentId: ""
|
|
660
|
+
};
|
|
651
661
|
}
|
|
652
662
|
/**
|
|
653
|
-
*
|
|
654
|
-
*
|
|
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.
|
|
663
|
+
* Returns the explicit columns. An empty array means the normal single-column layout.
|
|
664
|
+
* Column widths and trailing spaces are in points (pt).
|
|
658
665
|
* @example
|
|
659
666
|
* ```ts
|
|
660
667
|
* const fDocument = univerAPI.getActiveDocument();
|
|
661
|
-
*
|
|
662
|
-
* const element = fDocumentBody.getElement(0);
|
|
663
|
-
* console.log(fDocumentBody.getElementIndex(element));
|
|
668
|
+
* console.log(fDocument?.getSection(0)?.getColumns());
|
|
664
669
|
* ```
|
|
665
670
|
*/
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
if (index < 0) throw new Error("Doc element is stale");
|
|
670
|
-
return index;
|
|
671
|
+
getColumns() {
|
|
672
|
+
var _this$getConfig$colum;
|
|
673
|
+
return Tools.deepClone((_this$getConfig$colum = this.getConfig().columnProperties) !== null && _this$getConfig$colum !== void 0 ? _this$getConfig$colum : []);
|
|
671
674
|
}
|
|
672
675
|
/**
|
|
673
|
-
*
|
|
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.
|
|
676
|
+
* Returns a compact serializable section summary.
|
|
677
677
|
* @example
|
|
678
678
|
* ```ts
|
|
679
679
|
* const fDocument = univerAPI.getActiveDocument();
|
|
680
|
-
*
|
|
681
|
-
* fDocumentBody.insertText(0, 'Hello ');
|
|
680
|
+
* console.log(fDocument?.getSection(0)?.describe());
|
|
682
681
|
* ```
|
|
683
682
|
*/
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
683
|
+
describe() {
|
|
684
|
+
var _config$columnPropert, _config$columnSeparat, _config$sectionType;
|
|
685
|
+
const config = this.getConfig();
|
|
686
|
+
const columns = (_config$columnPropert = config.columnProperties) !== null && _config$columnPropert !== void 0 ? _config$columnPropert : [];
|
|
687
|
+
const headerFooter = {
|
|
688
|
+
defaultHeader: this._describeHeaderFooterReference("header", "default"),
|
|
689
|
+
defaultFooter: this._describeHeaderFooterReference("footer", "default"),
|
|
690
|
+
firstHeader: this._describeHeaderFooterReference("header", "first"),
|
|
691
|
+
firstFooter: this._describeHeaderFooterReference("footer", "first"),
|
|
692
|
+
evenHeader: this._describeHeaderFooterReference("header", "even"),
|
|
693
|
+
evenFooter: this._describeHeaderFooterReference("footer", "even")
|
|
694
|
+
};
|
|
695
|
+
return {
|
|
696
|
+
sectionId: this._sectionId,
|
|
697
|
+
index: this.getIndex(),
|
|
698
|
+
range: this.getRange(),
|
|
699
|
+
columnCount: columns.length || 1,
|
|
700
|
+
columns: Tools.deepClone(columns),
|
|
701
|
+
columnSeparatorType: (_config$columnSeparat = config.columnSeparatorType) !== null && _config$columnSeparat !== void 0 ? _config$columnSeparat : ColumnSeparatorType.NONE,
|
|
702
|
+
sectionType: (_config$sectionType = config.sectionType) !== null && _config$sectionType !== void 0 ? _config$sectionType : SectionType.SECTION_TYPE_UNSPECIFIED,
|
|
703
|
+
headerFooter,
|
|
704
|
+
config
|
|
705
|
+
};
|
|
689
706
|
}
|
|
690
707
|
/**
|
|
691
|
-
*
|
|
692
|
-
*
|
|
693
|
-
*
|
|
694
|
-
* @returns {boolean} `true` if the style was applied.
|
|
708
|
+
* Sets equal or explicitly sized columns for this traditional section.
|
|
709
|
+
* Use `columnCount = 1` to restore normal single-column layout.
|
|
710
|
+
* `gap` and `widths` are in points (pt).
|
|
695
711
|
* @example
|
|
696
712
|
* ```ts
|
|
697
713
|
* const fDocument = univerAPI.getActiveDocument();
|
|
698
|
-
*
|
|
699
|
-
*
|
|
714
|
+
* if (fDocument && !fDocument.isModern()) {
|
|
715
|
+
* fDocument.getSection(0)?.setColumns(2, { gap: 18, separator: true });
|
|
716
|
+
* }
|
|
700
717
|
* ```
|
|
701
718
|
*/
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
return this.
|
|
719
|
+
setColumns(columnCount, options = {}) {
|
|
720
|
+
var _options$gap, _options$separator;
|
|
721
|
+
this._assertTraditionalDocument();
|
|
722
|
+
if (!Number.isInteger(columnCount) || columnCount < 1) throw new RangeError("Section column count must be a positive integer.");
|
|
723
|
+
if (options.widths && options.widths.length !== columnCount) throw new RangeError("Section column widths must match the column count.");
|
|
724
|
+
const gap = Math.max(0, (_options$gap = options.gap) !== null && _options$gap !== void 0 ? _options$gap : 18);
|
|
725
|
+
const config = this.getConfig();
|
|
726
|
+
const columns = createSectionColumnProperties(this._document.getDocumentDataModel().getSnapshot().documentStyle, config, columnCount, gap, options.widths);
|
|
727
|
+
const separator = typeof options.separator === "boolean" ? options.separator ? ColumnSeparatorType.BETWEEN_EACH_COLUMN : ColumnSeparatorType.NONE : (_options$separator = options.separator) !== null && _options$separator !== void 0 ? _options$separator : ColumnSeparatorType.NONE;
|
|
728
|
+
return this._update({
|
|
729
|
+
columnProperties: columns,
|
|
730
|
+
columnSeparatorType: separator,
|
|
731
|
+
...options.sectionType == null ? {} : { sectionType: options.sectionType }
|
|
732
|
+
});
|
|
712
733
|
}
|
|
713
734
|
/**
|
|
714
|
-
*
|
|
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.
|
|
735
|
+
* Sets explicit OOXML-compatible column width and trailing-space values in points (pt).
|
|
718
736
|
* @example
|
|
719
737
|
* ```ts
|
|
720
738
|
* const fDocument = univerAPI.getActiveDocument();
|
|
721
|
-
*
|
|
722
|
-
*
|
|
723
|
-
*
|
|
739
|
+
* if (fDocument && !fDocument.isModern()) {
|
|
740
|
+
* fDocument.getSection(0)?.setColumnProperties([
|
|
741
|
+
* { width: 240, paddingEnd: 18 },
|
|
742
|
+
* { width: 240, paddingEnd: 0 },
|
|
743
|
+
* ], univerAPI.Enum.ColumnSeparatorType.BETWEEN_EACH_COLUMN);
|
|
744
|
+
* }
|
|
724
745
|
* ```
|
|
725
746
|
*/
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
}
|
|
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);
|
|
747
|
+
setColumnProperties(columns, separator = ColumnSeparatorType.NONE) {
|
|
748
|
+
this._assertTraditionalDocument();
|
|
749
|
+
if (columns.some(({ width, paddingEnd }) => width < 0 || paddingEnd < 0)) throw new RangeError("Section column widths and padding must be non-negative.");
|
|
750
|
+
return this._update({
|
|
751
|
+
columnProperties: Tools.deepClone(columns),
|
|
752
|
+
columnSeparatorType: separator
|
|
753
|
+
});
|
|
738
754
|
}
|
|
739
755
|
/**
|
|
740
|
-
*
|
|
741
|
-
* @param {string} text The paragraph text. Defaults to an empty paragraph.
|
|
742
|
-
* @returns {FDocumentParagraph} The appended paragraph wrapper.
|
|
756
|
+
* Sets how the next section begins.
|
|
743
757
|
* @example
|
|
744
758
|
* ```ts
|
|
745
759
|
* const fDocument = univerAPI.getActiveDocument();
|
|
746
|
-
*
|
|
747
|
-
*
|
|
748
|
-
*
|
|
760
|
+
* if (fDocument && !fDocument.isModern()) {
|
|
761
|
+
* fDocument.getSection(0)?.setSectionType(univerAPI.Enum.SectionType.NEXT_PAGE);
|
|
762
|
+
* }
|
|
749
763
|
* ```
|
|
750
764
|
*/
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
return this.
|
|
765
|
+
setSectionType(sectionType) {
|
|
766
|
+
this._assertTraditionalDocument();
|
|
767
|
+
return this._update({ sectionType });
|
|
754
768
|
}
|
|
755
769
|
/**
|
|
756
|
-
*
|
|
757
|
-
* @param {IFDocumentTextRange} range The text range to delete.
|
|
758
|
-
* @returns {boolean} `true` if the range was deleted.
|
|
770
|
+
* Ensures a header segment linked specifically to this section.
|
|
759
771
|
* @example
|
|
760
772
|
* ```ts
|
|
761
773
|
* const fDocument = univerAPI.getActiveDocument();
|
|
762
|
-
*
|
|
763
|
-
*
|
|
774
|
+
* if (fDocument && !fDocument.isModern()) {
|
|
775
|
+
* const segmentId = fDocument.getSection(0)?.ensureHeader();
|
|
776
|
+
* if (segmentId) {
|
|
777
|
+
* fDocument.insertText(0, 'Quarterly report', segmentId);
|
|
778
|
+
* }
|
|
779
|
+
* }
|
|
764
780
|
* ```
|
|
765
781
|
*/
|
|
766
|
-
|
|
767
|
-
return this.
|
|
782
|
+
ensureHeader(variant = "default") {
|
|
783
|
+
return this._ensureHeaderFooter("header", variant);
|
|
768
784
|
}
|
|
769
785
|
/**
|
|
770
|
-
*
|
|
771
|
-
* @param {FDocumentParagraph} paragraph The paragraph handle to remove.
|
|
772
|
-
* @returns {boolean} `true` if the paragraph was removed.
|
|
786
|
+
* Ensures a footer segment linked specifically to this section.
|
|
773
787
|
* @example
|
|
774
788
|
* ```ts
|
|
775
789
|
* const fDocument = univerAPI.getActiveDocument();
|
|
776
|
-
*
|
|
777
|
-
*
|
|
778
|
-
*
|
|
779
|
-
*
|
|
780
|
-
*
|
|
781
|
-
* const removed = fDocumentBody.removeParagraph(paragraph);
|
|
782
|
-
* console.log(removed ? 'Paragraph removed' : 'Failed to remove paragraph');
|
|
790
|
+
* if (fDocument && !fDocument.isModern()) {
|
|
791
|
+
* const segmentId = fDocument.getSection(0)?.ensureFooter('first');
|
|
792
|
+
* if (segmentId) {
|
|
793
|
+
* fDocument.insertText(0, 'Confidential', segmentId);
|
|
794
|
+
* }
|
|
783
795
|
* }
|
|
784
796
|
* ```
|
|
785
797
|
*/
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
return this.deleteRange({
|
|
789
|
-
startOffset,
|
|
790
|
-
endOffset: endOffset + 1
|
|
791
|
-
});
|
|
798
|
+
ensureFooter(variant = "default") {
|
|
799
|
+
return this._ensureHeaderFooter("footer", variant);
|
|
792
800
|
}
|
|
793
801
|
/**
|
|
794
|
-
*
|
|
795
|
-
* @param {FDocumentBlockRange} blockRange The block range handle to remove.
|
|
796
|
-
* @returns {boolean} `true` if the block range content was removed.
|
|
802
|
+
* Returns the effective header id after resolving links to previous sections.
|
|
797
803
|
* @example
|
|
798
804
|
* ```ts
|
|
799
805
|
* const fDocument = univerAPI.getActiveDocument();
|
|
800
|
-
*
|
|
801
|
-
*
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
806
|
+
* console.log(fDocument?.getSection(0)?.getHeaderId('default'));
|
|
807
|
+
* ```
|
|
808
|
+
*/
|
|
809
|
+
getHeaderId(variant = "default") {
|
|
810
|
+
var _this$_getHeaderFoote;
|
|
811
|
+
return (_this$_getHeaderFoote = this._getHeaderFooterReference("header", variant).segmentId) !== null && _this$_getHeaderFoote !== void 0 ? _this$_getHeaderFoote : null;
|
|
812
|
+
}
|
|
813
|
+
/**
|
|
814
|
+
* Returns the effective footer id after resolving links to previous sections.
|
|
815
|
+
* @example
|
|
816
|
+
* ```ts
|
|
817
|
+
* const fDocument = univerAPI.getActiveDocument();
|
|
818
|
+
* console.log(fDocument?.getSection(0)?.getFooterId('first'));
|
|
819
|
+
* ```
|
|
820
|
+
*/
|
|
821
|
+
getFooterId(variant = "default") {
|
|
822
|
+
var _this$_getHeaderFoote2;
|
|
823
|
+
return (_this$_getHeaderFoote2 = this._getHeaderFooterReference("footer", variant).segmentId) !== null && _this$_getHeaderFoote2 !== void 0 ? _this$_getHeaderFoote2 : null;
|
|
824
|
+
}
|
|
825
|
+
/**
|
|
826
|
+
* Whether this header variant inherits the previous section's reference.
|
|
827
|
+
* @example
|
|
828
|
+
* ```ts
|
|
829
|
+
* const fDocument = univerAPI.getActiveDocument();
|
|
830
|
+
* console.log(fDocument?.getSection(1)?.isHeaderLinkedToPrevious());
|
|
831
|
+
* ```
|
|
832
|
+
*/
|
|
833
|
+
isHeaderLinkedToPrevious(variant = "default") {
|
|
834
|
+
return this._getHeaderFooterReference("header", variant).linkedToPrevious;
|
|
835
|
+
}
|
|
836
|
+
/**
|
|
837
|
+
* Whether this footer variant inherits the previous section's reference.
|
|
838
|
+
* @example
|
|
839
|
+
* ```ts
|
|
840
|
+
* const fDocument = univerAPI.getActiveDocument();
|
|
841
|
+
* console.log(fDocument?.getSection(1)?.isFooterLinkedToPrevious('even'));
|
|
842
|
+
* ```
|
|
843
|
+
*/
|
|
844
|
+
isFooterLinkedToPrevious(variant = "default") {
|
|
845
|
+
return this._getHeaderFooterReference("footer", variant).linkedToPrevious;
|
|
846
|
+
}
|
|
847
|
+
/**
|
|
848
|
+
* Links or unlinks this header variant. Unlinking clones the inherited header.
|
|
849
|
+
* @example
|
|
850
|
+
* ```ts
|
|
851
|
+
* const fDocument = univerAPI.getActiveDocument();
|
|
852
|
+
* if (fDocument && !fDocument.isModern()) {
|
|
853
|
+
* fDocument.getSection(1)?.setHeaderLinkedToPrevious(false, 'default');
|
|
807
854
|
* }
|
|
808
855
|
* ```
|
|
809
856
|
*/
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
return this.deleteRange({
|
|
813
|
-
startOffset: startIndex,
|
|
814
|
-
endOffset: endIndex + 1
|
|
815
|
-
});
|
|
857
|
+
setHeaderLinkedToPrevious(linkedToPrevious, variant = "default") {
|
|
858
|
+
return this._setHeaderFooterLinkedToPrevious("header", variant, linkedToPrevious);
|
|
816
859
|
}
|
|
817
860
|
/**
|
|
818
|
-
*
|
|
819
|
-
* @returns {boolean} `true` if the table range was removed.
|
|
861
|
+
* Links or unlinks this footer variant. Unlinking clones the inherited footer.
|
|
820
862
|
* @example
|
|
821
863
|
* ```ts
|
|
822
864
|
* const fDocument = univerAPI.getActiveDocument();
|
|
823
|
-
*
|
|
824
|
-
*
|
|
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');
|
|
865
|
+
* if (fDocument && !fDocument.isModern()) {
|
|
866
|
+
* fDocument.getSection(1)?.setFooterLinkedToPrevious(true, 'even');
|
|
830
867
|
* }
|
|
831
868
|
* ```
|
|
832
869
|
*/
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
return this.deleteRange({
|
|
836
|
-
startOffset: startIndex,
|
|
837
|
-
endOffset: endIndex + 1
|
|
838
|
-
});
|
|
870
|
+
setFooterLinkedToPrevious(linkedToPrevious, variant = "default") {
|
|
871
|
+
return this._setHeaderFooterLinkedToPrevious("footer", variant, linkedToPrevious);
|
|
839
872
|
}
|
|
840
873
|
/**
|
|
841
|
-
*
|
|
842
|
-
*
|
|
843
|
-
* @returns {boolean} `true` if the custom block placeholder was removed.
|
|
874
|
+
* Updates header/footer switches and margins on this section break.
|
|
875
|
+
* `marginHeader` and `marginFooter` are in points (pt).
|
|
844
876
|
* @example
|
|
845
877
|
* ```ts
|
|
846
878
|
* const fDocument = univerAPI.getActiveDocument();
|
|
847
|
-
*
|
|
848
|
-
*
|
|
849
|
-
*
|
|
850
|
-
*
|
|
851
|
-
*
|
|
852
|
-
*
|
|
853
|
-
* console.log(removed ? 'Custom block removed' : 'Failed to remove custom block');
|
|
879
|
+
* if (fDocument && !fDocument.isModern()) {
|
|
880
|
+
* fDocument.getSection(0)?.setHeaderFooterOptions({
|
|
881
|
+
* marginHeader: 36,
|
|
882
|
+
* marginFooter: 36,
|
|
883
|
+
* useFirstPageHeaderFooter: univerAPI.Enum.BooleanNumber.TRUE,
|
|
884
|
+
* });
|
|
854
885
|
* }
|
|
855
886
|
* ```
|
|
856
887
|
*/
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
return this.
|
|
860
|
-
startOffset: startIndex,
|
|
861
|
-
endOffset: startIndex + 1
|
|
862
|
-
});
|
|
888
|
+
setHeaderFooterOptions(options) {
|
|
889
|
+
this._assertTraditionalDocument();
|
|
890
|
+
return this._update(options);
|
|
863
891
|
}
|
|
864
892
|
/**
|
|
865
|
-
*
|
|
866
|
-
* @param {FDocumentElement} element The element handle to resolve.
|
|
867
|
-
* @returns {IFDocumentElementInfo} The current child metadata used by the facade.
|
|
893
|
+
* Deletes this section break. The final top-level section break cannot be removed.
|
|
868
894
|
* @example
|
|
869
895
|
* ```ts
|
|
870
896
|
* const fDocument = univerAPI.getActiveDocument();
|
|
871
|
-
*
|
|
872
|
-
*
|
|
873
|
-
*
|
|
874
|
-
*
|
|
875
|
-
*
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
return
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
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);
|
|
897
|
+
* if (fDocument && !fDocument.isModern()) {
|
|
898
|
+
* const sections = fDocument.getSections();
|
|
899
|
+
* if (sections.length > 1) {
|
|
900
|
+
* sections[0].remove();
|
|
901
|
+
* }
|
|
902
|
+
* }
|
|
903
|
+
* ```
|
|
904
|
+
*/
|
|
905
|
+
remove() {
|
|
906
|
+
this._assertTraditionalDocument();
|
|
907
|
+
return this._injector.get(ICommandService).syncExecuteCommand(DeleteDocumentSectionBreakCommand.id, {
|
|
908
|
+
unitId: this._document.getId(),
|
|
909
|
+
sectionId: this._sectionId
|
|
910
|
+
});
|
|
920
911
|
}
|
|
921
|
-
|
|
912
|
+
_update(patch) {
|
|
913
|
+
const { sectionId: _sectionId, startIndex: _startIndex, ...config } = patch;
|
|
914
|
+
return this._injector.get(ICommandService).syncExecuteCommand(UpdateDocumentSectionCommand.id, {
|
|
915
|
+
unitId: this._document.getId(),
|
|
916
|
+
updates: [{
|
|
917
|
+
sectionId: this._sectionId,
|
|
918
|
+
config
|
|
919
|
+
}]
|
|
920
|
+
});
|
|
921
|
+
}
|
|
922
|
+
_ensureHeaderFooter(kind, variant) {
|
|
923
|
+
this._assertTraditionalDocument();
|
|
924
|
+
const { index } = this._resolve();
|
|
925
|
+
const existing = this.getConfig()[getSectionHeaderFooterReferenceKey(kind, variant)];
|
|
926
|
+
if (typeof existing === "string" && existing) return existing;
|
|
927
|
+
if (index > 0) {
|
|
928
|
+
const segmentId = generateRandomId(6);
|
|
929
|
+
if (!this._injector.get(ICommandService).syncExecuteCommand(SetSectionHeaderFooterLinkCommand.id, {
|
|
930
|
+
unitId: this._document.getId(),
|
|
931
|
+
sectionId: this._sectionId,
|
|
932
|
+
kind,
|
|
933
|
+
variant,
|
|
934
|
+
linkedToPrevious: false,
|
|
935
|
+
segmentId
|
|
936
|
+
})) throw new Error(`Failed to create section ${kind}.`);
|
|
937
|
+
return segmentId;
|
|
938
|
+
}
|
|
939
|
+
const types = {
|
|
940
|
+
default: kind === "header" ? HeaderFooterType.DEFAULT_HEADER : HeaderFooterType.DEFAULT_FOOTER,
|
|
941
|
+
first: kind === "header" ? HeaderFooterType.FIRST_PAGE_HEADER : HeaderFooterType.FIRST_PAGE_FOOTER,
|
|
942
|
+
even: kind === "header" ? HeaderFooterType.EVEN_PAGE_HEADER : HeaderFooterType.EVEN_PAGE_FOOTER
|
|
943
|
+
};
|
|
944
|
+
const segmentId = generateRandomId(6);
|
|
945
|
+
if (!this._injector.get(ICommandService).syncExecuteCommand(CreateHeaderFooterCommand.id, {
|
|
946
|
+
unitId: this._document.getId(),
|
|
947
|
+
segmentId,
|
|
948
|
+
createType: types[variant],
|
|
949
|
+
sectionId: this._sectionId
|
|
950
|
+
})) throw new Error(`Failed to create section ${kind}.`);
|
|
951
|
+
return segmentId;
|
|
952
|
+
}
|
|
953
|
+
_getHeaderFooterReference(kind, variant) {
|
|
954
|
+
const { index } = this._resolve();
|
|
955
|
+
return resolveSectionHeaderFooterReference(this._document.getDocumentDataModel().getSnapshot().documentStyle, getTopLevelSectionBreaks(this._document.getBody()), index, getSectionHeaderFooterReferenceKey(kind, variant));
|
|
956
|
+
}
|
|
957
|
+
_describeHeaderFooterReference(kind, variant) {
|
|
958
|
+
var _reference$segmentId;
|
|
959
|
+
const reference = this._getHeaderFooterReference(kind, variant);
|
|
922
960
|
return {
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
position: paragraphIndex > 0 ? previousParagraphStartIndex + 1 : 0,
|
|
926
|
-
priority: 3
|
|
961
|
+
segmentId: (_reference$segmentId = reference.segmentId) !== null && _reference$segmentId !== void 0 ? _reference$segmentId : null,
|
|
962
|
+
linkedToPrevious: reference.linkedToPrevious
|
|
927
963
|
};
|
|
928
964
|
}
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
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
|
|
965
|
+
_setHeaderFooterLinkedToPrevious(kind, variant, linkedToPrevious) {
|
|
966
|
+
this._assertTraditionalDocument();
|
|
967
|
+
return this._injector.get(ICommandService).syncExecuteCommand(SetSectionHeaderFooterLinkCommand.id, {
|
|
968
|
+
unitId: this._document.getId(),
|
|
969
|
+
sectionId: this._sectionId,
|
|
970
|
+
kind,
|
|
971
|
+
variant,
|
|
972
|
+
linkedToPrevious,
|
|
973
|
+
...linkedToPrevious ? {} : { segmentId: generateRandomId(6) }
|
|
966
974
|
});
|
|
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
|
}
|
|
975
|
-
|
|
976
|
-
|
|
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
|
-
});
|
|
976
|
+
_assertTraditionalDocument() {
|
|
977
|
+
if (this._document.getDocumentDataModel().getSnapshot().documentStyle.documentFlavor !== DocumentFlavor.TRADITIONAL) throw new DocsSectionUnsupportedDocumentFlavorError();
|
|
984
978
|
}
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
}
|
|
979
|
+
_resolve() {
|
|
980
|
+
this._assertTraditionalDocument();
|
|
981
|
+
const sectionBreaks = getTopLevelSectionBreaks(this._document.getBody());
|
|
982
|
+
const index = sectionBreaks.findIndex((section) => section.sectionId === this._sectionId);
|
|
983
|
+
if (index < 0) throw new Error(`Document section with id ${this._sectionId} not found.`);
|
|
984
|
+
return {
|
|
985
|
+
index,
|
|
986
|
+
sectionBreak: sectionBreaks[index]
|
|
987
|
+
};
|
|
994
988
|
}
|
|
995
989
|
};
|
|
996
990
|
|
|
991
|
+
//#endregion
|
|
992
|
+
//#region \0@oxc-project+runtime@0.137.0/helpers/esm/typeof.js
|
|
993
|
+
function _typeof(o) {
|
|
994
|
+
"@babel/helpers - typeof";
|
|
995
|
+
return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function(o) {
|
|
996
|
+
return typeof o;
|
|
997
|
+
} : function(o) {
|
|
998
|
+
return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o;
|
|
999
|
+
}, _typeof(o);
|
|
1000
|
+
}
|
|
1001
|
+
|
|
1002
|
+
//#endregion
|
|
1003
|
+
//#region \0@oxc-project+runtime@0.137.0/helpers/esm/toPrimitive.js
|
|
1004
|
+
function toPrimitive(t, r) {
|
|
1005
|
+
if ("object" != _typeof(t) || !t) return t;
|
|
1006
|
+
var e = t[Symbol.toPrimitive];
|
|
1007
|
+
if (void 0 !== e) {
|
|
1008
|
+
var i = e.call(t, r || "default");
|
|
1009
|
+
if ("object" != _typeof(i)) return i;
|
|
1010
|
+
throw new TypeError("@@toPrimitive must return a primitive value.");
|
|
1011
|
+
}
|
|
1012
|
+
return ("string" === r ? String : Number)(t);
|
|
1013
|
+
}
|
|
1014
|
+
|
|
1015
|
+
//#endregion
|
|
1016
|
+
//#region \0@oxc-project+runtime@0.137.0/helpers/esm/toPropertyKey.js
|
|
1017
|
+
function toPropertyKey(t) {
|
|
1018
|
+
var i = toPrimitive(t, "string");
|
|
1019
|
+
return "symbol" == _typeof(i) ? i : i + "";
|
|
1020
|
+
}
|
|
1021
|
+
|
|
1022
|
+
//#endregion
|
|
1023
|
+
//#region \0@oxc-project+runtime@0.137.0/helpers/esm/defineProperty.js
|
|
1024
|
+
function _defineProperty(e, r, t) {
|
|
1025
|
+
return (r = toPropertyKey(r)) in e ? Object.defineProperty(e, r, {
|
|
1026
|
+
value: t,
|
|
1027
|
+
enumerable: !0,
|
|
1028
|
+
configurable: !0,
|
|
1029
|
+
writable: !0
|
|
1030
|
+
}) : e[r] = t, e;
|
|
1031
|
+
}
|
|
1032
|
+
|
|
997
1033
|
//#endregion
|
|
998
1034
|
//#region \0@oxc-project+runtime@0.137.0/helpers/esm/decorateParam.js
|
|
999
1035
|
function __decorateParam(paramIndex, decorator) {
|
|
@@ -1026,42 +1062,42 @@ let FDocument = class FDocument extends FBaseInitialable {
|
|
|
1026
1062
|
}
|
|
1027
1063
|
/**
|
|
1028
1064
|
* Get the document data model of the document.
|
|
1065
|
+
* @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
1066
|
* @returns {DocumentDataModel} The document data model.
|
|
1030
1067
|
* @example
|
|
1031
1068
|
* ```typescript
|
|
1032
1069
|
* const fDocument = univerAPI.getActiveDocument();
|
|
1033
|
-
*
|
|
1034
|
-
*
|
|
1070
|
+
* console.log(fDocument.getDocumentDataModel());
|
|
1071
|
+
*
|
|
1072
|
+
* const headerSegmentId = fDocument.ensurePageHeader();
|
|
1073
|
+
* console.log(fDocument.getDocumentDataModel(headerSegmentId));
|
|
1035
1074
|
* ```
|
|
1036
1075
|
*/
|
|
1037
|
-
getDocumentDataModel() {
|
|
1038
|
-
|
|
1076
|
+
getDocumentDataModel(segmentId = "") {
|
|
1077
|
+
const documentDataModel = this._documentDataModel.getSelfOrHeaderFooterModel(segmentId);
|
|
1078
|
+
if (!documentDataModel) throw new Error(segmentId === "" ? "Document data model is not found." : `Document data model is not found in the segment: ${segmentId}`);
|
|
1079
|
+
return documentDataModel;
|
|
1039
1080
|
}
|
|
1040
1081
|
/**
|
|
1041
|
-
* Get the document body
|
|
1042
|
-
*
|
|
1043
|
-
* The
|
|
1044
|
-
*
|
|
1045
|
-
*
|
|
1046
|
-
* and custom blocks, use their existing ids.
|
|
1047
|
-
*
|
|
1048
|
-
* @returns {FDocumentBody} The document body API instance.
|
|
1082
|
+
* Get the document body or header/footer body by the segment id.
|
|
1083
|
+
* The main body has an empty segment id.
|
|
1084
|
+
* The header and footer body have their respective segment ids.
|
|
1085
|
+
* @param {string} segmentId The segment id of the body. Defaults to an empty string for the main body.
|
|
1086
|
+
* @returns {IDocumentBody} The document body.
|
|
1049
1087
|
* @example
|
|
1050
1088
|
* ```typescript
|
|
1051
1089
|
* const fDocument = univerAPI.getActiveDocument();
|
|
1052
|
-
*
|
|
1053
|
-
* console.log(fDocumentBody.getBody());
|
|
1090
|
+
* console.log(fDocument.getBody()); // Get the main body
|
|
1054
1091
|
*
|
|
1055
|
-
* const
|
|
1056
|
-
*
|
|
1057
|
-
* const paragraph = element.asParagraph();
|
|
1058
|
-
* paragraph.appendText(' updated');
|
|
1059
|
-
* console.log(paragraph.getText());
|
|
1060
|
-
* }
|
|
1092
|
+
* const footerSegmentId = fDocument.ensurePageFooter();
|
|
1093
|
+
* console.log(fDocument.getBody(footerSegmentId)); // Get the footer body
|
|
1061
1094
|
* ```
|
|
1062
1095
|
*/
|
|
1063
|
-
getBody() {
|
|
1064
|
-
|
|
1096
|
+
getBody(segmentId = "") {
|
|
1097
|
+
var _this$_documentDataMo;
|
|
1098
|
+
const body = (_this$_documentDataMo = this._documentDataModel.getSelfOrHeaderFooterModel(segmentId)) === null || _this$_documentDataMo === void 0 ? void 0 : _this$_documentDataMo.getBody();
|
|
1099
|
+
if (!body) throw new Error(segmentId === "" ? "Body is not found in the document." : `Body is not found in the segment: ${segmentId}`);
|
|
1100
|
+
return body;
|
|
1065
1101
|
}
|
|
1066
1102
|
dispose() {
|
|
1067
1103
|
super.dispose();
|
|
@@ -1072,8 +1108,7 @@ let FDocument = class FDocument extends FBaseInitialable {
|
|
|
1072
1108
|
* @example
|
|
1073
1109
|
* ```typescript
|
|
1074
1110
|
* const fDocument = univerAPI.getActiveDocument();
|
|
1075
|
-
*
|
|
1076
|
-
* console.log(unitId);
|
|
1111
|
+
* console.log(fDocument.getId());
|
|
1077
1112
|
* ```
|
|
1078
1113
|
*/
|
|
1079
1114
|
getId() {
|
|
@@ -1085,14 +1120,25 @@ let FDocument = class FDocument extends FBaseInitialable {
|
|
|
1085
1120
|
* @example
|
|
1086
1121
|
* ```typescript
|
|
1087
1122
|
* const fDocument = univerAPI.getActiveDocument();
|
|
1088
|
-
*
|
|
1089
|
-
* console.log(name);
|
|
1123
|
+
* console.log(fDocument.getName());
|
|
1090
1124
|
* ```
|
|
1091
1125
|
*/
|
|
1092
1126
|
getName() {
|
|
1093
1127
|
return this._documentDataModel.getTitle() || "";
|
|
1094
1128
|
}
|
|
1095
1129
|
/**
|
|
1130
|
+
* Whether the document is a modern document or not.
|
|
1131
|
+
* @returns {boolean} `true` if the document is a modern document, or `false` if it is not.
|
|
1132
|
+
* @example
|
|
1133
|
+
* ```typescript
|
|
1134
|
+
* const fDocument = univerAPI.getActiveDocument();
|
|
1135
|
+
* console.log(fDocument.isModern());
|
|
1136
|
+
* ```
|
|
1137
|
+
*/
|
|
1138
|
+
isModern() {
|
|
1139
|
+
return this._documentDataModel.getSnapshot().documentStyle.documentFlavor === DocumentFlavor.MODERN;
|
|
1140
|
+
}
|
|
1141
|
+
/**
|
|
1096
1142
|
* Save the document snapshot data, including the document content and resource data, etc.
|
|
1097
1143
|
* @returns {IDocumentData} The document snapshot data.
|
|
1098
1144
|
* @example
|
|
@@ -1133,264 +1179,505 @@ let FDocument = class FDocument extends FBaseInitialable {
|
|
|
1133
1179
|
this._univerInstanceService.focusUnit(this.id);
|
|
1134
1180
|
return this._commandService.syncExecuteCommand(RedoCommand.id);
|
|
1135
1181
|
}
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
return this._injector.createInstance(FDocument, document);
|
|
1182
|
+
/**
|
|
1183
|
+
* Ensure the page header segment exists and return its segment id.
|
|
1184
|
+
* @param {number} pageIndex The zero-based page index. Defaults to the first page.
|
|
1185
|
+
* @returns {string} The header segment id.
|
|
1186
|
+
* @example
|
|
1187
|
+
* ```ts
|
|
1188
|
+
* const fDocument = univerAPI.getActiveDocument();
|
|
1189
|
+
* const headerSegmentId = fDocument.ensurePageHeader();
|
|
1190
|
+
* fDocument.insertText(0, 'Header text', headerSegmentId);
|
|
1191
|
+
* ```
|
|
1192
|
+
*/
|
|
1193
|
+
ensurePageHeader(pageIndex = 0) {
|
|
1194
|
+
return this._ensureHeaderFooter("header", pageIndex);
|
|
1150
1195
|
}
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1196
|
+
/**
|
|
1197
|
+
* Ensure the page footer segment exists and return its segment id.
|
|
1198
|
+
* @param {number} pageIndex The zero-based page index. Defaults to the first page.
|
|
1199
|
+
* @returns {string} The footer segment id.
|
|
1200
|
+
* @example
|
|
1201
|
+
* ```ts
|
|
1202
|
+
* const fDocument = univerAPI.getActiveDocument();
|
|
1203
|
+
* const footerSegmentId = fDocument.ensurePageFooter();
|
|
1204
|
+
* fDocument.insertText(0, 'Footer text', footerSegmentId);
|
|
1205
|
+
* ```
|
|
1206
|
+
*/
|
|
1207
|
+
ensurePageFooter(pageIndex = 0) {
|
|
1208
|
+
return this._ensureHeaderFooter("footer", pageIndex);
|
|
1155
1209
|
}
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1210
|
+
/**
|
|
1211
|
+
* Insert plain text at a document body offset.
|
|
1212
|
+
* @param {number} index The zero-based insertion offset.
|
|
1213
|
+
* @param {string} text The plain text to insert.
|
|
1214
|
+
* @param {string} segmentId The segment id of the body. Defaults to an empty string for the main body.
|
|
1215
|
+
* @returns {boolean} `true` if the edit was applied.
|
|
1216
|
+
* @example
|
|
1217
|
+
* ```ts
|
|
1218
|
+
* const fDocument = univerAPI.getActiveDocument();
|
|
1219
|
+
* fDocument.insertText(0, 'Hello ');
|
|
1220
|
+
*
|
|
1221
|
+
* const headerSegmentId = fDocument.ensurePageHeader();
|
|
1222
|
+
* fDocument.insertText(0, 'Header text', headerSegmentId);
|
|
1223
|
+
* ```
|
|
1224
|
+
*/
|
|
1225
|
+
insertText(index, text, segmentId = "") {
|
|
1226
|
+
return replaceBodyRange({
|
|
1227
|
+
startOffset: index,
|
|
1228
|
+
endOffset: index,
|
|
1229
|
+
segmentId
|
|
1230
|
+
}, buildPlainTextInsertBody(text), this._documentDataModel, this._injector);
|
|
1160
1231
|
}
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
*
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
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()}`);
|
|
1232
|
+
/**
|
|
1233
|
+
* Returns document-level header/footer switches and margins. Margin values are in points (pt).
|
|
1234
|
+
* @example
|
|
1235
|
+
* ```ts
|
|
1236
|
+
* const fDocument = univerAPI.getActiveDocument();
|
|
1237
|
+
* console.log(fDocument?.getHeaderFooterOptions());
|
|
1238
|
+
* ```
|
|
1239
|
+
*/
|
|
1240
|
+
getHeaderFooterOptions() {
|
|
1241
|
+
const style = this._documentDataModel.getSnapshot().documentStyle;
|
|
1242
|
+
return {
|
|
1243
|
+
marginHeader: style.marginHeader,
|
|
1244
|
+
marginFooter: style.marginFooter,
|
|
1245
|
+
useFirstPageHeaderFooter: style.useFirstPageHeaderFooter,
|
|
1246
|
+
evenAndOddHeaders: style.evenAndOddHeaders
|
|
1247
|
+
};
|
|
1182
1248
|
}
|
|
1183
1249
|
/**
|
|
1184
|
-
*
|
|
1185
|
-
*
|
|
1250
|
+
* Updates document-level header/footer switches and margins in a traditional document.
|
|
1251
|
+
* `marginHeader` and `marginFooter` are in points (pt).
|
|
1186
1252
|
* @example
|
|
1187
1253
|
* ```ts
|
|
1188
1254
|
* const fDocument = univerAPI.getActiveDocument();
|
|
1189
|
-
*
|
|
1190
|
-
*
|
|
1191
|
-
*
|
|
1192
|
-
* if (element?.isBlockRange()) {
|
|
1193
|
-
* const blockRange = element.asBlockRange();
|
|
1194
|
-
* console.log(blockRange.getBlockRange());
|
|
1255
|
+
* if (fDocument && !fDocument.isModern()) {
|
|
1256
|
+
* fDocument.setHeaderFooterOptions({ marginHeader: 36, marginFooter: 36 });
|
|
1195
1257
|
* }
|
|
1196
1258
|
* ```
|
|
1197
1259
|
*/
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1260
|
+
setHeaderFooterOptions(options) {
|
|
1261
|
+
if (this.isModern()) throw new Error("The document is a modern document, header/footer is not supported.");
|
|
1262
|
+
return this._commandService.syncExecuteCommand(CreateHeaderFooterCommand.id, {
|
|
1263
|
+
unitId: this.getId(),
|
|
1264
|
+
headerFooterProps: options
|
|
1265
|
+
});
|
|
1203
1266
|
}
|
|
1204
1267
|
/**
|
|
1205
|
-
*
|
|
1206
|
-
*
|
|
1268
|
+
* Creates a facade for reading and styling a document text range.
|
|
1269
|
+
* The end offset is exclusive, and offsets are scoped to the selected body segment.
|
|
1270
|
+
* @param {number} startOffset The inclusive start offset.
|
|
1271
|
+
* @param {number} endOffset The exclusive end offset.
|
|
1272
|
+
* @param {string} segmentId The header/footer segment id, or an empty string for the main body.
|
|
1273
|
+
* @returns {FDocumentTextRange} A fixed text-range facade.
|
|
1274
|
+
* @example
|
|
1275
|
+
* ```ts
|
|
1276
|
+
* const range = univerAPI.getActiveDocument()?.getTextRange(0, 5);
|
|
1277
|
+
* console.log(range?.describe());
|
|
1278
|
+
* range?.setTextStyle({ bl: 1 });
|
|
1279
|
+
* ```
|
|
1280
|
+
*/
|
|
1281
|
+
getTextRange(startOffset, endOffset, segmentId = "") {
|
|
1282
|
+
return this._injector.createInstance(FDocumentTextRange, this, startOffset, endOffset, segmentId, this._injector);
|
|
1283
|
+
}
|
|
1284
|
+
/**
|
|
1285
|
+
* Returns traditional document sections backed by persisted SectionBreak ids.
|
|
1286
|
+
* Modern documents use ColumnGroup instead and return an empty array from this read API.
|
|
1207
1287
|
* @example
|
|
1208
1288
|
* ```ts
|
|
1209
1289
|
* const fDocument = univerAPI.getActiveDocument();
|
|
1210
|
-
* const
|
|
1211
|
-
*
|
|
1212
|
-
*
|
|
1213
|
-
* if (element?.isBlockRange()) {
|
|
1214
|
-
* const blockRange = element.asBlockRange();
|
|
1215
|
-
* console.log(blockRange.getBlockType());
|
|
1216
|
-
* }
|
|
1290
|
+
* const sections = fDocument?.getSections() ?? [];
|
|
1291
|
+
* console.log(sections.map((section) => section.describe()));
|
|
1217
1292
|
* ```
|
|
1218
1293
|
*/
|
|
1219
|
-
|
|
1220
|
-
|
|
1294
|
+
getSections() {
|
|
1295
|
+
if (this._documentDataModel.getSnapshot().documentStyle.documentFlavor !== DocumentFlavor.TRADITIONAL) return [];
|
|
1296
|
+
return getTopLevelSectionBreaks(this.getBody()).map((sectionBreak) => this._injector.createInstance(FDocumentSection, this, sectionBreak.sectionId, this._injector));
|
|
1221
1297
|
}
|
|
1222
1298
|
/**
|
|
1223
|
-
*
|
|
1224
|
-
* @returns {string} The block range text.
|
|
1299
|
+
* Returns a traditional section by zero-based index, or `null` in modern documents.
|
|
1225
1300
|
* @example
|
|
1226
1301
|
* ```ts
|
|
1227
1302
|
* const fDocument = univerAPI.getActiveDocument();
|
|
1228
|
-
* const
|
|
1229
|
-
*
|
|
1230
|
-
*
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1303
|
+
* const firstSection = fDocument?.getSection(0);
|
|
1304
|
+
* console.log(firstSection?.describe());
|
|
1305
|
+
* ```
|
|
1306
|
+
*/
|
|
1307
|
+
getSection(index) {
|
|
1308
|
+
var _this$getSections$ind;
|
|
1309
|
+
return (_this$getSections$ind = this.getSections()[index]) !== null && _this$getSections$ind !== void 0 ? _this$getSections$ind : null;
|
|
1310
|
+
}
|
|
1311
|
+
/**
|
|
1312
|
+
* Returns the traditional section containing a data-stream offset, or `null` in modern documents.
|
|
1313
|
+
* @example
|
|
1314
|
+
* ```ts
|
|
1315
|
+
* const fDocument = univerAPI.getActiveDocument();
|
|
1316
|
+
* const paragraph = fDocument?.findParagraphByText('Launch');
|
|
1317
|
+
* const offset = paragraph?.getInfo().startOffset;
|
|
1318
|
+
* const section = offset == null ? null : fDocument?.getSectionAt(offset);
|
|
1319
|
+
* console.log(section?.getId());
|
|
1320
|
+
* ```
|
|
1321
|
+
*/
|
|
1322
|
+
getSectionAt(offset) {
|
|
1323
|
+
var _this$getSections$fin;
|
|
1324
|
+
return (_this$getSections$fin = this.getSections().find((section) => {
|
|
1325
|
+
const range = section.getRange();
|
|
1326
|
+
return offset >= range.startOffset && offset <= range.endOffset;
|
|
1327
|
+
})) !== null && _this$getSections$fin !== void 0 ? _this$getSections$fin : null;
|
|
1328
|
+
}
|
|
1329
|
+
/**
|
|
1330
|
+
* Inserts a traditional document section break and returns its stable facade.
|
|
1331
|
+
* Modern documents must use ColumnGroup and throw `DocsSectionUnsupportedDocumentFlavorError`.
|
|
1332
|
+
* Numeric layout values in `config` are in points (pt).
|
|
1333
|
+
* @example
|
|
1334
|
+
* ```ts
|
|
1335
|
+
* const fDocument = univerAPI.getActiveDocument();
|
|
1336
|
+
* if (fDocument && !fDocument.isModern()) {
|
|
1337
|
+
* const paragraph = fDocument.findParagraphByText('Appendix');
|
|
1338
|
+
* const offset = paragraph?.getInfo().startOffset;
|
|
1339
|
+
* const section = offset == null ? null : fDocument.insertSectionBreak(offset);
|
|
1340
|
+
* console.log(section?.getId());
|
|
1234
1341
|
* }
|
|
1235
1342
|
* ```
|
|
1236
1343
|
*/
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1344
|
+
insertSectionBreak(offset, config = {}) {
|
|
1345
|
+
var _this$getBody$section;
|
|
1346
|
+
if (this._documentDataModel.getSnapshot().documentStyle.documentFlavor !== DocumentFlavor.TRADITIONAL) throw new DocsSectionUnsupportedDocumentFlavorError();
|
|
1347
|
+
const sectionId = createSectionId(new Set(((_this$getBody$section = this.getBody().sectionBreaks) !== null && _this$getBody$section !== void 0 ? _this$getBody$section : []).map((section) => section.sectionId)));
|
|
1348
|
+
return this._commandService.syncExecuteCommand(InsertDocumentSectionBreakCommand.id, {
|
|
1349
|
+
unitId: this.getId(),
|
|
1350
|
+
offset,
|
|
1351
|
+
sectionId,
|
|
1352
|
+
config
|
|
1353
|
+
}) ? this._injector.createInstance(FDocumentSection, this, sectionId, this._injector) : null;
|
|
1241
1354
|
}
|
|
1242
1355
|
/**
|
|
1243
|
-
*
|
|
1244
|
-
*
|
|
1245
|
-
* @returns {boolean} `true` if the block range text was replaced.
|
|
1356
|
+
* Inserts a column-break token in a traditional document.
|
|
1357
|
+
* Modern documents must use ColumnGroup and throw `DocsSectionUnsupportedDocumentFlavorError`.
|
|
1246
1358
|
* @example
|
|
1247
1359
|
* ```ts
|
|
1248
1360
|
* const fDocument = univerAPI.getActiveDocument();
|
|
1249
|
-
*
|
|
1250
|
-
*
|
|
1251
|
-
*
|
|
1252
|
-
*
|
|
1253
|
-
*
|
|
1254
|
-
*
|
|
1255
|
-
* console.log(blockRange.getText());
|
|
1361
|
+
* if (fDocument && !fDocument.isModern()) {
|
|
1362
|
+
* const paragraph = fDocument.findParagraphByText('Continue in next column');
|
|
1363
|
+
* const offset = paragraph?.getInfo().startOffset;
|
|
1364
|
+
* if (offset != null) {
|
|
1365
|
+
* fDocument.insertColumnBreak(offset);
|
|
1366
|
+
* }
|
|
1256
1367
|
* }
|
|
1257
1368
|
* ```
|
|
1258
1369
|
*/
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
*
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1370
|
+
insertColumnBreak(offset) {
|
|
1371
|
+
if (this._documentDataModel.getSnapshot().documentStyle.documentFlavor !== DocumentFlavor.TRADITIONAL) throw new DocsSectionUnsupportedDocumentFlavorError();
|
|
1372
|
+
return this.insertText(offset, DataStreamTreeTokenType.COLUMN_BREAK);
|
|
1373
|
+
}
|
|
1374
|
+
/**
|
|
1375
|
+
* Inserts a horizontal rule using the existing paragraph `borderBottom` mechanism.
|
|
1376
|
+
* The returned paragraph can be inspected or removed with normal paragraph APIs.
|
|
1377
|
+
* Border width and padding are in points (pt).
|
|
1378
|
+
* @example
|
|
1379
|
+
* ```ts
|
|
1380
|
+
* const fDocument = univerAPI.getActiveDocument();
|
|
1381
|
+
* const paragraph = fDocument?.findParagraphByText('Summary');
|
|
1382
|
+
* const offset = paragraph?.getInfo().startOffset;
|
|
1383
|
+
* const rule = offset == null ? null : fDocument?.insertHorizontalRule(offset);
|
|
1384
|
+
* console.log(rule?.getId());
|
|
1385
|
+
* ```
|
|
1386
|
+
*/
|
|
1387
|
+
insertHorizontalRule(offset, border = {
|
|
1388
|
+
padding: 5,
|
|
1389
|
+
color: { rgb: "#CDD0D8" },
|
|
1390
|
+
width: 1,
|
|
1391
|
+
dashStyle: DashStyleType.SOLID
|
|
1392
|
+
}, segmentId = "") {
|
|
1393
|
+
var _body$paragraphs;
|
|
1394
|
+
const body = this.getBody(segmentId);
|
|
1395
|
+
const paragraphs = generateParagraphs(DataStreamTreeTokenType.PARAGRAPH, void 0, border, (_body$paragraphs = body.paragraphs) === null || _body$paragraphs === void 0 ? void 0 : _body$paragraphs.map((paragraph) => paragraph.paragraphId));
|
|
1396
|
+
const paragraphId = paragraphs[0].paragraphId;
|
|
1397
|
+
return replaceBodyRange({
|
|
1398
|
+
startOffset: offset,
|
|
1399
|
+
endOffset: offset,
|
|
1400
|
+
segmentId
|
|
1401
|
+
}, {
|
|
1402
|
+
dataStream: DataStreamTreeTokenType.PARAGRAPH,
|
|
1403
|
+
paragraphs
|
|
1404
|
+
}, this._documentDataModel, this._injector) ? this.getParagraph(paragraphId, segmentId) : null;
|
|
1405
|
+
}
|
|
1406
|
+
/**
|
|
1407
|
+
* Get all paragraphs in the document body or header/footer body by the segment id.
|
|
1408
|
+
* @param {string} segmentId The segment id of the body. Defaults to an empty string for the main body.
|
|
1409
|
+
* @returns {FDocumentParagraph[]} An array of paragraph facade instances.
|
|
1280
1410
|
* @example
|
|
1281
1411
|
* ```ts
|
|
1282
1412
|
* const fDocument = univerAPI.getActiveDocument();
|
|
1283
|
-
* const
|
|
1284
|
-
*
|
|
1413
|
+
* const paragraphs = fDocument.getParagraphs();
|
|
1414
|
+
* console.log(paragraphs);
|
|
1285
1415
|
*
|
|
1286
|
-
*
|
|
1287
|
-
*
|
|
1288
|
-
*
|
|
1289
|
-
* console.log(removed ? 'Block range removed' : 'Failed to remove block range');
|
|
1290
|
-
* }
|
|
1416
|
+
* const headerSegmentId = fDocument.ensurePageHeader();
|
|
1417
|
+
* const headerParagraphs = fDocument.getParagraphs(headerSegmentId);
|
|
1418
|
+
* console.log(headerParagraphs);
|
|
1291
1419
|
* ```
|
|
1292
1420
|
*/
|
|
1293
|
-
|
|
1294
|
-
|
|
1421
|
+
getParagraphs(segmentId = "") {
|
|
1422
|
+
const { paragraphs = [] } = this.getBody(segmentId);
|
|
1423
|
+
return paragraphs.map((paragraph) => this._createFDocumentParagraph(paragraph.paragraphId, segmentId));
|
|
1295
1424
|
}
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
1425
|
+
/**
|
|
1426
|
+
* Get a paragraph by its paragraph id and segment id.
|
|
1427
|
+
* @param {string} paragraphId The paragraph id.
|
|
1428
|
+
* @param {string} segmentId The segment id of the body. Defaults to an empty string for the main body.
|
|
1429
|
+
* @returns {FDocumentParagraph | null} The paragraph facade instance, or `null` if the paragraph is not found.
|
|
1430
|
+
* @example
|
|
1431
|
+
* ```ts
|
|
1432
|
+
* const fDocument = univerAPI.getActiveDocument();
|
|
1433
|
+
* const paragraph = fDocument.getParagraph('paragraph-01');
|
|
1434
|
+
* console.log(paragraph);
|
|
1435
|
+
*
|
|
1436
|
+
* const headerSegmentId = fDocument.ensurePageHeader();
|
|
1437
|
+
* const headerParagraph = fDocument.getParagraph('header-paragraph-01', headerSegmentId);
|
|
1438
|
+
* console.log(headerParagraph);
|
|
1439
|
+
* ```
|
|
1440
|
+
*/
|
|
1441
|
+
getParagraph(paragraphId, segmentId = "") {
|
|
1442
|
+
const { paragraphs = [] } = this.getBody(segmentId);
|
|
1443
|
+
if (!paragraphs.find((paragraph) => paragraph.paragraphId === paragraphId)) return null;
|
|
1444
|
+
return this._createFDocumentParagraph(paragraphId, segmentId);
|
|
1301
1445
|
}
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
*
|
|
1309
|
-
*
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
|
|
1446
|
+
/**
|
|
1447
|
+
* Find a paragraph by its text content and segment id.
|
|
1448
|
+
* @param {string} text The text content to search for.
|
|
1449
|
+
* @param {string} segmentId The segment id of the body. Defaults to an empty string for the main body.
|
|
1450
|
+
* @returns {FDocumentParagraph | null} The paragraph facade instance, or `null` if the paragraph is not found.
|
|
1451
|
+
* @example
|
|
1452
|
+
* ```ts
|
|
1453
|
+
* const fDocument = univerAPI.getActiveDocument();
|
|
1454
|
+
* const paragraph = fDocument.findParagraphByText('Hello');
|
|
1455
|
+
* console.log(paragraph);
|
|
1456
|
+
*
|
|
1457
|
+
* const footerSegmentId = fDocument.ensurePageFooter();
|
|
1458
|
+
* const footerParagraph = fDocument.findParagraphByText('Page', footerSegmentId);
|
|
1459
|
+
* console.log(footerParagraph);
|
|
1460
|
+
* ```
|
|
1461
|
+
*/
|
|
1462
|
+
findParagraphByText(text, segmentId = "") {
|
|
1463
|
+
return this.findParagraphs({
|
|
1464
|
+
text,
|
|
1465
|
+
segmentId
|
|
1466
|
+
})[0] || null;
|
|
1319
1467
|
}
|
|
1320
1468
|
/**
|
|
1321
|
-
*
|
|
1322
|
-
* @
|
|
1469
|
+
* Find paragraphs by a query object, which can include text content, paragraph id, and segment id.
|
|
1470
|
+
* @param {string | IFDocumentParagraphQuery} query The query object or text content to search for.
|
|
1471
|
+
* @returns {FDocumentParagraph[]} An array of paragraph facade instances that match the query.
|
|
1323
1472
|
* @example
|
|
1324
1473
|
* ```ts
|
|
1325
1474
|
* const fDocument = univerAPI.getActiveDocument();
|
|
1326
|
-
* const
|
|
1327
|
-
*
|
|
1475
|
+
* const paragraphsWithText = fDocument.findParagraphs('Hello');
|
|
1476
|
+
* console.log(paragraphsWithText);
|
|
1328
1477
|
*
|
|
1329
|
-
*
|
|
1330
|
-
*
|
|
1331
|
-
*
|
|
1332
|
-
*
|
|
1478
|
+
* const paragraphsWithId = fDocument.findParagraphs({ paragraphId: 'paragraph-01' });
|
|
1479
|
+
* console.log(paragraphsWithId);
|
|
1480
|
+
*
|
|
1481
|
+
* const headerSegmentId = fDocument.ensurePageHeader();
|
|
1482
|
+
* const paragraphsWithSegment = fDocument.findParagraphs({ segmentId: headerSegmentId });
|
|
1483
|
+
* console.log(paragraphsWithSegment);
|
|
1333
1484
|
* ```
|
|
1334
1485
|
*/
|
|
1335
|
-
|
|
1336
|
-
const {
|
|
1337
|
-
|
|
1338
|
-
|
|
1339
|
-
|
|
1486
|
+
findParagraphs(query) {
|
|
1487
|
+
const { text, paragraphId, segmentId = "" } = typeof query === "string" ? { text: query } : query;
|
|
1488
|
+
return this.getParagraphs(segmentId).filter((paragraph) => {
|
|
1489
|
+
if (paragraphId && paragraph.getId() !== paragraphId) return false;
|
|
1490
|
+
if (text && !paragraph.getText().includes(text)) return false;
|
|
1491
|
+
return true;
|
|
1492
|
+
});
|
|
1340
1493
|
}
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
|
|
1494
|
+
/**
|
|
1495
|
+
* Insert a plain-text paragraph before the paragraph at the given paragraph index.
|
|
1496
|
+
* @param {number} index The zero-based paragraph insertion index.
|
|
1497
|
+
* @param {string} text The paragraph text. Defaults to an empty paragraph.
|
|
1498
|
+
* @param {string} segmentId The segment id of the body. Defaults to an empty string for the main body.
|
|
1499
|
+
* @returns {FDocumentParagraph} The inserted paragraph facade instance.
|
|
1500
|
+
* @example
|
|
1501
|
+
* ```ts
|
|
1502
|
+
* const fDocument = univerAPI.getActiveDocument();
|
|
1503
|
+
* const paragraph = fDocument.insertParagraph(0, 'Document title');
|
|
1504
|
+
* paragraph.appendText(' suffix');
|
|
1505
|
+
*
|
|
1506
|
+
* const headerSegmentId = fDocument.ensurePageHeader();
|
|
1507
|
+
* const headerParagraph = fDocument.insertParagraph(0, 'Header title', headerSegmentId);
|
|
1508
|
+
* headerParagraph.appendText(' suffix');
|
|
1509
|
+
* ```
|
|
1510
|
+
*/
|
|
1511
|
+
insertParagraph(index, text = "", segmentId = "") {
|
|
1512
|
+
const offset = this._getParagraphInsertOffset(index, segmentId);
|
|
1513
|
+
if (!replaceBodyRange({
|
|
1514
|
+
startOffset: offset,
|
|
1515
|
+
endOffset: offset,
|
|
1516
|
+
segmentId
|
|
1517
|
+
}, buildPlainTextInsertBody(`${text}\r`), this._documentDataModel, this._injector)) throw new Error("Failed to insert paragraph.");
|
|
1518
|
+
const { paragraphs = [] } = this.getBody(segmentId);
|
|
1519
|
+
const paragraph = paragraphs[index];
|
|
1520
|
+
if (!paragraph) throw new Error("Failed to insert paragraph.");
|
|
1521
|
+
return this._createFDocumentParagraph(paragraph.paragraphId, segmentId);
|
|
1346
1522
|
}
|
|
1347
|
-
|
|
1348
|
-
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
*
|
|
1354
|
-
*
|
|
1355
|
-
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
|
|
1523
|
+
/**
|
|
1524
|
+
* Append a plain-text paragraph at the end of the body.
|
|
1525
|
+
* @param {string} text The paragraph text. Defaults to an empty paragraph.
|
|
1526
|
+
* @param {string} segmentId The segment id of the body. Defaults to an empty string for the main body.
|
|
1527
|
+
* @returns {FDocumentParagraph} The appended paragraph wrapper.
|
|
1528
|
+
* @example
|
|
1529
|
+
* ```ts
|
|
1530
|
+
* const fDocument = univerAPI.getActiveDocument();
|
|
1531
|
+
* const paragraph = fDocument.appendParagraph('Summary');
|
|
1532
|
+
* console.log(paragraph.getText());
|
|
1533
|
+
*
|
|
1534
|
+
* const footerSegmentId = fDocument.ensurePageFooter();
|
|
1535
|
+
* const footerParagraph = fDocument.appendParagraph('Confidential', footerSegmentId);
|
|
1536
|
+
* console.log(footerParagraph.getText());
|
|
1537
|
+
* ```
|
|
1538
|
+
*/
|
|
1539
|
+
appendParagraph(text = "", segmentId = "") {
|
|
1540
|
+
const { paragraphs = [] } = this.getBody(segmentId);
|
|
1541
|
+
return this.insertParagraph(paragraphs.length, text, segmentId);
|
|
1364
1542
|
}
|
|
1365
1543
|
/**
|
|
1366
|
-
*
|
|
1367
|
-
* @
|
|
1544
|
+
* Delete a range from the body.
|
|
1545
|
+
* @param {IFDocumentTextRange} range The text range to delete.
|
|
1546
|
+
* @returns {boolean} `true` if the range was deleted.
|
|
1368
1547
|
* @example
|
|
1369
1548
|
* ```ts
|
|
1370
1549
|
* const fDocument = univerAPI.getActiveDocument();
|
|
1371
|
-
*
|
|
1372
|
-
* const element = fDocumentBody.getElement(0);
|
|
1550
|
+
* fDocument.deleteRange({ startOffset: 0, endOffset: 5 });
|
|
1373
1551
|
*
|
|
1374
|
-
*
|
|
1375
|
-
*
|
|
1376
|
-
* console.log(table.getTable());
|
|
1377
|
-
* }
|
|
1552
|
+
* const headerSegmentId = fDocument.ensurePageHeader();
|
|
1553
|
+
* fDocument.deleteRange({ startOffset: 0, endOffset: 5, segmentId: headerSegmentId });
|
|
1378
1554
|
* ```
|
|
1379
1555
|
*/
|
|
1380
|
-
|
|
1381
|
-
const
|
|
1382
|
-
|
|
1383
|
-
|
|
1384
|
-
|
|
1556
|
+
deleteRange(range) {
|
|
1557
|
+
const normalizedRange = this._normalizeDeleteRange(range);
|
|
1558
|
+
if (normalizedRange.startOffset >= normalizedRange.endOffset) return false;
|
|
1559
|
+
return replaceBodyRange(normalizedRange, { dataStream: "" }, this._documentDataModel, this._injector);
|
|
1560
|
+
}
|
|
1561
|
+
_createFDocumentParagraph(paragraphId, segmentId = "") {
|
|
1562
|
+
return this._injector.createInstance(FDocumentParagraph, this, paragraphId, segmentId, this._injector);
|
|
1563
|
+
}
|
|
1564
|
+
_normalizeDeleteRange(range) {
|
|
1565
|
+
const body = this.getBody(range.segmentId);
|
|
1566
|
+
const protectedEndOffset = body.dataStream.endsWith("\r\n") ? Math.max(0, body.dataStream.length - 2) : body.dataStream.length;
|
|
1567
|
+
const endOffset = Math.min(Math.max(range.endOffset, 0), protectedEndOffset);
|
|
1568
|
+
return {
|
|
1569
|
+
...range,
|
|
1570
|
+
startOffset: Math.min(Math.max(range.startOffset, 0), endOffset),
|
|
1571
|
+
endOffset
|
|
1572
|
+
};
|
|
1573
|
+
}
|
|
1574
|
+
_getParagraphInsertOffset(index, segmentId = "") {
|
|
1575
|
+
if (index <= 0) return 0;
|
|
1576
|
+
const body = this.getBody(segmentId);
|
|
1577
|
+
const { dataStream, paragraphs = [] } = body;
|
|
1578
|
+
if (paragraphs.length === 0) return Math.max(0, dataStream.length - 1);
|
|
1579
|
+
if (index >= paragraphs.length) return paragraphs[paragraphs.length - 1].startIndex + 1;
|
|
1580
|
+
return getParagraphContentStartOffset(body, paragraphs[index]);
|
|
1581
|
+
}
|
|
1582
|
+
_ensureHeaderFooter(kind, pageIndex) {
|
|
1583
|
+
if (this.isModern()) throw new Error("The document is a modern document, header/footer is not supported.");
|
|
1584
|
+
const { createType, segmentId: existingSegmentId } = this._getHeaderFooterCreateInfo(kind, pageIndex);
|
|
1585
|
+
if (existingSegmentId) return existingSegmentId;
|
|
1586
|
+
const segmentId = generateRandomId(6);
|
|
1587
|
+
if (!this._commandService.syncExecuteCommand(CreateHeaderFooterCommand.id, {
|
|
1588
|
+
unitId: this.getId(),
|
|
1589
|
+
segmentId,
|
|
1590
|
+
createType
|
|
1591
|
+
})) throw new Error(`Failed to create page ${kind}.`);
|
|
1592
|
+
return segmentId;
|
|
1593
|
+
}
|
|
1594
|
+
_getHeaderFooterCreateInfo(kind, pageIndex) {
|
|
1595
|
+
var _documentStyle$defaul, _documentStyle$defaul2;
|
|
1596
|
+
const { documentStyle } = this._documentDataModel.getSnapshot();
|
|
1597
|
+
const isFirstPage = pageIndex === 0;
|
|
1598
|
+
const isEvenPage = (pageIndex + 1) % 2 === 0;
|
|
1599
|
+
if (isFirstPage && documentStyle.useFirstPageHeaderFooter === BooleanNumber.TRUE) {
|
|
1600
|
+
var _documentStyle$firstP, _documentStyle$firstP2;
|
|
1601
|
+
return kind === "header" ? {
|
|
1602
|
+
createType: HeaderFooterType.FIRST_PAGE_HEADER,
|
|
1603
|
+
segmentId: (_documentStyle$firstP = documentStyle.firstPageHeaderId) !== null && _documentStyle$firstP !== void 0 ? _documentStyle$firstP : ""
|
|
1604
|
+
} : {
|
|
1605
|
+
createType: HeaderFooterType.FIRST_PAGE_FOOTER,
|
|
1606
|
+
segmentId: (_documentStyle$firstP2 = documentStyle.firstPageFooterId) !== null && _documentStyle$firstP2 !== void 0 ? _documentStyle$firstP2 : ""
|
|
1607
|
+
};
|
|
1608
|
+
}
|
|
1609
|
+
if (isEvenPage && documentStyle.evenAndOddHeaders === BooleanNumber.TRUE) {
|
|
1610
|
+
var _documentStyle$evenPa, _documentStyle$evenPa2;
|
|
1611
|
+
return kind === "header" ? {
|
|
1612
|
+
createType: HeaderFooterType.EVEN_PAGE_HEADER,
|
|
1613
|
+
segmentId: (_documentStyle$evenPa = documentStyle.evenPageHeaderId) !== null && _documentStyle$evenPa !== void 0 ? _documentStyle$evenPa : ""
|
|
1614
|
+
} : {
|
|
1615
|
+
createType: HeaderFooterType.EVEN_PAGE_FOOTER,
|
|
1616
|
+
segmentId: (_documentStyle$evenPa2 = documentStyle.evenPageFooterId) !== null && _documentStyle$evenPa2 !== void 0 ? _documentStyle$evenPa2 : ""
|
|
1617
|
+
};
|
|
1618
|
+
}
|
|
1619
|
+
return kind === "header" ? {
|
|
1620
|
+
createType: HeaderFooterType.DEFAULT_HEADER,
|
|
1621
|
+
segmentId: (_documentStyle$defaul = documentStyle.defaultHeaderId) !== null && _documentStyle$defaul !== void 0 ? _documentStyle$defaul : ""
|
|
1622
|
+
} : {
|
|
1623
|
+
createType: HeaderFooterType.DEFAULT_FOOTER,
|
|
1624
|
+
segmentId: (_documentStyle$defaul2 = documentStyle.defaultFooterId) !== null && _documentStyle$defaul2 !== void 0 ? _documentStyle$defaul2 : ""
|
|
1625
|
+
};
|
|
1626
|
+
}
|
|
1627
|
+
};
|
|
1628
|
+
FDocument = __decorate([
|
|
1629
|
+
__decorateParam(1, Inject(Injector)),
|
|
1630
|
+
__decorateParam(2, IUniverInstanceService),
|
|
1631
|
+
__decorateParam(3, Inject(IResourceLoaderService)),
|
|
1632
|
+
__decorateParam(4, ICommandService)
|
|
1633
|
+
], FDocument);
|
|
1634
|
+
|
|
1635
|
+
//#endregion
|
|
1636
|
+
//#region src/facade/f-univer.ts
|
|
1637
|
+
var FUniverDocsMixin = class extends FUniver {
|
|
1638
|
+
createDocument(data) {
|
|
1639
|
+
const document = this._injector.get(IUniverInstanceService).createUnit(UniverInstanceType.UNIVER_DOC, data);
|
|
1640
|
+
return this._injector.createInstance(FDocument, document);
|
|
1641
|
+
}
|
|
1642
|
+
getActiveDocument() {
|
|
1643
|
+
const document = this._univerInstanceService.getCurrentUnitOfType(UniverInstanceType.UNIVER_DOC);
|
|
1644
|
+
if (!document) return null;
|
|
1645
|
+
return this._injector.createInstance(FDocument, document);
|
|
1646
|
+
}
|
|
1647
|
+
getDocument(id) {
|
|
1648
|
+
const document = this._univerInstanceService.getUnit(id, UniverInstanceType.UNIVER_DOC);
|
|
1649
|
+
if (!document) return null;
|
|
1650
|
+
return this._injector.createInstance(FDocument, document);
|
|
1385
1651
|
}
|
|
1386
1652
|
};
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
|
|
1390
|
-
|
|
1653
|
+
FUniver.extend(FUniverDocsMixin);
|
|
1654
|
+
|
|
1655
|
+
//#endregion
|
|
1656
|
+
//#region src/facade/f-enum.ts
|
|
1657
|
+
/**
|
|
1658
|
+
* Copyright 2023-present DreamNum Co., Ltd.
|
|
1659
|
+
*
|
|
1660
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
1661
|
+
* you may not use this file except in compliance with the License.
|
|
1662
|
+
* You may obtain a copy of the License at
|
|
1663
|
+
*
|
|
1664
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
1665
|
+
*
|
|
1666
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
1667
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
1668
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
1669
|
+
* See the License for the specific language governing permissions and
|
|
1670
|
+
* limitations under the License.
|
|
1671
|
+
*/
|
|
1672
|
+
var FDocsEnumMixin = class extends FEnum {
|
|
1673
|
+
get SectionType() {
|
|
1674
|
+
return SectionType;
|
|
1675
|
+
}
|
|
1676
|
+
get ColumnSeparatorType() {
|
|
1677
|
+
return ColumnSeparatorType;
|
|
1391
1678
|
}
|
|
1392
1679
|
};
|
|
1393
|
-
|
|
1680
|
+
FEnum.extend(FDocsEnumMixin);
|
|
1394
1681
|
|
|
1395
1682
|
//#endregion
|
|
1396
|
-
export {
|
|
1683
|
+
export { DocsSectionUnsupportedDocumentFlavorError, FDocsEnumMixin, FDocument, FDocumentParagraph, FDocumentSection, FDocumentTextRange, isParagraphFacade, stripBlockTokens };
|