docxodus 9.8.0 → 9.9.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/editor.bundle.js +164 -23
- package/dist/embed.bundle.js +164 -23
- package/dist/embed.iife.js +164 -23
- package/dist/pagination.bundle.js +163 -23
- package/dist/pagination.d.ts +28 -0
- package/dist/pagination.d.ts.map +1 -1
- package/dist/pagination.js +155 -27
- package/dist/pagination.js.map +1 -1
- package/dist/ribbon-chrome.d.ts +1 -1
- package/dist/ribbon-chrome.d.ts.map +1 -1
- package/dist/ribbon-chrome.js +1 -0
- package/dist/ribbon-chrome.js.map +1 -1
- package/dist/wasm/_framework/Docxodus.wasm +0 -0
- package/dist/wasm/_framework/Docxodus.wasm.br +0 -0
- package/dist/wasm/_framework/DocxodusWasm.wasm +0 -0
- package/dist/wasm/_framework/DocxodusWasm.wasm.br +0 -0
- package/dist/wasm/_framework/System.Collections.Concurrent.wasm +0 -0
- package/dist/wasm/_framework/System.Collections.Concurrent.wasm.br +0 -0
- package/dist/wasm/_framework/System.Collections.Immutable.wasm +0 -0
- package/dist/wasm/_framework/System.Collections.Immutable.wasm.br +0 -0
- package/dist/wasm/_framework/System.Collections.NonGeneric.wasm +0 -0
- package/dist/wasm/_framework/System.Collections.NonGeneric.wasm.br +0 -0
- package/dist/wasm/_framework/System.Collections.Specialized.wasm +0 -0
- package/dist/wasm/_framework/System.Collections.Specialized.wasm.br +0 -0
- package/dist/wasm/_framework/System.Collections.wasm +0 -0
- package/dist/wasm/_framework/System.Collections.wasm.br +0 -0
- package/dist/wasm/_framework/System.ComponentModel.Primitives.wasm +0 -0
- package/dist/wasm/_framework/System.ComponentModel.Primitives.wasm.br +0 -0
- package/dist/wasm/_framework/System.ComponentModel.TypeConverter.wasm +0 -0
- package/dist/wasm/_framework/System.ComponentModel.TypeConverter.wasm.br +0 -0
- package/dist/wasm/_framework/System.ComponentModel.wasm +0 -0
- package/dist/wasm/_framework/System.ComponentModel.wasm.br +0 -0
- package/dist/wasm/_framework/System.Console.wasm +0 -0
- package/dist/wasm/_framework/System.Console.wasm.br +0 -0
- package/dist/wasm/_framework/System.Diagnostics.Process.wasm +0 -0
- package/dist/wasm/_framework/System.Diagnostics.Process.wasm.br +0 -0
- package/dist/wasm/_framework/System.IO.Compression.wasm +0 -0
- package/dist/wasm/_framework/System.IO.Compression.wasm.br +0 -0
- package/dist/wasm/_framework/System.IO.Pipelines.wasm +0 -0
- package/dist/wasm/_framework/System.IO.Pipelines.wasm.br +0 -0
- package/dist/wasm/_framework/System.Linq.Expressions.wasm +0 -0
- package/dist/wasm/_framework/System.Linq.Expressions.wasm.br +0 -0
- package/dist/wasm/_framework/System.Linq.wasm +0 -0
- package/dist/wasm/_framework/System.Linq.wasm.br +0 -0
- package/dist/wasm/_framework/System.Memory.wasm +0 -0
- package/dist/wasm/_framework/System.Memory.wasm.br +0 -0
- package/dist/wasm/_framework/System.Net.Http.wasm +0 -0
- package/dist/wasm/_framework/System.Net.Http.wasm.br +0 -0
- package/dist/wasm/_framework/System.Net.Primitives.wasm +0 -0
- package/dist/wasm/_framework/System.Net.Primitives.wasm.br +0 -0
- package/dist/wasm/_framework/System.ObjectModel.wasm +0 -0
- package/dist/wasm/_framework/System.ObjectModel.wasm.br +0 -0
- package/dist/wasm/_framework/System.Private.CoreLib.wasm +0 -0
- package/dist/wasm/_framework/System.Private.CoreLib.wasm.br +0 -0
- package/dist/wasm/_framework/System.Private.Uri.wasm +0 -0
- package/dist/wasm/_framework/System.Private.Uri.wasm.br +0 -0
- package/dist/wasm/_framework/System.Private.Xml.Linq.wasm +0 -0
- package/dist/wasm/_framework/System.Private.Xml.Linq.wasm.br +0 -0
- package/dist/wasm/_framework/System.Private.Xml.wasm +0 -0
- package/dist/wasm/_framework/System.Private.Xml.wasm.br +0 -0
- package/dist/wasm/_framework/System.Runtime.InteropServices.JavaScript.wasm +0 -0
- package/dist/wasm/_framework/System.Runtime.InteropServices.JavaScript.wasm.br +0 -0
- package/dist/wasm/_framework/System.Runtime.wasm +0 -0
- package/dist/wasm/_framework/System.Runtime.wasm.br +0 -0
- package/dist/wasm/_framework/System.Security.Cryptography.wasm +0 -0
- package/dist/wasm/_framework/System.Security.Cryptography.wasm.br +0 -0
- package/dist/wasm/_framework/System.Text.Encodings.Web.wasm +0 -0
- package/dist/wasm/_framework/System.Text.Encodings.Web.wasm.br +0 -0
- package/dist/wasm/_framework/System.Text.Json.wasm +0 -0
- package/dist/wasm/_framework/System.Text.Json.wasm.br +0 -0
- package/dist/wasm/_framework/System.Text.RegularExpressions.wasm +0 -0
- package/dist/wasm/_framework/System.Text.RegularExpressions.wasm.br +0 -0
- package/dist/wasm/_framework/System.Xml.Linq.wasm +0 -0
- package/dist/wasm/_framework/System.Xml.Linq.wasm.br +0 -0
- package/dist/wasm/_framework/System.Xml.XDocument.wasm +0 -0
- package/dist/wasm/_framework/System.Xml.XDocument.wasm.br +0 -0
- package/dist/wasm/_framework/System.wasm +0 -0
- package/dist/wasm/_framework/System.wasm.br +0 -0
- package/dist/wasm/_framework/dotnet.boot.js +35 -35
- package/dist/wasm/_framework/dotnet.boot.js.br +0 -0
- package/dist/wasm/_framework/dotnet.js +1 -1
- package/dist/wasm/_framework/dotnet.js.br +0 -0
- package/dist/wasm/_framework/dotnet.native.js +3 -3
- package/dist/wasm/_framework/dotnet.native.js.br +0 -0
- package/dist/wasm/_framework/dotnet.native.wasm +0 -0
- package/dist/wasm/_framework/dotnet.native.wasm.br +0 -0
- package/dist/wasm/_framework/dotnet.runtime.js +1 -1
- package/dist/wasm/_framework/dotnet.runtime.js.br +0 -0
- package/package.json +5 -4
package/dist/embed.iife.js
CHANGED
|
@@ -1544,6 +1544,9 @@ var Docxodus = (() => {
|
|
|
1544
1544
|
}
|
|
1545
1545
|
|
|
1546
1546
|
// src/pagination.ts
|
|
1547
|
+
function samePageBox(a, b) {
|
|
1548
|
+
return a.pageWidth === b.pageWidth && a.pageHeight === b.pageHeight && a.marginTop === b.marginTop && a.marginRight === b.marginRight && a.marginBottom === b.marginBottom && a.marginLeft === b.marginLeft;
|
|
1549
|
+
}
|
|
1547
1550
|
var MAX_FOOTNOTE_AREA_RATIO = 0.6;
|
|
1548
1551
|
var MIN_BODY_CONTENT_HEIGHT = 72;
|
|
1549
1552
|
var PaginationEngine = class {
|
|
@@ -1589,16 +1592,43 @@ var Docxodus = (() => {
|
|
|
1589
1592
|
);
|
|
1590
1593
|
this.pageNumbering = this.parsePageNumbering(sections);
|
|
1591
1594
|
const sectionsToProcess = sections.length > 0 ? Array.from(sections) : [this.stagingElement];
|
|
1595
|
+
const runs = [];
|
|
1592
1596
|
for (const section of sectionsToProcess) {
|
|
1593
|
-
const sectionIndex = parseInt(section.dataset.sectionIndex || "0", 10);
|
|
1594
1597
|
const dims = parseSectionDimensions(section);
|
|
1598
|
+
const previous = runs[runs.length - 1];
|
|
1599
|
+
if (previous && section.dataset.sectionType === "continuous" && samePageBox(previous.dims, dims)) {
|
|
1600
|
+
previous.sections.push(section);
|
|
1601
|
+
} else {
|
|
1602
|
+
runs.push({
|
|
1603
|
+
sections: [section],
|
|
1604
|
+
sectionIndex: parseInt(section.dataset.sectionIndex || "0", 10),
|
|
1605
|
+
dims
|
|
1606
|
+
});
|
|
1607
|
+
}
|
|
1608
|
+
}
|
|
1609
|
+
for (const run of runs) {
|
|
1595
1610
|
this.stagingElement.style.visibility = "hidden";
|
|
1596
1611
|
this.stagingElement.style.position = "absolute";
|
|
1597
1612
|
this.stagingElement.style.left = "-9999px";
|
|
1598
1613
|
this.stagingElement.style.display = "block";
|
|
1599
|
-
|
|
1600
|
-
const
|
|
1601
|
-
|
|
1614
|
+
const blocks = [];
|
|
1615
|
+
for (const section of run.sections) {
|
|
1616
|
+
section.style.width = `${run.dims.contentWidth}pt`;
|
|
1617
|
+
const columnCount = parseInt(section.dataset.cols || "1", 10);
|
|
1618
|
+
if (columnCount > 1) {
|
|
1619
|
+
const gap = parseFloat(section.dataset.colGap || "");
|
|
1620
|
+
blocks.push(...this.buildColumnBlocks(
|
|
1621
|
+
section,
|
|
1622
|
+
run.dims,
|
|
1623
|
+
run.sectionIndex,
|
|
1624
|
+
columnCount,
|
|
1625
|
+
Number.isFinite(gap) ? gap : 36
|
|
1626
|
+
));
|
|
1627
|
+
} else {
|
|
1628
|
+
blocks.push(...this.measureBlocks(section, run.dims));
|
|
1629
|
+
}
|
|
1630
|
+
}
|
|
1631
|
+
const sectionPages = this.flowToPages(blocks, run.dims, pageNumber, run.sectionIndex);
|
|
1602
1632
|
pages.push(...sectionPages);
|
|
1603
1633
|
pageNumber += sectionPages.length;
|
|
1604
1634
|
}
|
|
@@ -1687,11 +1717,70 @@ var Docxodus = (() => {
|
|
|
1687
1717
|
keepWithNext: child.dataset.keepWithNext === "true",
|
|
1688
1718
|
keepLines: child.dataset.keepLines === "true",
|
|
1689
1719
|
pageBreakBefore: child.dataset.pageBreakBefore === "true",
|
|
1690
|
-
isPageBreak
|
|
1720
|
+
isPageBreak,
|
|
1721
|
+
isWordParagraph: this.isWordParagraphElement(child)
|
|
1691
1722
|
});
|
|
1692
1723
|
}
|
|
1693
1724
|
return blocks;
|
|
1694
1725
|
}
|
|
1726
|
+
/**
|
|
1727
|
+
* Flows a multi-column (`w:cols`) section's children into CSS-multicol container
|
|
1728
|
+
* blocks. Word lays such a section out as N columns inside the same body extent;
|
|
1729
|
+
* a balanced `column-count` container reproduces that geometry, and the paginator
|
|
1730
|
+
* then places each container as one ordinary measured block. A container grows
|
|
1731
|
+
* greedily until its balanced height would exceed the smallest page body available
|
|
1732
|
+
* to the section, so a long columned section still splits across pages at block
|
|
1733
|
+
* boundaries. Each child lands in exactly one container, so anchors never
|
|
1734
|
+
* duplicate. An explicit page break child passes through as its own block, which
|
|
1735
|
+
* ends the current container and lets the normal flow logic turn the page.
|
|
1736
|
+
*/
|
|
1737
|
+
buildColumnBlocks(section, dims, sectionIndex, columnCount, columnGapPt) {
|
|
1738
|
+
const children = Array.from(section.children);
|
|
1739
|
+
const blocks = [];
|
|
1740
|
+
const maxFragmentHeight = this.smallestEffectiveContentHeight(dims, sectionIndex);
|
|
1741
|
+
const isBreak = (child) => child.dataset.pageBreak === "true" || child.classList.contains(`${this.cssPrefix}break`);
|
|
1742
|
+
const makeContainer = (slice) => {
|
|
1743
|
+
const container = document.createElement("div");
|
|
1744
|
+
container.style.columnCount = String(columnCount);
|
|
1745
|
+
container.style.columnGap = `${columnGapPt}pt`;
|
|
1746
|
+
for (const child of slice) {
|
|
1747
|
+
container.appendChild(child.cloneNode(true));
|
|
1748
|
+
}
|
|
1749
|
+
return container;
|
|
1750
|
+
};
|
|
1751
|
+
let start2 = 0;
|
|
1752
|
+
while (start2 < children.length) {
|
|
1753
|
+
if (isBreak(children[start2])) {
|
|
1754
|
+
blocks.push(this.measureElement(children[start2], dims));
|
|
1755
|
+
start2++;
|
|
1756
|
+
continue;
|
|
1757
|
+
}
|
|
1758
|
+
let end = start2 + 1;
|
|
1759
|
+
let container = makeContainer(children.slice(start2, end));
|
|
1760
|
+
let measured = this.measureElement(container, dims);
|
|
1761
|
+
while (end < children.length && !isBreak(children[end])) {
|
|
1762
|
+
const candidate = makeContainer(children.slice(start2, end + 1));
|
|
1763
|
+
const candidateMeasured = this.measureElement(candidate, dims);
|
|
1764
|
+
if (candidateMeasured.heightPt > maxFragmentHeight) break;
|
|
1765
|
+
container = candidate;
|
|
1766
|
+
measured = candidateMeasured;
|
|
1767
|
+
end++;
|
|
1768
|
+
}
|
|
1769
|
+
blocks.push({
|
|
1770
|
+
element: container,
|
|
1771
|
+
heightPt: measured.heightPt,
|
|
1772
|
+
marginTopPt: measured.marginTopPt,
|
|
1773
|
+
marginBottomPt: measured.marginBottomPt,
|
|
1774
|
+
keepWithNext: false,
|
|
1775
|
+
keepLines: false,
|
|
1776
|
+
pageBreakBefore: false,
|
|
1777
|
+
isPageBreak: false,
|
|
1778
|
+
isWordParagraph: false
|
|
1779
|
+
});
|
|
1780
|
+
start2 = end;
|
|
1781
|
+
}
|
|
1782
|
+
return blocks;
|
|
1783
|
+
}
|
|
1695
1784
|
/**
|
|
1696
1785
|
* Measures one element in the same hidden staging context used for the source blocks.
|
|
1697
1786
|
* This is intentionally DOM-based: table row heights cannot be inferred from individual
|
|
@@ -1716,7 +1805,8 @@ var Docxodus = (() => {
|
|
|
1716
1805
|
keepWithNext: element.dataset.keepWithNext === "true",
|
|
1717
1806
|
keepLines: element.dataset.keepLines === "true",
|
|
1718
1807
|
pageBreakBefore: element.dataset.pageBreakBefore === "true",
|
|
1719
|
-
isPageBreak: element.dataset.pageBreak === "true" || element.classList.contains(`${this.cssPrefix}break`)
|
|
1808
|
+
isPageBreak: element.dataset.pageBreak === "true" || element.classList.contains(`${this.cssPrefix}break`),
|
|
1809
|
+
isWordParagraph: this.isWordParagraphElement(element)
|
|
1720
1810
|
};
|
|
1721
1811
|
this.stagingElement.removeChild(measurementHost);
|
|
1722
1812
|
return measured;
|
|
@@ -1748,10 +1838,15 @@ var Docxodus = (() => {
|
|
|
1748
1838
|
* collapsed-margin rules as normal block placement. The trailing margin is
|
|
1749
1839
|
* intentionally excluded, matching the individual block fit check.
|
|
1750
1840
|
*/
|
|
1751
|
-
measureKeepWithNextChainBodyHeight(chain, previousMarginBottomPt, isFirstOnPage) {
|
|
1841
|
+
measureKeepWithNextChainBodyHeight(chain, previousMarginBottomPt, isFirstOnPage, pageInSection) {
|
|
1752
1842
|
const firstBlock = chain[0];
|
|
1753
1843
|
if (!firstBlock) return 0;
|
|
1754
|
-
const firstMarginTop =
|
|
1844
|
+
const firstMarginTop = this.effectiveBlockMarginTop(
|
|
1845
|
+
firstBlock,
|
|
1846
|
+
previousMarginBottomPt,
|
|
1847
|
+
isFirstOnPage,
|
|
1848
|
+
pageInSection
|
|
1849
|
+
);
|
|
1755
1850
|
let bodyHeight = firstMarginTop + firstBlock.heightPt;
|
|
1756
1851
|
for (let index = 1; index < chain.length; index++) {
|
|
1757
1852
|
const previousBlock = chain[index - 1];
|
|
@@ -1760,6 +1855,35 @@ var Docxodus = (() => {
|
|
|
1760
1855
|
}
|
|
1761
1856
|
return bodyHeight;
|
|
1762
1857
|
}
|
|
1858
|
+
/** Word paragraphs render as `p`, or as `h1`–`h6` when their style has an outline level. */
|
|
1859
|
+
isWordParagraphElement(element) {
|
|
1860
|
+
return element.tagName === "P" || /^H[1-6]$/.test(element.tagName);
|
|
1861
|
+
}
|
|
1862
|
+
shouldSuppressPageTopSpacing(block, isFirstOnPage, pageInSection) {
|
|
1863
|
+
return isFirstOnPage && pageInSection > 1 && block.isWordParagraph === true;
|
|
1864
|
+
}
|
|
1865
|
+
/**
|
|
1866
|
+
* Resolves the part of a block's top margin that consumes the current page.
|
|
1867
|
+
*
|
|
1868
|
+
* In Word's native DOCX layout, paragraph space-before is suppressed when a paragraph is the
|
|
1869
|
+
* first body block on a later page of the SAME section. The first page of a document/section is
|
|
1870
|
+
* the exception and keeps its spacing. Tables and other block margins are not paragraph spacing,
|
|
1871
|
+
* so they continue to use the ordinary CSS collapsing rule.
|
|
1872
|
+
*/
|
|
1873
|
+
effectiveBlockMarginTop(block, previousMarginBottomPt, isFirstOnPage, pageInSection) {
|
|
1874
|
+
if (this.shouldSuppressPageTopSpacing(block, isFirstOnPage, pageInSection)) {
|
|
1875
|
+
return 0;
|
|
1876
|
+
}
|
|
1877
|
+
return isFirstOnPage ? block.marginTopPt : Math.max(block.marginTopPt, previousMarginBottomPt) - previousMarginBottomPt;
|
|
1878
|
+
}
|
|
1879
|
+
/** Clone a source block with the same page-top spacing decision used by the height budget. */
|
|
1880
|
+
cloneBlockForPage(block, isFirstOnPage, pageInSection) {
|
|
1881
|
+
const clone = block.element.cloneNode(true);
|
|
1882
|
+
if (this.shouldSuppressPageTopSpacing(block, isFirstOnPage, pageInSection)) {
|
|
1883
|
+
clone.style.setProperty("margin-top", "0", "important");
|
|
1884
|
+
}
|
|
1885
|
+
return clone;
|
|
1886
|
+
}
|
|
1763
1887
|
/**
|
|
1764
1888
|
* Finds footnote references introduced by a sequence of blocks, preserving
|
|
1765
1889
|
* document order and excluding references already assigned to the page.
|
|
@@ -2565,7 +2689,8 @@ var Docxodus = (() => {
|
|
|
2565
2689
|
const currentChainHeight = this.measureKeepWithNextChainBodyHeight(
|
|
2566
2690
|
keepChain,
|
|
2567
2691
|
prevMarginBottomPt,
|
|
2568
|
-
currentContent.length === 0
|
|
2692
|
+
currentContent.length === 0,
|
|
2693
|
+
pageInSection
|
|
2569
2694
|
) + additionalChainFootnoteHeight;
|
|
2570
2695
|
const currentAvailableHeight = remainingHeight - currentFootnoteHeight;
|
|
2571
2696
|
if (currentChainHeight > currentAvailableHeight) {
|
|
@@ -2578,7 +2703,8 @@ var Docxodus = (() => {
|
|
|
2578
2703
|
const freshChainBodyHeight = this.measureKeepWithNextChainBodyHeight(
|
|
2579
2704
|
keepChain,
|
|
2580
2705
|
0,
|
|
2581
|
-
true
|
|
2706
|
+
true,
|
|
2707
|
+
pageInSection + 1
|
|
2582
2708
|
);
|
|
2583
2709
|
const freshChainFootnoteHeight = this.measureFootnotesHeight(
|
|
2584
2710
|
newChainFootnoteIds,
|
|
@@ -2604,10 +2730,12 @@ var Docxodus = (() => {
|
|
|
2604
2730
|
additionalFootnoteHeight = totalFootnoteHeight - currentFootnoteHeight;
|
|
2605
2731
|
}
|
|
2606
2732
|
const isFirstOnPage = currentContent.length === 0;
|
|
2607
|
-
|
|
2608
|
-
|
|
2609
|
-
|
|
2610
|
-
|
|
2733
|
+
const effectiveMarginTop = this.effectiveBlockMarginTop(
|
|
2734
|
+
block,
|
|
2735
|
+
prevMarginBottomPt,
|
|
2736
|
+
isFirstOnPage,
|
|
2737
|
+
pageInSection
|
|
2738
|
+
);
|
|
2611
2739
|
const blockSpace = effectiveMarginTop + block.heightPt + additionalFootnoteHeight;
|
|
2612
2740
|
const effectiveRemainingHeight = remainingHeight - currentFootnoteHeight;
|
|
2613
2741
|
const bodyContentUsed = effectiveContentHeight - remainingHeight;
|
|
@@ -2627,19 +2755,19 @@ var Docxodus = (() => {
|
|
|
2627
2755
|
}
|
|
2628
2756
|
}
|
|
2629
2757
|
if (blockSpace <= effectiveRemainingHeight) {
|
|
2630
|
-
currentContent.push(
|
|
2758
|
+
currentContent.push(this.cloneBlockForPage(block, isFirstOnPage, pageInSection));
|
|
2631
2759
|
remainingHeight -= effectiveMarginTop + block.heightPt + block.marginBottomPt;
|
|
2632
2760
|
prevMarginBottomPt = block.marginBottomPt;
|
|
2633
2761
|
if (newFootnoteIds.length > 0) {
|
|
2634
2762
|
currentFootnoteIds.push(...newFootnoteIds);
|
|
2635
2763
|
currentFootnoteHeight += additionalFootnoteHeight;
|
|
2636
2764
|
}
|
|
2637
|
-
} else if (block.heightPt + block
|
|
2765
|
+
} else if (block.heightPt + this.effectiveBlockMarginTop(block, 0, true, pageInSection + 1) <= effectiveContentHeight) {
|
|
2638
2766
|
const blockSpaceWithoutFootnotes = effectiveMarginTop + block.heightPt;
|
|
2639
2767
|
const minBodySpaceNeeded = bodyContentUsed + blockSpaceWithoutFootnotes + MIN_BODY_CONTENT_HEIGHT;
|
|
2640
2768
|
const canExpandFootnotes = minBodySpaceNeeded <= effectiveContentHeight;
|
|
2641
2769
|
if (newFootnoteIds.length > 0 && blockSpaceWithoutFootnotes <= effectiveRemainingHeight) {
|
|
2642
|
-
currentContent.push(
|
|
2770
|
+
currentContent.push(this.cloneBlockForPage(block, isFirstOnPage, pageInSection));
|
|
2643
2771
|
remainingHeight -= effectiveMarginTop + block.heightPt + block.marginBottomPt;
|
|
2644
2772
|
prevMarginBottomPt = block.marginBottomPt;
|
|
2645
2773
|
const availableForFootnotes = Math.min(
|
|
@@ -2686,7 +2814,7 @@ var Docxodus = (() => {
|
|
|
2686
2814
|
const expandedFootnoteSpace = Math.min(maxFootnoteArea, additionalFootnoteHeight + currentFootnoteHeight);
|
|
2687
2815
|
const bodySpaceAfterExpansion = effectiveContentHeight - expandedFootnoteSpace;
|
|
2688
2816
|
if (blockSpaceWithoutFootnotes <= bodySpaceAfterExpansion - bodyContentUsed) {
|
|
2689
|
-
currentContent.push(
|
|
2817
|
+
currentContent.push(this.cloneBlockForPage(block, isFirstOnPage, pageInSection));
|
|
2690
2818
|
remainingHeight = bodySpaceAfterExpansion - bodyContentUsed - blockSpaceWithoutFootnotes;
|
|
2691
2819
|
prevMarginBottomPt = block.marginBottomPt;
|
|
2692
2820
|
currentFootnoteIds.push(...newFootnoteIds);
|
|
@@ -2694,8 +2822,14 @@ var Docxodus = (() => {
|
|
|
2694
2822
|
} else {
|
|
2695
2823
|
finishPage();
|
|
2696
2824
|
const newPageFootnoteHeight = allBlockFootnoteIds.length > 0 ? this.measureFootnotesHeight(allBlockFootnoteIds, dims.contentWidth, currentContinuation) : currentContinuation ? this.measureContinuationHeight(currentContinuation, dims.contentWidth) : 0;
|
|
2697
|
-
const
|
|
2698
|
-
|
|
2825
|
+
const newPageMarginTop = this.effectiveBlockMarginTop(
|
|
2826
|
+
block,
|
|
2827
|
+
0,
|
|
2828
|
+
true,
|
|
2829
|
+
pageInSection
|
|
2830
|
+
);
|
|
2831
|
+
const newPageSpace = newPageMarginTop + block.heightPt + block.marginBottomPt;
|
|
2832
|
+
currentContent.push(this.cloneBlockForPage(block, true, pageInSection));
|
|
2699
2833
|
remainingHeight = effectiveContentHeight - newPageSpace;
|
|
2700
2834
|
prevMarginBottomPt = block.marginBottomPt;
|
|
2701
2835
|
currentFootnoteIds = [...currentFootnoteIds, ...allBlockFootnoteIds];
|
|
@@ -2704,8 +2838,14 @@ var Docxodus = (() => {
|
|
|
2704
2838
|
} else {
|
|
2705
2839
|
finishPage();
|
|
2706
2840
|
const newPageFootnoteHeight = allBlockFootnoteIds.length > 0 ? this.measureFootnotesHeight(allBlockFootnoteIds, dims.contentWidth, currentContinuation) : currentContinuation ? this.measureContinuationHeight(currentContinuation, dims.contentWidth) : 0;
|
|
2707
|
-
const
|
|
2708
|
-
|
|
2841
|
+
const newPageMarginTop = this.effectiveBlockMarginTop(
|
|
2842
|
+
block,
|
|
2843
|
+
0,
|
|
2844
|
+
true,
|
|
2845
|
+
pageInSection
|
|
2846
|
+
);
|
|
2847
|
+
const newPageSpace = newPageMarginTop + block.heightPt + block.marginBottomPt;
|
|
2848
|
+
currentContent.push(this.cloneBlockForPage(block, true, pageInSection));
|
|
2709
2849
|
remainingHeight = effectiveContentHeight - newPageSpace;
|
|
2710
2850
|
prevMarginBottomPt = block.marginBottomPt;
|
|
2711
2851
|
currentFootnoteIds = [...currentFootnoteIds, ...allBlockFootnoteIds];
|
|
@@ -2724,7 +2864,7 @@ var Docxodus = (() => {
|
|
|
2724
2864
|
if (currentContent.length > 0) {
|
|
2725
2865
|
finishPage();
|
|
2726
2866
|
}
|
|
2727
|
-
currentContent.push(
|
|
2867
|
+
currentContent.push(this.cloneBlockForPage(block, true, pageInSection));
|
|
2728
2868
|
currentFootnoteIds = [...currentFootnoteIds, ...allBlockFootnoteIds];
|
|
2729
2869
|
finishPage();
|
|
2730
2870
|
}
|
|
@@ -9254,6 +9394,7 @@ var Docxodus = (() => {
|
|
|
9254
9394
|
color: var(--dxr-ink);
|
|
9255
9395
|
background: var(--dxr-desk);
|
|
9256
9396
|
-webkit-text-size-adjust: 100%;
|
|
9397
|
+
text-size-adjust: 100%;
|
|
9257
9398
|
}
|
|
9258
9399
|
.dxr *, .dxr *::before, .dxr *::after { box-sizing: border-box; }
|
|
9259
9400
|
|
|
@@ -125,6 +125,9 @@ var DocxodusPagination = (() => {
|
|
|
125
125
|
}
|
|
126
126
|
|
|
127
127
|
// src/pagination.ts
|
|
128
|
+
function samePageBox(a, b) {
|
|
129
|
+
return a.pageWidth === b.pageWidth && a.pageHeight === b.pageHeight && a.marginTop === b.marginTop && a.marginRight === b.marginRight && a.marginBottom === b.marginBottom && a.marginLeft === b.marginLeft;
|
|
130
|
+
}
|
|
128
131
|
var MAX_FOOTNOTE_AREA_RATIO = 0.6;
|
|
129
132
|
var MIN_BODY_CONTENT_HEIGHT = 72;
|
|
130
133
|
var PaginationEngine = class {
|
|
@@ -170,16 +173,43 @@ var DocxodusPagination = (() => {
|
|
|
170
173
|
);
|
|
171
174
|
this.pageNumbering = this.parsePageNumbering(sections);
|
|
172
175
|
const sectionsToProcess = sections.length > 0 ? Array.from(sections) : [this.stagingElement];
|
|
176
|
+
const runs = [];
|
|
173
177
|
for (const section of sectionsToProcess) {
|
|
174
|
-
const sectionIndex = parseInt(section.dataset.sectionIndex || "0", 10);
|
|
175
178
|
const dims = parseSectionDimensions(section);
|
|
179
|
+
const previous = runs[runs.length - 1];
|
|
180
|
+
if (previous && section.dataset.sectionType === "continuous" && samePageBox(previous.dims, dims)) {
|
|
181
|
+
previous.sections.push(section);
|
|
182
|
+
} else {
|
|
183
|
+
runs.push({
|
|
184
|
+
sections: [section],
|
|
185
|
+
sectionIndex: parseInt(section.dataset.sectionIndex || "0", 10),
|
|
186
|
+
dims
|
|
187
|
+
});
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
for (const run of runs) {
|
|
176
191
|
this.stagingElement.style.visibility = "hidden";
|
|
177
192
|
this.stagingElement.style.position = "absolute";
|
|
178
193
|
this.stagingElement.style.left = "-9999px";
|
|
179
194
|
this.stagingElement.style.display = "block";
|
|
180
|
-
|
|
181
|
-
const
|
|
182
|
-
|
|
195
|
+
const blocks = [];
|
|
196
|
+
for (const section of run.sections) {
|
|
197
|
+
section.style.width = `${run.dims.contentWidth}pt`;
|
|
198
|
+
const columnCount = parseInt(section.dataset.cols || "1", 10);
|
|
199
|
+
if (columnCount > 1) {
|
|
200
|
+
const gap = parseFloat(section.dataset.colGap || "");
|
|
201
|
+
blocks.push(...this.buildColumnBlocks(
|
|
202
|
+
section,
|
|
203
|
+
run.dims,
|
|
204
|
+
run.sectionIndex,
|
|
205
|
+
columnCount,
|
|
206
|
+
Number.isFinite(gap) ? gap : 36
|
|
207
|
+
));
|
|
208
|
+
} else {
|
|
209
|
+
blocks.push(...this.measureBlocks(section, run.dims));
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
const sectionPages = this.flowToPages(blocks, run.dims, pageNumber, run.sectionIndex);
|
|
183
213
|
pages.push(...sectionPages);
|
|
184
214
|
pageNumber += sectionPages.length;
|
|
185
215
|
}
|
|
@@ -268,11 +298,70 @@ var DocxodusPagination = (() => {
|
|
|
268
298
|
keepWithNext: child.dataset.keepWithNext === "true",
|
|
269
299
|
keepLines: child.dataset.keepLines === "true",
|
|
270
300
|
pageBreakBefore: child.dataset.pageBreakBefore === "true",
|
|
271
|
-
isPageBreak
|
|
301
|
+
isPageBreak,
|
|
302
|
+
isWordParagraph: this.isWordParagraphElement(child)
|
|
272
303
|
});
|
|
273
304
|
}
|
|
274
305
|
return blocks;
|
|
275
306
|
}
|
|
307
|
+
/**
|
|
308
|
+
* Flows a multi-column (`w:cols`) section's children into CSS-multicol container
|
|
309
|
+
* blocks. Word lays such a section out as N columns inside the same body extent;
|
|
310
|
+
* a balanced `column-count` container reproduces that geometry, and the paginator
|
|
311
|
+
* then places each container as one ordinary measured block. A container grows
|
|
312
|
+
* greedily until its balanced height would exceed the smallest page body available
|
|
313
|
+
* to the section, so a long columned section still splits across pages at block
|
|
314
|
+
* boundaries. Each child lands in exactly one container, so anchors never
|
|
315
|
+
* duplicate. An explicit page break child passes through as its own block, which
|
|
316
|
+
* ends the current container and lets the normal flow logic turn the page.
|
|
317
|
+
*/
|
|
318
|
+
buildColumnBlocks(section, dims, sectionIndex, columnCount, columnGapPt) {
|
|
319
|
+
const children = Array.from(section.children);
|
|
320
|
+
const blocks = [];
|
|
321
|
+
const maxFragmentHeight = this.smallestEffectiveContentHeight(dims, sectionIndex);
|
|
322
|
+
const isBreak = (child) => child.dataset.pageBreak === "true" || child.classList.contains(`${this.cssPrefix}break`);
|
|
323
|
+
const makeContainer = (slice) => {
|
|
324
|
+
const container = document.createElement("div");
|
|
325
|
+
container.style.columnCount = String(columnCount);
|
|
326
|
+
container.style.columnGap = `${columnGapPt}pt`;
|
|
327
|
+
for (const child of slice) {
|
|
328
|
+
container.appendChild(child.cloneNode(true));
|
|
329
|
+
}
|
|
330
|
+
return container;
|
|
331
|
+
};
|
|
332
|
+
let start = 0;
|
|
333
|
+
while (start < children.length) {
|
|
334
|
+
if (isBreak(children[start])) {
|
|
335
|
+
blocks.push(this.measureElement(children[start], dims));
|
|
336
|
+
start++;
|
|
337
|
+
continue;
|
|
338
|
+
}
|
|
339
|
+
let end = start + 1;
|
|
340
|
+
let container = makeContainer(children.slice(start, end));
|
|
341
|
+
let measured = this.measureElement(container, dims);
|
|
342
|
+
while (end < children.length && !isBreak(children[end])) {
|
|
343
|
+
const candidate = makeContainer(children.slice(start, end + 1));
|
|
344
|
+
const candidateMeasured = this.measureElement(candidate, dims);
|
|
345
|
+
if (candidateMeasured.heightPt > maxFragmentHeight) break;
|
|
346
|
+
container = candidate;
|
|
347
|
+
measured = candidateMeasured;
|
|
348
|
+
end++;
|
|
349
|
+
}
|
|
350
|
+
blocks.push({
|
|
351
|
+
element: container,
|
|
352
|
+
heightPt: measured.heightPt,
|
|
353
|
+
marginTopPt: measured.marginTopPt,
|
|
354
|
+
marginBottomPt: measured.marginBottomPt,
|
|
355
|
+
keepWithNext: false,
|
|
356
|
+
keepLines: false,
|
|
357
|
+
pageBreakBefore: false,
|
|
358
|
+
isPageBreak: false,
|
|
359
|
+
isWordParagraph: false
|
|
360
|
+
});
|
|
361
|
+
start = end;
|
|
362
|
+
}
|
|
363
|
+
return blocks;
|
|
364
|
+
}
|
|
276
365
|
/**
|
|
277
366
|
* Measures one element in the same hidden staging context used for the source blocks.
|
|
278
367
|
* This is intentionally DOM-based: table row heights cannot be inferred from individual
|
|
@@ -297,7 +386,8 @@ var DocxodusPagination = (() => {
|
|
|
297
386
|
keepWithNext: element.dataset.keepWithNext === "true",
|
|
298
387
|
keepLines: element.dataset.keepLines === "true",
|
|
299
388
|
pageBreakBefore: element.dataset.pageBreakBefore === "true",
|
|
300
|
-
isPageBreak: element.dataset.pageBreak === "true" || element.classList.contains(`${this.cssPrefix}break`)
|
|
389
|
+
isPageBreak: element.dataset.pageBreak === "true" || element.classList.contains(`${this.cssPrefix}break`),
|
|
390
|
+
isWordParagraph: this.isWordParagraphElement(element)
|
|
301
391
|
};
|
|
302
392
|
this.stagingElement.removeChild(measurementHost);
|
|
303
393
|
return measured;
|
|
@@ -329,10 +419,15 @@ var DocxodusPagination = (() => {
|
|
|
329
419
|
* collapsed-margin rules as normal block placement. The trailing margin is
|
|
330
420
|
* intentionally excluded, matching the individual block fit check.
|
|
331
421
|
*/
|
|
332
|
-
measureKeepWithNextChainBodyHeight(chain, previousMarginBottomPt, isFirstOnPage) {
|
|
422
|
+
measureKeepWithNextChainBodyHeight(chain, previousMarginBottomPt, isFirstOnPage, pageInSection) {
|
|
333
423
|
const firstBlock = chain[0];
|
|
334
424
|
if (!firstBlock) return 0;
|
|
335
|
-
const firstMarginTop =
|
|
425
|
+
const firstMarginTop = this.effectiveBlockMarginTop(
|
|
426
|
+
firstBlock,
|
|
427
|
+
previousMarginBottomPt,
|
|
428
|
+
isFirstOnPage,
|
|
429
|
+
pageInSection
|
|
430
|
+
);
|
|
336
431
|
let bodyHeight = firstMarginTop + firstBlock.heightPt;
|
|
337
432
|
for (let index = 1; index < chain.length; index++) {
|
|
338
433
|
const previousBlock = chain[index - 1];
|
|
@@ -341,6 +436,35 @@ var DocxodusPagination = (() => {
|
|
|
341
436
|
}
|
|
342
437
|
return bodyHeight;
|
|
343
438
|
}
|
|
439
|
+
/** Word paragraphs render as `p`, or as `h1`–`h6` when their style has an outline level. */
|
|
440
|
+
isWordParagraphElement(element) {
|
|
441
|
+
return element.tagName === "P" || /^H[1-6]$/.test(element.tagName);
|
|
442
|
+
}
|
|
443
|
+
shouldSuppressPageTopSpacing(block, isFirstOnPage, pageInSection) {
|
|
444
|
+
return isFirstOnPage && pageInSection > 1 && block.isWordParagraph === true;
|
|
445
|
+
}
|
|
446
|
+
/**
|
|
447
|
+
* Resolves the part of a block's top margin that consumes the current page.
|
|
448
|
+
*
|
|
449
|
+
* In Word's native DOCX layout, paragraph space-before is suppressed when a paragraph is the
|
|
450
|
+
* first body block on a later page of the SAME section. The first page of a document/section is
|
|
451
|
+
* the exception and keeps its spacing. Tables and other block margins are not paragraph spacing,
|
|
452
|
+
* so they continue to use the ordinary CSS collapsing rule.
|
|
453
|
+
*/
|
|
454
|
+
effectiveBlockMarginTop(block, previousMarginBottomPt, isFirstOnPage, pageInSection) {
|
|
455
|
+
if (this.shouldSuppressPageTopSpacing(block, isFirstOnPage, pageInSection)) {
|
|
456
|
+
return 0;
|
|
457
|
+
}
|
|
458
|
+
return isFirstOnPage ? block.marginTopPt : Math.max(block.marginTopPt, previousMarginBottomPt) - previousMarginBottomPt;
|
|
459
|
+
}
|
|
460
|
+
/** Clone a source block with the same page-top spacing decision used by the height budget. */
|
|
461
|
+
cloneBlockForPage(block, isFirstOnPage, pageInSection) {
|
|
462
|
+
const clone = block.element.cloneNode(true);
|
|
463
|
+
if (this.shouldSuppressPageTopSpacing(block, isFirstOnPage, pageInSection)) {
|
|
464
|
+
clone.style.setProperty("margin-top", "0", "important");
|
|
465
|
+
}
|
|
466
|
+
return clone;
|
|
467
|
+
}
|
|
344
468
|
/**
|
|
345
469
|
* Finds footnote references introduced by a sequence of blocks, preserving
|
|
346
470
|
* document order and excluding references already assigned to the page.
|
|
@@ -1146,7 +1270,8 @@ var DocxodusPagination = (() => {
|
|
|
1146
1270
|
const currentChainHeight = this.measureKeepWithNextChainBodyHeight(
|
|
1147
1271
|
keepChain,
|
|
1148
1272
|
prevMarginBottomPt,
|
|
1149
|
-
currentContent.length === 0
|
|
1273
|
+
currentContent.length === 0,
|
|
1274
|
+
pageInSection
|
|
1150
1275
|
) + additionalChainFootnoteHeight;
|
|
1151
1276
|
const currentAvailableHeight = remainingHeight - currentFootnoteHeight;
|
|
1152
1277
|
if (currentChainHeight > currentAvailableHeight) {
|
|
@@ -1159,7 +1284,8 @@ var DocxodusPagination = (() => {
|
|
|
1159
1284
|
const freshChainBodyHeight = this.measureKeepWithNextChainBodyHeight(
|
|
1160
1285
|
keepChain,
|
|
1161
1286
|
0,
|
|
1162
|
-
true
|
|
1287
|
+
true,
|
|
1288
|
+
pageInSection + 1
|
|
1163
1289
|
);
|
|
1164
1290
|
const freshChainFootnoteHeight = this.measureFootnotesHeight(
|
|
1165
1291
|
newChainFootnoteIds,
|
|
@@ -1185,10 +1311,12 @@ var DocxodusPagination = (() => {
|
|
|
1185
1311
|
additionalFootnoteHeight = totalFootnoteHeight - currentFootnoteHeight;
|
|
1186
1312
|
}
|
|
1187
1313
|
const isFirstOnPage = currentContent.length === 0;
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
|
|
1314
|
+
const effectiveMarginTop = this.effectiveBlockMarginTop(
|
|
1315
|
+
block,
|
|
1316
|
+
prevMarginBottomPt,
|
|
1317
|
+
isFirstOnPage,
|
|
1318
|
+
pageInSection
|
|
1319
|
+
);
|
|
1192
1320
|
const blockSpace = effectiveMarginTop + block.heightPt + additionalFootnoteHeight;
|
|
1193
1321
|
const effectiveRemainingHeight = remainingHeight - currentFootnoteHeight;
|
|
1194
1322
|
const bodyContentUsed = effectiveContentHeight - remainingHeight;
|
|
@@ -1208,19 +1336,19 @@ var DocxodusPagination = (() => {
|
|
|
1208
1336
|
}
|
|
1209
1337
|
}
|
|
1210
1338
|
if (blockSpace <= effectiveRemainingHeight) {
|
|
1211
|
-
currentContent.push(
|
|
1339
|
+
currentContent.push(this.cloneBlockForPage(block, isFirstOnPage, pageInSection));
|
|
1212
1340
|
remainingHeight -= effectiveMarginTop + block.heightPt + block.marginBottomPt;
|
|
1213
1341
|
prevMarginBottomPt = block.marginBottomPt;
|
|
1214
1342
|
if (newFootnoteIds.length > 0) {
|
|
1215
1343
|
currentFootnoteIds.push(...newFootnoteIds);
|
|
1216
1344
|
currentFootnoteHeight += additionalFootnoteHeight;
|
|
1217
1345
|
}
|
|
1218
|
-
} else if (block.heightPt + block
|
|
1346
|
+
} else if (block.heightPt + this.effectiveBlockMarginTop(block, 0, true, pageInSection + 1) <= effectiveContentHeight) {
|
|
1219
1347
|
const blockSpaceWithoutFootnotes = effectiveMarginTop + block.heightPt;
|
|
1220
1348
|
const minBodySpaceNeeded = bodyContentUsed + blockSpaceWithoutFootnotes + MIN_BODY_CONTENT_HEIGHT;
|
|
1221
1349
|
const canExpandFootnotes = minBodySpaceNeeded <= effectiveContentHeight;
|
|
1222
1350
|
if (newFootnoteIds.length > 0 && blockSpaceWithoutFootnotes <= effectiveRemainingHeight) {
|
|
1223
|
-
currentContent.push(
|
|
1351
|
+
currentContent.push(this.cloneBlockForPage(block, isFirstOnPage, pageInSection));
|
|
1224
1352
|
remainingHeight -= effectiveMarginTop + block.heightPt + block.marginBottomPt;
|
|
1225
1353
|
prevMarginBottomPt = block.marginBottomPt;
|
|
1226
1354
|
const availableForFootnotes = Math.min(
|
|
@@ -1267,7 +1395,7 @@ var DocxodusPagination = (() => {
|
|
|
1267
1395
|
const expandedFootnoteSpace = Math.min(maxFootnoteArea, additionalFootnoteHeight + currentFootnoteHeight);
|
|
1268
1396
|
const bodySpaceAfterExpansion = effectiveContentHeight - expandedFootnoteSpace;
|
|
1269
1397
|
if (blockSpaceWithoutFootnotes <= bodySpaceAfterExpansion - bodyContentUsed) {
|
|
1270
|
-
currentContent.push(
|
|
1398
|
+
currentContent.push(this.cloneBlockForPage(block, isFirstOnPage, pageInSection));
|
|
1271
1399
|
remainingHeight = bodySpaceAfterExpansion - bodyContentUsed - blockSpaceWithoutFootnotes;
|
|
1272
1400
|
prevMarginBottomPt = block.marginBottomPt;
|
|
1273
1401
|
currentFootnoteIds.push(...newFootnoteIds);
|
|
@@ -1275,8 +1403,14 @@ var DocxodusPagination = (() => {
|
|
|
1275
1403
|
} else {
|
|
1276
1404
|
finishPage();
|
|
1277
1405
|
const newPageFootnoteHeight = allBlockFootnoteIds.length > 0 ? this.measureFootnotesHeight(allBlockFootnoteIds, dims.contentWidth, currentContinuation) : currentContinuation ? this.measureContinuationHeight(currentContinuation, dims.contentWidth) : 0;
|
|
1278
|
-
const
|
|
1279
|
-
|
|
1406
|
+
const newPageMarginTop = this.effectiveBlockMarginTop(
|
|
1407
|
+
block,
|
|
1408
|
+
0,
|
|
1409
|
+
true,
|
|
1410
|
+
pageInSection
|
|
1411
|
+
);
|
|
1412
|
+
const newPageSpace = newPageMarginTop + block.heightPt + block.marginBottomPt;
|
|
1413
|
+
currentContent.push(this.cloneBlockForPage(block, true, pageInSection));
|
|
1280
1414
|
remainingHeight = effectiveContentHeight - newPageSpace;
|
|
1281
1415
|
prevMarginBottomPt = block.marginBottomPt;
|
|
1282
1416
|
currentFootnoteIds = [...currentFootnoteIds, ...allBlockFootnoteIds];
|
|
@@ -1285,8 +1419,14 @@ var DocxodusPagination = (() => {
|
|
|
1285
1419
|
} else {
|
|
1286
1420
|
finishPage();
|
|
1287
1421
|
const newPageFootnoteHeight = allBlockFootnoteIds.length > 0 ? this.measureFootnotesHeight(allBlockFootnoteIds, dims.contentWidth, currentContinuation) : currentContinuation ? this.measureContinuationHeight(currentContinuation, dims.contentWidth) : 0;
|
|
1288
|
-
const
|
|
1289
|
-
|
|
1422
|
+
const newPageMarginTop = this.effectiveBlockMarginTop(
|
|
1423
|
+
block,
|
|
1424
|
+
0,
|
|
1425
|
+
true,
|
|
1426
|
+
pageInSection
|
|
1427
|
+
);
|
|
1428
|
+
const newPageSpace = newPageMarginTop + block.heightPt + block.marginBottomPt;
|
|
1429
|
+
currentContent.push(this.cloneBlockForPage(block, true, pageInSection));
|
|
1290
1430
|
remainingHeight = effectiveContentHeight - newPageSpace;
|
|
1291
1431
|
prevMarginBottomPt = block.marginBottomPt;
|
|
1292
1432
|
currentFootnoteIds = [...currentFootnoteIds, ...allBlockFootnoteIds];
|
|
@@ -1305,7 +1445,7 @@ var DocxodusPagination = (() => {
|
|
|
1305
1445
|
if (currentContent.length > 0) {
|
|
1306
1446
|
finishPage();
|
|
1307
1447
|
}
|
|
1308
|
-
currentContent.push(
|
|
1448
|
+
currentContent.push(this.cloneBlockForPage(block, true, pageInSection));
|
|
1309
1449
|
currentFootnoteIds = [...currentFootnoteIds, ...allBlockFootnoteIds];
|
|
1310
1450
|
finishPage();
|
|
1311
1451
|
}
|
package/dist/pagination.d.ts
CHANGED
|
@@ -59,6 +59,8 @@ export interface MeasuredBlock {
|
|
|
59
59
|
pageBreakBefore: boolean;
|
|
60
60
|
/** Whether this is a page break marker */
|
|
61
61
|
isPageBreak: boolean;
|
|
62
|
+
/** Whether the block is a Word paragraph whose top margin represents paragraph space-before */
|
|
63
|
+
isWordParagraph?: boolean;
|
|
62
64
|
}
|
|
63
65
|
/**
|
|
64
66
|
* Information about a rendered page.
|
|
@@ -162,6 +164,18 @@ export declare class PaginationEngine {
|
|
|
162
164
|
* Measures all content blocks in a section.
|
|
163
165
|
*/
|
|
164
166
|
private measureBlocks;
|
|
167
|
+
/**
|
|
168
|
+
* Flows a multi-column (`w:cols`) section's children into CSS-multicol container
|
|
169
|
+
* blocks. Word lays such a section out as N columns inside the same body extent;
|
|
170
|
+
* a balanced `column-count` container reproduces that geometry, and the paginator
|
|
171
|
+
* then places each container as one ordinary measured block. A container grows
|
|
172
|
+
* greedily until its balanced height would exceed the smallest page body available
|
|
173
|
+
* to the section, so a long columned section still splits across pages at block
|
|
174
|
+
* boundaries. Each child lands in exactly one container, so anchors never
|
|
175
|
+
* duplicate. An explicit page break child passes through as its own block, which
|
|
176
|
+
* ends the current container and lets the normal flow logic turn the page.
|
|
177
|
+
*/
|
|
178
|
+
private buildColumnBlocks;
|
|
165
179
|
/**
|
|
166
180
|
* Measures one element in the same hidden staging context used for the source blocks.
|
|
167
181
|
* This is intentionally DOM-based: table row heights cannot be inferred from individual
|
|
@@ -182,6 +196,20 @@ export declare class PaginationEngine {
|
|
|
182
196
|
* intentionally excluded, matching the individual block fit check.
|
|
183
197
|
*/
|
|
184
198
|
private measureKeepWithNextChainBodyHeight;
|
|
199
|
+
/** Word paragraphs render as `p`, or as `h1`–`h6` when their style has an outline level. */
|
|
200
|
+
private isWordParagraphElement;
|
|
201
|
+
private shouldSuppressPageTopSpacing;
|
|
202
|
+
/**
|
|
203
|
+
* Resolves the part of a block's top margin that consumes the current page.
|
|
204
|
+
*
|
|
205
|
+
* In Word's native DOCX layout, paragraph space-before is suppressed when a paragraph is the
|
|
206
|
+
* first body block on a later page of the SAME section. The first page of a document/section is
|
|
207
|
+
* the exception and keeps its spacing. Tables and other block margins are not paragraph spacing,
|
|
208
|
+
* so they continue to use the ordinary CSS collapsing rule.
|
|
209
|
+
*/
|
|
210
|
+
private effectiveBlockMarginTop;
|
|
211
|
+
/** Clone a source block with the same page-top spacing decision used by the height budget. */
|
|
212
|
+
private cloneBlockForPage;
|
|
185
213
|
/**
|
|
186
214
|
* Finds footnote references introduced by a sequence of blocks, preserving
|
|
187
215
|
* document order and excluding references already assigned to the page.
|