@stll/folio-core 0.3.1 → 0.5.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.d.ts +3 -9
- package/dist/ai-edits/apply.js +94 -14
- package/dist/ai-edits/blockRange.d.ts +33 -0
- package/dist/ai-edits/blockRange.js +58 -0
- package/dist/ai-edits/headless.d.ts +35 -5
- package/dist/ai-edits/headless.js +92 -22
- package/dist/ai-edits/index.d.ts +5 -3
- package/dist/ai-edits/index.js +3 -2
- package/dist/ai-edits/snapshot.d.ts +14 -2
- package/dist/ai-edits/snapshot.js +12 -1
- package/dist/ai-edits/types.d.ts +42 -3
- package/dist/compat/eigenpal.d.ts +3 -2
- package/dist/compat/eigenpal.js +6 -5
- package/dist/controller/layoutPipeline.d.ts +1 -0
- package/dist/controller/layoutPipeline.js +35 -115
- package/dist/controller/layoutScheduler.d.ts +2 -1
- package/dist/controller/layoutScheduler.js +6 -0
- package/dist/document-operations.d.ts +122 -0
- package/dist/document-operations.js +575 -0
- package/dist/docx/blockContentParser.js +17 -7
- package/dist/docx/encryption/agileDecryption.d.ts +6 -0
- package/dist/docx/encryption/agileDecryption.js +209 -0
- package/dist/docx/encryption/compoundFile.d.ts +20 -0
- package/dist/docx/encryption/compoundFile.js +251 -0
- package/dist/docx/encryption/containerFormat.d.ts +15 -0
- package/dist/docx/encryption/containerFormat.js +40 -0
- package/dist/docx/encryption/cryptoBytes.d.ts +11 -0
- package/dist/docx/encryption/cryptoBytes.js +55 -0
- package/dist/docx/encryption/encryptionInfo.d.ts +32 -0
- package/dist/docx/encryption/encryptionInfo.js +128 -0
- package/dist/docx/encryption/errors.d.ts +18 -0
- package/dist/docx/encryption/errors.js +13 -0
- package/dist/docx/encryption/index.d.ts +4 -0
- package/dist/docx/encryption/index.js +4 -0
- package/dist/docx/encryption/openEncryptedDocx.d.ts +28 -0
- package/dist/docx/encryption/openEncryptedDocx.js +65 -0
- package/dist/docx/footnoteParser.d.ts +1 -17
- package/dist/docx/footnoteParser.js +1 -27
- package/dist/docx/groupDrawingParser.d.ts +8 -0
- package/dist/docx/groupDrawingParser.js +131 -0
- package/dist/docx/index.d.ts +3 -1
- package/dist/docx/index.js +3 -1
- package/dist/docx/numberingParser.d.ts +3 -1
- package/dist/docx/numberingParser.js +8 -2
- package/dist/docx/paragraphParser.js +9 -3
- package/dist/docx/parser.d.ts +4 -5
- package/dist/docx/parser.js +8 -2
- package/dist/docx/runParser.js +8 -1
- package/dist/docx/selectiveXmlPatch.js +4 -10
- package/dist/docx/serializer/numberingSerializer.js +3 -1
- package/dist/docx/settingsParser.d.ts +6 -3
- package/dist/docx/settingsParser.js +2 -0
- package/dist/docx/unzip.d.ts +7 -5
- package/dist/docx/unzip.js +8 -2
- package/dist/docx/xmlParser.js +11 -4
- package/dist/index.d.ts +3 -2
- package/dist/index.js +6 -5
- package/dist/layout-bridge/convert/footnoteLayout.d.ts +37 -1
- package/dist/layout-bridge/convert/footnoteLayout.js +138 -14
- package/dist/layout-bridge/convert/headerFooterLayout.d.ts +6 -8
- package/dist/layout-bridge/convert/headerFooterLayout.js +21 -13
- package/dist/layout-bridge/convert/toFlowBlocks.js +58 -19
- package/dist/layout-engine/index.d.ts +6 -5
- package/dist/layout-engine/index.js +116 -27
- package/dist/layout-engine/keep-together.d.ts +13 -8
- package/dist/layout-engine/keep-together.js +40 -25
- package/dist/layout-engine/layoutInstrumentation.d.ts +11 -1
- package/dist/layout-engine/layoutInstrumentation.js +10 -1
- package/dist/layout-engine/measure/measureBlocks.js +43 -19
- package/dist/layout-engine/measure/measureParagraph.js +91 -14
- package/dist/layout-engine/paginator.d.ts +2 -1
- package/dist/layout-engine/paginator.js +9 -3
- package/dist/layout-engine/textBoxGroup.d.ts +7 -0
- package/dist/layout-engine/textBoxGroup.js +8 -0
- package/dist/layout-engine/types.d.ts +33 -9
- package/dist/layout-engine/types.js +20 -2
- package/dist/layout-painter/renderPage.d.ts +15 -1
- package/dist/layout-painter/renderPage.js +29 -12
- package/dist/layout-painter/renderParagraph.js +44 -9
- package/dist/layout-painter/renderTable.js +27 -7
- package/dist/managers/DocumentLoaderManager.d.ts +3 -1
- package/dist/managers/DocumentLoaderManager.js +13 -5
- package/dist/managers/TableSelectionManager.js +1 -1
- package/dist/model.js +1 -1
- package/dist/paged-layout/pageText.d.ts +14 -0
- package/dist/paged-layout/pageText.js +21 -0
- package/dist/prosemirror/attrs/index.js +3 -0
- package/dist/prosemirror/commands/comments.js +75 -5
- package/dist/prosemirror/commands/hyperlink.js +4 -2
- package/dist/prosemirror/commands/image.js +2 -1
- package/dist/prosemirror/commands/index.js +1 -1
- package/dist/prosemirror/commands/propertyChangeScope.d.ts +68 -0
- package/dist/prosemirror/commands/propertyChangeScope.js +242 -0
- package/dist/prosemirror/conversion/fromProseDoc.js +21 -5
- package/dist/prosemirror/conversion/toProseDoc.js +43 -15
- package/dist/prosemirror/extensions/core/ParagraphExtension.js +3 -0
- package/dist/prosemirror/extensions/features/ListExtension.js +6 -0
- package/dist/prosemirror/extensions/nodes/TableExtension.js +12 -11
- package/dist/prosemirror/findReplaceSelection.js +2 -1
- package/dist/prosemirror/index.js +1 -1
- package/dist/prosemirror/insertOperations.js +1 -1
- package/dist/prosemirror/schema/nodes.d.ts +14 -7
- package/dist/prosemirror/styles/resolvedStyleAttrs.js +1 -0
- package/dist/prosemirror/utils/tabCalculator.js +4 -2
- package/dist/redline.d.ts +20 -0
- package/dist/redline.js +127 -0
- package/dist/server.d.ts +7 -3
- package/dist/server.js +6 -2
- package/dist/symbols.d.ts +35 -0
- package/dist/symbols.js +512 -0
- package/dist/utils/clipboard.js +3 -3
- package/dist/utils/fontLoader.js +3 -0
- package/dist/utils/fontResolver.js +65 -1
- package/dist/utils/zoom.d.ts +21 -0
- package/dist/utils/zoom.js +21 -0
- package/dist/version-comparison.d.ts +92 -0
- package/dist/version-comparison.js +436 -0
- package/package.json +7 -3
- package/dist/paged-layout/headerFooterMargins.d.ts +0 -73
- package/dist/paged-layout/headerFooterMargins.js +0 -120
|
@@ -42,6 +42,20 @@ type PageFloatingImage = {
|
|
|
42
42
|
*/
|
|
43
43
|
behindDoc: boolean;
|
|
44
44
|
};
|
|
45
|
+
type FloatingTableBandOptions = {
|
|
46
|
+
contentX: number;
|
|
47
|
+
tableWidth: number;
|
|
48
|
+
contentWidth: number;
|
|
49
|
+
distLeft: number;
|
|
50
|
+
distRight: number;
|
|
51
|
+
};
|
|
52
|
+
declare const floatingTableReservesBand: ({
|
|
53
|
+
contentX,
|
|
54
|
+
tableWidth,
|
|
55
|
+
contentWidth,
|
|
56
|
+
distLeft,
|
|
57
|
+
distRight
|
|
58
|
+
}: FloatingTableBandOptions) => boolean;
|
|
45
59
|
/**
|
|
46
60
|
* CSS class names for page elements
|
|
47
61
|
*/
|
|
@@ -276,4 +290,4 @@ declare function findPageShellForPmPos(container: HTMLElement, pmPos: number): {
|
|
|
276
290
|
isExact: boolean;
|
|
277
291
|
} | null;
|
|
278
292
|
//#endregion
|
|
279
|
-
export { AnchoredImagePosition, FootnoteRenderItem, type HeaderFooterContent, HeaderFooterLayoutInfo, PAGE_CLASS_NAMES, PAINTER_PAINTED_EVENT, PageFloatingImage, PageGeometry, PainterPaintedDetail, type RenderContext, RenderPageOptions, applySectionHeaderFooterOptions, calculateFootnoteAreaRenderHeight, computePageFingerprint, emuToPixels, findPageShellForPmPos, getDefaultPageFontFamily, isFloatingImageRun, renderAllPagesNow, renderFloatingImagesLayer, renderFootnoteArea, renderPage, renderPages, resolveAnchoredImagePosition, resolveHeaderFooterFloatLeft };
|
|
293
|
+
export { AnchoredImagePosition, FootnoteRenderItem, type HeaderFooterContent, HeaderFooterLayoutInfo, PAGE_CLASS_NAMES, PAINTER_PAINTED_EVENT, PageFloatingImage, PageGeometry, PainterPaintedDetail, type RenderContext, RenderPageOptions, applySectionHeaderFooterOptions, calculateFootnoteAreaRenderHeight, computePageFingerprint, emuToPixels, findPageShellForPmPos, floatingTableReservesBand, getDefaultPageFontFamily, isFloatingImageRun, renderAllPagesNow, renderFloatingImagesLayer, renderFootnoteArea, renderPage, renderPages, resolveAnchoredImagePosition, resolveHeaderFooterFloatLeft };
|
|
@@ -19,6 +19,11 @@ import { panic } from "better-result";
|
|
|
19
19
|
* Renders a single page from Layout data to DOM elements.
|
|
20
20
|
* Each page contains positioned fragments within a content area.
|
|
21
21
|
*/
|
|
22
|
+
const floatingTableReservesBand = ({ contentX, tableWidth, contentWidth, distLeft, distRight }) => {
|
|
23
|
+
const leftClearance = Math.max(0, contentX - distLeft);
|
|
24
|
+
const rightClearance = Math.max(0, contentWidth - contentX - tableWidth - distRight);
|
|
25
|
+
return Math.max(leftClearance, rightClearance) < 24;
|
|
26
|
+
};
|
|
22
27
|
/**
|
|
23
28
|
* CSS class names for page elements
|
|
24
29
|
*/
|
|
@@ -874,7 +879,8 @@ function renderPage(page, context, options = {}) {
|
|
|
874
879
|
...img.wrapType !== void 0 ? { wrapType: img.wrapType } : {}
|
|
875
880
|
});
|
|
876
881
|
}
|
|
877
|
-
if (options.blockLookup) for (
|
|
882
|
+
if (options.blockLookup) for (let fragmentIndex = 0; fragmentIndex < page.fragments.length; fragmentIndex++) {
|
|
883
|
+
const fragment = page.fragments[fragmentIndex];
|
|
878
884
|
if (fragment.kind !== "table") continue;
|
|
879
885
|
const blockData = options.blockLookup.get(String(fragment.blockId));
|
|
880
886
|
if (blockData?.block.kind !== "table") continue;
|
|
@@ -886,9 +892,8 @@ function renderPage(page, context, options = {}) {
|
|
|
886
892
|
const distBottom = floating.bottomFromText ?? 0;
|
|
887
893
|
const distLeft = floating.leftFromText ?? 12;
|
|
888
894
|
const distRight = floating.rightFromText ?? 12;
|
|
889
|
-
const
|
|
890
|
-
|
|
891
|
-
side,
|
|
895
|
+
const rect = {
|
|
896
|
+
side: contentX < contentWidth / 2 ? "left" : "right",
|
|
892
897
|
x: contentX,
|
|
893
898
|
y: contentY,
|
|
894
899
|
width: fragment.width,
|
|
@@ -897,7 +902,19 @@ function renderPage(page, context, options = {}) {
|
|
|
897
902
|
distBottom,
|
|
898
903
|
distLeft,
|
|
899
904
|
distRight
|
|
905
|
+
};
|
|
906
|
+
if (floatingTableReservesBand({
|
|
907
|
+
contentX,
|
|
908
|
+
tableWidth: fragment.width,
|
|
909
|
+
contentWidth,
|
|
910
|
+
distLeft,
|
|
911
|
+
distRight
|
|
912
|
+
})) rect.wrapType = "topAndBottom";
|
|
913
|
+
if (floating.vertAnchor === "text") scopedFloatingRects.push({
|
|
914
|
+
startsAtFragmentIndex: fragmentIndex,
|
|
915
|
+
rect
|
|
900
916
|
});
|
|
917
|
+
else floatingRects.push(rect);
|
|
901
918
|
}
|
|
902
919
|
if (options.blockLookup) for (let fragmentIndex = 0; fragmentIndex < page.fragments.length; fragmentIndex++) {
|
|
903
920
|
const fragment = page.fragments[fragmentIndex];
|
|
@@ -1162,7 +1179,8 @@ function applySectionHeaderFooterOptions(page, pageOptions, options) {
|
|
|
1162
1179
|
if (!refs) return false;
|
|
1163
1180
|
const isFirstSectionPage = page.sectionPageNumber === 1;
|
|
1164
1181
|
const useFirst = refs.titlePg === true && isFirstSectionPage;
|
|
1165
|
-
const
|
|
1182
|
+
const sectionPageNumber = page.sectionPageNumber ?? page.number;
|
|
1183
|
+
const useEven = refs.evenAndOddHeaders === true && sectionPageNumber % 2 === 0;
|
|
1166
1184
|
const headerRId = (() => {
|
|
1167
1185
|
if (useFirst) return refs.headerFirst;
|
|
1168
1186
|
if (useEven && refs.headerEven) return refs.headerEven;
|
|
@@ -1556,22 +1574,21 @@ function renderPages(pages, container, options = {}) {
|
|
|
1556
1574
|
const pageShells = [];
|
|
1557
1575
|
for (let i = 0; i < pages.length; i++) {
|
|
1558
1576
|
const page = pages[i];
|
|
1577
|
+
let pageEl;
|
|
1559
1578
|
if (!useVirtualization) {
|
|
1560
1579
|
const { context, pageOptions } = buildPageRenderArgs(page, totalPages, options);
|
|
1561
|
-
|
|
1562
|
-
container.insertBefore(pageEl, overlayBefore);
|
|
1563
|
-
pageShells.push(pageEl);
|
|
1580
|
+
pageEl = renderPage(page, context, pageOptions);
|
|
1564
1581
|
} else {
|
|
1565
1582
|
const doc = options.document ?? document;
|
|
1566
|
-
|
|
1583
|
+
pageEl = doc.createElement("div");
|
|
1567
1584
|
pageEl.className = options.pageClassName ?? PAGE_CLASS_NAMES.page;
|
|
1568
1585
|
pageEl.dataset["pageNumber"] = String(page.number);
|
|
1569
1586
|
pageEl.dataset["pageIndex"] = String(i);
|
|
1570
1587
|
applyPageStyles(pageEl, page.size.w, page.size.h, options);
|
|
1571
1588
|
syncPageBorderOverlay(pageEl, page, options, doc);
|
|
1572
|
-
container.insertBefore(pageEl, overlayBefore);
|
|
1573
|
-
pageShells.push(pageEl);
|
|
1574
1589
|
}
|
|
1590
|
+
container.insertBefore(pageEl, overlayBefore);
|
|
1591
|
+
pageShells.push(pageEl);
|
|
1575
1592
|
}
|
|
1576
1593
|
if (!useVirtualization) {
|
|
1577
1594
|
emitPainterPainted(container);
|
|
@@ -1819,4 +1836,4 @@ function depopulatePageShell(shell, pageDataMap) {
|
|
|
1819
1836
|
}
|
|
1820
1837
|
}
|
|
1821
1838
|
//#endregion
|
|
1822
|
-
export { PAGE_CLASS_NAMES, PAINTER_PAINTED_EVENT, applySectionHeaderFooterOptions, calculateFootnoteAreaRenderHeight, computePageFingerprint, emuToPixels, findPageShellForPmPos, getDefaultPageFontFamily, isFloatingImageRun, renderAllPagesNow, renderFloatingImagesLayer, renderFootnoteArea, renderPage, renderPages, resolveAnchoredImagePosition, resolveHeaderFooterFloatLeft };
|
|
1839
|
+
export { PAGE_CLASS_NAMES, PAINTER_PAINTED_EVENT, applySectionHeaderFooterOptions, calculateFootnoteAreaRenderHeight, computePageFingerprint, emuToPixels, findPageShellForPmPos, floatingTableReservesBand, getDefaultPageFontFamily, isFloatingImageRun, renderAllPagesNow, renderFloatingImagesLayer, renderFootnoteArea, renderPage, renderPages, resolveAnchoredImagePosition, resolveHeaderFooterFloatLeft };
|
|
@@ -330,6 +330,10 @@ function renderTabRun(run, doc, width, leader) {
|
|
|
330
330
|
} else span.textContent = "\xA0";
|
|
331
331
|
return span;
|
|
332
332
|
}
|
|
333
|
+
function canClampTabToRightEdge(alignment, hasPriorRenderedContent, hasPriorTab, isLastLine) {
|
|
334
|
+
if (alignment === "start" || alignment === "default") return hasPriorRenderedContent && (hasPriorTab || isLastLine);
|
|
335
|
+
return true;
|
|
336
|
+
}
|
|
333
337
|
function applyTabUnderline(element, run) {
|
|
334
338
|
if (!run.underline) return;
|
|
335
339
|
removeUnderlineTextDecoration(element);
|
|
@@ -529,7 +533,9 @@ const EMPTY_SEQ_VALUES = /* @__PURE__ */ new Map();
|
|
|
529
533
|
* Returns the cached fallback when no render context is available.
|
|
530
534
|
*/
|
|
531
535
|
function resolveFieldText(run, context) {
|
|
532
|
-
|
|
536
|
+
const fallback = run.fallback ?? "";
|
|
537
|
+
if (run.fieldType === "OTHER" && run.pmStart === void 0) return fallback;
|
|
538
|
+
if (!context) return fallback;
|
|
533
539
|
const fieldContext = {
|
|
534
540
|
pageNumber: context.pageNumber,
|
|
535
541
|
totalPages: context.totalPages,
|
|
@@ -540,7 +546,7 @@ function resolveFieldText(run, context) {
|
|
|
540
546
|
...context.sectionPages === void 0 ? {} : { sectionPages: context.sectionPages }
|
|
541
547
|
};
|
|
542
548
|
return evaluateFieldInstruction(run.instruction || run.fieldType, fieldContext, {
|
|
543
|
-
fallback
|
|
549
|
+
fallback,
|
|
544
550
|
...run.pmStart === void 0 ? {} : { instanceId: run.pmStart },
|
|
545
551
|
...run.fldLock ? { locked: true } : {}
|
|
546
552
|
});
|
|
@@ -710,6 +716,17 @@ function splitTextRunsByEastAsia(runs) {
|
|
|
710
716
|
* must trigger within this slack.
|
|
711
717
|
*/
|
|
712
718
|
const RIGHT_EDGE_EPSILON_PX = .5;
|
|
719
|
+
function countShrinkableSpaces(runs) {
|
|
720
|
+
let count = 0;
|
|
721
|
+
for (const run of runs) if (isTextRun(run)) {
|
|
722
|
+
for (const char of run.text ?? "") if (char === " ") count++;
|
|
723
|
+
} else if (isFieldRun(run)) {
|
|
724
|
+
for (const char of run.fallback ?? "") if (char === " ") count++;
|
|
725
|
+
} else if (isMathRun(run)) {
|
|
726
|
+
for (const char of run.plainText ?? "") if (char === " ") count++;
|
|
727
|
+
}
|
|
728
|
+
return count;
|
|
729
|
+
}
|
|
713
730
|
/**
|
|
714
731
|
* Build a TextMeasureStyle from a TextRun or FieldRun's relevant fields.
|
|
715
732
|
*/
|
|
@@ -888,16 +905,32 @@ function renderLine(block, line, alignment, doc, options) {
|
|
|
888
905
|
lineEl.append(emptySpan);
|
|
889
906
|
return lineEl;
|
|
890
907
|
}
|
|
908
|
+
const hasTabRuns = runsForLine.some(isTabRun);
|
|
891
909
|
if (alignment === "justify" && options) {
|
|
892
910
|
if (!options.isLastLine || options.paragraphEndsWithLineBreak) {
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
911
|
+
const firstLineIndentPx = options.isFirstLine ? options.firstLineIndentPx ?? 0 : 0;
|
|
912
|
+
const firstLineHangingPx = Math.max(0, -firstLineIndentPx);
|
|
913
|
+
const justifyCapacityPx = options.availableWidth + firstLineHangingPx;
|
|
914
|
+
const overfullPx = line.width - justifyCapacityPx;
|
|
915
|
+
const shrinkableSpaces = countShrinkableSpaces(runsForLine);
|
|
916
|
+
if (overfullPx > RIGHT_EDGE_EPSILON_PX && shrinkableSpaces > 0) {
|
|
917
|
+
lineEl.style.textAlign = "left";
|
|
918
|
+
lineEl.style.textAlignLast = "auto";
|
|
919
|
+
lineEl.style.wordSpacing = `${-overfullPx / shrinkableSpaces}px`;
|
|
920
|
+
} else if (hasTabRuns && shrinkableSpaces > 0 && -overfullPx > RIGHT_EDGE_EPSILON_PX) {
|
|
921
|
+
lineEl.style.textAlign = "left";
|
|
922
|
+
lineEl.style.textAlignLast = "auto";
|
|
923
|
+
lineEl.style.wordSpacing = `${-overfullPx / shrinkableSpaces}px`;
|
|
924
|
+
} else {
|
|
925
|
+
lineEl.style.textAlign = "justify";
|
|
926
|
+
lineEl.style.textAlignLast = "justify";
|
|
927
|
+
}
|
|
928
|
+
const listFirstLineOffset = options.isFirstLine && block.attrs?.listMarker && !block.attrs.listMarkerHidden ? options.firstLineIndentPx ?? 0 : 0;
|
|
929
|
+
lineEl.style.width = `${options.availableWidth - listFirstLineOffset}px`;
|
|
896
930
|
}
|
|
897
931
|
}
|
|
898
932
|
lineEl.style.whiteSpace = "pre";
|
|
899
933
|
lineEl.style.overflow = "visible";
|
|
900
|
-
const hasTabRuns = runsForLine.some(isTabRun);
|
|
901
934
|
let tabContext;
|
|
902
935
|
const measureText = createTextMeasurer(doc);
|
|
903
936
|
if (hasTabRuns) {
|
|
@@ -905,6 +938,7 @@ function renderLine(block, line, alignment, doc, options) {
|
|
|
905
938
|
const leftIndentTwips = options?.leftIndentPx ? Math.round(options.leftIndentPx * 15) : 0;
|
|
906
939
|
tabContext = {
|
|
907
940
|
...explicitStops !== void 0 ? { explicitStops } : {},
|
|
941
|
+
...block.attrs?.defaultTabStopTwips !== void 0 ? { defaultTabInterval: block.attrs.defaultTabStopTwips } : {},
|
|
908
942
|
leftIndent: leftIndentTwips
|
|
909
943
|
};
|
|
910
944
|
}
|
|
@@ -967,7 +1001,7 @@ function renderLine(block, line, alignment, doc, options) {
|
|
|
967
1001
|
break;
|
|
968
1002
|
}
|
|
969
1003
|
let tabWidth = tabResult.width;
|
|
970
|
-
if (lineRightEdgeX !== void 0 && currentX + tabWidth + followingWidthForCheck > lineRightEdgeX) tabWidth = Math.max(1, lineRightEdgeX - currentX - followingWidthForCheck);
|
|
1004
|
+
if (lineRightEdgeX !== void 0 && canClampTabToRightEdge(tabResult.alignment, i > 0, runsForLine.slice(0, i).some(isTabRun), options?.isLastLine === true) && currentX + tabWidth + followingWidthForCheck > lineRightEdgeX) tabWidth = Math.max(1, lineRightEdgeX - currentX - followingWidthForCheck);
|
|
971
1005
|
const tabEl = renderTabRun(run, doc, tabWidth, tabResult.leader);
|
|
972
1006
|
lineEl.append(tabEl);
|
|
973
1007
|
currentX += tabWidth;
|
|
@@ -1215,7 +1249,7 @@ function renderParagraphFragment(fragment, block, measure, context, options = {}
|
|
|
1215
1249
|
} else if (indentLeft > 0) lineEl.style.paddingLeft = `${indentLeft}px`;
|
|
1216
1250
|
else if (hasFirstLine && !isFlexLine) lineEl.style.textIndent = `${indent.firstLine ?? 0}px`;
|
|
1217
1251
|
} else if (indentLeft > 0) lineEl.style.paddingLeft = `${indentLeft}px`;
|
|
1218
|
-
else if (hasHanging) lineEl.style.paddingLeft = `${indent.hanging ?? 0}px`;
|
|
1252
|
+
else if (hasHanging && indentLeft === 0) lineEl.style.paddingLeft = `${indent.hanging ?? 0}px`;
|
|
1219
1253
|
if (indentRight > 0) lineEl.style.paddingRight = `${indentRight}px`;
|
|
1220
1254
|
if (isFirstLine && block.attrs?.listMarker && !block.attrs.listMarkerHidden) {
|
|
1221
1255
|
const hanging = indent?.hanging ?? 0;
|
|
@@ -1234,7 +1268,8 @@ function renderParagraphFragment(fragment, block, measure, context, options = {}
|
|
|
1234
1268
|
const markerFontFamily = block.attrs.listMarkerFontFamily ?? firstTextRun?.fontFamily ?? block.attrs.defaultFontFamily;
|
|
1235
1269
|
const markerFontSize = block.attrs.listMarkerFontSize ?? firstTextRun?.fontSize ?? block.attrs.defaultFontSize;
|
|
1236
1270
|
const marker = renderListMarker(block.attrs.listMarker, getListMarkerInlineWidth(block), doc, markerFontFamily, markerFontSize, block.attrs.listMarkerRevision, block.attrs.listMarkerSecondSlotOffsetTwips);
|
|
1237
|
-
|
|
1271
|
+
const markerMarginLeft = markerStart - Math.min(indentLeft, 0);
|
|
1272
|
+
if (markerMarginLeft < 0 && indentLeft !== 0) marker.style.marginLeft = `${markerMarginLeft}px`;
|
|
1238
1273
|
lineEl.prepend(marker);
|
|
1239
1274
|
}
|
|
1240
1275
|
fragmentEl.append(lineEl);
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { tableColumnsArePinned } from "../layout-engine/types.js";
|
|
1
2
|
import { measureParagraph } from "../layout-engine/measure/measureParagraph.js";
|
|
2
3
|
import { getAutomaticTextColorForBackground } from "./documentColors.js";
|
|
3
4
|
import { renderParagraphFragment } from "./renderParagraph.js";
|
|
@@ -97,6 +98,10 @@ function renderCellContent(cell, cellMeasure, context, doc) {
|
|
|
97
98
|
};
|
|
98
99
|
const fragEl = renderParagraphFragment(syntheticFragment, paragraphBlock, paragraphMeasure, cellContext, { document: doc });
|
|
99
100
|
fragEl.style.position = "relative";
|
|
101
|
+
fragEl.style.boxSizing = "border-box";
|
|
102
|
+
fragEl.style.height = `${paragraphMeasure.totalHeight}px`;
|
|
103
|
+
const spaceBefore = paragraphBlock.attrs?.spacing?.before ?? 0;
|
|
104
|
+
if (spaceBefore > 0) fragEl.style.paddingTop = `${spaceBefore}px`;
|
|
100
105
|
contentEl.append(fragEl);
|
|
101
106
|
cumulativeY += paragraphMeasure.totalHeight;
|
|
102
107
|
} else if (block?.kind === "table" && measure?.kind === "table") {
|
|
@@ -133,12 +138,17 @@ function renderNestedTable(block, measure, context, doc) {
|
|
|
133
138
|
}
|
|
134
139
|
rowYPositions.push(yPos);
|
|
135
140
|
const spanningCells = /* @__PURE__ */ new Map();
|
|
141
|
+
const columnsPinned = tableColumnsArePinned(block);
|
|
136
142
|
let y = 0;
|
|
137
143
|
for (let rowIndex = 0; rowIndex < block.rows.length; rowIndex++) {
|
|
138
144
|
const row = block.rows[rowIndex];
|
|
139
145
|
const rowMeasure = measure.rows[rowIndex];
|
|
140
146
|
if (!row || !rowMeasure) continue;
|
|
141
|
-
|
|
147
|
+
if (row.hidden) {
|
|
148
|
+
y += rowMeasure.height;
|
|
149
|
+
continue;
|
|
150
|
+
}
|
|
151
|
+
const rowEl = renderTableRow(row, rowMeasure, rowIndex, y, measure.columnWidths, block.rows.length, context, doc, spanningCells, rowYPositions, void 0, block.bidi, columnsPinned);
|
|
142
152
|
tableEl.append(rowEl);
|
|
143
153
|
y += rowMeasure.height;
|
|
144
154
|
}
|
|
@@ -161,7 +171,7 @@ function applyBorder(el, side, border) {
|
|
|
161
171
|
/**
|
|
162
172
|
* Render a single table cell
|
|
163
173
|
*/
|
|
164
|
-
function renderTableCell(cell, cellMeasure, x, rowHeight, borderFlags, context, doc) {
|
|
174
|
+
function renderTableCell(cell, cellMeasure, x, rowHeight, borderFlags, columnsPinned, context, doc) {
|
|
165
175
|
const cellEl = doc.createElement("div");
|
|
166
176
|
cellEl.className = TABLE_CLASS_NAMES.cell;
|
|
167
177
|
cellEl.style.position = "absolute";
|
|
@@ -187,7 +197,7 @@ function renderTableCell(cell, cellMeasure, x, rowHeight, borderFlags, context,
|
|
|
187
197
|
const automaticTextColor = getAutomaticTextColorForBackground(cell.background);
|
|
188
198
|
if (automaticTextColor) cellEl.style.color = automaticTextColor;
|
|
189
199
|
}
|
|
190
|
-
if (cell.noWrap) cellEl.style.whiteSpace = "nowrap";
|
|
200
|
+
if (cell.noWrap && !columnsPinned) cellEl.style.whiteSpace = "nowrap";
|
|
191
201
|
if (cell.verticalAlign) {
|
|
192
202
|
cellEl.style.display = "flex";
|
|
193
203
|
cellEl.style.flexDirection = "column";
|
|
@@ -218,7 +228,7 @@ function renderTableCell(cell, cellMeasure, x, rowHeight, borderFlags, context,
|
|
|
218
228
|
/**
|
|
219
229
|
* Render a table row with rowSpan support
|
|
220
230
|
*/
|
|
221
|
-
function renderTableRow(row, rowMeasure, rowIndex, y, columnWidths, totalRows, context, doc, spanningCells, rowYPositions, isFirstRowInFragment, bidi = false) {
|
|
231
|
+
function renderTableRow(row, rowMeasure, rowIndex, y, columnWidths, totalRows, context, doc, spanningCells, rowYPositions, isFirstRowInFragment, bidi = false, columnsPinned = false) {
|
|
222
232
|
const rowEl = doc.createElement("div");
|
|
223
233
|
rowEl.className = TABLE_CLASS_NAMES.row;
|
|
224
234
|
const tableWidth = bidi ? columnWidths.reduce((sum, columnWidth) => sum + columnWidth, 0) : 0;
|
|
@@ -262,7 +272,7 @@ function renderTableRow(row, rowMeasure, rowIndex, y, columnWidths, totalRows, c
|
|
|
262
272
|
isLastRow,
|
|
263
273
|
isFirstCol: bidi ? atLogicalEnd : atLogicalStart,
|
|
264
274
|
isLastCol: bidi ? atLogicalStart : atLogicalEnd
|
|
265
|
-
}, context, doc);
|
|
275
|
+
}, columnsPinned, context, doc);
|
|
266
276
|
cellEl.dataset["cellIndex"] = String(cellIndex);
|
|
267
277
|
cellEl.dataset["columnIndex"] = String(columnIndex);
|
|
268
278
|
if (rowSpan > 1) cellEl.dataset["rowSpan"] = String(rowSpan);
|
|
@@ -340,13 +350,18 @@ function renderTableFragment(fragment, block, measure, context, options = {}) {
|
|
|
340
350
|
}
|
|
341
351
|
rowYPositions.push(yPos);
|
|
342
352
|
const spanningCells = /* @__PURE__ */ new Map();
|
|
353
|
+
const columnsPinned = tableColumnsArePinned(block);
|
|
343
354
|
const headerRowCount = fragment.headerRowCount ?? 0;
|
|
344
355
|
let y = 0;
|
|
345
356
|
if (headerRowCount > 0 && fragment.continuesFromPrev) for (let hdrIdx = 0; hdrIdx < headerRowCount; hdrIdx++) {
|
|
346
357
|
const hdrRow = block.rows[hdrIdx];
|
|
347
358
|
const hdrRowMeasure = measure.rows[hdrIdx];
|
|
348
359
|
if (!hdrRow || !hdrRowMeasure) continue;
|
|
349
|
-
|
|
360
|
+
if (hdrRow.hidden) {
|
|
361
|
+
y += hdrRowMeasure.height;
|
|
362
|
+
continue;
|
|
363
|
+
}
|
|
364
|
+
const rowEl = renderTableRow(hdrRow, hdrRowMeasure, hdrIdx, y, measure.columnWidths, block.rows.length, context, doc, spanningCells, rowYPositions, hdrIdx === 0, block.bidi, columnsPinned);
|
|
350
365
|
rowEl.dataset["repeatedHeader"] = "true";
|
|
351
366
|
tableEl.append(rowEl);
|
|
352
367
|
y += hdrRowMeasure.height;
|
|
@@ -369,13 +384,18 @@ function renderTableFragment(fragment, block, measure, context, options = {}) {
|
|
|
369
384
|
const row = block.rows[rowIndex];
|
|
370
385
|
const rowMeasure = measure.rows[rowIndex];
|
|
371
386
|
if (!row || !rowMeasure) continue;
|
|
387
|
+
if (row.hidden) {
|
|
388
|
+
y += rowMeasure.height;
|
|
389
|
+
continue;
|
|
390
|
+
}
|
|
372
391
|
const isFirstRowInFragment = headerRowCount > 0 && fragment.continuesFromPrev ? false : fragment.continuesFromPrev && rowIndex === fragment.fromRow;
|
|
373
|
-
const rowEl = renderTableRow(row, rowMeasure, rowIndex, y, measure.columnWidths, block.rows.length, context, doc, spanningCells, rowYPositions, isFirstRowInFragment, block.bidi);
|
|
392
|
+
const rowEl = renderTableRow(row, rowMeasure, rowIndex, y, measure.columnWidths, block.rows.length, context, doc, spanningCells, rowYPositions, isFirstRowInFragment, block.bidi, columnsPinned);
|
|
374
393
|
contentParent.append(rowEl);
|
|
375
394
|
y += rowMeasure.height;
|
|
376
395
|
}
|
|
377
396
|
let handleY = 0;
|
|
378
397
|
for (let rowIdx = fragment.fromRow; rowIdx < fragment.toRow; rowIdx++) {
|
|
398
|
+
if (block.rows[rowIdx]?.hidden) continue;
|
|
379
399
|
handleY += measure.rows[rowIdx]?.height ?? 0;
|
|
380
400
|
if (rowIdx < fragment.toRow - 1) {
|
|
381
401
|
const rowHandle = doc.createElement("div");
|
|
@@ -41,7 +41,9 @@ declare class DocumentLoaderManager {
|
|
|
41
41
|
* the result (and any error) when a newer load started while this one was in
|
|
42
42
|
* flight.
|
|
43
43
|
*/
|
|
44
|
-
loadBuffer(buffer: DocxInput
|
|
44
|
+
loadBuffer(buffer: DocxInput, options?: {
|
|
45
|
+
password?: string | undefined;
|
|
46
|
+
}): Promise<void>;
|
|
45
47
|
}
|
|
46
48
|
//#endregion
|
|
47
49
|
export { DocumentLoadState, DocumentLoaderCallbacks, DocumentLoaderHistory, DocumentLoaderManager };
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { resetAuthorColors } from "../utils/authorColors.js";
|
|
2
2
|
import { loadFontsWithMapping } from "../utils/fontLoader.js";
|
|
3
3
|
import { parseDocx } from "../docx/parser.js";
|
|
4
|
+
import { recordDocumentLoadPhase } from "../layout-engine/layoutInstrumentation.js";
|
|
4
5
|
import { inspectDocxCompatibility } from "../docx/compatibility.js";
|
|
5
6
|
//#region src/managers/DocumentLoaderManager.ts
|
|
6
7
|
/**
|
|
@@ -43,15 +44,22 @@ var DocumentLoaderManager = class {
|
|
|
43
44
|
* the result (and any error) when a newer load started while this one was in
|
|
44
45
|
* flight.
|
|
45
46
|
*/
|
|
46
|
-
async loadBuffer(buffer) {
|
|
47
|
+
async loadBuffer(buffer, options = {}) {
|
|
47
48
|
const { history, onError, setDocumentLoadState } = this.callbacks;
|
|
48
49
|
const generation = ++this.loadGeneration;
|
|
49
50
|
if (!(history.state !== null)) setDocumentLoadState({ status: "loading" });
|
|
50
51
|
try {
|
|
51
|
-
const
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
52
|
+
const parseStartedAt = performance.now();
|
|
53
|
+
let doc;
|
|
54
|
+
try {
|
|
55
|
+
doc = await parseDocx(buffer, {
|
|
56
|
+
detectVariables: false,
|
|
57
|
+
preloadFonts: false,
|
|
58
|
+
password: options.password
|
|
59
|
+
});
|
|
60
|
+
} finally {
|
|
61
|
+
recordDocumentLoadPhase("docx-parse", performance.now() - parseStartedAt);
|
|
62
|
+
}
|
|
55
63
|
if (this.loadGeneration !== generation) return;
|
|
56
64
|
this.loadParsedDocument(doc);
|
|
57
65
|
} catch (error) {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { Subscribable } from "./Subscribable.js";
|
|
2
1
|
import { addColumn, addRow, createTableContext, deleteColumn, deleteRow, getColumnCount, mergeCells, splitCell } from "../utils/tableOperations.js";
|
|
2
|
+
import { Subscribable } from "./Subscribable.js";
|
|
3
3
|
//#region src/managers/TableSelectionManager.ts
|
|
4
4
|
/** Data attributes for table elements in the rendered DOM */
|
|
5
5
|
const TABLE_DATA_ATTRIBUTES = {
|
package/dist/model.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { BORDER_STYLE_VALUES, CONDITIONAL_STYLE_TYPE_VALUES, EMPHASIS_MARK_VALUES, FIELD_TYPE_VALUES, FLOATING_TABLE_X_SPEC_VALUES, FLOATING_TABLE_Y_SPEC_VALUES, FONT_THEME_VALUES, FRAME_WRAP_VALUES, FRAME_X_ALIGN_VALUES, FRAME_Y_ALIGN_VALUES, HIGHLIGHT_COLOR_VALUES, IMAGE_HORIZONTAL_ALIGNMENT_VALUES, IMAGE_HORIZONTAL_RELATIVE_TO_VALUES, IMAGE_VERTICAL_ALIGNMENT_VALUES, IMAGE_VERTICAL_RELATIVE_TO_VALUES, IMAGE_WRAP_TEXT_VALUES, IMAGE_WRAP_TYPE_VALUES, LEVEL_SUFFIX_VALUES, LINE_SPACING_RULE_VALUES, NUMBER_FORMAT_VALUES, OUTLINE_STYLE_ATTR_VALUES, OUTLINE_STYLE_CSS_ALIASES, OUTLINE_STYLE_CSS_ALIAS_VALUES, PARAGRAPH_ALIGNMENT_VALUES, SDT_LOCK_VALUES, SDT_TYPE_VALUES, SHADING_PATTERN_VALUES, SHAPE_OUTLINE_STYLE_VALUES, SHAPE_TYPE_VALUES, STYLE_TYPE_VALUES, TABLE_CELL_TEXT_DIRECTION_VALUES, TABLE_CELL_VERTICAL_ALIGNMENT_VALUES, TABLE_JUSTIFICATION_VALUES, TABLE_ROW_HEIGHT_RULE_VALUES, TABLE_WIDTH_TYPE_VALUES, TAB_LEADER_VALUES, TAB_STOP_ALIGNMENT_VALUES, TEXT_EFFECT_VALUES, THEME_COLOR_SLOT_VALUES, UNDERLINE_STYLE_VALUES } from "./types/documentEnumValues.js";
|
|
2
1
|
import { deriveBlockId, getFolioParaIdFromBlockId, getSequentialFolioBlockIdIndex, isFolioBlockId, isSequentialFolioBlockId } from "./types/block-id.js";
|
|
2
|
+
import { BORDER_STYLE_VALUES, CONDITIONAL_STYLE_TYPE_VALUES, EMPHASIS_MARK_VALUES, FIELD_TYPE_VALUES, FLOATING_TABLE_X_SPEC_VALUES, FLOATING_TABLE_Y_SPEC_VALUES, FONT_THEME_VALUES, FRAME_WRAP_VALUES, FRAME_X_ALIGN_VALUES, FRAME_Y_ALIGN_VALUES, HIGHLIGHT_COLOR_VALUES, IMAGE_HORIZONTAL_ALIGNMENT_VALUES, IMAGE_HORIZONTAL_RELATIVE_TO_VALUES, IMAGE_VERTICAL_ALIGNMENT_VALUES, IMAGE_VERTICAL_RELATIVE_TO_VALUES, IMAGE_WRAP_TEXT_VALUES, IMAGE_WRAP_TYPE_VALUES, LEVEL_SUFFIX_VALUES, LINE_SPACING_RULE_VALUES, NUMBER_FORMAT_VALUES, OUTLINE_STYLE_ATTR_VALUES, OUTLINE_STYLE_CSS_ALIASES, OUTLINE_STYLE_CSS_ALIAS_VALUES, PARAGRAPH_ALIGNMENT_VALUES, SDT_LOCK_VALUES, SDT_TYPE_VALUES, SHADING_PATTERN_VALUES, SHAPE_OUTLINE_STYLE_VALUES, SHAPE_TYPE_VALUES, STYLE_TYPE_VALUES, TABLE_CELL_TEXT_DIRECTION_VALUES, TABLE_CELL_VERTICAL_ALIGNMENT_VALUES, TABLE_JUSTIFICATION_VALUES, TABLE_ROW_HEIGHT_RULE_VALUES, TABLE_WIDTH_TYPE_VALUES, TAB_LEADER_VALUES, TAB_STOP_ALIGNMENT_VALUES, TEXT_EFFECT_VALUES, THEME_COLOR_SLOT_VALUES, UNDERLINE_STYLE_VALUES } from "./types/documentEnumValues.js";
|
|
3
3
|
import { types_exports } from "./layout-engine/types.js";
|
|
4
4
|
export { BORDER_STYLE_VALUES, CONDITIONAL_STYLE_TYPE_VALUES, EMPHASIS_MARK_VALUES, FIELD_TYPE_VALUES, FLOATING_TABLE_X_SPEC_VALUES, FLOATING_TABLE_Y_SPEC_VALUES, FONT_THEME_VALUES, FRAME_WRAP_VALUES, FRAME_X_ALIGN_VALUES, FRAME_Y_ALIGN_VALUES, HIGHLIGHT_COLOR_VALUES, IMAGE_HORIZONTAL_ALIGNMENT_VALUES, IMAGE_HORIZONTAL_RELATIVE_TO_VALUES, IMAGE_VERTICAL_ALIGNMENT_VALUES, IMAGE_VERTICAL_RELATIVE_TO_VALUES, IMAGE_WRAP_TEXT_VALUES, IMAGE_WRAP_TYPE_VALUES, LEVEL_SUFFIX_VALUES, LINE_SPACING_RULE_VALUES, types_exports as Layout, NUMBER_FORMAT_VALUES, OUTLINE_STYLE_ATTR_VALUES, OUTLINE_STYLE_CSS_ALIASES, OUTLINE_STYLE_CSS_ALIAS_VALUES, PARAGRAPH_ALIGNMENT_VALUES, SDT_LOCK_VALUES, SDT_TYPE_VALUES, SHADING_PATTERN_VALUES, SHAPE_OUTLINE_STYLE_VALUES, SHAPE_TYPE_VALUES, STYLE_TYPE_VALUES, TABLE_CELL_TEXT_DIRECTION_VALUES, TABLE_CELL_VERTICAL_ALIGNMENT_VALUES, TABLE_JUSTIFICATION_VALUES, TABLE_ROW_HEIGHT_RULE_VALUES, TABLE_WIDTH_TYPE_VALUES, TAB_LEADER_VALUES, TAB_STOP_ALIGNMENT_VALUES, TEXT_EFFECT_VALUES, THEME_COLOR_SLOT_VALUES, UNDERLINE_STYLE_VALUES, deriveBlockId, getFolioParaIdFromBlockId, getSequentialFolioBlockIdIndex, isFolioBlockId, isSequentialFolioBlockId };
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { Layout } from "../layout-engine/types.js";
|
|
2
|
+
import { Node } from "prosemirror-model";
|
|
3
|
+
|
|
4
|
+
//#region src/paged-layout/pageText.d.ts
|
|
5
|
+
/**
|
|
6
|
+
* The plain text of a single rendered page (1-based), read by joining each of
|
|
7
|
+
* the page's layout fragments' `[pmStart, pmEnd)` document text with a
|
|
8
|
+
* newline. Fragments with no `pmStart`/`pmEnd` (e.g. a page-shell placeholder)
|
|
9
|
+
* are skipped. Returns `null` when the layout hasn't been computed yet or the
|
|
10
|
+
* page number is out of range.
|
|
11
|
+
*/
|
|
12
|
+
declare const getPageTextFromLayout: (layout: Layout | null, doc: Node, page: number) => string | null;
|
|
13
|
+
//#endregion
|
|
14
|
+
export { getPageTextFromLayout };
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
//#region src/paged-layout/pageText.ts
|
|
2
|
+
/**
|
|
3
|
+
* The plain text of a single rendered page (1-based), read by joining each of
|
|
4
|
+
* the page's layout fragments' `[pmStart, pmEnd)` document text with a
|
|
5
|
+
* newline. Fragments with no `pmStart`/`pmEnd` (e.g. a page-shell placeholder)
|
|
6
|
+
* are skipped. Returns `null` when the layout hasn't been computed yet or the
|
|
7
|
+
* page number is out of range.
|
|
8
|
+
*/
|
|
9
|
+
const getPageTextFromLayout = (layout, doc, page) => {
|
|
10
|
+
if (!layout || !Number.isInteger(page) || page < 1) return null;
|
|
11
|
+
const layoutPage = layout.pages[page - 1];
|
|
12
|
+
if (!layoutPage) return null;
|
|
13
|
+
const fragmentTexts = [];
|
|
14
|
+
for (const fragment of layoutPage.fragments) {
|
|
15
|
+
if (typeof fragment.pmStart !== "number" || typeof fragment.pmEnd !== "number") continue;
|
|
16
|
+
fragmentTexts.push(doc.textBetween(fragment.pmStart, fragment.pmEnd, "\n"));
|
|
17
|
+
}
|
|
18
|
+
return fragmentTexts.join("\n");
|
|
19
|
+
};
|
|
20
|
+
//#endregion
|
|
21
|
+
export { getPageTextFromLayout };
|
|
@@ -174,6 +174,7 @@ const readParagraphAttrs = (node) => {
|
|
|
174
174
|
});
|
|
175
175
|
optionalOneOf(attrs, "sectionBreakType", "paragraph.attrs.sectionBreakType", issues, SECTION_BREAK_TYPES);
|
|
176
176
|
optionalStringArray(attrs, "listLevelNumFmts", "paragraph.attrs.listLevelNumFmts", issues);
|
|
177
|
+
optionalNumberArray(attrs, "listLevelStarts", "paragraph.attrs.listLevelStarts", issues);
|
|
177
178
|
optionalNumber(attrs, "listAbstractNumId", "paragraph.attrs.listAbstractNumId", issues);
|
|
178
179
|
optionalBorderMap(attrs, "borders", "paragraph.attrs.borders", issues, [
|
|
179
180
|
"top",
|
|
@@ -186,6 +187,7 @@ const readParagraphAttrs = (node) => {
|
|
|
186
187
|
optionalShading(attrs, "shading", "paragraph.attrs.shading", issues);
|
|
187
188
|
optionalTabStops(attrs, "tabs", "paragraph.attrs.tabs", issues);
|
|
188
189
|
optionalRecord(attrs, "spacingExplicit", "paragraph.attrs.spacingExplicit", issues);
|
|
190
|
+
optionalRecord(attrs, "spacingFromDocDefaults", "paragraph.attrs.spacingFromDocDefaults", issues);
|
|
189
191
|
optionalTextFormatting(attrs, "defaultTextFormatting", "paragraph.attrs.defaultTextFormatting", issues);
|
|
190
192
|
optionalRecord(attrs, "numPr", "paragraph.attrs.numPr", issues);
|
|
191
193
|
validateNumPr(attrs["numPr"], issues);
|
|
@@ -236,6 +238,7 @@ const readTableRowAttrs = (node) => {
|
|
|
236
238
|
optionalNumber(attrs, "height", "tableRow.attrs.height", issues);
|
|
237
239
|
optionalOneOf(attrs, "heightRule", "tableRow.attrs.heightRule", issues, TABLE_ROW_HEIGHT_RULE_VALUES);
|
|
238
240
|
optionalBoolean(attrs, "isHeader", "tableRow.attrs.isHeader", issues);
|
|
241
|
+
optionalBoolean(attrs, "hidden", "tableRow.attrs.hidden", issues);
|
|
239
242
|
optionalRecord(attrs, "_originalFormatting", "tableRow.attrs._originalFormatting", issues);
|
|
240
243
|
return attrsResult(attrs, issues);
|
|
241
244
|
};
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { paragraphRejectAttrPatch, paragraphRejectOriginalFormatting, sectionRejectProperties, tableCellRejectAttrPatch, tableRejectAttrPatch, tableRowRejectAttrPatch } from "./propertyChangeScope.js";
|
|
1
2
|
//#region src/prosemirror/commands/comments.ts
|
|
2
3
|
/**
|
|
3
4
|
* Add a comment mark to the current selection.
|
|
@@ -59,21 +60,47 @@ function resolveChange(from, to, mode, revisionIds) {
|
|
|
59
60
|
if (node.type.name === "paragraph") {
|
|
60
61
|
const op = collectPPrMarkOp(node, pos, from, to, mode, revisionSet);
|
|
61
62
|
if (op) pPrMarkOps.push(op);
|
|
63
|
+
const boundaryCovered = rangeCoversParagraphBoundary(from, to, pos, node);
|
|
64
|
+
let nextAttrs = null;
|
|
62
65
|
const propertyChanges = node.attrs["_propertyChanges"];
|
|
63
|
-
if (Array.isArray(propertyChanges) && propertyChanges.length > 0 &&
|
|
66
|
+
if (Array.isArray(propertyChanges) && propertyChanges.length > 0 && boundaryCovered) {
|
|
64
67
|
const matches = propertyChanges.filter((c) => revisionSet === null || c.info && revisionSet.has(c.info.id));
|
|
65
68
|
if (matches.length > 0) {
|
|
66
69
|
const remaining = propertyChanges.filter((c) => revisionSet !== null && (!c.info || !revisionSet.has(c.info.id)));
|
|
67
|
-
|
|
70
|
+
nextAttrs = {
|
|
68
71
|
...node.attrs,
|
|
69
72
|
_propertyChanges: remaining.length > 0 ? remaining : null
|
|
70
73
|
};
|
|
71
|
-
if (mode === "reject") {
|
|
72
|
-
|
|
74
|
+
if (mode === "reject") for (const change of matches.toReversed()) {
|
|
75
|
+
Object.assign(nextAttrs, paragraphRejectAttrPatch(change.previousFormatting));
|
|
76
|
+
nextAttrs["_originalFormatting"] = paragraphRejectOriginalFormatting(change.previousFormatting, node.attrs["_originalFormatting"]);
|
|
73
77
|
}
|
|
74
|
-
tr.setNodeMarkup(pos, void 0, nextAttrs);
|
|
75
78
|
}
|
|
76
79
|
}
|
|
80
|
+
const sectionProperties = node.attrs["_sectionProperties"];
|
|
81
|
+
const sectionChanges = sectionProperties?.propertyChanges;
|
|
82
|
+
if (sectionProperties && Array.isArray(sectionChanges) && sectionChanges.length > 0 && boundaryCovered) {
|
|
83
|
+
const matches = sectionChanges.filter((c) => revisionSet === null || c.info && revisionSet.has(c.info.id));
|
|
84
|
+
if (matches.length > 0) {
|
|
85
|
+
const remaining = sectionChanges.filter((c) => revisionSet !== null && (!c.info || !revisionSet.has(c.info.id)));
|
|
86
|
+
let restored = { ...sectionProperties };
|
|
87
|
+
if (mode === "reject") for (const change of matches.toReversed()) restored = sectionRejectProperties(restored, change.previousProperties);
|
|
88
|
+
delete restored.propertyChanges;
|
|
89
|
+
if (remaining.length > 0) restored.propertyChanges = remaining;
|
|
90
|
+
nextAttrs = nextAttrs ?? { ...node.attrs };
|
|
91
|
+
nextAttrs["_sectionProperties"] = restored;
|
|
92
|
+
nextAttrs["sectionBreakType"] = sectionBreakTypeFromSectionStart(restored.sectionStart);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
if (nextAttrs) tr.setNodeMarkup(pos, void 0, nextAttrs);
|
|
96
|
+
return true;
|
|
97
|
+
}
|
|
98
|
+
const tableChangeAttrName = TABLE_PROPERTY_CHANGE_ATTR_BY_NODE[node.type.name];
|
|
99
|
+
if (tableChangeAttrName !== void 0) {
|
|
100
|
+
if (rangeCoversNode(from, to, pos, node)) {
|
|
101
|
+
const nextAttrs = resolveTablePropertyChangeAttrs(node, tableChangeAttrName, mode, revisionSet);
|
|
102
|
+
if (nextAttrs) tr.setNodeMarkup(pos, void 0, nextAttrs);
|
|
103
|
+
}
|
|
77
104
|
return true;
|
|
78
105
|
}
|
|
79
106
|
if (!node.isInline) return true;
|
|
@@ -124,6 +151,49 @@ function rangeCoversParagraphBoundary(from, to, pos, node) {
|
|
|
124
151
|
const boundaryTo = pos + node.nodeSize;
|
|
125
152
|
return from <= boundaryFrom && to >= boundaryTo;
|
|
126
153
|
}
|
|
154
|
+
/** Whether [from, to] fully covers the node — the range property-change cards
|
|
155
|
+
* and accept-all / reject-all sweeps supply for table-level records. */
|
|
156
|
+
function rangeCoversNode(from, to, pos, node) {
|
|
157
|
+
return from <= pos && to >= pos + node.nodeSize;
|
|
158
|
+
}
|
|
159
|
+
const SECTION_BREAK_TYPE_VALUES = [
|
|
160
|
+
"nextPage",
|
|
161
|
+
"continuous",
|
|
162
|
+
"oddPage",
|
|
163
|
+
"evenPage"
|
|
164
|
+
];
|
|
165
|
+
function sectionBreakTypeFromSectionStart(sectionStart) {
|
|
166
|
+
return SECTION_BREAK_TYPE_VALUES.find((value) => value === sectionStart) ?? null;
|
|
167
|
+
}
|
|
168
|
+
/** PM node type name → the attr its tracked property-change records live on. */
|
|
169
|
+
const TABLE_PROPERTY_CHANGE_ATTR_BY_NODE = {
|
|
170
|
+
table: "tblPrChange",
|
|
171
|
+
tableRow: "trPrChange",
|
|
172
|
+
tableCell: "tcPrChange",
|
|
173
|
+
tableHeader: "tcPrChange"
|
|
174
|
+
};
|
|
175
|
+
/**
|
|
176
|
+
* Resolve the tracked property-change records on one table / row / cell node.
|
|
177
|
+
* Accept keeps the live formatting and clears the matched records; reject
|
|
178
|
+
* additionally restores the stored previous formatting wholesale (the change
|
|
179
|
+
* element stores the complete old property set — see propertyChangeScope.ts).
|
|
180
|
+
* Returns the next attrs, or `null` when no record matches.
|
|
181
|
+
*/
|
|
182
|
+
function resolveTablePropertyChangeAttrs(node, attrName, mode, revisionSet) {
|
|
183
|
+
const changes = node.attrs[attrName];
|
|
184
|
+
if (!Array.isArray(changes) || changes.length === 0) return null;
|
|
185
|
+
const matches = changes.filter((c) => revisionSet === null || c.info && revisionSet.has(c.info.id));
|
|
186
|
+
if (matches.length === 0) return null;
|
|
187
|
+
const remaining = changes.filter((c) => revisionSet !== null && (!c.info || !revisionSet.has(c.info.id)));
|
|
188
|
+
const nextAttrs = {
|
|
189
|
+
...node.attrs,
|
|
190
|
+
[attrName]: remaining.length > 0 ? remaining : null
|
|
191
|
+
};
|
|
192
|
+
if (mode === "reject") for (const change of matches.toReversed()) if (attrName === "tblPrChange") Object.assign(nextAttrs, tableRejectAttrPatch(change.previousFormatting));
|
|
193
|
+
else if (attrName === "trPrChange") Object.assign(nextAttrs, tableRowRejectAttrPatch(change.previousFormatting));
|
|
194
|
+
else Object.assign(nextAttrs, tableCellRejectAttrPatch(change.previousFormatting, node.attrs["_originalFormatting"]));
|
|
195
|
+
return nextAttrs;
|
|
196
|
+
}
|
|
127
197
|
function isPPrMarkAttr(value) {
|
|
128
198
|
if (typeof value !== "object" || value === null) return false;
|
|
129
199
|
const kind = value.kind;
|
|
@@ -39,7 +39,8 @@ const editHyperlinkAtCursor = (view, { displayText, href }) => {
|
|
|
39
39
|
const { $from } = view.state.selection;
|
|
40
40
|
const linkMark = $from.marks().find((m) => m.type === hlType);
|
|
41
41
|
if (!linkMark) return true;
|
|
42
|
-
const
|
|
42
|
+
const ranges = collectHyperlinkRanges($from.parent, $from.start(), hlType, hyperlinkHref(linkMark));
|
|
43
|
+
const targetRange = rangeAtCursor(ranges, $from.pos);
|
|
43
44
|
if (!targetRange) return false;
|
|
44
45
|
const { tooltip } = expectHyperlinkMarkAttrs(linkMark);
|
|
45
46
|
const newMark = hlType.create({
|
|
@@ -69,7 +70,8 @@ const removeHyperlinkAtCursor = (view, { popupHref }) => {
|
|
|
69
70
|
}
|
|
70
71
|
});
|
|
71
72
|
if (!linkMark) return false;
|
|
72
|
-
const
|
|
73
|
+
const ranges = collectHyperlinkRanges($from.parent, $from.start(), hlType, hyperlinkHref(linkMark));
|
|
74
|
+
const targetRange = rangeAtCursor(ranges, $from.pos);
|
|
73
75
|
if (!targetRange) return false;
|
|
74
76
|
const tr = view.state.tr.removeMark(targetRange.start, targetRange.end, hlType);
|
|
75
77
|
view.dispatch(tr.scrollIntoView());
|
|
@@ -124,7 +124,8 @@ const applyImageWrapType = (view, pos, wrapType) => {
|
|
|
124
124
|
const applyImageTransform = (view, pos, action) => {
|
|
125
125
|
const node = imageNodeAt(view, pos);
|
|
126
126
|
if (!node) return false;
|
|
127
|
-
const
|
|
127
|
+
const currentTransform = expectImageAttrs(node).transform ?? "";
|
|
128
|
+
const transform = computeImageTransform(currentTransform, action);
|
|
128
129
|
const tr = view.state.tr.setNodeMarkup(pos, void 0, mergeImageAttrs(node, { transform }));
|
|
129
130
|
view.dispatch(tr.scrollIntoView());
|
|
130
131
|
return true;
|
|
@@ -5,9 +5,9 @@ import { getTableContext, isInTable as isInTableCell } from "../extensions/nodes
|
|
|
5
5
|
import { getListInfo, isInList } from "../extensions/features/ListExtension.js";
|
|
6
6
|
import { CLIPBOARD_READ_ERROR_EVENT, buildPlainTextSlice, pasteWithoutFormatting } from "./pastePlainText.js";
|
|
7
7
|
import { getHyperlinkAttrs, getSelectedText, isHyperlinkActive } from "../extensions/marks/HyperlinkExtension.js";
|
|
8
|
-
import { addColumnLeft, addColumnRight, addRowAbove, addRowBelow, applyTableStyle, autoFitContents, deleteColumn, deleteRow, deleteTable, distributeColumns, insertTable, mergeCells, removeTableBorders, selectColumn, selectRow, selectTable, setAllTableBorders, setCellBorder, setCellFillColor, setCellMargins, setCellTextDirection, setCellVerticalAlign, setInsideTableBorders, setOutsideTableBorders, setRowHeight, setTableBorderColor, setTableBorderPreset, setTableBorderWidth, setTableBorders, setTableProperties, splitCell, toggleHeaderRow, toggleNoWrap } from "./table.js";
|
|
9
8
|
import { clearFontFamily, clearFontSize, clearHighlight, clearTextColor, insertHyperlink, removeHyperlink, setFontFamily, setFontSize, setHighlight, setHyperlink, setTextColor, setUnderlineStyle, toggleBold, toggleItalic, toggleStrike, toggleSubscript, toggleSuperscript, toggleUnderline } from "./formatting.js";
|
|
10
9
|
import { addTabStop, alignCenter, alignJustify, alignLeft, alignRight, applyStyle, clearStyle, decreaseIndent, decreaseListLevel, doubleSpacing, generateTOC, increaseIndent, increaseListLevel, oneAndHalfSpacing, removeList, removeTabStop, setAlignment, setIndentFirstLine, setIndentLeft, setIndentRight, setLineSpacing, setLtr, setRtl, setSpaceAfter, setSpaceBefore, singleSpacing, toggleBidi, toggleBulletList, toggleNumberedList } from "./paragraph.js";
|
|
10
|
+
import { addColumnLeft, addColumnRight, addRowAbove, addRowBelow, applyTableStyle, autoFitContents, deleteColumn, deleteRow, deleteTable, distributeColumns, insertTable, mergeCells, removeTableBorders, selectColumn, selectRow, selectTable, setAllTableBorders, setCellBorder, setCellFillColor, setCellMargins, setCellTextDirection, setCellVerticalAlign, setInsideTableBorders, setOutsideTableBorders, setRowHeight, setTableBorderColor, setTableBorderPreset, setTableBorderWidth, setTableBorders, setTableProperties, splitCell, toggleHeaderRow, toggleNoWrap } from "./table.js";
|
|
11
11
|
import { PAINTABLE_MARK_NAMES, applyFormatMarks, captureFormatMarks } from "./formatPainter.js";
|
|
12
12
|
import { insertPageBreak } from "./pageBreak.js";
|
|
13
13
|
export { CLIPBOARD_READ_ERROR_EVENT, PAINTABLE_MARK_NAMES, acceptAIEditRevision, acceptAllChanges, acceptChange, addColumnLeft, addColumnRight, addCommentMark, addRowAbove, addRowBelow, addTabStop, alignCenter, alignJustify, alignLeft, alignRight, applyFormatMarks, applyStyle, applyTableStyle, autoFitContents, buildPlainTextSlice, captureFormatMarks, clearFontFamily, clearFontSize, clearFormatting, clearHighlight, clearStyle, clearTextColor, createRemoveMarkCommand, createSetMarkCommand, decreaseIndent, decreaseListLevel, deleteColumn, deleteRow, deleteTable, distributeColumns, doubleSpacing, findAIEditRevisionRange, findNextChange, findPreviousChange, generateTOC, getHyperlinkAttrs, getListInfo, getMarkAttr, getParagraphAlignment, getParagraphBidi, getSelectedText, getStyleId, getTableContext, increaseIndent, increaseListLevel, insertHyperlink, insertPageBreak, insertTable, isHyperlinkActive, isInList, isInTableCell as isInTable, isMarkActive, mergeCells, oneAndHalfSpacing, pasteWithoutFormatting, rejectAIEditRevision, rejectAllChanges, rejectChange, removeCommentMark, removeHyperlink, removeList, removeTabStop, removeTableBorders, selectColumn, selectRow, selectTable, setAlignment, setAllTableBorders, setCellBorder, setCellFillColor, setCellMargins, setCellTextDirection, setCellVerticalAlign, setFontFamily, setFontSize, setHighlight, setHyperlink, setIndentFirstLine, setIndentLeft, setIndentRight, setInsideTableBorders, setLineSpacing, setLtr, setOutsideTableBorders, setRowHeight, setRtl, setSpaceAfter, setSpaceBefore, setTableBorderColor, setTableBorderPreset, setTableBorderWidth, setTableBorders, setTableProperties, setTextColor, setUnderlineStyle, singleSpacing, splitCell, toggleBidi, toggleBold, toggleBulletList, toggleHeaderRow, toggleItalic, toggleNoWrap, toggleNumberedList, toggleStrike, toggleSubscript, toggleSuperscript, toggleUnderline };
|