docxodus 9.7.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/LICENSE +22 -0
- package/README.md +0 -1
- package/dist/editor.bundle.js +454 -99
- package/dist/editor.d.ts +4 -4
- package/dist/editor.d.ts.map +1 -1
- package/dist/editor.js +55 -8
- package/dist/editor.js.map +1 -1
- package/dist/embed.bundle.js +454 -99
- package/dist/embed.iife.js +454 -99
- package/dist/page-geometry.d.ts +50 -3
- package/dist/page-geometry.d.ts.map +1 -1
- package/dist/page-geometry.js +63 -6
- package/dist/page-geometry.js.map +1 -1
- package/dist/pagination.bundle.js +416 -91
- package/dist/pagination.d.ts +61 -8
- package/dist/pagination.d.ts.map +1 -1
- package/dist/pagination.js +353 -105
- 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 +14 -5
- package/dist/wasm/index.html +0 -238
- package/dist/wasm/main.js +0 -26
package/dist/embed.iife.js
CHANGED
|
@@ -1450,7 +1450,7 @@ var Docxodus = (() => {
|
|
|
1450
1450
|
var DEFAULT_PAGE_WIDTH = 612;
|
|
1451
1451
|
var DEFAULT_PAGE_HEIGHT = 792;
|
|
1452
1452
|
var DEFAULT_MARGIN = 72;
|
|
1453
|
-
var
|
|
1453
|
+
var DEFAULT_HEADER_FOOTER_DISTANCE = 36;
|
|
1454
1454
|
function pxToPt(px) {
|
|
1455
1455
|
return px * 0.75;
|
|
1456
1456
|
}
|
|
@@ -1466,8 +1466,8 @@ var Docxodus = (() => {
|
|
|
1466
1466
|
const marginRight = parseFloat(section.dataset.marginRight || "") || DEFAULT_MARGIN;
|
|
1467
1467
|
const marginBottom = parseFloat(section.dataset.marginBottom || "") || DEFAULT_MARGIN;
|
|
1468
1468
|
const marginLeft = parseFloat(section.dataset.marginLeft || "") || DEFAULT_MARGIN;
|
|
1469
|
-
const
|
|
1470
|
-
const
|
|
1469
|
+
const headerDistance = parseFloat(section.dataset.headerHeight || "") || DEFAULT_HEADER_FOOTER_DISTANCE;
|
|
1470
|
+
const footerDistance = parseFloat(section.dataset.footerHeight || "") || DEFAULT_HEADER_FOOTER_DISTANCE;
|
|
1471
1471
|
return {
|
|
1472
1472
|
pageWidth,
|
|
1473
1473
|
pageHeight,
|
|
@@ -1477,8 +1477,37 @@ var Docxodus = (() => {
|
|
|
1477
1477
|
marginRight,
|
|
1478
1478
|
marginBottom,
|
|
1479
1479
|
marginLeft,
|
|
1480
|
-
|
|
1481
|
-
|
|
1480
|
+
headerDistance,
|
|
1481
|
+
footerDistance,
|
|
1482
|
+
headerHeight: headerDistance,
|
|
1483
|
+
footerHeight: footerDistance
|
|
1484
|
+
};
|
|
1485
|
+
}
|
|
1486
|
+
var MIN_BODY_BAND_PT = 12;
|
|
1487
|
+
function resolvePageBands(dims, headerContentHeight, footerContentHeight) {
|
|
1488
|
+
const headerTop = dims.headerDistance;
|
|
1489
|
+
const footerBottom = dims.pageHeight - dims.footerDistance;
|
|
1490
|
+
const headerReach = headerContentHeight > 0 ? headerTop + headerContentHeight : 0;
|
|
1491
|
+
const footerReach = footerContentHeight > 0 ? footerBottom - footerContentHeight : dims.pageHeight;
|
|
1492
|
+
let bodyTop = Math.max(dims.marginTop, headerReach);
|
|
1493
|
+
let bodyBottom = Math.min(dims.pageHeight - dims.marginBottom, footerReach);
|
|
1494
|
+
const shortfall = MIN_BODY_BAND_PT - (bodyBottom - bodyTop);
|
|
1495
|
+
if (shortfall > 0) {
|
|
1496
|
+
const headerGrowth = bodyTop - dims.marginTop;
|
|
1497
|
+
const footerGrowth = dims.pageHeight - dims.marginBottom - bodyBottom;
|
|
1498
|
+
const growth = headerGrowth + footerGrowth;
|
|
1499
|
+
if (growth > 0) {
|
|
1500
|
+
bodyTop -= shortfall * headerGrowth / growth;
|
|
1501
|
+
bodyBottom += shortfall * footerGrowth / growth;
|
|
1502
|
+
}
|
|
1503
|
+
}
|
|
1504
|
+
return {
|
|
1505
|
+
headerTop,
|
|
1506
|
+
headerHeight: Math.max(0, Math.min(headerContentHeight, bodyTop - headerTop)),
|
|
1507
|
+
bodyTop,
|
|
1508
|
+
bodyHeight: Math.max(0, bodyBottom - bodyTop),
|
|
1509
|
+
footerTop: footerBottom - Math.max(0, Math.min(footerContentHeight, footerBottom - bodyBottom)),
|
|
1510
|
+
footerHeight: Math.max(0, Math.min(footerContentHeight, footerBottom - bodyBottom))
|
|
1482
1511
|
};
|
|
1483
1512
|
}
|
|
1484
1513
|
function sectionWrappers(root) {
|
|
@@ -1515,6 +1544,9 @@ var Docxodus = (() => {
|
|
|
1515
1544
|
}
|
|
1516
1545
|
|
|
1517
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
|
+
}
|
|
1518
1550
|
var MAX_FOOTNOTE_AREA_RATIO = 0.6;
|
|
1519
1551
|
var MIN_BODY_CONTENT_HEIGHT = 72;
|
|
1520
1552
|
var PaginationEngine = class {
|
|
@@ -1560,16 +1592,43 @@ var Docxodus = (() => {
|
|
|
1560
1592
|
);
|
|
1561
1593
|
this.pageNumbering = this.parsePageNumbering(sections);
|
|
1562
1594
|
const sectionsToProcess = sections.length > 0 ? Array.from(sections) : [this.stagingElement];
|
|
1595
|
+
const runs = [];
|
|
1563
1596
|
for (const section of sectionsToProcess) {
|
|
1564
|
-
const sectionIndex = parseInt(section.dataset.sectionIndex || "0", 10);
|
|
1565
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) {
|
|
1566
1610
|
this.stagingElement.style.visibility = "hidden";
|
|
1567
1611
|
this.stagingElement.style.position = "absolute";
|
|
1568
1612
|
this.stagingElement.style.left = "-9999px";
|
|
1569
1613
|
this.stagingElement.style.display = "block";
|
|
1570
|
-
|
|
1571
|
-
const
|
|
1572
|
-
|
|
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);
|
|
1573
1632
|
pages.push(...sectionPages);
|
|
1574
1633
|
pageNumber += sectionPages.length;
|
|
1575
1634
|
}
|
|
@@ -1658,11 +1717,70 @@ var Docxodus = (() => {
|
|
|
1658
1717
|
keepWithNext: child.dataset.keepWithNext === "true",
|
|
1659
1718
|
keepLines: child.dataset.keepLines === "true",
|
|
1660
1719
|
pageBreakBefore: child.dataset.pageBreakBefore === "true",
|
|
1661
|
-
isPageBreak
|
|
1720
|
+
isPageBreak,
|
|
1721
|
+
isWordParagraph: this.isWordParagraphElement(child)
|
|
1662
1722
|
});
|
|
1663
1723
|
}
|
|
1664
1724
|
return blocks;
|
|
1665
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
|
+
}
|
|
1666
1784
|
/**
|
|
1667
1785
|
* Measures one element in the same hidden staging context used for the source blocks.
|
|
1668
1786
|
* This is intentionally DOM-based: table row heights cannot be inferred from individual
|
|
@@ -1687,7 +1805,8 @@ var Docxodus = (() => {
|
|
|
1687
1805
|
keepWithNext: element.dataset.keepWithNext === "true",
|
|
1688
1806
|
keepLines: element.dataset.keepLines === "true",
|
|
1689
1807
|
pageBreakBefore: element.dataset.pageBreakBefore === "true",
|
|
1690
|
-
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)
|
|
1691
1810
|
};
|
|
1692
1811
|
this.stagingElement.removeChild(measurementHost);
|
|
1693
1812
|
return measured;
|
|
@@ -1719,10 +1838,15 @@ var Docxodus = (() => {
|
|
|
1719
1838
|
* collapsed-margin rules as normal block placement. The trailing margin is
|
|
1720
1839
|
* intentionally excluded, matching the individual block fit check.
|
|
1721
1840
|
*/
|
|
1722
|
-
measureKeepWithNextChainBodyHeight(chain, previousMarginBottomPt, isFirstOnPage) {
|
|
1841
|
+
measureKeepWithNextChainBodyHeight(chain, previousMarginBottomPt, isFirstOnPage, pageInSection) {
|
|
1723
1842
|
const firstBlock = chain[0];
|
|
1724
1843
|
if (!firstBlock) return 0;
|
|
1725
|
-
const firstMarginTop =
|
|
1844
|
+
const firstMarginTop = this.effectiveBlockMarginTop(
|
|
1845
|
+
firstBlock,
|
|
1846
|
+
previousMarginBottomPt,
|
|
1847
|
+
isFirstOnPage,
|
|
1848
|
+
pageInSection
|
|
1849
|
+
);
|
|
1726
1850
|
let bodyHeight = firstMarginTop + firstBlock.heightPt;
|
|
1727
1851
|
for (let index = 1; index < chain.length; index++) {
|
|
1728
1852
|
const previousBlock = chain[index - 1];
|
|
@@ -1731,6 +1855,35 @@ var Docxodus = (() => {
|
|
|
1731
1855
|
}
|
|
1732
1856
|
return bodyHeight;
|
|
1733
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
|
+
}
|
|
1734
1887
|
/**
|
|
1735
1888
|
* Finds footnote references introduced by a sequence of blocks, preserving
|
|
1736
1889
|
* document order and excluding references already assigned to the page.
|
|
@@ -1755,9 +1908,9 @@ var Docxodus = (() => {
|
|
|
1755
1908
|
*/
|
|
1756
1909
|
smallestEffectiveContentHeight(dims, sectionIndex) {
|
|
1757
1910
|
return Math.min(
|
|
1758
|
-
this.
|
|
1759
|
-
this.
|
|
1760
|
-
this.
|
|
1911
|
+
this.getPageBands(dims, sectionIndex, 1, 1).bodyHeight,
|
|
1912
|
+
this.getPageBands(dims, sectionIndex, 2, 1).bodyHeight,
|
|
1913
|
+
this.getPageBands(dims, sectionIndex, 2, 2).bodyHeight
|
|
1761
1914
|
);
|
|
1762
1915
|
}
|
|
1763
1916
|
/**
|
|
@@ -2281,7 +2434,7 @@ var Docxodus = (() => {
|
|
|
2281
2434
|
/**
|
|
2282
2435
|
* Adds footnotes to a page container, including continuation content.
|
|
2283
2436
|
*/
|
|
2284
|
-
addPageFootnotes(pageBox, footnoteIds, dims, footnoteHeight, continuation, partialFootnotes) {
|
|
2437
|
+
addPageFootnotes(pageBox, footnoteIds, dims, bands, footnoteHeight, continuation, partialFootnotes) {
|
|
2285
2438
|
const hasContinuation = continuation && continuation.remainingElements.length > 0;
|
|
2286
2439
|
if (footnoteIds.length === 0 && !hasContinuation) {
|
|
2287
2440
|
return;
|
|
@@ -2292,12 +2445,12 @@ var Docxodus = (() => {
|
|
|
2292
2445
|
const partialFootnoteIds = new Set(partialFootnotes?.map((p) => p.footnoteId) || []);
|
|
2293
2446
|
const maxFootnoteHeight = Math.min(
|
|
2294
2447
|
footnoteHeight,
|
|
2295
|
-
|
|
2448
|
+
bands.bodyHeight * MAX_FOOTNOTE_AREA_RATIO
|
|
2296
2449
|
);
|
|
2297
2450
|
const footnotesDiv = document.createElement("div");
|
|
2298
2451
|
footnotesDiv.className = `${this.cssPrefix}footnotes`;
|
|
2299
2452
|
footnotesDiv.style.position = "absolute";
|
|
2300
|
-
footnotesDiv.style.bottom = `${dims.
|
|
2453
|
+
footnotesDiv.style.bottom = `${dims.pageHeight - (bands.bodyTop + bands.bodyHeight)}pt`;
|
|
2301
2454
|
footnotesDiv.style.left = `${dims.marginLeft}pt`;
|
|
2302
2455
|
footnotesDiv.style.width = `${dims.contentWidth}pt`;
|
|
2303
2456
|
footnotesDiv.style.boxSizing = "border-box";
|
|
@@ -2371,50 +2524,51 @@ var Docxodus = (() => {
|
|
|
2371
2524
|
return sectionHf.footerDefault;
|
|
2372
2525
|
}
|
|
2373
2526
|
/**
|
|
2374
|
-
*
|
|
2375
|
-
*
|
|
2376
|
-
*
|
|
2377
|
-
*
|
|
2378
|
-
*
|
|
2527
|
+
* The header, body, and footer bands for one page position.
|
|
2528
|
+
*
|
|
2529
|
+
* The single owner of "where does anything sit vertically on this page" — placement in
|
|
2530
|
+
* {@link createPage}, the body budget the flow loop spends, and the note area's anchor all
|
|
2531
|
+
* read it, so those three cannot disagree about where the body ends.
|
|
2532
|
+
*
|
|
2533
|
+
* Deterministic: it depends only on the section's page setup and the registry's pre-measured
|
|
2534
|
+
* story heights, never on the page's content, which is what keeps it lazy-loading compatible.
|
|
2379
2535
|
*/
|
|
2380
|
-
|
|
2536
|
+
getPageBands(dims, sectionIndex, pageInSection, globalPageNumber) {
|
|
2381
2537
|
const sectionHf = this.hfRegistry.get(sectionIndex);
|
|
2382
|
-
|
|
2383
|
-
|
|
2384
|
-
|
|
2385
|
-
|
|
2386
|
-
|
|
2387
|
-
|
|
2388
|
-
|
|
2389
|
-
|
|
2390
|
-
|
|
2391
|
-
|
|
2392
|
-
|
|
2393
|
-
|
|
2394
|
-
|
|
2395
|
-
|
|
2396
|
-
|
|
2397
|
-
|
|
2398
|
-
|
|
2399
|
-
|
|
2400
|
-
|
|
2401
|
-
|
|
2402
|
-
|
|
2403
|
-
|
|
2404
|
-
|
|
2405
|
-
|
|
2406
|
-
|
|
2407
|
-
|
|
2408
|
-
}
|
|
2409
|
-
}
|
|
2410
|
-
const headerExpansion = headerHeight - dims.marginTop;
|
|
2411
|
-
const footerExpansion = footerHeight - dims.marginBottom;
|
|
2412
|
-
const contentHeight = dims.contentHeight - headerExpansion - footerExpansion;
|
|
2413
|
-
return { headerHeight, footerHeight, contentHeight };
|
|
2538
|
+
return resolvePageBands(
|
|
2539
|
+
dims,
|
|
2540
|
+
this.selectStoryHeight(
|
|
2541
|
+
sectionHf?.headerFirstHeight,
|
|
2542
|
+
sectionHf?.headerEvenHeight,
|
|
2543
|
+
sectionHf?.headerDefaultHeight,
|
|
2544
|
+
pageInSection,
|
|
2545
|
+
globalPageNumber
|
|
2546
|
+
),
|
|
2547
|
+
this.selectStoryHeight(
|
|
2548
|
+
sectionHf?.footerFirstHeight,
|
|
2549
|
+
sectionHf?.footerEvenHeight,
|
|
2550
|
+
sectionHf?.footerDefaultHeight,
|
|
2551
|
+
pageInSection,
|
|
2552
|
+
globalPageNumber
|
|
2553
|
+
)
|
|
2554
|
+
);
|
|
2555
|
+
}
|
|
2556
|
+
/**
|
|
2557
|
+
* The measured height of the running story this page position selects, mirroring
|
|
2558
|
+
* {@link selectHeader}/{@link selectFooter}. Zero when the page has no such story.
|
|
2559
|
+
*/
|
|
2560
|
+
selectStoryHeight(first, even, fallback, pageInSection, globalPageNumber) {
|
|
2561
|
+
if (pageInSection === 1 && first != null) return first;
|
|
2562
|
+
if (globalPageNumber % 2 === 0 && even != null) return even;
|
|
2563
|
+
return fallback ?? 0;
|
|
2414
2564
|
}
|
|
2415
2565
|
/**
|
|
2416
2566
|
* Measures the content height of a header or footer element.
|
|
2417
|
-
*
|
|
2567
|
+
*
|
|
2568
|
+
* This is what tells {@link resolvePageBands} whether the story stays inside its margin or
|
|
2569
|
+
* pushes the body, so it must measure the story ALONE — any padding added here would have to
|
|
2570
|
+
* be added to the rendered band too, and the two drifting apart is exactly how a header
|
|
2571
|
+
* silently starts overlapping body text.
|
|
2418
2572
|
*/
|
|
2419
2573
|
measureHeaderFooterHeight(source, contentWidth) {
|
|
2420
2574
|
const measureContainer = document.createElement("div");
|
|
@@ -2422,7 +2576,6 @@ var Docxodus = (() => {
|
|
|
2422
2576
|
measureContainer.style.visibility = "hidden";
|
|
2423
2577
|
measureContainer.style.width = `${contentWidth}pt`;
|
|
2424
2578
|
measureContainer.style.left = "-9999px";
|
|
2425
|
-
measureContainer.style.paddingBottom = "4pt";
|
|
2426
2579
|
for (const child of Array.from(source.childNodes)) {
|
|
2427
2580
|
measureContainer.appendChild(child.cloneNode(true));
|
|
2428
2581
|
}
|
|
@@ -2442,7 +2595,7 @@ var Docxodus = (() => {
|
|
|
2442
2595
|
let currentContent = [];
|
|
2443
2596
|
let pageNumber = startPageNumber;
|
|
2444
2597
|
let pageInSection = 1;
|
|
2445
|
-
let {
|
|
2598
|
+
let { bodyHeight: effectiveContentHeight } = this.getPageBands(
|
|
2446
2599
|
dims,
|
|
2447
2600
|
sectionIndex,
|
|
2448
2601
|
pageInSection,
|
|
@@ -2477,8 +2630,8 @@ var Docxodus = (() => {
|
|
|
2477
2630
|
pageNumber++;
|
|
2478
2631
|
pageInSection++;
|
|
2479
2632
|
currentContent = [];
|
|
2480
|
-
const
|
|
2481
|
-
effectiveContentHeight =
|
|
2633
|
+
const newBands = this.getPageBands(dims, sectionIndex, pageInSection, pageNumber);
|
|
2634
|
+
effectiveContentHeight = newBands.bodyHeight;
|
|
2482
2635
|
remainingHeight = effectiveContentHeight;
|
|
2483
2636
|
prevMarginBottomPt = 0;
|
|
2484
2637
|
currentFootnoteIds = [];
|
|
@@ -2536,11 +2689,12 @@ var Docxodus = (() => {
|
|
|
2536
2689
|
const currentChainHeight = this.measureKeepWithNextChainBodyHeight(
|
|
2537
2690
|
keepChain,
|
|
2538
2691
|
prevMarginBottomPt,
|
|
2539
|
-
currentContent.length === 0
|
|
2692
|
+
currentContent.length === 0,
|
|
2693
|
+
pageInSection
|
|
2540
2694
|
) + additionalChainFootnoteHeight;
|
|
2541
2695
|
const currentAvailableHeight = remainingHeight - currentFootnoteHeight;
|
|
2542
2696
|
if (currentChainHeight > currentAvailableHeight) {
|
|
2543
|
-
const
|
|
2697
|
+
const nextPageBands = this.getPageBands(
|
|
2544
2698
|
dims,
|
|
2545
2699
|
sectionIndex,
|
|
2546
2700
|
pageInSection + 1,
|
|
@@ -2549,14 +2703,15 @@ var Docxodus = (() => {
|
|
|
2549
2703
|
const freshChainBodyHeight = this.measureKeepWithNextChainBodyHeight(
|
|
2550
2704
|
keepChain,
|
|
2551
2705
|
0,
|
|
2552
|
-
true
|
|
2706
|
+
true,
|
|
2707
|
+
pageInSection + 1
|
|
2553
2708
|
);
|
|
2554
2709
|
const freshChainFootnoteHeight = this.measureFootnotesHeight(
|
|
2555
2710
|
newChainFootnoteIds,
|
|
2556
2711
|
dims.contentWidth,
|
|
2557
2712
|
nextPageContinuation
|
|
2558
2713
|
);
|
|
2559
|
-
if (freshChainBodyHeight + freshChainFootnoteHeight <=
|
|
2714
|
+
if (freshChainBodyHeight + freshChainFootnoteHeight <= nextPageBands.bodyHeight) {
|
|
2560
2715
|
finishPage();
|
|
2561
2716
|
}
|
|
2562
2717
|
}
|
|
@@ -2575,10 +2730,12 @@ var Docxodus = (() => {
|
|
|
2575
2730
|
additionalFootnoteHeight = totalFootnoteHeight - currentFootnoteHeight;
|
|
2576
2731
|
}
|
|
2577
2732
|
const isFirstOnPage = currentContent.length === 0;
|
|
2578
|
-
|
|
2579
|
-
|
|
2580
|
-
|
|
2581
|
-
|
|
2733
|
+
const effectiveMarginTop = this.effectiveBlockMarginTop(
|
|
2734
|
+
block,
|
|
2735
|
+
prevMarginBottomPt,
|
|
2736
|
+
isFirstOnPage,
|
|
2737
|
+
pageInSection
|
|
2738
|
+
);
|
|
2582
2739
|
const blockSpace = effectiveMarginTop + block.heightPt + additionalFootnoteHeight;
|
|
2583
2740
|
const effectiveRemainingHeight = remainingHeight - currentFootnoteHeight;
|
|
2584
2741
|
const bodyContentUsed = effectiveContentHeight - remainingHeight;
|
|
@@ -2598,19 +2755,19 @@ var Docxodus = (() => {
|
|
|
2598
2755
|
}
|
|
2599
2756
|
}
|
|
2600
2757
|
if (blockSpace <= effectiveRemainingHeight) {
|
|
2601
|
-
currentContent.push(
|
|
2758
|
+
currentContent.push(this.cloneBlockForPage(block, isFirstOnPage, pageInSection));
|
|
2602
2759
|
remainingHeight -= effectiveMarginTop + block.heightPt + block.marginBottomPt;
|
|
2603
2760
|
prevMarginBottomPt = block.marginBottomPt;
|
|
2604
2761
|
if (newFootnoteIds.length > 0) {
|
|
2605
2762
|
currentFootnoteIds.push(...newFootnoteIds);
|
|
2606
2763
|
currentFootnoteHeight += additionalFootnoteHeight;
|
|
2607
2764
|
}
|
|
2608
|
-
} else if (block.heightPt + block
|
|
2765
|
+
} else if (block.heightPt + this.effectiveBlockMarginTop(block, 0, true, pageInSection + 1) <= effectiveContentHeight) {
|
|
2609
2766
|
const blockSpaceWithoutFootnotes = effectiveMarginTop + block.heightPt;
|
|
2610
2767
|
const minBodySpaceNeeded = bodyContentUsed + blockSpaceWithoutFootnotes + MIN_BODY_CONTENT_HEIGHT;
|
|
2611
2768
|
const canExpandFootnotes = minBodySpaceNeeded <= effectiveContentHeight;
|
|
2612
2769
|
if (newFootnoteIds.length > 0 && blockSpaceWithoutFootnotes <= effectiveRemainingHeight) {
|
|
2613
|
-
currentContent.push(
|
|
2770
|
+
currentContent.push(this.cloneBlockForPage(block, isFirstOnPage, pageInSection));
|
|
2614
2771
|
remainingHeight -= effectiveMarginTop + block.heightPt + block.marginBottomPt;
|
|
2615
2772
|
prevMarginBottomPt = block.marginBottomPt;
|
|
2616
2773
|
const availableForFootnotes = Math.min(
|
|
@@ -2657,7 +2814,7 @@ var Docxodus = (() => {
|
|
|
2657
2814
|
const expandedFootnoteSpace = Math.min(maxFootnoteArea, additionalFootnoteHeight + currentFootnoteHeight);
|
|
2658
2815
|
const bodySpaceAfterExpansion = effectiveContentHeight - expandedFootnoteSpace;
|
|
2659
2816
|
if (blockSpaceWithoutFootnotes <= bodySpaceAfterExpansion - bodyContentUsed) {
|
|
2660
|
-
currentContent.push(
|
|
2817
|
+
currentContent.push(this.cloneBlockForPage(block, isFirstOnPage, pageInSection));
|
|
2661
2818
|
remainingHeight = bodySpaceAfterExpansion - bodyContentUsed - blockSpaceWithoutFootnotes;
|
|
2662
2819
|
prevMarginBottomPt = block.marginBottomPt;
|
|
2663
2820
|
currentFootnoteIds.push(...newFootnoteIds);
|
|
@@ -2665,8 +2822,14 @@ var Docxodus = (() => {
|
|
|
2665
2822
|
} else {
|
|
2666
2823
|
finishPage();
|
|
2667
2824
|
const newPageFootnoteHeight = allBlockFootnoteIds.length > 0 ? this.measureFootnotesHeight(allBlockFootnoteIds, dims.contentWidth, currentContinuation) : currentContinuation ? this.measureContinuationHeight(currentContinuation, dims.contentWidth) : 0;
|
|
2668
|
-
const
|
|
2669
|
-
|
|
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));
|
|
2670
2833
|
remainingHeight = effectiveContentHeight - newPageSpace;
|
|
2671
2834
|
prevMarginBottomPt = block.marginBottomPt;
|
|
2672
2835
|
currentFootnoteIds = [...currentFootnoteIds, ...allBlockFootnoteIds];
|
|
@@ -2675,8 +2838,14 @@ var Docxodus = (() => {
|
|
|
2675
2838
|
} else {
|
|
2676
2839
|
finishPage();
|
|
2677
2840
|
const newPageFootnoteHeight = allBlockFootnoteIds.length > 0 ? this.measureFootnotesHeight(allBlockFootnoteIds, dims.contentWidth, currentContinuation) : currentContinuation ? this.measureContinuationHeight(currentContinuation, dims.contentWidth) : 0;
|
|
2678
|
-
const
|
|
2679
|
-
|
|
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));
|
|
2680
2849
|
remainingHeight = effectiveContentHeight - newPageSpace;
|
|
2681
2850
|
prevMarginBottomPt = block.marginBottomPt;
|
|
2682
2851
|
currentFootnoteIds = [...currentFootnoteIds, ...allBlockFootnoteIds];
|
|
@@ -2695,7 +2864,7 @@ var Docxodus = (() => {
|
|
|
2695
2864
|
if (currentContent.length > 0) {
|
|
2696
2865
|
finishPage();
|
|
2697
2866
|
}
|
|
2698
|
-
currentContent.push(
|
|
2867
|
+
currentContent.push(this.cloneBlockForPage(block, true, pageInSection));
|
|
2699
2868
|
currentFootnoteIds = [...currentFootnoteIds, ...allBlockFootnoteIds];
|
|
2700
2869
|
finishPage();
|
|
2701
2870
|
}
|
|
@@ -2725,6 +2894,161 @@ var Docxodus = (() => {
|
|
|
2725
2894
|
if (el.getAttribute("contenteditable") !== null) el.setAttribute("contenteditable", "false");
|
|
2726
2895
|
}
|
|
2727
2896
|
}
|
|
2897
|
+
/**
|
|
2898
|
+
* Resolves floating DrawingML objects after their anchor paragraphs have landed on a page.
|
|
2899
|
+
*
|
|
2900
|
+
* The converter deliberately carries the OOXML bases and offsets as data instead of flattening
|
|
2901
|
+
* them into CSS: page/margin/column bases belong to the page, while paragraph/line/character
|
|
2902
|
+
* bases belong to the laid-out anchor. Once both coordinate systems exist, promote the object
|
|
2903
|
+
* from the clipped text column into the page box and position it in one shared point space.
|
|
2904
|
+
*/
|
|
2905
|
+
positionDrawingAnchors(pageBox, contentArea, dims, pageNumber) {
|
|
2906
|
+
const anchors = Array.from(
|
|
2907
|
+
contentArea.querySelectorAll('[data-docx-drawing-anchor="true"]')
|
|
2908
|
+
);
|
|
2909
|
+
if (anchors.length === 0) return;
|
|
2910
|
+
const pageRect = pageBox.getBoundingClientRect();
|
|
2911
|
+
const pixelsPerPoint = pageRect.width / dims.pageWidth;
|
|
2912
|
+
if (!(pixelsPerPoint > 0)) return;
|
|
2913
|
+
for (const anchor of anchors) {
|
|
2914
|
+
const staticRect = anchor.getBoundingClientRect();
|
|
2915
|
+
const paragraph = anchor.closest("p, h1, h2, h3, h4, h5, h6");
|
|
2916
|
+
const paragraphRect = paragraph?.getBoundingClientRect() ?? staticRect;
|
|
2917
|
+
const toPageX = (x) => (x - pageRect.left) / pixelsPerPoint;
|
|
2918
|
+
const toPageY = (y) => (y - pageRect.top) / pixelsPerPoint;
|
|
2919
|
+
const context = {
|
|
2920
|
+
staticLeft: toPageX(staticRect.left),
|
|
2921
|
+
staticTop: toPageY(staticRect.top),
|
|
2922
|
+
lineHeight: paragraph ? (parseFloat(getComputedStyle(paragraph).lineHeight) || staticRect.height) / pixelsPerPoint : staticRect.height / pixelsPerPoint,
|
|
2923
|
+
paragraphLeft: toPageX(paragraphRect.left),
|
|
2924
|
+
paragraphTop: toPageY(paragraphRect.top),
|
|
2925
|
+
paragraphWidth: paragraphRect.width / pixelsPerPoint,
|
|
2926
|
+
paragraphHeight: paragraphRect.height / pixelsPerPoint
|
|
2927
|
+
};
|
|
2928
|
+
const widthReference = this.horizontalAnchorReference(
|
|
2929
|
+
anchor.getAttribute("data-docx-anchor-width-relative") ?? "margin",
|
|
2930
|
+
dims,
|
|
2931
|
+
pageNumber,
|
|
2932
|
+
context
|
|
2933
|
+
);
|
|
2934
|
+
const widthPercent = this.anchorNumber(anchor, "width-percent");
|
|
2935
|
+
if (widthPercent !== void 0) {
|
|
2936
|
+
anchor.style.width = `${widthReference.size * widthPercent / 100}pt`;
|
|
2937
|
+
}
|
|
2938
|
+
const heightReference = this.verticalAnchorReference(
|
|
2939
|
+
anchor.getAttribute("data-docx-anchor-height-relative") ?? "margin",
|
|
2940
|
+
dims,
|
|
2941
|
+
pageNumber,
|
|
2942
|
+
context
|
|
2943
|
+
);
|
|
2944
|
+
const heightPercent = this.anchorNumber(anchor, "height-percent");
|
|
2945
|
+
if (heightPercent !== void 0 && anchor.dataset.docxAnchorAutofit !== "true") {
|
|
2946
|
+
anchor.style.height = `${heightReference.size * heightPercent / 100}pt`;
|
|
2947
|
+
}
|
|
2948
|
+
const sizedRect = anchor.getBoundingClientRect();
|
|
2949
|
+
const width = sizedRect.width / pixelsPerPoint;
|
|
2950
|
+
const height = sizedRect.height / pixelsPerPoint;
|
|
2951
|
+
const horizontal2 = this.horizontalAnchorReference(
|
|
2952
|
+
anchor.getAttribute("data-docx-anchor-h-relative") ?? "column",
|
|
2953
|
+
dims,
|
|
2954
|
+
pageNumber,
|
|
2955
|
+
context
|
|
2956
|
+
);
|
|
2957
|
+
const vertical2 = this.verticalAnchorReference(
|
|
2958
|
+
anchor.getAttribute("data-docx-anchor-v-relative") ?? "paragraph",
|
|
2959
|
+
dims,
|
|
2960
|
+
pageNumber,
|
|
2961
|
+
context
|
|
2962
|
+
);
|
|
2963
|
+
const left2 = this.resolveAnchorAxis(
|
|
2964
|
+
horizontal2,
|
|
2965
|
+
width,
|
|
2966
|
+
anchor.getAttribute("data-docx-anchor-h-align"),
|
|
2967
|
+
this.anchorNumber(anchor, "h-offset"),
|
|
2968
|
+
pageNumber
|
|
2969
|
+
);
|
|
2970
|
+
const top2 = this.resolveAnchorAxis(
|
|
2971
|
+
vertical2,
|
|
2972
|
+
height,
|
|
2973
|
+
anchor.getAttribute("data-docx-anchor-v-align"),
|
|
2974
|
+
this.anchorNumber(anchor, "v-offset"),
|
|
2975
|
+
pageNumber
|
|
2976
|
+
);
|
|
2977
|
+
pageBox.appendChild(anchor);
|
|
2978
|
+
anchor.style.position = "absolute";
|
|
2979
|
+
anchor.style.left = `${left2}pt`;
|
|
2980
|
+
anchor.style.top = `${top2}pt`;
|
|
2981
|
+
anchor.style.margin = "0";
|
|
2982
|
+
}
|
|
2983
|
+
}
|
|
2984
|
+
anchorNumber(anchor, suffix) {
|
|
2985
|
+
const raw = anchor.getAttribute(`data-docx-anchor-${suffix}`);
|
|
2986
|
+
if (raw === null) return void 0;
|
|
2987
|
+
const value = Number(raw);
|
|
2988
|
+
return Number.isFinite(value) ? value : void 0;
|
|
2989
|
+
}
|
|
2990
|
+
horizontalAnchorReference(relativeFrom, dims, pageNumber, context) {
|
|
2991
|
+
const leftMargin = { start: 0, size: dims.marginLeft };
|
|
2992
|
+
const rightMargin = {
|
|
2993
|
+
start: dims.marginLeft + dims.contentWidth,
|
|
2994
|
+
size: dims.marginRight
|
|
2995
|
+
};
|
|
2996
|
+
switch (relativeFrom) {
|
|
2997
|
+
case "page":
|
|
2998
|
+
return { start: 0, size: dims.pageWidth };
|
|
2999
|
+
case "character":
|
|
3000
|
+
return { start: context.staticLeft, size: 0 };
|
|
3001
|
+
case "leftMargin":
|
|
3002
|
+
return leftMargin;
|
|
3003
|
+
case "rightMargin":
|
|
3004
|
+
return rightMargin;
|
|
3005
|
+
case "insideMargin":
|
|
3006
|
+
return pageNumber % 2 === 1 ? leftMargin : rightMargin;
|
|
3007
|
+
case "outsideMargin":
|
|
3008
|
+
return pageNumber % 2 === 1 ? rightMargin : leftMargin;
|
|
3009
|
+
case "paragraph":
|
|
3010
|
+
return { start: context.paragraphLeft, size: context.paragraphWidth };
|
|
3011
|
+
case "column":
|
|
3012
|
+
case "margin":
|
|
3013
|
+
default:
|
|
3014
|
+
return { start: dims.marginLeft, size: dims.contentWidth };
|
|
3015
|
+
}
|
|
3016
|
+
}
|
|
3017
|
+
verticalAnchorReference(relativeFrom, dims, pageNumber, context) {
|
|
3018
|
+
const topMargin = { start: 0, size: dims.marginTop };
|
|
3019
|
+
const bottomMargin = {
|
|
3020
|
+
start: dims.marginTop + dims.contentHeight,
|
|
3021
|
+
size: dims.marginBottom
|
|
3022
|
+
};
|
|
3023
|
+
switch (relativeFrom) {
|
|
3024
|
+
case "page":
|
|
3025
|
+
return { start: 0, size: dims.pageHeight };
|
|
3026
|
+
case "paragraph":
|
|
3027
|
+
return { start: context.paragraphTop, size: context.paragraphHeight };
|
|
3028
|
+
case "line":
|
|
3029
|
+
return { start: context.staticTop, size: context.lineHeight };
|
|
3030
|
+
case "topMargin":
|
|
3031
|
+
return topMargin;
|
|
3032
|
+
case "bottomMargin":
|
|
3033
|
+
return bottomMargin;
|
|
3034
|
+
case "insideMargin":
|
|
3035
|
+
return pageNumber % 2 === 1 ? topMargin : bottomMargin;
|
|
3036
|
+
case "outsideMargin":
|
|
3037
|
+
return pageNumber % 2 === 1 ? bottomMargin : topMargin;
|
|
3038
|
+
case "margin":
|
|
3039
|
+
default:
|
|
3040
|
+
return { start: dims.marginTop, size: dims.contentHeight };
|
|
3041
|
+
}
|
|
3042
|
+
}
|
|
3043
|
+
resolveAnchorAxis(reference, objectSize, alignment, offset, pageNumber) {
|
|
3044
|
+
if (offset !== void 0) return reference.start + offset;
|
|
3045
|
+
let fraction = 0;
|
|
3046
|
+
if (alignment === "center") fraction = 0.5;
|
|
3047
|
+
else if (alignment === "right" || alignment === "bottom") fraction = 1;
|
|
3048
|
+
else if (alignment === "inside") fraction = pageNumber % 2 === 1 ? 0 : 1;
|
|
3049
|
+
else if (alignment === "outside") fraction = pageNumber % 2 === 1 ? 1 : 0;
|
|
3050
|
+
return reference.start + (reference.size - objectSize) * fraction;
|
|
3051
|
+
}
|
|
2728
3052
|
/**
|
|
2729
3053
|
* Creates a page container element.
|
|
2730
3054
|
*/
|
|
@@ -2751,22 +3075,22 @@ var Docxodus = (() => {
|
|
|
2751
3075
|
pageBox.dataset.pageNumber = String(pageNumber);
|
|
2752
3076
|
pageBox.dataset.sectionIndex = String(sectionIndex);
|
|
2753
3077
|
pageBox.dataset.pageInSection = String(pageInSection);
|
|
2754
|
-
const
|
|
3078
|
+
const bands = this.getPageBands(dims, sectionIndex, pageInSection, pageNumber);
|
|
2755
3079
|
const headerSource = this.selectHeader(sectionIndex, pageInSection, pageNumber);
|
|
2756
3080
|
if (headerSource) {
|
|
2757
3081
|
const headerDiv = document.createElement("div");
|
|
2758
3082
|
headerDiv.className = `${this.cssPrefix}header`;
|
|
2759
3083
|
headerDiv.style.position = "absolute";
|
|
2760
|
-
headerDiv.style.top =
|
|
3084
|
+
headerDiv.style.top = `${bands.headerTop}pt`;
|
|
3085
|
+
headerDiv.style.bottom = "auto";
|
|
2761
3086
|
headerDiv.style.left = `${dims.marginLeft}pt`;
|
|
2762
3087
|
headerDiv.style.width = `${dims.contentWidth}pt`;
|
|
2763
|
-
headerDiv.style.height = `${
|
|
3088
|
+
headerDiv.style.height = `${bands.headerHeight}pt`;
|
|
2764
3089
|
headerDiv.style.overflow = "hidden";
|
|
2765
3090
|
headerDiv.style.boxSizing = "border-box";
|
|
2766
3091
|
headerDiv.style.display = "flex";
|
|
2767
3092
|
headerDiv.style.flexDirection = "column";
|
|
2768
|
-
headerDiv.style.justifyContent = "flex-
|
|
2769
|
-
headerDiv.style.paddingBottom = "4pt";
|
|
3093
|
+
headerDiv.style.justifyContent = "flex-start";
|
|
2770
3094
|
for (const child of Array.from(headerSource.childNodes)) {
|
|
2771
3095
|
const clonedheaderDiv = child.cloneNode(true);
|
|
2772
3096
|
if (clonedheaderDiv.nodeType === 1) this.makeClonedStoryInert(clonedheaderDiv);
|
|
@@ -2774,8 +3098,8 @@ var Docxodus = (() => {
|
|
|
2774
3098
|
}
|
|
2775
3099
|
pageBox.appendChild(headerDiv);
|
|
2776
3100
|
}
|
|
2777
|
-
const contentAreaTop =
|
|
2778
|
-
const contentAreaHeight =
|
|
3101
|
+
const contentAreaTop = bands.bodyTop;
|
|
3102
|
+
const contentAreaHeight = bands.bodyHeight;
|
|
2779
3103
|
const contentArea = document.createElement("div");
|
|
2780
3104
|
contentArea.className = `${this.cssPrefix}content`;
|
|
2781
3105
|
contentArea.style.position = "absolute";
|
|
@@ -2790,23 +3114,23 @@ var Docxodus = (() => {
|
|
|
2790
3114
|
pageBox.appendChild(contentArea);
|
|
2791
3115
|
const hasContinuation = continuation && continuation.remainingElements.length > 0;
|
|
2792
3116
|
if (footnoteIds.length > 0 || hasContinuation) {
|
|
2793
|
-
this.addPageFootnotes(pageBox, footnoteIds, dims, footnoteHeight, continuation, partialFootnotes);
|
|
3117
|
+
this.addPageFootnotes(pageBox, footnoteIds, dims, bands, footnoteHeight, continuation, partialFootnotes);
|
|
2794
3118
|
}
|
|
2795
3119
|
const footerSource = this.selectFooter(sectionIndex, pageInSection, pageNumber);
|
|
2796
3120
|
if (footerSource) {
|
|
2797
3121
|
const footerDiv = document.createElement("div");
|
|
2798
3122
|
footerDiv.className = `${this.cssPrefix}footer`;
|
|
2799
3123
|
footerDiv.style.position = "absolute";
|
|
2800
|
-
footerDiv.style.
|
|
3124
|
+
footerDiv.style.top = "auto";
|
|
3125
|
+
footerDiv.style.bottom = `${dims.footerDistance}pt`;
|
|
2801
3126
|
footerDiv.style.left = `${dims.marginLeft}pt`;
|
|
2802
3127
|
footerDiv.style.width = `${dims.contentWidth}pt`;
|
|
2803
|
-
footerDiv.style.height = `${
|
|
3128
|
+
footerDiv.style.height = `${bands.footerHeight}pt`;
|
|
2804
3129
|
footerDiv.style.overflow = "hidden";
|
|
2805
3130
|
footerDiv.style.boxSizing = "border-box";
|
|
2806
3131
|
footerDiv.style.display = "flex";
|
|
2807
3132
|
footerDiv.style.flexDirection = "column";
|
|
2808
|
-
footerDiv.style.justifyContent = "flex-
|
|
2809
|
-
footerDiv.style.paddingTop = "4pt";
|
|
3133
|
+
footerDiv.style.justifyContent = "flex-end";
|
|
2810
3134
|
for (const child of Array.from(footerSource.childNodes)) {
|
|
2811
3135
|
const clonedfooterDiv = child.cloneNode(true);
|
|
2812
3136
|
if (clonedfooterDiv.nodeType === 1) this.makeClonedStoryInert(clonedfooterDiv);
|
|
@@ -2821,6 +3145,7 @@ var Docxodus = (() => {
|
|
|
2821
3145
|
pageBox.appendChild(pageNum);
|
|
2822
3146
|
}
|
|
2823
3147
|
this.containerElement.appendChild(pageBox);
|
|
3148
|
+
this.positionDrawingAnchors(pageBox, contentArea, dims, pageNumber);
|
|
2824
3149
|
const notesEl = pageBox.querySelector(`.${this.cssPrefix}footnotes`);
|
|
2825
3150
|
if (notesEl) {
|
|
2826
3151
|
const notesHeightPt = pxToPt(notesEl.getBoundingClientRect().height);
|
|
@@ -6195,6 +6520,19 @@ var Docxodus = (() => {
|
|
|
6195
6520
|
function isListBlock(block) {
|
|
6196
6521
|
return !!block.querySelector(":scope > [data-list-marker]");
|
|
6197
6522
|
}
|
|
6523
|
+
function ensureListMarkerSeparator(block) {
|
|
6524
|
+
const marker = block.querySelector(":scope > [data-list-marker]");
|
|
6525
|
+
if (!marker) return;
|
|
6526
|
+
const next = marker.nextElementSibling;
|
|
6527
|
+
if (next?.hasAttribute("data-editor-list-separator")) return;
|
|
6528
|
+
const separator = block.ownerDocument.createElement("span");
|
|
6529
|
+
separator.setAttribute("data-editor-list-separator", "");
|
|
6530
|
+
separator.setAttribute("data-list-marker", "true");
|
|
6531
|
+
separator.setAttribute("aria-hidden", "true");
|
|
6532
|
+
separator.style.display = "none";
|
|
6533
|
+
separator.textContent = " ";
|
|
6534
|
+
marker.after(separator);
|
|
6535
|
+
}
|
|
6198
6536
|
var GENERATED_CHROME_SELECTOR = '[data-list-marker], a.footnote-ref, a.endnote-ref, a[class$="-backref"]';
|
|
6199
6537
|
function isGeneratedChrome(node) {
|
|
6200
6538
|
return node?.nodeType === 1 && !!node.matches?.(GENERATED_CHROME_SELECTOR);
|
|
@@ -7485,6 +7823,7 @@ var Docxodus = (() => {
|
|
|
7485
7823
|
const unid = el.getAttribute("data-anchor");
|
|
7486
7824
|
if (!unid || !this.anchorIdOf(el)) return;
|
|
7487
7825
|
el.setAttribute("contenteditable", "true");
|
|
7826
|
+
ensureListMarkerSeparator(el);
|
|
7488
7827
|
el.querySelectorAll(GENERATED_CHROME_SELECTOR).forEach((m) => m.setAttribute("contenteditable", "false"));
|
|
7489
7828
|
el.dataset.committedText = blockContentText(el);
|
|
7490
7829
|
el.addEventListener("focus", () => {
|
|
@@ -8347,8 +8686,8 @@ var Docxodus = (() => {
|
|
|
8347
8686
|
* editable `data-anchor` blocks in the notes section, so editing it afterwards needs no new op.
|
|
8348
8687
|
*
|
|
8349
8688
|
* Body blocks only: Word disallows a note reference inside a header/footer story or inside
|
|
8350
|
-
* another note, and the session rejects those with `AnchorWrongKind`.
|
|
8351
|
-
*
|
|
8689
|
+
* another note, and the session rejects those with `AnchorWrongKind`. Reconciliation creates
|
|
8690
|
+
* the first notes section when needed and renumbers every affected citation in place.
|
|
8352
8691
|
*/
|
|
8353
8692
|
insertFootnote(markdown = "New footnote.") {
|
|
8354
8693
|
this.insertNote("footnote", markdown);
|
|
@@ -8740,7 +9079,7 @@ var Docxodus = (() => {
|
|
|
8740
9079
|
* the current node — never a section div (multi-child) or the edit root. */
|
|
8741
9080
|
unitWrapperOf(el) {
|
|
8742
9081
|
let n = el;
|
|
8743
|
-
while (n.parentElement && n.parentElement !== this.editRoot && n.parentElement.tagName === "DIV" && !n.parentElement.hasAttribute("data-anchor") && n.parentElement.childElementCount === 1) {
|
|
9082
|
+
while (n.parentElement && n.parentElement !== this.editRoot && n.parentElement.tagName === "DIV" && !n.parentElement.hasAttribute("data-section-index") && !n.parentElement.hasAttribute("data-anchor") && n.parentElement.childElementCount === 1) {
|
|
8744
9083
|
n = n.parentElement;
|
|
8745
9084
|
}
|
|
8746
9085
|
return n;
|
|
@@ -8776,6 +9115,7 @@ var Docxodus = (() => {
|
|
|
8776
9115
|
const pureRemoved = diff.removed.filter(
|
|
8777
9116
|
(i) => !diff.substituted.some((s) => s.oldIndex === i) && !movedOld.has(i)
|
|
8778
9117
|
);
|
|
9118
|
+
const appliedFresh = /* @__PURE__ */ new Set();
|
|
8779
9119
|
const nodeAt = (j) => {
|
|
8780
9120
|
const oi = diff.keep.get(j);
|
|
8781
9121
|
if (oi !== void 0) return oldNodes[oi];
|
|
@@ -8783,7 +9123,7 @@ var Docxodus = (() => {
|
|
|
8783
9123
|
if (movedOi !== void 0) return oldNodes[movedOi];
|
|
8784
9124
|
if (subOldByNew.has(j)) return fresh.get(j);
|
|
8785
9125
|
const f = fresh.get(j);
|
|
8786
|
-
return f &&
|
|
9126
|
+
return f && appliedFresh.has(j) ? f : null;
|
|
8787
9127
|
};
|
|
8788
9128
|
for (const j of pureAdded) {
|
|
8789
9129
|
const el = fresh.get(j);
|
|
@@ -8798,6 +9138,7 @@ var Docxodus = (() => {
|
|
|
8798
9138
|
if (prevW) prevW.after(el);
|
|
8799
9139
|
else if (nextW) nextW.before(el);
|
|
8800
9140
|
else return "insert with no anchored neighbor";
|
|
9141
|
+
appliedFresh.add(j);
|
|
8801
9142
|
this.wireUnit(el, units[j]);
|
|
8802
9143
|
}
|
|
8803
9144
|
for (const i of pureRemoved) {
|
|
@@ -8836,13 +9177,13 @@ var Docxodus = (() => {
|
|
|
8836
9177
|
if (anchorEl) this.wireBlock(anchorEl);
|
|
8837
9178
|
root.querySelectorAll("[data-anchor]").forEach((b) => this.wireBlock(b));
|
|
8838
9179
|
}
|
|
8839
|
-
/** Old-sequence diff state for one notes section. `null` requests remount
|
|
8840
|
-
* stampable
|
|
9180
|
+
/** Old-sequence diff state for one notes section. `null` requests remount when an
|
|
9181
|
+
* existing list is not stampable; an absent list is the valid first-note case. */
|
|
8841
9182
|
notesDiff(sectionClass, units) {
|
|
8842
9183
|
const ol = this.editRoot.querySelector(`section.${sectionClass} > ol`);
|
|
8843
9184
|
const lis = ol ? Array.from(ol.children).filter((c) => c.tagName === "LI") : [];
|
|
8844
9185
|
if (units.length === 0 && lis.length === 0) return { lis, diff: diffUnits([], []) };
|
|
8845
|
-
if (!ol) return
|
|
9186
|
+
if (!ol) return { lis, diff: diffUnits([], units) };
|
|
8846
9187
|
const tokens = [];
|
|
8847
9188
|
for (const li of lis) {
|
|
8848
9189
|
const unid = li.getAttribute("data-note-anchor");
|
|
@@ -8859,7 +9200,20 @@ var Docxodus = (() => {
|
|
|
8859
9200
|
this.editRoot.querySelector(`section.${sectionClass}`)?.remove();
|
|
8860
9201
|
return;
|
|
8861
9202
|
}
|
|
8862
|
-
|
|
9203
|
+
let section = this.editRoot.querySelector(`:scope > section.${sectionClass}`);
|
|
9204
|
+
let ol = section?.querySelector(`:scope > ol`) ?? null;
|
|
9205
|
+
if (!ol) {
|
|
9206
|
+
if (!section) {
|
|
9207
|
+
section = document.createElement("section");
|
|
9208
|
+
section.className = sectionClass;
|
|
9209
|
+
const following = sectionClass === "footnotes" ? this.editRoot.querySelector(`:scope > section.endnotes`) : null;
|
|
9210
|
+
if (following) following.before(section);
|
|
9211
|
+
else this.editRoot.append(section);
|
|
9212
|
+
}
|
|
9213
|
+
if (!section.querySelector(":scope > hr")) section.prepend(document.createElement("hr"));
|
|
9214
|
+
ol = document.createElement("ol");
|
|
9215
|
+
section.append(ol);
|
|
9216
|
+
}
|
|
8863
9217
|
const prefix = sectionClass === "footnotes" ? "fn" : "en";
|
|
8864
9218
|
const nodes = [];
|
|
8865
9219
|
for (let j = 0; j < units.length; j++) {
|
|
@@ -9040,6 +9394,7 @@ var Docxodus = (() => {
|
|
|
9040
9394
|
color: var(--dxr-ink);
|
|
9041
9395
|
background: var(--dxr-desk);
|
|
9042
9396
|
-webkit-text-size-adjust: 100%;
|
|
9397
|
+
text-size-adjust: 100%;
|
|
9043
9398
|
}
|
|
9044
9399
|
.dxr *, .dxr *::before, .dxr *::after { box-sizing: border-box; }
|
|
9045
9400
|
|