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.bundle.js
CHANGED
|
@@ -1332,7 +1332,7 @@ function formatPageNumber(value, format) {
|
|
|
1332
1332
|
var DEFAULT_PAGE_WIDTH = 612;
|
|
1333
1333
|
var DEFAULT_PAGE_HEIGHT = 792;
|
|
1334
1334
|
var DEFAULT_MARGIN = 72;
|
|
1335
|
-
var
|
|
1335
|
+
var DEFAULT_HEADER_FOOTER_DISTANCE = 36;
|
|
1336
1336
|
function pxToPt(px) {
|
|
1337
1337
|
return px * 0.75;
|
|
1338
1338
|
}
|
|
@@ -1348,8 +1348,8 @@ function parseSectionDimensions(section) {
|
|
|
1348
1348
|
const marginRight = parseFloat(section.dataset.marginRight || "") || DEFAULT_MARGIN;
|
|
1349
1349
|
const marginBottom = parseFloat(section.dataset.marginBottom || "") || DEFAULT_MARGIN;
|
|
1350
1350
|
const marginLeft = parseFloat(section.dataset.marginLeft || "") || DEFAULT_MARGIN;
|
|
1351
|
-
const
|
|
1352
|
-
const
|
|
1351
|
+
const headerDistance = parseFloat(section.dataset.headerHeight || "") || DEFAULT_HEADER_FOOTER_DISTANCE;
|
|
1352
|
+
const footerDistance = parseFloat(section.dataset.footerHeight || "") || DEFAULT_HEADER_FOOTER_DISTANCE;
|
|
1353
1353
|
return {
|
|
1354
1354
|
pageWidth,
|
|
1355
1355
|
pageHeight,
|
|
@@ -1359,8 +1359,37 @@ function parseSectionDimensions(section) {
|
|
|
1359
1359
|
marginRight,
|
|
1360
1360
|
marginBottom,
|
|
1361
1361
|
marginLeft,
|
|
1362
|
-
|
|
1363
|
-
|
|
1362
|
+
headerDistance,
|
|
1363
|
+
footerDistance,
|
|
1364
|
+
headerHeight: headerDistance,
|
|
1365
|
+
footerHeight: footerDistance
|
|
1366
|
+
};
|
|
1367
|
+
}
|
|
1368
|
+
var MIN_BODY_BAND_PT = 12;
|
|
1369
|
+
function resolvePageBands(dims, headerContentHeight, footerContentHeight) {
|
|
1370
|
+
const headerTop = dims.headerDistance;
|
|
1371
|
+
const footerBottom = dims.pageHeight - dims.footerDistance;
|
|
1372
|
+
const headerReach = headerContentHeight > 0 ? headerTop + headerContentHeight : 0;
|
|
1373
|
+
const footerReach = footerContentHeight > 0 ? footerBottom - footerContentHeight : dims.pageHeight;
|
|
1374
|
+
let bodyTop = Math.max(dims.marginTop, headerReach);
|
|
1375
|
+
let bodyBottom = Math.min(dims.pageHeight - dims.marginBottom, footerReach);
|
|
1376
|
+
const shortfall = MIN_BODY_BAND_PT - (bodyBottom - bodyTop);
|
|
1377
|
+
if (shortfall > 0) {
|
|
1378
|
+
const headerGrowth = bodyTop - dims.marginTop;
|
|
1379
|
+
const footerGrowth = dims.pageHeight - dims.marginBottom - bodyBottom;
|
|
1380
|
+
const growth = headerGrowth + footerGrowth;
|
|
1381
|
+
if (growth > 0) {
|
|
1382
|
+
bodyTop -= shortfall * headerGrowth / growth;
|
|
1383
|
+
bodyBottom += shortfall * footerGrowth / growth;
|
|
1384
|
+
}
|
|
1385
|
+
}
|
|
1386
|
+
return {
|
|
1387
|
+
headerTop,
|
|
1388
|
+
headerHeight: Math.max(0, Math.min(headerContentHeight, bodyTop - headerTop)),
|
|
1389
|
+
bodyTop,
|
|
1390
|
+
bodyHeight: Math.max(0, bodyBottom - bodyTop),
|
|
1391
|
+
footerTop: footerBottom - Math.max(0, Math.min(footerContentHeight, footerBottom - bodyBottom)),
|
|
1392
|
+
footerHeight: Math.max(0, Math.min(footerContentHeight, footerBottom - bodyBottom))
|
|
1364
1393
|
};
|
|
1365
1394
|
}
|
|
1366
1395
|
function sectionWrappers(root) {
|
|
@@ -1397,6 +1426,9 @@ function applyZoom(el, scale, naturalPt) {
|
|
|
1397
1426
|
}
|
|
1398
1427
|
|
|
1399
1428
|
// src/pagination.ts
|
|
1429
|
+
function samePageBox(a, b) {
|
|
1430
|
+
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;
|
|
1431
|
+
}
|
|
1400
1432
|
var MAX_FOOTNOTE_AREA_RATIO = 0.6;
|
|
1401
1433
|
var MIN_BODY_CONTENT_HEIGHT = 72;
|
|
1402
1434
|
var PaginationEngine = class {
|
|
@@ -1442,16 +1474,43 @@ var PaginationEngine = class {
|
|
|
1442
1474
|
);
|
|
1443
1475
|
this.pageNumbering = this.parsePageNumbering(sections);
|
|
1444
1476
|
const sectionsToProcess = sections.length > 0 ? Array.from(sections) : [this.stagingElement];
|
|
1477
|
+
const runs = [];
|
|
1445
1478
|
for (const section of sectionsToProcess) {
|
|
1446
|
-
const sectionIndex = parseInt(section.dataset.sectionIndex || "0", 10);
|
|
1447
1479
|
const dims = parseSectionDimensions(section);
|
|
1480
|
+
const previous = runs[runs.length - 1];
|
|
1481
|
+
if (previous && section.dataset.sectionType === "continuous" && samePageBox(previous.dims, dims)) {
|
|
1482
|
+
previous.sections.push(section);
|
|
1483
|
+
} else {
|
|
1484
|
+
runs.push({
|
|
1485
|
+
sections: [section],
|
|
1486
|
+
sectionIndex: parseInt(section.dataset.sectionIndex || "0", 10),
|
|
1487
|
+
dims
|
|
1488
|
+
});
|
|
1489
|
+
}
|
|
1490
|
+
}
|
|
1491
|
+
for (const run of runs) {
|
|
1448
1492
|
this.stagingElement.style.visibility = "hidden";
|
|
1449
1493
|
this.stagingElement.style.position = "absolute";
|
|
1450
1494
|
this.stagingElement.style.left = "-9999px";
|
|
1451
1495
|
this.stagingElement.style.display = "block";
|
|
1452
|
-
|
|
1453
|
-
const
|
|
1454
|
-
|
|
1496
|
+
const blocks = [];
|
|
1497
|
+
for (const section of run.sections) {
|
|
1498
|
+
section.style.width = `${run.dims.contentWidth}pt`;
|
|
1499
|
+
const columnCount = parseInt(section.dataset.cols || "1", 10);
|
|
1500
|
+
if (columnCount > 1) {
|
|
1501
|
+
const gap = parseFloat(section.dataset.colGap || "");
|
|
1502
|
+
blocks.push(...this.buildColumnBlocks(
|
|
1503
|
+
section,
|
|
1504
|
+
run.dims,
|
|
1505
|
+
run.sectionIndex,
|
|
1506
|
+
columnCount,
|
|
1507
|
+
Number.isFinite(gap) ? gap : 36
|
|
1508
|
+
));
|
|
1509
|
+
} else {
|
|
1510
|
+
blocks.push(...this.measureBlocks(section, run.dims));
|
|
1511
|
+
}
|
|
1512
|
+
}
|
|
1513
|
+
const sectionPages = this.flowToPages(blocks, run.dims, pageNumber, run.sectionIndex);
|
|
1455
1514
|
pages.push(...sectionPages);
|
|
1456
1515
|
pageNumber += sectionPages.length;
|
|
1457
1516
|
}
|
|
@@ -1540,11 +1599,70 @@ var PaginationEngine = class {
|
|
|
1540
1599
|
keepWithNext: child.dataset.keepWithNext === "true",
|
|
1541
1600
|
keepLines: child.dataset.keepLines === "true",
|
|
1542
1601
|
pageBreakBefore: child.dataset.pageBreakBefore === "true",
|
|
1543
|
-
isPageBreak
|
|
1602
|
+
isPageBreak,
|
|
1603
|
+
isWordParagraph: this.isWordParagraphElement(child)
|
|
1544
1604
|
});
|
|
1545
1605
|
}
|
|
1546
1606
|
return blocks;
|
|
1547
1607
|
}
|
|
1608
|
+
/**
|
|
1609
|
+
* Flows a multi-column (`w:cols`) section's children into CSS-multicol container
|
|
1610
|
+
* blocks. Word lays such a section out as N columns inside the same body extent;
|
|
1611
|
+
* a balanced `column-count` container reproduces that geometry, and the paginator
|
|
1612
|
+
* then places each container as one ordinary measured block. A container grows
|
|
1613
|
+
* greedily until its balanced height would exceed the smallest page body available
|
|
1614
|
+
* to the section, so a long columned section still splits across pages at block
|
|
1615
|
+
* boundaries. Each child lands in exactly one container, so anchors never
|
|
1616
|
+
* duplicate. An explicit page break child passes through as its own block, which
|
|
1617
|
+
* ends the current container and lets the normal flow logic turn the page.
|
|
1618
|
+
*/
|
|
1619
|
+
buildColumnBlocks(section, dims, sectionIndex, columnCount, columnGapPt) {
|
|
1620
|
+
const children = Array.from(section.children);
|
|
1621
|
+
const blocks = [];
|
|
1622
|
+
const maxFragmentHeight = this.smallestEffectiveContentHeight(dims, sectionIndex);
|
|
1623
|
+
const isBreak = (child) => child.dataset.pageBreak === "true" || child.classList.contains(`${this.cssPrefix}break`);
|
|
1624
|
+
const makeContainer = (slice) => {
|
|
1625
|
+
const container = document.createElement("div");
|
|
1626
|
+
container.style.columnCount = String(columnCount);
|
|
1627
|
+
container.style.columnGap = `${columnGapPt}pt`;
|
|
1628
|
+
for (const child of slice) {
|
|
1629
|
+
container.appendChild(child.cloneNode(true));
|
|
1630
|
+
}
|
|
1631
|
+
return container;
|
|
1632
|
+
};
|
|
1633
|
+
let start2 = 0;
|
|
1634
|
+
while (start2 < children.length) {
|
|
1635
|
+
if (isBreak(children[start2])) {
|
|
1636
|
+
blocks.push(this.measureElement(children[start2], dims));
|
|
1637
|
+
start2++;
|
|
1638
|
+
continue;
|
|
1639
|
+
}
|
|
1640
|
+
let end = start2 + 1;
|
|
1641
|
+
let container = makeContainer(children.slice(start2, end));
|
|
1642
|
+
let measured = this.measureElement(container, dims);
|
|
1643
|
+
while (end < children.length && !isBreak(children[end])) {
|
|
1644
|
+
const candidate = makeContainer(children.slice(start2, end + 1));
|
|
1645
|
+
const candidateMeasured = this.measureElement(candidate, dims);
|
|
1646
|
+
if (candidateMeasured.heightPt > maxFragmentHeight) break;
|
|
1647
|
+
container = candidate;
|
|
1648
|
+
measured = candidateMeasured;
|
|
1649
|
+
end++;
|
|
1650
|
+
}
|
|
1651
|
+
blocks.push({
|
|
1652
|
+
element: container,
|
|
1653
|
+
heightPt: measured.heightPt,
|
|
1654
|
+
marginTopPt: measured.marginTopPt,
|
|
1655
|
+
marginBottomPt: measured.marginBottomPt,
|
|
1656
|
+
keepWithNext: false,
|
|
1657
|
+
keepLines: false,
|
|
1658
|
+
pageBreakBefore: false,
|
|
1659
|
+
isPageBreak: false,
|
|
1660
|
+
isWordParagraph: false
|
|
1661
|
+
});
|
|
1662
|
+
start2 = end;
|
|
1663
|
+
}
|
|
1664
|
+
return blocks;
|
|
1665
|
+
}
|
|
1548
1666
|
/**
|
|
1549
1667
|
* Measures one element in the same hidden staging context used for the source blocks.
|
|
1550
1668
|
* This is intentionally DOM-based: table row heights cannot be inferred from individual
|
|
@@ -1569,7 +1687,8 @@ var PaginationEngine = class {
|
|
|
1569
1687
|
keepWithNext: element.dataset.keepWithNext === "true",
|
|
1570
1688
|
keepLines: element.dataset.keepLines === "true",
|
|
1571
1689
|
pageBreakBefore: element.dataset.pageBreakBefore === "true",
|
|
1572
|
-
isPageBreak: element.dataset.pageBreak === "true" || element.classList.contains(`${this.cssPrefix}break`)
|
|
1690
|
+
isPageBreak: element.dataset.pageBreak === "true" || element.classList.contains(`${this.cssPrefix}break`),
|
|
1691
|
+
isWordParagraph: this.isWordParagraphElement(element)
|
|
1573
1692
|
};
|
|
1574
1693
|
this.stagingElement.removeChild(measurementHost);
|
|
1575
1694
|
return measured;
|
|
@@ -1601,10 +1720,15 @@ var PaginationEngine = class {
|
|
|
1601
1720
|
* collapsed-margin rules as normal block placement. The trailing margin is
|
|
1602
1721
|
* intentionally excluded, matching the individual block fit check.
|
|
1603
1722
|
*/
|
|
1604
|
-
measureKeepWithNextChainBodyHeight(chain, previousMarginBottomPt, isFirstOnPage) {
|
|
1723
|
+
measureKeepWithNextChainBodyHeight(chain, previousMarginBottomPt, isFirstOnPage, pageInSection) {
|
|
1605
1724
|
const firstBlock = chain[0];
|
|
1606
1725
|
if (!firstBlock) return 0;
|
|
1607
|
-
const firstMarginTop =
|
|
1726
|
+
const firstMarginTop = this.effectiveBlockMarginTop(
|
|
1727
|
+
firstBlock,
|
|
1728
|
+
previousMarginBottomPt,
|
|
1729
|
+
isFirstOnPage,
|
|
1730
|
+
pageInSection
|
|
1731
|
+
);
|
|
1608
1732
|
let bodyHeight = firstMarginTop + firstBlock.heightPt;
|
|
1609
1733
|
for (let index = 1; index < chain.length; index++) {
|
|
1610
1734
|
const previousBlock = chain[index - 1];
|
|
@@ -1613,6 +1737,35 @@ var PaginationEngine = class {
|
|
|
1613
1737
|
}
|
|
1614
1738
|
return bodyHeight;
|
|
1615
1739
|
}
|
|
1740
|
+
/** Word paragraphs render as `p`, or as `h1`–`h6` when their style has an outline level. */
|
|
1741
|
+
isWordParagraphElement(element) {
|
|
1742
|
+
return element.tagName === "P" || /^H[1-6]$/.test(element.tagName);
|
|
1743
|
+
}
|
|
1744
|
+
shouldSuppressPageTopSpacing(block, isFirstOnPage, pageInSection) {
|
|
1745
|
+
return isFirstOnPage && pageInSection > 1 && block.isWordParagraph === true;
|
|
1746
|
+
}
|
|
1747
|
+
/**
|
|
1748
|
+
* Resolves the part of a block's top margin that consumes the current page.
|
|
1749
|
+
*
|
|
1750
|
+
* In Word's native DOCX layout, paragraph space-before is suppressed when a paragraph is the
|
|
1751
|
+
* first body block on a later page of the SAME section. The first page of a document/section is
|
|
1752
|
+
* the exception and keeps its spacing. Tables and other block margins are not paragraph spacing,
|
|
1753
|
+
* so they continue to use the ordinary CSS collapsing rule.
|
|
1754
|
+
*/
|
|
1755
|
+
effectiveBlockMarginTop(block, previousMarginBottomPt, isFirstOnPage, pageInSection) {
|
|
1756
|
+
if (this.shouldSuppressPageTopSpacing(block, isFirstOnPage, pageInSection)) {
|
|
1757
|
+
return 0;
|
|
1758
|
+
}
|
|
1759
|
+
return isFirstOnPage ? block.marginTopPt : Math.max(block.marginTopPt, previousMarginBottomPt) - previousMarginBottomPt;
|
|
1760
|
+
}
|
|
1761
|
+
/** Clone a source block with the same page-top spacing decision used by the height budget. */
|
|
1762
|
+
cloneBlockForPage(block, isFirstOnPage, pageInSection) {
|
|
1763
|
+
const clone = block.element.cloneNode(true);
|
|
1764
|
+
if (this.shouldSuppressPageTopSpacing(block, isFirstOnPage, pageInSection)) {
|
|
1765
|
+
clone.style.setProperty("margin-top", "0", "important");
|
|
1766
|
+
}
|
|
1767
|
+
return clone;
|
|
1768
|
+
}
|
|
1616
1769
|
/**
|
|
1617
1770
|
* Finds footnote references introduced by a sequence of blocks, preserving
|
|
1618
1771
|
* document order and excluding references already assigned to the page.
|
|
@@ -1637,9 +1790,9 @@ var PaginationEngine = class {
|
|
|
1637
1790
|
*/
|
|
1638
1791
|
smallestEffectiveContentHeight(dims, sectionIndex) {
|
|
1639
1792
|
return Math.min(
|
|
1640
|
-
this.
|
|
1641
|
-
this.
|
|
1642
|
-
this.
|
|
1793
|
+
this.getPageBands(dims, sectionIndex, 1, 1).bodyHeight,
|
|
1794
|
+
this.getPageBands(dims, sectionIndex, 2, 1).bodyHeight,
|
|
1795
|
+
this.getPageBands(dims, sectionIndex, 2, 2).bodyHeight
|
|
1643
1796
|
);
|
|
1644
1797
|
}
|
|
1645
1798
|
/**
|
|
@@ -2163,7 +2316,7 @@ var PaginationEngine = class {
|
|
|
2163
2316
|
/**
|
|
2164
2317
|
* Adds footnotes to a page container, including continuation content.
|
|
2165
2318
|
*/
|
|
2166
|
-
addPageFootnotes(pageBox, footnoteIds, dims, footnoteHeight, continuation, partialFootnotes) {
|
|
2319
|
+
addPageFootnotes(pageBox, footnoteIds, dims, bands, footnoteHeight, continuation, partialFootnotes) {
|
|
2167
2320
|
const hasContinuation = continuation && continuation.remainingElements.length > 0;
|
|
2168
2321
|
if (footnoteIds.length === 0 && !hasContinuation) {
|
|
2169
2322
|
return;
|
|
@@ -2174,12 +2327,12 @@ var PaginationEngine = class {
|
|
|
2174
2327
|
const partialFootnoteIds = new Set(partialFootnotes?.map((p) => p.footnoteId) || []);
|
|
2175
2328
|
const maxFootnoteHeight = Math.min(
|
|
2176
2329
|
footnoteHeight,
|
|
2177
|
-
|
|
2330
|
+
bands.bodyHeight * MAX_FOOTNOTE_AREA_RATIO
|
|
2178
2331
|
);
|
|
2179
2332
|
const footnotesDiv = document.createElement("div");
|
|
2180
2333
|
footnotesDiv.className = `${this.cssPrefix}footnotes`;
|
|
2181
2334
|
footnotesDiv.style.position = "absolute";
|
|
2182
|
-
footnotesDiv.style.bottom = `${dims.
|
|
2335
|
+
footnotesDiv.style.bottom = `${dims.pageHeight - (bands.bodyTop + bands.bodyHeight)}pt`;
|
|
2183
2336
|
footnotesDiv.style.left = `${dims.marginLeft}pt`;
|
|
2184
2337
|
footnotesDiv.style.width = `${dims.contentWidth}pt`;
|
|
2185
2338
|
footnotesDiv.style.boxSizing = "border-box";
|
|
@@ -2253,50 +2406,51 @@ var PaginationEngine = class {
|
|
|
2253
2406
|
return sectionHf.footerDefault;
|
|
2254
2407
|
}
|
|
2255
2408
|
/**
|
|
2256
|
-
*
|
|
2257
|
-
*
|
|
2258
|
-
*
|
|
2259
|
-
*
|
|
2260
|
-
*
|
|
2409
|
+
* The header, body, and footer bands for one page position.
|
|
2410
|
+
*
|
|
2411
|
+
* The single owner of "where does anything sit vertically on this page" — placement in
|
|
2412
|
+
* {@link createPage}, the body budget the flow loop spends, and the note area's anchor all
|
|
2413
|
+
* read it, so those three cannot disagree about where the body ends.
|
|
2414
|
+
*
|
|
2415
|
+
* Deterministic: it depends only on the section's page setup and the registry's pre-measured
|
|
2416
|
+
* story heights, never on the page's content, which is what keeps it lazy-loading compatible.
|
|
2261
2417
|
*/
|
|
2262
|
-
|
|
2418
|
+
getPageBands(dims, sectionIndex, pageInSection, globalPageNumber) {
|
|
2263
2419
|
const sectionHf = this.hfRegistry.get(sectionIndex);
|
|
2264
|
-
|
|
2265
|
-
|
|
2266
|
-
|
|
2267
|
-
|
|
2268
|
-
|
|
2269
|
-
|
|
2270
|
-
|
|
2271
|
-
|
|
2272
|
-
|
|
2273
|
-
|
|
2274
|
-
|
|
2275
|
-
|
|
2276
|
-
|
|
2277
|
-
|
|
2278
|
-
|
|
2279
|
-
|
|
2280
|
-
|
|
2281
|
-
|
|
2282
|
-
|
|
2283
|
-
|
|
2284
|
-
|
|
2285
|
-
|
|
2286
|
-
|
|
2287
|
-
|
|
2288
|
-
|
|
2289
|
-
|
|
2290
|
-
}
|
|
2291
|
-
}
|
|
2292
|
-
const headerExpansion = headerHeight - dims.marginTop;
|
|
2293
|
-
const footerExpansion = footerHeight - dims.marginBottom;
|
|
2294
|
-
const contentHeight = dims.contentHeight - headerExpansion - footerExpansion;
|
|
2295
|
-
return { headerHeight, footerHeight, contentHeight };
|
|
2420
|
+
return resolvePageBands(
|
|
2421
|
+
dims,
|
|
2422
|
+
this.selectStoryHeight(
|
|
2423
|
+
sectionHf?.headerFirstHeight,
|
|
2424
|
+
sectionHf?.headerEvenHeight,
|
|
2425
|
+
sectionHf?.headerDefaultHeight,
|
|
2426
|
+
pageInSection,
|
|
2427
|
+
globalPageNumber
|
|
2428
|
+
),
|
|
2429
|
+
this.selectStoryHeight(
|
|
2430
|
+
sectionHf?.footerFirstHeight,
|
|
2431
|
+
sectionHf?.footerEvenHeight,
|
|
2432
|
+
sectionHf?.footerDefaultHeight,
|
|
2433
|
+
pageInSection,
|
|
2434
|
+
globalPageNumber
|
|
2435
|
+
)
|
|
2436
|
+
);
|
|
2437
|
+
}
|
|
2438
|
+
/**
|
|
2439
|
+
* The measured height of the running story this page position selects, mirroring
|
|
2440
|
+
* {@link selectHeader}/{@link selectFooter}. Zero when the page has no such story.
|
|
2441
|
+
*/
|
|
2442
|
+
selectStoryHeight(first, even, fallback, pageInSection, globalPageNumber) {
|
|
2443
|
+
if (pageInSection === 1 && first != null) return first;
|
|
2444
|
+
if (globalPageNumber % 2 === 0 && even != null) return even;
|
|
2445
|
+
return fallback ?? 0;
|
|
2296
2446
|
}
|
|
2297
2447
|
/**
|
|
2298
2448
|
* Measures the content height of a header or footer element.
|
|
2299
|
-
*
|
|
2449
|
+
*
|
|
2450
|
+
* This is what tells {@link resolvePageBands} whether the story stays inside its margin or
|
|
2451
|
+
* pushes the body, so it must measure the story ALONE — any padding added here would have to
|
|
2452
|
+
* be added to the rendered band too, and the two drifting apart is exactly how a header
|
|
2453
|
+
* silently starts overlapping body text.
|
|
2300
2454
|
*/
|
|
2301
2455
|
measureHeaderFooterHeight(source, contentWidth) {
|
|
2302
2456
|
const measureContainer = document.createElement("div");
|
|
@@ -2304,7 +2458,6 @@ var PaginationEngine = class {
|
|
|
2304
2458
|
measureContainer.style.visibility = "hidden";
|
|
2305
2459
|
measureContainer.style.width = `${contentWidth}pt`;
|
|
2306
2460
|
measureContainer.style.left = "-9999px";
|
|
2307
|
-
measureContainer.style.paddingBottom = "4pt";
|
|
2308
2461
|
for (const child of Array.from(source.childNodes)) {
|
|
2309
2462
|
measureContainer.appendChild(child.cloneNode(true));
|
|
2310
2463
|
}
|
|
@@ -2324,7 +2477,7 @@ var PaginationEngine = class {
|
|
|
2324
2477
|
let currentContent = [];
|
|
2325
2478
|
let pageNumber = startPageNumber;
|
|
2326
2479
|
let pageInSection = 1;
|
|
2327
|
-
let {
|
|
2480
|
+
let { bodyHeight: effectiveContentHeight } = this.getPageBands(
|
|
2328
2481
|
dims,
|
|
2329
2482
|
sectionIndex,
|
|
2330
2483
|
pageInSection,
|
|
@@ -2359,8 +2512,8 @@ var PaginationEngine = class {
|
|
|
2359
2512
|
pageNumber++;
|
|
2360
2513
|
pageInSection++;
|
|
2361
2514
|
currentContent = [];
|
|
2362
|
-
const
|
|
2363
|
-
effectiveContentHeight =
|
|
2515
|
+
const newBands = this.getPageBands(dims, sectionIndex, pageInSection, pageNumber);
|
|
2516
|
+
effectiveContentHeight = newBands.bodyHeight;
|
|
2364
2517
|
remainingHeight = effectiveContentHeight;
|
|
2365
2518
|
prevMarginBottomPt = 0;
|
|
2366
2519
|
currentFootnoteIds = [];
|
|
@@ -2418,11 +2571,12 @@ var PaginationEngine = class {
|
|
|
2418
2571
|
const currentChainHeight = this.measureKeepWithNextChainBodyHeight(
|
|
2419
2572
|
keepChain,
|
|
2420
2573
|
prevMarginBottomPt,
|
|
2421
|
-
currentContent.length === 0
|
|
2574
|
+
currentContent.length === 0,
|
|
2575
|
+
pageInSection
|
|
2422
2576
|
) + additionalChainFootnoteHeight;
|
|
2423
2577
|
const currentAvailableHeight = remainingHeight - currentFootnoteHeight;
|
|
2424
2578
|
if (currentChainHeight > currentAvailableHeight) {
|
|
2425
|
-
const
|
|
2579
|
+
const nextPageBands = this.getPageBands(
|
|
2426
2580
|
dims,
|
|
2427
2581
|
sectionIndex,
|
|
2428
2582
|
pageInSection + 1,
|
|
@@ -2431,14 +2585,15 @@ var PaginationEngine = class {
|
|
|
2431
2585
|
const freshChainBodyHeight = this.measureKeepWithNextChainBodyHeight(
|
|
2432
2586
|
keepChain,
|
|
2433
2587
|
0,
|
|
2434
|
-
true
|
|
2588
|
+
true,
|
|
2589
|
+
pageInSection + 1
|
|
2435
2590
|
);
|
|
2436
2591
|
const freshChainFootnoteHeight = this.measureFootnotesHeight(
|
|
2437
2592
|
newChainFootnoteIds,
|
|
2438
2593
|
dims.contentWidth,
|
|
2439
2594
|
nextPageContinuation
|
|
2440
2595
|
);
|
|
2441
|
-
if (freshChainBodyHeight + freshChainFootnoteHeight <=
|
|
2596
|
+
if (freshChainBodyHeight + freshChainFootnoteHeight <= nextPageBands.bodyHeight) {
|
|
2442
2597
|
finishPage();
|
|
2443
2598
|
}
|
|
2444
2599
|
}
|
|
@@ -2457,10 +2612,12 @@ var PaginationEngine = class {
|
|
|
2457
2612
|
additionalFootnoteHeight = totalFootnoteHeight - currentFootnoteHeight;
|
|
2458
2613
|
}
|
|
2459
2614
|
const isFirstOnPage = currentContent.length === 0;
|
|
2460
|
-
|
|
2461
|
-
|
|
2462
|
-
|
|
2463
|
-
|
|
2615
|
+
const effectiveMarginTop = this.effectiveBlockMarginTop(
|
|
2616
|
+
block,
|
|
2617
|
+
prevMarginBottomPt,
|
|
2618
|
+
isFirstOnPage,
|
|
2619
|
+
pageInSection
|
|
2620
|
+
);
|
|
2464
2621
|
const blockSpace = effectiveMarginTop + block.heightPt + additionalFootnoteHeight;
|
|
2465
2622
|
const effectiveRemainingHeight = remainingHeight - currentFootnoteHeight;
|
|
2466
2623
|
const bodyContentUsed = effectiveContentHeight - remainingHeight;
|
|
@@ -2480,19 +2637,19 @@ var PaginationEngine = class {
|
|
|
2480
2637
|
}
|
|
2481
2638
|
}
|
|
2482
2639
|
if (blockSpace <= effectiveRemainingHeight) {
|
|
2483
|
-
currentContent.push(
|
|
2640
|
+
currentContent.push(this.cloneBlockForPage(block, isFirstOnPage, pageInSection));
|
|
2484
2641
|
remainingHeight -= effectiveMarginTop + block.heightPt + block.marginBottomPt;
|
|
2485
2642
|
prevMarginBottomPt = block.marginBottomPt;
|
|
2486
2643
|
if (newFootnoteIds.length > 0) {
|
|
2487
2644
|
currentFootnoteIds.push(...newFootnoteIds);
|
|
2488
2645
|
currentFootnoteHeight += additionalFootnoteHeight;
|
|
2489
2646
|
}
|
|
2490
|
-
} else if (block.heightPt + block
|
|
2647
|
+
} else if (block.heightPt + this.effectiveBlockMarginTop(block, 0, true, pageInSection + 1) <= effectiveContentHeight) {
|
|
2491
2648
|
const blockSpaceWithoutFootnotes = effectiveMarginTop + block.heightPt;
|
|
2492
2649
|
const minBodySpaceNeeded = bodyContentUsed + blockSpaceWithoutFootnotes + MIN_BODY_CONTENT_HEIGHT;
|
|
2493
2650
|
const canExpandFootnotes = minBodySpaceNeeded <= effectiveContentHeight;
|
|
2494
2651
|
if (newFootnoteIds.length > 0 && blockSpaceWithoutFootnotes <= effectiveRemainingHeight) {
|
|
2495
|
-
currentContent.push(
|
|
2652
|
+
currentContent.push(this.cloneBlockForPage(block, isFirstOnPage, pageInSection));
|
|
2496
2653
|
remainingHeight -= effectiveMarginTop + block.heightPt + block.marginBottomPt;
|
|
2497
2654
|
prevMarginBottomPt = block.marginBottomPt;
|
|
2498
2655
|
const availableForFootnotes = Math.min(
|
|
@@ -2539,7 +2696,7 @@ var PaginationEngine = class {
|
|
|
2539
2696
|
const expandedFootnoteSpace = Math.min(maxFootnoteArea, additionalFootnoteHeight + currentFootnoteHeight);
|
|
2540
2697
|
const bodySpaceAfterExpansion = effectiveContentHeight - expandedFootnoteSpace;
|
|
2541
2698
|
if (blockSpaceWithoutFootnotes <= bodySpaceAfterExpansion - bodyContentUsed) {
|
|
2542
|
-
currentContent.push(
|
|
2699
|
+
currentContent.push(this.cloneBlockForPage(block, isFirstOnPage, pageInSection));
|
|
2543
2700
|
remainingHeight = bodySpaceAfterExpansion - bodyContentUsed - blockSpaceWithoutFootnotes;
|
|
2544
2701
|
prevMarginBottomPt = block.marginBottomPt;
|
|
2545
2702
|
currentFootnoteIds.push(...newFootnoteIds);
|
|
@@ -2547,8 +2704,14 @@ var PaginationEngine = class {
|
|
|
2547
2704
|
} else {
|
|
2548
2705
|
finishPage();
|
|
2549
2706
|
const newPageFootnoteHeight = allBlockFootnoteIds.length > 0 ? this.measureFootnotesHeight(allBlockFootnoteIds, dims.contentWidth, currentContinuation) : currentContinuation ? this.measureContinuationHeight(currentContinuation, dims.contentWidth) : 0;
|
|
2550
|
-
const
|
|
2551
|
-
|
|
2707
|
+
const newPageMarginTop = this.effectiveBlockMarginTop(
|
|
2708
|
+
block,
|
|
2709
|
+
0,
|
|
2710
|
+
true,
|
|
2711
|
+
pageInSection
|
|
2712
|
+
);
|
|
2713
|
+
const newPageSpace = newPageMarginTop + block.heightPt + block.marginBottomPt;
|
|
2714
|
+
currentContent.push(this.cloneBlockForPage(block, true, pageInSection));
|
|
2552
2715
|
remainingHeight = effectiveContentHeight - newPageSpace;
|
|
2553
2716
|
prevMarginBottomPt = block.marginBottomPt;
|
|
2554
2717
|
currentFootnoteIds = [...currentFootnoteIds, ...allBlockFootnoteIds];
|
|
@@ -2557,8 +2720,14 @@ var PaginationEngine = class {
|
|
|
2557
2720
|
} else {
|
|
2558
2721
|
finishPage();
|
|
2559
2722
|
const newPageFootnoteHeight = allBlockFootnoteIds.length > 0 ? this.measureFootnotesHeight(allBlockFootnoteIds, dims.contentWidth, currentContinuation) : currentContinuation ? this.measureContinuationHeight(currentContinuation, dims.contentWidth) : 0;
|
|
2560
|
-
const
|
|
2561
|
-
|
|
2723
|
+
const newPageMarginTop = this.effectiveBlockMarginTop(
|
|
2724
|
+
block,
|
|
2725
|
+
0,
|
|
2726
|
+
true,
|
|
2727
|
+
pageInSection
|
|
2728
|
+
);
|
|
2729
|
+
const newPageSpace = newPageMarginTop + block.heightPt + block.marginBottomPt;
|
|
2730
|
+
currentContent.push(this.cloneBlockForPage(block, true, pageInSection));
|
|
2562
2731
|
remainingHeight = effectiveContentHeight - newPageSpace;
|
|
2563
2732
|
prevMarginBottomPt = block.marginBottomPt;
|
|
2564
2733
|
currentFootnoteIds = [...currentFootnoteIds, ...allBlockFootnoteIds];
|
|
@@ -2577,7 +2746,7 @@ var PaginationEngine = class {
|
|
|
2577
2746
|
if (currentContent.length > 0) {
|
|
2578
2747
|
finishPage();
|
|
2579
2748
|
}
|
|
2580
|
-
currentContent.push(
|
|
2749
|
+
currentContent.push(this.cloneBlockForPage(block, true, pageInSection));
|
|
2581
2750
|
currentFootnoteIds = [...currentFootnoteIds, ...allBlockFootnoteIds];
|
|
2582
2751
|
finishPage();
|
|
2583
2752
|
}
|
|
@@ -2607,6 +2776,161 @@ var PaginationEngine = class {
|
|
|
2607
2776
|
if (el.getAttribute("contenteditable") !== null) el.setAttribute("contenteditable", "false");
|
|
2608
2777
|
}
|
|
2609
2778
|
}
|
|
2779
|
+
/**
|
|
2780
|
+
* Resolves floating DrawingML objects after their anchor paragraphs have landed on a page.
|
|
2781
|
+
*
|
|
2782
|
+
* The converter deliberately carries the OOXML bases and offsets as data instead of flattening
|
|
2783
|
+
* them into CSS: page/margin/column bases belong to the page, while paragraph/line/character
|
|
2784
|
+
* bases belong to the laid-out anchor. Once both coordinate systems exist, promote the object
|
|
2785
|
+
* from the clipped text column into the page box and position it in one shared point space.
|
|
2786
|
+
*/
|
|
2787
|
+
positionDrawingAnchors(pageBox, contentArea, dims, pageNumber) {
|
|
2788
|
+
const anchors = Array.from(
|
|
2789
|
+
contentArea.querySelectorAll('[data-docx-drawing-anchor="true"]')
|
|
2790
|
+
);
|
|
2791
|
+
if (anchors.length === 0) return;
|
|
2792
|
+
const pageRect = pageBox.getBoundingClientRect();
|
|
2793
|
+
const pixelsPerPoint = pageRect.width / dims.pageWidth;
|
|
2794
|
+
if (!(pixelsPerPoint > 0)) return;
|
|
2795
|
+
for (const anchor of anchors) {
|
|
2796
|
+
const staticRect = anchor.getBoundingClientRect();
|
|
2797
|
+
const paragraph = anchor.closest("p, h1, h2, h3, h4, h5, h6");
|
|
2798
|
+
const paragraphRect = paragraph?.getBoundingClientRect() ?? staticRect;
|
|
2799
|
+
const toPageX = (x) => (x - pageRect.left) / pixelsPerPoint;
|
|
2800
|
+
const toPageY = (y) => (y - pageRect.top) / pixelsPerPoint;
|
|
2801
|
+
const context = {
|
|
2802
|
+
staticLeft: toPageX(staticRect.left),
|
|
2803
|
+
staticTop: toPageY(staticRect.top),
|
|
2804
|
+
lineHeight: paragraph ? (parseFloat(getComputedStyle(paragraph).lineHeight) || staticRect.height) / pixelsPerPoint : staticRect.height / pixelsPerPoint,
|
|
2805
|
+
paragraphLeft: toPageX(paragraphRect.left),
|
|
2806
|
+
paragraphTop: toPageY(paragraphRect.top),
|
|
2807
|
+
paragraphWidth: paragraphRect.width / pixelsPerPoint,
|
|
2808
|
+
paragraphHeight: paragraphRect.height / pixelsPerPoint
|
|
2809
|
+
};
|
|
2810
|
+
const widthReference = this.horizontalAnchorReference(
|
|
2811
|
+
anchor.getAttribute("data-docx-anchor-width-relative") ?? "margin",
|
|
2812
|
+
dims,
|
|
2813
|
+
pageNumber,
|
|
2814
|
+
context
|
|
2815
|
+
);
|
|
2816
|
+
const widthPercent = this.anchorNumber(anchor, "width-percent");
|
|
2817
|
+
if (widthPercent !== void 0) {
|
|
2818
|
+
anchor.style.width = `${widthReference.size * widthPercent / 100}pt`;
|
|
2819
|
+
}
|
|
2820
|
+
const heightReference = this.verticalAnchorReference(
|
|
2821
|
+
anchor.getAttribute("data-docx-anchor-height-relative") ?? "margin",
|
|
2822
|
+
dims,
|
|
2823
|
+
pageNumber,
|
|
2824
|
+
context
|
|
2825
|
+
);
|
|
2826
|
+
const heightPercent = this.anchorNumber(anchor, "height-percent");
|
|
2827
|
+
if (heightPercent !== void 0 && anchor.dataset.docxAnchorAutofit !== "true") {
|
|
2828
|
+
anchor.style.height = `${heightReference.size * heightPercent / 100}pt`;
|
|
2829
|
+
}
|
|
2830
|
+
const sizedRect = anchor.getBoundingClientRect();
|
|
2831
|
+
const width = sizedRect.width / pixelsPerPoint;
|
|
2832
|
+
const height = sizedRect.height / pixelsPerPoint;
|
|
2833
|
+
const horizontal2 = this.horizontalAnchorReference(
|
|
2834
|
+
anchor.getAttribute("data-docx-anchor-h-relative") ?? "column",
|
|
2835
|
+
dims,
|
|
2836
|
+
pageNumber,
|
|
2837
|
+
context
|
|
2838
|
+
);
|
|
2839
|
+
const vertical2 = this.verticalAnchorReference(
|
|
2840
|
+
anchor.getAttribute("data-docx-anchor-v-relative") ?? "paragraph",
|
|
2841
|
+
dims,
|
|
2842
|
+
pageNumber,
|
|
2843
|
+
context
|
|
2844
|
+
);
|
|
2845
|
+
const left2 = this.resolveAnchorAxis(
|
|
2846
|
+
horizontal2,
|
|
2847
|
+
width,
|
|
2848
|
+
anchor.getAttribute("data-docx-anchor-h-align"),
|
|
2849
|
+
this.anchorNumber(anchor, "h-offset"),
|
|
2850
|
+
pageNumber
|
|
2851
|
+
);
|
|
2852
|
+
const top2 = this.resolveAnchorAxis(
|
|
2853
|
+
vertical2,
|
|
2854
|
+
height,
|
|
2855
|
+
anchor.getAttribute("data-docx-anchor-v-align"),
|
|
2856
|
+
this.anchorNumber(anchor, "v-offset"),
|
|
2857
|
+
pageNumber
|
|
2858
|
+
);
|
|
2859
|
+
pageBox.appendChild(anchor);
|
|
2860
|
+
anchor.style.position = "absolute";
|
|
2861
|
+
anchor.style.left = `${left2}pt`;
|
|
2862
|
+
anchor.style.top = `${top2}pt`;
|
|
2863
|
+
anchor.style.margin = "0";
|
|
2864
|
+
}
|
|
2865
|
+
}
|
|
2866
|
+
anchorNumber(anchor, suffix) {
|
|
2867
|
+
const raw = anchor.getAttribute(`data-docx-anchor-${suffix}`);
|
|
2868
|
+
if (raw === null) return void 0;
|
|
2869
|
+
const value = Number(raw);
|
|
2870
|
+
return Number.isFinite(value) ? value : void 0;
|
|
2871
|
+
}
|
|
2872
|
+
horizontalAnchorReference(relativeFrom, dims, pageNumber, context) {
|
|
2873
|
+
const leftMargin = { start: 0, size: dims.marginLeft };
|
|
2874
|
+
const rightMargin = {
|
|
2875
|
+
start: dims.marginLeft + dims.contentWidth,
|
|
2876
|
+
size: dims.marginRight
|
|
2877
|
+
};
|
|
2878
|
+
switch (relativeFrom) {
|
|
2879
|
+
case "page":
|
|
2880
|
+
return { start: 0, size: dims.pageWidth };
|
|
2881
|
+
case "character":
|
|
2882
|
+
return { start: context.staticLeft, size: 0 };
|
|
2883
|
+
case "leftMargin":
|
|
2884
|
+
return leftMargin;
|
|
2885
|
+
case "rightMargin":
|
|
2886
|
+
return rightMargin;
|
|
2887
|
+
case "insideMargin":
|
|
2888
|
+
return pageNumber % 2 === 1 ? leftMargin : rightMargin;
|
|
2889
|
+
case "outsideMargin":
|
|
2890
|
+
return pageNumber % 2 === 1 ? rightMargin : leftMargin;
|
|
2891
|
+
case "paragraph":
|
|
2892
|
+
return { start: context.paragraphLeft, size: context.paragraphWidth };
|
|
2893
|
+
case "column":
|
|
2894
|
+
case "margin":
|
|
2895
|
+
default:
|
|
2896
|
+
return { start: dims.marginLeft, size: dims.contentWidth };
|
|
2897
|
+
}
|
|
2898
|
+
}
|
|
2899
|
+
verticalAnchorReference(relativeFrom, dims, pageNumber, context) {
|
|
2900
|
+
const topMargin = { start: 0, size: dims.marginTop };
|
|
2901
|
+
const bottomMargin = {
|
|
2902
|
+
start: dims.marginTop + dims.contentHeight,
|
|
2903
|
+
size: dims.marginBottom
|
|
2904
|
+
};
|
|
2905
|
+
switch (relativeFrom) {
|
|
2906
|
+
case "page":
|
|
2907
|
+
return { start: 0, size: dims.pageHeight };
|
|
2908
|
+
case "paragraph":
|
|
2909
|
+
return { start: context.paragraphTop, size: context.paragraphHeight };
|
|
2910
|
+
case "line":
|
|
2911
|
+
return { start: context.staticTop, size: context.lineHeight };
|
|
2912
|
+
case "topMargin":
|
|
2913
|
+
return topMargin;
|
|
2914
|
+
case "bottomMargin":
|
|
2915
|
+
return bottomMargin;
|
|
2916
|
+
case "insideMargin":
|
|
2917
|
+
return pageNumber % 2 === 1 ? topMargin : bottomMargin;
|
|
2918
|
+
case "outsideMargin":
|
|
2919
|
+
return pageNumber % 2 === 1 ? bottomMargin : topMargin;
|
|
2920
|
+
case "margin":
|
|
2921
|
+
default:
|
|
2922
|
+
return { start: dims.marginTop, size: dims.contentHeight };
|
|
2923
|
+
}
|
|
2924
|
+
}
|
|
2925
|
+
resolveAnchorAxis(reference, objectSize, alignment, offset, pageNumber) {
|
|
2926
|
+
if (offset !== void 0) return reference.start + offset;
|
|
2927
|
+
let fraction = 0;
|
|
2928
|
+
if (alignment === "center") fraction = 0.5;
|
|
2929
|
+
else if (alignment === "right" || alignment === "bottom") fraction = 1;
|
|
2930
|
+
else if (alignment === "inside") fraction = pageNumber % 2 === 1 ? 0 : 1;
|
|
2931
|
+
else if (alignment === "outside") fraction = pageNumber % 2 === 1 ? 1 : 0;
|
|
2932
|
+
return reference.start + (reference.size - objectSize) * fraction;
|
|
2933
|
+
}
|
|
2610
2934
|
/**
|
|
2611
2935
|
* Creates a page container element.
|
|
2612
2936
|
*/
|
|
@@ -2633,22 +2957,22 @@ var PaginationEngine = class {
|
|
|
2633
2957
|
pageBox.dataset.pageNumber = String(pageNumber);
|
|
2634
2958
|
pageBox.dataset.sectionIndex = String(sectionIndex);
|
|
2635
2959
|
pageBox.dataset.pageInSection = String(pageInSection);
|
|
2636
|
-
const
|
|
2960
|
+
const bands = this.getPageBands(dims, sectionIndex, pageInSection, pageNumber);
|
|
2637
2961
|
const headerSource = this.selectHeader(sectionIndex, pageInSection, pageNumber);
|
|
2638
2962
|
if (headerSource) {
|
|
2639
2963
|
const headerDiv = document.createElement("div");
|
|
2640
2964
|
headerDiv.className = `${this.cssPrefix}header`;
|
|
2641
2965
|
headerDiv.style.position = "absolute";
|
|
2642
|
-
headerDiv.style.top =
|
|
2966
|
+
headerDiv.style.top = `${bands.headerTop}pt`;
|
|
2967
|
+
headerDiv.style.bottom = "auto";
|
|
2643
2968
|
headerDiv.style.left = `${dims.marginLeft}pt`;
|
|
2644
2969
|
headerDiv.style.width = `${dims.contentWidth}pt`;
|
|
2645
|
-
headerDiv.style.height = `${
|
|
2970
|
+
headerDiv.style.height = `${bands.headerHeight}pt`;
|
|
2646
2971
|
headerDiv.style.overflow = "hidden";
|
|
2647
2972
|
headerDiv.style.boxSizing = "border-box";
|
|
2648
2973
|
headerDiv.style.display = "flex";
|
|
2649
2974
|
headerDiv.style.flexDirection = "column";
|
|
2650
|
-
headerDiv.style.justifyContent = "flex-
|
|
2651
|
-
headerDiv.style.paddingBottom = "4pt";
|
|
2975
|
+
headerDiv.style.justifyContent = "flex-start";
|
|
2652
2976
|
for (const child of Array.from(headerSource.childNodes)) {
|
|
2653
2977
|
const clonedheaderDiv = child.cloneNode(true);
|
|
2654
2978
|
if (clonedheaderDiv.nodeType === 1) this.makeClonedStoryInert(clonedheaderDiv);
|
|
@@ -2656,8 +2980,8 @@ var PaginationEngine = class {
|
|
|
2656
2980
|
}
|
|
2657
2981
|
pageBox.appendChild(headerDiv);
|
|
2658
2982
|
}
|
|
2659
|
-
const contentAreaTop =
|
|
2660
|
-
const contentAreaHeight =
|
|
2983
|
+
const contentAreaTop = bands.bodyTop;
|
|
2984
|
+
const contentAreaHeight = bands.bodyHeight;
|
|
2661
2985
|
const contentArea = document.createElement("div");
|
|
2662
2986
|
contentArea.className = `${this.cssPrefix}content`;
|
|
2663
2987
|
contentArea.style.position = "absolute";
|
|
@@ -2672,23 +2996,23 @@ var PaginationEngine = class {
|
|
|
2672
2996
|
pageBox.appendChild(contentArea);
|
|
2673
2997
|
const hasContinuation = continuation && continuation.remainingElements.length > 0;
|
|
2674
2998
|
if (footnoteIds.length > 0 || hasContinuation) {
|
|
2675
|
-
this.addPageFootnotes(pageBox, footnoteIds, dims, footnoteHeight, continuation, partialFootnotes);
|
|
2999
|
+
this.addPageFootnotes(pageBox, footnoteIds, dims, bands, footnoteHeight, continuation, partialFootnotes);
|
|
2676
3000
|
}
|
|
2677
3001
|
const footerSource = this.selectFooter(sectionIndex, pageInSection, pageNumber);
|
|
2678
3002
|
if (footerSource) {
|
|
2679
3003
|
const footerDiv = document.createElement("div");
|
|
2680
3004
|
footerDiv.className = `${this.cssPrefix}footer`;
|
|
2681
3005
|
footerDiv.style.position = "absolute";
|
|
2682
|
-
footerDiv.style.
|
|
3006
|
+
footerDiv.style.top = "auto";
|
|
3007
|
+
footerDiv.style.bottom = `${dims.footerDistance}pt`;
|
|
2683
3008
|
footerDiv.style.left = `${dims.marginLeft}pt`;
|
|
2684
3009
|
footerDiv.style.width = `${dims.contentWidth}pt`;
|
|
2685
|
-
footerDiv.style.height = `${
|
|
3010
|
+
footerDiv.style.height = `${bands.footerHeight}pt`;
|
|
2686
3011
|
footerDiv.style.overflow = "hidden";
|
|
2687
3012
|
footerDiv.style.boxSizing = "border-box";
|
|
2688
3013
|
footerDiv.style.display = "flex";
|
|
2689
3014
|
footerDiv.style.flexDirection = "column";
|
|
2690
|
-
footerDiv.style.justifyContent = "flex-
|
|
2691
|
-
footerDiv.style.paddingTop = "4pt";
|
|
3015
|
+
footerDiv.style.justifyContent = "flex-end";
|
|
2692
3016
|
for (const child of Array.from(footerSource.childNodes)) {
|
|
2693
3017
|
const clonedfooterDiv = child.cloneNode(true);
|
|
2694
3018
|
if (clonedfooterDiv.nodeType === 1) this.makeClonedStoryInert(clonedfooterDiv);
|
|
@@ -2703,6 +3027,7 @@ var PaginationEngine = class {
|
|
|
2703
3027
|
pageBox.appendChild(pageNum);
|
|
2704
3028
|
}
|
|
2705
3029
|
this.containerElement.appendChild(pageBox);
|
|
3030
|
+
this.positionDrawingAnchors(pageBox, contentArea, dims, pageNumber);
|
|
2706
3031
|
const notesEl = pageBox.querySelector(`.${this.cssPrefix}footnotes`);
|
|
2707
3032
|
if (notesEl) {
|
|
2708
3033
|
const notesHeightPt = pxToPt(notesEl.getBoundingClientRect().height);
|
|
@@ -6077,6 +6402,19 @@ function serializeInlineMarkdown(block) {
|
|
|
6077
6402
|
function isListBlock(block) {
|
|
6078
6403
|
return !!block.querySelector(":scope > [data-list-marker]");
|
|
6079
6404
|
}
|
|
6405
|
+
function ensureListMarkerSeparator(block) {
|
|
6406
|
+
const marker = block.querySelector(":scope > [data-list-marker]");
|
|
6407
|
+
if (!marker) return;
|
|
6408
|
+
const next = marker.nextElementSibling;
|
|
6409
|
+
if (next?.hasAttribute("data-editor-list-separator")) return;
|
|
6410
|
+
const separator = block.ownerDocument.createElement("span");
|
|
6411
|
+
separator.setAttribute("data-editor-list-separator", "");
|
|
6412
|
+
separator.setAttribute("data-list-marker", "true");
|
|
6413
|
+
separator.setAttribute("aria-hidden", "true");
|
|
6414
|
+
separator.style.display = "none";
|
|
6415
|
+
separator.textContent = " ";
|
|
6416
|
+
marker.after(separator);
|
|
6417
|
+
}
|
|
6080
6418
|
var GENERATED_CHROME_SELECTOR = '[data-list-marker], a.footnote-ref, a.endnote-ref, a[class$="-backref"]';
|
|
6081
6419
|
function isGeneratedChrome(node) {
|
|
6082
6420
|
return node?.nodeType === 1 && !!node.matches?.(GENERATED_CHROME_SELECTOR);
|
|
@@ -7367,6 +7705,7 @@ var DocxEditor = class _DocxEditor {
|
|
|
7367
7705
|
const unid = el.getAttribute("data-anchor");
|
|
7368
7706
|
if (!unid || !this.anchorIdOf(el)) return;
|
|
7369
7707
|
el.setAttribute("contenteditable", "true");
|
|
7708
|
+
ensureListMarkerSeparator(el);
|
|
7370
7709
|
el.querySelectorAll(GENERATED_CHROME_SELECTOR).forEach((m) => m.setAttribute("contenteditable", "false"));
|
|
7371
7710
|
el.dataset.committedText = blockContentText(el);
|
|
7372
7711
|
el.addEventListener("focus", () => {
|
|
@@ -8229,8 +8568,8 @@ var DocxEditor = class _DocxEditor {
|
|
|
8229
8568
|
* editable `data-anchor` blocks in the notes section, so editing it afterwards needs no new op.
|
|
8230
8569
|
*
|
|
8231
8570
|
* Body blocks only: Word disallows a note reference inside a header/footer story or inside
|
|
8232
|
-
* another note, and the session rejects those with `AnchorWrongKind`.
|
|
8233
|
-
*
|
|
8571
|
+
* another note, and the session rejects those with `AnchorWrongKind`. Reconciliation creates
|
|
8572
|
+
* the first notes section when needed and renumbers every affected citation in place.
|
|
8234
8573
|
*/
|
|
8235
8574
|
insertFootnote(markdown = "New footnote.") {
|
|
8236
8575
|
this.insertNote("footnote", markdown);
|
|
@@ -8622,7 +8961,7 @@ var DocxEditor = class _DocxEditor {
|
|
|
8622
8961
|
* the current node — never a section div (multi-child) or the edit root. */
|
|
8623
8962
|
unitWrapperOf(el) {
|
|
8624
8963
|
let n = el;
|
|
8625
|
-
while (n.parentElement && n.parentElement !== this.editRoot && n.parentElement.tagName === "DIV" && !n.parentElement.hasAttribute("data-anchor") && n.parentElement.childElementCount === 1) {
|
|
8964
|
+
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) {
|
|
8626
8965
|
n = n.parentElement;
|
|
8627
8966
|
}
|
|
8628
8967
|
return n;
|
|
@@ -8658,6 +8997,7 @@ var DocxEditor = class _DocxEditor {
|
|
|
8658
8997
|
const pureRemoved = diff.removed.filter(
|
|
8659
8998
|
(i) => !diff.substituted.some((s) => s.oldIndex === i) && !movedOld.has(i)
|
|
8660
8999
|
);
|
|
9000
|
+
const appliedFresh = /* @__PURE__ */ new Set();
|
|
8661
9001
|
const nodeAt = (j) => {
|
|
8662
9002
|
const oi = diff.keep.get(j);
|
|
8663
9003
|
if (oi !== void 0) return oldNodes[oi];
|
|
@@ -8665,7 +9005,7 @@ var DocxEditor = class _DocxEditor {
|
|
|
8665
9005
|
if (movedOi !== void 0) return oldNodes[movedOi];
|
|
8666
9006
|
if (subOldByNew.has(j)) return fresh.get(j);
|
|
8667
9007
|
const f = fresh.get(j);
|
|
8668
|
-
return f &&
|
|
9008
|
+
return f && appliedFresh.has(j) ? f : null;
|
|
8669
9009
|
};
|
|
8670
9010
|
for (const j of pureAdded) {
|
|
8671
9011
|
const el = fresh.get(j);
|
|
@@ -8680,6 +9020,7 @@ var DocxEditor = class _DocxEditor {
|
|
|
8680
9020
|
if (prevW) prevW.after(el);
|
|
8681
9021
|
else if (nextW) nextW.before(el);
|
|
8682
9022
|
else return "insert with no anchored neighbor";
|
|
9023
|
+
appliedFresh.add(j);
|
|
8683
9024
|
this.wireUnit(el, units[j]);
|
|
8684
9025
|
}
|
|
8685
9026
|
for (const i of pureRemoved) {
|
|
@@ -8718,13 +9059,13 @@ var DocxEditor = class _DocxEditor {
|
|
|
8718
9059
|
if (anchorEl) this.wireBlock(anchorEl);
|
|
8719
9060
|
root.querySelectorAll("[data-anchor]").forEach((b) => this.wireBlock(b));
|
|
8720
9061
|
}
|
|
8721
|
-
/** Old-sequence diff state for one notes section. `null` requests remount
|
|
8722
|
-
* stampable
|
|
9062
|
+
/** Old-sequence diff state for one notes section. `null` requests remount when an
|
|
9063
|
+
* existing list is not stampable; an absent list is the valid first-note case. */
|
|
8723
9064
|
notesDiff(sectionClass, units) {
|
|
8724
9065
|
const ol = this.editRoot.querySelector(`section.${sectionClass} > ol`);
|
|
8725
9066
|
const lis = ol ? Array.from(ol.children).filter((c) => c.tagName === "LI") : [];
|
|
8726
9067
|
if (units.length === 0 && lis.length === 0) return { lis, diff: diffUnits([], []) };
|
|
8727
|
-
if (!ol) return
|
|
9068
|
+
if (!ol) return { lis, diff: diffUnits([], units) };
|
|
8728
9069
|
const tokens = [];
|
|
8729
9070
|
for (const li of lis) {
|
|
8730
9071
|
const unid = li.getAttribute("data-note-anchor");
|
|
@@ -8741,7 +9082,20 @@ var DocxEditor = class _DocxEditor {
|
|
|
8741
9082
|
this.editRoot.querySelector(`section.${sectionClass}`)?.remove();
|
|
8742
9083
|
return;
|
|
8743
9084
|
}
|
|
8744
|
-
|
|
9085
|
+
let section = this.editRoot.querySelector(`:scope > section.${sectionClass}`);
|
|
9086
|
+
let ol = section?.querySelector(`:scope > ol`) ?? null;
|
|
9087
|
+
if (!ol) {
|
|
9088
|
+
if (!section) {
|
|
9089
|
+
section = document.createElement("section");
|
|
9090
|
+
section.className = sectionClass;
|
|
9091
|
+
const following = sectionClass === "footnotes" ? this.editRoot.querySelector(`:scope > section.endnotes`) : null;
|
|
9092
|
+
if (following) following.before(section);
|
|
9093
|
+
else this.editRoot.append(section);
|
|
9094
|
+
}
|
|
9095
|
+
if (!section.querySelector(":scope > hr")) section.prepend(document.createElement("hr"));
|
|
9096
|
+
ol = document.createElement("ol");
|
|
9097
|
+
section.append(ol);
|
|
9098
|
+
}
|
|
8745
9099
|
const prefix = sectionClass === "footnotes" ? "fn" : "en";
|
|
8746
9100
|
const nodes = [];
|
|
8747
9101
|
for (let j = 0; j < units.length; j++) {
|
|
@@ -8922,6 +9276,7 @@ var RIBBON_CSS = `
|
|
|
8922
9276
|
color: var(--dxr-ink);
|
|
8923
9277
|
background: var(--dxr-desk);
|
|
8924
9278
|
-webkit-text-size-adjust: 100%;
|
|
9279
|
+
text-size-adjust: 100%;
|
|
8925
9280
|
}
|
|
8926
9281
|
.dxr *, .dxr *::before, .dxr *::after { box-sizing: border-box; }
|
|
8927
9282
|
|