@stll/folio-core 0.56.0 → 0.57.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/dist/ai-edits/apply.js +45 -14
- package/dist/ai-edits/batch-claims.d.ts +3 -1
- package/dist/ai-edits/batch-claims.js +25 -1
- package/dist/ai-edits/table-row-column-mutations.js +17 -3
- package/dist/ai-suggestions/apply.js +20 -1
- package/dist/compare/inline-atoms.js +40 -16
- package/dist/compare/inline-provenance.js +12 -5
- package/dist/compat/eigenpal.d.ts +2 -1
- package/dist/compat/eigenpal.js +2 -1
- package/dist/controller/canonicalClipboard.js +7 -1
- package/dist/controller/canonicalComments.d.ts +41 -0
- package/dist/controller/canonicalComments.js +152 -0
- package/dist/controller/canonicalComposition.d.ts +4 -0
- package/dist/controller/canonicalComposition.js +43 -11
- package/dist/controller/canonicalInlineProjection.d.ts +6 -1
- package/dist/controller/canonicalInlineProjection.js +86 -3
- package/dist/controller/canonicalInput.js +10 -1
- package/dist/controller/canonicalInputTimer.d.ts +10 -1
- package/dist/controller/canonicalInputTimer.js +24 -1
- package/dist/controller/canonicalPublicOperations.d.ts +2 -2
- package/dist/controller/canonicalPublicOperations.js +107 -15
- package/dist/controller/canonicalSelection.d.ts +18 -0
- package/dist/controller/canonicalSelection.js +32 -0
- package/dist/controller/canonicalSession.d.ts +3 -0
- package/dist/controller/canonicalSession.js +58 -24
- package/dist/controller/canonicalStoryEditor.d.ts +2 -0
- package/dist/controller/canonicalStoryEditor.js +20 -0
- package/dist/controller/folioEditor.js +13 -0
- package/dist/controller/headerFooterEditorManager.d.ts +1 -1
- package/dist/controller/headerFooterEditorManager.js +25 -11
- package/dist/controller/hiddenEditorApi.d.ts +13 -2
- package/dist/controller/hiddenEditorApi.js +4 -0
- package/dist/controller/hiddenEditorManager.d.ts +3 -1
- package/dist/controller/hiddenEditorManager.js +166 -13
- package/dist/controller/noteEditorManager.d.ts +1 -1
- package/dist/controller/noteEditorManager.js +28 -13
- package/dist/docx/builtInStyles.js +13 -6
- package/dist/docx/containerChildren.gen.d.ts +3 -1
- package/dist/docx/containerChildren.gen.js +33 -1
- package/dist/docx/fieldParser.js +14 -2
- package/dist/docx/hyperlinkParser.d.ts +1 -1
- package/dist/docx/hyperlinkParser.js +20 -1
- package/dist/docx/inlineWrapperContent.d.ts +4 -4
- package/dist/docx/inlineWrapperContent.js +4 -4
- package/dist/docx/linkedSdtPreservation.d.ts +10 -0
- package/dist/docx/linkedSdtPreservation.js +37 -0
- package/dist/docx/paragraphParser.js +88 -67
- package/dist/docx/paragraphPropertySource.d.ts +22 -1
- package/dist/docx/paragraphPropertySource.js +107 -1
- package/dist/docx/preservedRunContent.js +2 -1
- package/dist/docx/relsParser.js +26 -2
- package/dist/docx/rezip.js +9 -6
- package/dist/docx/selectiveSave.js +10 -8
- package/dist/docx/serializer/commentSerializer.d.ts +4 -1
- package/dist/docx/serializer/commentSerializer.js +7 -3
- package/dist/docx/serializer/paragraphSerializer.js +207 -94
- package/dist/docx/server/materializeYjsDocx.js +14 -6
- package/dist/docx/server/migrateYjsAttrSchema.js +17 -5
- package/dist/i18n/messages/ar.gen.js +4 -0
- package/dist/i18n/messages/catalogs.gen.d.ts +68 -0
- package/dist/i18n/messages/catalogs.gen.js +68 -0
- package/dist/i18n/messages/cs.gen.js +4 -0
- package/dist/i18n/messages/de.gen.js +4 -0
- package/dist/i18n/messages/en.gen.js +4 -0
- package/dist/i18n/messages/es.gen.js +4 -0
- package/dist/i18n/messages/et.gen.js +4 -0
- package/dist/i18n/messages/fr.gen.js +4 -0
- package/dist/i18n/messages/he.gen.js +4 -0
- package/dist/i18n/messages/hi.gen.js +4 -0
- package/dist/i18n/messages/hu.gen.js +4 -0
- package/dist/i18n/messages/lt.gen.js +4 -0
- package/dist/i18n/messages/lv.gen.js +4 -0
- package/dist/i18n/messages/messages.gen.d.ts +4 -0
- package/dist/i18n/messages/pl.gen.js +4 -0
- package/dist/i18n/messages/pt-BR.gen.js +4 -0
- package/dist/i18n/messages/sk.gen.js +4 -0
- package/dist/i18n/messages/tr.gen.js +4 -0
- package/dist/i18n/messages/zh-CN.gen.js +4 -0
- package/dist/index.d.ts +2 -1
- package/dist/index.js +2 -1
- package/dist/internal/revisionResolutionInline.js +25 -3
- package/dist/markdown/renderRuns.js +1 -11
- package/dist/panel-layout.d.ts +11 -9
- package/dist/panel-layout.js +13 -9
- package/dist/prosemirror/addTrackedDeletionMark.d.ts +18 -0
- package/dist/prosemirror/addTrackedDeletionMark.js +87 -0
- package/dist/prosemirror/attrs/index.js +5 -0
- package/dist/prosemirror/commands/comments.js +60 -35
- package/dist/prosemirror/commands/propertyChangeScope.js +3 -6
- package/dist/prosemirror/commands/resolveParagraphProperties.js +22 -13
- package/dist/prosemirror/commentOps.js +15 -1
- package/dist/prosemirror/conversion/fromProseDoc.js +22 -3
- package/dist/prosemirror/conversion/toProseDoc.js +119 -18
- package/dist/prosemirror/extensions/core/ParagraphExtension.js +22 -5
- package/dist/prosemirror/extensions/features/BaseKeymapExtension.js +74 -25
- package/dist/prosemirror/extensions/marks/FootnoteRefExtension.js +11 -0
- package/dist/prosemirror/extensions/marks/HyperlinkExtension.js +22 -14
- package/dist/prosemirror/extensions/marks/markUtils.js +8 -7
- package/dist/prosemirror/extensions/marks/noteReferenceDeletion.js +5 -2
- package/dist/prosemirror/fieldRepresentation.d.ts +8 -0
- package/dist/prosemirror/fieldRepresentation.js +18 -0
- package/dist/prosemirror/hyperlinkRemoval.d.ts +13 -1
- package/dist/prosemirror/hyperlinkRemoval.js +28 -9
- package/dist/prosemirror/listNumbering.js +11 -5
- package/dist/prosemirror/noteReferenceOccurrenceId.d.ts +5 -0
- package/dist/prosemirror/noteReferenceOccurrenceId.js +5 -0
- package/dist/prosemirror/noteReferenceOccurrences.d.ts +21 -0
- package/dist/prosemirror/noteReferenceOccurrences.js +185 -0
- package/dist/prosemirror/noteReferenceReview.js +14 -1
- package/dist/prosemirror/plugins/documentStyles.d.ts +4 -1
- package/dist/prosemirror/plugins/documentStyles.js +17 -10
- package/dist/prosemirror/plugins/suggestionMode.js +47 -49
- package/dist/prosemirror/preservedXmlReview.d.ts +6 -0
- package/dist/prosemirror/preservedXmlReview.js +35 -0
- package/dist/prosemirror/runFormattingFromMarks.js +2 -2
- package/dist/prosemirror/runFormattingReconciliation.js +5 -4
- package/dist/prosemirror/runPropertyChangeResolution.d.ts +8 -1
- package/dist/prosemirror/runPropertyChangeResolution.js +24 -2
- package/dist/prosemirror/runStyleFormatting.d.ts +3 -1
- package/dist/prosemirror/runStyleFormatting.js +3 -1
- package/dist/prosemirror/schema/marks.d.ts +1 -0
- package/dist/prosemirror/schema/nodes.d.ts +2 -0
- package/dist/prosemirror/styles/paragraphStyleCascade.js +4 -1
- package/dist/prosemirror/styles/resolvedStyleAttrs.d.ts +15 -15
- package/dist/prosemirror/styles/resolvedStyleAttrs.js +69 -28
- package/dist/prosemirror/textInput.d.ts +5 -1
- package/dist/prosemirror/textInput.js +3 -3
- package/dist/prosemirror/trackedRevisionPath.d.ts +5 -1
- package/dist/prosemirror/trackedRevisionPath.js +39 -1
- package/dist/prosemirror/validation.js +3 -5
- package/dist/prosemirror/yjsDocumentMetadata.d.ts +9 -3
- package/dist/prosemirror/yjsDocumentMetadata.js +37 -8
- package/dist/types/canonicalCapabilities.d.ts +6 -20
- package/dist/types/canonicalCapabilities.js +6 -20
- package/dist/types/canonicalComments.d.ts +51 -0
- package/dist/types/canonicalComments.js +0 -0
- package/dist/types/canonicalSections.d.ts +12 -0
- package/dist/types/canonicalSections.js +0 -0
- package/dist/utils/headingCollector.js +45 -4
- package/dist/utils/outlineDepth.d.ts +9 -0
- package/dist/utils/outlineDepth.js +9 -0
- package/package.json +2 -2
|
@@ -10,20 +10,25 @@ import { ensureBaseDirectionInState } from "../prosemirror/extensions/features/A
|
|
|
10
10
|
import { ensureParaIdsInDoc, ensureParaIdsInState } from "../prosemirror/extensions/features/ParaIdAllocatorExtension.js";
|
|
11
11
|
import { createParagraphChangeTrackerPlugin, markPackageChange } from "../prosemirror/extensions/features/ParagraphChangeTrackerExtension.js";
|
|
12
12
|
import { toggleMarkForAllScripts, toggleUnderlineMark } from "../prosemirror/extensions/marks/markUtils.js";
|
|
13
|
+
import { HyperlinkRemovalRefusal } from "../prosemirror/hyperlinkRemoval.js";
|
|
14
|
+
import { markNoteReferenceReplay, noteReferenceTransactionIssue } from "../prosemirror/noteReferenceOccurrences.js";
|
|
13
15
|
import { createDocumentNumberingPlugin } from "../prosemirror/plugins/documentNumbering.js";
|
|
14
|
-
import { createDocumentStylesPlugin } from "../prosemirror/plugins/documentStyles.js";
|
|
16
|
+
import { createDocumentStyleContextPlugin, createDocumentStylesPlugin } from "../prosemirror/plugins/documentStyles.js";
|
|
15
17
|
import { schema } from "../prosemirror/schema/index.js";
|
|
16
18
|
import { createTextInputPlugin } from "../prosemirror/textInput.js";
|
|
17
19
|
import { applyAttrSchemaMigrations, proseDocumentParagraphSourceContract, readYjsAttrSchemaVersion, readYjsParagraphSourceContract, withParagraphSourceContract, writeYjsDocumentMetadata } from "../prosemirror/yjsDocumentMetadata.js";
|
|
18
20
|
import { CANONICAL_GAP, usesCanonicalSession } from "../types/canonicalCapabilities.js";
|
|
19
21
|
import { prepareCanonicalPaste } from "./canonicalClipboard.js";
|
|
22
|
+
import { canonicalCommentBody, compileCanonicalComments } from "./canonicalComments.js";
|
|
20
23
|
import { createCanonicalInputBoundary } from "./canonicalInput.js";
|
|
24
|
+
import { createCanonicalSectionPropertiesOperation } from "./canonicalOperations.js";
|
|
21
25
|
import { CanonicalPublicOperations } from "./canonicalPublicOperations.js";
|
|
26
|
+
import { restoreCanonicalSelection } from "./canonicalSelection.js";
|
|
22
27
|
import { createCanonicalSession, publishCanonicalProjection } from "./canonicalSession.js";
|
|
23
28
|
import { prepareCanonicalAutoformat, prepareCanonicalCommands } from "./canonicalStructure.js";
|
|
24
29
|
import { createHiddenEditorApi } from "./hiddenEditorApi.js";
|
|
25
30
|
import { Result, TaggedError, panic } from "better-result";
|
|
26
|
-
import { OP_STORIES } from "@stll/docx-core/ops";
|
|
31
|
+
import { OP_STORIES, freshCommentId } from "@stll/docx-core/ops";
|
|
27
32
|
import { EditorState, Plugin } from "prosemirror-state";
|
|
28
33
|
import { EditorView } from "prosemirror-view";
|
|
29
34
|
//#region src/controller/hiddenEditorManager.ts
|
|
@@ -206,6 +211,7 @@ const createHiddenEditorManager = (deps) => {
|
|
|
206
211
|
let view = null;
|
|
207
212
|
let releaseCommandOwner;
|
|
208
213
|
let editorSession = { type: "prosemirror" };
|
|
214
|
+
let canonicalSessionEpoch = 0;
|
|
209
215
|
let modeOverride = null;
|
|
210
216
|
const syncCanonicalMode = () => {
|
|
211
217
|
if (editorSession.type !== "canonical") return;
|
|
@@ -253,6 +259,7 @@ const createHiddenEditorManager = (deps) => {
|
|
|
253
259
|
type: "canonical",
|
|
254
260
|
session: result.value
|
|
255
261
|
};
|
|
262
|
+
canonicalSessionEpoch += 1;
|
|
256
263
|
modeOverride = null;
|
|
257
264
|
syncCanonicalMode();
|
|
258
265
|
return true;
|
|
@@ -261,7 +268,7 @@ const createHiddenEditorManager = (deps) => {
|
|
|
261
268
|
doc: session.projection.doc,
|
|
262
269
|
plugins: [
|
|
263
270
|
createParagraphChangeTrackerPlugin(),
|
|
264
|
-
|
|
271
|
+
createDocumentStyleContextPlugin(deps.getStyles() ?? session.document.package.styles),
|
|
265
272
|
createDocumentNumberingPlugin(session.document.package.numbering),
|
|
266
273
|
...[...deps.getExtensionManager()?.getPlugins() ?? [], ...deps.getExternalPlugins()].flatMap(({ props }) => props.transformPastedHTML === void 0 && props.transformPasted === void 0 && props.transformCopied === void 0 && props.clipboardTextSerializer === void 0 ? [] : [new Plugin({ props: {
|
|
267
274
|
...props.transformCopied === void 0 ? {} : { transformCopied: props.transformCopied },
|
|
@@ -271,7 +278,7 @@ const createHiddenEditorManager = (deps) => {
|
|
|
271
278
|
} })])
|
|
272
279
|
]
|
|
273
280
|
});
|
|
274
|
-
const publishCommit = (commit) => {
|
|
281
|
+
const publishCommit = (commit, reportRefusal = refuse) => {
|
|
275
282
|
if (!view || deps.getReadOnly() || editorSession.type !== "canonical") return false;
|
|
276
283
|
const session = editorSession.session;
|
|
277
284
|
const result = publishCanonicalProjection({
|
|
@@ -280,7 +287,7 @@ const createHiddenEditorManager = (deps) => {
|
|
|
280
287
|
session
|
|
281
288
|
});
|
|
282
289
|
if (result.isErr()) {
|
|
283
|
-
|
|
290
|
+
reportRefusal(result.error.message, result.error.gap);
|
|
284
291
|
return false;
|
|
285
292
|
}
|
|
286
293
|
const staged = result.value;
|
|
@@ -312,7 +319,21 @@ const createHiddenEditorManager = (deps) => {
|
|
|
312
319
|
refuse("Composition must finish before formatting.");
|
|
313
320
|
return false;
|
|
314
321
|
}
|
|
315
|
-
const
|
|
322
|
+
const commandState = view.state;
|
|
323
|
+
const described = Result.try({
|
|
324
|
+
try: () => getCanonicalCommandIntents(command, commandState),
|
|
325
|
+
catch: (error) => error
|
|
326
|
+
});
|
|
327
|
+
if (described.isErr()) {
|
|
328
|
+
if (!(described.error instanceof HyperlinkRemovalRefusal)) throw described.error;
|
|
329
|
+
const refusal = new CanonicalSessionRefusalError({
|
|
330
|
+
gap: CANONICAL_GAP.commands,
|
|
331
|
+
message: described.error.message
|
|
332
|
+
});
|
|
333
|
+
refuse(refusal.message, refusal.gap);
|
|
334
|
+
return false;
|
|
335
|
+
}
|
|
336
|
+
const intents = described.value;
|
|
316
337
|
if (intents === void 0) return void 0;
|
|
317
338
|
syncCanonicalMode();
|
|
318
339
|
editorSession.session.breakUndoGroup();
|
|
@@ -568,7 +589,11 @@ const createHiddenEditorManager = (deps) => {
|
|
|
568
589
|
lastInputRule = void 0;
|
|
569
590
|
editorSession.session.breakUndoGroup();
|
|
570
591
|
}
|
|
592
|
+
const modules = deps.getCollaborationModules();
|
|
593
|
+
if (modules && transaction.getMeta(modules.yProseMirror.ySyncPluginKey) !== void 0) markNoteReferenceReplay(transaction);
|
|
571
594
|
const applied = view.state.applyTransaction(transaction);
|
|
595
|
+
const noteIssue = noteReferenceTransactionIssue(transaction);
|
|
596
|
+
if (noteIssue) deps.onSessionRefusal?.(noteIssue.message, CANONICAL_GAP.dispatch, noteIssue);
|
|
572
597
|
if (editorSession.type === "canonical" && !applied.state.doc.eq(view.state.doc)) {
|
|
573
598
|
refuse("A plugin attempted an unclassified canonical document mutation.");
|
|
574
599
|
return;
|
|
@@ -751,14 +776,15 @@ const createHiddenEditorManager = (deps) => {
|
|
|
751
776
|
};
|
|
752
777
|
const syncExternalDocument = () => {
|
|
753
778
|
if (!view || isDestroying) return;
|
|
779
|
+
const canonicalRequested = usesCanonicalSession(deps.getExperimentalSession?.(), CANONICAL_GAP.authorityRouting);
|
|
754
780
|
const collaboration = deps.getCollaboration();
|
|
755
781
|
const collaborationModules = deps.getCollaborationModules();
|
|
756
|
-
if (collaboration && !collaborationModules && !
|
|
782
|
+
if (collaboration && !collaborationModules && !canonicalRequested) return;
|
|
757
783
|
const document = deps.getDocument();
|
|
758
784
|
const currentDocId = deps.getDocumentIdentity();
|
|
759
785
|
const currentCollaborationFragment = collaboration?.yXmlFragment ?? null;
|
|
760
786
|
const collaborationSourceChanged = currentCollaborationFragment !== lastCollaborationFragment;
|
|
761
|
-
const sessionChanged = editorSession.type !== "prosemirror" !==
|
|
787
|
+
const sessionChanged = editorSession.type !== "prosemirror" !== canonicalRequested;
|
|
762
788
|
if (collaboration && !collaborationSourceChanged && !sessionChanged) return;
|
|
763
789
|
if (isInitialized && currentDocId === lastDocumentId && !collaborationSourceChanged && !sessionChanged) return;
|
|
764
790
|
input.reset();
|
|
@@ -790,13 +816,20 @@ const createHiddenEditorManager = (deps) => {
|
|
|
790
816
|
};
|
|
791
817
|
const publishStoryCommit = (storyView, commit) => {
|
|
792
818
|
if (!view || editorSession.type !== "canonical") return false;
|
|
793
|
-
if (deps.getEditingMode?.() === "suggesting") {
|
|
794
|
-
refuse("Suggesting is unavailable in the experimental canonical session.", CANONICAL_GAP.suggesting);
|
|
795
|
-
return false;
|
|
796
|
-
}
|
|
797
819
|
const session = editorSession.session;
|
|
798
820
|
const bodyTransaction = view.state.tr;
|
|
799
821
|
if (!bodyTransaction.doc.eq(commit.bodyProjection.doc)) bodyTransaction.replaceWith(0, bodyTransaction.doc.content.size, commit.bodyProjection.doc.content);
|
|
822
|
+
if (commit.selection.anchor.story === OP_STORIES.MAIN && commit.selection.head.story === OP_STORIES.MAIN) {
|
|
823
|
+
if (!restoreCanonicalSelection({
|
|
824
|
+
transaction: bodyTransaction,
|
|
825
|
+
projection: commit.bodyProjection,
|
|
826
|
+
selection: commit.selection,
|
|
827
|
+
unavailable: { type: "refuse" }
|
|
828
|
+
})) {
|
|
829
|
+
refuse("The canonical body history selection is unavailable.");
|
|
830
|
+
return false;
|
|
831
|
+
}
|
|
832
|
+
}
|
|
800
833
|
markPackageChange(bodyTransaction);
|
|
801
834
|
bodyTransaction.setMeta("addToHistory", false);
|
|
802
835
|
const bodyStaged = Result.try(() => view?.state.applyTransaction(bodyTransaction));
|
|
@@ -839,6 +872,7 @@ const createHiddenEditorManager = (deps) => {
|
|
|
839
872
|
};
|
|
840
873
|
return executor;
|
|
841
874
|
};
|
|
875
|
+
const isCanonicalModelSessionRequested = () => usesCanonicalSession(deps.getExperimentalSession?.(), CANONICAL_GAP.authorityRouting);
|
|
842
876
|
return {
|
|
843
877
|
ensureView,
|
|
844
878
|
retryViewCreation,
|
|
@@ -851,6 +885,8 @@ const createHiddenEditorManager = (deps) => {
|
|
|
851
885
|
api: createHiddenEditorApi({
|
|
852
886
|
getView: () => view,
|
|
853
887
|
getDocumentContext: () => editorSession.type === "refused" ? null : deps.getDocumentContext(),
|
|
888
|
+
getCanonicalComments: () => editorSession.type === "canonical" ? editorSession.session.getCommittedComments() : null,
|
|
889
|
+
getCanonicalCommittedVersion: () => editorSession.type === "canonical" ? `${canonicalSessionEpoch}:${editorSession.session.version}` : null,
|
|
854
890
|
isCanonicalSaveCurrent: (version) => editorSession.type === "canonical" && !editorSession.session.isComposing && editorSession.session.version === version,
|
|
855
891
|
captureCanonicalSave: () => editorSession.type === "canonical" ? editorSession.session.captureSaveSnapshot() : null,
|
|
856
892
|
getCanonicalDocument: () => editorSession.type === "canonical" ? editorSession.session.document : null,
|
|
@@ -880,6 +916,120 @@ const createHiddenEditorManager = (deps) => {
|
|
|
880
916
|
canRedo: () => editorSession.type === "canonical" && editorSession.session.canRedo
|
|
881
917
|
} : null,
|
|
882
918
|
canonicalOperations: {
|
|
919
|
+
applyCanonicalSectionProperties: (patch) => {
|
|
920
|
+
ensureView();
|
|
921
|
+
const fail = (message) => {
|
|
922
|
+
refuse(message, CANONICAL_GAP.sectionProperties);
|
|
923
|
+
return {
|
|
924
|
+
status: "refused",
|
|
925
|
+
gap: CANONICAL_GAP.sectionProperties,
|
|
926
|
+
message
|
|
927
|
+
};
|
|
928
|
+
};
|
|
929
|
+
if (editorSession.type === "refused") return fail(editorSession.reason);
|
|
930
|
+
if (editorSession.type !== "canonical") {
|
|
931
|
+
if (isCanonicalModelSessionRequested()) return fail("The canonical document is not ready for section changes.");
|
|
932
|
+
return null;
|
|
933
|
+
}
|
|
934
|
+
if (!view || deps.getReadOnly() || isDestroying) return fail("The document is not editable.");
|
|
935
|
+
const session = editorSession.session;
|
|
936
|
+
if (session.isComposing) return fail("Section properties cannot change during composition.");
|
|
937
|
+
const prepared = session.prepareOperations(view.state, [createCanonicalSectionPropertiesOperation(session.document, patch)]);
|
|
938
|
+
if (prepared.isErr()) return fail(prepared.error.message);
|
|
939
|
+
let failureMessage = "The section projection could not publish.";
|
|
940
|
+
if (!publishCommit(prepared.value, (message) => {
|
|
941
|
+
failureMessage = message;
|
|
942
|
+
})) return fail(failureMessage);
|
|
943
|
+
return {
|
|
944
|
+
status: "applied",
|
|
945
|
+
version: session.version
|
|
946
|
+
};
|
|
947
|
+
},
|
|
948
|
+
applyCanonicalComment: (request) => {
|
|
949
|
+
ensureView();
|
|
950
|
+
const fail = (message, retry = "never") => {
|
|
951
|
+
if (retry === "never") refuse(message, CANONICAL_GAP.comments);
|
|
952
|
+
return {
|
|
953
|
+
status: "refused",
|
|
954
|
+
gap: CANONICAL_GAP.comments,
|
|
955
|
+
message,
|
|
956
|
+
retry
|
|
957
|
+
};
|
|
958
|
+
};
|
|
959
|
+
if (editorSession.type === "refused") return fail(editorSession.reason);
|
|
960
|
+
if (editorSession.type !== "canonical") {
|
|
961
|
+
if (isCanonicalModelSessionRequested()) return fail("The canonical document is not ready for comment changes.");
|
|
962
|
+
return null;
|
|
963
|
+
}
|
|
964
|
+
if (!view || deps.getReadOnly()) return fail("The document is not editable.");
|
|
965
|
+
const session = editorSession.session;
|
|
966
|
+
if (session.isComposing) return fail("Comments cannot change during composition.", "afterComposition");
|
|
967
|
+
let command;
|
|
968
|
+
if (request.type === "create") {
|
|
969
|
+
const id = freshCommentId(session.document);
|
|
970
|
+
if (id.isErr()) return fail(id.error.message);
|
|
971
|
+
let anchor;
|
|
972
|
+
switch (request.anchor.kind) {
|
|
973
|
+
case "selection": {
|
|
974
|
+
const projection = session.projectStory(request.anchor.story);
|
|
975
|
+
if (projection.isErr()) return fail(projection.error.message);
|
|
976
|
+
const from = projection.value.addressAt(request.anchor.from);
|
|
977
|
+
const to = projection.value.addressAt(request.anchor.to);
|
|
978
|
+
if (from.isErr()) return fail(from.error.message);
|
|
979
|
+
if (to.isErr()) return fail(to.error.message);
|
|
980
|
+
anchor = request.anchor.from === request.anchor.to ? {
|
|
981
|
+
kind: "point",
|
|
982
|
+
at: from.value
|
|
983
|
+
} : {
|
|
984
|
+
kind: "range",
|
|
985
|
+
from: from.value,
|
|
986
|
+
to: to.value
|
|
987
|
+
};
|
|
988
|
+
break;
|
|
989
|
+
}
|
|
990
|
+
case "reply":
|
|
991
|
+
anchor = {
|
|
992
|
+
kind: "reply",
|
|
993
|
+
parentId: request.anchor.parentId
|
|
994
|
+
};
|
|
995
|
+
break;
|
|
996
|
+
case "revision":
|
|
997
|
+
anchor = {
|
|
998
|
+
kind: "revision",
|
|
999
|
+
story: request.anchor.story,
|
|
1000
|
+
revisionId: request.anchor.revisionId
|
|
1001
|
+
};
|
|
1002
|
+
break;
|
|
1003
|
+
default: return request.anchor;
|
|
1004
|
+
}
|
|
1005
|
+
command = {
|
|
1006
|
+
type: "create",
|
|
1007
|
+
anchor,
|
|
1008
|
+
comment: {
|
|
1009
|
+
id: id.value,
|
|
1010
|
+
author: request.author,
|
|
1011
|
+
done: false,
|
|
1012
|
+
date: request.date ?? (/* @__PURE__ */ new Date()).toISOString(),
|
|
1013
|
+
content: canonicalCommentBody(session.document, request.text)
|
|
1014
|
+
}
|
|
1015
|
+
};
|
|
1016
|
+
} else command = request;
|
|
1017
|
+
const compiled = compileCanonicalComments({
|
|
1018
|
+
document: session.document,
|
|
1019
|
+
command
|
|
1020
|
+
});
|
|
1021
|
+
if (compiled.isErr()) return fail(compiled.error.message);
|
|
1022
|
+
if (compiled.value.ops.length > 0) {
|
|
1023
|
+
const prepared = session.prepareOperations(view.state, compiled.value.ops);
|
|
1024
|
+
if (prepared.isErr()) return fail(prepared.error.message);
|
|
1025
|
+
if (!publishCommit(prepared.value)) return fail("The comment projection could not publish.");
|
|
1026
|
+
}
|
|
1027
|
+
return {
|
|
1028
|
+
status: "applied",
|
|
1029
|
+
comments: session.getCommittedComments(),
|
|
1030
|
+
...compiled.value.commentId === void 0 ? {} : { commentId: compiled.value.commentId }
|
|
1031
|
+
};
|
|
1032
|
+
},
|
|
883
1033
|
applyCanonicalDocumentOperations: (options) => {
|
|
884
1034
|
ensureView();
|
|
885
1035
|
return getPublicOperations()?.apply(options) ?? null;
|
|
@@ -914,6 +1064,7 @@ const createHiddenEditorManager = (deps) => {
|
|
|
914
1064
|
applyCanonicalStoryHistory: ({ view: storyView, story, direction }) => {
|
|
915
1065
|
if (story === OP_STORIES.MAIN && storyView === view) return history(direction);
|
|
916
1066
|
if (!view || editorSession.type !== "canonical" || deps.getReadOnly()) return false;
|
|
1067
|
+
syncCanonicalMode();
|
|
917
1068
|
const session = editorSession.session;
|
|
918
1069
|
if (direction === "undo" ? !session.canUndo : !session.canRedo) return false;
|
|
919
1070
|
const prepared = direction === "undo" ? session.prepareUndo(storyView.state, story) : session.prepareRedo(storyView.state, story);
|
|
@@ -945,6 +1096,7 @@ const createHiddenEditorManager = (deps) => {
|
|
|
945
1096
|
},
|
|
946
1097
|
replaceCanonicalStoryText: ({ view: storyView, story, intent }) => {
|
|
947
1098
|
if (!view || editorSession.type !== "canonical" || deps.getReadOnly()) return false;
|
|
1099
|
+
syncCanonicalMode();
|
|
948
1100
|
const prepared = editorSession.session.prepareReplace(storyView.state, {
|
|
949
1101
|
...intent,
|
|
950
1102
|
story
|
|
@@ -959,7 +1111,8 @@ const createHiddenEditorManager = (deps) => {
|
|
|
959
1111
|
isDestroying: () => isDestroying,
|
|
960
1112
|
ensureView,
|
|
961
1113
|
isViewRequested
|
|
962
|
-
})
|
|
1114
|
+
}),
|
|
1115
|
+
isCanonicalComposing: () => editorSession.type === "canonical" && editorSession.session.isComposing
|
|
963
1116
|
};
|
|
964
1117
|
};
|
|
965
1118
|
//#endregion
|
|
@@ -16,7 +16,7 @@ type NoteEditorManagerDeps = {
|
|
|
16
16
|
getDocument: () => document_d_exports.Document | null;
|
|
17
17
|
getCanonicalApi?: (() => HiddenEditorApi | null) | undefined;
|
|
18
18
|
getExperimentalSession?: (() => "canonical" | undefined) | undefined;
|
|
19
|
-
onSessionRefusal?: ((reason: string, gap: CanonicalGap) => void) | undefined;
|
|
19
|
+
onSessionRefusal?: ((reason: string, gap: CanonicalGap, error?: Error) => void) | undefined;
|
|
20
20
|
getHost: () => HTMLElement | null;
|
|
21
21
|
getPlugins?: (() => Plugin[]) | undefined;
|
|
22
22
|
getStyles: () => document_d_exports.StyleDefinitions | null | undefined;
|
|
@@ -7,11 +7,13 @@ import { ExtensionManager } from "../prosemirror/extensions/ExtensionManager.js"
|
|
|
7
7
|
import { createStarterKit } from "../prosemirror/extensions/StarterKit.js";
|
|
8
8
|
import { ensureBaseDirectionInState } from "../prosemirror/extensions/features/AutoBidiDetectionExtension.js";
|
|
9
9
|
import { ensureParaIdsInState } from "../prosemirror/extensions/features/ParaIdAllocatorExtension.js";
|
|
10
|
+
import { noteReferenceTransactionIssue } from "../prosemirror/noteReferenceOccurrences.js";
|
|
10
11
|
import { createDocumentNumberingPlugin } from "../prosemirror/plugins/documentNumbering.js";
|
|
11
|
-
import { createDocumentStylesPlugin } from "../prosemirror/plugins/documentStyles.js";
|
|
12
|
+
import { createDocumentStyleContextPlugin, createDocumentStylesPlugin } from "../prosemirror/plugins/documentStyles.js";
|
|
12
13
|
import { schema } from "../prosemirror/schema/index.js";
|
|
13
14
|
import { storyListNumbering } from "../prosemirror/storyListNumbering.js";
|
|
14
15
|
import { CANONICAL_GAP, usesCanonicalSession } from "../types/canonicalCapabilities.js";
|
|
16
|
+
import { CanonicalSessionError } from "./canonicalSession.js";
|
|
15
17
|
import { createCanonicalStoryEditor } from "./canonicalStoryEditor.js";
|
|
16
18
|
import { OP_STORIES } from "@stll/docx-core/ops";
|
|
17
19
|
import { EditorState, TextSelection } from "prosemirror-state";
|
|
@@ -88,11 +90,12 @@ const createNoteEditorManager = (deps) => {
|
|
|
88
90
|
mounted.clear();
|
|
89
91
|
active = null;
|
|
90
92
|
};
|
|
93
|
+
const getOwnedDocument = () => usesCanonicalSession(deps.getExperimentalSession?.(), CANONICAL_GAP.authorityRouting) ? deps.getCanonicalApi?.()?.getCanonicalDocument() ?? null : deps.getDocument();
|
|
91
94
|
const sync = () => {
|
|
92
95
|
const host = deps.getHost();
|
|
93
96
|
if (!host) return;
|
|
94
|
-
if (usesCanonicalSession(deps.getExperimentalSession?.(), CANONICAL_GAP.
|
|
95
|
-
const document =
|
|
97
|
+
if (usesCanonicalSession(deps.getExperimentalSession?.(), CANONICAL_GAP.authorityRouting) && !deps.getCanonicalApi?.()?.getCanonicalStoryProjection(OP_STORIES.MAIN)) return;
|
|
98
|
+
const document = getOwnedDocument();
|
|
96
99
|
const styles = deps.getStyles();
|
|
97
100
|
const theme = deps.getTheme();
|
|
98
101
|
const numbering = document?.package.numbering;
|
|
@@ -116,7 +119,7 @@ const createNoteEditorManager = (deps) => {
|
|
|
116
119
|
const existing = mounted.get(key);
|
|
117
120
|
if (existing) {
|
|
118
121
|
if (existing.mountNode.parentElement !== host) host.append(existing.mountNode);
|
|
119
|
-
if (usesCanonicalSession(deps.getExperimentalSession?.(), CANONICAL_GAP.
|
|
122
|
+
if (usesCanonicalSession(deps.getExperimentalSession?.(), CANONICAL_GAP.authorityRouting)) {
|
|
120
123
|
const projected = deps.getCanonicalApi?.()?.getCanonicalStoryProjection({
|
|
121
124
|
kind: storyKey.kind,
|
|
122
125
|
id: storyKey.noteId
|
|
@@ -176,7 +179,7 @@ const createNoteEditorManager = (deps) => {
|
|
|
176
179
|
},
|
|
177
180
|
getView: () => view,
|
|
178
181
|
getApi: () => deps.getCanonicalApi?.() ?? null,
|
|
179
|
-
enabled: () => usesCanonicalSession(deps.getExperimentalSession?.(), CANONICAL_GAP.
|
|
182
|
+
enabled: () => usesCanonicalSession(deps.getExperimentalSession?.(), CANONICAL_GAP.authorityRouting),
|
|
180
183
|
onRefusal: deps.onSessionRefusal,
|
|
181
184
|
onSelectionChange: () => deps.onTransaction?.({
|
|
182
185
|
...storyKey,
|
|
@@ -185,11 +188,11 @@ const createNoteEditorManager = (deps) => {
|
|
|
185
188
|
selectionChanged: true
|
|
186
189
|
})
|
|
187
190
|
});
|
|
188
|
-
const canonicalProjection = usesCanonicalSession(deps.getExperimentalSession?.(), CANONICAL_GAP.
|
|
191
|
+
const canonicalProjection = usesCanonicalSession(deps.getExperimentalSession?.(), CANONICAL_GAP.authorityRouting) ? deps.getCanonicalApi?.()?.getCanonicalStoryProjection({
|
|
189
192
|
kind: storyKey.kind,
|
|
190
193
|
id: storyKey.noteId
|
|
191
194
|
}) : null;
|
|
192
|
-
if (usesCanonicalSession(deps.getExperimentalSession?.(), CANONICAL_GAP.
|
|
195
|
+
if (usesCanonicalSession(deps.getExperimentalSession?.(), CANONICAL_GAP.authorityRouting) && !canonicalProjection) {
|
|
193
196
|
manager.destroy();
|
|
194
197
|
mountNode.remove();
|
|
195
198
|
continue;
|
|
@@ -198,16 +201,20 @@ const createNoteEditorManager = (deps) => {
|
|
|
198
201
|
...canonical.props,
|
|
199
202
|
state: canonicalProjection ? EditorState.create({
|
|
200
203
|
doc: canonicalProjection,
|
|
201
|
-
plugins: [
|
|
204
|
+
plugins: [createDocumentStyleContextPlugin(styles), createDocumentNumberingPlugin(numbering)]
|
|
202
205
|
}) : buildInitialState(proseDocument, styles, numbering, manager, externalPlugins),
|
|
203
206
|
dispatchTransaction(transaction) {
|
|
204
207
|
if (canonical.dispatch(transaction)) return;
|
|
205
|
-
view.
|
|
208
|
+
const nextState = view.state.apply(transaction);
|
|
209
|
+
const docChanged = !nextState.doc.eq(view.state.doc);
|
|
210
|
+
view.updateState(nextState);
|
|
211
|
+
const noteIssue = noteReferenceTransactionIssue(transaction);
|
|
212
|
+
if (noteIssue) deps.onSessionRefusal?.(noteIssue.message, CANONICAL_GAP.dispatch, noteIssue);
|
|
206
213
|
const mountedStory = mounted.get(key);
|
|
207
|
-
if (mountedStory &&
|
|
214
|
+
if (mountedStory && docChanged) mountedStory.dirty = true;
|
|
208
215
|
deps.onTransaction?.({
|
|
209
216
|
...storyKey,
|
|
210
|
-
docChanged
|
|
217
|
+
docChanged,
|
|
211
218
|
selectionChanged: transaction.selectionSet,
|
|
212
219
|
view
|
|
213
220
|
});
|
|
@@ -245,9 +252,17 @@ const createNoteEditorManager = (deps) => {
|
|
|
245
252
|
destroy,
|
|
246
253
|
getActive: () => active,
|
|
247
254
|
getView: (story) => mounted.get(storyMapKey(story))?.view ?? null,
|
|
248
|
-
listStories: () => enumerateDocumentNoteStories(
|
|
255
|
+
listStories: () => enumerateDocumentNoteStories(getOwnedDocument()),
|
|
249
256
|
snapshotDocument: (document) => {
|
|
250
|
-
if (usesCanonicalSession(deps.getExperimentalSession?.(), CANONICAL_GAP.
|
|
257
|
+
if (usesCanonicalSession(deps.getExperimentalSession?.(), CANONICAL_GAP.authorityRouting)) {
|
|
258
|
+
const canonical = deps.getCanonicalApi?.()?.getCanonicalDocument();
|
|
259
|
+
if (canonical) return canonical;
|
|
260
|
+
throw new CanonicalSessionError({
|
|
261
|
+
gap: CANONICAL_GAP.authorityRouting,
|
|
262
|
+
reason: "refused",
|
|
263
|
+
message: "Canonical story snapshot is unavailable."
|
|
264
|
+
});
|
|
265
|
+
}
|
|
251
266
|
let footnotes = document.package.footnotes;
|
|
252
267
|
let endnotes = document.package.endnotes;
|
|
253
268
|
let footnotesChanged = false;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { BUILT_IN_DEFAULT_PARAGRAPH_STYLE_NAME, resolveDefaultParagraphStyle } from "./defaultParagraphStyle.js";
|
|
2
|
-
import { headingLevelOf } from "@stll/docx-core/model";
|
|
2
|
+
import { headingLevelOf, headingOutlineLevel } from "@stll/docx-core/model";
|
|
3
3
|
//#region src/docx/builtInStyles.ts
|
|
4
4
|
/**
|
|
5
5
|
* Whether a paragraph is a heading, and of which level, without reading the
|
|
@@ -134,20 +134,27 @@ const headingOutlineLevelFromStyleName = (name) => {
|
|
|
134
134
|
const CANONICAL_BY_NORMALIZED = new Map(Object.values(BUILT_IN_STYLE_NAME).map((name) => [normalizeStyleName(name), name]));
|
|
135
135
|
const asBuiltInName = (normalized) => CANONICAL_BY_NORMALIZED.get(normalized);
|
|
136
136
|
/**
|
|
137
|
-
* The outline
|
|
138
|
-
* the
|
|
139
|
-
*
|
|
140
|
-
*
|
|
141
|
-
*
|
|
137
|
+
* The effective outline contribution of a style chain: the nearest explicit
|
|
138
|
+
* `w:outlineLvl` wins across the chain; only when none exists does the nearest
|
|
139
|
+
* built-in heading name supply its implicit level. `styleParser` already flattens
|
|
140
|
+
* `w:basedOn` for a parsed package, but a style set built in memory carries the
|
|
141
|
+
* raw chain, so the walk keeps both kinds of input on the same answer. `seen`
|
|
142
|
+
* guards the circular `basedOn` a malformed package can contain.
|
|
142
143
|
*/
|
|
143
144
|
const inheritedOutlineLevel = (style, styleById) => {
|
|
144
145
|
const seen = /* @__PURE__ */ new Set();
|
|
145
146
|
let current = style;
|
|
147
|
+
let nearestImplicitHeadingLevel;
|
|
146
148
|
while (current && !seen.has(current.styleId)) {
|
|
147
149
|
seen.add(current.styleId);
|
|
148
150
|
if (current.pPr?.outlineLevel !== void 0) return current.pPr.outlineLevel;
|
|
151
|
+
if (nearestImplicitHeadingLevel === void 0) {
|
|
152
|
+
const namedLevel = headingOutlineLevelFromStyleName(current.name);
|
|
153
|
+
if (namedLevel !== void 0) nearestImplicitHeadingLevel = headingOutlineLevel(namedLevel);
|
|
154
|
+
}
|
|
149
155
|
current = current.basedOn === void 0 ? void 0 : styleById.get(current.basedOn);
|
|
150
156
|
}
|
|
157
|
+
return nearestImplicitHeadingLevel;
|
|
151
158
|
};
|
|
152
159
|
/** The level a heading style is indexed under, or undefined if it is not one. */
|
|
153
160
|
const headingLevelForIndex = (namedLevel, statedLevel) => {
|
|
@@ -35,9 +35,11 @@ declare const CONTAINER_CHILDREN: {
|
|
|
35
35
|
readonly "w:fldSimple": readonly ["bdo", "bookmarkEnd", "bookmarkStart", "commentRangeEnd", "commentRangeStart", "customXml", "customXmlDelRangeEnd", "customXmlDelRangeStart", "customXmlInsRangeEnd", "customXmlInsRangeStart", "customXmlMoveFromRangeEnd", "customXmlMoveFromRangeStart", "customXmlMoveToRangeEnd", "customXmlMoveToRangeStart", "del", "dir", "fldData", "fldSimple", "hyperlink", "ins", "moveFrom", "moveFromRangeEnd", "moveFromRangeStart", "moveTo", "moveToRangeEnd", "moveToRangeStart", "permEnd", "permStart", "proofErr", "r", "sdt", "smartTag", "subDoc"];
|
|
36
36
|
readonly "block-content": readonly ["altChunk", "bookmarkEnd", "bookmarkStart", "commentRangeEnd", "commentRangeStart", "customXml", "customXmlDelRangeEnd", "customXmlDelRangeStart", "customXmlInsRangeEnd", "customXmlInsRangeStart", "customXmlMoveFromRangeEnd", "customXmlMoveFromRangeStart", "customXmlMoveToRangeEnd", "customXmlMoveToRangeStart", "del", "ins", "moveFrom", "moveFromRangeEnd", "moveFromRangeStart", "moveTo", "moveToRangeEnd", "moveToRangeStart", "p", "permEnd", "permStart", "proofErr", "sdt", "sectPr", "tbl", "tcPr"];
|
|
37
37
|
};
|
|
38
|
+
/** WordprocessingML children permitted directly inside CT_RunTrackChange. */
|
|
39
|
+
declare const TRACKED_RUN_WORDPROCESSING_CHILDREN: readonly ["bdo", "bookmarkEnd", "bookmarkStart", "commentRangeEnd", "commentRangeStart", "customXml", "customXmlDelRangeEnd", "customXmlDelRangeStart", "customXmlInsRangeEnd", "customXmlInsRangeStart", "customXmlMoveFromRangeEnd", "customXmlMoveFromRangeStart", "customXmlMoveToRangeEnd", "customXmlMoveToRangeStart", "del", "dir", "ins", "moveFrom", "moveFromRangeEnd", "moveFromRangeStart", "moveTo", "moveToRangeEnd", "moveToRangeStart", "permEnd", "permStart", "proofErr", "r", "sdt", "smartTag"];
|
|
38
40
|
/** A container the shared child dispatcher covers. */
|
|
39
41
|
type DispatchedContainer = keyof typeof CONTAINER_CHILDREN;
|
|
40
42
|
/** Every child name the schema declares for `Container`. */
|
|
41
43
|
type DeclaredChild<Container extends DispatchedContainer> = (typeof CONTAINER_CHILDREN)[Container][number];
|
|
42
44
|
//#endregion
|
|
43
|
-
export { CONTAINER_CHILDREN, DeclaredChild, DispatchedContainer };
|
|
45
|
+
export { CONTAINER_CHILDREN, DeclaredChild, DispatchedContainer, TRACKED_RUN_WORDPROCESSING_CHILDREN };
|
|
@@ -260,5 +260,37 @@ const CONTAINER_CHILDREN = {
|
|
|
260
260
|
],
|
|
261
261
|
...SEQUENCE_CHILDREN
|
|
262
262
|
};
|
|
263
|
+
/** WordprocessingML children permitted directly inside CT_RunTrackChange. */
|
|
264
|
+
const TRACKED_RUN_WORDPROCESSING_CHILDREN = [
|
|
265
|
+
"bdo",
|
|
266
|
+
"bookmarkEnd",
|
|
267
|
+
"bookmarkStart",
|
|
268
|
+
"commentRangeEnd",
|
|
269
|
+
"commentRangeStart",
|
|
270
|
+
"customXml",
|
|
271
|
+
"customXmlDelRangeEnd",
|
|
272
|
+
"customXmlDelRangeStart",
|
|
273
|
+
"customXmlInsRangeEnd",
|
|
274
|
+
"customXmlInsRangeStart",
|
|
275
|
+
"customXmlMoveFromRangeEnd",
|
|
276
|
+
"customXmlMoveFromRangeStart",
|
|
277
|
+
"customXmlMoveToRangeEnd",
|
|
278
|
+
"customXmlMoveToRangeStart",
|
|
279
|
+
"del",
|
|
280
|
+
"dir",
|
|
281
|
+
"ins",
|
|
282
|
+
"moveFrom",
|
|
283
|
+
"moveFromRangeEnd",
|
|
284
|
+
"moveFromRangeStart",
|
|
285
|
+
"moveTo",
|
|
286
|
+
"moveToRangeEnd",
|
|
287
|
+
"moveToRangeStart",
|
|
288
|
+
"permEnd",
|
|
289
|
+
"permStart",
|
|
290
|
+
"proofErr",
|
|
291
|
+
"r",
|
|
292
|
+
"sdt",
|
|
293
|
+
"smartTag"
|
|
294
|
+
];
|
|
263
295
|
//#endregion
|
|
264
|
-
export { CONTAINER_CHILDREN };
|
|
296
|
+
export { CONTAINER_CHILDREN, TRACKED_RUN_WORDPROCESSING_CHILDREN };
|
package/dist/docx/fieldParser.js
CHANGED
|
@@ -231,8 +231,20 @@ function finalizeComplexField(ctx) {
|
|
|
231
231
|
* @returns The display text
|
|
232
232
|
*/
|
|
233
233
|
function getFieldDisplayValue(field) {
|
|
234
|
-
|
|
235
|
-
|
|
234
|
+
const displayText = (content) => content.map((child) => {
|
|
235
|
+
switch (child.type) {
|
|
236
|
+
case "run": return getRunText(child);
|
|
237
|
+
case "hyperlink": return displayText(child.children);
|
|
238
|
+
case "inlineWrapper":
|
|
239
|
+
case "insertion":
|
|
240
|
+
case "deletion":
|
|
241
|
+
case "moveFrom":
|
|
242
|
+
case "moveTo": return displayText(child.content);
|
|
243
|
+
case "preservedInline": return child.text;
|
|
244
|
+
default: return "";
|
|
245
|
+
}
|
|
246
|
+
}).join("");
|
|
247
|
+
return displayText(field.type === "simpleField" ? field.content : field.fieldResult);
|
|
236
248
|
}
|
|
237
249
|
/**
|
|
238
250
|
* Helper to get text from a run (simplified)
|
|
@@ -86,7 +86,7 @@ declare const HYPERLINK_CHILD_HANDLERS: {
|
|
|
86
86
|
readonly permEnd: "capture";
|
|
87
87
|
readonly permStart: "capture";
|
|
88
88
|
readonly proofErr: "capture";
|
|
89
|
-
readonly sdt:
|
|
89
|
+
readonly sdt: (child: XmlElement, { push }: HyperlinkChildContext) => void;
|
|
90
90
|
readonly subDoc: "capture";
|
|
91
91
|
};
|
|
92
92
|
/**
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { sanitizeExternalUrl } from "../utils/urlSecurity.js";
|
|
2
2
|
import { CAPTURE, dispatchChildrenWithContext, ownedElsewhere, withPreservedChildren } from "./containerChildren.js";
|
|
3
3
|
import { inlineWrapperOf } from "./inlineWrapperParser.js";
|
|
4
|
+
import { preserveLinkedSdt } from "./linkedSdtPreservation.js";
|
|
4
5
|
import { preserveInlineChild, preservedInlineCapture } from "./preservedRunContent.js";
|
|
5
6
|
import { standalonePreviewLedger } from "./previewBudget.js";
|
|
6
7
|
import { RELATIONSHIP_TYPES, resolveRelationshipIdOfType } from "./relsParser.js";
|
|
@@ -9,6 +10,22 @@ import { runHoldsPayload } from "./runPayload.js";
|
|
|
9
10
|
import { getAttribute, mergeXmlnsDeclarations, parseNumericAttribute, parseOnOffAttribute } from "./xmlParser.js";
|
|
10
11
|
//#region src/docx/hyperlinkParser.ts
|
|
11
12
|
/**
|
|
13
|
+
* Hyperlink Parser - Parse hyperlinks (w:hyperlink) with URL resolution
|
|
14
|
+
*
|
|
15
|
+
* OOXML Reference:
|
|
16
|
+
* - Hyperlink element: w:hyperlink
|
|
17
|
+
* - Attributes:
|
|
18
|
+
* - r:id - Relationship ID for external link (resolves via .rels)
|
|
19
|
+
* - w:anchor - Internal bookmark name
|
|
20
|
+
* - w:tooltip - Tooltip/title text
|
|
21
|
+
* - w:tgtFrame - Target frame (_blank, _self, etc.)
|
|
22
|
+
* - w:history - Whether to add to history
|
|
23
|
+
* - w:docLocation - Location within a document
|
|
24
|
+
*
|
|
25
|
+
* External links use r:id to reference a relationship in document.xml.rels
|
|
26
|
+
* Internal links use w:anchor to reference a bookmark in the same document
|
|
27
|
+
*/
|
|
28
|
+
/**
|
|
12
29
|
* Parse bookmark start (w:bookmarkStart)
|
|
13
30
|
*
|
|
14
31
|
* Used for internal hyperlink targets within the document.
|
|
@@ -169,7 +186,9 @@ const HYPERLINK_CHILD_HANDLERS = {
|
|
|
169
186
|
permEnd: CAPTURE,
|
|
170
187
|
permStart: CAPTURE,
|
|
171
188
|
proofErr: CAPTURE,
|
|
172
|
-
sdt:
|
|
189
|
+
sdt: (child, { push }) => {
|
|
190
|
+
push(preserveLinkedSdt(child));
|
|
191
|
+
},
|
|
173
192
|
subDoc: CAPTURE
|
|
174
193
|
};
|
|
175
194
|
const LINKED_SMART_TAG_PROPERTIES_OWNER = ownedElsewhere({
|
|
@@ -138,14 +138,14 @@ declare const SIMPLE_FIELD_CONTENT: {
|
|
|
138
138
|
readonly commentRangeStart: false;
|
|
139
139
|
readonly commentReference: false;
|
|
140
140
|
readonly complexField: false;
|
|
141
|
-
readonly deletion:
|
|
141
|
+
readonly deletion: true;
|
|
142
142
|
readonly inlineSdt: false;
|
|
143
|
-
readonly insertion:
|
|
143
|
+
readonly insertion: true;
|
|
144
144
|
readonly mathEquation: false;
|
|
145
|
-
readonly moveFrom:
|
|
145
|
+
readonly moveFrom: true;
|
|
146
146
|
readonly moveFromRangeEnd: false;
|
|
147
147
|
readonly moveFromRangeStart: false;
|
|
148
|
-
readonly moveTo:
|
|
148
|
+
readonly moveTo: true;
|
|
149
149
|
readonly moveToRangeEnd: false;
|
|
150
150
|
readonly moveToRangeStart: false;
|
|
151
151
|
readonly simpleField: false;
|
|
@@ -137,14 +137,14 @@ const SIMPLE_FIELD_CONTENT = {
|
|
|
137
137
|
commentRangeStart: false,
|
|
138
138
|
commentReference: false,
|
|
139
139
|
complexField: false,
|
|
140
|
-
deletion:
|
|
140
|
+
deletion: true,
|
|
141
141
|
inlineSdt: false,
|
|
142
|
-
insertion:
|
|
142
|
+
insertion: true,
|
|
143
143
|
mathEquation: false,
|
|
144
|
-
moveFrom:
|
|
144
|
+
moveFrom: true,
|
|
145
145
|
moveFromRangeEnd: false,
|
|
146
146
|
moveFromRangeStart: false,
|
|
147
|
-
moveTo:
|
|
147
|
+
moveTo: true,
|
|
148
148
|
moveToRangeEnd: false,
|
|
149
149
|
moveToRangeStart: false,
|
|
150
150
|
simpleField: false
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { XmlElement } from "./xmlParser.js";
|
|
2
|
+
//#region src/docx/linkedSdtPreservation.d.ts
|
|
3
|
+
declare const UnrepresentableLinkedSdtRevisionError_base: import("better-result").TaggedErrorClass<"UnrepresentableLinkedSdtRevisionError">;
|
|
4
|
+
declare class UnrepresentableLinkedSdtRevisionError extends UnrepresentableLinkedSdtRevisionError_base<{
|
|
5
|
+
message: string;
|
|
6
|
+
}> {}
|
|
7
|
+
/** Capture only the unsupported hyperlink child, never its enclosing revision. */
|
|
8
|
+
declare const preserveLinkedSdt: (root: XmlElement) => import("@stll/docx-core/model").PreservedInline;
|
|
9
|
+
//#endregion
|
|
10
|
+
export { UnrepresentableLinkedSdtRevisionError, preserveLinkedSdt };
|