@beyondwork/docx-react-component 1.0.42 → 1.0.43
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/package.json +30 -41
- package/src/api/editor-state-types.ts +110 -0
- package/src/api/public-types.ts +194 -1
- package/src/core/commands/index.ts +33 -8
- package/src/core/search/search-text.ts +15 -2
- package/src/index.ts +13 -0
- package/src/io/docx-session.ts +672 -2
- package/src/io/load-scheduler.ts +230 -0
- package/src/io/normalize/normalize-text.ts +83 -0
- package/src/io/ooxml/workflow-payload-validator.ts +97 -1
- package/src/io/ooxml/workflow-payload.ts +172 -1
- package/src/runtime/collab-session.ts +1 -1
- package/src/runtime/document-runtime.ts +364 -36
- package/src/runtime/editor-state-channel.ts +544 -0
- package/src/runtime/editor-state-integration.ts +217 -0
- package/src/runtime/layout/index.ts +2 -0
- package/src/runtime/layout/inert-layout-facet.ts +2 -0
- package/src/runtime/layout/layout-engine-instance.ts +17 -2
- package/src/runtime/layout/paginated-layout-engine.ts +211 -14
- package/src/runtime/layout/public-facet.ts +400 -1
- package/src/runtime/perf-counters.ts +28 -0
- package/src/runtime/render/render-frame-types.ts +17 -0
- package/src/runtime/render/render-kernel.ts +172 -29
- package/src/runtime/surface-projection.ts +10 -5
- package/src/runtime/workflow-markup.ts +71 -16
- package/src/ui/WordReviewEditor.tsx +67 -45
- package/src/ui/editor-command-bag.ts +14 -0
- package/src/ui/editor-runtime-boundary.ts +110 -11
- package/src/ui/editor-shell-view.tsx +10 -0
- package/src/ui/editor-surface-controller.tsx +5 -0
- package/src/ui/headless/selection-helpers.ts +10 -0
- package/src/ui-tailwind/chrome/chrome-preset-toolbar.tsx +62 -2
- package/src/ui-tailwind/chrome/collab-top-nav-container.tsx +281 -0
- package/src/ui-tailwind/chrome-overlay/tw-chrome-overlay.tsx +48 -0
- package/src/ui-tailwind/editor-surface/paste-plain-text.ts +72 -0
- package/src/ui-tailwind/editor-surface/pm-command-bridge.ts +118 -8
- package/src/ui-tailwind/editor-surface/pm-schema.ts +152 -4
- package/src/ui-tailwind/editor-surface/pm-state-from-snapshot.ts +35 -7
- package/src/ui-tailwind/editor-surface/tw-page-block-view.helpers.ts +265 -0
- package/src/ui-tailwind/editor-surface/tw-page-block-view.tsx +8 -255
- package/src/ui-tailwind/editor-surface/tw-prosemirror-surface.tsx +9 -0
- package/src/ui-tailwind/index.ts +5 -1
- package/src/ui-tailwind/page-stack/tw-endnote-area.tsx +57 -0
- package/src/ui-tailwind/page-stack/tw-footnote-area.tsx +71 -0
- package/src/ui-tailwind/page-stack/tw-page-footer-band.tsx +73 -0
- package/src/ui-tailwind/page-stack/tw-page-header-band.tsx +74 -0
- package/src/ui-tailwind/page-stack/tw-page-stack-chrome-layer.tsx +477 -0
- package/src/ui-tailwind/page-stack/tw-region-block-renderer.tsx +374 -0
- package/src/ui-tailwind/review/comment-markdown-renderer.tsx +155 -0
- package/src/ui-tailwind/review/tw-comment-sidebar.tsx +77 -16
- package/src/ui-tailwind/tw-review-workspace.tsx +172 -94
package/src/io/docx-session.ts
CHANGED
|
@@ -39,7 +39,11 @@ import {
|
|
|
39
39
|
type ParsedInlineNode,
|
|
40
40
|
type ParsedPermStartInlineNode,
|
|
41
41
|
} from "./ooxml/parse-main-document.ts";
|
|
42
|
-
import {
|
|
42
|
+
import {
|
|
43
|
+
normalizeParsedTextDocument,
|
|
44
|
+
normalizeParsedTextDocumentAsync,
|
|
45
|
+
} from "./normalize/normalize-text.ts";
|
|
46
|
+
import { type LoadScheduler } from "./load-scheduler.ts";
|
|
43
47
|
import {
|
|
44
48
|
CONTENT_TYPES_PATH,
|
|
45
49
|
PACKAGE_RELATIONSHIPS_PATH,
|
|
@@ -213,6 +217,17 @@ interface LoadDocxEditorSessionOptions {
|
|
|
213
217
|
sourceLabel?: string;
|
|
214
218
|
bytes: Uint8Array | ArrayBuffer;
|
|
215
219
|
editorBuild?: string;
|
|
220
|
+
/**
|
|
221
|
+
* Fastload P2: optional instrumentation callback invoked once per
|
|
222
|
+
* completed load stage. Stage ordering: opc → body →
|
|
223
|
+
* styles-numbering-comments → skeleton-ready. `durationMs` is
|
|
224
|
+
* measured against `performance.now()` boundaries inside the loader.
|
|
225
|
+
*
|
|
226
|
+
* Pure instrumentation — has no effect on returned session shape.
|
|
227
|
+
* Safe to leave undefined; existing callers observe no behavior
|
|
228
|
+
* change.
|
|
229
|
+
*/
|
|
230
|
+
onLoadStage?: (stage: import("../api/public-types.ts").LoadStage, durationMs: number) => void;
|
|
216
231
|
}
|
|
217
232
|
|
|
218
233
|
export interface LoadedDocxEditorSession {
|
|
@@ -225,6 +240,8 @@ export interface LoadedDocxEditorSession {
|
|
|
225
240
|
sessionState: EditorSessionState | PersistedEditorSnapshot,
|
|
226
241
|
options?: ExportDocxOptions,
|
|
227
242
|
) => Promise<ExportResult>;
|
|
243
|
+
/** Schema 1.2 — editorState block parsed from the 1.2 payload, if present. */
|
|
244
|
+
initialEditorStatePayload?: import("./ooxml/workflow-payload.ts").EditorStatePayload;
|
|
228
245
|
}
|
|
229
246
|
|
|
230
247
|
interface ImportedDocxState {
|
|
@@ -277,6 +294,37 @@ const BLOCKING_COMMENT_DIAGNOSTIC_CODES = new Set<CommentImportDiagnostic["code"
|
|
|
277
294
|
"preserve_only_revision_overlap",
|
|
278
295
|
]);
|
|
279
296
|
|
|
297
|
+
interface StageEmitter {
|
|
298
|
+
emit(stage: import("../api/public-types.ts").LoadStage): void;
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
/**
|
|
302
|
+
* Fastload P2 (hoisted in P6): build a stage-event emitter. When no callback
|
|
303
|
+
* is supplied the emitter is a zero-cost no-op. Shared between the sync and
|
|
304
|
+
* async load orchestrators so both paths emit `load-stage` events at the
|
|
305
|
+
* same four boundaries: `opc` → `body` → `styles-numbering-comments` →
|
|
306
|
+
* `skeleton-ready`.
|
|
307
|
+
*/
|
|
308
|
+
function createStageEmitter(
|
|
309
|
+
onStage: LoadDocxEditorSessionOptions["onLoadStage"],
|
|
310
|
+
): StageEmitter {
|
|
311
|
+
if (!onStage) {
|
|
312
|
+
return {
|
|
313
|
+
emit() {
|
|
314
|
+
/* no-op */
|
|
315
|
+
},
|
|
316
|
+
};
|
|
317
|
+
}
|
|
318
|
+
let cursor = loadStageNow();
|
|
319
|
+
return {
|
|
320
|
+
emit(stage) {
|
|
321
|
+
const nextMark = loadStageNow();
|
|
322
|
+
onStage(stage, nextMark - cursor);
|
|
323
|
+
cursor = nextMark;
|
|
324
|
+
},
|
|
325
|
+
};
|
|
326
|
+
}
|
|
327
|
+
|
|
280
328
|
export function loadDocxEditorSession(
|
|
281
329
|
options: LoadDocxEditorSessionOptions,
|
|
282
330
|
): LoadedDocxEditorSession {
|
|
@@ -285,6 +333,9 @@ export function loadDocxEditorSession(
|
|
|
285
333
|
? options.editorBuild
|
|
286
334
|
: "dev";
|
|
287
335
|
const sourceBytes = toUint8Array(options.bytes);
|
|
336
|
+
|
|
337
|
+
const stages = createStageEmitter(options.onLoadStage);
|
|
338
|
+
|
|
288
339
|
let sourcePackage: OpcPackage;
|
|
289
340
|
|
|
290
341
|
try {
|
|
@@ -297,6 +348,7 @@ export function loadDocxEditorSession(
|
|
|
297
348
|
}),
|
|
298
349
|
);
|
|
299
350
|
}
|
|
351
|
+
stages.emit("opc");
|
|
300
352
|
const embeddedWorkflowPayload = parseWorkflowPayloadEnvelopeFromPackage(sourcePackage);
|
|
301
353
|
const embeddedWorkflowMetadata = embeddedWorkflowPayload?.workflowMetadata;
|
|
302
354
|
const embeddedWorkflowOverlay = embeddedWorkflowPayload?.workflowOverlay;
|
|
@@ -376,6 +428,7 @@ export function loadDocxEditorSession(
|
|
|
376
428
|
parsedDocument,
|
|
377
429
|
mainDocumentPath,
|
|
378
430
|
);
|
|
431
|
+
stages.emit("body");
|
|
379
432
|
const commentsPartPath = resolveCommentsPartPath(
|
|
380
433
|
sourcePackage,
|
|
381
434
|
mainDocumentPath,
|
|
@@ -438,6 +491,7 @@ export function loadDocxEditorSession(
|
|
|
438
491
|
normalizedDocument.preservation.opaqueFragments,
|
|
439
492
|
normalizedRevisions.revisions,
|
|
440
493
|
);
|
|
494
|
+
stages.emit("styles-numbering-comments");
|
|
441
495
|
const importedStoryRevisions: ReviewRevisionRecord[] = [];
|
|
442
496
|
const importedStoryRevisionDiagnostics: ParsedRevisionsResult["diagnostics"] = [];
|
|
443
497
|
const subPartOpaqueState = createSubPartOpaqueImportState(
|
|
@@ -813,6 +867,7 @@ export function loadDocxEditorSession(
|
|
|
813
867
|
},
|
|
814
868
|
};
|
|
815
869
|
|
|
870
|
+
stages.emit("skeleton-ready");
|
|
816
871
|
return {
|
|
817
872
|
initialSessionState,
|
|
818
873
|
initialSnapshot: snapshot,
|
|
@@ -820,6 +875,9 @@ export function loadDocxEditorSession(
|
|
|
820
875
|
protectionSnapshot: importedProtectionSnapshot,
|
|
821
876
|
exportDocx: async (nextSessionState, exportOptions) =>
|
|
822
877
|
exportDocxEditorSession(importedState, nextSessionState, exportOptions),
|
|
878
|
+
...(embeddedWorkflowPayload?.editorState
|
|
879
|
+
? { initialEditorStatePayload: embeddedWorkflowPayload.editorState }
|
|
880
|
+
: {}),
|
|
823
881
|
};
|
|
824
882
|
} catch (error) {
|
|
825
883
|
return createDiagnosticsSession(
|
|
@@ -829,6 +887,614 @@ export function loadDocxEditorSession(
|
|
|
829
887
|
}
|
|
830
888
|
}
|
|
831
889
|
|
|
890
|
+
interface LoadDocxEditorSessionAsyncOptions extends LoadDocxEditorSessionOptions {
|
|
891
|
+
/**
|
|
892
|
+
* Scheduler that the async loader awaits between parse stages. Callers
|
|
893
|
+
* in DOM environments should construct this with `createLoadScheduler()`
|
|
894
|
+
* (auto-detects scheduler.yield → MessageChannel → setTimeout backend).
|
|
895
|
+
* Callers in Node / SSR should pass
|
|
896
|
+
* `createLoadScheduler({ backendOverride: "sync" })` — sync backend
|
|
897
|
+
* yields resolve without task-boundary latency, so the async path
|
|
898
|
+
* behaves like the sync path from the test harness POV.
|
|
899
|
+
*/
|
|
900
|
+
scheduler: LoadScheduler;
|
|
901
|
+
}
|
|
902
|
+
|
|
903
|
+
/**
|
|
904
|
+
* Fastload P6: async sibling of {@link loadDocxEditorSession} that yields to
|
|
905
|
+
* the browser between parse stages. Parse sequence is byte-equivalent to
|
|
906
|
+
* the sync path (asserted on every F*.docx fixture in
|
|
907
|
+
* `test/io/fastload-parity.test.ts`). Yields fire at:
|
|
908
|
+
* 1. after OPC read,
|
|
909
|
+
* 2. after `parseMainDocumentXml`,
|
|
910
|
+
* 3. between every header/footer sub-part parse,
|
|
911
|
+
* 4. after footnotes/endnotes parse,
|
|
912
|
+
* 5. after theme + settings + styles parse,
|
|
913
|
+
* 6. after `buildCompatibilityReport`,
|
|
914
|
+
* plus mid-walk yields every 256 blocks inside
|
|
915
|
+
* `normalizeParsedTextDocumentAsync` (stage 3 — body normalize).
|
|
916
|
+
*
|
|
917
|
+
* Sync `loadDocxEditorSession` remains the only entry point for Node tests
|
|
918
|
+
* and SSR. The DOM boundary in `editor-runtime-boundary.ts` calls this
|
|
919
|
+
* async path so the browser can paint the skeleton mid-parse.
|
|
920
|
+
*/
|
|
921
|
+
export async function loadDocxEditorSessionAsync(
|
|
922
|
+
options: LoadDocxEditorSessionAsyncOptions,
|
|
923
|
+
): Promise<LoadedDocxEditorSession> {
|
|
924
|
+
const { scheduler } = options;
|
|
925
|
+
const editorBuild =
|
|
926
|
+
typeof options.editorBuild === "string" && options.editorBuild.length > 0
|
|
927
|
+
? options.editorBuild
|
|
928
|
+
: "dev";
|
|
929
|
+
const sourceBytes = toUint8Array(options.bytes);
|
|
930
|
+
|
|
931
|
+
const stages = createStageEmitter(options.onLoadStage);
|
|
932
|
+
|
|
933
|
+
let sourcePackage: OpcPackage;
|
|
934
|
+
|
|
935
|
+
try {
|
|
936
|
+
sourcePackage = readOpcPackage(sourceBytes);
|
|
937
|
+
} catch (error) {
|
|
938
|
+
return createDiagnosticsSession(
|
|
939
|
+
options,
|
|
940
|
+
createPackageImportDiagnostics({
|
|
941
|
+
issue: classifyCorruptPackageError(error),
|
|
942
|
+
}),
|
|
943
|
+
);
|
|
944
|
+
}
|
|
945
|
+
stages.emit("opc");
|
|
946
|
+
await scheduler.yield();
|
|
947
|
+
const embeddedWorkflowPayload = parseWorkflowPayloadEnvelopeFromPackage(sourcePackage);
|
|
948
|
+
const embeddedWorkflowMetadata = embeddedWorkflowPayload?.workflowMetadata;
|
|
949
|
+
const embeddedWorkflowOverlay = embeddedWorkflowPayload?.workflowOverlay;
|
|
950
|
+
|
|
951
|
+
const mainDocumentPath = resolveMainDocumentPartPath(sourcePackage);
|
|
952
|
+
const brokenRelationshipIssues = collectBrokenInternalRelationshipIssues(
|
|
953
|
+
sourcePackage,
|
|
954
|
+
mainDocumentPath,
|
|
955
|
+
);
|
|
956
|
+
if (brokenRelationshipIssues.length > 0) {
|
|
957
|
+
return createDiagnosticsSession(
|
|
958
|
+
options,
|
|
959
|
+
createPackageImportDiagnostics({
|
|
960
|
+
issue: {
|
|
961
|
+
...brokenRelationshipIssues[0],
|
|
962
|
+
message: summarizeBrokenRelationshipIssues(brokenRelationshipIssues),
|
|
963
|
+
details: {
|
|
964
|
+
issueCount: brokenRelationshipIssues.length,
|
|
965
|
+
targets: brokenRelationshipIssues.map((issue) => issue.targetPartPath).filter(Boolean),
|
|
966
|
+
},
|
|
967
|
+
},
|
|
968
|
+
}),
|
|
969
|
+
);
|
|
970
|
+
}
|
|
971
|
+
|
|
972
|
+
if (!mainDocumentPath) {
|
|
973
|
+
return createDiagnosticsSession(
|
|
974
|
+
options,
|
|
975
|
+
createPackageImportDiagnostics({
|
|
976
|
+
issue: createMissingPartIssue(MAIN_DOCUMENT_PATH),
|
|
977
|
+
}),
|
|
978
|
+
);
|
|
979
|
+
}
|
|
980
|
+
|
|
981
|
+
const documentPart = sourcePackage.parts.get(mainDocumentPath);
|
|
982
|
+
if (!documentPart) {
|
|
983
|
+
return createDiagnosticsSession(
|
|
984
|
+
options,
|
|
985
|
+
createPackageImportDiagnostics({
|
|
986
|
+
issue: createMissingPartIssue(mainDocumentPath),
|
|
987
|
+
}),
|
|
988
|
+
);
|
|
989
|
+
}
|
|
990
|
+
if (documentPart.contentType !== MAIN_DOCUMENT_CONTENT_TYPE) {
|
|
991
|
+
return createDiagnosticsSession(
|
|
992
|
+
options,
|
|
993
|
+
createValidationImportDiagnostics({
|
|
994
|
+
message: `DOCX main document part ${mainDocumentPath} must use content type ${MAIN_DOCUMENT_CONTENT_TYPE}.`,
|
|
995
|
+
}),
|
|
996
|
+
);
|
|
997
|
+
}
|
|
998
|
+
|
|
999
|
+
try {
|
|
1000
|
+
const sourceDocumentXml = decodeUtf8(documentPart.bytes);
|
|
1001
|
+
const importedRevisions = parseRevisionsFromDocumentXml(sourceDocumentXml);
|
|
1002
|
+
const numberingPartPath = resolveDocumentRelatedPartPath(
|
|
1003
|
+
sourcePackage,
|
|
1004
|
+
mainDocumentPath,
|
|
1005
|
+
documentPart.relationships,
|
|
1006
|
+
NUMBERING_RELATIONSHIP_TYPE,
|
|
1007
|
+
NUMBERING_PART_PATH,
|
|
1008
|
+
);
|
|
1009
|
+
const parsedNumbering = numberingPartPath
|
|
1010
|
+
? parseNumberingXml(
|
|
1011
|
+
decodeUtf8(sourcePackage.parts.get(numberingPartPath)?.bytes ?? new Uint8Array()),
|
|
1012
|
+
)
|
|
1013
|
+
: createEmptyNumberingCatalog();
|
|
1014
|
+
const mediaParts = collectInlineMediaParts(sourcePackage);
|
|
1015
|
+
const parsedDocument = parseMainDocumentXml(
|
|
1016
|
+
sourceDocumentXml,
|
|
1017
|
+
documentPart.relationships,
|
|
1018
|
+
mediaParts,
|
|
1019
|
+
mainDocumentPath,
|
|
1020
|
+
);
|
|
1021
|
+
await scheduler.yield();
|
|
1022
|
+
const protectionRanges = extractProtectionRanges(parsedDocument.blocks);
|
|
1023
|
+
const normalizedDocument = await normalizeParsedTextDocumentAsync(
|
|
1024
|
+
parsedDocument,
|
|
1025
|
+
mainDocumentPath,
|
|
1026
|
+
scheduler,
|
|
1027
|
+
);
|
|
1028
|
+
stages.emit("body");
|
|
1029
|
+
await scheduler.yield();
|
|
1030
|
+
const commentsPartPath = resolveCommentsPartPath(
|
|
1031
|
+
sourcePackage,
|
|
1032
|
+
mainDocumentPath,
|
|
1033
|
+
documentPart.relationships,
|
|
1034
|
+
);
|
|
1035
|
+
const commentsExtendedPartPath = resolveDocumentRelatedPartPath(
|
|
1036
|
+
sourcePackage,
|
|
1037
|
+
mainDocumentPath,
|
|
1038
|
+
documentPart.relationships,
|
|
1039
|
+
COMMENTS_EXTENDED_RELATIONSHIP_TYPE,
|
|
1040
|
+
COMMENTS_EXTENDED_PART_PATH,
|
|
1041
|
+
);
|
|
1042
|
+
const commentsIdsPartPath = resolveDocumentRelatedPartPath(
|
|
1043
|
+
sourcePackage,
|
|
1044
|
+
mainDocumentPath,
|
|
1045
|
+
documentPart.relationships,
|
|
1046
|
+
COMMENTS_IDS_RELATIONSHIP_TYPE,
|
|
1047
|
+
COMMENTS_IDS_PART_PATH,
|
|
1048
|
+
);
|
|
1049
|
+
const peoplePartPath = resolveDocumentRelatedPartPath(
|
|
1050
|
+
sourcePackage,
|
|
1051
|
+
mainDocumentPath,
|
|
1052
|
+
documentPart.relationships,
|
|
1053
|
+
PEOPLE_RELATIONSHIP_TYPE,
|
|
1054
|
+
PEOPLE_PART_PATH,
|
|
1055
|
+
);
|
|
1056
|
+
const parsedComments = commentsPartPath
|
|
1057
|
+
? parseCommentsFromOoxml(
|
|
1058
|
+
sourceDocumentXml,
|
|
1059
|
+
{
|
|
1060
|
+
commentsXml: decodeUtf8(sourcePackage.parts.get(commentsPartPath)?.bytes ?? new Uint8Array()),
|
|
1061
|
+
commentsExtendedXml: decodeUtf8(
|
|
1062
|
+
sourcePackage.parts.get(commentsExtendedPartPath ?? "")?.bytes ?? new Uint8Array(),
|
|
1063
|
+
),
|
|
1064
|
+
commentsIdsXml: decodeUtf8(
|
|
1065
|
+
sourcePackage.parts.get(commentsIdsPartPath ?? "")?.bytes ?? new Uint8Array(),
|
|
1066
|
+
),
|
|
1067
|
+
peopleXml: decodeUtf8(
|
|
1068
|
+
sourcePackage.parts.get(peoplePartPath ?? "")?.bytes ?? new Uint8Array(),
|
|
1069
|
+
),
|
|
1070
|
+
},
|
|
1071
|
+
)
|
|
1072
|
+
: {
|
|
1073
|
+
threads: [] as CommentThread[],
|
|
1074
|
+
diagnostics: [] as CommentImportDiagnostic[],
|
|
1075
|
+
definitions: [] as ImportedCommentDefinition[],
|
|
1076
|
+
sourceRootTag: undefined,
|
|
1077
|
+
sourceExtendedRootTag: undefined,
|
|
1078
|
+
sourceIdsRootTag: undefined,
|
|
1079
|
+
sourcePeopleRootTag: undefined,
|
|
1080
|
+
peopleAuthors: [] as string[],
|
|
1081
|
+
};
|
|
1082
|
+
const normalizedRevisions = normalizeImportedRevisionRecords(
|
|
1083
|
+
importedRevisions,
|
|
1084
|
+
normalizedDocument.content,
|
|
1085
|
+
normalizedDocument.preservation.opaqueFragments,
|
|
1086
|
+
);
|
|
1087
|
+
const normalizedComments = normalizeImportedCommentThreads(
|
|
1088
|
+
parsedComments,
|
|
1089
|
+
normalizedDocument.preservation.opaqueFragments,
|
|
1090
|
+
normalizedRevisions.revisions,
|
|
1091
|
+
);
|
|
1092
|
+
stages.emit("styles-numbering-comments");
|
|
1093
|
+
const importedStoryRevisions: ReviewRevisionRecord[] = [];
|
|
1094
|
+
const importedStoryRevisionDiagnostics: ParsedRevisionsResult["diagnostics"] = [];
|
|
1095
|
+
const subPartOpaqueState = createSubPartOpaqueImportState(
|
|
1096
|
+
normalizedDocument.preservation.opaqueFragments,
|
|
1097
|
+
normalizedDocument.diagnostics.warnings,
|
|
1098
|
+
);
|
|
1099
|
+
// ---- Parse sub-parts: headers, footers, footnotes, endnotes, theme ----
|
|
1100
|
+
const headerFooterRefs = parseHeaderFooterReferences(sourceDocumentXml);
|
|
1101
|
+
const parsedHeaders: HeaderDocument[] = [];
|
|
1102
|
+
const parsedFooters: FooterDocument[] = [];
|
|
1103
|
+
const sourceHeaderPaths: Array<{ partPath: string; relationshipId: string }> = [];
|
|
1104
|
+
const sourceFooterPaths: Array<{ partPath: string; relationshipId: string }> = [];
|
|
1105
|
+
const seenSubPartKeys = new Set<string>();
|
|
1106
|
+
|
|
1107
|
+
for (const ref of headerFooterRefs) {
|
|
1108
|
+
const dedupeKey = `${ref.kind}:${ref.variant}:${ref.relationshipId}`;
|
|
1109
|
+
if (seenSubPartKeys.has(dedupeKey)) {
|
|
1110
|
+
continue;
|
|
1111
|
+
}
|
|
1112
|
+
seenSubPartKeys.add(dedupeKey);
|
|
1113
|
+
|
|
1114
|
+
const relationship = documentPart.relationships.find(
|
|
1115
|
+
(r) => r.id === ref.relationshipId && r.targetMode === "internal",
|
|
1116
|
+
);
|
|
1117
|
+
if (!relationship) {
|
|
1118
|
+
continue;
|
|
1119
|
+
}
|
|
1120
|
+
|
|
1121
|
+
const partPath = resolveRelationshipTarget(mainDocumentPath, relationship);
|
|
1122
|
+
const partBytes = sourcePackage.parts.get(partPath)?.bytes;
|
|
1123
|
+
if (!partBytes) {
|
|
1124
|
+
continue;
|
|
1125
|
+
}
|
|
1126
|
+
|
|
1127
|
+
await scheduler.yield();
|
|
1128
|
+
const xml = decodeUtf8(partBytes);
|
|
1129
|
+
if (ref.kind === "header") {
|
|
1130
|
+
const parsedHeaderRevisions = parseRevisionsFromStoryXml(xml);
|
|
1131
|
+
const parsed = parseHeaderXml(xml);
|
|
1132
|
+
parsedHeaders.push({
|
|
1133
|
+
variant: ref.variant,
|
|
1134
|
+
partPath,
|
|
1135
|
+
relationshipId: ref.relationshipId,
|
|
1136
|
+
...(ref.sectionIndex !== undefined ? { sectionIndex: ref.sectionIndex } : {}),
|
|
1137
|
+
blocks: normalizeSubPartOpaqueBlocks(
|
|
1138
|
+
parsed.blocks,
|
|
1139
|
+
normalizedDocument.preservation.opaqueFragments,
|
|
1140
|
+
normalizedDocument.diagnostics.warnings,
|
|
1141
|
+
partPath,
|
|
1142
|
+
subPartOpaqueState,
|
|
1143
|
+
),
|
|
1144
|
+
});
|
|
1145
|
+
importedStoryRevisions.push(
|
|
1146
|
+
...parsedHeaderRevisions.revisions.map((revision): ReviewRevisionRecord => ({
|
|
1147
|
+
...revision,
|
|
1148
|
+
metadata: {
|
|
1149
|
+
...revision.metadata,
|
|
1150
|
+
storyTarget: {
|
|
1151
|
+
kind: "header" as const,
|
|
1152
|
+
relationshipId: ref.relationshipId,
|
|
1153
|
+
variant: ref.variant,
|
|
1154
|
+
...(ref.sectionIndex !== undefined ? { sectionIndex: ref.sectionIndex } : {}),
|
|
1155
|
+
},
|
|
1156
|
+
},
|
|
1157
|
+
})),
|
|
1158
|
+
);
|
|
1159
|
+
importedStoryRevisionDiagnostics.push(...parsedHeaderRevisions.diagnostics);
|
|
1160
|
+
sourceHeaderPaths.push({ partPath, relationshipId: ref.relationshipId });
|
|
1161
|
+
} else {
|
|
1162
|
+
const parsedFooterRevisions = parseRevisionsFromStoryXml(xml);
|
|
1163
|
+
const parsed = parseFooterXml(xml);
|
|
1164
|
+
parsedFooters.push({
|
|
1165
|
+
variant: ref.variant,
|
|
1166
|
+
partPath,
|
|
1167
|
+
relationshipId: ref.relationshipId,
|
|
1168
|
+
...(ref.sectionIndex !== undefined ? { sectionIndex: ref.sectionIndex } : {}),
|
|
1169
|
+
blocks: normalizeSubPartOpaqueBlocks(
|
|
1170
|
+
parsed.blocks,
|
|
1171
|
+
normalizedDocument.preservation.opaqueFragments,
|
|
1172
|
+
normalizedDocument.diagnostics.warnings,
|
|
1173
|
+
partPath,
|
|
1174
|
+
subPartOpaqueState,
|
|
1175
|
+
),
|
|
1176
|
+
});
|
|
1177
|
+
importedStoryRevisions.push(
|
|
1178
|
+
...parsedFooterRevisions.revisions.map((revision): ReviewRevisionRecord => ({
|
|
1179
|
+
...revision,
|
|
1180
|
+
metadata: {
|
|
1181
|
+
...revision.metadata,
|
|
1182
|
+
storyTarget: {
|
|
1183
|
+
kind: "footer" as const,
|
|
1184
|
+
relationshipId: ref.relationshipId,
|
|
1185
|
+
variant: ref.variant,
|
|
1186
|
+
...(ref.sectionIndex !== undefined ? { sectionIndex: ref.sectionIndex } : {}),
|
|
1187
|
+
},
|
|
1188
|
+
},
|
|
1189
|
+
})),
|
|
1190
|
+
);
|
|
1191
|
+
importedStoryRevisionDiagnostics.push(...parsedFooterRevisions.diagnostics);
|
|
1192
|
+
sourceFooterPaths.push({ partPath, relationshipId: ref.relationshipId });
|
|
1193
|
+
}
|
|
1194
|
+
}
|
|
1195
|
+
|
|
1196
|
+
const footnotesPartPath = resolveDocumentRelatedPartPath(
|
|
1197
|
+
sourcePackage,
|
|
1198
|
+
mainDocumentPath,
|
|
1199
|
+
documentPart.relationships,
|
|
1200
|
+
FOOTNOTES_RELATIONSHIP_TYPE,
|
|
1201
|
+
FOOTNOTES_PART_PATH,
|
|
1202
|
+
);
|
|
1203
|
+
const footnotesRelationshipId = documentPart.relationships.find(
|
|
1204
|
+
(r) => r.type === FOOTNOTES_RELATIONSHIP_TYPE && r.targetMode === "internal",
|
|
1205
|
+
)?.id;
|
|
1206
|
+
const endnotesPartPath = resolveDocumentRelatedPartPath(
|
|
1207
|
+
sourcePackage,
|
|
1208
|
+
mainDocumentPath,
|
|
1209
|
+
documentPart.relationships,
|
|
1210
|
+
ENDNOTES_RELATIONSHIP_TYPE,
|
|
1211
|
+
ENDNOTES_PART_PATH,
|
|
1212
|
+
);
|
|
1213
|
+
const endnotesRelationshipId = documentPart.relationships.find(
|
|
1214
|
+
(r) => r.type === ENDNOTES_RELATIONSHIP_TYPE && r.targetMode === "internal",
|
|
1215
|
+
)?.id;
|
|
1216
|
+
|
|
1217
|
+
let footnoteCollection: FootnoteCollection | undefined;
|
|
1218
|
+
if (footnotesPartPath) {
|
|
1219
|
+
footnoteCollection = parseFootnotesXml(
|
|
1220
|
+
decodeUtf8(sourcePackage.parts.get(footnotesPartPath)?.bytes ?? new Uint8Array()),
|
|
1221
|
+
);
|
|
1222
|
+
normalizeFootnoteCollectionOpaqueBlocks(
|
|
1223
|
+
footnoteCollection,
|
|
1224
|
+
"footnote",
|
|
1225
|
+
normalizedDocument.preservation.opaqueFragments,
|
|
1226
|
+
normalizedDocument.diagnostics.warnings,
|
|
1227
|
+
footnotesPartPath,
|
|
1228
|
+
subPartOpaqueState,
|
|
1229
|
+
);
|
|
1230
|
+
}
|
|
1231
|
+
if (endnotesPartPath) {
|
|
1232
|
+
footnoteCollection = parseEndnotesXml(
|
|
1233
|
+
decodeUtf8(sourcePackage.parts.get(endnotesPartPath)?.bytes ?? new Uint8Array()),
|
|
1234
|
+
footnoteCollection,
|
|
1235
|
+
);
|
|
1236
|
+
normalizeFootnoteCollectionOpaqueBlocks(
|
|
1237
|
+
footnoteCollection,
|
|
1238
|
+
"endnote",
|
|
1239
|
+
normalizedDocument.preservation.opaqueFragments,
|
|
1240
|
+
normalizedDocument.diagnostics.warnings,
|
|
1241
|
+
endnotesPartPath,
|
|
1242
|
+
subPartOpaqueState,
|
|
1243
|
+
);
|
|
1244
|
+
}
|
|
1245
|
+
await scheduler.yield();
|
|
1246
|
+
|
|
1247
|
+
const themeRelationship = documentPart.relationships.find(
|
|
1248
|
+
(r) => r.type === "http://schemas.openxmlformats.org/officeDocument/2006/relationships/theme" &&
|
|
1249
|
+
r.targetMode === "internal",
|
|
1250
|
+
);
|
|
1251
|
+
const themePartPath = themeRelationship
|
|
1252
|
+
? resolveRelationshipTarget(mainDocumentPath, themeRelationship)
|
|
1253
|
+
: undefined;
|
|
1254
|
+
const parsedTheme =
|
|
1255
|
+
themePartPath && sourcePackage.parts.has(themePartPath)
|
|
1256
|
+
? parseThemeXml(
|
|
1257
|
+
decodeUtf8(sourcePackage.parts.get(themePartPath)?.bytes ?? new Uint8Array()),
|
|
1258
|
+
)
|
|
1259
|
+
: undefined;
|
|
1260
|
+
const resolvedTheme = parsedTheme ? resolveTheme(parsedTheme) : undefined;
|
|
1261
|
+
const settingsPartPath = resolveDocumentRelatedPartPath(
|
|
1262
|
+
sourcePackage,
|
|
1263
|
+
mainDocumentPath,
|
|
1264
|
+
documentPart.relationships,
|
|
1265
|
+
SETTINGS_RELATIONSHIP_TYPE,
|
|
1266
|
+
SETTINGS_PART_PATH,
|
|
1267
|
+
);
|
|
1268
|
+
const parsedSettings =
|
|
1269
|
+
settingsPartPath && sourcePackage.parts.has(settingsPartPath)
|
|
1270
|
+
? parseSettingsXml(
|
|
1271
|
+
decodeUtf8(sourcePackage.parts.get(settingsPartPath)?.bytes ?? new Uint8Array()),
|
|
1272
|
+
)
|
|
1273
|
+
: undefined;
|
|
1274
|
+
const settingsXmlForProtection =
|
|
1275
|
+
settingsPartPath && sourcePackage.parts.has(settingsPartPath)
|
|
1276
|
+
? decodeUtf8(sourcePackage.parts.get(settingsPartPath)?.bytes ?? new Uint8Array())
|
|
1277
|
+
: "";
|
|
1278
|
+
const documentProtection = extractDocumentProtection(settingsXmlForProtection);
|
|
1279
|
+
const importedProtectionSnapshot = buildProtectionSnapshot(documentProtection, protectionRanges);
|
|
1280
|
+
|
|
1281
|
+
// ---- Parse styles.xml for canonical style catalog ----
|
|
1282
|
+
const stylesPartPath = resolveDocumentRelatedPartPath(
|
|
1283
|
+
sourcePackage,
|
|
1284
|
+
mainDocumentPath,
|
|
1285
|
+
documentPart.relationships,
|
|
1286
|
+
STYLES_RELATIONSHIP_TYPE,
|
|
1287
|
+
STYLES_PART_PATH,
|
|
1288
|
+
);
|
|
1289
|
+
const parsedStyles =
|
|
1290
|
+
stylesPartPath && sourcePackage.parts.has(stylesPartPath)
|
|
1291
|
+
? parseStylesXml(
|
|
1292
|
+
decodeUtf8(sourcePackage.parts.get(stylesPartPath)?.bytes ?? new Uint8Array()),
|
|
1293
|
+
)
|
|
1294
|
+
: parseStylesXml("");
|
|
1295
|
+
await scheduler.yield();
|
|
1296
|
+
|
|
1297
|
+
const subParts: SubPartsCatalog | undefined =
|
|
1298
|
+
parsedHeaders.length > 0 ||
|
|
1299
|
+
parsedFooters.length > 0 ||
|
|
1300
|
+
footnoteCollection !== undefined ||
|
|
1301
|
+
parsedTheme !== undefined ||
|
|
1302
|
+
normalizedDocument.finalSectionProperties !== undefined ||
|
|
1303
|
+
resolvedTheme !== undefined ||
|
|
1304
|
+
parsedSettings !== undefined
|
|
1305
|
+
? {
|
|
1306
|
+
headers: parsedHeaders,
|
|
1307
|
+
footers: parsedFooters,
|
|
1308
|
+
...(footnoteCollection !== undefined ? { footnoteCollection } : {}),
|
|
1309
|
+
...(parsedTheme !== undefined ? { theme: parsedTheme } : {}),
|
|
1310
|
+
...(normalizedDocument.finalSectionProperties !== undefined
|
|
1311
|
+
? { finalSectionProperties: normalizedDocument.finalSectionProperties }
|
|
1312
|
+
: {}),
|
|
1313
|
+
...(resolvedTheme !== undefined ? { resolvedTheme } : {}),
|
|
1314
|
+
...(parsedSettings !== undefined ? { settings: parsedSettings } : {}),
|
|
1315
|
+
}
|
|
1316
|
+
: undefined;
|
|
1317
|
+
|
|
1318
|
+
const timestamp = new Date().toISOString();
|
|
1319
|
+
const translatedWorkflowState = translateClmCommentsToWorkflow({
|
|
1320
|
+
comments: normalizedComments.threads,
|
|
1321
|
+
workflowOverlay: embeddedWorkflowOverlay,
|
|
1322
|
+
workflowMetadata: embeddedWorkflowMetadata,
|
|
1323
|
+
timestamp,
|
|
1324
|
+
});
|
|
1325
|
+
const document = createImportedCanonicalDocument({
|
|
1326
|
+
documentId: options.documentId,
|
|
1327
|
+
timestamp,
|
|
1328
|
+
numbering: parsedNumbering,
|
|
1329
|
+
media: normalizedDocument.media,
|
|
1330
|
+
content: normalizedDocument.content,
|
|
1331
|
+
subParts,
|
|
1332
|
+
parsedStyles,
|
|
1333
|
+
preservation: {
|
|
1334
|
+
...normalizedDocument.preservation,
|
|
1335
|
+
packageParts: {
|
|
1336
|
+
...normalizedDocument.preservation.packageParts,
|
|
1337
|
+
...collectPreservedPackageParts(sourcePackage, [
|
|
1338
|
+
mainDocumentPath,
|
|
1339
|
+
numberingPartPath,
|
|
1340
|
+
commentsPartPath,
|
|
1341
|
+
commentsExtendedPartPath,
|
|
1342
|
+
commentsIdsPartPath,
|
|
1343
|
+
peoplePartPath,
|
|
1344
|
+
]),
|
|
1345
|
+
},
|
|
1346
|
+
},
|
|
1347
|
+
diagnostics: {
|
|
1348
|
+
warnings: [
|
|
1349
|
+
...createBrokenRelationshipWarnings(sourcePackage, mainDocumentPath),
|
|
1350
|
+
...normalizedDocument.diagnostics.warnings,
|
|
1351
|
+
...normalizedRevisions.diagnostics.map((diagnostic, index) => ({
|
|
1352
|
+
diagnosticId: `diagnostic:revision-import-${index + 1}`,
|
|
1353
|
+
warningId: `warning:revision-import-${diagnostic.revisionId}`,
|
|
1354
|
+
source: "review" as const,
|
|
1355
|
+
message: diagnostic.message,
|
|
1356
|
+
})),
|
|
1357
|
+
...importedStoryRevisionDiagnostics.map((diagnostic, index) => ({
|
|
1358
|
+
diagnosticId: `diagnostic:story-revision-import-${index + 1}`,
|
|
1359
|
+
warningId: `warning:story-revision-import-${diagnostic.revisionId}`,
|
|
1360
|
+
source: "review" as const,
|
|
1361
|
+
message: diagnostic.message,
|
|
1362
|
+
})),
|
|
1363
|
+
...normalizedComments.diagnostics.map((diagnostic, index) => ({
|
|
1364
|
+
diagnosticId: `diagnostic:comment-import-${index + 1}`,
|
|
1365
|
+
warningId: `warning:comment-import-${diagnostic.commentId}`,
|
|
1366
|
+
source: "review" as const,
|
|
1367
|
+
message: diagnostic.message,
|
|
1368
|
+
})),
|
|
1369
|
+
],
|
|
1370
|
+
errors: [],
|
|
1371
|
+
},
|
|
1372
|
+
review: {
|
|
1373
|
+
comments: toRuntimeCommentRecords(translatedWorkflowState.comments),
|
|
1374
|
+
revisions: toRuntimeRevisionRecords([
|
|
1375
|
+
...normalizedRevisions.revisions,
|
|
1376
|
+
...importedStoryRevisions,
|
|
1377
|
+
]),
|
|
1378
|
+
},
|
|
1379
|
+
});
|
|
1380
|
+
const compatibility = buildCompatibilityReport({
|
|
1381
|
+
document,
|
|
1382
|
+
generatedAt: timestamp,
|
|
1383
|
+
});
|
|
1384
|
+
await scheduler.yield();
|
|
1385
|
+
const snapshot = createImportedSnapshot({
|
|
1386
|
+
documentId: options.documentId,
|
|
1387
|
+
editorBuild,
|
|
1388
|
+
timestamp,
|
|
1389
|
+
document,
|
|
1390
|
+
compatibility: toPublicCompatibilityReport(compatibility),
|
|
1391
|
+
protectionSnapshot: importedProtectionSnapshot,
|
|
1392
|
+
sourcePackage: createPersistedSourcePackage(sourceBytes, options.sourceLabel),
|
|
1393
|
+
workflowOverlay: translatedWorkflowState.workflowOverlay,
|
|
1394
|
+
workflowMetadata: translatedWorkflowState.workflowMetadata,
|
|
1395
|
+
});
|
|
1396
|
+
const snapshotIssues = validatePersistedEditorSnapshot(snapshot);
|
|
1397
|
+
if (snapshotIssues.length > 0) {
|
|
1398
|
+
const firstIssue = snapshotIssues[0];
|
|
1399
|
+
return createDiagnosticsSession(
|
|
1400
|
+
options,
|
|
1401
|
+
createValidationImportDiagnostics({
|
|
1402
|
+
message: `DOCX import produced an invalid editor state during validation${firstIssue ? ` (${firstIssue.path}: ${firstIssue.message})` : "."}`,
|
|
1403
|
+
source: "import",
|
|
1404
|
+
details: {
|
|
1405
|
+
issueCount: snapshotIssues.length,
|
|
1406
|
+
firstIssuePath: firstIssue?.path,
|
|
1407
|
+
},
|
|
1408
|
+
}),
|
|
1409
|
+
);
|
|
1410
|
+
}
|
|
1411
|
+
const initialSessionState = editorSessionStateFromPersistedSnapshot(snapshot);
|
|
1412
|
+
const importedState: ImportedDocxState = {
|
|
1413
|
+
sourceBytes: new Uint8Array(sourceBytes),
|
|
1414
|
+
sourcePackage,
|
|
1415
|
+
sourceDocumentXml,
|
|
1416
|
+
sourceDocumentPartPath: mainDocumentPath,
|
|
1417
|
+
sourceDocumentRelationships: documentPart.relationships,
|
|
1418
|
+
sourceDocumentAttributes: extractDocumentRootAttributes(sourceDocumentXml),
|
|
1419
|
+
sourceNumberingPartPath: numberingPartPath,
|
|
1420
|
+
sourceNumberingRelationshipId: documentPart.relationships.find(
|
|
1421
|
+
(relationship) =>
|
|
1422
|
+
relationship.type === NUMBERING_RELATIONSHIP_TYPE &&
|
|
1423
|
+
relationship.targetMode === "internal",
|
|
1424
|
+
)?.id,
|
|
1425
|
+
sourceCommentsPartPath: commentsPartPath,
|
|
1426
|
+
sourceCommentsRelationshipId: documentPart.relationships.find(
|
|
1427
|
+
(relationship) =>
|
|
1428
|
+
relationship.type === COMMENTS_RELATIONSHIP_TYPE &&
|
|
1429
|
+
relationship.targetMode === "internal",
|
|
1430
|
+
)?.id,
|
|
1431
|
+
sourceCommentsRootTag: normalizedComments.sourceRootTag,
|
|
1432
|
+
sourceCommentsExtendedPartPath: commentsExtendedPartPath,
|
|
1433
|
+
sourceCommentsExtendedRelationshipId: documentPart.relationships.find(
|
|
1434
|
+
(relationship) =>
|
|
1435
|
+
relationship.type === COMMENTS_EXTENDED_RELATIONSHIP_TYPE &&
|
|
1436
|
+
relationship.targetMode === "internal",
|
|
1437
|
+
)?.id,
|
|
1438
|
+
sourceCommentsExtendedRootTag: normalizedComments.sourceExtendedRootTag,
|
|
1439
|
+
sourceCommentsIdsPartPath: commentsIdsPartPath,
|
|
1440
|
+
sourceCommentsIdsRelationshipId: documentPart.relationships.find(
|
|
1441
|
+
(relationship) =>
|
|
1442
|
+
relationship.type === COMMENTS_IDS_RELATIONSHIP_TYPE &&
|
|
1443
|
+
relationship.targetMode === "internal",
|
|
1444
|
+
)?.id,
|
|
1445
|
+
sourceCommentsIdsRootTag: normalizedComments.sourceIdsRootTag,
|
|
1446
|
+
sourcePeoplePartPath: peoplePartPath,
|
|
1447
|
+
sourcePeopleRelationshipId: documentPart.relationships.find(
|
|
1448
|
+
(relationship) =>
|
|
1449
|
+
relationship.type === PEOPLE_RELATIONSHIP_TYPE &&
|
|
1450
|
+
relationship.targetMode === "internal",
|
|
1451
|
+
)?.id,
|
|
1452
|
+
sourcePeopleRootTag: normalizedComments.sourcePeopleRootTag,
|
|
1453
|
+
sourcePeopleAuthors: normalizedComments.peopleAuthors,
|
|
1454
|
+
protectionSnapshot: buildProtectionSnapshot(documentProtection, protectionRanges),
|
|
1455
|
+
preservedCommentDefinitions: normalizedComments.preservedDefinitions,
|
|
1456
|
+
blockingCommentDiagnostics: normalizedComments.diagnostics.filter((diagnostic) =>
|
|
1457
|
+
BLOCKING_COMMENT_DIAGNOSTIC_CODES.has(diagnostic.code),
|
|
1458
|
+
),
|
|
1459
|
+
initialCanonicalSignature: serializeCanonicalDocumentForExport(document),
|
|
1460
|
+
sourceSubPartPaths: {
|
|
1461
|
+
headers: sourceHeaderPaths,
|
|
1462
|
+
footers: sourceFooterPaths,
|
|
1463
|
+
footnotesPartPath,
|
|
1464
|
+
footnotesRelationshipId,
|
|
1465
|
+
endnotesPartPath,
|
|
1466
|
+
endnotesRelationshipId,
|
|
1467
|
+
themePartPath,
|
|
1468
|
+
themeRelationshipId: themeRelationship?.id,
|
|
1469
|
+
},
|
|
1470
|
+
};
|
|
1471
|
+
|
|
1472
|
+
stages.emit("skeleton-ready");
|
|
1473
|
+
return {
|
|
1474
|
+
initialSessionState,
|
|
1475
|
+
initialSnapshot: snapshot,
|
|
1476
|
+
readOnly: false,
|
|
1477
|
+
protectionSnapshot: importedProtectionSnapshot,
|
|
1478
|
+
exportDocx: async (nextSessionState, exportOptions) =>
|
|
1479
|
+
exportDocxEditorSession(importedState, nextSessionState, exportOptions),
|
|
1480
|
+
...(embeddedWorkflowPayload?.editorState
|
|
1481
|
+
? { initialEditorStatePayload: embeddedWorkflowPayload.editorState }
|
|
1482
|
+
: {}),
|
|
1483
|
+
};
|
|
1484
|
+
} catch (error) {
|
|
1485
|
+
return createDiagnosticsSession(
|
|
1486
|
+
options,
|
|
1487
|
+
createImportDiagnosticsFromError(error),
|
|
1488
|
+
);
|
|
1489
|
+
}
|
|
1490
|
+
}
|
|
1491
|
+
|
|
1492
|
+
function loadStageNow(): number {
|
|
1493
|
+
return typeof performance !== "undefined" && typeof performance.now === "function"
|
|
1494
|
+
? performance.now()
|
|
1495
|
+
: Date.now();
|
|
1496
|
+
}
|
|
1497
|
+
|
|
832
1498
|
function exportDocxEditorSession(
|
|
833
1499
|
state: ImportedDocxState,
|
|
834
1500
|
sessionStateOrSnapshot: EditorSessionState | PersistedEditorSnapshot,
|
|
@@ -1286,7 +1952,9 @@ function exportDocxEditorSession(
|
|
|
1286
1952
|
}
|
|
1287
1953
|
|
|
1288
1954
|
ensureHostMetadataParts(exportSession, state.sourcePackage, currentDocument);
|
|
1289
|
-
|
|
1955
|
+
// Schema 1.2: pass through editorState payload collected by the runtime channel.
|
|
1956
|
+
const internalEditorState = (options as { _editorState?: import("./ooxml/workflow-payload.ts").EditorStatePayload } | undefined)?._editorState;
|
|
1957
|
+
ensureWorkflowPayloadParts(exportSession, sessionState, currentDocument, state.sourcePackage, internalEditorState);
|
|
1290
1958
|
|
|
1291
1959
|
return {
|
|
1292
1960
|
bytes: exportSession.serialize(),
|
|
@@ -3012,11 +3680,13 @@ function ensureWorkflowPayloadParts(
|
|
|
3012
3680
|
sessionState: EditorSessionState,
|
|
3013
3681
|
document: CanonicalDocumentEnvelope,
|
|
3014
3682
|
sourcePackage: OpcPackage,
|
|
3683
|
+
editorState?: import("./ooxml/workflow-payload.ts").EditorStatePayload,
|
|
3015
3684
|
): void {
|
|
3016
3685
|
const payloadParts = buildWorkflowPayloadParts({
|
|
3017
3686
|
sourcePackage,
|
|
3018
3687
|
workflowMetadata: sessionState.workflowMetadata,
|
|
3019
3688
|
workflowOverlay: sessionState.workflowOverlay,
|
|
3689
|
+
editorState,
|
|
3020
3690
|
documentId: sessionState.documentId,
|
|
3021
3691
|
createdAt: document.createdAt,
|
|
3022
3692
|
updatedAt: document.updatedAt,
|