docxodus 9.7.0 → 9.8.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 +290 -76
- 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 +290 -76
- package/dist/embed.iife.js +290 -76
- 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 +253 -68
- package/dist/pagination.d.ts +33 -8
- package/dist/pagination.d.ts.map +1 -1
- package/dist/pagination.js +198 -78
- package/dist/pagination.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.Linq.wasm +0 -0
- package/dist/wasm/_framework/System.Linq.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/dotnet.boot.js +6 -6
- package/dist/wasm/_framework/dotnet.boot.js.br +0 -0
- package/dist/wasm/_framework/dotnet.native.wasm +0 -0
- package/dist/wasm/_framework/dotnet.native.wasm.br +0 -0
- package/package.json +13 -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) {
|
|
@@ -1637,9 +1666,9 @@ var PaginationEngine = class {
|
|
|
1637
1666
|
*/
|
|
1638
1667
|
smallestEffectiveContentHeight(dims, sectionIndex) {
|
|
1639
1668
|
return Math.min(
|
|
1640
|
-
this.
|
|
1641
|
-
this.
|
|
1642
|
-
this.
|
|
1669
|
+
this.getPageBands(dims, sectionIndex, 1, 1).bodyHeight,
|
|
1670
|
+
this.getPageBands(dims, sectionIndex, 2, 1).bodyHeight,
|
|
1671
|
+
this.getPageBands(dims, sectionIndex, 2, 2).bodyHeight
|
|
1643
1672
|
);
|
|
1644
1673
|
}
|
|
1645
1674
|
/**
|
|
@@ -2163,7 +2192,7 @@ var PaginationEngine = class {
|
|
|
2163
2192
|
/**
|
|
2164
2193
|
* Adds footnotes to a page container, including continuation content.
|
|
2165
2194
|
*/
|
|
2166
|
-
addPageFootnotes(pageBox, footnoteIds, dims, footnoteHeight, continuation, partialFootnotes) {
|
|
2195
|
+
addPageFootnotes(pageBox, footnoteIds, dims, bands, footnoteHeight, continuation, partialFootnotes) {
|
|
2167
2196
|
const hasContinuation = continuation && continuation.remainingElements.length > 0;
|
|
2168
2197
|
if (footnoteIds.length === 0 && !hasContinuation) {
|
|
2169
2198
|
return;
|
|
@@ -2174,12 +2203,12 @@ var PaginationEngine = class {
|
|
|
2174
2203
|
const partialFootnoteIds = new Set(partialFootnotes?.map((p) => p.footnoteId) || []);
|
|
2175
2204
|
const maxFootnoteHeight = Math.min(
|
|
2176
2205
|
footnoteHeight,
|
|
2177
|
-
|
|
2206
|
+
bands.bodyHeight * MAX_FOOTNOTE_AREA_RATIO
|
|
2178
2207
|
);
|
|
2179
2208
|
const footnotesDiv = document.createElement("div");
|
|
2180
2209
|
footnotesDiv.className = `${this.cssPrefix}footnotes`;
|
|
2181
2210
|
footnotesDiv.style.position = "absolute";
|
|
2182
|
-
footnotesDiv.style.bottom = `${dims.
|
|
2211
|
+
footnotesDiv.style.bottom = `${dims.pageHeight - (bands.bodyTop + bands.bodyHeight)}pt`;
|
|
2183
2212
|
footnotesDiv.style.left = `${dims.marginLeft}pt`;
|
|
2184
2213
|
footnotesDiv.style.width = `${dims.contentWidth}pt`;
|
|
2185
2214
|
footnotesDiv.style.boxSizing = "border-box";
|
|
@@ -2253,50 +2282,51 @@ var PaginationEngine = class {
|
|
|
2253
2282
|
return sectionHf.footerDefault;
|
|
2254
2283
|
}
|
|
2255
2284
|
/**
|
|
2256
|
-
*
|
|
2257
|
-
*
|
|
2258
|
-
*
|
|
2259
|
-
*
|
|
2260
|
-
*
|
|
2285
|
+
* The header, body, and footer bands for one page position.
|
|
2286
|
+
*
|
|
2287
|
+
* The single owner of "where does anything sit vertically on this page" — placement in
|
|
2288
|
+
* {@link createPage}, the body budget the flow loop spends, and the note area's anchor all
|
|
2289
|
+
* read it, so those three cannot disagree about where the body ends.
|
|
2290
|
+
*
|
|
2291
|
+
* Deterministic: it depends only on the section's page setup and the registry's pre-measured
|
|
2292
|
+
* story heights, never on the page's content, which is what keeps it lazy-loading compatible.
|
|
2261
2293
|
*/
|
|
2262
|
-
|
|
2294
|
+
getPageBands(dims, sectionIndex, pageInSection, globalPageNumber) {
|
|
2263
2295
|
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 };
|
|
2296
|
+
return resolvePageBands(
|
|
2297
|
+
dims,
|
|
2298
|
+
this.selectStoryHeight(
|
|
2299
|
+
sectionHf?.headerFirstHeight,
|
|
2300
|
+
sectionHf?.headerEvenHeight,
|
|
2301
|
+
sectionHf?.headerDefaultHeight,
|
|
2302
|
+
pageInSection,
|
|
2303
|
+
globalPageNumber
|
|
2304
|
+
),
|
|
2305
|
+
this.selectStoryHeight(
|
|
2306
|
+
sectionHf?.footerFirstHeight,
|
|
2307
|
+
sectionHf?.footerEvenHeight,
|
|
2308
|
+
sectionHf?.footerDefaultHeight,
|
|
2309
|
+
pageInSection,
|
|
2310
|
+
globalPageNumber
|
|
2311
|
+
)
|
|
2312
|
+
);
|
|
2313
|
+
}
|
|
2314
|
+
/**
|
|
2315
|
+
* The measured height of the running story this page position selects, mirroring
|
|
2316
|
+
* {@link selectHeader}/{@link selectFooter}. Zero when the page has no such story.
|
|
2317
|
+
*/
|
|
2318
|
+
selectStoryHeight(first, even, fallback, pageInSection, globalPageNumber) {
|
|
2319
|
+
if (pageInSection === 1 && first != null) return first;
|
|
2320
|
+
if (globalPageNumber % 2 === 0 && even != null) return even;
|
|
2321
|
+
return fallback ?? 0;
|
|
2296
2322
|
}
|
|
2297
2323
|
/**
|
|
2298
2324
|
* Measures the content height of a header or footer element.
|
|
2299
|
-
*
|
|
2325
|
+
*
|
|
2326
|
+
* This is what tells {@link resolvePageBands} whether the story stays inside its margin or
|
|
2327
|
+
* pushes the body, so it must measure the story ALONE — any padding added here would have to
|
|
2328
|
+
* be added to the rendered band too, and the two drifting apart is exactly how a header
|
|
2329
|
+
* silently starts overlapping body text.
|
|
2300
2330
|
*/
|
|
2301
2331
|
measureHeaderFooterHeight(source, contentWidth) {
|
|
2302
2332
|
const measureContainer = document.createElement("div");
|
|
@@ -2304,7 +2334,6 @@ var PaginationEngine = class {
|
|
|
2304
2334
|
measureContainer.style.visibility = "hidden";
|
|
2305
2335
|
measureContainer.style.width = `${contentWidth}pt`;
|
|
2306
2336
|
measureContainer.style.left = "-9999px";
|
|
2307
|
-
measureContainer.style.paddingBottom = "4pt";
|
|
2308
2337
|
for (const child of Array.from(source.childNodes)) {
|
|
2309
2338
|
measureContainer.appendChild(child.cloneNode(true));
|
|
2310
2339
|
}
|
|
@@ -2324,7 +2353,7 @@ var PaginationEngine = class {
|
|
|
2324
2353
|
let currentContent = [];
|
|
2325
2354
|
let pageNumber = startPageNumber;
|
|
2326
2355
|
let pageInSection = 1;
|
|
2327
|
-
let {
|
|
2356
|
+
let { bodyHeight: effectiveContentHeight } = this.getPageBands(
|
|
2328
2357
|
dims,
|
|
2329
2358
|
sectionIndex,
|
|
2330
2359
|
pageInSection,
|
|
@@ -2359,8 +2388,8 @@ var PaginationEngine = class {
|
|
|
2359
2388
|
pageNumber++;
|
|
2360
2389
|
pageInSection++;
|
|
2361
2390
|
currentContent = [];
|
|
2362
|
-
const
|
|
2363
|
-
effectiveContentHeight =
|
|
2391
|
+
const newBands = this.getPageBands(dims, sectionIndex, pageInSection, pageNumber);
|
|
2392
|
+
effectiveContentHeight = newBands.bodyHeight;
|
|
2364
2393
|
remainingHeight = effectiveContentHeight;
|
|
2365
2394
|
prevMarginBottomPt = 0;
|
|
2366
2395
|
currentFootnoteIds = [];
|
|
@@ -2422,7 +2451,7 @@ var PaginationEngine = class {
|
|
|
2422
2451
|
) + additionalChainFootnoteHeight;
|
|
2423
2452
|
const currentAvailableHeight = remainingHeight - currentFootnoteHeight;
|
|
2424
2453
|
if (currentChainHeight > currentAvailableHeight) {
|
|
2425
|
-
const
|
|
2454
|
+
const nextPageBands = this.getPageBands(
|
|
2426
2455
|
dims,
|
|
2427
2456
|
sectionIndex,
|
|
2428
2457
|
pageInSection + 1,
|
|
@@ -2438,7 +2467,7 @@ var PaginationEngine = class {
|
|
|
2438
2467
|
dims.contentWidth,
|
|
2439
2468
|
nextPageContinuation
|
|
2440
2469
|
);
|
|
2441
|
-
if (freshChainBodyHeight + freshChainFootnoteHeight <=
|
|
2470
|
+
if (freshChainBodyHeight + freshChainFootnoteHeight <= nextPageBands.bodyHeight) {
|
|
2442
2471
|
finishPage();
|
|
2443
2472
|
}
|
|
2444
2473
|
}
|
|
@@ -2607,6 +2636,161 @@ var PaginationEngine = class {
|
|
|
2607
2636
|
if (el.getAttribute("contenteditable") !== null) el.setAttribute("contenteditable", "false");
|
|
2608
2637
|
}
|
|
2609
2638
|
}
|
|
2639
|
+
/**
|
|
2640
|
+
* Resolves floating DrawingML objects after their anchor paragraphs have landed on a page.
|
|
2641
|
+
*
|
|
2642
|
+
* The converter deliberately carries the OOXML bases and offsets as data instead of flattening
|
|
2643
|
+
* them into CSS: page/margin/column bases belong to the page, while paragraph/line/character
|
|
2644
|
+
* bases belong to the laid-out anchor. Once both coordinate systems exist, promote the object
|
|
2645
|
+
* from the clipped text column into the page box and position it in one shared point space.
|
|
2646
|
+
*/
|
|
2647
|
+
positionDrawingAnchors(pageBox, contentArea, dims, pageNumber) {
|
|
2648
|
+
const anchors = Array.from(
|
|
2649
|
+
contentArea.querySelectorAll('[data-docx-drawing-anchor="true"]')
|
|
2650
|
+
);
|
|
2651
|
+
if (anchors.length === 0) return;
|
|
2652
|
+
const pageRect = pageBox.getBoundingClientRect();
|
|
2653
|
+
const pixelsPerPoint = pageRect.width / dims.pageWidth;
|
|
2654
|
+
if (!(pixelsPerPoint > 0)) return;
|
|
2655
|
+
for (const anchor of anchors) {
|
|
2656
|
+
const staticRect = anchor.getBoundingClientRect();
|
|
2657
|
+
const paragraph = anchor.closest("p, h1, h2, h3, h4, h5, h6");
|
|
2658
|
+
const paragraphRect = paragraph?.getBoundingClientRect() ?? staticRect;
|
|
2659
|
+
const toPageX = (x) => (x - pageRect.left) / pixelsPerPoint;
|
|
2660
|
+
const toPageY = (y) => (y - pageRect.top) / pixelsPerPoint;
|
|
2661
|
+
const context = {
|
|
2662
|
+
staticLeft: toPageX(staticRect.left),
|
|
2663
|
+
staticTop: toPageY(staticRect.top),
|
|
2664
|
+
lineHeight: paragraph ? (parseFloat(getComputedStyle(paragraph).lineHeight) || staticRect.height) / pixelsPerPoint : staticRect.height / pixelsPerPoint,
|
|
2665
|
+
paragraphLeft: toPageX(paragraphRect.left),
|
|
2666
|
+
paragraphTop: toPageY(paragraphRect.top),
|
|
2667
|
+
paragraphWidth: paragraphRect.width / pixelsPerPoint,
|
|
2668
|
+
paragraphHeight: paragraphRect.height / pixelsPerPoint
|
|
2669
|
+
};
|
|
2670
|
+
const widthReference = this.horizontalAnchorReference(
|
|
2671
|
+
anchor.getAttribute("data-docx-anchor-width-relative") ?? "margin",
|
|
2672
|
+
dims,
|
|
2673
|
+
pageNumber,
|
|
2674
|
+
context
|
|
2675
|
+
);
|
|
2676
|
+
const widthPercent = this.anchorNumber(anchor, "width-percent");
|
|
2677
|
+
if (widthPercent !== void 0) {
|
|
2678
|
+
anchor.style.width = `${widthReference.size * widthPercent / 100}pt`;
|
|
2679
|
+
}
|
|
2680
|
+
const heightReference = this.verticalAnchorReference(
|
|
2681
|
+
anchor.getAttribute("data-docx-anchor-height-relative") ?? "margin",
|
|
2682
|
+
dims,
|
|
2683
|
+
pageNumber,
|
|
2684
|
+
context
|
|
2685
|
+
);
|
|
2686
|
+
const heightPercent = this.anchorNumber(anchor, "height-percent");
|
|
2687
|
+
if (heightPercent !== void 0 && anchor.dataset.docxAnchorAutofit !== "true") {
|
|
2688
|
+
anchor.style.height = `${heightReference.size * heightPercent / 100}pt`;
|
|
2689
|
+
}
|
|
2690
|
+
const sizedRect = anchor.getBoundingClientRect();
|
|
2691
|
+
const width = sizedRect.width / pixelsPerPoint;
|
|
2692
|
+
const height = sizedRect.height / pixelsPerPoint;
|
|
2693
|
+
const horizontal2 = this.horizontalAnchorReference(
|
|
2694
|
+
anchor.getAttribute("data-docx-anchor-h-relative") ?? "column",
|
|
2695
|
+
dims,
|
|
2696
|
+
pageNumber,
|
|
2697
|
+
context
|
|
2698
|
+
);
|
|
2699
|
+
const vertical2 = this.verticalAnchorReference(
|
|
2700
|
+
anchor.getAttribute("data-docx-anchor-v-relative") ?? "paragraph",
|
|
2701
|
+
dims,
|
|
2702
|
+
pageNumber,
|
|
2703
|
+
context
|
|
2704
|
+
);
|
|
2705
|
+
const left2 = this.resolveAnchorAxis(
|
|
2706
|
+
horizontal2,
|
|
2707
|
+
width,
|
|
2708
|
+
anchor.getAttribute("data-docx-anchor-h-align"),
|
|
2709
|
+
this.anchorNumber(anchor, "h-offset"),
|
|
2710
|
+
pageNumber
|
|
2711
|
+
);
|
|
2712
|
+
const top2 = this.resolveAnchorAxis(
|
|
2713
|
+
vertical2,
|
|
2714
|
+
height,
|
|
2715
|
+
anchor.getAttribute("data-docx-anchor-v-align"),
|
|
2716
|
+
this.anchorNumber(anchor, "v-offset"),
|
|
2717
|
+
pageNumber
|
|
2718
|
+
);
|
|
2719
|
+
pageBox.appendChild(anchor);
|
|
2720
|
+
anchor.style.position = "absolute";
|
|
2721
|
+
anchor.style.left = `${left2}pt`;
|
|
2722
|
+
anchor.style.top = `${top2}pt`;
|
|
2723
|
+
anchor.style.margin = "0";
|
|
2724
|
+
}
|
|
2725
|
+
}
|
|
2726
|
+
anchorNumber(anchor, suffix) {
|
|
2727
|
+
const raw = anchor.getAttribute(`data-docx-anchor-${suffix}`);
|
|
2728
|
+
if (raw === null) return void 0;
|
|
2729
|
+
const value = Number(raw);
|
|
2730
|
+
return Number.isFinite(value) ? value : void 0;
|
|
2731
|
+
}
|
|
2732
|
+
horizontalAnchorReference(relativeFrom, dims, pageNumber, context) {
|
|
2733
|
+
const leftMargin = { start: 0, size: dims.marginLeft };
|
|
2734
|
+
const rightMargin = {
|
|
2735
|
+
start: dims.marginLeft + dims.contentWidth,
|
|
2736
|
+
size: dims.marginRight
|
|
2737
|
+
};
|
|
2738
|
+
switch (relativeFrom) {
|
|
2739
|
+
case "page":
|
|
2740
|
+
return { start: 0, size: dims.pageWidth };
|
|
2741
|
+
case "character":
|
|
2742
|
+
return { start: context.staticLeft, size: 0 };
|
|
2743
|
+
case "leftMargin":
|
|
2744
|
+
return leftMargin;
|
|
2745
|
+
case "rightMargin":
|
|
2746
|
+
return rightMargin;
|
|
2747
|
+
case "insideMargin":
|
|
2748
|
+
return pageNumber % 2 === 1 ? leftMargin : rightMargin;
|
|
2749
|
+
case "outsideMargin":
|
|
2750
|
+
return pageNumber % 2 === 1 ? rightMargin : leftMargin;
|
|
2751
|
+
case "paragraph":
|
|
2752
|
+
return { start: context.paragraphLeft, size: context.paragraphWidth };
|
|
2753
|
+
case "column":
|
|
2754
|
+
case "margin":
|
|
2755
|
+
default:
|
|
2756
|
+
return { start: dims.marginLeft, size: dims.contentWidth };
|
|
2757
|
+
}
|
|
2758
|
+
}
|
|
2759
|
+
verticalAnchorReference(relativeFrom, dims, pageNumber, context) {
|
|
2760
|
+
const topMargin = { start: 0, size: dims.marginTop };
|
|
2761
|
+
const bottomMargin = {
|
|
2762
|
+
start: dims.marginTop + dims.contentHeight,
|
|
2763
|
+
size: dims.marginBottom
|
|
2764
|
+
};
|
|
2765
|
+
switch (relativeFrom) {
|
|
2766
|
+
case "page":
|
|
2767
|
+
return { start: 0, size: dims.pageHeight };
|
|
2768
|
+
case "paragraph":
|
|
2769
|
+
return { start: context.paragraphTop, size: context.paragraphHeight };
|
|
2770
|
+
case "line":
|
|
2771
|
+
return { start: context.staticTop, size: context.lineHeight };
|
|
2772
|
+
case "topMargin":
|
|
2773
|
+
return topMargin;
|
|
2774
|
+
case "bottomMargin":
|
|
2775
|
+
return bottomMargin;
|
|
2776
|
+
case "insideMargin":
|
|
2777
|
+
return pageNumber % 2 === 1 ? topMargin : bottomMargin;
|
|
2778
|
+
case "outsideMargin":
|
|
2779
|
+
return pageNumber % 2 === 1 ? bottomMargin : topMargin;
|
|
2780
|
+
case "margin":
|
|
2781
|
+
default:
|
|
2782
|
+
return { start: dims.marginTop, size: dims.contentHeight };
|
|
2783
|
+
}
|
|
2784
|
+
}
|
|
2785
|
+
resolveAnchorAxis(reference, objectSize, alignment, offset, pageNumber) {
|
|
2786
|
+
if (offset !== void 0) return reference.start + offset;
|
|
2787
|
+
let fraction = 0;
|
|
2788
|
+
if (alignment === "center") fraction = 0.5;
|
|
2789
|
+
else if (alignment === "right" || alignment === "bottom") fraction = 1;
|
|
2790
|
+
else if (alignment === "inside") fraction = pageNumber % 2 === 1 ? 0 : 1;
|
|
2791
|
+
else if (alignment === "outside") fraction = pageNumber % 2 === 1 ? 1 : 0;
|
|
2792
|
+
return reference.start + (reference.size - objectSize) * fraction;
|
|
2793
|
+
}
|
|
2610
2794
|
/**
|
|
2611
2795
|
* Creates a page container element.
|
|
2612
2796
|
*/
|
|
@@ -2633,22 +2817,22 @@ var PaginationEngine = class {
|
|
|
2633
2817
|
pageBox.dataset.pageNumber = String(pageNumber);
|
|
2634
2818
|
pageBox.dataset.sectionIndex = String(sectionIndex);
|
|
2635
2819
|
pageBox.dataset.pageInSection = String(pageInSection);
|
|
2636
|
-
const
|
|
2820
|
+
const bands = this.getPageBands(dims, sectionIndex, pageInSection, pageNumber);
|
|
2637
2821
|
const headerSource = this.selectHeader(sectionIndex, pageInSection, pageNumber);
|
|
2638
2822
|
if (headerSource) {
|
|
2639
2823
|
const headerDiv = document.createElement("div");
|
|
2640
2824
|
headerDiv.className = `${this.cssPrefix}header`;
|
|
2641
2825
|
headerDiv.style.position = "absolute";
|
|
2642
|
-
headerDiv.style.top =
|
|
2826
|
+
headerDiv.style.top = `${bands.headerTop}pt`;
|
|
2827
|
+
headerDiv.style.bottom = "auto";
|
|
2643
2828
|
headerDiv.style.left = `${dims.marginLeft}pt`;
|
|
2644
2829
|
headerDiv.style.width = `${dims.contentWidth}pt`;
|
|
2645
|
-
headerDiv.style.height = `${
|
|
2830
|
+
headerDiv.style.height = `${bands.headerHeight}pt`;
|
|
2646
2831
|
headerDiv.style.overflow = "hidden";
|
|
2647
2832
|
headerDiv.style.boxSizing = "border-box";
|
|
2648
2833
|
headerDiv.style.display = "flex";
|
|
2649
2834
|
headerDiv.style.flexDirection = "column";
|
|
2650
|
-
headerDiv.style.justifyContent = "flex-
|
|
2651
|
-
headerDiv.style.paddingBottom = "4pt";
|
|
2835
|
+
headerDiv.style.justifyContent = "flex-start";
|
|
2652
2836
|
for (const child of Array.from(headerSource.childNodes)) {
|
|
2653
2837
|
const clonedheaderDiv = child.cloneNode(true);
|
|
2654
2838
|
if (clonedheaderDiv.nodeType === 1) this.makeClonedStoryInert(clonedheaderDiv);
|
|
@@ -2656,8 +2840,8 @@ var PaginationEngine = class {
|
|
|
2656
2840
|
}
|
|
2657
2841
|
pageBox.appendChild(headerDiv);
|
|
2658
2842
|
}
|
|
2659
|
-
const contentAreaTop =
|
|
2660
|
-
const contentAreaHeight =
|
|
2843
|
+
const contentAreaTop = bands.bodyTop;
|
|
2844
|
+
const contentAreaHeight = bands.bodyHeight;
|
|
2661
2845
|
const contentArea = document.createElement("div");
|
|
2662
2846
|
contentArea.className = `${this.cssPrefix}content`;
|
|
2663
2847
|
contentArea.style.position = "absolute";
|
|
@@ -2672,23 +2856,23 @@ var PaginationEngine = class {
|
|
|
2672
2856
|
pageBox.appendChild(contentArea);
|
|
2673
2857
|
const hasContinuation = continuation && continuation.remainingElements.length > 0;
|
|
2674
2858
|
if (footnoteIds.length > 0 || hasContinuation) {
|
|
2675
|
-
this.addPageFootnotes(pageBox, footnoteIds, dims, footnoteHeight, continuation, partialFootnotes);
|
|
2859
|
+
this.addPageFootnotes(pageBox, footnoteIds, dims, bands, footnoteHeight, continuation, partialFootnotes);
|
|
2676
2860
|
}
|
|
2677
2861
|
const footerSource = this.selectFooter(sectionIndex, pageInSection, pageNumber);
|
|
2678
2862
|
if (footerSource) {
|
|
2679
2863
|
const footerDiv = document.createElement("div");
|
|
2680
2864
|
footerDiv.className = `${this.cssPrefix}footer`;
|
|
2681
2865
|
footerDiv.style.position = "absolute";
|
|
2682
|
-
footerDiv.style.
|
|
2866
|
+
footerDiv.style.top = "auto";
|
|
2867
|
+
footerDiv.style.bottom = `${dims.footerDistance}pt`;
|
|
2683
2868
|
footerDiv.style.left = `${dims.marginLeft}pt`;
|
|
2684
2869
|
footerDiv.style.width = `${dims.contentWidth}pt`;
|
|
2685
|
-
footerDiv.style.height = `${
|
|
2870
|
+
footerDiv.style.height = `${bands.footerHeight}pt`;
|
|
2686
2871
|
footerDiv.style.overflow = "hidden";
|
|
2687
2872
|
footerDiv.style.boxSizing = "border-box";
|
|
2688
2873
|
footerDiv.style.display = "flex";
|
|
2689
2874
|
footerDiv.style.flexDirection = "column";
|
|
2690
|
-
footerDiv.style.justifyContent = "flex-
|
|
2691
|
-
footerDiv.style.paddingTop = "4pt";
|
|
2875
|
+
footerDiv.style.justifyContent = "flex-end";
|
|
2692
2876
|
for (const child of Array.from(footerSource.childNodes)) {
|
|
2693
2877
|
const clonedfooterDiv = child.cloneNode(true);
|
|
2694
2878
|
if (clonedfooterDiv.nodeType === 1) this.makeClonedStoryInert(clonedfooterDiv);
|
|
@@ -2703,6 +2887,7 @@ var PaginationEngine = class {
|
|
|
2703
2887
|
pageBox.appendChild(pageNum);
|
|
2704
2888
|
}
|
|
2705
2889
|
this.containerElement.appendChild(pageBox);
|
|
2890
|
+
this.positionDrawingAnchors(pageBox, contentArea, dims, pageNumber);
|
|
2706
2891
|
const notesEl = pageBox.querySelector(`.${this.cssPrefix}footnotes`);
|
|
2707
2892
|
if (notesEl) {
|
|
2708
2893
|
const notesHeightPt = pxToPt(notesEl.getBoundingClientRect().height);
|
|
@@ -6077,6 +6262,19 @@ function serializeInlineMarkdown(block) {
|
|
|
6077
6262
|
function isListBlock(block) {
|
|
6078
6263
|
return !!block.querySelector(":scope > [data-list-marker]");
|
|
6079
6264
|
}
|
|
6265
|
+
function ensureListMarkerSeparator(block) {
|
|
6266
|
+
const marker = block.querySelector(":scope > [data-list-marker]");
|
|
6267
|
+
if (!marker) return;
|
|
6268
|
+
const next = marker.nextElementSibling;
|
|
6269
|
+
if (next?.hasAttribute("data-editor-list-separator")) return;
|
|
6270
|
+
const separator = block.ownerDocument.createElement("span");
|
|
6271
|
+
separator.setAttribute("data-editor-list-separator", "");
|
|
6272
|
+
separator.setAttribute("data-list-marker", "true");
|
|
6273
|
+
separator.setAttribute("aria-hidden", "true");
|
|
6274
|
+
separator.style.display = "none";
|
|
6275
|
+
separator.textContent = " ";
|
|
6276
|
+
marker.after(separator);
|
|
6277
|
+
}
|
|
6080
6278
|
var GENERATED_CHROME_SELECTOR = '[data-list-marker], a.footnote-ref, a.endnote-ref, a[class$="-backref"]';
|
|
6081
6279
|
function isGeneratedChrome(node) {
|
|
6082
6280
|
return node?.nodeType === 1 && !!node.matches?.(GENERATED_CHROME_SELECTOR);
|
|
@@ -7367,6 +7565,7 @@ var DocxEditor = class _DocxEditor {
|
|
|
7367
7565
|
const unid = el.getAttribute("data-anchor");
|
|
7368
7566
|
if (!unid || !this.anchorIdOf(el)) return;
|
|
7369
7567
|
el.setAttribute("contenteditable", "true");
|
|
7568
|
+
ensureListMarkerSeparator(el);
|
|
7370
7569
|
el.querySelectorAll(GENERATED_CHROME_SELECTOR).forEach((m) => m.setAttribute("contenteditable", "false"));
|
|
7371
7570
|
el.dataset.committedText = blockContentText(el);
|
|
7372
7571
|
el.addEventListener("focus", () => {
|
|
@@ -8229,8 +8428,8 @@ var DocxEditor = class _DocxEditor {
|
|
|
8229
8428
|
* editable `data-anchor` blocks in the notes section, so editing it afterwards needs no new op.
|
|
8230
8429
|
*
|
|
8231
8430
|
* 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
|
-
*
|
|
8431
|
+
* another note, and the session rejects those with `AnchorWrongKind`. Reconciliation creates
|
|
8432
|
+
* the first notes section when needed and renumbers every affected citation in place.
|
|
8234
8433
|
*/
|
|
8235
8434
|
insertFootnote(markdown = "New footnote.") {
|
|
8236
8435
|
this.insertNote("footnote", markdown);
|
|
@@ -8622,7 +8821,7 @@ var DocxEditor = class _DocxEditor {
|
|
|
8622
8821
|
* the current node — never a section div (multi-child) or the edit root. */
|
|
8623
8822
|
unitWrapperOf(el) {
|
|
8624
8823
|
let n = el;
|
|
8625
|
-
while (n.parentElement && n.parentElement !== this.editRoot && n.parentElement.tagName === "DIV" && !n.parentElement.hasAttribute("data-anchor") && n.parentElement.childElementCount === 1) {
|
|
8824
|
+
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
8825
|
n = n.parentElement;
|
|
8627
8826
|
}
|
|
8628
8827
|
return n;
|
|
@@ -8658,6 +8857,7 @@ var DocxEditor = class _DocxEditor {
|
|
|
8658
8857
|
const pureRemoved = diff.removed.filter(
|
|
8659
8858
|
(i) => !diff.substituted.some((s) => s.oldIndex === i) && !movedOld.has(i)
|
|
8660
8859
|
);
|
|
8860
|
+
const appliedFresh = /* @__PURE__ */ new Set();
|
|
8661
8861
|
const nodeAt = (j) => {
|
|
8662
8862
|
const oi = diff.keep.get(j);
|
|
8663
8863
|
if (oi !== void 0) return oldNodes[oi];
|
|
@@ -8665,7 +8865,7 @@ var DocxEditor = class _DocxEditor {
|
|
|
8665
8865
|
if (movedOi !== void 0) return oldNodes[movedOi];
|
|
8666
8866
|
if (subOldByNew.has(j)) return fresh.get(j);
|
|
8667
8867
|
const f = fresh.get(j);
|
|
8668
|
-
return f &&
|
|
8868
|
+
return f && appliedFresh.has(j) ? f : null;
|
|
8669
8869
|
};
|
|
8670
8870
|
for (const j of pureAdded) {
|
|
8671
8871
|
const el = fresh.get(j);
|
|
@@ -8680,6 +8880,7 @@ var DocxEditor = class _DocxEditor {
|
|
|
8680
8880
|
if (prevW) prevW.after(el);
|
|
8681
8881
|
else if (nextW) nextW.before(el);
|
|
8682
8882
|
else return "insert with no anchored neighbor";
|
|
8883
|
+
appliedFresh.add(j);
|
|
8683
8884
|
this.wireUnit(el, units[j]);
|
|
8684
8885
|
}
|
|
8685
8886
|
for (const i of pureRemoved) {
|
|
@@ -8718,13 +8919,13 @@ var DocxEditor = class _DocxEditor {
|
|
|
8718
8919
|
if (anchorEl) this.wireBlock(anchorEl);
|
|
8719
8920
|
root.querySelectorAll("[data-anchor]").forEach((b) => this.wireBlock(b));
|
|
8720
8921
|
}
|
|
8721
|
-
/** Old-sequence diff state for one notes section. `null` requests remount
|
|
8722
|
-
* stampable
|
|
8922
|
+
/** Old-sequence diff state for one notes section. `null` requests remount when an
|
|
8923
|
+
* existing list is not stampable; an absent list is the valid first-note case. */
|
|
8723
8924
|
notesDiff(sectionClass, units) {
|
|
8724
8925
|
const ol = this.editRoot.querySelector(`section.${sectionClass} > ol`);
|
|
8725
8926
|
const lis = ol ? Array.from(ol.children).filter((c) => c.tagName === "LI") : [];
|
|
8726
8927
|
if (units.length === 0 && lis.length === 0) return { lis, diff: diffUnits([], []) };
|
|
8727
|
-
if (!ol) return
|
|
8928
|
+
if (!ol) return { lis, diff: diffUnits([], units) };
|
|
8728
8929
|
const tokens = [];
|
|
8729
8930
|
for (const li of lis) {
|
|
8730
8931
|
const unid = li.getAttribute("data-note-anchor");
|
|
@@ -8741,7 +8942,20 @@ var DocxEditor = class _DocxEditor {
|
|
|
8741
8942
|
this.editRoot.querySelector(`section.${sectionClass}`)?.remove();
|
|
8742
8943
|
return;
|
|
8743
8944
|
}
|
|
8744
|
-
|
|
8945
|
+
let section = this.editRoot.querySelector(`:scope > section.${sectionClass}`);
|
|
8946
|
+
let ol = section?.querySelector(`:scope > ol`) ?? null;
|
|
8947
|
+
if (!ol) {
|
|
8948
|
+
if (!section) {
|
|
8949
|
+
section = document.createElement("section");
|
|
8950
|
+
section.className = sectionClass;
|
|
8951
|
+
const following = sectionClass === "footnotes" ? this.editRoot.querySelector(`:scope > section.endnotes`) : null;
|
|
8952
|
+
if (following) following.before(section);
|
|
8953
|
+
else this.editRoot.append(section);
|
|
8954
|
+
}
|
|
8955
|
+
if (!section.querySelector(":scope > hr")) section.prepend(document.createElement("hr"));
|
|
8956
|
+
ol = document.createElement("ol");
|
|
8957
|
+
section.append(ol);
|
|
8958
|
+
}
|
|
8745
8959
|
const prefix = sectionClass === "footnotes" ? "fn" : "en";
|
|
8746
8960
|
const nodes = [];
|
|
8747
8961
|
for (let j = 0; j < units.length; j++) {
|