@univerjs/docs 1.0.0-rc.0 → 1.0.0
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 +66 -20
- package/lib/cjs/index.js +347 -64
- package/lib/es/facade.js +66 -20
- package/lib/es/index.js +349 -66
- package/lib/facade.js +66 -20
- package/lib/index.js +349 -66
- package/lib/types/commands/mutations/core-editing.mutation.d.ts +2 -0
- package/lib/types/commands/mutations/doc-structure-mutation-validation.d.ts +2 -1
- package/lib/types/facade/f-document-section.d.ts +28 -0
- package/lib/types/facade/f-document-text-range.d.ts +4 -0
- package/lib/types/facade/f-document.d.ts +29 -13
- package/lib/types/facade/f-univer.d.ts +2 -2
- package/lib/types/layout-worker/config/config.d.ts +8 -0
- package/lib/types/layout-worker/font-loader.d.ts +26 -0
- package/lib/types/layout-worker/index.d.ts +5 -2
- package/lib/types/layout-worker/protocol.d.ts +2 -0
- package/lib/types/layout-worker/worker.d.ts +3 -1
- package/lib/types/plugin.d.ts +1 -0
- package/lib/types/services/doc-layout-executor.service.d.ts +6 -0
- package/lib/types/services/doc-state-change-manager.service.d.ts +2 -0
- package/lib/types/services/doc-state-emit.service.d.ts +1 -0
- package/lib/umd/facade.js +1 -1
- package/lib/umd/index.js +2 -2
- package/package.json +7 -7
package/lib/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { AlignTypeH, BooleanNumber, BuildTextUtils, ColumnSeparatorType, CommandType, CustomCommandExecutionError, CustomRangeType, DOCS_FORMULA_BAR_EDITOR_UNIT_ID_KEY, DOCS_NORMAL_EDITOR_UNIT_ID_KEY, DataStreamTreeTokenType, DeleteDirection, DependentOn, Disposable, DisposableCollection, DocumentDataModel, DocumentFlavor, DocxBreakType, DrawingTypeEnum, ErrorService, ICommandService, IConfigService, ILogService, IPermissionService, IResourceManagerService, IUndoRedoService, IUniverInstanceService, Inject, Injector, JSON1, JSONX, LocaleService, MemoryCursor, ObjectPermissionRuleModel, ObjectPermissionService, ObjectRelativeFromH, ObjectRelativeFromV, Optional, PAGE_SIZE, PageOrientType, PaperType, PermissionStatus, Plugin, PositionedObjectLayoutType, RESTORE_INSERTED_PARAGRAPH_IDS, RedoCommandId, RxDisposable, SectionType, TRADITIONAL_DOCUMENT_DEFAULT_MARGIN, TextX, TextXActionType, Tools, UndoCommandId, UniverInstanceType, UpdateDocsAttributeType, composeInterceptors, containsInteriorInsertionOffset, createIdentifier, createInterceptorKey, createParagraphId, createSectionId, generateRandomId, getBlockRangeInterval, getColumnGroupRangeInterval, getParagraphContentStartOffset, getParagraphContentStartOffsets, getRichTextEditPath, getSectionHeaderFooterReferenceKey, getTableRangeInterval, isInternalEditorID, merge, remove, requestImmediateMacroTask, resolveSectionHeaderFooterReference, toDisposable, validateDocBodyStructure, validateDocumentStructure } from "@univerjs/core";
|
|
2
|
-
import { DocumentLayoutSession, DocumentSkeleton, DocumentViewModel, FontCache, IRenderManagerService, NORMAL_TEXT_SELECTION_PLUGIN_STYLE, getDocsCustomBlockRenderViewport, getFontStyleString, setDocsCustomBlockRenderViewportProvider } from "@univerjs/engine-render";
|
|
1
|
+
import { AlignTypeH, BooleanNumber, BuildTextUtils, ColumnSeparatorType, CommandType, CustomCommandExecutionError, CustomRangeType, DEFAULT_STYLES, DOCS_FORMULA_BAR_EDITOR_UNIT_ID_KEY, DOCS_NORMAL_EDITOR_UNIT_ID_KEY, DataStreamTreeTokenType, DeleteDirection, DependentOn, Disposable, DisposableCollection, DocumentDataModel, DocumentFlavor, DocxBreakType, DrawingTypeEnum, ErrorService, ICommandService, IConfigService, ILogService, IPermissionService, IResourceManagerService, IUndoRedoService, IUniverInstanceService, Inject, Injector, JSON1, JSONX, LocaleService, MemoryCursor, ObjectPermissionRuleModel, ObjectPermissionService, ObjectRelativeFromH, ObjectRelativeFromV, Optional, PAGE_SIZE, PageOrientType, PaperType, PermissionStatus, Plugin, PositionedObjectLayoutType, RESTORE_INSERTED_PARAGRAPH_IDS, RedoCommandId, RxDisposable, SectionType, TRADITIONAL_DOCUMENT_DEFAULT_MARGIN, TextX, TextXActionType, Tools, UndoCommandId, UniverInstanceType, UpdateDocsAttributeType, composeInterceptors, containsInteriorInsertionOffset, createIdentifier, createInterceptorKey, createParagraphId, createSectionId, generateRandomId, getBlockRangeInterval, getColumnGroupRangeInterval, getParagraphContentStartOffset, getParagraphContentStartOffsets, getRichTextEditPath, getSdtBindingKey, getSdtBindingValue, getSectionHeaderFooterReferenceKey, getTableRangeInterval, isInternalEditorID, merge, remove, requestImmediateMacroTask, resolveSectionHeaderFooterReference, toDisposable, validateDocBodyStructure, validateDocumentStructure } from "@univerjs/core";
|
|
2
|
+
import { DocumentLayoutSession, DocumentSkeleton, DocumentViewModel, FontCache, IRenderManagerService, NORMAL_TEXT_SELECTION_PLUGIN_STYLE, getDocsCustomBlockRenderViewport, getDocumentLayoutPresentation, getFontStyleString, setDocsCustomBlockRenderViewportProvider } from "@univerjs/engine-render";
|
|
3
3
|
import { BehaviorSubject, Observable, Subject, shareReplay, takeUntil } from "rxjs";
|
|
4
4
|
import { UnitAction, UnitObject } from "@univerjs/protocol";
|
|
5
5
|
import { ChannelService, fromModule, toModule } from "@univerjs/rpc";
|
|
@@ -14,7 +14,7 @@ const SetTextSelectionsOperation = {
|
|
|
14
14
|
};
|
|
15
15
|
|
|
16
16
|
//#endregion
|
|
17
|
-
//#region \0@oxc-project+runtime@0.
|
|
17
|
+
//#region \0@oxc-project+runtime@0.149.0/helpers/esm/typeof.js
|
|
18
18
|
function _typeof(o) {
|
|
19
19
|
"@babel/helpers - typeof";
|
|
20
20
|
return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function(o) {
|
|
@@ -25,7 +25,7 @@ function _typeof(o) {
|
|
|
25
25
|
}
|
|
26
26
|
|
|
27
27
|
//#endregion
|
|
28
|
-
//#region \0@oxc-project+runtime@0.
|
|
28
|
+
//#region \0@oxc-project+runtime@0.149.0/helpers/esm/toPrimitive.js
|
|
29
29
|
function toPrimitive(t, r) {
|
|
30
30
|
if ("object" != _typeof(t) || !t) return t;
|
|
31
31
|
var e = t[Symbol.toPrimitive];
|
|
@@ -38,14 +38,14 @@ function toPrimitive(t, r) {
|
|
|
38
38
|
}
|
|
39
39
|
|
|
40
40
|
//#endregion
|
|
41
|
-
//#region \0@oxc-project+runtime@0.
|
|
41
|
+
//#region \0@oxc-project+runtime@0.149.0/helpers/esm/toPropertyKey.js
|
|
42
42
|
function toPropertyKey(t) {
|
|
43
43
|
var i = toPrimitive(t, "string");
|
|
44
44
|
return "symbol" == _typeof(i) ? i : i + "";
|
|
45
45
|
}
|
|
46
46
|
|
|
47
47
|
//#endregion
|
|
48
|
-
//#region \0@oxc-project+runtime@0.
|
|
48
|
+
//#region \0@oxc-project+runtime@0.149.0/helpers/esm/defineProperty.js
|
|
49
49
|
function _defineProperty(e, r, t) {
|
|
50
50
|
return (r = toPropertyKey(r)) in e ? Object.defineProperty(e, r, {
|
|
51
51
|
value: t,
|
|
@@ -56,7 +56,7 @@ function _defineProperty(e, r, t) {
|
|
|
56
56
|
}
|
|
57
57
|
|
|
58
58
|
//#endregion
|
|
59
|
-
//#region \0@oxc-project+runtime@0.
|
|
59
|
+
//#region \0@oxc-project+runtime@0.149.0/helpers/esm/decorateParam.js
|
|
60
60
|
function __decorateParam(paramIndex, decorator) {
|
|
61
61
|
return function(target, key) {
|
|
62
62
|
decorator(target, key, paramIndex);
|
|
@@ -64,7 +64,7 @@ function __decorateParam(paramIndex, decorator) {
|
|
|
64
64
|
}
|
|
65
65
|
|
|
66
66
|
//#endregion
|
|
67
|
-
//#region \0@oxc-project+runtime@0.
|
|
67
|
+
//#region \0@oxc-project+runtime@0.149.0/helpers/esm/decorate.js
|
|
68
68
|
function __decorate(decorators, target, key, desc) {
|
|
69
69
|
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
70
70
|
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
@@ -291,9 +291,17 @@ function projectFooter(footer) {
|
|
|
291
291
|
* the structured-clone boundary because they do not affect document geometry.
|
|
292
292
|
*/
|
|
293
293
|
function createDocumentLayoutSnapshot(snapshot) {
|
|
294
|
-
const { resources: _resources, body, headers, footers, ...layoutSnapshot } = snapshot;
|
|
294
|
+
const { resources: _resources, body, headers, footers, footnotes, endnotes, ...layoutSnapshot } = snapshot;
|
|
295
295
|
return {
|
|
296
296
|
...layoutSnapshot,
|
|
297
|
+
...footnotes == null ? {} : { footnotes: Object.fromEntries(Object.entries(footnotes).map(([id, note]) => [id, {
|
|
298
|
+
...note,
|
|
299
|
+
body: projectDocumentBody(note.body)
|
|
300
|
+
}])) },
|
|
301
|
+
...endnotes == null ? {} : { endnotes: Object.fromEntries(Object.entries(endnotes).map(([id, note]) => [id, {
|
|
302
|
+
...note,
|
|
303
|
+
body: projectDocumentBody(note.body)
|
|
304
|
+
}])) },
|
|
297
305
|
...body == null ? {} : { body: projectDocumentBody(body) },
|
|
298
306
|
...headers == null ? {} : { headers: Object.fromEntries(Object.entries(headers).map(([headerId, header]) => [headerId, projectHeader(header)])) },
|
|
299
307
|
...footers == null ? {} : { footers: Object.fromEntries(Object.entries(footers).map(([footerId, footer]) => [footerId, projectFooter(footer)])) }
|
|
@@ -366,11 +374,15 @@ function isRichTextEditingMutationParams(value) {
|
|
|
366
374
|
return typeof value === "object" && value != null && "unitId" in value && typeof value.unitId === "string" && "actions" in value;
|
|
367
375
|
}
|
|
368
376
|
function collectCustomBlockViewports(dataModel) {
|
|
369
|
-
var _snapshot$body;
|
|
370
377
|
const snapshot = dataModel.getSnapshot();
|
|
371
378
|
const documentStyle = snapshot.documentStyle;
|
|
372
379
|
const viewports = {};
|
|
373
|
-
|
|
380
|
+
const bodies = [
|
|
381
|
+
snapshot.body,
|
|
382
|
+
...Object.values(snapshot.headers ?? {}).map((header) => header.body),
|
|
383
|
+
...Object.values(snapshot.footers ?? {}).map((footer) => footer.body)
|
|
384
|
+
];
|
|
385
|
+
for (const customBlock of bodies.flatMap((body) => (body === null || body === void 0 ? void 0 : body.customBlocks) ?? [])) {
|
|
374
386
|
var _snapshot$drawings, _documentStyle$pageSi;
|
|
375
387
|
const drawing = (_snapshot$drawings = snapshot.drawings) === null || _snapshot$drawings === void 0 ? void 0 : _snapshot$drawings[customBlock.blockId];
|
|
376
388
|
if (drawing == null) continue;
|
|
@@ -520,19 +532,21 @@ let DocLayoutExecutorService = _DocLayoutExecutorService = class DocLayoutExecut
|
|
|
520
532
|
this._executorReady = executorReady;
|
|
521
533
|
await executorReady;
|
|
522
534
|
} catch (error) {
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
535
|
+
if (this._executor === executor) {
|
|
536
|
+
const recoveryDiagnostic = error instanceof Error ? error.message : String(error);
|
|
537
|
+
this._executor = null;
|
|
538
|
+
this._executorReady = null;
|
|
539
|
+
this._recoveryFailure = {
|
|
540
|
+
diagnostic: recoveryDiagnostic,
|
|
541
|
+
unitId
|
|
542
|
+
};
|
|
543
|
+
this._executorStatus$.next({
|
|
544
|
+
state: "recovering",
|
|
545
|
+
executor: executor.type,
|
|
546
|
+
diagnostic: recoveryDiagnostic,
|
|
547
|
+
recoveryUnitId: unitId
|
|
548
|
+
});
|
|
549
|
+
}
|
|
536
550
|
throw error;
|
|
537
551
|
}
|
|
538
552
|
}
|
|
@@ -557,7 +571,9 @@ let DocLayoutExecutorService = _DocLayoutExecutorService = class DocLayoutExecut
|
|
|
557
571
|
let session = this._sessions.get(unitId);
|
|
558
572
|
if (session != null && session.sourceMutationRevision !== dataModel.getMutationRevision()) session.needsResnapshot = true;
|
|
559
573
|
if (session == null || session.needsResnapshot) session = await this._replaceSession(dataModel);
|
|
574
|
+
if (session.disposed || this._executor !== executor || this._getEligibleModel(unitId) !== dataModel) return null;
|
|
560
575
|
let result = await this._startSynchronizedLayout(executor, session, identity, options, budgetMs);
|
|
576
|
+
if (session.disposed || this._executor !== executor || this._getEligibleModel(unitId) !== dataModel) return null;
|
|
561
577
|
if (result.status === "not-found" || result.status === "resnapshot-required") {
|
|
562
578
|
session = await this._replaceSession(dataModel);
|
|
563
579
|
result = await this._startSynchronizedLayout(executor, session, identity, options, budgetMs);
|
|
@@ -595,7 +611,7 @@ let DocLayoutExecutorService = _DocLayoutExecutorService = class DocLayoutExecut
|
|
|
595
611
|
unitId,
|
|
596
612
|
sessionEpoch: session.sessionEpoch
|
|
597
613
|
}).catch((error) => {
|
|
598
|
-
this._logService.error("[DocLayoutExecutorService]: failed to dispose a Worker session.", error);
|
|
614
|
+
if (this._executor === executor) this._logService.error("[DocLayoutExecutorService]: failed to dispose a Worker session.", error);
|
|
599
615
|
});
|
|
600
616
|
}
|
|
601
617
|
this._sessions.clear();
|
|
@@ -685,6 +701,7 @@ let DocLayoutExecutorService = _DocLayoutExecutorService = class DocLayoutExecut
|
|
|
685
701
|
return result;
|
|
686
702
|
});
|
|
687
703
|
session.queue = startTask.then(() => void 0, (error) => {
|
|
704
|
+
if (session.disposed || this._executor !== executor) return;
|
|
688
705
|
session.needsResnapshot = true;
|
|
689
706
|
this._logService.error("[DocLayoutExecutorService]: synchronized layout start failed.", error);
|
|
690
707
|
});
|
|
@@ -738,23 +755,25 @@ let DocLayoutExecutorService = _DocLayoutExecutorService = class DocLayoutExecut
|
|
|
738
755
|
try {
|
|
739
756
|
await createTask;
|
|
740
757
|
} catch (error) {
|
|
741
|
-
session.
|
|
742
|
-
|
|
758
|
+
if (!session.disposed && this._executor === executor) {
|
|
759
|
+
session.needsResnapshot = true;
|
|
760
|
+
throw error;
|
|
761
|
+
}
|
|
743
762
|
}
|
|
744
763
|
return session;
|
|
745
764
|
}
|
|
746
765
|
_disposeSession(unitId) {
|
|
747
|
-
var _this$_executor3;
|
|
748
766
|
const session = this._sessions.get(unitId);
|
|
749
767
|
if (session == null) return;
|
|
750
768
|
this._markSessionDisposed(session);
|
|
751
769
|
this._sessions.delete(unitId);
|
|
752
770
|
this._hydrationSamples.delete(unitId);
|
|
753
|
-
|
|
771
|
+
const executor = this._executor;
|
|
772
|
+
executor === null || executor === void 0 || executor.disposeSession({
|
|
754
773
|
unitId,
|
|
755
774
|
sessionEpoch: session.sessionEpoch
|
|
756
775
|
}).catch((error) => {
|
|
757
|
-
this._logService.error("[DocLayoutExecutorService]: failed to dispose a Worker session.", error);
|
|
776
|
+
if (this._executor === executor) this._logService.error("[DocLayoutExecutorService]: failed to dispose a Worker session.", error);
|
|
758
777
|
});
|
|
759
778
|
}
|
|
760
779
|
_getEligibleModel(unitId) {
|
|
@@ -910,7 +929,7 @@ let DocSkeletonManagerService = class DocSkeletonManagerService extends RxDispos
|
|
|
910
929
|
supportsIncrementalLayout() {
|
|
911
930
|
var _this$_context$unit$g;
|
|
912
931
|
const documentFlavor = (_this$_context$unit$g = this._context.unit.getSnapshot().documentStyle) === null || _this$_context$unit$g === void 0 ? void 0 : _this$_context$unit$g.documentFlavor;
|
|
913
|
-
return this._docLayoutExecutorService.getExecutor() != null && !isInternalEditorID(this._context.unitId) && (documentFlavor === DocumentFlavor.TRADITIONAL || documentFlavor === DocumentFlavor.MODERN);
|
|
932
|
+
return this._docLayoutExecutorService.getExecutor() != null && !isInternalEditorID(this._context.unitId) && !getDocumentLayoutPresentation(this._context.unit) && (documentFlavor === DocumentFlavor.TRADITIONAL || documentFlavor === DocumentFlavor.MODERN);
|
|
914
933
|
}
|
|
915
934
|
recalculate() {
|
|
916
935
|
const skeleton = this._skeleton;
|
|
@@ -1068,23 +1087,136 @@ function getSegmentType(documentDataModel, segmentId) {
|
|
|
1068
1087
|
if ((_documentDataModel$ge = documentDataModel.getSnapshot().notes) === null || _documentDataModel$ge === void 0 ? void 0 : _documentDataModel$ge[segmentId]) return "note";
|
|
1069
1088
|
return "body";
|
|
1070
1089
|
}
|
|
1071
|
-
function
|
|
1090
|
+
function getSnapshotBody(snapshot, segmentId) {
|
|
1091
|
+
var _snapshot$headers, _snapshot$footers, _snapshot$notes;
|
|
1092
|
+
if (!segmentId) return snapshot.body;
|
|
1093
|
+
return ((_snapshot$headers = snapshot.headers) === null || _snapshot$headers === void 0 || (_snapshot$headers = _snapshot$headers[segmentId]) === null || _snapshot$headers === void 0 ? void 0 : _snapshot$headers.body) ?? ((_snapshot$footers = snapshot.footers) === null || _snapshot$footers === void 0 || (_snapshot$footers = _snapshot$footers[segmentId]) === null || _snapshot$footers === void 0 ? void 0 : _snapshot$footers.body) ?? ((_snapshot$notes = snapshot.notes) === null || _snapshot$notes === void 0 || (_snapshot$notes = _snapshot$notes[segmentId]) === null || _snapshot$notes === void 0 ? void 0 : _snapshot$notes.body);
|
|
1094
|
+
}
|
|
1095
|
+
function containsTextXEdit(actions) {
|
|
1096
|
+
const cursor = JSON1.type.readCursor(actions);
|
|
1097
|
+
let found = false;
|
|
1098
|
+
cursor.traverse(null, (component) => {
|
|
1099
|
+
if (component.et === TextX.id) found = true;
|
|
1100
|
+
});
|
|
1101
|
+
return found;
|
|
1102
|
+
}
|
|
1103
|
+
function subtractBaselineIssues(issues, baseline) {
|
|
1104
|
+
const counts = /* @__PURE__ */ new Map();
|
|
1105
|
+
baseline.forEach((issue) => counts.set(issue.code, (counts.get(issue.code) ?? 0) + 1));
|
|
1106
|
+
return issues.filter((issue) => {
|
|
1107
|
+
const count = counts.get(issue.code) ?? 0;
|
|
1108
|
+
if (count === 0) return true;
|
|
1109
|
+
counts.set(issue.code, count - 1);
|
|
1110
|
+
return false;
|
|
1111
|
+
});
|
|
1112
|
+
}
|
|
1113
|
+
function assertValidDocBodyStructure(documentDataModel, segmentId, undoActions) {
|
|
1072
1114
|
var _documentDataModel$ge2;
|
|
1073
1115
|
const segmentModel = documentDataModel.getSelfOrHeaderFooterModel(segmentId);
|
|
1074
1116
|
const body = segmentModel === null || segmentModel === void 0 ? void 0 : segmentModel.getBody();
|
|
1075
1117
|
if (!body) return;
|
|
1076
1118
|
const segmentType = getSegmentType(documentDataModel, segmentId);
|
|
1119
|
+
const context = {
|
|
1120
|
+
segmentType,
|
|
1121
|
+
segmentId: segmentId || void 0
|
|
1122
|
+
};
|
|
1077
1123
|
const note = (_documentDataModel$ge2 = documentDataModel.getSnapshot().notes) === null || _documentDataModel$ge2 === void 0 ? void 0 : _documentDataModel$ge2[segmentId];
|
|
1078
1124
|
const issues = note ? validateDocumentStructure({ notes: { [segmentId]: note } }) : validateDocBodyStructure(body, {
|
|
1079
1125
|
segmentType,
|
|
1080
1126
|
segmentId: segmentId || void 0
|
|
1081
1127
|
});
|
|
1082
1128
|
if (!issues.length) return;
|
|
1083
|
-
const
|
|
1129
|
+
const snapshot = Tools.deepClone(documentDataModel.getSnapshot());
|
|
1130
|
+
const baselineBody = getSnapshotBody(JSONX.apply(snapshot, undoActions), segmentId);
|
|
1131
|
+
const newIssues = baselineBody ? subtractBaselineIssues(issues, validateDocBodyStructure(baselineBody, context)) : issues;
|
|
1132
|
+
if (!newIssues.length) return;
|
|
1133
|
+
const detail = newIssues.map((issue) => `${issue.code}${issue.index == null ? "" : `@${issue.index}`}`).join(", ");
|
|
1084
1134
|
const segmentLabel = segmentId ? `${segmentType} ${segmentId}` : segmentType;
|
|
1085
1135
|
throw new Error(`[DocStructure] ${segmentLabel}: ${detail}`);
|
|
1086
1136
|
}
|
|
1087
|
-
function
|
|
1137
|
+
function getLockedSdtContent(body, range) {
|
|
1138
|
+
var _range$properties;
|
|
1139
|
+
if (((_range$properties = range.properties) === null || _range$properties === void 0 ? void 0 : _range$properties.kind) !== "group") return body.dataStream.slice(range.startIndex, range.endIndex + 1);
|
|
1140
|
+
const children = (body.customRanges ?? []).filter((child) => child.rangeType === CustomRangeType.SDT && child.rangeId !== range.rangeId && child.startIndex >= range.startIndex && child.endIndex <= range.endIndex).sort((left, right) => {
|
|
1141
|
+
const position = left.startIndex - right.startIndex || right.endIndex - left.endIndex;
|
|
1142
|
+
if (position || left.rangeId === right.rangeId) return position;
|
|
1143
|
+
return left.rangeId < right.rangeId ? -1 : 1;
|
|
1144
|
+
});
|
|
1145
|
+
const protectedContent = [];
|
|
1146
|
+
let offset = range.startIndex;
|
|
1147
|
+
for (const child of children) {
|
|
1148
|
+
if (child.startIndex < offset) continue;
|
|
1149
|
+
protectedContent.push(body.dataStream.slice(offset, child.startIndex), child.rangeId);
|
|
1150
|
+
offset = child.endIndex + 1;
|
|
1151
|
+
}
|
|
1152
|
+
protectedContent.push(body.dataStream.slice(offset, range.endIndex + 1));
|
|
1153
|
+
return JSON.stringify(protectedContent);
|
|
1154
|
+
}
|
|
1155
|
+
function getRepeatingItemIds(body, section) {
|
|
1156
|
+
const ranges = body.customRanges ?? [];
|
|
1157
|
+
const sectionIndex = ranges.indexOf(section);
|
|
1158
|
+
const nestedSections = ranges.filter((range, index) => {
|
|
1159
|
+
var _range$properties2;
|
|
1160
|
+
return range.rangeType === CustomRangeType.SDT && ((_range$properties2 = range.properties) === null || _range$properties2 === void 0 ? void 0 : _range$properties2.kind) === "repeatingSection" && range.rangeId !== section.rangeId && range.startIndex >= section.startIndex && range.endIndex <= section.endIndex && (range.startIndex > section.startIndex || range.endIndex < section.endIndex || index < sectionIndex);
|
|
1161
|
+
});
|
|
1162
|
+
return ranges.filter((range, index) => {
|
|
1163
|
+
var _range$properties3;
|
|
1164
|
+
return range.rangeType === CustomRangeType.SDT && ((_range$properties3 = range.properties) === null || _range$properties3 === void 0 ? void 0 : _range$properties3.kind) === "repeatingSectionItem" && range.startIndex >= section.startIndex && range.endIndex <= section.endIndex && !nestedSections.some((nested) => nested.startIndex <= range.startIndex && range.endIndex <= nested.endIndex && (nested.startIndex < range.startIndex || range.endIndex < nested.endIndex || index < ranges.indexOf(nested)));
|
|
1165
|
+
}).map((range) => range.rangeId).sort();
|
|
1166
|
+
}
|
|
1167
|
+
function isDocSdtMutationAllowed(documentDataModel, segmentId, actions) {
|
|
1168
|
+
var _previousBody$customR;
|
|
1169
|
+
if (!containsTextXEdit(actions) && isStructurePreservingJSONXEdit(actions, getRichTextEditPath(documentDataModel, segmentId))) return true;
|
|
1170
|
+
const snapshot = documentDataModel.getSnapshot();
|
|
1171
|
+
const previousBody = getSnapshotBody(snapshot, segmentId);
|
|
1172
|
+
const lockedRanges = previousBody === null || previousBody === void 0 || (_previousBody$customR = previousBody.customRanges) === null || _previousBody$customR === void 0 ? void 0 : _previousBody$customR.filter((range) => {
|
|
1173
|
+
var _range$properties4, _range$properties5, _range$properties$rep;
|
|
1174
|
+
return range.rangeType === CustomRangeType.SDT && (((_range$properties4 = range.properties) === null || _range$properties4 === void 0 ? void 0 : _range$properties4.lock) && range.properties.lock !== "unlocked" || ((_range$properties5 = range.properties) === null || _range$properties5 === void 0 ? void 0 : _range$properties5.kind) === "repeatingSection" && ((_range$properties$rep = range.properties.repeatingSection) === null || _range$properties$rep === void 0 ? void 0 : _range$properties$rep.doNotAllowInsertDelete));
|
|
1175
|
+
});
|
|
1176
|
+
if (!previousBody || !(lockedRanges === null || lockedRanges === void 0 ? void 0 : lockedRanges.length)) return true;
|
|
1177
|
+
const candidate = JSONX.apply(Tools.deepClone(snapshot), actions);
|
|
1178
|
+
const currentBody = getSnapshotBody(candidate, segmentId);
|
|
1179
|
+
for (const previous of lockedRanges) {
|
|
1180
|
+
var _previous$properties, _currentBody$customRa, _previous$properties2, _previous$properties$;
|
|
1181
|
+
const lock = (_previous$properties = previous.properties) === null || _previous$properties === void 0 ? void 0 : _previous$properties.lock;
|
|
1182
|
+
const current = currentBody === null || currentBody === void 0 || (_currentBody$customRa = currentBody.customRanges) === null || _currentBody$customRa === void 0 ? void 0 : _currentBody$customRa.find((range) => range.rangeId === previous.rangeId && range.rangeType === CustomRangeType.SDT);
|
|
1183
|
+
const wrapperLocked = lock === "sdtLocked" || lock === "sdtContentLocked";
|
|
1184
|
+
const contentLocked = lock === "contentLocked" || lock === "sdtContentLocked";
|
|
1185
|
+
if (wrapperLocked && !current) return false;
|
|
1186
|
+
if (((_previous$properties2 = previous.properties) === null || _previous$properties2 === void 0 ? void 0 : _previous$properties2.kind) === "repeatingSection" && ((_previous$properties$ = previous.properties.repeatingSection) === null || _previous$properties$ === void 0 ? void 0 : _previous$properties$.doNotAllowInsertDelete) && current && currentBody) {
|
|
1187
|
+
const before = getRepeatingItemIds(previousBody, previous);
|
|
1188
|
+
const after = getRepeatingItemIds(currentBody, current);
|
|
1189
|
+
if (before.length !== after.length || before.some((id, index) => id !== after[index])) return false;
|
|
1190
|
+
}
|
|
1191
|
+
if (contentLocked && current && currentBody) {
|
|
1192
|
+
if (getLockedSdtContent(previousBody, previous) !== getLockedSdtContent(currentBody, current) && !isBoundSdtValueUpdate(snapshot, candidate, previous, current, currentBody)) return false;
|
|
1193
|
+
}
|
|
1194
|
+
}
|
|
1195
|
+
return true;
|
|
1196
|
+
}
|
|
1197
|
+
function isBoundSdtValueUpdate(before, after, previous, current, currentBody) {
|
|
1198
|
+
const key = getSdtBindingKey(previous);
|
|
1199
|
+
const value = getSdtBindingValue(currentBody, current);
|
|
1200
|
+
if (!key || key !== getSdtBindingKey(current) || value === void 0) return false;
|
|
1201
|
+
return [
|
|
1202
|
+
"",
|
|
1203
|
+
...Object.keys(before.headers ?? {}),
|
|
1204
|
+
...Object.keys(before.footers ?? {}),
|
|
1205
|
+
...Object.keys(before.notes ?? {})
|
|
1206
|
+
].some((segmentId) => {
|
|
1207
|
+
var _previousBody$customR2;
|
|
1208
|
+
const previousBody = getSnapshotBody(before, segmentId);
|
|
1209
|
+
const nextBody = getSnapshotBody(after, segmentId);
|
|
1210
|
+
if (!previousBody || !nextBody) return false;
|
|
1211
|
+
return ((_previousBody$customR2 = previousBody.customRanges) === null || _previousBody$customR2 === void 0 ? void 0 : _previousBody$customR2.some((range) => {
|
|
1212
|
+
var _range$properties6, _range$properties7, _nextBody$customRange;
|
|
1213
|
+
if (range.rangeType !== CustomRangeType.SDT || ((_range$properties6 = range.properties) === null || _range$properties6 === void 0 ? void 0 : _range$properties6.lock) === "contentLocked" || ((_range$properties7 = range.properties) === null || _range$properties7 === void 0 ? void 0 : _range$properties7.lock) === "sdtContentLocked" || getSdtBindingKey(range) !== key) return false;
|
|
1214
|
+
const next = (_nextBody$customRange = nextBody.customRanges) === null || _nextBody$customRange === void 0 ? void 0 : _nextBody$customRange.find((item) => item.rangeType === CustomRangeType.SDT && item.rangeId === range.rangeId);
|
|
1215
|
+
return next != null && getSdtBindingKey(next) === key && getSdtBindingValue(previousBody, range) !== value && getSdtBindingValue(nextBody, next) === value;
|
|
1216
|
+
})) ?? false;
|
|
1217
|
+
});
|
|
1218
|
+
}
|
|
1219
|
+
function validateDocStructureMutation(documentDataModel, segmentId, actions, undoActions, isHistoryReplay = false) {
|
|
1088
1220
|
const editPath = getRichTextEditPath(documentDataModel, segmentId);
|
|
1089
1221
|
const preservesStructure = isStructurePreservingJSONXEdit(actions, editPath) && isStructurePreservingJSONXEdit(undoActions, editPath);
|
|
1090
1222
|
let changesFootnoteStructure = false;
|
|
@@ -1093,6 +1225,7 @@ function validateDocStructureMutation(documentDataModel, segmentId, actions, und
|
|
|
1093
1225
|
const path = cursor.getPath();
|
|
1094
1226
|
if (path[0] === "notes" && (path.length <= 2 || path[2] !== "body") || path.includes("customRanges")) changesFootnoteStructure = true;
|
|
1095
1227
|
if (component.et === TextX.id && Array.isArray(component.e)) for (const action of component.e) {
|
|
1228
|
+
if (isRecord$3(action) && Array.isArray(action.rangeUpdates) && action.rangeUpdates.some((update) => isRecord$3(update) && isRecord$3(update.range) && (update.range.rangeType === CustomRangeType.FOOTNOTE || update.range.rangeType === CustomRangeType.ENDNOTE))) changesFootnoteStructure = true;
|
|
1096
1229
|
const ranges = isRecord$3(action) && isRecord$3(action.body) ? action.body.customRanges : void 0;
|
|
1097
1230
|
if (Array.isArray(ranges) && ranges.some((range) => isRecord$3(range) && (range.rangeType === CustomRangeType.FOOTNOTE || range.rangeType === CustomRangeType.ENDNOTE))) changesFootnoteStructure = true;
|
|
1098
1231
|
}
|
|
@@ -1100,7 +1233,7 @@ function validateDocStructureMutation(documentDataModel, segmentId, actions, und
|
|
|
1100
1233
|
if (changesFootnoteStructure) {
|
|
1101
1234
|
const issues = validateDocumentStructure(documentDataModel.getSnapshot());
|
|
1102
1235
|
if (issues.length > 0) throw new Error(`[DocStructure] ${issues.map((issue) => `${issue.code}@${issue.index ?? issue.segmentId ?? ""}`).join(", ")}`);
|
|
1103
|
-
} else if (!preservesStructure) assertValidDocBodyStructure(documentDataModel, segmentId);
|
|
1236
|
+
} else if (!preservesStructure && !isHistoryReplay) assertValidDocBodyStructure(documentDataModel, segmentId, undoActions);
|
|
1104
1237
|
return preservesStructure && !changesFootnoteStructure;
|
|
1105
1238
|
}
|
|
1106
1239
|
|
|
@@ -1156,12 +1289,12 @@ function canRemoveFootnoteReference(actions, references) {
|
|
|
1156
1289
|
if (path.length === 1 && component.et === TextX.id && Array.isArray(component.e)) {
|
|
1157
1290
|
let offset = 0;
|
|
1158
1291
|
for (const action of component.e) {
|
|
1159
|
-
var _action$body;
|
|
1292
|
+
var _action$body, _action$rangeUpdates;
|
|
1160
1293
|
if (action.t === TextXActionType.DELETE && references.some((reference) => offset <= reference.endIndex && offset + action.len > reference.startIndex)) {
|
|
1161
1294
|
canRemove = true;
|
|
1162
1295
|
return;
|
|
1163
1296
|
}
|
|
1164
|
-
if (action.t === TextXActionType.RETAIN && ((_action$body = action.body) === null || _action$body === void 0 ? void 0 : _action$body.customRanges) != null) {
|
|
1297
|
+
if (action.t === TextXActionType.RETAIN && (((_action$body = action.body) === null || _action$body === void 0 ? void 0 : _action$body.customRanges) != null || ((_action$rangeUpdates = action.rangeUpdates) === null || _action$rangeUpdates === void 0 ? void 0 : _action$rangeUpdates.some((update) => references.some((reference) => reference.rangeId === update.rangeId))))) {
|
|
1165
1298
|
canRemove = true;
|
|
1166
1299
|
return;
|
|
1167
1300
|
}
|
|
@@ -1192,7 +1325,7 @@ function includeFootnoteCleanup(before, actions) {
|
|
|
1192
1325
|
}
|
|
1193
1326
|
return JSONX.isNoop(cleanup) ? actions : JSONX.compose(actions, cleanup);
|
|
1194
1327
|
}
|
|
1195
|
-
function applyValidatedDocumentActions(documentDataModel, segmentId, actions) {
|
|
1328
|
+
function applyValidatedDocumentActions(documentDataModel, segmentId, actions, isHistoryReplay = false) {
|
|
1196
1329
|
const before = documentDataModel.getSnapshot();
|
|
1197
1330
|
const appliedActions = includeFootnoteCleanup(before, actions);
|
|
1198
1331
|
const undoActions = JSONX.invertWithDoc(appliedActions, before);
|
|
@@ -1201,7 +1334,7 @@ function applyValidatedDocumentActions(documentDataModel, segmentId, actions) {
|
|
|
1201
1334
|
return {
|
|
1202
1335
|
actions: appliedActions,
|
|
1203
1336
|
undoActions,
|
|
1204
|
-
preservesStructure: validateDocStructureMutation(documentDataModel, segmentId, appliedActions, undoActions)
|
|
1337
|
+
preservesStructure: validateDocStructureMutation(documentDataModel, segmentId, appliedActions, undoActions, isHistoryReplay)
|
|
1205
1338
|
};
|
|
1206
1339
|
} catch (error) {
|
|
1207
1340
|
documentDataModel.apply(undoActions);
|
|
@@ -1268,7 +1401,27 @@ const RichTextEditingMutation = {
|
|
|
1268
1401
|
actions: [],
|
|
1269
1402
|
textRanges: docRanges
|
|
1270
1403
|
};
|
|
1271
|
-
const
|
|
1404
|
+
const isHistoryReplay = trigger === UndoCommandId || trigger === RedoCommandId;
|
|
1405
|
+
if (!isHistoryReplay && !isDocSdtMutationAllowed(documentDataModel, segmentId, actions)) {
|
|
1406
|
+
params.actions = [];
|
|
1407
|
+
return {
|
|
1408
|
+
unitId,
|
|
1409
|
+
actions: [],
|
|
1410
|
+
textRanges: docRanges
|
|
1411
|
+
};
|
|
1412
|
+
}
|
|
1413
|
+
const presentation = getDocumentLayoutPresentation(documentDataModel);
|
|
1414
|
+
const previousLayoutState = presentation === null || presentation === void 0 ? void 0 : presentation.captureState();
|
|
1415
|
+
const { actions: appliedActions, undoActions, preservesStructure } = applyValidatedDocumentActions(documentDataModel, segmentId, actions, isHistoryReplay);
|
|
1416
|
+
if (presentation) try {
|
|
1417
|
+
if (params.layoutState !== void 0) presentation.restoreState(params.layoutState);
|
|
1418
|
+
else presentation.applyActions(appliedActions, documentDataModel.getSnapshot());
|
|
1419
|
+
params.layoutState = presentation.captureState();
|
|
1420
|
+
} catch (error) {
|
|
1421
|
+
documentDataModel.apply(undoActions);
|
|
1422
|
+
presentation.restoreState(previousLayoutState);
|
|
1423
|
+
throw error;
|
|
1424
|
+
}
|
|
1272
1425
|
params.actions = appliedActions;
|
|
1273
1426
|
resetDocumentViewModel(documentViewModel, documentDataModel, segmentId, appliedActions, preservesStructure);
|
|
1274
1427
|
scheduleDocumentSelectionUpdate(docSelectionManagerService, params, isSync);
|
|
@@ -1280,12 +1433,14 @@ const RichTextEditingMutation = {
|
|
|
1280
1433
|
noHistory,
|
|
1281
1434
|
debounce,
|
|
1282
1435
|
redoState: {
|
|
1436
|
+
...presentation ? { layoutState: params.layoutState } : {},
|
|
1283
1437
|
actions: appliedActions,
|
|
1284
1438
|
textRanges,
|
|
1285
1439
|
options: params.options,
|
|
1286
1440
|
isEditing
|
|
1287
1441
|
},
|
|
1288
1442
|
undoState: {
|
|
1443
|
+
...presentation ? { layoutState: previousLayoutState } : {},
|
|
1289
1444
|
actions: undoActions,
|
|
1290
1445
|
textRanges: prevTextRanges ?? docRanges,
|
|
1291
1446
|
options: selectionInfo === null || selectionInfo === void 0 ? void 0 : selectionInfo.options,
|
|
@@ -1299,6 +1454,7 @@ const RichTextEditingMutation = {
|
|
|
1299
1454
|
return {
|
|
1300
1455
|
unitId,
|
|
1301
1456
|
actions: undoActions,
|
|
1457
|
+
...presentation ? { layoutState: previousLayoutState } : {},
|
|
1302
1458
|
textRanges: docRanges
|
|
1303
1459
|
};
|
|
1304
1460
|
}
|
|
@@ -1415,7 +1571,7 @@ const DeleteTextCommand = {
|
|
|
1415
1571
|
startOffset: start,
|
|
1416
1572
|
endOffset: end + 1,
|
|
1417
1573
|
collapsed: false
|
|
1418
|
-
}], body));
|
|
1574
|
+
}], body, 0, null, true, docDataModel.getDocumentStyle().documentFlavor));
|
|
1419
1575
|
const path = getRichTextEditPath(docDataModel, segmentId);
|
|
1420
1576
|
doMutation.params.actions = appendRemovedDrawingActions(jsonX.editOp(textX.serialize(), path), docDataModel, body, start, end + 1, segmentId);
|
|
1421
1577
|
const result = commandService.syncExecuteCommand(doMutation.id, doMutation.params);
|
|
@@ -2624,7 +2780,7 @@ function composeActions(actions) {
|
|
|
2624
2780
|
//#endregion
|
|
2625
2781
|
//#region package.json
|
|
2626
2782
|
var name = "@univerjs/docs";
|
|
2627
|
-
var version = "1.0.0
|
|
2783
|
+
var version = "1.0.0";
|
|
2628
2784
|
|
|
2629
2785
|
//#endregion
|
|
2630
2786
|
//#region src/config/config.ts
|
|
@@ -3252,6 +3408,20 @@ let DocStateChangeManagerService = class DocStateChangeManagerService extends Rx
|
|
|
3252
3408
|
this._initialize();
|
|
3253
3409
|
this._listenDocStateChange();
|
|
3254
3410
|
}
|
|
3411
|
+
dispose() {
|
|
3412
|
+
if (this._historyTimer != null) {
|
|
3413
|
+
clearTimeout(this._historyTimer);
|
|
3414
|
+
this._historyTimer = null;
|
|
3415
|
+
}
|
|
3416
|
+
if (this._changeStateCacheTimer != null) {
|
|
3417
|
+
clearTimeout(this._changeStateCacheTimer);
|
|
3418
|
+
this._changeStateCacheTimer = null;
|
|
3419
|
+
}
|
|
3420
|
+
this._historyStateCache.clear();
|
|
3421
|
+
this._changeStateCache.clear();
|
|
3422
|
+
this._docStateChange$.complete();
|
|
3423
|
+
super.dispose();
|
|
3424
|
+
}
|
|
3255
3425
|
getStateCache(unitId) {
|
|
3256
3426
|
return {
|
|
3257
3427
|
history: this._historyStateCache.get(unitId) ?? [],
|
|
@@ -3265,6 +3435,10 @@ let DocStateChangeManagerService = class DocStateChangeManagerService extends Rx
|
|
|
3265
3435
|
clearHistory(unitId) {
|
|
3266
3436
|
this._historyStateCache.delete(unitId);
|
|
3267
3437
|
}
|
|
3438
|
+
flushPendingChanges(unitId) {
|
|
3439
|
+
this._pushHistory(unitId);
|
|
3440
|
+
this._emitChangeState(unitId);
|
|
3441
|
+
}
|
|
3268
3442
|
_setChangeState(changeState) {
|
|
3269
3443
|
this._cacheChangeState(changeState, "history");
|
|
3270
3444
|
this._cacheChangeState(changeState, "collaboration");
|
|
@@ -3303,18 +3477,19 @@ let DocStateChangeManagerService = class DocStateChangeManagerService extends Rx
|
|
|
3303
3477
|
const cacheStates = stateCache.get(unitId);
|
|
3304
3478
|
cacheStates === null || cacheStates === void 0 || cacheStates.push(changeState);
|
|
3305
3479
|
} else stateCache.set(unitId, [changeState]);
|
|
3306
|
-
if (debounce)
|
|
3307
|
-
if (
|
|
3308
|
-
|
|
3309
|
-
|
|
3310
|
-
|
|
3311
|
-
|
|
3312
|
-
|
|
3313
|
-
|
|
3314
|
-
|
|
3315
|
-
|
|
3316
|
-
|
|
3317
|
-
|
|
3480
|
+
if (debounce) {
|
|
3481
|
+
if (type === "history") {
|
|
3482
|
+
if (this._historyTimer) clearTimeout(this._historyTimer);
|
|
3483
|
+
this._historyTimer = setTimeout(() => {
|
|
3484
|
+
cb(unitId);
|
|
3485
|
+
}, DEBOUNCE_DELAY);
|
|
3486
|
+
} else {
|
|
3487
|
+
if (this._changeStateCacheTimer) clearTimeout(this._changeStateCacheTimer);
|
|
3488
|
+
this._changeStateCacheTimer = setTimeout(() => {
|
|
3489
|
+
cb(unitId);
|
|
3490
|
+
}, DEBOUNCE_DELAY);
|
|
3491
|
+
}
|
|
3492
|
+
} else cb(unitId);
|
|
3318
3493
|
}
|
|
3319
3494
|
_pushHistory(unitId) {
|
|
3320
3495
|
const undoRedoService = this._undoRedoService;
|
|
@@ -3326,6 +3501,8 @@ let DocStateChangeManagerService = class DocStateChangeManagerService extends Rx
|
|
|
3326
3501
|
const lastState = cacheStates[len - 1];
|
|
3327
3502
|
const redoParams = {
|
|
3328
3503
|
unitId,
|
|
3504
|
+
trigger: RedoCommandId,
|
|
3505
|
+
...lastState.redoState.layoutState === void 0 ? {} : { layoutState: lastState.redoState.layoutState },
|
|
3329
3506
|
actions: cacheStates.reduce((acc, cur) => JSONX.compose(acc, cur.redoState.actions), null),
|
|
3330
3507
|
textRanges: lastState.redoState.textRanges,
|
|
3331
3508
|
segmentId: lastState.segmentId,
|
|
@@ -3334,6 +3511,8 @@ let DocStateChangeManagerService = class DocStateChangeManagerService extends Rx
|
|
|
3334
3511
|
};
|
|
3335
3512
|
const undoParams = {
|
|
3336
3513
|
unitId,
|
|
3514
|
+
trigger: UndoCommandId,
|
|
3515
|
+
...firstState.undoState.layoutState === void 0 ? {} : { layoutState: firstState.undoState.layoutState },
|
|
3337
3516
|
actions: cacheStates.reverse().reduce((acc, cur) => JSONX.compose(acc, cur.undoState.actions), null),
|
|
3338
3517
|
textRanges: firstState.undoState.textRanges,
|
|
3339
3518
|
segmentId: firstState.segmentId,
|
|
@@ -3487,6 +3666,25 @@ let UniverDocsPlugin = class UniverDocsPlugin extends Plugin {
|
|
|
3487
3666
|
this.disposeWithMe(this._injector.get(ObjectPermissionService).registerRuleModel(UnitObject.Document, this._injector.get(DocumentPermissionRuleModel), SetDocumentPermissionRuleMutation.id, SetDocumentPermissionRulesMutation.id));
|
|
3488
3667
|
this._initializeDependencies();
|
|
3489
3668
|
this._initializeCommands();
|
|
3669
|
+
this._initializeWordResources();
|
|
3670
|
+
}
|
|
3671
|
+
_initializeWordResources() {
|
|
3672
|
+
for (const pluginName of ["DOC_WORD_STYLES_PLUGIN", "DOC_NOTE_PLUGIN"]) {
|
|
3673
|
+
const resources = /* @__PURE__ */ new Map();
|
|
3674
|
+
this.disposeWithMe({ dispose: () => resources.clear() });
|
|
3675
|
+
this.disposeWithMe(this._injector.get(IResourceManagerService).registerPluginResource({
|
|
3676
|
+
pluginName,
|
|
3677
|
+
businesses: [UniverInstanceType.UNIVER_DOC],
|
|
3678
|
+
parseJson: (data) => data,
|
|
3679
|
+
onLoad: (unitId, data) => {
|
|
3680
|
+
resources.set(unitId, data);
|
|
3681
|
+
},
|
|
3682
|
+
onUnLoad: (unitId) => {
|
|
3683
|
+
resources.delete(unitId);
|
|
3684
|
+
},
|
|
3685
|
+
toJson: (unitId) => resources.get(unitId) ?? ""
|
|
3686
|
+
}));
|
|
3687
|
+
}
|
|
3490
3688
|
}
|
|
3491
3689
|
_initializeCommands() {
|
|
3492
3690
|
[
|
|
@@ -3585,6 +3783,12 @@ function collectDocumentFontFamilies(value, families) {
|
|
|
3585
3783
|
}
|
|
3586
3784
|
return;
|
|
3587
3785
|
}
|
|
3786
|
+
const textStyle = value;
|
|
3787
|
+
if (typeof textStyle.eastAsiaFontFamily === "string" && textStyle.eastAsiaFontFamily.trim()) {
|
|
3788
|
+
const primary = typeof textStyle.ff === "string" && textStyle.ff.trim() ? textStyle.ff : DEFAULT_STYLES.ff;
|
|
3789
|
+
families.add(`${primary}, ${textStyle.eastAsiaFontFamily.trim()}`);
|
|
3790
|
+
families.add(`${textStyle.eastAsiaFontFamily.trim()}, ${primary}, ${textStyle.eastAsiaFontFamily.trim()}`);
|
|
3791
|
+
}
|
|
3588
3792
|
for (const [key, item] of Object.entries(value)) if (key === "ff" && typeof item === "string") families.add(item);
|
|
3589
3793
|
else collectDocumentFontFamilies(item, families);
|
|
3590
3794
|
}
|
|
@@ -3598,6 +3802,53 @@ function measureDocumentFontFamilies(families) {
|
|
|
3598
3802
|
return FontCache.getNormalLineHeightCache();
|
|
3599
3803
|
}
|
|
3600
3804
|
|
|
3805
|
+
//#endregion
|
|
3806
|
+
//#region src/layout-worker/font-loader.ts
|
|
3807
|
+
/** Owns the same explicitly supplied font faces in the rendering and layout realms. */
|
|
3808
|
+
var DocsLayoutFontLoader = class extends Disposable {
|
|
3809
|
+
constructor(..._args) {
|
|
3810
|
+
super(..._args);
|
|
3811
|
+
_defineProperty(this, "_loading", null);
|
|
3812
|
+
_defineProperty(this, "_fontSet", void 0);
|
|
3813
|
+
_defineProperty(this, "_faces", []);
|
|
3814
|
+
}
|
|
3815
|
+
load(fonts) {
|
|
3816
|
+
this._loading ??= this._load(fonts);
|
|
3817
|
+
return this._loading;
|
|
3818
|
+
}
|
|
3819
|
+
dispose() {
|
|
3820
|
+
for (const face of this._faces) {
|
|
3821
|
+
var _this$_fontSet;
|
|
3822
|
+
(_this$_fontSet = this._fontSet) === null || _this$_fontSet === void 0 || _this$_fontSet.delete(face);
|
|
3823
|
+
}
|
|
3824
|
+
if (this._faces.length > 0) FontCache.invalidateMetrics(() => true);
|
|
3825
|
+
this._faces = [];
|
|
3826
|
+
this._fontSet = void 0;
|
|
3827
|
+
super.dispose();
|
|
3828
|
+
}
|
|
3829
|
+
async _load(fonts) {
|
|
3830
|
+
this.ensureNotDisposed();
|
|
3831
|
+
if (fonts.length === 0) return;
|
|
3832
|
+
const fontSet = typeof document === "undefined" ? globalThis.fonts : document.fonts;
|
|
3833
|
+
if (typeof FontFace === "undefined" || fontSet == null) throw new Error("Document layout requires FontFace support to load the configured fonts.");
|
|
3834
|
+
try {
|
|
3835
|
+
const faces = fonts.map(({ family, source, descriptors }) => {
|
|
3836
|
+
if (!family.trim() || (typeof source === "string" ? !source.trim() : source.byteLength === 0)) throw new TypeError("Document layout font family and source must not be empty.");
|
|
3837
|
+
return new FontFace(family, source, descriptors);
|
|
3838
|
+
});
|
|
3839
|
+
await Promise.all(faces.map((face) => face.load()));
|
|
3840
|
+
this.ensureNotDisposed();
|
|
3841
|
+
this._fontSet = fontSet;
|
|
3842
|
+
this._faces = faces;
|
|
3843
|
+
for (const face of faces) fontSet.add(face);
|
|
3844
|
+
FontCache.invalidateMetrics(() => true);
|
|
3845
|
+
} catch (error) {
|
|
3846
|
+
this.dispose();
|
|
3847
|
+
throw error;
|
|
3848
|
+
}
|
|
3849
|
+
}
|
|
3850
|
+
};
|
|
3851
|
+
|
|
3601
3852
|
//#endregion
|
|
3602
3853
|
//#region src/layout-worker/performance-tracker.ts
|
|
3603
3854
|
const PERFORMANCE_SAMPLE_LIMIT = 2048;
|
|
@@ -3710,10 +3961,11 @@ var DocsLayoutWorkerRuntime = class {
|
|
|
3710
3961
|
constructor(_performanceTracker = new DocsLayoutWorkerPerformanceTracker()) {
|
|
3711
3962
|
this._performanceTracker = _performanceTracker;
|
|
3712
3963
|
_defineProperty(this, "_sessions", /* @__PURE__ */ new Map());
|
|
3964
|
+
_defineProperty(this, "_fontLoader", new DocsLayoutFontLoader());
|
|
3713
3965
|
_defineProperty(this, "type", "worker");
|
|
3714
3966
|
}
|
|
3715
|
-
initialize() {
|
|
3716
|
-
return
|
|
3967
|
+
initialize(fontFaces = []) {
|
|
3968
|
+
return this._fontLoader.load(fontFaces);
|
|
3717
3969
|
}
|
|
3718
3970
|
async getCapabilities() {
|
|
3719
3971
|
const metrics = FontCache.getMeasureText(FONT_PROBE_CONTENT, FONT_PROBE_STYLE);
|
|
@@ -3801,7 +4053,9 @@ var DocsLayoutWorkerRuntime = class {
|
|
|
3801
4053
|
reason: request.reason,
|
|
3802
4054
|
anchor: request.anchor,
|
|
3803
4055
|
priorityAnchor: request.priorityAnchor,
|
|
3804
|
-
invalidation: request.invalidation
|
|
4056
|
+
invalidation: request.invalidation,
|
|
4057
|
+
modernPageWidth: request.modernPageWidth,
|
|
4058
|
+
modernHorizontalMargin: request.modernHorizontalMargin
|
|
3805
4059
|
});
|
|
3806
4060
|
mount.activeGeneration = generation;
|
|
3807
4061
|
mount.cancelledGeneration = null;
|
|
@@ -3923,6 +4177,7 @@ var DocsLayoutWorkerRuntime = class {
|
|
|
3923
4177
|
this._performanceTracker.reset(request.unitId);
|
|
3924
4178
|
}
|
|
3925
4179
|
dispose() {
|
|
4180
|
+
this._fontLoader.dispose();
|
|
3926
4181
|
for (const unitId of this._sessions.keys()) this._disposeSession(unitId);
|
|
3927
4182
|
this._performanceTracker.resetAll();
|
|
3928
4183
|
}
|
|
@@ -3980,10 +4235,21 @@ var DocsLayoutWorkerRuntime = class {
|
|
|
3980
4235
|
session.localeService.dispose();
|
|
3981
4236
|
}
|
|
3982
4237
|
};
|
|
4238
|
+
var DocsLayoutWorkerChannelService = class extends ChannelService {
|
|
4239
|
+
constructor(protocol, _runtime) {
|
|
4240
|
+
super(protocol);
|
|
4241
|
+
this._runtime = _runtime;
|
|
4242
|
+
}
|
|
4243
|
+
dispose() {
|
|
4244
|
+
this._runtime.dispose();
|
|
4245
|
+
super.dispose();
|
|
4246
|
+
}
|
|
4247
|
+
};
|
|
3983
4248
|
function startDocsLayoutWorker() {
|
|
3984
4249
|
const performanceTracker = new DocsLayoutWorkerPerformanceTracker();
|
|
3985
|
-
const
|
|
3986
|
-
channelService
|
|
4250
|
+
const runtime = new DocsLayoutWorkerRuntime(performanceTracker);
|
|
4251
|
+
const channelService = new DocsLayoutWorkerChannelService(createDocsLayoutWorkerMessageProtocol$1(performanceTracker), runtime);
|
|
4252
|
+
channelService.registerChannel(DOCS_LAYOUT_WORKER_CHANNEL, fromModule(runtime));
|
|
3987
4253
|
return channelService;
|
|
3988
4254
|
}
|
|
3989
4255
|
|
|
@@ -4014,10 +4280,11 @@ function createDocsLayoutWorkerMessageProtocol(worker, performanceTracker) {
|
|
|
4014
4280
|
};
|
|
4015
4281
|
}
|
|
4016
4282
|
var DocsLayoutWorkerClientService = class extends Disposable {
|
|
4017
|
-
constructor(_workerFactory, _requestTimeoutMs = DEFAULT_DOCS_LAYOUT_WORKER_REQUEST_TIMEOUT_MS) {
|
|
4283
|
+
constructor(_workerFactory, _requestTimeoutMs = DEFAULT_DOCS_LAYOUT_WORKER_REQUEST_TIMEOUT_MS, _fontFaces = []) {
|
|
4018
4284
|
super();
|
|
4019
4285
|
this._workerFactory = _workerFactory;
|
|
4020
4286
|
this._requestTimeoutMs = _requestTimeoutMs;
|
|
4287
|
+
this._fontFaces = _fontFaces;
|
|
4021
4288
|
_defineProperty(this, "type", "worker");
|
|
4022
4289
|
_defineProperty(this, "_worker", null);
|
|
4023
4290
|
_defineProperty(this, "_channelService", null);
|
|
@@ -4026,12 +4293,18 @@ var DocsLayoutWorkerClientService = class extends Disposable {
|
|
|
4026
4293
|
_defineProperty(this, "_initialized", false);
|
|
4027
4294
|
_defineProperty(this, "_performanceTracker", new DocsLayoutWorkerPerformanceTracker());
|
|
4028
4295
|
_defineProperty(this, "_fontFamilies", /* @__PURE__ */ new Map());
|
|
4296
|
+
_defineProperty(this, "_fontLoader", new DocsLayoutFontLoader());
|
|
4297
|
+
this.disposeWithMe(this._fontLoader);
|
|
4029
4298
|
this._initialization = this._replaceRuntime();
|
|
4030
4299
|
}
|
|
4031
4300
|
initialize() {
|
|
4032
4301
|
return this._initialization;
|
|
4033
4302
|
}
|
|
4034
|
-
|
|
4303
|
+
get renderingFontsReady() {
|
|
4304
|
+
return this._fontFaces.length > 0 ? this._initialization : void 0;
|
|
4305
|
+
}
|
|
4306
|
+
async getCapabilities() {
|
|
4307
|
+
await this._initialization;
|
|
4035
4308
|
return this._getRuntime().getCapabilities();
|
|
4036
4309
|
}
|
|
4037
4310
|
async recover() {
|
|
@@ -4108,13 +4381,22 @@ var DocsLayoutWorkerClientService = class extends Disposable {
|
|
|
4108
4381
|
async _replaceRuntime() {
|
|
4109
4382
|
this._initialized = false;
|
|
4110
4383
|
this._disposeRuntime();
|
|
4384
|
+
await this._withTimeout(this._fontLoader.load(this._fontFaces), "load rendering fonts");
|
|
4385
|
+
this.ensureNotDisposed();
|
|
4111
4386
|
const worker = this._workerFactory();
|
|
4112
4387
|
const channelService = new ChannelService(createDocsLayoutWorkerMessageProtocol(worker, this._performanceTracker));
|
|
4113
4388
|
this._worker = worker;
|
|
4114
4389
|
this._channelService = channelService;
|
|
4115
4390
|
this._runtime = toModule(channelService.requestChannel(DOCS_LAYOUT_WORKER_CHANNEL));
|
|
4116
|
-
|
|
4117
|
-
|
|
4391
|
+
try {
|
|
4392
|
+
await this._withTimeout(this._runtime.initialize(this._fontFaces), "load Worker fonts");
|
|
4393
|
+
await this._withTimeout(this._verifyCapabilities(), "verify capabilities");
|
|
4394
|
+
this.ensureNotDisposed();
|
|
4395
|
+
this._initialized = true;
|
|
4396
|
+
} catch (error) {
|
|
4397
|
+
if (this._worker === worker) this._disposeRuntime();
|
|
4398
|
+
throw error;
|
|
4399
|
+
}
|
|
4118
4400
|
}
|
|
4119
4401
|
_disposeRuntime() {
|
|
4120
4402
|
var _this$_channelService, _this$_worker;
|
|
@@ -4143,7 +4425,7 @@ var DocsLayoutWorkerClientService = class extends Disposable {
|
|
|
4143
4425
|
});
|
|
4144
4426
|
}
|
|
4145
4427
|
async _verifyCapabilities() {
|
|
4146
|
-
const capabilities = await this.getCapabilities();
|
|
4428
|
+
const capabilities = await this._getRuntime().getCapabilities();
|
|
4147
4429
|
if (capabilities.protocolVersion !== 5) throw new DocsLayoutWorkerCapabilityError("Document layout Worker protocol version mismatch.");
|
|
4148
4430
|
if (!capabilities.offscreenCanvas || !capabilities.structuredClone) throw new DocsLayoutWorkerCapabilityError("Document layout Worker requires OffscreenCanvas and structured clone support.");
|
|
4149
4431
|
const mainMetrics = FontCache.getMeasureText(capabilities.fontProbe.content, capabilities.fontProbe.font);
|
|
@@ -4168,7 +4450,7 @@ let UniverDocsLayoutWorkerPlugin = class UniverDocsLayoutWorkerPlugin extends Pl
|
|
|
4168
4450
|
if (typeof this._config.workerFactory !== "function") throw new TypeError("[UniverDocsLayoutWorkerPlugin]: workerFactory is required.");
|
|
4169
4451
|
const requestTimeoutMs = this._config.requestTimeoutMs ?? 15e3;
|
|
4170
4452
|
if (!Number.isFinite(requestTimeoutMs) || requestTimeoutMs <= 0) throw new RangeError("[UniverDocsLayoutWorkerPlugin]: requestTimeoutMs must be a positive finite number.");
|
|
4171
|
-
const client = new DocsLayoutWorkerClientService(this._config.workerFactory, requestTimeoutMs);
|
|
4453
|
+
const client = new DocsLayoutWorkerClientService(this._config.workerFactory, requestTimeoutMs, this._config.fontFaces);
|
|
4172
4454
|
this._injector.add([DocsLayoutWorkerClientService, { useValue: client }]);
|
|
4173
4455
|
this.disposeWithMe(client);
|
|
4174
4456
|
this.disposeWithMe(this._layoutExecutorService.register(client));
|
|
@@ -4231,7 +4513,8 @@ let DocInterceptorService = class DocInterceptorService extends Disposable {
|
|
|
4231
4513
|
}
|
|
4232
4514
|
fetchThroughInterceptors(name) {
|
|
4233
4515
|
const key = name;
|
|
4234
|
-
|
|
4516
|
+
const interceptors = this._interceptorsByName.get(key);
|
|
4517
|
+
return composeInterceptors(interceptors || []);
|
|
4235
4518
|
}
|
|
4236
4519
|
interceptDocumentViewModel(viewModel) {
|
|
4237
4520
|
const disposableCollection = new DisposableCollection();
|