gutterpress 0.11.23-beta.1 → 0.11.23-beta.2
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/README.md +1 -1
- package/dist/api/index.js +5 -5
- package/dist/{build-dg8a566j.js → build-3e18wnqj.js} +8 -8
- package/dist/{cli-vhav8g82.js → cli-0ep11b0q.js} +1 -1
- package/dist/{cli-e31jshz6.js → cli-88arpdke.js} +2 -2
- package/dist/{cli-1fy1pm9d.js → cli-9n9kg58f.js} +1 -1
- package/dist/{cli-k087gj0p.js → cli-pd2cje5b.js} +122 -11
- package/dist/{cli-989eg8jz.js → cli-pnrararp.js} +11 -10
- package/dist/{cli-ttj95aex.js → cli-tgnyvra3.js} +13 -3
- package/dist/{cli-31anr0r9.js → cli-v0evdpdf.js} +68 -28
- package/dist/{cli-s1zt779w.js → cli-x7gcdg6w.js} +1 -1
- package/dist/cli.js +12 -12
- package/dist/{doctor-g4a42tcz.js → doctor-2f4s9dyn.js} +3 -3
- package/dist/engine/compiler/postprocess.d.ts +3 -0
- package/dist/engine/shared/pdf-inspect.d.ts +33 -0
- package/dist/{engine-jvkcahr1.js → engine-c4pxz79g.js} +1 -1
- package/dist/{engine-wgkaqjsc.js → engine-cs5g2ez0.js} +2 -2
- package/dist/{ext-w9d5ftcg.js → ext-70gv86v5.js} +8 -8
- package/dist/{extension-restore-5x4mj79d.js → extension-restore-chj5nx3t.js} +2 -2
- package/dist/{extension-restore-as0g38p1.js → extension-restore-pd87p8r2.js} +4 -4
- package/dist/{gutterpress-agent-d29ry3ak.js → gutterpress-agent-wyryqehx.js} +13 -4
- package/dist/{gutterpress-viewer-ze691rrd.js → gutterpress-viewer-ywkf49q5.js} +38 -153
- package/dist/{index-c6y0p7jy.js → index-0k43evt0.js} +66 -22
- package/dist/{index-fk2kpf2t.js → index-2t1gdma7.js} +121 -10
- package/dist/{index-cw03e9p4.js → index-7j3hkwya.js} +68 -28
- package/dist/{index-a4j3xcfp.js → index-80vg3ed6.js} +13 -3
- package/dist/{index-798jt0qc.js → index-swfdgn2n.js} +2 -2
- package/dist/{index-rj5vrhz6.js → index-ytjkvwy5.js} +1 -1
- package/dist/index.js +6 -6
- package/dist/lib/markdown/gutterpress-css.d.ts +1 -1
- package/dist/lib/source-provider.d.ts +27 -0
- package/dist/lib/version-changes.d.ts +14 -4
- package/dist/{new-jtk028rf.js → new-d61n5cn0.js} +8 -8
- package/dist/{plugins-bcbe7xs8.js → plugins-0hhw6s17.js} +1 -1
- package/dist/{plugins-zsm6wv79.js → plugins-e0n46s6m.js} +3 -3
- package/dist/{preflight-cs6mj1d6.js → preflight-fjayhjr5.js} +8 -8
- package/dist/{preview-d1j1g4qf.js → preview-h815jrfb.js} +8 -8
- package/dist/{publish-7yw4jyrt.js → publish-ft39zgma.js} +8 -8
- package/dist/render.js +12 -2
- package/dist/{source-provider-n7vehh6t.js → source-provider-j1w7byeq.js} +5 -1
- package/dist/{source-provider-tgzet3j5.js → source-provider-tjaf303m.js} +5 -1
- package/dist/test-helpers/vocabulary.d.ts +12 -0
- package/dist/{validate-rkcdnzhw.js → validate-b201dbrb.js} +8 -8
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -8,7 +8,7 @@ import {
|
|
|
8
8
|
} from "./cli-d8xjns66.js";
|
|
9
9
|
import {
|
|
10
10
|
package_default
|
|
11
|
-
} from "./cli-
|
|
11
|
+
} from "./cli-x7gcdg6w.js";
|
|
12
12
|
import {
|
|
13
13
|
EXIT_CODES
|
|
14
14
|
} from "./cli-46ycxe6r.js";
|
|
@@ -20,14 +20,14 @@ import {
|
|
|
20
20
|
import { defineCommand, parseArgs, runMain } from "citty";
|
|
21
21
|
import { statSync } from "node:fs";
|
|
22
22
|
var SUBCOMMANDS = {
|
|
23
|
-
new: () => import("./new-
|
|
24
|
-
preview: () => import("./preview-
|
|
25
|
-
build: () => import("./build-
|
|
26
|
-
publish: () => import("./publish-
|
|
27
|
-
validate: () => import("./validate-
|
|
28
|
-
preflight: () => import("./preflight-
|
|
29
|
-
doctor: () => import("./doctor-
|
|
30
|
-
ext: () => import("./ext-
|
|
23
|
+
new: () => import("./new-d61n5cn0.js").then((m) => m.default),
|
|
24
|
+
preview: () => import("./preview-h815jrfb.js").then((m) => m.default),
|
|
25
|
+
build: () => import("./build-3e18wnqj.js").then((m) => m.default),
|
|
26
|
+
publish: () => import("./publish-ft39zgma.js").then((m) => m.default),
|
|
27
|
+
validate: () => import("./validate-b201dbrb.js").then((m) => m.default),
|
|
28
|
+
preflight: () => import("./preflight-fjayhjr5.js").then((m) => m.default),
|
|
29
|
+
doctor: () => import("./doctor-2f4s9dyn.js").then((m) => m.default),
|
|
30
|
+
ext: () => import("./ext-70gv86v5.js").then((m) => m.default)
|
|
31
31
|
};
|
|
32
32
|
var VERSION = package_default.version;
|
|
33
33
|
var main = defineCommand({
|
|
@@ -52,7 +52,7 @@ async function preflightRequiredInvocations(rawArgs) {
|
|
|
52
52
|
const [command, ...commandArgs] = rawArgs;
|
|
53
53
|
try {
|
|
54
54
|
if (command === "new") {
|
|
55
|
-
const { newArgs } = await import("./new-
|
|
55
|
+
const { newArgs } = await import("./new-d61n5cn0.js");
|
|
56
56
|
rejectUnknownFlags(commandArgs, newArgs, "new");
|
|
57
57
|
const parsed = parseArgs(commandArgs, {
|
|
58
58
|
...newArgs,
|
|
@@ -64,7 +64,7 @@ async function preflightRequiredInvocations(rawArgs) {
|
|
|
64
64
|
return;
|
|
65
65
|
}
|
|
66
66
|
if (command === "preflight") {
|
|
67
|
-
const { preflightArgs } = await import("./preflight-
|
|
67
|
+
const { preflightArgs } = await import("./preflight-fjayhjr5.js");
|
|
68
68
|
rejectUnknownFlags(commandArgs, preflightArgs, "preflight");
|
|
69
69
|
const parsed = parseArgs(commandArgs, {
|
|
70
70
|
...preflightArgs,
|
|
@@ -84,7 +84,7 @@ async function preflightRequiredInvocations(rawArgs) {
|
|
|
84
84
|
}
|
|
85
85
|
if (subcommand.startsWith("-"))
|
|
86
86
|
return;
|
|
87
|
-
const { EXT_SUBCOMMANDS, extAddArgs, extRemoveArgs, extEnableArgs, extDisableArgs } = await import("./ext-
|
|
87
|
+
const { EXT_SUBCOMMANDS, extAddArgs, extRemoveArgs, extEnableArgs, extDisableArgs } = await import("./ext-70gv86v5.js");
|
|
88
88
|
if (!EXT_SUBCOMMANDS.includes(subcommand)) {
|
|
89
89
|
throw new UsageError(`gutterpress ext: unknown command "${subcommand}"`);
|
|
90
90
|
}
|
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
import {
|
|
2
2
|
getSystemDiagnostics
|
|
3
|
-
} from "./cli-
|
|
3
|
+
} from "./cli-0ep11b0q.js";
|
|
4
4
|
import"./cli-5crpmz42.js";
|
|
5
5
|
import"./cli-asap4t1z.js";
|
|
6
6
|
import {
|
|
7
7
|
log
|
|
8
|
-
} from "./cli-
|
|
8
|
+
} from "./cli-9n9kg58f.js";
|
|
9
9
|
import {
|
|
10
10
|
UsageError,
|
|
11
11
|
rejectExtraPositionals,
|
|
12
12
|
rejectUnknownFlags
|
|
13
13
|
} from "./cli-d8xjns66.js";
|
|
14
|
-
import"./cli-
|
|
14
|
+
import"./cli-x7gcdg6w.js";
|
|
15
15
|
import"./cli-46ycxe6r.js";
|
|
16
16
|
import"./cli-37x76zdn.js";
|
|
17
17
|
|
|
@@ -27,5 +27,8 @@ export interface PostprocessResult {
|
|
|
27
27
|
bleed: number[];
|
|
28
28
|
trim: number[];
|
|
29
29
|
};
|
|
30
|
+
/** The scale Chromium printed at, read before anything here draws:
|
|
31
|
+
* `printScale` in shared/pdf-inspect.ts (1 = not shrunk). */
|
|
32
|
+
scale: number | null;
|
|
30
33
|
}
|
|
31
34
|
export declare function postprocess(input: Uint8Array, opts: PostprocessOptions): Promise<PostprocessResult>;
|
|
@@ -1,3 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Read-side PDF utilities (pdf-lib, pure JS).
|
|
3
|
+
*
|
|
4
|
+
* Three jobs:
|
|
5
|
+
* 1. Verification: page count, page boxes, embedded fonts — the evidence the
|
|
6
|
+
* tests assert on.
|
|
7
|
+
* 2. Tier 3 measurement channel (§8): harvest Chromium's own link annotations
|
|
8
|
+
* and document outline to learn "which page is element X on", with no text
|
|
9
|
+
* heuristics.
|
|
10
|
+
* 3. The print scale: whether Chromium's shrink-to-fit scaled the page area
|
|
11
|
+
* ({@link printScale}).
|
|
12
|
+
*/
|
|
13
|
+
import { PDFDocument } from "pdf-lib";
|
|
1
14
|
export interface PageBoxes {
|
|
2
15
|
media: number[];
|
|
3
16
|
crop?: number[];
|
|
@@ -18,3 +31,23 @@ export interface PdfFacts {
|
|
|
18
31
|
}>;
|
|
19
32
|
}
|
|
20
33
|
export declare function inspectPdf(bytes: Uint8Array): Promise<PdfFacts>;
|
|
34
|
+
/**
|
|
35
|
+
* The scale Chromium printed the page area at: 1 when it laid the document
|
|
36
|
+
* out at the page content box's own width, below 1 when print shrink-to-fit
|
|
37
|
+
* scaled the whole document down because something reached past that box
|
|
38
|
+
* (ENGINE.md §9). `null` when no page shows the transform — a reader that
|
|
39
|
+
* cannot find it makes no claim. Pass Chromium's own print, before anything
|
|
40
|
+
* redraws its pages.
|
|
41
|
+
*
|
|
42
|
+
* Read off the content streams rather than predicted from element widths.
|
|
43
|
+
* Each page draws its page box (background, margin boxes) under an unscaled
|
|
44
|
+
* `3.125 0 0 3.125 0 0 cm` — CSS px to 300-per-inch device units — then clips
|
|
45
|
+
* to the page area, its largest clip, and draws the page area's content
|
|
46
|
+
* under `s 0 0 s x y cm`, where x is the clip's own left edge and s is 3.125
|
|
47
|
+
* times the shrink. An element with a CSS transform or its own clip draws
|
|
48
|
+
* under other matrices, so one page can read wrong; Chromium applies one
|
|
49
|
+
* factor to the whole document, so the first reading three pages agree on
|
|
50
|
+
* (or the most common, in a shorter document) is the answer. The prologue
|
|
51
|
+
* fixes the device resolution: the scale is s × prologue × 96/72.
|
|
52
|
+
*/
|
|
53
|
+
export declare function printScale(doc: PDFDocument): number | null;
|
|
@@ -2,14 +2,14 @@ import {
|
|
|
2
2
|
importExtensionFromFile,
|
|
3
3
|
importExtensionFromUrl,
|
|
4
4
|
searchNpmExtensions
|
|
5
|
-
} from "./cli-
|
|
6
|
-
import"./cli-
|
|
5
|
+
} from "./cli-pnrararp.js";
|
|
6
|
+
import"./cli-0ep11b0q.js";
|
|
7
7
|
import"./cli-ht1bcqdd.js";
|
|
8
|
-
import"./cli-
|
|
8
|
+
import"./cli-pd2cje5b.js";
|
|
9
9
|
import"./cli-5crpmz42.js";
|
|
10
10
|
import"./cli-eyyggect.js";
|
|
11
11
|
import"./cli-asap4t1z.js";
|
|
12
|
-
import"./cli-
|
|
12
|
+
import"./cli-v0evdpdf.js";
|
|
13
13
|
import"./cli-v5mp7a6q.js";
|
|
14
14
|
import {
|
|
15
15
|
addExtension,
|
|
@@ -18,12 +18,12 @@ import {
|
|
|
18
18
|
removeExtension,
|
|
19
19
|
setExtensionEnabled,
|
|
20
20
|
updateExtensions
|
|
21
|
-
} from "./cli-
|
|
21
|
+
} from "./cli-88arpdke.js";
|
|
22
22
|
import {
|
|
23
23
|
isPathSpecifier,
|
|
24
24
|
parseExtensionSpecifier
|
|
25
|
-
} from "./cli-
|
|
26
|
-
import"./cli-
|
|
25
|
+
} from "./cli-tgnyvra3.js";
|
|
26
|
+
import"./cli-9n9kg58f.js";
|
|
27
27
|
import {
|
|
28
28
|
UsageError,
|
|
29
29
|
exitForUsage,
|
|
@@ -31,7 +31,7 @@ import {
|
|
|
31
31
|
rejectUnknownFlags,
|
|
32
32
|
resolveProjectDir
|
|
33
33
|
} from "./cli-d8xjns66.js";
|
|
34
|
-
import"./cli-
|
|
34
|
+
import"./cli-x7gcdg6w.js";
|
|
35
35
|
import"./cli-65gy8ask.js";
|
|
36
36
|
import {
|
|
37
37
|
EXIT_CODES
|
|
@@ -3,8 +3,8 @@ import {
|
|
|
3
3
|
restoreForCommand,
|
|
4
4
|
restoreOfflineMessage,
|
|
5
5
|
restorePinnedExtensions
|
|
6
|
-
} from "./index-
|
|
7
|
-
import"./index-
|
|
6
|
+
} from "./index-ytjkvwy5.js";
|
|
7
|
+
import"./index-80vg3ed6.js";
|
|
8
8
|
import"./index-tayzfr9c.js";
|
|
9
9
|
import"./index-5x42amh8.js";
|
|
10
10
|
import"./index-37x76zdn.js";
|
|
@@ -3,11 +3,11 @@ import {
|
|
|
3
3
|
restoreForCommand,
|
|
4
4
|
restoreOfflineMessage,
|
|
5
5
|
restorePinnedExtensions
|
|
6
|
-
} from "./cli-
|
|
7
|
-
import"./cli-
|
|
8
|
-
import"./cli-
|
|
6
|
+
} from "./cli-88arpdke.js";
|
|
7
|
+
import"./cli-tgnyvra3.js";
|
|
8
|
+
import"./cli-9n9kg58f.js";
|
|
9
9
|
import"./cli-d8xjns66.js";
|
|
10
|
-
import"./cli-
|
|
10
|
+
import"./cli-x7gcdg6w.js";
|
|
11
11
|
import"./cli-65gy8ask.js";
|
|
12
12
|
import"./cli-46ycxe6r.js";
|
|
13
13
|
import"./cli-y28j019d.js";
|
|
@@ -59,6 +59,7 @@
|
|
|
59
59
|
});
|
|
60
60
|
|
|
61
61
|
// src/engine/shared/synthesis.ts
|
|
62
|
+
var RECTO_VERSO_VALUES = /^(right|recto|left|verso)$/;
|
|
62
63
|
var WHICH_VALUES = new Set(["first", "start", "last", "first-except"]);
|
|
63
64
|
var LEADER_RE = /\uE000([^\uE001]*)\uE001/;
|
|
64
65
|
function leaderFillCount(gapPx, gluePx) {
|
|
@@ -422,7 +423,8 @@
|
|
|
422
423
|
return out;
|
|
423
424
|
}
|
|
424
425
|
function forcedBreakSites(decls) {
|
|
425
|
-
const
|
|
426
|
+
const found = [];
|
|
427
|
+
const seen = new Set;
|
|
426
428
|
for (const d of decls) {
|
|
427
429
|
let els = [];
|
|
428
430
|
try {
|
|
@@ -430,10 +432,17 @@
|
|
|
430
432
|
} catch {
|
|
431
433
|
continue;
|
|
432
434
|
}
|
|
433
|
-
for (const el of els)
|
|
434
|
-
|
|
435
|
+
for (const el of els) {
|
|
436
|
+
const id = ensureAnchor(el);
|
|
437
|
+
const value = getComputedStyle(el).breakBefore;
|
|
438
|
+
if (seen.has(el) || !RECTO_VERSO_VALUES.test(value))
|
|
439
|
+
continue;
|
|
440
|
+
seen.add(el);
|
|
441
|
+
found.push({ el, id, prop: d.prop, value, selector: d.selector });
|
|
442
|
+
}
|
|
435
443
|
}
|
|
436
|
-
|
|
444
|
+
found.sort((a, b) => a.el.compareDocumentPosition(b.el) & Node.DOCUMENT_POSITION_FOLLOWING ? -1 : 1);
|
|
445
|
+
return found.map(({ el: _el, ...site }) => site);
|
|
437
446
|
}
|
|
438
447
|
function counterResetSites(resets) {
|
|
439
448
|
const out = [];
|
|
@@ -40,7 +40,6 @@
|
|
|
40
40
|
fragmentDocument: () => fragmentDocument,
|
|
41
41
|
cssZoomOf: () => cssZoomOf,
|
|
42
42
|
contentEdgeRect: () => contentEdgeRect,
|
|
43
|
-
compensateRepeatedHeaders: () => compensateRepeatedHeaders,
|
|
44
43
|
compensateRectoBreaks: () => compensateRectoBreaks,
|
|
45
44
|
columnReserve: () => columnReserve,
|
|
46
45
|
collectCssText: () => collectCssText,
|
|
@@ -193,6 +192,29 @@
|
|
|
193
192
|
no extractable body text; \`rabbit-walking.png\` (1379x2530, unique) sits on
|
|
194
193
|
PDF p134 vs viewer folio 135. */
|
|
195
194
|
|
|
195
|
+
/* Repeated table headers and footers. Print draws a table's header group
|
|
196
|
+
(\`thead\`) at the top of every page the table spans, and its footer group
|
|
197
|
+
(\`tfoot\`) at the foot of each, and never leaves a header alone at the foot
|
|
198
|
+
of a page. Chromium does the same in a multicol column, through the same
|
|
199
|
+
table fragmentation, when the group is unbreakable; print media treats
|
|
200
|
+
every header and footer group so, the screen only one that is
|
|
201
|
+
\`break-inside: avoid\` (measured: on screen, a plain \`thead\` printed once and
|
|
202
|
+
a \`break-inside: avoid\` one on every column, exactly as print media does).
|
|
203
|
+
Setting it here makes the columns repeat the groups print repeats, where
|
|
204
|
+
print repeats them, and break around them as print does. A group the author
|
|
205
|
+
set to another \`display\` is not a header group and repeats in neither.
|
|
206
|
+
|
|
207
|
+
The viewer used to imitate this in script, cloning the header into each
|
|
208
|
+
continuation column and forcing a break before a table whose header would
|
|
209
|
+
be left alone. It moved a lead-in paragraph whole where print splits it,
|
|
210
|
+
left a clone at a column's foot, drew a second header wherever Chromium
|
|
211
|
+
already drew one, and shifted pages after the forced-break spacers had been
|
|
212
|
+
placed, losing a chapter's break (the gp-dimm-city design guide's reference
|
|
213
|
+
tables: #454). docs/fixtures/repeated-table-header pins it. */
|
|
214
|
+
.gp-strip :is(thead, tfoot) {
|
|
215
|
+
break-inside: avoid;
|
|
216
|
+
}
|
|
217
|
+
|
|
196
218
|
/* View mode (\`applySpreadMode\` in fragment.ts): wraps this run's multicol
|
|
197
219
|
columns into \`--gp-wrap-cols\` ROWS instead of one long row — 2 for
|
|
198
220
|
two-up/spread, 1 for single (a plain vertical stack of pages), using
|
|
@@ -1482,10 +1504,13 @@
|
|
|
1482
1504
|
function clearLeadingForcedBreaks(strip) {
|
|
1483
1505
|
for (let el = strip.firstElementChild;el; el = el.firstElementChild) {
|
|
1484
1506
|
const cs = getComputedStyle(el);
|
|
1485
|
-
if (FORCED_BREAK.test(cs.breakBefore))
|
|
1486
|
-
|
|
1507
|
+
if (!FORCED_BREAK.test(cs.breakBefore))
|
|
1508
|
+
continue;
|
|
1509
|
+
clearedLeadingBreaks.set(el, cs.breakBefore);
|
|
1510
|
+
el.style.breakBefore = "auto";
|
|
1487
1511
|
}
|
|
1488
1512
|
}
|
|
1513
|
+
var clearedLeadingBreaks = new WeakMap;
|
|
1489
1514
|
function stabilizeFullHeightPageRoots(model, strips) {
|
|
1490
1515
|
let stabilized = 0;
|
|
1491
1516
|
for (const strip of strips) {
|
|
@@ -1688,148 +1713,6 @@
|
|
|
1688
1713
|
clearLeadingForcedBreaks(s.el);
|
|
1689
1714
|
return strips;
|
|
1690
1715
|
}
|
|
1691
|
-
var AVOID_BREAK = /^avoid(-page|-column)?$/;
|
|
1692
|
-
function keepChainHead(el) {
|
|
1693
|
-
let head = el;
|
|
1694
|
-
for (let prev = head.previousElementSibling;prev instanceof HTMLElement; prev = head.previousElementSibling) {
|
|
1695
|
-
const linked = AVOID_BREAK.test(getComputedStyle(prev).breakAfter) || AVOID_BREAK.test(getComputedStyle(head).breakBefore);
|
|
1696
|
-
if (!linked)
|
|
1697
|
-
break;
|
|
1698
|
-
head = prev;
|
|
1699
|
-
}
|
|
1700
|
-
return head;
|
|
1701
|
-
}
|
|
1702
|
-
var pushTargets = new WeakMap;
|
|
1703
|
-
function repeatingHead(table) {
|
|
1704
|
-
const head = table.tHead;
|
|
1705
|
-
return head && getComputedStyle(head).display === "table-header-group" ? head : null;
|
|
1706
|
-
}
|
|
1707
|
-
function repeatingFoot(table) {
|
|
1708
|
-
const foot = table.tFoot;
|
|
1709
|
-
return foot && getComputedStyle(foot).display === "table-footer-group" ? foot : null;
|
|
1710
|
-
}
|
|
1711
|
-
function compensateRepeatedHeaders(strips, maxPasses = 24) {
|
|
1712
|
-
const warnings = [];
|
|
1713
|
-
let passes = 0;
|
|
1714
|
-
let touched = 0;
|
|
1715
|
-
for (const strip of strips) {
|
|
1716
|
-
const tables = Array.from(strip.el.querySelectorAll("table")).filter((t) => repeatingHead(t) || repeatingFoot(t));
|
|
1717
|
-
if (!tables.length)
|
|
1718
|
-
continue;
|
|
1719
|
-
for (const table of tables) {
|
|
1720
|
-
for (const shim of Array.from(table.querySelectorAll("tr.gp-thead-shim, tr.gp-tfoot-shim")))
|
|
1721
|
-
shim.remove();
|
|
1722
|
-
table.style.breakBefore = "";
|
|
1723
|
-
const target = pushTargets.get(table);
|
|
1724
|
-
if (target)
|
|
1725
|
-
target.style.breakBefore = "";
|
|
1726
|
-
pushTargets.delete(table);
|
|
1727
|
-
}
|
|
1728
|
-
const pushed = new Set;
|
|
1729
|
-
const footClaims = new Map;
|
|
1730
|
-
let previous = "";
|
|
1731
|
-
for (let pass = 0;pass < maxPasses; pass++) {
|
|
1732
|
-
passes = Math.max(passes, pass + 1);
|
|
1733
|
-
const { stride, height: colBottom } = stripMetrics(strip.el);
|
|
1734
|
-
const stripLeft = strip.el.getBoundingClientRect().left - strip.el.scrollLeft;
|
|
1735
|
-
const zoom = cssZoomOf(strip.el);
|
|
1736
|
-
const colOf = (r) => Math.floor(((r.left - stripLeft) / zoom + 1) / stride);
|
|
1737
|
-
const stripTop = strip.el.getBoundingClientRect().top;
|
|
1738
|
-
const plans = [];
|
|
1739
|
-
for (const table of tables) {
|
|
1740
|
-
const head = repeatingHead(table);
|
|
1741
|
-
const headRect = head?.getClientRects()[0];
|
|
1742
|
-
const footHeight = (repeatingFoot(table)?.getBoundingClientRect().height ?? 0) / zoom;
|
|
1743
|
-
const rows = Array.from(table.querySelectorAll("tbody > tr")).filter((r) => !r.classList.contains("gp-thead-shim") && !r.classList.contains("gp-tfoot-shim"));
|
|
1744
|
-
if (!rows.length)
|
|
1745
|
-
continue;
|
|
1746
|
-
const rects = rows.map((r) => r.getClientRects()[0] ?? r.getBoundingClientRect());
|
|
1747
|
-
const cols = rects.map(colOf);
|
|
1748
|
-
const claims = footClaims.get(table) ?? new Map;
|
|
1749
|
-
footClaims.set(table, claims);
|
|
1750
|
-
let newClaim;
|
|
1751
|
-
if (footHeight > 0) {
|
|
1752
|
-
const lastCol = cols[cols.length - 1];
|
|
1753
|
-
for (let i = 0;i < rows.length; i++) {
|
|
1754
|
-
const row = rows[i];
|
|
1755
|
-
if (cols[i] === lastCol || claims.has(row))
|
|
1756
|
-
continue;
|
|
1757
|
-
const bottom = (rects[i].bottom - stripTop) / zoom;
|
|
1758
|
-
if (bottom > colBottom - footHeight + 0.5) {
|
|
1759
|
-
newClaim = row;
|
|
1760
|
-
claims.set(row, colBottom - (rects[i].top - stripTop) / zoom);
|
|
1761
|
-
break;
|
|
1762
|
-
}
|
|
1763
|
-
}
|
|
1764
|
-
}
|
|
1765
|
-
plans.push({
|
|
1766
|
-
table,
|
|
1767
|
-
push: headRect ? colOf(headRect) < cols[0] : false,
|
|
1768
|
-
headHeight: (headRect?.height ?? 0) / zoom,
|
|
1769
|
-
footHeight,
|
|
1770
|
-
breakRows: headRect ? rows.filter((_, i) => i > 0 && cols[i] > cols[i - 1]) : [],
|
|
1771
|
-
footRows: [...claims.entries()],
|
|
1772
|
-
grew: newClaim !== undefined,
|
|
1773
|
-
cells: Math.max(1, ...rows.map((r) => r.cells.length))
|
|
1774
|
-
});
|
|
1775
|
-
}
|
|
1776
|
-
const signature = plans.map((p) => `${p.push || pushed.has(p.table) ? "P" : ""}${p.breakRows.map((r) => r.rowIndex).join(".")}~${p.footRows.map(([r]) => r.rowIndex).join(".")}`).join("|");
|
|
1777
|
-
const anyGrowth = plans.some((p) => p.grew);
|
|
1778
|
-
if (!anyGrowth && signature === previous)
|
|
1779
|
-
break;
|
|
1780
|
-
previous = signature;
|
|
1781
|
-
for (const plan of plans) {
|
|
1782
|
-
for (const shim of Array.from(plan.table.querySelectorAll("tr.gp-thead-shim, tr.gp-tfoot-shim")))
|
|
1783
|
-
shim.remove();
|
|
1784
|
-
if (plan.push && !pushed.has(plan.table)) {
|
|
1785
|
-
pushed.add(plan.table);
|
|
1786
|
-
const target = keepChainHead(plan.table);
|
|
1787
|
-
target.style.breakBefore = "column";
|
|
1788
|
-
pushTargets.set(plan.table, target);
|
|
1789
|
-
touched++;
|
|
1790
|
-
continue;
|
|
1791
|
-
}
|
|
1792
|
-
for (const row of plan.breakRows) {
|
|
1793
|
-
row.before(headerShim(plan.table.tHead, plan.headHeight, plan.cells));
|
|
1794
|
-
touched++;
|
|
1795
|
-
}
|
|
1796
|
-
for (const [row, height] of plan.footRows) {
|
|
1797
|
-
row.before(sectionShim(plan.table.tFoot, height, plan.cells, "gp-tfoot-shim"));
|
|
1798
|
-
touched++;
|
|
1799
|
-
}
|
|
1800
|
-
}
|
|
1801
|
-
}
|
|
1802
|
-
}
|
|
1803
|
-
return { tables: touched, passes, warnings };
|
|
1804
|
-
}
|
|
1805
|
-
function headerShim(head, height, cells) {
|
|
1806
|
-
return sectionShim(head, height, cells, "gp-thead-shim");
|
|
1807
|
-
}
|
|
1808
|
-
function sectionShim(section, height, cells, className) {
|
|
1809
|
-
const shim = document.createElement("tr");
|
|
1810
|
-
shim.className = className;
|
|
1811
|
-
shim.setAttribute("aria-hidden", "true");
|
|
1812
|
-
shim.style.height = `${height}px`;
|
|
1813
|
-
if (className === "gp-tfoot-shim")
|
|
1814
|
-
shim.style.verticalAlign = "bottom";
|
|
1815
|
-
const source = section.rows[0];
|
|
1816
|
-
if (source) {
|
|
1817
|
-
for (const cell of Array.from(source.cells)) {
|
|
1818
|
-
const td = document.createElement("td");
|
|
1819
|
-
td.colSpan = cell.colSpan;
|
|
1820
|
-
td.innerHTML = cell.innerHTML;
|
|
1821
|
-
const cs = getComputedStyle(cell);
|
|
1822
|
-
td.style.cssText = `font:${cs.font};color:${cs.color};letter-spacing:${cs.letterSpacing};text-transform:${cs.textTransform};vertical-align:${cs.verticalAlign};text-align:${cs.textAlign};padding:${cs.padding};border:${cs.border};background:${cs.backgroundColor};`;
|
|
1823
|
-
shim.appendChild(td);
|
|
1824
|
-
}
|
|
1825
|
-
} else {
|
|
1826
|
-
const td = document.createElement("td");
|
|
1827
|
-
td.colSpan = cells;
|
|
1828
|
-
td.style.cssText = `height:${height}px;padding:0;border:0;`;
|
|
1829
|
-
shim.appendChild(td);
|
|
1830
|
-
}
|
|
1831
|
-
return shim;
|
|
1832
|
-
}
|
|
1833
1716
|
function compensateRectoBreaks(model, strips) {
|
|
1834
1717
|
const decls2 = model.breaks.filter(isRectoVersoBreak);
|
|
1835
1718
|
for (const spacer of Array.from(document.querySelectorAll(".gp-recto-spacer")))
|
|
@@ -1837,6 +1720,7 @@
|
|
|
1837
1720
|
if (!decls2.length)
|
|
1838
1721
|
return 0;
|
|
1839
1722
|
const sites = [];
|
|
1723
|
+
const seen = new Set;
|
|
1840
1724
|
for (const d of decls2) {
|
|
1841
1725
|
let els = [];
|
|
1842
1726
|
try {
|
|
@@ -1844,8 +1728,13 @@
|
|
|
1844
1728
|
} catch {
|
|
1845
1729
|
continue;
|
|
1846
1730
|
}
|
|
1847
|
-
for (const el of els)
|
|
1848
|
-
|
|
1731
|
+
for (const el of els) {
|
|
1732
|
+
const value = clearedLeadingBreaks.get(el) ?? getComputedStyle(el).breakBefore;
|
|
1733
|
+
if (seen.has(el) || !RECTO_VERSO_VALUES.test(value))
|
|
1734
|
+
continue;
|
|
1735
|
+
seen.add(el);
|
|
1736
|
+
sites.push({ el, wantsRecto: wantsRecto(value) });
|
|
1737
|
+
}
|
|
1849
1738
|
}
|
|
1850
1739
|
sites.sort((a, b) => a.el.compareDocumentPosition(b.el) & Node.DOCUMENT_POSITION_FOLLOWING ? -1 : 1);
|
|
1851
1740
|
const plan = planRectoBlanks(sites.map((site) => ({ page: pageOf(site.el, strips) + 1, wantsRecto: site.wantsRecto })));
|
|
@@ -2043,7 +1932,6 @@
|
|
|
2043
1932
|
const blanks = compensateRectoBreaks(model, strips);
|
|
2044
1933
|
if (blanks)
|
|
2045
1934
|
measure(strips);
|
|
2046
|
-
const headers = opts.compensateHeaders === false ? { tables: 0, passes: 0, warnings: [] } : compensateRepeatedHeaders(strips);
|
|
2047
1935
|
const contentPages = measure(strips).totalPages;
|
|
2048
1936
|
const totalPages = padToSignature(strips, contentPages);
|
|
2049
1937
|
fitVersoPinRoots(model, strips);
|
|
@@ -2051,7 +1939,7 @@
|
|
|
2051
1939
|
model,
|
|
2052
1940
|
strips,
|
|
2053
1941
|
totalPages,
|
|
2054
|
-
warnings: [...new Set(
|
|
1942
|
+
warnings: [...new Set(authoring)],
|
|
2055
1943
|
blankPages: blanks,
|
|
2056
1944
|
blankPageIndices: blankPageIndices(strips),
|
|
2057
1945
|
paddedPageIndices: pagesAfter(contentPages, totalPages),
|
|
@@ -2072,10 +1960,7 @@
|
|
|
2072
1960
|
synthesizeColumnBreaks(model);
|
|
2073
1961
|
measure(strips);
|
|
2074
1962
|
api.blankPages = compensateRectoBreaks(model, strips);
|
|
2075
|
-
|
|
2076
|
-
api.warnings = [
|
|
2077
|
-
...new Set([...authoring, ...compensateRepeatedHeaders(strips).warnings])
|
|
2078
|
-
];
|
|
1963
|
+
api.warnings = [...new Set(authoring)];
|
|
2079
1964
|
const content = measure(strips).totalPages;
|
|
2080
1965
|
padToSignature(strips, content);
|
|
2081
1966
|
const r = measure(strips);
|