@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,7 +10,7 @@ import { RELATIONSHIP_TYPES } from "./relsParser.js";
|
|
|
10
10
|
import { COMMENTS_CONTENT_TYPE, COMMENTS_EXTENDED_PART_LOWER, addCommentsExtendedOverride, addCommentsExtendedRelationship, applyUpdatesToZip, collectHeaderFooterUpdates, findMaxRId, hasModelDrivenPictureWatermark, hasUnmaterializedHeaderFooter, hasUnmaterializedHyperlinkBindings, hasUnmaterializedInlineResources, planAddedStyles, publishCanonicalImageResources, updateCoreProperties, withoutAttachedTemplate } from "./rezip.js";
|
|
11
11
|
import "./selectiveSaveFlags.js";
|
|
12
12
|
import { buildPatchedDocumentXml, buildPatchedNoteXml, collectAddedNumberingDefs, collectParaIds, patchNumberingDefinitions } from "./selectiveXmlPatch.js";
|
|
13
|
-
import { planCommentParts, serializeComments, serializeCommentsExtended } from "./serializer/commentSerializer.js";
|
|
13
|
+
import { hasOwnedCommentsPart, planCommentParts, serializeComments, serializeCommentsExtended } from "./serializer/commentSerializer.js";
|
|
14
14
|
import { serializeDocument } from "./serializer/documentSerializer.js";
|
|
15
15
|
import { serializeEndnotes, serializeFootnotes } from "./serializer/noteSerializer.js";
|
|
16
16
|
import { serializeNumberingXml } from "./serializer/numberingSerializer.js";
|
|
@@ -201,6 +201,7 @@ async function attemptSelectiveSave(doc, originalBuffer, options) {
|
|
|
201
201
|
if (!validateFolioDocumentModel(doc).valid) return null;
|
|
202
202
|
const comments = doc.package.document.comments ?? [];
|
|
203
203
|
const hasComments = comments.length > 0;
|
|
204
|
+
const ownsCommentsPart = hasOwnedCommentsPart(doc);
|
|
204
205
|
const commentPlan = planCommentParts(comments);
|
|
205
206
|
try {
|
|
206
207
|
const zip = await (await import("jszip")).default.loadAsync(originalBuffer);
|
|
@@ -259,25 +260,26 @@ async function attemptSelectiveSave(doc, originalBuffer, options) {
|
|
|
259
260
|
updates.set("word/document.xml", patchedDocXml);
|
|
260
261
|
}
|
|
261
262
|
}
|
|
262
|
-
const sourceCommentsFile = zip
|
|
263
|
-
|
|
263
|
+
const sourceCommentsFile = findZipEntryCaseInsensitive(zip, "word/comments.xml");
|
|
264
|
+
const commentsPartPath = sourceCommentsFile?.name ?? "word/comments.xml";
|
|
265
|
+
if (hasComments || ownsCommentsPart || sourceCommentsFile) {
|
|
264
266
|
const sourceCommentsXml = sourceCommentsFile ? await sourceCommentsFile.async("text") : void 0;
|
|
265
267
|
const commentsXml = serializeComments(commentPlan, sourceCommentsXml === void 0 ? void 0 : readRootNamespaceBindings(sourceCommentsXml));
|
|
266
|
-
if (commentsXml !== sourceCommentsXml) updates.set(
|
|
268
|
+
if (commentsXml !== sourceCommentsXml) updates.set(commentsPartPath, commentsXml);
|
|
267
269
|
}
|
|
268
|
-
if (hasComments) {
|
|
270
|
+
if (hasComments || ownsCommentsPart) {
|
|
269
271
|
const ctFile = zip.file("[Content_Types].xml");
|
|
270
272
|
if (ctFile) {
|
|
271
273
|
const ctXml = await ctFile.async("text");
|
|
272
|
-
if (!ctXml.includes("/word/comments.xml")) updates.set("[Content_Types].xml", ctXml.replace("</Types>", `<Override PartName="
|
|
274
|
+
if (!ctXml.toLowerCase().includes("/word/comments.xml")) updates.set("[Content_Types].xml", ctXml.replace("</Types>", `<Override PartName="/${commentsPartPath}" ContentType="${COMMENTS_CONTENT_TYPE}"/></Types>`));
|
|
273
275
|
}
|
|
274
276
|
const relsPath = "word/_rels/document.xml.rels";
|
|
275
277
|
const relsFile = zip.file(relsPath);
|
|
276
278
|
if (relsFile) {
|
|
277
279
|
const relsXml = await relsFile.async("text");
|
|
278
|
-
if (!relsXml.includes("comments.xml")) {
|
|
280
|
+
if (!relsXml.toLowerCase().includes("comments.xml")) {
|
|
279
281
|
const maxId = findMaxRId(relsXml);
|
|
280
|
-
updates.set(relsPath, relsXml.replace("</Relationships>", `<Relationship Id="rId${maxId + 1}" Type="${RELATIONSHIP_TYPES.comments}" Target="
|
|
282
|
+
updates.set(relsPath, relsXml.replace("</Relationships>", `<Relationship Id="rId${maxId + 1}" Type="${RELATIONSHIP_TYPES.comments}" Target="${commentsPartPath.slice(5)}"/></Relationships>`));
|
|
281
283
|
}
|
|
282
284
|
}
|
|
283
285
|
}
|
|
@@ -1,5 +1,8 @@
|
|
|
1
|
+
import { document_d_exports } from "../../types/document.js";
|
|
1
2
|
import { Comment } from "../../types/content.js";
|
|
2
3
|
//#region src/docx/serializer/commentSerializer.d.ts
|
|
4
|
+
/** An owned empty part survives deletion of its final thread. */
|
|
5
|
+
declare const hasOwnedCommentsPart: (document: document_d_exports.Document) => boolean;
|
|
3
6
|
/**
|
|
4
7
|
* What every comment part is written from: one ordered list of comment ids, and
|
|
5
8
|
* the facts each id carries.
|
|
@@ -52,4 +55,4 @@ declare function serializeComments({ order, byId }: CommentPartPlan, sourceBindi
|
|
|
52
55
|
*/
|
|
53
56
|
declare function serializeCommentsExtended(plan: CommentPartPlan): string | null;
|
|
54
57
|
//#endregion
|
|
55
|
-
export { CommentPartPlan, planCommentParts, serializeComments, serializeCommentsExtended };
|
|
58
|
+
export { CommentPartPlan, hasOwnedCommentsPart, planCommentParts, serializeComments, serializeCommentsExtended };
|
|
@@ -5,12 +5,15 @@ import { serializeParagraph } from "./paragraphSerializer.js";
|
|
|
5
5
|
import { serializePartElement } from "./partNamespaces.js";
|
|
6
6
|
import { serializeTextFormatting } from "./textFormattingSerializer.js";
|
|
7
7
|
import { escapeXmlAttribute } from "@stll/docx-core";
|
|
8
|
+
import { COMMENT_PART_RELATIONSHIPS } from "@stll/docx-core/model";
|
|
8
9
|
//#region src/docx/serializer/commentSerializer.ts
|
|
9
10
|
/**
|
|
10
11
|
* Comment Serializer
|
|
11
12
|
*
|
|
12
13
|
* Serializes Comment[] to OOXML comments.xml format.
|
|
13
14
|
*/
|
|
15
|
+
/** An owned empty part survives deletion of its final thread. */
|
|
16
|
+
const hasOwnedCommentsPart = (document) => [...document.package.relationships?.values() ?? []].some(({ type }) => type === COMMENT_PART_RELATIONSHIPS.comments.type);
|
|
14
17
|
const DEFAULT_ANNOTATION_REFERENCE_PROPERTIES = "<w:rPr><w:rStyle w:val=\"CommentReference\"/></w:rPr>";
|
|
15
18
|
const PARAGRAPH_PROPERTIES_END = "</w:pPr>";
|
|
16
19
|
const serializeAnnotationReference = (formatting) => {
|
|
@@ -169,7 +172,7 @@ function buildCommentExtendedEntries({ order, byId, threadParaIdById, threadedId
|
|
|
169
172
|
entries.push({
|
|
170
173
|
paraId,
|
|
171
174
|
...parentParaId !== void 0 ? { paraIdParent: parentParaId } : {},
|
|
172
|
-
done: done
|
|
175
|
+
...done === void 0 ? {} : { done }
|
|
173
176
|
});
|
|
174
177
|
}
|
|
175
178
|
return entries.length > 0 ? entries : null;
|
|
@@ -185,7 +188,8 @@ function serializeCommentsExtended(plan) {
|
|
|
185
188
|
if (!entries) return null;
|
|
186
189
|
const body = entries.map((entry) => {
|
|
187
190
|
const parentAttr = entry.paraIdParent !== void 0 ? ` w15:paraIdParent="${escapeXmlAttribute(entry.paraIdParent)}"` : "";
|
|
188
|
-
|
|
191
|
+
const doneAttr = entry.done === void 0 ? "" : ` w15:done="${entry.done ? "1" : "0"}"`;
|
|
192
|
+
return `<w15:commentEx w15:paraId="${escapeXmlAttribute(entry.paraId)}"${parentAttr}${doneAttr}/>`;
|
|
189
193
|
}).join("");
|
|
190
194
|
return XML_DECLARATION + serializePartElement({
|
|
191
195
|
partPath: "word/commentsExtended.xml",
|
|
@@ -196,4 +200,4 @@ function serializeCommentsExtended(plan) {
|
|
|
196
200
|
});
|
|
197
201
|
}
|
|
198
202
|
//#endregion
|
|
199
|
-
export { planCommentParts, serializeComments, serializeCommentsExtended };
|
|
203
|
+
export { hasOwnedCommentsPart, planCommentParts, serializeComments, serializeCommentsExtended };
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
import { modelParagraphFormattingEmission, serializeParagraphPropertySet } from "../../internal/paragraphFormattingSerialization.js";
|
|
2
2
|
import { serializePreservedAttributes } from "../attributeRemainder.js";
|
|
3
|
-
import { CONTAINER_CHILDREN } from "../containerChildren.gen.js";
|
|
3
|
+
import { CONTAINER_CHILDREN, TRACKED_RUN_WORDPROCESSING_CHILDREN } from "../containerChildren.gen.js";
|
|
4
4
|
import { fieldStateAttributes } from "../fieldState.js";
|
|
5
5
|
import { serializeEmptyMarkProperties } from "../paragraphMarkPropertyPresence.js";
|
|
6
|
-
import { getParagraphPropertySource, paragraphPropertySourceMatchesEmission } from "../paragraphPropertySource.js";
|
|
6
|
+
import { getParagraphPropertySource, paragraphFormattingWithAuthoredIndentation, paragraphPropertySourceMatchesAuthoredIndentation, paragraphPropertySourceMatchesEmission } from "../paragraphPropertySource.js";
|
|
7
7
|
import { ReviewResolutionProvenanceError, paragraphMarkResolutionJoinAttributes, serializeParagraphMarkResolutionJoin, serializeResolutionJoins } from "../reviewResolutionProvenance.js";
|
|
8
8
|
import { DATE_UTC_ATTRIBUTE } from "../trackedChangeInfo.js";
|
|
9
9
|
import { toTransitionalNamespaceUri } from "../transitionalSpelling.js";
|
|
10
10
|
import { captureVerbatimXml, createCapturedXmlSanitizer } from "../verbatimCapture.js";
|
|
11
|
-
import { NAMESPACES, OOXML_NAMESPACE_SCOPE, cloneElement, getChildElements, getLocalName, parseXml } from "../xmlParser.js";
|
|
11
|
+
import { NAMESPACES, OOXML_NAMESPACE_SCOPE, WORDPROCESSINGML_NAMESPACE_URIS, cloneElement, getChildElements, getLocalName, parseXml } from "../xmlParser.js";
|
|
12
12
|
import { writeGroupTextBoxesBack } from "./groupTextBoxWriteBack.js";
|
|
13
13
|
import { markupRangeAttributes, moveBookmarkAttributes, serializeBookmarkMarker } from "./markupRangeAttributes.js";
|
|
14
14
|
import { serializeRun, serializeShapeTextBody } from "./runSerializer.js";
|
|
@@ -248,7 +248,7 @@ const withParagraphMarkChange = (sourceXml, mark) => {
|
|
|
248
248
|
}
|
|
249
249
|
return captureVerbatimXml(cloneElement(root, { elements }));
|
|
250
250
|
};
|
|
251
|
-
const serializeParagraphFormattingWithOptions = (formatting, { propertyChanges, paragraphMarkChange, propertySource, sectionProperties } = {}) => {
|
|
251
|
+
const serializeParagraphFormattingWithOptions = (formatting, { propertyChanges, paragraphMarkChange, propertySource, sourceParagraph, sectionProperties } = {}) => {
|
|
252
252
|
const modeledFormatting = modelParagraphFormattingEmission(formatting);
|
|
253
253
|
const serializablePropertyChangeCount = propertyChanges?.length ?? 0;
|
|
254
254
|
if (serializablePropertyChangeCount > 1) panic("A paragraph cannot serialize more than one w:pPrChange", { count: serializablePropertyChangeCount });
|
|
@@ -260,13 +260,13 @@ const serializeParagraphFormattingWithOptions = (formatting, { propertyChanges,
|
|
|
260
260
|
sectionPropertiesXml,
|
|
261
261
|
...propertyChangesXml
|
|
262
262
|
].some((xml) => xml.includes(`${DATE_UTC_ATTRIBUTE}=`));
|
|
263
|
-
const verifiedSource = verifiedParagraphPropertySource(modeledFormatting, propertySource);
|
|
263
|
+
const verifiedSource = sourceParagraph && !paragraphPropertySourceMatchesAuthoredIndentation(sourceParagraph) ? null : verifiedParagraphPropertySource(modeledFormatting, propertySource);
|
|
264
264
|
if (verifiedSource !== null && (!composedChildrenUseDateUtc || !sourceShadowsDateUtcPrefix(verifiedSource))) {
|
|
265
265
|
const sourceWithMark = paragraphMarkChange ? withParagraphMarkChange(verifiedSource, paragraphMarkChange) : verifiedSource;
|
|
266
266
|
return withTrailingParagraphPropertyChildren(sourceWithMark, [sectionPropertiesXml, ...propertyChangesXml]);
|
|
267
267
|
}
|
|
268
268
|
return serializeParagraphPropertySet({
|
|
269
|
-
formatting,
|
|
269
|
+
formatting: sourceParagraph ? paragraphFormattingWithAuthoredIndentation(sourceParagraph) : formatting,
|
|
270
270
|
markPropertiesPrefixXml: paragraphMarkXml,
|
|
271
271
|
sectionPropertiesXml,
|
|
272
272
|
propertyChangesXml
|
|
@@ -320,15 +320,7 @@ function serializeHyperlink(hyperlink, disposition = "kept") {
|
|
|
320
320
|
/** Serialize a simple field without changing its authored OOXML field form. */
|
|
321
321
|
function serializeSimpleField(field) {
|
|
322
322
|
const attrs = [`w:instr="${escapeXmlAttribute(field.instruction)}"`, ...fieldStateAttributes(field)];
|
|
323
|
-
const contentXml = field.content.map((item) =>
|
|
324
|
-
switch (item.type) {
|
|
325
|
-
case "run": return serializeRun(item);
|
|
326
|
-
case "hyperlink": return serializeHyperlink(item);
|
|
327
|
-
case "inlineWrapper": return serializeParagraphContent(item);
|
|
328
|
-
case "preservedInline": return item.xml;
|
|
329
|
-
default: return item;
|
|
330
|
-
}
|
|
331
|
-
}).join("");
|
|
323
|
+
const contentXml = field.content.map((item) => serializeParagraphContent(item)).join("");
|
|
332
324
|
return `<w:fldSimple ${attrs.join(" ")}>${contentXml}</w:fldSimple>`;
|
|
333
325
|
}
|
|
334
326
|
const replayableFormFieldDataXml = createCapturedXmlSanitizer({
|
|
@@ -369,27 +361,67 @@ function serializeRemovedPreservedInline(item) {
|
|
|
369
361
|
if (item.foldedListNumber) throw new UnrepresentableTrackedCaptureError({ message: "A folded list-number field holds markup that cannot be written as deleted content." });
|
|
370
362
|
return item.xml;
|
|
371
363
|
}
|
|
372
|
-
var
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
364
|
+
var UnrepresentableTrackedFieldChildError = class extends TaggedError("UnrepresentableTrackedFieldChildError") {};
|
|
365
|
+
const TRACKED_FIELD_CAPTURE_NAMES = new Set(TRACKED_RUN_WORDPROCESSING_CHILDREN);
|
|
366
|
+
const replayableFieldDataXml = createCapturedXmlSanitizer({
|
|
367
|
+
allowedLocalNames: /* @__PURE__ */ new Set(["fldData"]),
|
|
368
|
+
allowedNamespaceUris: WORDPROCESSINGML_NAMESPACE_URIS,
|
|
369
|
+
inheritedNamespaceScope: OOXML_NAMESPACE_SCOPE
|
|
370
|
+
});
|
|
371
|
+
/** Lower a tracked field into run-level structure before revision/link segmentation. */
|
|
372
|
+
const trackedSimpleFieldContent = (field) => {
|
|
373
|
+
const formatting = field.content.find((item) => item.type === "run")?.formatting;
|
|
374
|
+
const structuralRun = (content) => ({
|
|
375
|
+
type: "run",
|
|
376
|
+
content,
|
|
377
|
+
...formatting && { formatting }
|
|
378
|
+
});
|
|
379
|
+
let fieldDataXml = null;
|
|
380
|
+
const result = [];
|
|
376
381
|
for (const item of field.content) {
|
|
377
|
-
if (item.type !== "
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
}
|
|
381
|
-
|
|
382
|
+
if (item.type !== "preservedInline") {
|
|
383
|
+
result.push(item);
|
|
384
|
+
continue;
|
|
385
|
+
}
|
|
386
|
+
const captured = parseXml(item.xml, OOXML_NAMESPACE_SCOPE);
|
|
387
|
+
const root = captured.elements?.at(0);
|
|
388
|
+
if (captured.elements?.length !== 1 || !root || !WORDPROCESSINGML_NAMESPACE_URIS.has(root.namespaceUri ?? "")) throw new UnrepresentableTrackedFieldChildError({ message: "A tracked field capture has no representable revision-level home." });
|
|
389
|
+
const name = getLocalName(root.name);
|
|
390
|
+
if (name === "fldData") {
|
|
391
|
+
const data = replayableFieldDataXml(item.xml);
|
|
392
|
+
if (!data || fieldDataXml !== null) throw new UnrepresentableTrackedFieldChildError({ message: "A tracked field requires at most one valid fldData child." });
|
|
393
|
+
fieldDataXml = data;
|
|
394
|
+
continue;
|
|
395
|
+
}
|
|
396
|
+
if (!TRACKED_FIELD_CAPTURE_NAMES.has(name)) throw new UnrepresentableTrackedFieldChildError({ message: `A tracked field capture cannot lower ${name} into a revision wrapper.` });
|
|
397
|
+
result.push(item);
|
|
382
398
|
}
|
|
383
|
-
return
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
}
|
|
399
|
+
return [
|
|
400
|
+
fieldDataXml ? structuralRun([{
|
|
401
|
+
type: "preservedXml",
|
|
402
|
+
text: "",
|
|
403
|
+
xml: `<w:fldChar w:fldCharType="begin"${fieldStateAttributes(field).map((attr) => ` ${attr}`).join("")}>${fieldDataXml}</w:fldChar>`
|
|
404
|
+
}]) : structuralRun([{
|
|
405
|
+
type: "fieldChar",
|
|
406
|
+
charType: "begin",
|
|
407
|
+
...field.fldLock !== void 0 && { fldLock: field.fldLock },
|
|
408
|
+
...field.dirty !== void 0 && { dirty: field.dirty }
|
|
409
|
+
}]),
|
|
410
|
+
...field.instruction.length ? [structuralRun([{
|
|
411
|
+
type: "instrText",
|
|
412
|
+
text: field.instruction
|
|
413
|
+
}])] : [],
|
|
414
|
+
structuralRun([{
|
|
415
|
+
type: "fieldChar",
|
|
416
|
+
charType: "separate"
|
|
417
|
+
}]),
|
|
418
|
+
...result,
|
|
419
|
+
structuralRun([{
|
|
420
|
+
type: "fieldChar",
|
|
421
|
+
charType: "end"
|
|
422
|
+
}])
|
|
423
|
+
];
|
|
424
|
+
};
|
|
393
425
|
/**
|
|
394
426
|
* Serialize an inline SDT (w:sdt).
|
|
395
427
|
*
|
|
@@ -459,63 +491,143 @@ function trackedChangeTag(change) {
|
|
|
459
491
|
}
|
|
460
492
|
}
|
|
461
493
|
function serializeTrackedChange(tag, change) {
|
|
462
|
-
|
|
494
|
+
return emitTrackedInlineSegments(trackedChangeSegments({
|
|
495
|
+
tag,
|
|
496
|
+
change
|
|
497
|
+
}));
|
|
498
|
+
}
|
|
499
|
+
const emitTrackedInlineSegments = (segments) => segments.map((segment) => {
|
|
500
|
+
switch (segment.type) {
|
|
501
|
+
case "plain": return segment.xml;
|
|
502
|
+
case "hyperlink": return `<w:hyperlink${hyperlinkAttributes(segment.hyperlink)}>${segment.xml}</w:hyperlink>`;
|
|
503
|
+
default: return segment;
|
|
504
|
+
}
|
|
505
|
+
}).join("");
|
|
506
|
+
/** Wrap contiguous plain content once, and carry wrappers inside each lifted link. */
|
|
507
|
+
const wrapTrackedInlineSegments = (segments, wrap) => {
|
|
508
|
+
if (segments.length === 0) return [{
|
|
509
|
+
type: "plain",
|
|
510
|
+
xml: wrap("")
|
|
511
|
+
}];
|
|
512
|
+
const result = [];
|
|
513
|
+
const pending = [];
|
|
514
|
+
const flush = () => {
|
|
515
|
+
if (pending.length === 0) return;
|
|
516
|
+
result.push({
|
|
517
|
+
type: "plain",
|
|
518
|
+
xml: wrap(pending.join(""))
|
|
519
|
+
});
|
|
520
|
+
pending.length = 0;
|
|
521
|
+
};
|
|
522
|
+
for (const segment of segments) switch (segment.type) {
|
|
523
|
+
case "plain":
|
|
524
|
+
pending.push(segment.xml);
|
|
525
|
+
break;
|
|
526
|
+
case "hyperlink":
|
|
527
|
+
flush();
|
|
528
|
+
result.push({
|
|
529
|
+
type: "hyperlink",
|
|
530
|
+
hyperlink: segment.hyperlink,
|
|
531
|
+
xml: wrap(segment.xml)
|
|
532
|
+
});
|
|
533
|
+
break;
|
|
534
|
+
default: return segment;
|
|
535
|
+
}
|
|
536
|
+
flush();
|
|
537
|
+
return result;
|
|
538
|
+
};
|
|
539
|
+
const trackedChangeSegments = ({ tag, change }) => {
|
|
540
|
+
const disposition = tag === "del" || tag === "moveFrom" ? "removed" : "kept";
|
|
541
|
+
const segments = walkTrackedInlineContent(change.content, disposition);
|
|
542
|
+
if (change.resolutionJoins !== void 0 && segments.some((segment) => segment.type === "hyperlink")) throw new ReviewResolutionProvenanceError({
|
|
463
543
|
attribute: "resolutionJoins",
|
|
464
544
|
reason: "unrepresentable",
|
|
465
545
|
message: "Tracked-resolution provenance cannot be repartitioned across serialized hyperlinks."
|
|
466
546
|
});
|
|
467
547
|
const attrs = serializeTrackedChangeAttributes(change.info) + serializeResolutionJoins(change.resolutionJoins);
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
case "simpleField":
|
|
474
|
-
case "complexField": {
|
|
475
|
-
const xml = item.type === "simpleField" ? serializeTrackedSimpleField(item) : serializeComplexField(item);
|
|
476
|
-
return disposition === "removed" ? rewriteRunTextAsDeleted(xml) : xml;
|
|
477
|
-
}
|
|
478
|
-
case "mathEquation": return item.ommlXml;
|
|
479
|
-
case "insertion":
|
|
480
|
-
case "deletion":
|
|
481
|
-
case "moveFrom":
|
|
482
|
-
case "moveTo": return serializeTrackedChange(trackedChangeTag(item), item);
|
|
483
|
-
case "bookmarkStart":
|
|
484
|
-
case "bookmarkEnd": return serializeBookmarkMarker(item);
|
|
485
|
-
case "moveFromRangeStart": return serializeMoveRangeStart("moveFromRangeStart", item);
|
|
486
|
-
case "moveFromRangeEnd": return `<w:moveFromRangeEnd ${markupRangeAttributes(item).join(" ")}/>`;
|
|
487
|
-
case "moveToRangeStart": return serializeMoveRangeStart("moveToRangeStart", item);
|
|
488
|
-
case "moveToRangeEnd": return `<w:moveToRangeEnd ${markupRangeAttributes(item).join(" ")}/>`;
|
|
489
|
-
case "preservedInline": return disposition === "removed" ? serializeRemovedPreservedInline(item) : item.xml;
|
|
490
|
-
case "inlineWrapper":
|
|
491
|
-
case "inlineSdt": return serializeParagraphContent(item, disposition);
|
|
492
|
-
default: return item;
|
|
493
|
-
}
|
|
494
|
-
};
|
|
495
|
-
const open = `<w:${tag} ${attrs}>`;
|
|
496
|
-
const close = `</w:${tag}>`;
|
|
497
|
-
const wrap = (inner) => inner.length === 0 ? "" : `${open}${inner}${close}`;
|
|
498
|
-
if (change.content.length === 0) return `${open}${close}`;
|
|
548
|
+
return wrapTrackedInlineSegments(segments, (xml) => `<w:${tag} ${attrs}>${xml}</w:${tag}>`);
|
|
549
|
+
};
|
|
550
|
+
var UnrepresentableNestedHyperlinkError = class extends TaggedError("UnrepresentableNestedHyperlinkError") {};
|
|
551
|
+
/** One exhaustive recursive owner for all containers inside a tracked revision. */
|
|
552
|
+
const walkTrackedInlineContent = (content, disposition) => {
|
|
499
553
|
const segments = [];
|
|
500
|
-
const
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
554
|
+
for (const item of content) switch (item.type) {
|
|
555
|
+
case "hyperlink": {
|
|
556
|
+
const children = walkTrackedInlineContent(item.children, disposition);
|
|
557
|
+
if (children.some((child) => child.type === "hyperlink")) throw new UnrepresentableNestedHyperlinkError({ message: "A tracked hyperlink cannot contain another hyperlink." });
|
|
558
|
+
segments.push({
|
|
559
|
+
type: "hyperlink",
|
|
560
|
+
hyperlink: item,
|
|
561
|
+
xml: emitTrackedInlineSegments(children)
|
|
562
|
+
});
|
|
563
|
+
break;
|
|
505
564
|
}
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
565
|
+
case "simpleField":
|
|
566
|
+
segments.push(...walkTrackedInlineContent(trackedSimpleFieldContent(item), disposition));
|
|
567
|
+
break;
|
|
568
|
+
case "insertion":
|
|
569
|
+
case "deletion":
|
|
570
|
+
case "moveFrom":
|
|
571
|
+
case "moveTo":
|
|
572
|
+
segments.push(...trackedChangeSegments({
|
|
573
|
+
tag: trackedChangeTag(item),
|
|
574
|
+
change: item
|
|
575
|
+
}));
|
|
576
|
+
break;
|
|
577
|
+
case "inlineWrapper":
|
|
578
|
+
segments.push(...wrapTrackedInlineSegments(walkTrackedInlineContent(item.content, disposition), (xml) => serializeInlineWrapperMarkup(item, xml)));
|
|
579
|
+
break;
|
|
580
|
+
case "inlineSdt":
|
|
581
|
+
segments.push({
|
|
582
|
+
type: "plain",
|
|
583
|
+
xml: serializeSdtWrapper(item.properties, emitTrackedInlineSegments(walkTrackedInlineContent(item.content, disposition)))
|
|
584
|
+
});
|
|
585
|
+
break;
|
|
586
|
+
case "complexField": {
|
|
587
|
+
const xml = serializeComplexField(item);
|
|
588
|
+
segments.push({
|
|
589
|
+
type: "plain",
|
|
590
|
+
xml: disposition === "removed" ? rewriteRunTextAsDeleted(xml) : xml
|
|
591
|
+
});
|
|
592
|
+
break;
|
|
593
|
+
}
|
|
594
|
+
case "preservedInline": {
|
|
595
|
+
const pending = getChildElements(parseXml(item.xml, OOXML_NAMESPACE_SCOPE));
|
|
596
|
+
while (pending.length > 0) {
|
|
597
|
+
const captured = pending.pop();
|
|
598
|
+
if (!captured) continue;
|
|
599
|
+
const wordprocessing = WORDPROCESSINGML_NAMESPACE_URIS.has(captured.namespaceUri ?? "");
|
|
600
|
+
const name = getLocalName(captured.name);
|
|
601
|
+
if (wordprocessing && (name === "p" || name === "sdt")) continue;
|
|
602
|
+
if (wordprocessing && name === "hyperlink") throw new UnrepresentableTrackedCaptureError({ message: "A tracked capture containing a hyperlink requires typed content for lifting." });
|
|
603
|
+
pending.push(...getChildElements(captured));
|
|
604
|
+
}
|
|
605
|
+
segments.push({
|
|
606
|
+
type: "plain",
|
|
607
|
+
xml: disposition === "removed" ? serializeRemovedPreservedInline(item) : item.xml
|
|
608
|
+
});
|
|
609
|
+
break;
|
|
513
610
|
}
|
|
514
|
-
|
|
611
|
+
case "run":
|
|
612
|
+
case "mathEquation":
|
|
613
|
+
case "bookmarkStart":
|
|
614
|
+
case "bookmarkEnd":
|
|
615
|
+
case "moveFromRangeStart":
|
|
616
|
+
case "moveFromRangeEnd":
|
|
617
|
+
case "moveToRangeStart":
|
|
618
|
+
case "moveToRangeEnd":
|
|
619
|
+
case "commentRangeStart":
|
|
620
|
+
case "commentRangeEnd":
|
|
621
|
+
case "commentReference":
|
|
622
|
+
segments.push({
|
|
623
|
+
type: "plain",
|
|
624
|
+
xml: serializeParagraphContent(item, disposition)
|
|
625
|
+
});
|
|
626
|
+
break;
|
|
627
|
+
default: return item;
|
|
515
628
|
}
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
}
|
|
629
|
+
return segments;
|
|
630
|
+
};
|
|
519
631
|
/** The properties element each tagged wrapper declares ahead of its content. */
|
|
520
632
|
const TAGGED_WRAPPER_PROPERTIES = {
|
|
521
633
|
smartTag: "smartTagPr",
|
|
@@ -552,6 +664,17 @@ function serializeTaggedWrapper(kind, wrapper, inner) {
|
|
|
552
664
|
function serializeCommentReferenceRun(id) {
|
|
553
665
|
return `<w:r><w:rPr><w:rStyle w:val="CommentReference"/></w:rPr><w:commentReference w:id="${id}"/></w:r>`;
|
|
554
666
|
}
|
|
667
|
+
function serializeInlineWrapperMarkup(content, inner) {
|
|
668
|
+
switch (content.kind) {
|
|
669
|
+
case "bidi": {
|
|
670
|
+
const tag = content.control === "override" ? "bdo" : "dir";
|
|
671
|
+
return `<w:${tag}${content.direction === void 0 ? "" : ` w:val="${escapeXmlAttribute(content.direction)}"`}>${inner}</w:${tag}>`;
|
|
672
|
+
}
|
|
673
|
+
case "smartTag": return serializeTaggedWrapper("smartTag", content, inner);
|
|
674
|
+
case "customXml": return serializeTaggedWrapper("customXml", content, inner);
|
|
675
|
+
default: return content;
|
|
676
|
+
}
|
|
677
|
+
}
|
|
555
678
|
/**
|
|
556
679
|
* Serialize a single paragraph content item.
|
|
557
680
|
*
|
|
@@ -580,18 +703,7 @@ function serializeParagraphContent(content, disposition = "kept") {
|
|
|
580
703
|
case "moveFromRangeEnd": return `<w:moveFromRangeEnd ${markupRangeAttributes(content).join(" ")}/>`;
|
|
581
704
|
case "moveToRangeStart": return serializeMoveRangeStart("moveToRangeStart", content);
|
|
582
705
|
case "moveToRangeEnd": return `<w:moveToRangeEnd ${markupRangeAttributes(content).join(" ")}/>`;
|
|
583
|
-
case "inlineWrapper":
|
|
584
|
-
const inner = content.content.map((child) => serializeParagraphContent(child, disposition)).join("");
|
|
585
|
-
switch (content.kind) {
|
|
586
|
-
case "bidi": {
|
|
587
|
-
const tag = content.control === "override" ? "bdo" : "dir";
|
|
588
|
-
return `<w:${tag}${content.direction === void 0 ? "" : ` w:val="${escapeXmlAttribute(content.direction)}"`}>${inner}</w:${tag}>`;
|
|
589
|
-
}
|
|
590
|
-
case "smartTag": return serializeTaggedWrapper("smartTag", content, inner);
|
|
591
|
-
case "customXml": return serializeTaggedWrapper("customXml", content, inner);
|
|
592
|
-
default: return content;
|
|
593
|
-
}
|
|
594
|
-
}
|
|
706
|
+
case "inlineWrapper": return serializeInlineWrapperMarkup(content, content.content.map((child) => serializeParagraphContent(child, disposition)).join(""));
|
|
595
707
|
case "mathEquation": return content.ommlXml || "";
|
|
596
708
|
case "preservedInline": return content.xml;
|
|
597
709
|
default: return "";
|
|
@@ -617,6 +729,7 @@ function serializeParagraph(paragraph) {
|
|
|
617
729
|
propertyChanges: paragraph.propertyChanges,
|
|
618
730
|
paragraphMarkChange: paragraph.pPrMark,
|
|
619
731
|
propertySource: getParagraphPropertySource(paragraph),
|
|
732
|
+
sourceParagraph: paragraph,
|
|
620
733
|
sectionProperties: paragraph.sectionProperties
|
|
621
734
|
}));
|
|
622
735
|
let pendingRenderedPageBreak = paragraph.renderedPageBreakBefore === true;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { fromProseDoc } from "../../prosemirror/conversion/fromProseDoc.js";
|
|
2
2
|
import { schema } from "../../prosemirror/schema/index.js";
|
|
3
|
-
import { applyAttrSchemaMigrations, readYjsAttrSchemaVersion, readYjsParagraphSourceContract, withParagraphSourceContract } from "../../prosemirror/yjsDocumentMetadata.js";
|
|
3
|
+
import { FolioYjsNoteReferenceSchemaError, applyAttrSchemaMigrations, readYjsAttrSchemaVersion, readYjsParagraphSourceContract, withParagraphSourceContract } from "../../prosemirror/yjsDocumentMetadata.js";
|
|
4
4
|
import { ParagraphPropertySourceValidationError } from "../paragraphPropertySource.js";
|
|
5
5
|
import { parseDocx } from "../parser.js";
|
|
6
6
|
import { repackDocx } from "../rezip.js";
|
|
@@ -55,11 +55,19 @@ const readProseMirrorDocument = (yjsUpdate) => {
|
|
|
55
55
|
});
|
|
56
56
|
return withParagraphSourceContract(initProseMirrorDoc(fragment, schema).doc, contract);
|
|
57
57
|
},
|
|
58
|
-
catch: (cause) =>
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
58
|
+
catch: (cause) => {
|
|
59
|
+
if (cause instanceof FolioYjsDocxMaterializationError) return cause;
|
|
60
|
+
if (cause instanceof FolioYjsNoteReferenceSchemaError) return new FolioYjsDocxMaterializationError({
|
|
61
|
+
code: "stale_attr_schema",
|
|
62
|
+
message: cause.message,
|
|
63
|
+
cause
|
|
64
|
+
});
|
|
65
|
+
return new FolioYjsDocxMaterializationError({
|
|
66
|
+
code: "invalid_update",
|
|
67
|
+
message: "Yjs update is not a valid Folio collaboration snapshot.",
|
|
68
|
+
cause
|
|
69
|
+
});
|
|
70
|
+
}
|
|
63
71
|
});
|
|
64
72
|
ydoc.destroy();
|
|
65
73
|
if (parsed.isOk()) return parsed.value;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { applyAttrSchemaMigrations, readYjsAttrSchemaVersion } from "../../prosemirror/yjsDocumentMetadata.js";
|
|
1
|
+
import { FolioYjsNoteReferenceSchemaError, applyAttrSchemaMigrations, readYjsAttrSchemaVersion } from "../../prosemirror/yjsDocumentMetadata.js";
|
|
2
2
|
import { FOLIO_YJS_PROSEMIRROR_FRAGMENT_NAME } from "./materializeYjsDocx.js";
|
|
3
3
|
import { Result, TaggedError } from "better-result";
|
|
4
4
|
import * as Y from "yjs";
|
|
@@ -72,22 +72,34 @@ const migrateFolioYjsSnapshot = (update) => {
|
|
|
72
72
|
}));
|
|
73
73
|
}
|
|
74
74
|
const fromVersion = read.value;
|
|
75
|
-
|
|
75
|
+
const migratedAttrs = Result.try({
|
|
76
|
+
try: () => applyAttrSchemaMigrations(ydoc, ydoc.getXmlFragment(FOLIO_YJS_PROSEMIRROR_FRAGMENT_NAME), fromVersion),
|
|
77
|
+
catch: (cause) => new FolioYjsSnapshotMigrationError({
|
|
78
|
+
cause,
|
|
79
|
+
code: "unsupported_version",
|
|
80
|
+
message: cause instanceof FolioYjsNoteReferenceSchemaError ? cause.message : "Cannot migrate the collaboration attribute schema."
|
|
81
|
+
})
|
|
82
|
+
});
|
|
83
|
+
if (migratedAttrs.isErr()) {
|
|
84
|
+
ydoc.destroy();
|
|
85
|
+
return Result.err(migratedAttrs.error);
|
|
86
|
+
}
|
|
87
|
+
if (fromVersion === 12) {
|
|
76
88
|
ydoc.destroy();
|
|
77
89
|
return Result.ok({
|
|
78
90
|
fromVersion,
|
|
79
91
|
paragraphsRewritten: 0,
|
|
80
|
-
toVersion:
|
|
92
|
+
toVersion: 12,
|
|
81
93
|
update
|
|
82
94
|
});
|
|
83
95
|
}
|
|
84
|
-
const paragraphsRewritten =
|
|
96
|
+
const paragraphsRewritten = migratedAttrs.value;
|
|
85
97
|
const migrated = Y.encodeStateAsUpdate(ydoc);
|
|
86
98
|
ydoc.destroy();
|
|
87
99
|
return Result.ok({
|
|
88
100
|
fromVersion,
|
|
89
101
|
paragraphsRewritten,
|
|
90
|
-
toVersion:
|
|
102
|
+
toVersion: 12,
|
|
91
103
|
update: migrated
|
|
92
104
|
});
|
|
93
105
|
};
|
|
@@ -337,6 +337,10 @@ const messages = { "folio": {
|
|
|
337
337
|
"editor": {
|
|
338
338
|
"editing": "تحرير",
|
|
339
339
|
"editingDescription": "تحرير المستند مباشرةً",
|
|
340
|
+
"outlineDepthAll": "كل المستويات",
|
|
341
|
+
"outlineDepthLabel": "إظهار العناوين",
|
|
342
|
+
"outlineDepthThree": "المستويات 1–3",
|
|
343
|
+
"outlineDepthTwo": "المستويان 1–2",
|
|
340
344
|
"outlineTitle": "المخطط",
|
|
341
345
|
"showDocumentOutline": "مخطط المستند",
|
|
342
346
|
"suggesting": "تعقب التغييرات",
|