@stll/folio-core 0.47.7 → 0.49.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 +565 -121
- package/dist/ai-edits/minimal-replacement.d.ts +64 -0
- package/dist/ai-edits/minimal-replacement.js +282 -0
- package/dist/controller/fontReadiness.js +3 -3
- package/dist/controller/hyphenationReadiness.d.ts +19 -0
- package/dist/controller/hyphenationReadiness.js +47 -0
- package/dist/controller/layoutPipeline.d.ts +3 -0
- package/dist/controller/layoutPipeline.js +70 -18
- package/dist/display-list/build/buildDisplayList.js +39 -12
- package/dist/display-list/build/pageFurniture.d.ts +7 -1
- package/dist/display-list/build/pageFurniture.js +21 -8
- package/dist/display-list/build/paragraphPrimitives.js +68 -11
- package/dist/display-list/build/tablePrimitives.js +10 -6
- package/dist/display-list/build/textBoxPrimitives.js +1 -1
- package/dist/display-list/build/unsupported.d.ts +2 -2
- package/dist/display-list/build/unsupported.js +0 -0
- package/dist/display-list/dom/renderDisplayListToDom.js +0 -1
- package/dist/docx/attributeRemainder.js +10 -2
- package/dist/docx/blockContentParser.d.ts +2 -0
- package/dist/docx/blockContentParser.js +79 -64
- package/dist/docx/bulletMarkers.d.ts +18 -2
- package/dist/docx/bulletMarkers.js +27 -2
- package/dist/docx/commentParser.d.ts +2 -1
- package/dist/docx/commentParser.js +57 -45
- package/dist/docx/containerChildren.d.ts +21 -8
- package/dist/docx/containerChildren.js +39 -9
- package/dist/docx/documentParser.d.ts +5 -1
- package/dist/docx/documentParser.js +8 -5
- package/dist/docx/documentSectionFacts.d.ts +22 -0
- package/dist/docx/documentSectionFacts.js +43 -0
- package/dist/docx/drawingGroupChildren.d.ts +60 -0
- package/dist/docx/drawingGroupChildren.js +176 -0
- package/dist/docx/drawingUtils.js +3 -0
- package/dist/docx/fieldParser.d.ts +8 -1
- package/dist/docx/fieldParser.js +47 -3
- package/dist/docx/fontTableParser.js +34 -27
- package/dist/docx/footnoteParser.d.ts +3 -2
- package/dist/docx/footnoteParser.js +15 -12
- package/dist/docx/groupDrawingParser.d.ts +9 -2
- package/dist/docx/groupDrawingParser.js +125 -37
- package/dist/docx/headerFooterParser.d.ts +7 -2
- package/dist/docx/headerFooterParser.js +15 -5
- package/dist/docx/hyperlinkParser.d.ts +48 -36
- package/dist/docx/hyperlinkParser.js +97 -82
- package/dist/docx/numberingParser.js +108 -84
- package/dist/docx/packageParts.d.ts +45 -1
- package/dist/docx/packageParts.js +93 -2
- package/dist/docx/paraIdAttribute.d.ts +3 -2
- package/dist/docx/paragraphParser.d.ts +5 -1
- package/dist/docx/paragraphParser.js +468 -365
- package/dist/docx/paragraphProperties.js +123 -109
- package/dist/docx/paragraphPropertySource.d.ts +6 -1
- package/dist/docx/paragraphPropertySource.js +9 -1
- package/dist/docx/paragraphTextBoxEnrichment.d.ts +2 -1
- package/dist/docx/paragraphTextBoxEnrichment.js +143 -10
- package/dist/docx/parser.d.ts +7 -1
- package/dist/docx/parser.js +33 -16
- package/dist/docx/previewBudget.d.ts +55 -33
- package/dist/docx/previewBudget.js +59 -65
- package/dist/docx/rezip.js +41 -58
- package/dist/docx/runParser.d.ts +4 -1
- package/dist/docx/runParser.js +182 -184
- package/dist/docx/sdtProperties.js +87 -84
- package/dist/docx/sectionParser.js +169 -160
- package/dist/docx/selectiveSaveFlags.d.ts +10 -3
- package/dist/docx/selectiveSaveFlags.js +1 -1
- package/dist/docx/selectiveXmlPatch.d.ts +56 -34
- package/dist/docx/selectiveXmlPatch.js +222 -115
- package/dist/docx/serializer/groupTextBoxWriteBack.d.ts +12 -0
- package/dist/docx/serializer/groupTextBoxWriteBack.js +101 -0
- package/dist/docx/serializer/paragraphSerializer.js +47 -42
- package/dist/docx/serializer/runSerializer.d.ts +5 -1
- package/dist/docx/serializer/runSerializer.js +4 -3
- package/dist/docx/serializer/settingsSerializer.js +19 -1
- package/dist/docx/settingsParser.js +8 -0
- package/dist/docx/shapeAlternateContent.d.ts +25 -0
- package/dist/docx/shapeAlternateContent.js +52 -0
- package/dist/docx/streamingXmlParser.d.ts +6 -2
- package/dist/docx/streamingXmlParser.js +12 -7
- package/dist/docx/styleParser.js +34 -8
- package/dist/docx/tableParser.d.ts +21 -12
- package/dist/docx/tableParser.js +518 -441
- package/dist/docx/textBoxParser.d.ts +18 -5
- package/dist/docx/textBoxParser.js +12 -6
- package/dist/docx/verbatimCapture.d.ts +10 -8
- package/dist/docx/verbatimCapture.js +45 -2
- package/dist/docx/vmlImageParser.d.ts +15 -13
- package/dist/docx/vmlImageParser.js +75 -60
- package/dist/docx/vmlPreview.d.ts +3 -3
- package/dist/docx/vmlPreview.js +3 -4
- package/dist/docx/xmlNamespaceContext.d.ts +9 -0
- package/dist/docx/xmlNamespaceContext.js +54 -0
- package/dist/docx/xmlParser.d.ts +6 -3
- package/dist/docx/xmlParser.js +11 -41
- package/dist/docx/xmlResourceLimits.d.ts +2 -1
- package/dist/docx/xmlResourceLimits.js +4 -1
- package/dist/fonts/headlessMeasure.js +0 -0
- package/dist/headless-layout.d.ts +11 -2
- package/dist/headless-layout.js +153 -107
- package/dist/internal/headlessRevisionResolution.js +50 -13
- package/dist/internal/paragraphFormattingSerialization.js +3 -3
- package/dist/layout-bridge/convert/endnoteLayout.d.ts +65 -0
- package/dist/layout-bridge/convert/endnoteLayout.js +227 -0
- package/dist/layout-bridge/convert/footnoteLayout.d.ts +19 -3
- package/dist/layout-bridge/convert/footnoteLayout.js +40 -31
- package/dist/layout-bridge/convert/headerFooterLayout.d.ts +1 -7
- package/dist/layout-bridge/convert/headerFooterLayout.js +5 -20
- package/dist/layout-bridge/convert/paragraphMarkFormatting.d.ts +10 -0
- package/dist/layout-bridge/convert/paragraphMarkFormatting.js +59 -0
- package/dist/layout-bridge/convert/toFlowBlocks.d.ts +29 -1
- package/dist/layout-bridge/convert/toFlowBlocks.js +284 -39
- package/dist/layout-bridge/engine/hitTest.js +5 -3
- package/dist/layout-bridge/engine/selectionRects.js +5 -3
- package/dist/layout-engine/anchorLayoutInCellCompatibility.d.ts +10 -0
- package/dist/layout-engine/anchorLayoutInCellCompatibility.js +22 -0
- package/dist/layout-engine/index.d.ts +2 -2
- package/dist/layout-engine/index.js +102 -14
- package/dist/layout-engine/justificationCompatibility.d.ts +1 -1
- package/dist/layout-engine/justificationCompatibility.js +9 -5
- package/dist/layout-engine/keep-together.d.ts +15 -6
- package/dist/layout-engine/keep-together.js +43 -16
- package/dist/layout-engine/layoutInstrumentation.d.ts +8 -2
- package/dist/layout-engine/layoutInstrumentation.js +8 -1
- package/dist/layout-engine/measure/advanceComposition.js +50 -7
- package/dist/layout-engine/measure/hyphenationDictionaries.d.ts +74 -0
- package/dist/layout-engine/measure/hyphenationDictionaries.js +138 -0
- package/dist/layout-engine/measure/hyphenationPreload.d.ts +11 -0
- package/dist/layout-engine/measure/hyphenationPreload.js +24 -0
- package/dist/layout-engine/measure/lineBreakProvider.d.ts +12 -2
- package/dist/layout-engine/measure/lineBreakProvider.js +30 -30
- package/dist/layout-engine/measure/lineBreaks.d.ts +6 -1
- package/dist/layout-engine/measure/lineBreaks.js +10 -3
- package/dist/layout-engine/measure/listMarkerWidth.d.ts +9 -6
- package/dist/layout-engine/measure/listMarkerWidth.js +20 -22
- package/dist/layout-engine/measure/measureBlocks.js +46 -10
- package/dist/layout-engine/measure/measureContainer.js +51 -8
- package/dist/layout-engine/measure/measureHelpers.d.ts +15 -3
- package/dist/layout-engine/measure/measureHelpers.js +34 -8
- package/dist/layout-engine/measure/measureParagraph.js +143 -101
- package/dist/layout-engine/measure/measureTypes.d.ts +5 -0
- package/dist/layout-engine/measure/smallCapsCasing.d.ts +56 -0
- package/dist/layout-engine/measure/smallCapsCasing.js +88 -0
- package/dist/layout-engine/measure/tabCalculator.d.ts +2 -0
- package/dist/layout-engine/measure/tabCalculator.js +2 -1
- package/dist/layout-engine/measure/tableCellFloating.d.ts +2 -0
- package/dist/layout-engine/measure/tableCellFloating.js +51 -19
- package/dist/layout-engine/measure/tableCellGrid.d.ts +28 -3
- package/dist/layout-engine/measure/tableCellGrid.js +45 -5
- package/dist/layout-engine/measure/tableFragmentBorderGeometry.js +2 -1
- package/dist/layout-engine/noteAreaFlow.d.ts +19 -0
- package/dist/layout-engine/noteAreaFlow.js +83 -0
- package/dist/layout-engine/paginator.d.ts +12 -1
- package/dist/layout-engine/paginator.js +18 -2
- package/dist/layout-engine/paragraphSpacing.d.ts +4 -2
- package/dist/layout-engine/paragraphSpacing.js +2 -1
- package/dist/layout-engine/tableRowBreak.d.ts +8 -1
- package/dist/layout-engine/tableRowBreak.js +25 -2
- package/dist/layout-engine/types.d.ts +108 -3
- package/dist/layout-engine/types.js +96 -1
- package/dist/layout-painter/index.d.ts +3 -0
- package/dist/layout-painter/renderPage.js +32 -83
- package/dist/layout-painter/renderParagraph.d.ts +6 -1
- package/dist/layout-painter/renderParagraph.js +75 -26
- package/dist/layout-painter/renderTable.js +26 -13
- package/dist/layout-painter/renderTextBox.d.ts +12 -2
- package/dist/layout-painter/renderTextBox.js +26 -2
- package/dist/prosemirror/alternateContentAttrs.d.ts +9 -0
- package/dist/prosemirror/alternateContentAttrs.js +35 -0
- package/dist/prosemirror/attrs/index.d.ts +9 -9
- package/dist/prosemirror/attrs/index.js +133 -11
- package/dist/prosemirror/commands/comments.js +51 -41
- package/dist/prosemirror/contentControlRevisions.d.ts +43 -0
- package/dist/prosemirror/contentControlRevisions.js +84 -0
- package/dist/prosemirror/conversion/fromProseDoc.js +54 -23
- package/dist/prosemirror/conversion/markInterner.d.ts +21 -0
- package/dist/prosemirror/conversion/markInterner.js +90 -0
- package/dist/prosemirror/conversion/toProseDoc.js +117 -58
- package/dist/prosemirror/extensions/core/DocExtension.js +2 -1
- package/dist/prosemirror/extensions/core/ParagraphExtension.js +1 -0
- package/dist/prosemirror/extensions/features/AutoBidiDetectionExtension.d.ts +7 -7
- package/dist/prosemirror/extensions/features/AutoBidiDetectionExtension.js +7 -7
- package/dist/prosemirror/extensions/marks/markUtils.d.ts +6 -2
- package/dist/prosemirror/extensions/marks/markUtils.js +39 -51
- package/dist/prosemirror/extensions/nodes/FieldExtension.js +6 -3
- package/dist/prosemirror/extensions/nodes/SdtExtension.js +9 -2
- package/dist/prosemirror/extensions/nodes/ShapeExtension.js +1 -0
- package/dist/prosemirror/extensions/nodes/TextBoxExtension.js +5 -1
- package/dist/prosemirror/listMarker.d.ts +1 -0
- package/dist/prosemirror/listMarker.js +4 -2
- package/dist/prosemirror/listRenderingAttrs.d.ts +1 -0
- package/dist/prosemirror/listRenderingAttrs.js +3 -0
- package/dist/prosemirror/paragraphDirection.d.ts +29 -2
- package/dist/prosemirror/paragraphDirection.js +21 -2
- package/dist/prosemirror/plugins/suggestionMode.js +37 -8
- package/dist/prosemirror/rejoinRunCarriers.d.ts +27 -0
- package/dist/prosemirror/rejoinRunCarriers.js +66 -0
- package/dist/prosemirror/runIdentityAcrossRevisions.d.ts +10 -0
- package/dist/prosemirror/runIdentityAcrossRevisions.js +90 -0
- package/dist/prosemirror/schema/nodes.d.ts +50 -6
- package/dist/prosemirror/textBoxHostParagraph.d.ts +13 -0
- package/dist/prosemirror/textBoxHostParagraph.js +21 -0
- package/dist/prosemirror/validation.js +91 -80
- package/dist/types/content.d.ts +2 -2
- package/dist/utils/createDocument.js +10 -1
- package/dist/utils/scriptSegments.d.ts +33 -4
- package/dist/utils/scriptSegments.js +39 -6
- package/dist/utils/textFormattingMerge.d.ts +17 -3
- package/dist/utils/textFormattingMerge.js +18 -12
- package/dist/utils/trailingText.d.ts +22 -0
- package/dist/utils/trailingText.js +32 -0
- package/package.json +2 -2
- package/dist/layout-engine/justifiedLineFit.d.ts +0 -7
- package/dist/layout-engine/justifiedLineFit.js +0 -6
|
@@ -14,6 +14,7 @@ import { panic } from "better-result";
|
|
|
14
14
|
import { DRAWING_RAW_XML_MODES, THEME_COLORS, isOoxmlSymbolCharacter } from "@stll/docx-core/model";
|
|
15
15
|
import { isSafePreservedChildXml, isWithinPreservedMarkupBudget } from "@stll/docx-core/schema";
|
|
16
16
|
//#region src/prosemirror/attrs/index.ts
|
|
17
|
+
const RUN_FORMATTING_VALUE_PROPERTY_SET = new Set(RUN_FORMATTING_VALUE_PROPERTIES);
|
|
17
18
|
const PRESERVED_XML_LEVEL_VALUES = new Set(Object.values(PRESERVED_XML_LEVELS));
|
|
18
19
|
const IMAGE_DISPLAY_MODES = [
|
|
19
20
|
"inline",
|
|
@@ -149,15 +150,12 @@ const SECTION_VERTICAL_ALIGNMENTS = [
|
|
|
149
150
|
"bottom"
|
|
150
151
|
];
|
|
151
152
|
const OMITTED_GRID_SLOT_VALUES = ["before", "after"];
|
|
152
|
-
const paragraphAttrsCache = /* @__PURE__ */ new WeakMap();
|
|
153
153
|
const hardBreakAttrsCache = /* @__PURE__ */ new WeakMap();
|
|
154
154
|
const pageBreakRunAttrsCache = /* @__PURE__ */ new WeakMap();
|
|
155
155
|
const tabAttrsCache = /* @__PURE__ */ new WeakMap();
|
|
156
156
|
const symbolAttrsCache = /* @__PURE__ */ new WeakMap();
|
|
157
157
|
const preservedXmlAttrsCache = /* @__PURE__ */ new WeakMap();
|
|
158
158
|
const preservedBlockAttrsCache = /* @__PURE__ */ new WeakMap();
|
|
159
|
-
const tableAttrsCache = /* @__PURE__ */ new WeakMap();
|
|
160
|
-
const tableRowAttrsCache = /* @__PURE__ */ new WeakMap();
|
|
161
159
|
const tableCellAttrsCache = /* @__PURE__ */ new WeakMap();
|
|
162
160
|
const imageAttrsCache = /* @__PURE__ */ new WeakMap();
|
|
163
161
|
const fieldAttrsCache = /* @__PURE__ */ new WeakMap();
|
|
@@ -185,7 +183,36 @@ const runIdentityAttrsCache = /* @__PURE__ */ new WeakMap();
|
|
|
185
183
|
const inlineWrapperAttrsCache = /* @__PURE__ */ new WeakMap();
|
|
186
184
|
const runFormattingOverrideAttrsCache = /* @__PURE__ */ new WeakMap();
|
|
187
185
|
const hyperlinkAttrsCache = /* @__PURE__ */ new WeakMap();
|
|
188
|
-
|
|
186
|
+
/**
|
|
187
|
+
* Read a node's attrs once per node. Nodes are immutable, and one conversion
|
|
188
|
+
* reads each paragraph, table and row several times (node validation, the
|
|
189
|
+
* bookmark walk, numbering). The cached result is frozen, value and issues
|
|
190
|
+
* included, so no caller can change what the next one reads.
|
|
191
|
+
*/
|
|
192
|
+
const memoizeNodeAttrsReader = (read) => {
|
|
193
|
+
const results = /* @__PURE__ */ new WeakMap();
|
|
194
|
+
return (node) => {
|
|
195
|
+
const cached = results.get(node);
|
|
196
|
+
if (cached !== void 0) return cached;
|
|
197
|
+
const result = freezeAttrsResult(read(node));
|
|
198
|
+
results.set(node, result);
|
|
199
|
+
return result;
|
|
200
|
+
};
|
|
201
|
+
};
|
|
202
|
+
const freezeAttrsResult = (result) => {
|
|
203
|
+
if (!result.ok) {
|
|
204
|
+
const issues = result.issues.map((issue) => Object.freeze({ ...issue }));
|
|
205
|
+
return Object.freeze({
|
|
206
|
+
ok: false,
|
|
207
|
+
issues: Object.freeze(issues)
|
|
208
|
+
});
|
|
209
|
+
}
|
|
210
|
+
return Object.freeze({
|
|
211
|
+
ok: true,
|
|
212
|
+
value: Object.freeze(result.value)
|
|
213
|
+
});
|
|
214
|
+
};
|
|
215
|
+
const readParagraphAttrsUncached = (node) => {
|
|
189
216
|
const attrs = attrsRecord(node.attrs);
|
|
190
217
|
const issues = [];
|
|
191
218
|
expectNodeType(node, "paragraph", issues);
|
|
@@ -244,6 +271,7 @@ const readParagraphAttrs = (node) => {
|
|
|
244
271
|
});
|
|
245
272
|
optionalStringArray(attrs, "listLevelNumFmts", "paragraph.attrs.listLevelNumFmts", issues);
|
|
246
273
|
optionalNumberArray(attrs, "listLevelStarts", "paragraph.attrs.listLevelStarts", issues);
|
|
274
|
+
optionalTabStops(attrs, "listLevelTabs", "paragraph.attrs.listLevelTabs", issues);
|
|
247
275
|
optionalNumber(attrs, "listAbstractNumId", "paragraph.attrs.listAbstractNumId", issues);
|
|
248
276
|
optionalBorderMap(attrs, "borders", "paragraph.attrs.borders", issues, [
|
|
249
277
|
"top",
|
|
@@ -271,7 +299,8 @@ const readParagraphAttrs = (node) => {
|
|
|
271
299
|
optionalPreservedAttributes(attrs, "_preservedAttributes", "paragraph.attrs._preservedAttributes", issues);
|
|
272
300
|
return attrsResult(attrs, issues);
|
|
273
301
|
};
|
|
274
|
-
const
|
|
302
|
+
const readParagraphAttrs = memoizeNodeAttrsReader(readParagraphAttrsUncached);
|
|
303
|
+
const expectParagraphAttrs = (node) => expectAttrs(readParagraphAttrs(node), "paragraph attrs");
|
|
275
304
|
const readHardBreakAttrs = (node) => {
|
|
276
305
|
const attrs = attrsRecord(node.attrs);
|
|
277
306
|
const issues = [];
|
|
@@ -348,7 +377,7 @@ const readPreservedBlockAttrs = (node) => {
|
|
|
348
377
|
return attrsResult(attrs, issues);
|
|
349
378
|
};
|
|
350
379
|
const expectPreservedBlockAttrs = (node) => expectCachedNodeAttrs(node, preservedBlockAttrsCache, readPreservedBlockAttrs, "preservedBlock attrs");
|
|
351
|
-
const
|
|
380
|
+
const readTableAttrsUncached = (node) => {
|
|
352
381
|
const attrs = attrsRecord(node.attrs);
|
|
353
382
|
const issues = [];
|
|
354
383
|
expectNodeType(node, "table", issues);
|
|
@@ -375,8 +404,9 @@ const readTableAttrs = (node) => {
|
|
|
375
404
|
optionalTablePreservedMarkup(attrs, "_preserved", "table.attrs._preserved", issues);
|
|
376
405
|
return attrsResult(attrs, issues);
|
|
377
406
|
};
|
|
378
|
-
const
|
|
379
|
-
const
|
|
407
|
+
const readTableAttrs = memoizeNodeAttrsReader(readTableAttrsUncached);
|
|
408
|
+
const expectTableAttrs = (node) => expectAttrs(readTableAttrs(node), "table attrs");
|
|
409
|
+
const readTableRowAttrsUncached = (node) => {
|
|
380
410
|
const attrs = attrsRecord(node.attrs);
|
|
381
411
|
const issues = [];
|
|
382
412
|
expectNodeType(node, "tableRow", issues);
|
|
@@ -399,7 +429,8 @@ const readTableRowAttrs = (node) => {
|
|
|
399
429
|
optionalTablePreservedMarkup(attrs, "_preserved", "tableRow.attrs._preserved", issues);
|
|
400
430
|
return attrsResult(attrs, issues);
|
|
401
431
|
};
|
|
402
|
-
const
|
|
432
|
+
const readTableRowAttrs = memoizeNodeAttrsReader(readTableRowAttrsUncached);
|
|
433
|
+
const expectTableRowAttrs = (node) => expectAttrs(readTableRowAttrs(node), "table row attrs");
|
|
403
434
|
const readTableCellAttrs = (node) => {
|
|
404
435
|
const attrs = attrsRecord(node.attrs);
|
|
405
436
|
const issues = [];
|
|
@@ -509,6 +540,7 @@ const readFieldAttrs = (node) => {
|
|
|
509
540
|
requiredOneOf(attrs, "fieldKind", "field.attrs.fieldKind", issues, FIELD_KINDS);
|
|
510
541
|
optionalBoolean(attrs, "fldLock", "field.attrs.fldLock", issues);
|
|
511
542
|
optionalBoolean(attrs, "dirty", "field.attrs.dirty", issues);
|
|
543
|
+
optionalBoolean(attrs, "fieldResultIsFallback", "field.attrs.fieldResultIsFallback", issues);
|
|
512
544
|
return attrsResult(attrs, issues);
|
|
513
545
|
};
|
|
514
546
|
const expectFieldAttrs = (node) => expectCachedNodeAttrs(node, fieldAttrsCache, readFieldAttrs, "field attrs");
|
|
@@ -606,6 +638,7 @@ const readShapeAttrs = (node) => {
|
|
|
606
638
|
optionalNumber(attrs, "shadowOffsetY", "shape.attrs.shadowOffsetY", issues);
|
|
607
639
|
optionalString(attrs, "glowColor", "shape.attrs.glowColor", issues);
|
|
608
640
|
optionalNumber(attrs, "glowRadius", "shape.attrs.glowRadius", issues);
|
|
641
|
+
optionalAlternateContent(attrs, "shape.attrs._docxAlternateContent", issues);
|
|
609
642
|
return attrsResult(attrs, issues);
|
|
610
643
|
};
|
|
611
644
|
const expectShapeAttrs = (node) => expectCachedNodeAttrs(node, shapeAttrsCache, readShapeAttrs, "shape attrs");
|
|
@@ -623,6 +656,7 @@ const readTextBoxAttrs = (node) => {
|
|
|
623
656
|
optionalString(attrs, "alt", "textBox.attrs.alt", issues);
|
|
624
657
|
optionalString(attrs, "title", "textBox.attrs.title", issues);
|
|
625
658
|
optionalString(attrs, "fillColor", "textBox.attrs.fillColor", issues);
|
|
659
|
+
optionalGradientFill(attrs, "gradientFill", "textBox.attrs.gradientFill", issues);
|
|
626
660
|
optionalNumber(attrs, "outlineWidth", "textBox.attrs.outlineWidth", issues);
|
|
627
661
|
optionalAuthoredEmu(attrs, "_docxAuthoredEmu", "textBox.attrs._docxAuthoredEmu", issues, TEXT_BOX_AUTHORED_EMU_ATTRS);
|
|
628
662
|
optionalString(attrs, "outlineColor", "textBox.attrs.outlineColor", issues);
|
|
@@ -650,12 +684,15 @@ const readTextBoxAttrs = (node) => {
|
|
|
650
684
|
optionalEffectExtentSlots(attrs, "wrapEffectExtentSlots", "textBox.attrs.wrapEffectExtentSlots", issues);
|
|
651
685
|
optionalWrapPolygon(attrs, "wrapPolygon", "textBox.attrs.wrapPolygon", issues);
|
|
652
686
|
optionalOneOf(attrs, "_docxPlacement", "textBox.attrs._docxPlacement", issues, TEXT_BOX_DOCX_PLACEMENTS);
|
|
687
|
+
optionalAlternateContent(attrs, "textBox.attrs._docxAlternateContent", issues);
|
|
653
688
|
optionalString(attrs, "_docxGroupId", "textBox.attrs._docxGroupId", issues);
|
|
654
689
|
optionalString(attrs, "_docxAnchorId", "textBox.attrs._docxAnchorId", issues);
|
|
690
|
+
optionalDrawingGroupChild(attrs, "_docxGroupChild", "textBox.attrs._docxGroupChild", issues);
|
|
655
691
|
requiredTextBoxBodyContentState(attrs, issues);
|
|
656
692
|
optionalTextBoxTrackedChange(attrs, issues);
|
|
657
693
|
optionalTextBoxInlineSdts(attrs, issues);
|
|
658
694
|
optionalPreservedAttributes(attrs, "_preservedAttributes", "textBox.attrs._preservedAttributes", issues);
|
|
695
|
+
optionalRecord(attrs, "_docxHostParagraph", "textBox.attrs._docxHostParagraph", issues);
|
|
659
696
|
return attrsResult(attrs, issues);
|
|
660
697
|
};
|
|
661
698
|
const expectTextBoxAttrs = (node) => expectCachedNodeAttrs(node, textBoxAttrsCache, readTextBoxAttrs, "text box attrs");
|
|
@@ -1042,8 +1079,7 @@ const readRunFormattingOverrideMarkAttrs = (mark) => {
|
|
|
1042
1079
|
optionalTextFormatting(attrs, "_authoredValues", "runFormattingOverride.attrs._authoredValues", issues);
|
|
1043
1080
|
const authoredValues = attrs["_authoredValues"];
|
|
1044
1081
|
if (isRecord(authoredValues)) {
|
|
1045
|
-
const
|
|
1046
|
-
for (const property of Object.keys(authoredValues)) if (!allowed.has(property)) issues.push({
|
|
1082
|
+
for (const property of Object.keys(authoredValues)) if (!RUN_FORMATTING_VALUE_PROPERTY_SET.has(property)) issues.push({
|
|
1047
1083
|
path: `runFormattingOverride.attrs._authoredValues.${property}`,
|
|
1048
1084
|
message: "Expected a non-boolean authored formatting property."
|
|
1049
1085
|
});
|
|
@@ -1587,6 +1623,20 @@ const optionalTextBoxTrackedChange = (attrs, issues) => {
|
|
|
1587
1623
|
requiredString(info, "author", "textBox.attrs._docxTrackedChange.info.author", issues);
|
|
1588
1624
|
optionalString(info, "date", "textBox.attrs._docxTrackedChange.info.date", issues);
|
|
1589
1625
|
};
|
|
1626
|
+
/** `_docxAlternateContent`: a captured element and its node fingerprint, or absent. */
|
|
1627
|
+
const optionalAlternateContent = (attrs, path, issues) => {
|
|
1628
|
+
const value = attrs["_docxAlternateContent"];
|
|
1629
|
+
if (value === void 0 || value === null) return;
|
|
1630
|
+
if (!isRecord(value)) {
|
|
1631
|
+
issues.push({
|
|
1632
|
+
path,
|
|
1633
|
+
message: "Expected an object."
|
|
1634
|
+
});
|
|
1635
|
+
return;
|
|
1636
|
+
}
|
|
1637
|
+
requiredString(value, "xml", `${path}.xml`, issues);
|
|
1638
|
+
requiredString(value, "fingerprint", `${path}.fingerprint`, issues);
|
|
1639
|
+
};
|
|
1590
1640
|
const requiredTextBoxBodyContentState = (attrs, issues) => {
|
|
1591
1641
|
const value = attrs["_docxTextBodyContentState"];
|
|
1592
1642
|
if (!isRecord(value)) {
|
|
@@ -1636,6 +1686,7 @@ const validateSdtAttrsRecord = (attrs, path, issues) => {
|
|
|
1636
1686
|
optionalPreservedMarkup(attrs, "_preserved", `${path}._preserved`, issues);
|
|
1637
1687
|
optionalString(attrs, "rawEndPropertiesXml", `${path}.rawEndPropertiesXml`, issues);
|
|
1638
1688
|
optionalSdtEndProperties(attrs, `${path}.endProperties`, issues);
|
|
1689
|
+
optionalNumberArray(attrs, "_docxEnclosingRevisionIds", `${path}._docxEnclosingRevisionIds`, issues);
|
|
1639
1690
|
};
|
|
1640
1691
|
/**
|
|
1641
1692
|
* The attribute remainder an authored element's record carries.
|
|
@@ -2199,6 +2250,7 @@ const validateParagraphFormatting = (value, path, issues) => {
|
|
|
2199
2250
|
]);
|
|
2200
2251
|
optionalOneOfArray(value, "listLevelNumFmts", `${path}.listLevelNumFmts`, issues, COUNTER_FORMAT_VALUES);
|
|
2201
2252
|
optionalNumberArray(value, "listLevelStarts", `${path}.listLevelStarts`, issues);
|
|
2253
|
+
optionalTabStops(value, "listLevelTabs", `${path}.listLevelTabs`, issues);
|
|
2202
2254
|
optionalAutospacingBase(value, `${path}._autospacingBase`, issues);
|
|
2203
2255
|
for (const key of ["numPr", "numPrFromStyle"]) optionalParagraphNumbering(value, key, `${path}.${key}`, issues);
|
|
2204
2256
|
const direction = value["direction"];
|
|
@@ -2523,6 +2575,76 @@ const optionalWrapPolygon = (attrs, key, path, issues) => {
|
|
|
2523
2575
|
readWrapPolygonPoint(point, `${path}.lineTo[${index}]`, issues);
|
|
2524
2576
|
});
|
|
2525
2577
|
};
|
|
2578
|
+
/** A text box's gradient fill: the model's `ShapeFill`, and only its gradient arm. */
|
|
2579
|
+
const optionalGradientFill = (attrs, key, path, issues) => {
|
|
2580
|
+
const value = attrs[key];
|
|
2581
|
+
if (value === void 0 || value === null) return;
|
|
2582
|
+
if (!isRecord(value)) {
|
|
2583
|
+
issues.push({
|
|
2584
|
+
path,
|
|
2585
|
+
message: "Expected an object."
|
|
2586
|
+
});
|
|
2587
|
+
return;
|
|
2588
|
+
}
|
|
2589
|
+
if (value["type"] !== "gradient") issues.push({
|
|
2590
|
+
path: `${path}.type`,
|
|
2591
|
+
message: "Expected \"gradient\"."
|
|
2592
|
+
});
|
|
2593
|
+
optionalString(value, "rawXml", `${path}.rawXml`, issues);
|
|
2594
|
+
const gradient = value["gradient"];
|
|
2595
|
+
if (!isRecord(gradient)) {
|
|
2596
|
+
issues.push({
|
|
2597
|
+
path: `${path}.gradient`,
|
|
2598
|
+
message: "Expected an object."
|
|
2599
|
+
});
|
|
2600
|
+
return;
|
|
2601
|
+
}
|
|
2602
|
+
optionalOneOf(gradient, "type", `${path}.gradient.type`, issues, SHAPE_GRADIENT_TYPES);
|
|
2603
|
+
optionalNumber(gradient, "angle", `${path}.gradient.angle`, issues);
|
|
2604
|
+
optionalBoolean(gradient, "scaled", `${path}.gradient.scaled`, issues);
|
|
2605
|
+
const stops = gradient["stops"];
|
|
2606
|
+
if (!Array.isArray(stops)) {
|
|
2607
|
+
issues.push({
|
|
2608
|
+
path: `${path}.gradient.stops`,
|
|
2609
|
+
message: "Expected an array."
|
|
2610
|
+
});
|
|
2611
|
+
return;
|
|
2612
|
+
}
|
|
2613
|
+
stops.forEach((stop, index) => {
|
|
2614
|
+
const stopPath = `${path}.gradient.stops[${index}]`;
|
|
2615
|
+
if (!isRecord(stop)) {
|
|
2616
|
+
issues.push({
|
|
2617
|
+
path: stopPath,
|
|
2618
|
+
message: "Expected a gradient stop object."
|
|
2619
|
+
});
|
|
2620
|
+
return;
|
|
2621
|
+
}
|
|
2622
|
+
if (typeof stop["position"] !== "number") issues.push({
|
|
2623
|
+
path: `${stopPath}.position`,
|
|
2624
|
+
message: "Expected a number."
|
|
2625
|
+
});
|
|
2626
|
+
optionalColorValue(stop, "color", `${stopPath}.color`, issues);
|
|
2627
|
+
});
|
|
2628
|
+
};
|
|
2629
|
+
/** Where a text box sits inside a DrawingML group: its element path and two fingerprints. */
|
|
2630
|
+
const optionalDrawingGroupChild = (attrs, key, path, issues) => {
|
|
2631
|
+
const value = attrs[key];
|
|
2632
|
+
if (value === void 0 || value === null) return;
|
|
2633
|
+
if (!isRecord(value)) {
|
|
2634
|
+
issues.push({
|
|
2635
|
+
path,
|
|
2636
|
+
message: "Expected an object."
|
|
2637
|
+
});
|
|
2638
|
+
return;
|
|
2639
|
+
}
|
|
2640
|
+
const childPath = value["path"];
|
|
2641
|
+
if (!Array.isArray(childPath) || childPath.length === 0 || !childPath.every((index) => Number.isInteger(index) && index >= 0)) issues.push({
|
|
2642
|
+
path: `${path}.path`,
|
|
2643
|
+
message: "Expected a non-empty array of indices."
|
|
2644
|
+
});
|
|
2645
|
+
requiredString(value, "group", `${path}.group`, issues);
|
|
2646
|
+
requiredString(value, "content", `${path}.content`, issues);
|
|
2647
|
+
};
|
|
2526
2648
|
/** `a:hlinkClick` as captured: its own bytes, plus the target it named. */
|
|
2527
2649
|
const optionalDocPrLink = (attrs, key, path, issues) => {
|
|
2528
2650
|
const value = attrs[key];
|
|
@@ -4,11 +4,13 @@ import { appendHeadlessInlineResolution } from "../../internal/headlessRevisionR
|
|
|
4
4
|
import { stateAllowsHeadlessRevisionResolution } from "../../internal/headlessRevisionResolutionGuard.js";
|
|
5
5
|
import { expectParagraphAttrs, expectRunPropertyChangeMarkAttrs, expectTrackedChangeMarkAttrs } from "../attrs/index.js";
|
|
6
6
|
import { addedBreakCarrierBefore, finalParagraphsOf, paragraphEndsItsContainer } from "../containerFinalParagraph.js";
|
|
7
|
+
import { enclosingRevisionIds, resolutionRemovesControl, withoutResolvedEnclosures } from "../contentControlRevisions.js";
|
|
7
8
|
import { resolveParagraphDefaultTextFormatting } from "../conversion/toProseDoc.js";
|
|
8
9
|
import { markChangedParagraphRanges, markStructuralChange, markTrackedSectionEndpointRemoval } from "../extensions/features/ParagraphChangeTrackerExtension.js";
|
|
9
10
|
import "../extensions/nodes/SdtExtension.js";
|
|
10
11
|
import { getDocumentStyleResolver } from "../plugins/documentStyles.js";
|
|
11
12
|
import { setParagraphAttrsWithRebasedRunFormatting } from "../rebaseParagraphRunFormatting.js";
|
|
13
|
+
import { rejoinRunsAt } from "../rejoinRunCarriers.js";
|
|
12
14
|
import { getFolioNodeRevisionCarriers, nodePropertyRevisionSites, propertyRevisionMetadata, propertyRevisionRecords } from "../revisionCarriers.js";
|
|
13
15
|
import { RUN_FORMATTING_MARK_NAMES } from "../runFormattingMarkNames.js";
|
|
14
16
|
import { reconstructRejectedRunFormattingMarks } from "../runPropertyChangeResolution.js";
|
|
@@ -109,6 +111,8 @@ function resolveChange(from, to, mode, revisionIds, execution = "legacy") {
|
|
|
109
111
|
if (dispatch) {
|
|
110
112
|
const tr = state.tr;
|
|
111
113
|
const deleteRanges = [];
|
|
114
|
+
/** Where resolved inline content began and ended, in `state.doc`. */
|
|
115
|
+
const resolvedBoundaries = [];
|
|
112
116
|
const pPrMarkOps = [];
|
|
113
117
|
const tableRowStructuralOps = [];
|
|
114
118
|
const tableCellStructuralOps = [];
|
|
@@ -198,15 +202,27 @@ function resolveChange(from, to, mode, revisionIds, execution = "legacy") {
|
|
|
198
202
|
const nodeEnd = pos + node.nodeSize;
|
|
199
203
|
const rangeFrom = Math.max(from, pos);
|
|
200
204
|
const rangeTo = Math.min(to, nodeEnd);
|
|
201
|
-
if (node.type.name === "sdt"
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
205
|
+
if (node.type.name === "sdt") {
|
|
206
|
+
if (!rangeCoversNode(from, to, pos, node)) return true;
|
|
207
|
+
const resolvesRevision = (revisionId) => revisionSet === null || revisionSet.has(revisionId);
|
|
208
|
+
if (resolutionRemovesControl({
|
|
209
|
+
control: node,
|
|
210
|
+
removeType,
|
|
211
|
+
resolves: resolvesRevision
|
|
212
|
+
})) {
|
|
213
|
+
deleteRanges.push({
|
|
214
|
+
from: pos,
|
|
215
|
+
to: nodeEnd
|
|
216
|
+
});
|
|
217
|
+
return false;
|
|
218
|
+
}
|
|
219
|
+
const released = withoutResolvedEnclosures(node, resolvesRevision);
|
|
220
|
+
if (released) tr.setNodeMarkup(pos, void 0, released);
|
|
221
|
+
return true;
|
|
207
222
|
}
|
|
208
223
|
const runPropertyChangeMark = node.marks.find((mark) => mark.type.name === "runPropertyChange");
|
|
209
224
|
const removesNode = removeType !== void 0 && node.marks.some((mark) => mark.type === removeType && matchesRevision(mark));
|
|
225
|
+
if (removesNode || runPropertyChangeMark !== void 0 || node.marks.some((mark) => (mark.type === insertionType || mark.type === deletionType) && matchesRevision(mark))) resolvedBoundaries.push(rangeFrom, rangeTo);
|
|
210
226
|
if (runPropertyChangeMark) resolveRunPropertyChange({
|
|
211
227
|
tr,
|
|
212
228
|
node,
|
|
@@ -386,6 +402,11 @@ function resolveChange(from, to, mode, revisionIds, execution = "legacy") {
|
|
|
386
402
|
removedReferences: removedSectionReferences
|
|
387
403
|
});
|
|
388
404
|
if (!terminalTableDeletionIsPending(tr)) resolveTerminalTableReviewCarrier(tr, mode);
|
|
405
|
+
rejoinRunsAt({
|
|
406
|
+
tr,
|
|
407
|
+
boundaries: resolvedBoundaries.map((position) => tr.mapping.map(position)),
|
|
408
|
+
styleResolver
|
|
409
|
+
});
|
|
389
410
|
if (tr.steps.length > 0) dispatch(tr);
|
|
390
411
|
}
|
|
391
412
|
return true;
|
|
@@ -620,24 +641,6 @@ function rangeCoversNode(from, to, pos, node) {
|
|
|
620
641
|
return from <= pos && to >= pos + node.nodeSize;
|
|
621
642
|
}
|
|
622
643
|
/**
|
|
623
|
-
* Whether a revision covers everything an inline content control holds.
|
|
624
|
-
*
|
|
625
|
-
* The save leg writes such a revision around the control (`w:ins > w:sdt`),
|
|
626
|
-
* so resolving it is an operation over the control itself: a reader who
|
|
627
|
-
* rejects an inserted control gets no control, not an empty one standing
|
|
628
|
-
* where it was. A revision over part of the content is a revision over that
|
|
629
|
-
* part, and a control that holds nothing is covered by nothing.
|
|
630
|
-
*/
|
|
631
|
-
function revisionCoversWholeControl(node, removeType, matchesRevision) {
|
|
632
|
-
if (node.childCount === 0) return false;
|
|
633
|
-
for (let index = 0; index < node.childCount; index += 1) {
|
|
634
|
-
const child = node.child(index);
|
|
635
|
-
if (child.marks.some((mark) => mark.type === removeType && matchesRevision(mark))) continue;
|
|
636
|
-
if (child.type.name !== "sdt" || !revisionCoversWholeControl(child, removeType, matchesRevision)) return false;
|
|
637
|
-
}
|
|
638
|
-
return true;
|
|
639
|
-
}
|
|
640
|
-
/**
|
|
641
644
|
* The attrs a reject restores for each property revision the shared node-attr
|
|
642
645
|
* pass owns. Total over those kinds, so a revision the model gains either
|
|
643
646
|
* declares a different resolution or states here what rejecting it restores.
|
|
@@ -826,6 +829,7 @@ function findAIEditRevisionRange(state, revisionIds) {
|
|
|
826
829
|
};
|
|
827
830
|
state.doc.descendants((node, pos) => {
|
|
828
831
|
for (const carrier of getFolioNodeRevisionCarriers(node, pos)) if (idSet.has(carrier.id)) includeRange(carrier.from, carrier.to);
|
|
832
|
+
if (node.type.name === "sdt" && enclosingRevisionIds(node).some((id) => idSet.has(id))) includeRange(pos, pos + node.nodeSize);
|
|
829
833
|
if (node.type.name === "tableRow") for (const attrName of ["trIns", "trDel"]) {
|
|
830
834
|
const marker = node.attrs[attrName];
|
|
831
835
|
if (isTableRowRevisionAttr(marker) && idSet.has(marker.revisionId)) {
|
|
@@ -1724,24 +1728,30 @@ function expandTrackedChangeRange(state, mark, fromHint, toHint) {
|
|
|
1724
1728
|
const carriesSameInlineMark = (node) => node?.isInline === true && node.marks.some((m) => m.eq(mark));
|
|
1725
1729
|
let from = fromHint;
|
|
1726
1730
|
let to = toHint;
|
|
1727
|
-
|
|
1728
|
-
|
|
1729
|
-
|
|
1730
|
-
|
|
1731
|
-
|
|
1732
|
-
|
|
1733
|
-
|
|
1734
|
-
|
|
1735
|
-
|
|
1736
|
-
|
|
1737
|
-
|
|
1738
|
-
|
|
1739
|
-
|
|
1731
|
+
const revisionId = mark.attrs["revisionId"];
|
|
1732
|
+
for (;;) {
|
|
1733
|
+
let $from = state.doc.resolve(from);
|
|
1734
|
+
let nodeBefore = $from.nodeBefore;
|
|
1735
|
+
while (carriesSameInlineMark(nodeBefore)) {
|
|
1736
|
+
from -= nodeBefore.nodeSize;
|
|
1737
|
+
$from = state.doc.resolve(from);
|
|
1738
|
+
nodeBefore = $from.nodeBefore;
|
|
1739
|
+
}
|
|
1740
|
+
let $to = state.doc.resolve(to);
|
|
1741
|
+
let nodeAfter = $to.nodeAfter;
|
|
1742
|
+
while (carriesSameInlineMark(nodeAfter)) {
|
|
1743
|
+
to += nodeAfter.nodeSize;
|
|
1744
|
+
$to = state.doc.resolve(to);
|
|
1745
|
+
nodeAfter = $to.nodeAfter;
|
|
1746
|
+
}
|
|
1747
|
+
const control = $from.parent;
|
|
1748
|
+
if (control.type.name !== "sdt" || typeof revisionId !== "number" || !enclosingRevisionIds(control).includes(revisionId) || from !== $from.start() || to !== $from.end()) return {
|
|
1749
|
+
from,
|
|
1750
|
+
to
|
|
1751
|
+
};
|
|
1752
|
+
from = $from.before();
|
|
1753
|
+
to = $from.after();
|
|
1740
1754
|
}
|
|
1741
|
-
return {
|
|
1742
|
-
from,
|
|
1743
|
-
to
|
|
1744
|
-
};
|
|
1745
1755
|
}
|
|
1746
1756
|
/**
|
|
1747
1757
|
* Find the next tracked change after the given position. Returns the full
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { Transaction } from "prosemirror-state";
|
|
2
|
+
import { MarkType, Node } from "prosemirror-model";
|
|
3
|
+
//#region src/prosemirror/contentControlRevisions.d.ts
|
|
4
|
+
declare const ENCLOSING_REVISION_IDS_ATTR = "_docxEnclosingRevisionIds";
|
|
5
|
+
/** The revisions whose element encloses `control`. */
|
|
6
|
+
declare const enclosingRevisionIds: (control: Node) => readonly number[];
|
|
7
|
+
/** `control`'s attrs with `revisionId` added to its enclosing revisions. */
|
|
8
|
+
declare const withEnclosingRevision: (control: Node, revisionId: number) => Node["attrs"] | null;
|
|
9
|
+
type ResolutionRemovesControlOptions = {
|
|
10
|
+
control: Node;
|
|
11
|
+
/** The revision mark type the resolution removes content under. */
|
|
12
|
+
removeType: MarkType | undefined;
|
|
13
|
+
/** Whether the resolution resolves revision `revisionId`. */
|
|
14
|
+
resolves: (revisionId: number) => boolean;
|
|
15
|
+
};
|
|
16
|
+
/**
|
|
17
|
+
* Whether resolving removes the control itself: a revision that encloses it is
|
|
18
|
+
* resolved in the direction that removes its content, and still covers all of
|
|
19
|
+
* it. Removing only the content leaves the control standing, emptied.
|
|
20
|
+
*/
|
|
21
|
+
declare const resolutionRemovesControl: ({ control, removeType, resolves }: ResolutionRemovesControlOptions) => boolean;
|
|
22
|
+
/**
|
|
23
|
+
* `control`'s attrs without the enclosing revisions `resolved` names, or
|
|
24
|
+
* `null` when none of them is: a resolved revision no longer exists, and an id
|
|
25
|
+
* left behind would claim whatever revision is later given that id.
|
|
26
|
+
*/
|
|
27
|
+
declare const withoutResolvedEnclosures: (control: Node, resolved: (revisionId: number) => boolean) => Node["attrs"] | null;
|
|
28
|
+
type EncloseWholeControlsOptions = {
|
|
29
|
+
tr: Transaction;
|
|
30
|
+
from: number;
|
|
31
|
+
to: number;
|
|
32
|
+
revisionId: number;
|
|
33
|
+
};
|
|
34
|
+
/**
|
|
35
|
+
* Record `revisionId` as enclosing every inline control `[from, to]` covers
|
|
36
|
+
* whole, opening and closing token included: the revision removes or adds the
|
|
37
|
+
* control, as deleting or inserting the same range directly would. A control
|
|
38
|
+
* the range covers only the content of is left alone, and its revision stays
|
|
39
|
+
* one over that content.
|
|
40
|
+
*/
|
|
41
|
+
declare const encloseWholeControls: ({ tr, from, to, revisionId }: EncloseWholeControlsOptions) => void;
|
|
42
|
+
//#endregion
|
|
43
|
+
export { ENCLOSING_REVISION_IDS_ATTR, encloseWholeControls, enclosingRevisionIds, resolutionRemovesControl, withEnclosingRevision, withoutResolvedEnclosures };
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import { expectTrackedChangeMarkAttrs } from "./attrs/index.js";
|
|
2
|
+
import "./extensions/nodes/SdtExtension.js";
|
|
3
|
+
//#region src/prosemirror/contentControlRevisions.ts
|
|
4
|
+
const ENCLOSING_REVISION_IDS_ATTR = "_docxEnclosingRevisionIds";
|
|
5
|
+
const isInlineControl = (node) => node.type.name === "sdt";
|
|
6
|
+
/** The revisions whose element encloses `control`. */
|
|
7
|
+
const enclosingRevisionIds = (control) => {
|
|
8
|
+
const ids = control.attrs[ENCLOSING_REVISION_IDS_ATTR];
|
|
9
|
+
return Array.isArray(ids) ? ids.filter((id) => typeof id === "number") : [];
|
|
10
|
+
};
|
|
11
|
+
/** `control`'s attrs with `revisionId` added to its enclosing revisions. */
|
|
12
|
+
const withEnclosingRevision = (control, revisionId) => {
|
|
13
|
+
const ids = enclosingRevisionIds(control);
|
|
14
|
+
return ids.includes(revisionId) ? null : {
|
|
15
|
+
...control.attrs,
|
|
16
|
+
[ENCLOSING_REVISION_IDS_ATTR]: [...ids, revisionId]
|
|
17
|
+
};
|
|
18
|
+
};
|
|
19
|
+
const REMOVED_LAYERS = {
|
|
20
|
+
deletion: /* @__PURE__ */ new Set(["deletion", "moveFrom"]),
|
|
21
|
+
insertion: /* @__PURE__ */ new Set(["insertion", "moveTo"])
|
|
22
|
+
};
|
|
23
|
+
/** Whether `mark`, or a revision it is nested in, is `revisionId` of `removeType`'s kind. */
|
|
24
|
+
const carriesRevision = (mark, removeType, revisionId) => {
|
|
25
|
+
if (mark.type.name !== "insertion" && mark.type.name !== "deletion") return false;
|
|
26
|
+
const attrs = expectTrackedChangeMarkAttrs(mark);
|
|
27
|
+
if (mark.type === removeType && attrs.revisionId === revisionId) return true;
|
|
28
|
+
const removed = removeType.name === "deletion" ? REMOVED_LAYERS.deletion : REMOVED_LAYERS.insertion;
|
|
29
|
+
return (attrs._docxRevisionAncestors ?? []).some((layer) => layer.revisionId === revisionId && removed.has(layer.type));
|
|
30
|
+
};
|
|
31
|
+
const coveredBy = (node, covers) => {
|
|
32
|
+
if (node.childCount === 0) return false;
|
|
33
|
+
for (let index = 0; index < node.childCount; index += 1) {
|
|
34
|
+
const child = node.child(index);
|
|
35
|
+
if (child.marks.some(covers)) continue;
|
|
36
|
+
if (!isInlineControl(child) || !coveredBy(child, covers)) return false;
|
|
37
|
+
}
|
|
38
|
+
return true;
|
|
39
|
+
};
|
|
40
|
+
/**
|
|
41
|
+
* Whether resolving removes the control itself: a revision that encloses it is
|
|
42
|
+
* resolved in the direction that removes its content, and still covers all of
|
|
43
|
+
* it. Removing only the content leaves the control standing, emptied.
|
|
44
|
+
*/
|
|
45
|
+
const resolutionRemovesControl = ({ control, removeType, resolves }) => {
|
|
46
|
+
if (removeType === void 0 || !isInlineControl(control)) return false;
|
|
47
|
+
return enclosingRevisionIds(control).some((revisionId) => resolves(revisionId) && coveredBy(control, (mark) => carriesRevision(mark, removeType, revisionId)));
|
|
48
|
+
};
|
|
49
|
+
/**
|
|
50
|
+
* `control`'s attrs without the enclosing revisions `resolved` names, or
|
|
51
|
+
* `null` when none of them is: a resolved revision no longer exists, and an id
|
|
52
|
+
* left behind would claim whatever revision is later given that id.
|
|
53
|
+
*/
|
|
54
|
+
const withoutResolvedEnclosures = (control, resolved) => {
|
|
55
|
+
const ids = enclosingRevisionIds(control);
|
|
56
|
+
const remaining = ids.filter((revisionId) => !resolved(revisionId));
|
|
57
|
+
if (remaining.length === ids.length) return null;
|
|
58
|
+
return {
|
|
59
|
+
...control.attrs,
|
|
60
|
+
[ENCLOSING_REVISION_IDS_ATTR]: remaining.length > 0 ? remaining : null
|
|
61
|
+
};
|
|
62
|
+
};
|
|
63
|
+
/**
|
|
64
|
+
* Record `revisionId` as enclosing every inline control `[from, to]` covers
|
|
65
|
+
* whole, opening and closing token included: the revision removes or adds the
|
|
66
|
+
* control, as deleting or inserting the same range directly would. A control
|
|
67
|
+
* the range covers only the content of is left alone, and its revision stays
|
|
68
|
+
* one over that content.
|
|
69
|
+
*/
|
|
70
|
+
const encloseWholeControls = ({ tr, from, to, revisionId }) => {
|
|
71
|
+
const enclosed = [];
|
|
72
|
+
tr.doc.nodesBetween(from, to, (node, pos) => {
|
|
73
|
+
if (!isInlineControl(node) || pos < from || pos + node.nodeSize > to) return true;
|
|
74
|
+
const attrs = withEnclosingRevision(node, revisionId);
|
|
75
|
+
if (attrs) enclosed.push({
|
|
76
|
+
pos,
|
|
77
|
+
attrs
|
|
78
|
+
});
|
|
79
|
+
return true;
|
|
80
|
+
});
|
|
81
|
+
for (const { pos, attrs } of enclosed) tr.setNodeMarkup(pos, void 0, attrs);
|
|
82
|
+
};
|
|
83
|
+
//#endregion
|
|
84
|
+
export { ENCLOSING_REVISION_IDS_ATTR, encloseWholeControls, enclosingRevisionIds, resolutionRemovesControl, withEnclosingRevision, withoutResolvedEnclosures };
|