gutterpress 0.11.20-alpha.2 → 0.11.20-alpha.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/api/index.js +3 -2
- package/dist/{build-qmjg9r2d.js → build-epdcrm2c.js} +5 -4
- package/dist/{cli-zacevwcy.js → cli-0ey902sx.js} +267 -455
- package/dist/{cli-j802s31j.js → cli-61vd4ews.js} +83 -41
- package/dist/{cli-7z29z4wz.js → cli-fmksazej.js} +1 -1
- package/dist/{cli-gh0ym80r.js → cli-h4tfmpg3.js} +121 -20
- package/dist/cli-sth219v1.js +418 -0
- package/dist/cli.js +12 -12
- package/dist/{doctor-fe7tcs4v.js → doctor-78es5scm.js} +2 -2
- package/dist/engine/compiler/build.d.ts +1 -1
- package/dist/engine/shared/margin-box-support.d.ts +2 -2
- package/dist/engine/shared/pin-edges.d.ts +127 -0
- package/dist/engine/shared/print-area.d.ts +68 -0
- package/dist/{engine-9xb1ky8d.js → engine-67f68bxs.js} +1 -1
- package/dist/{engine-yax79k9m.js → engine-7ha27n2b.js} +2 -2
- package/dist/{ext-ahwxt6gv.js → ext-9mc7sr0d.js} +5 -4
- package/dist/{gutterpress-agent-cazqstr1.js → gutterpress-agent-mrdnwktc.js} +78 -13
- package/dist/{gutterpress-viewer-retj6ym2.js → gutterpress-viewer-jr30yw8t.js} +155 -56
- package/dist/{index-6xwtb7cw.js → index-ad95fws8.js} +82 -40
- package/dist/{index-3nr5rzzp.js → index-gm5xbx5w.js} +3 -3
- package/dist/index-sth219v1.js +418 -0
- package/dist/{index-razpty47.js → index-t13p8y08.js} +493 -582
- package/dist/index.js +4 -3
- package/dist/lib/build-fingerprint.d.ts +8 -0
- package/dist/lib/extension-manifest.d.ts +13 -0
- package/dist/lib/ghostscript.d.ts +70 -16
- package/dist/lib/markdown/assemble.d.ts +12 -2
- package/dist/lib/markdown/gutterpress-css.d.ts +46 -30
- package/dist/lib/markdown/index.d.ts +5 -0
- package/dist/lib/pdf-inspect.d.ts +45 -0
- package/dist/{manifest.schema-74s1ykyv.json → manifest.schema-13dfax80.json} +16 -4
- package/dist/{new-ftd4fec4.js → new-s4f0tnya.js} +5 -4
- package/dist/pdf-inspect-zdmy7qca.js +35 -0
- package/dist/{preflight-8sqarcsr.js → preflight-7ck4rbsq.js} +5 -4
- package/dist/preview/file-watcher.d.ts +4 -10
- package/dist/{preview-q76xn95h.js → preview-j91sxadd.js} +5 -4
- package/dist/{publish-7gdy6gbf.js → publish-f12xaenm.js} +5 -4
- package/dist/render.js +57 -6
- package/dist/schema/manifest.types.d.ts +28 -8
- package/dist/test-helpers/testkit.d.ts +2 -2
- package/dist/{validate-e3ryegce.js → validate-pb5gysvr.js} +5 -4
- package/package.json +1 -1
- package/dist/engine/shared/flush.d.ts +0 -59
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The project's print area: the manifest's `page` block, carried into every
|
|
3
|
+
* assembled book (preview, build, publish) as ONE
|
|
4
|
+
* `<meta name="gp-print-area">` by the markdown assembly
|
|
5
|
+
* (lib/markdown/assemble.ts) and read back here by everything that needs it:
|
|
6
|
+
* the preview's print overlays (viewer/overlay.ts) and both engines' pinned
|
|
7
|
+
* art (pin-edges.ts — a pin sits on the printer's art-safe line).
|
|
8
|
+
*
|
|
9
|
+
* Only the manifest feeds it — `page.width` x `page.height` (the sheet),
|
|
10
|
+
* `page.bleed` (a bleed the sheet already contains on the top, bottom and
|
|
11
|
+
* OUTER edge; the binding edge has none, as DriveThruRPG cuts it),
|
|
12
|
+
* `page.safe` (the TEXT rule: its inset from the trim on every edge) and
|
|
13
|
+
* `page.artSafe` (the ART rule: its inset on the top, bottom and outer edge,
|
|
14
|
+
* while the binding edge takes `safe`; absent = `safe`) — plus the preset's
|
|
15
|
+
* id and the printer spec it follows, which only word what the overlay finds.
|
|
16
|
+
* No book or plugin CSS feeds it: not the `@page` margins (they are where the
|
|
17
|
+
* author put the TEXT, which is not the printer's safe area), not
|
|
18
|
+
* `@page { bleed }`.
|
|
19
|
+
*
|
|
20
|
+
* The meta is metadata: it changes nothing a browser renders on its own.
|
|
21
|
+
* Node-safe: the writer is pure, and the reader takes the document it reads.
|
|
22
|
+
*/
|
|
23
|
+
/** The project's page geometry, in pt — the manifest's `page` block. */
|
|
24
|
+
export interface PrintArea {
|
|
25
|
+
width: number;
|
|
26
|
+
height: number;
|
|
27
|
+
/** in-sheet bleed on the top, bottom and outer edge; 0 = none */
|
|
28
|
+
bleed: number;
|
|
29
|
+
/** the TEXT rule: inset from the trim on every edge; 0 = none */
|
|
30
|
+
safe: number;
|
|
31
|
+
/** the ART rule: inset on the top, bottom and outer edge (the binding edge takes `safe`) */
|
|
32
|
+
artSafe: number;
|
|
33
|
+
/** the manifest's preset id, and the printer spec it follows: they only word what is found */
|
|
34
|
+
preset?: string;
|
|
35
|
+
spec?: {
|
|
36
|
+
label: string;
|
|
37
|
+
url: string;
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
/** Which side of the spread a page is: page 1 is a recto, so every odd page is one. */
|
|
41
|
+
export type PageSide = "recto" | "verso";
|
|
42
|
+
/** What a host knows from its resolved config: the `page` block, the preset and its spec. */
|
|
43
|
+
export interface PrintAreaSource {
|
|
44
|
+
width: number;
|
|
45
|
+
height: number;
|
|
46
|
+
bleed?: number;
|
|
47
|
+
safe?: number;
|
|
48
|
+
artSafe?: number;
|
|
49
|
+
preset?: string;
|
|
50
|
+
spec?: {
|
|
51
|
+
label: string;
|
|
52
|
+
url: string;
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* The `<meta>` tag for one book. An unset bleed or text rule is written as 0,
|
|
57
|
+
* never left out; an unset art rule stays out (the reader takes it as `safe`).
|
|
58
|
+
* Anything else the config's `page` block holds (`tolerance`) is not part of it.
|
|
59
|
+
*/
|
|
60
|
+
export declare function printAreaMeta(page: PrintAreaSource): string;
|
|
61
|
+
/** The one DOM call the reader makes: a `Document` satisfies it. */
|
|
62
|
+
export interface MetaDocument {
|
|
63
|
+
querySelector(selector: string): {
|
|
64
|
+
getAttribute(name: string): string | null;
|
|
65
|
+
} | null;
|
|
66
|
+
}
|
|
67
|
+
/** The book's print area from its `<meta name="gp-print-area">`; `null` without one. */
|
|
68
|
+
export declare function printAreaFromMeta(doc: MetaDocument): PrintArea | null;
|
|
@@ -12,20 +12,21 @@ import {
|
|
|
12
12
|
searchNpmExtensions,
|
|
13
13
|
setExtensionEnabled,
|
|
14
14
|
updateExtensions
|
|
15
|
-
} from "./cli-
|
|
16
|
-
import"./cli-
|
|
15
|
+
} from "./cli-0ey902sx.js";
|
|
16
|
+
import"./cli-h4tfmpg3.js";
|
|
17
17
|
import {
|
|
18
18
|
UsageError,
|
|
19
19
|
exitForUsage,
|
|
20
20
|
rejectExtraPositionals,
|
|
21
21
|
rejectUnknownFlags,
|
|
22
22
|
resolveProjectDir
|
|
23
|
-
} from "./cli-
|
|
23
|
+
} from "./cli-fmksazej.js";
|
|
24
24
|
import"./cli-ht1bcqdd.js";
|
|
25
|
-
import"./cli-
|
|
25
|
+
import"./cli-61vd4ews.js";
|
|
26
26
|
import {
|
|
27
27
|
EXIT_CODES
|
|
28
28
|
} from "./cli-46ycxe6r.js";
|
|
29
|
+
import"./cli-sth219v1.js";
|
|
29
30
|
import"./cli-eyyggect.js";
|
|
30
31
|
import"./cli-asap4t1z.js";
|
|
31
32
|
import"./cli-5qr3z0qa.js";
|
|
@@ -43,11 +43,13 @@
|
|
|
43
43
|
xrefSites: () => xrefSites,
|
|
44
44
|
targetTexts: () => targetTexts,
|
|
45
45
|
stringSources: () => stringSources,
|
|
46
|
+
setPinGeometry: () => setPinGeometry,
|
|
47
|
+
setPinFurniture: () => setPinFurniture,
|
|
46
48
|
setGenerated: () => setGenerated,
|
|
47
|
-
|
|
49
|
+
printArea: () => printArea,
|
|
50
|
+
pinRoots: () => pinRoots,
|
|
48
51
|
instrument: () => instrument,
|
|
49
52
|
forcedBreakSites: () => forcedBreakSites,
|
|
50
|
-
flushRoots: () => flushRoots,
|
|
51
53
|
fillLeaders: () => fillLeaders,
|
|
52
54
|
counterResetSites: () => counterResetSites,
|
|
53
55
|
collectCss: () => collectCss,
|
|
@@ -302,6 +304,51 @@
|
|
|
302
304
|
return evaluateContent(parseContent(value), ctx);
|
|
303
305
|
}
|
|
304
306
|
|
|
307
|
+
// src/engine/shared/pin-edges.ts
|
|
308
|
+
var PIN_EDGES = ["top", "right", "bottom", "left"];
|
|
309
|
+
var EDGE_PIN_SELECTOR = PIN_EDGES.map((edge) => `.gp-pin.gp-${edge}`).join(", ");
|
|
310
|
+
function pinEdgesIn(root) {
|
|
311
|
+
const pins = Array.from(root.querySelectorAll(EDGE_PIN_SELECTOR)).filter((pin) => pin.offsetParent === root);
|
|
312
|
+
return PIN_EDGES.filter((edge) => pins.some((pin) => pin.classList.contains(`gp-${edge}`)));
|
|
313
|
+
}
|
|
314
|
+
function pinKey(edges) {
|
|
315
|
+
return PIN_EDGES.filter((e) => edges.includes(e)).map((e) => e[0]).join("");
|
|
316
|
+
}
|
|
317
|
+
function paddingOf(cs) {
|
|
318
|
+
return {
|
|
319
|
+
top: parseFloat(cs.paddingTop) || 0,
|
|
320
|
+
right: parseFloat(cs.paddingRight) || 0,
|
|
321
|
+
bottom: parseFloat(cs.paddingBottom) || 0,
|
|
322
|
+
left: parseFloat(cs.paddingLeft) || 0
|
|
323
|
+
};
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
// src/engine/shared/print-area.ts
|
|
327
|
+
function printAreaFromMeta(doc) {
|
|
328
|
+
const raw = doc.querySelector('meta[name="gp-print-area"]')?.getAttribute("content");
|
|
329
|
+
if (!raw)
|
|
330
|
+
return null;
|
|
331
|
+
try {
|
|
332
|
+
const v = JSON.parse(raw);
|
|
333
|
+
const n = (x) => typeof x === "number" && Number.isFinite(x) && x > 0 ? x : 0;
|
|
334
|
+
if (!n(v.width) || !n(v.height))
|
|
335
|
+
return null;
|
|
336
|
+
const safe = n(v.safe);
|
|
337
|
+
const spec = v.spec && typeof v.spec.label === "string" && typeof v.spec.url === "string" && /^https?:\/\//i.test(v.spec.url) ? v.spec : undefined;
|
|
338
|
+
return {
|
|
339
|
+
width: n(v.width),
|
|
340
|
+
height: n(v.height),
|
|
341
|
+
bleed: n(v.bleed),
|
|
342
|
+
safe,
|
|
343
|
+
artSafe: typeof v.artSafe === "number" ? n(v.artSafe) : safe,
|
|
344
|
+
preset: typeof v.preset === "string" ? v.preset : undefined,
|
|
345
|
+
spec
|
|
346
|
+
};
|
|
347
|
+
} catch {
|
|
348
|
+
return null;
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
|
|
305
352
|
// src/engine/compiler/agent.ts
|
|
306
353
|
var uid = 0;
|
|
307
354
|
function ensureAnchor(el) {
|
|
@@ -559,29 +606,45 @@
|
|
|
559
606
|
addCss("gp-generated-content", css);
|
|
560
607
|
return entries.length;
|
|
561
608
|
}
|
|
562
|
-
function
|
|
609
|
+
function pinRoots() {
|
|
563
610
|
const out = [];
|
|
564
611
|
for (const root of Array.from(document.querySelectorAll(".page, .spread"))) {
|
|
565
|
-
const edges =
|
|
612
|
+
const edges = pinEdgesIn(root);
|
|
566
613
|
if (!edges.length)
|
|
567
614
|
continue;
|
|
568
|
-
const
|
|
569
|
-
const
|
|
570
|
-
|
|
571
|
-
|
|
615
|
+
const cs = getComputedStyle(root);
|
|
616
|
+
const padding = paddingOf(cs);
|
|
617
|
+
const key = `${cs.page === "auto" ? "" : cs.page}|${pinKey(edges)}|${edges.map((e) => padding[e]).join(",")}`;
|
|
618
|
+
root.dataset.gpPin = key;
|
|
619
|
+
out.push({ id: ensureAnchor(root), page: cs.page, edges, padding, key });
|
|
572
620
|
}
|
|
573
621
|
return out;
|
|
574
622
|
}
|
|
575
|
-
function
|
|
623
|
+
function printArea() {
|
|
624
|
+
return printAreaFromMeta(document);
|
|
625
|
+
}
|
|
626
|
+
function setPinGeometry(items) {
|
|
627
|
+
let set = 0;
|
|
628
|
+
for (const item of items) {
|
|
629
|
+
const host = anchorHost(item.id);
|
|
630
|
+
if (!host)
|
|
631
|
+
continue;
|
|
632
|
+
for (const [prop, value] of Object.entries(item.style))
|
|
633
|
+
host.style.setProperty(prop, value);
|
|
634
|
+
set++;
|
|
635
|
+
}
|
|
636
|
+
return set;
|
|
637
|
+
}
|
|
638
|
+
function setPinFurniture(items) {
|
|
576
639
|
let painted = 0;
|
|
577
640
|
for (const item of items) {
|
|
578
641
|
const host = anchorHost(item.id);
|
|
579
642
|
if (!host)
|
|
580
643
|
continue;
|
|
581
|
-
let layer = host.querySelector(":scope > .gp-
|
|
644
|
+
let layer = host.querySelector(":scope > .gp-pin-furniture");
|
|
582
645
|
if (!layer) {
|
|
583
646
|
layer = document.createElement("div");
|
|
584
|
-
layer.className = "gp-
|
|
647
|
+
layer.className = "gp-pin-furniture";
|
|
585
648
|
layer.setAttribute("aria-hidden", "true");
|
|
586
649
|
layer.setAttribute("style", "position:absolute;inset:0;pointer-events:none;z-index:10;");
|
|
587
650
|
host.appendChild(layer);
|
|
@@ -616,8 +679,10 @@
|
|
|
616
679
|
instrument,
|
|
617
680
|
addCss,
|
|
618
681
|
setGenerated,
|
|
619
|
-
|
|
620
|
-
|
|
682
|
+
pinRoots,
|
|
683
|
+
printArea,
|
|
684
|
+
setPinGeometry,
|
|
685
|
+
setPinFurniture
|
|
621
686
|
};
|
|
622
687
|
if (typeof window !== "undefined")
|
|
623
688
|
window.__gp = api;
|
|
@@ -1038,10 +1038,12 @@
|
|
|
1038
1038
|
`);
|
|
1039
1039
|
}
|
|
1040
1040
|
|
|
1041
|
-
// src/engine/shared/
|
|
1042
|
-
var
|
|
1043
|
-
|
|
1044
|
-
|
|
1041
|
+
// src/engine/shared/pin-edges.ts
|
|
1042
|
+
var PIN_EDGES = ["top", "right", "bottom", "left"];
|
|
1043
|
+
var EDGE_PIN_SELECTOR = PIN_EDGES.map((edge) => `.gp-pin.gp-${edge}`).join(", ");
|
|
1044
|
+
function pinEdgesIn(root) {
|
|
1045
|
+
const pins = Array.from(root.querySelectorAll(EDGE_PIN_SELECTOR)).filter((pin) => pin.offsetParent === root);
|
|
1046
|
+
return PIN_EDGES.filter((edge) => pins.some((pin) => pin.classList.contains(`gp-${edge}`)));
|
|
1045
1047
|
}
|
|
1046
1048
|
function flushMargins(margin, edges) {
|
|
1047
1049
|
return {
|
|
@@ -1051,6 +1053,57 @@
|
|
|
1051
1053
|
left: edges.includes("left") ? 0 : margin.left
|
|
1052
1054
|
};
|
|
1053
1055
|
}
|
|
1056
|
+
function pinInsets(area, side, edges) {
|
|
1057
|
+
const binding = side === "recto" ? "left" : "right";
|
|
1058
|
+
const inset = (edge) => !area || !edges.includes(edge) ? 0 : edge === binding ? area.safe : area.bleed + area.artSafe;
|
|
1059
|
+
return { top: inset("top"), right: inset("right"), bottom: inset("bottom"), left: inset("left") };
|
|
1060
|
+
}
|
|
1061
|
+
var NO_PADDING = { top: 0, right: 0, bottom: 0, left: 0 };
|
|
1062
|
+
function pinRootStyle(margin, area, side, edges, padding = NO_PADDING) {
|
|
1063
|
+
const px = (pt) => pt * 96 / 72;
|
|
1064
|
+
const inset = pinInsets(area, side, edges);
|
|
1065
|
+
const style = { "box-decoration-break": "clone" };
|
|
1066
|
+
for (const edge of PIN_EDGES)
|
|
1067
|
+
if (edges.includes(edge))
|
|
1068
|
+
style[`padding-${edge}`] = `${px(margin[edge]) + padding[edge]}px`;
|
|
1069
|
+
for (const edge of PIN_EDGES)
|
|
1070
|
+
style[`--gp-pin-${edge}`] = `${px(inset[edge])}px`;
|
|
1071
|
+
return style;
|
|
1072
|
+
}
|
|
1073
|
+
function paddingOf(cs) {
|
|
1074
|
+
return {
|
|
1075
|
+
top: parseFloat(cs.paddingTop) || 0,
|
|
1076
|
+
right: parseFloat(cs.paddingRight) || 0,
|
|
1077
|
+
bottom: parseFloat(cs.paddingBottom) || 0,
|
|
1078
|
+
left: parseFloat(cs.paddingLeft) || 0
|
|
1079
|
+
};
|
|
1080
|
+
}
|
|
1081
|
+
|
|
1082
|
+
// src/engine/shared/print-area.ts
|
|
1083
|
+
function printAreaFromMeta(doc) {
|
|
1084
|
+
const raw = doc.querySelector('meta[name="gp-print-area"]')?.getAttribute("content");
|
|
1085
|
+
if (!raw)
|
|
1086
|
+
return null;
|
|
1087
|
+
try {
|
|
1088
|
+
const v = JSON.parse(raw);
|
|
1089
|
+
const n = (x) => typeof x === "number" && Number.isFinite(x) && x > 0 ? x : 0;
|
|
1090
|
+
if (!n(v.width) || !n(v.height))
|
|
1091
|
+
return null;
|
|
1092
|
+
const safe = n(v.safe);
|
|
1093
|
+
const spec = v.spec && typeof v.spec.label === "string" && typeof v.spec.url === "string" && /^https?:\/\//i.test(v.spec.url) ? v.spec : undefined;
|
|
1094
|
+
return {
|
|
1095
|
+
width: n(v.width),
|
|
1096
|
+
height: n(v.height),
|
|
1097
|
+
bleed: n(v.bleed),
|
|
1098
|
+
safe,
|
|
1099
|
+
artSafe: typeof v.artSafe === "number" ? n(v.artSafe) : safe,
|
|
1100
|
+
preset: typeof v.preset === "string" ? v.preset : undefined,
|
|
1101
|
+
spec
|
|
1102
|
+
};
|
|
1103
|
+
} catch {
|
|
1104
|
+
return null;
|
|
1105
|
+
}
|
|
1106
|
+
}
|
|
1054
1107
|
|
|
1055
1108
|
// src/engine/viewer/fragment.ts
|
|
1056
1109
|
var PX_PER_PT = 96 / 72;
|
|
@@ -1210,13 +1263,29 @@
|
|
|
1210
1263
|
}
|
|
1211
1264
|
return false;
|
|
1212
1265
|
}
|
|
1213
|
-
function pushRun(runs, page, nodes,
|
|
1214
|
-
const key = (r) => `${r.page ?? ""}\x00${(r.
|
|
1266
|
+
function pushRun(runs, page, nodes, pin) {
|
|
1267
|
+
const key = (r) => `${r.page ?? ""}\x00${(r.pin?.edges ?? []).join(",")}`;
|
|
1215
1268
|
const last = runs[runs.length - 1];
|
|
1216
|
-
if (last && key(last) === key({ page,
|
|
1269
|
+
if (last && key(last) === key({ page, pin })) {
|
|
1217
1270
|
last.nodes.push(...nodes);
|
|
1218
|
-
|
|
1219
|
-
|
|
1271
|
+
if (pin)
|
|
1272
|
+
last.pin.roots.push(...pin.roots);
|
|
1273
|
+
} else
|
|
1274
|
+
runs.push({ page, nodes, pin: pin && { edges: pin.edges, roots: [...pin.roots] } });
|
|
1275
|
+
}
|
|
1276
|
+
var PAGE_ROOT = ".page, .spread";
|
|
1277
|
+
var ownPadding = new WeakMap;
|
|
1278
|
+
function pinRunOf(el) {
|
|
1279
|
+
if (!el.matches(PAGE_ROOT))
|
|
1280
|
+
return;
|
|
1281
|
+
const edges = pinEdgesIn(el);
|
|
1282
|
+
return edges.length ? { edges, roots: [el] } : undefined;
|
|
1283
|
+
}
|
|
1284
|
+
function holdsPinRoot(el) {
|
|
1285
|
+
return Array.from(el.querySelectorAll(EDGE_PIN_SELECTOR)).some((pin) => {
|
|
1286
|
+
const root = pin.offsetParent;
|
|
1287
|
+
return !!root && root !== el && el.contains(root) && root.matches(PAGE_ROOT);
|
|
1288
|
+
});
|
|
1220
1289
|
}
|
|
1221
1290
|
function explodeChildren(container, model) {
|
|
1222
1291
|
const runs = [];
|
|
@@ -1228,7 +1297,7 @@
|
|
|
1228
1297
|
pending = [];
|
|
1229
1298
|
const last = runs[runs.length - 1];
|
|
1230
1299
|
if (last) {
|
|
1231
|
-
pushRun(runs, last.page, held, last.
|
|
1300
|
+
pushRun(runs, last.page, held, last.pin && { edges: last.pin.edges, roots: [] });
|
|
1232
1301
|
return [];
|
|
1233
1302
|
}
|
|
1234
1303
|
if (held.some((n) => (n.textContent ?? "").trim() !== "")) {
|
|
@@ -1245,19 +1314,19 @@
|
|
|
1245
1314
|
const kid = node;
|
|
1246
1315
|
if (kid.classList.contains("gp-layer"))
|
|
1247
1316
|
continue;
|
|
1248
|
-
const
|
|
1317
|
+
const pin = pinRunOf(kid);
|
|
1249
1318
|
const own = directPageName(kid, model);
|
|
1250
1319
|
if (own !== undefined) {
|
|
1251
|
-
pushRun(runs, own, [...carry(), kid],
|
|
1320
|
+
pushRun(runs, own, [...carry(), kid], pin);
|
|
1252
1321
|
continue;
|
|
1253
1322
|
}
|
|
1254
|
-
if (!hasDescendantPageAssignment(kid, model)) {
|
|
1255
|
-
pushRun(runs, undefined, [...carry(), kid],
|
|
1323
|
+
if (!hasDescendantPageAssignment(kid, model) && !holdsPinRoot(kid)) {
|
|
1324
|
+
pushRun(runs, undefined, [...carry(), kid], pin);
|
|
1256
1325
|
continue;
|
|
1257
1326
|
}
|
|
1258
1327
|
const inner = explodeChildren(kid, model);
|
|
1259
1328
|
if (inner.length <= 1) {
|
|
1260
|
-
pushRun(runs, inner[0]?.page, [...carry(), kid]);
|
|
1329
|
+
pushRun(runs, inner[0]?.page, [...carry(), kid], pin ?? inner[0]?.pin);
|
|
1261
1330
|
continue;
|
|
1262
1331
|
}
|
|
1263
1332
|
let lead = carry();
|
|
@@ -1266,7 +1335,7 @@
|
|
|
1266
1335
|
for (const n of r.nodes)
|
|
1267
1336
|
shell.appendChild(n);
|
|
1268
1337
|
kid.before(shell);
|
|
1269
|
-
pushRun(runs, r.page, [...lead, shell],
|
|
1338
|
+
pushRun(runs, r.page, [...lead, shell], pin ? pinRunOf(shell) : r.pin);
|
|
1270
1339
|
lead = [];
|
|
1271
1340
|
}
|
|
1272
1341
|
kid.remove();
|
|
@@ -1323,6 +1392,42 @@
|
|
|
1323
1392
|
delete el.dataset.gpLeadingPageRootDisplayPriority;
|
|
1324
1393
|
}
|
|
1325
1394
|
}
|
|
1395
|
+
function fitVersoPinRoots(model, strips) {
|
|
1396
|
+
const area = printAreaFromMeta(document);
|
|
1397
|
+
const versos = [];
|
|
1398
|
+
for (const strip of strips) {
|
|
1399
|
+
if (!strip.pinEdges || !strip.pinRoots?.length)
|
|
1400
|
+
continue;
|
|
1401
|
+
const edges = strip.pinEdges;
|
|
1402
|
+
const { left, agree } = pageSides(model, strip.page);
|
|
1403
|
+
const verso = agree ? left.margin : strip.geometry.margin;
|
|
1404
|
+
const margin = { ...strip.geometry.margin, left: verso.left, right: verso.right };
|
|
1405
|
+
const shift = pt(strip.versoShift);
|
|
1406
|
+
for (const root of strip.pinRoots) {
|
|
1407
|
+
if (pageOf(root, strips) % 2 !== 1)
|
|
1408
|
+
continue;
|
|
1409
|
+
const style = pinRootStyle(margin, area, "verso", edges, ownPadding.get(root));
|
|
1410
|
+
if (shift && edges.includes("left"))
|
|
1411
|
+
style["margin-left"] = `${shift}px`;
|
|
1412
|
+
if (shift && edges.includes("right"))
|
|
1413
|
+
style["margin-right"] = `${-shift}px`;
|
|
1414
|
+
versos.push({ root, style });
|
|
1415
|
+
}
|
|
1416
|
+
}
|
|
1417
|
+
for (const { root, style } of versos)
|
|
1418
|
+
for (const [prop, value] of Object.entries(style))
|
|
1419
|
+
root.style.setProperty(prop, value);
|
|
1420
|
+
}
|
|
1421
|
+
function restorePinRoots(doc = document) {
|
|
1422
|
+
for (const el of Array.from(doc.querySelectorAll("[data-gp-pin-style]"))) {
|
|
1423
|
+
const style = el.dataset.gpPinStyle;
|
|
1424
|
+
if (style)
|
|
1425
|
+
el.setAttribute("style", style);
|
|
1426
|
+
else
|
|
1427
|
+
el.removeAttribute("style");
|
|
1428
|
+
delete el.dataset.gpPinStyle;
|
|
1429
|
+
}
|
|
1430
|
+
}
|
|
1326
1431
|
var SCROLLABLE = /^(auto|scroll|hidden)$/;
|
|
1327
1432
|
function makeOverflowFragmentable(strips) {
|
|
1328
1433
|
const todo = [];
|
|
@@ -1388,21 +1493,16 @@
|
|
|
1388
1493
|
agree: Math.abs(r.w - l.w) < 0.01 && Math.abs(r.h - l.h) < 0.01
|
|
1389
1494
|
};
|
|
1390
1495
|
}
|
|
1391
|
-
function versoShiftPt(model, name
|
|
1496
|
+
function versoShiftPt(model, name) {
|
|
1392
1497
|
const { right, left, agree } = pageSides(model, name);
|
|
1393
|
-
|
|
1394
|
-
return 0;
|
|
1395
|
-
const r = flushMargins(right.margin, flushEdges);
|
|
1396
|
-
const l = flushMargins(left.margin, flushEdges);
|
|
1397
|
-
if (Math.abs(r.left + r.right - (l.left + l.right)) >= 0.01)
|
|
1398
|
-
return 0;
|
|
1399
|
-
return r.left - l.left;
|
|
1498
|
+
return agree ? right.margin.left - left.margin.left : 0;
|
|
1400
1499
|
}
|
|
1401
1500
|
function buildStrips(model, opts = {}, warnings = []) {
|
|
1402
1501
|
const doc = document;
|
|
1403
1502
|
const root = opts.root ?? doc.querySelector("main") ?? doc.body;
|
|
1404
1503
|
const gap = opts.sheetGap ?? 24;
|
|
1405
1504
|
const runs = explodeChildren(root, model);
|
|
1505
|
+
const area = printAreaFromMeta(doc);
|
|
1406
1506
|
const strips = [];
|
|
1407
1507
|
for (const run of runs) {
|
|
1408
1508
|
const geometry = runPageBox(model, run.page, warnings);
|
|
@@ -1410,7 +1510,18 @@
|
|
|
1410
1510
|
strip.className = "gp-strip";
|
|
1411
1511
|
if (run.page)
|
|
1412
1512
|
strip.dataset.page = run.page;
|
|
1413
|
-
const margin = run.
|
|
1513
|
+
const margin = run.pin ? flushMargins(geometry.margin, run.pin.edges) : geometry.margin;
|
|
1514
|
+
if (run.pin) {
|
|
1515
|
+
const { edges, roots } = run.pin;
|
|
1516
|
+
for (const pinRoot of roots)
|
|
1517
|
+
ownPadding.set(pinRoot, paddingOf(getComputedStyle(pinRoot)));
|
|
1518
|
+
for (const pinRoot of roots) {
|
|
1519
|
+
pinRoot.dataset.gpPinStyle ??= pinRoot.getAttribute("style") ?? "";
|
|
1520
|
+
const recto = pinRootStyle(geometry.margin, area, "recto", edges, ownPadding.get(pinRoot));
|
|
1521
|
+
for (const [prop, value] of Object.entries(recto))
|
|
1522
|
+
pinRoot.style.setProperty(prop, value);
|
|
1523
|
+
}
|
|
1524
|
+
}
|
|
1414
1525
|
const w = pt(geometry.width - margin.left - margin.right);
|
|
1415
1526
|
const h = pt(geometry.height - margin.top - margin.bottom);
|
|
1416
1527
|
strip.style.setProperty("--gp-content-w", `${w}px`);
|
|
@@ -1422,7 +1533,7 @@
|
|
|
1422
1533
|
strip.style.setProperty("--gp-margin-right", `${pt(margin.right)}px`);
|
|
1423
1534
|
strip.style.setProperty("--gp-margin-bottom", `${pt(margin.bottom)}px`);
|
|
1424
1535
|
strip.style.setProperty("--gp-margin-left", `${pt(margin.left)}px`);
|
|
1425
|
-
const rawShift = versoShiftPt(model, run.page
|
|
1536
|
+
const rawShift = versoShiftPt(model, run.page);
|
|
1426
1537
|
const versoShift = Math.abs(rawShift) >= 0.01 ? rawShift : 0;
|
|
1427
1538
|
if (versoShift)
|
|
1428
1539
|
strip.style.setProperty("--gp-verso-shift", `${pt(versoShift)}px`);
|
|
@@ -1433,7 +1544,8 @@
|
|
|
1433
1544
|
el: strip,
|
|
1434
1545
|
page: run.page,
|
|
1435
1546
|
geometry,
|
|
1436
|
-
|
|
1547
|
+
pinEdges: run.pin?.edges,
|
|
1548
|
+
pinRoots: run.pin?.roots,
|
|
1437
1549
|
versoShift,
|
|
1438
1550
|
pages: 0,
|
|
1439
1551
|
offset: 0
|
|
@@ -1455,12 +1567,20 @@
|
|
|
1455
1567
|
return head;
|
|
1456
1568
|
}
|
|
1457
1569
|
var pushTargets = new WeakMap;
|
|
1570
|
+
function repeatingHead(table) {
|
|
1571
|
+
const head = table.tHead;
|
|
1572
|
+
return head && getComputedStyle(head).display === "table-header-group" ? head : null;
|
|
1573
|
+
}
|
|
1574
|
+
function repeatingFoot(table) {
|
|
1575
|
+
const foot = table.tFoot;
|
|
1576
|
+
return foot && getComputedStyle(foot).display === "table-footer-group" ? foot : null;
|
|
1577
|
+
}
|
|
1458
1578
|
function compensateRepeatedHeaders(strips, maxPasses = 24) {
|
|
1459
1579
|
const warnings = [];
|
|
1460
1580
|
let passes = 0;
|
|
1461
1581
|
let touched = 0;
|
|
1462
1582
|
for (const strip of strips) {
|
|
1463
|
-
const tables = Array.from(strip.el.querySelectorAll("table")).filter((t) => t
|
|
1583
|
+
const tables = Array.from(strip.el.querySelectorAll("table")).filter((t) => repeatingHead(t) || repeatingFoot(t));
|
|
1464
1584
|
if (!tables.length)
|
|
1465
1585
|
continue;
|
|
1466
1586
|
for (const table of tables) {
|
|
@@ -1485,9 +1605,9 @@
|
|
|
1485
1605
|
const colBottom = strip.el.clientHeight;
|
|
1486
1606
|
const plans = [];
|
|
1487
1607
|
for (const table of tables) {
|
|
1488
|
-
const head = table
|
|
1608
|
+
const head = repeatingHead(table);
|
|
1489
1609
|
const headRect = head?.getClientRects()[0];
|
|
1490
|
-
const footHeight = (table
|
|
1610
|
+
const footHeight = (repeatingFoot(table)?.getBoundingClientRect().height ?? 0) / zoom;
|
|
1491
1611
|
const rows = Array.from(table.querySelectorAll("tbody > tr")).filter((r) => !r.classList.contains("gp-thead-shim") && !r.classList.contains("gp-tfoot-shim"));
|
|
1492
1612
|
if (!rows.length)
|
|
1493
1613
|
continue;
|
|
@@ -1567,7 +1687,7 @@
|
|
|
1567
1687
|
td.colSpan = cell.colSpan;
|
|
1568
1688
|
td.innerHTML = cell.innerHTML;
|
|
1569
1689
|
const cs = getComputedStyle(cell);
|
|
1570
|
-
td.style.cssText = `font:${cs.font};text-align:${cs.textAlign};padding:${cs.padding};border:${cs.border};background:${cs.backgroundColor};`;
|
|
1690
|
+
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};`;
|
|
1571
1691
|
shim.appendChild(td);
|
|
1572
1692
|
}
|
|
1573
1693
|
} else {
|
|
@@ -1797,6 +1917,7 @@
|
|
|
1797
1917
|
const headers = opts.compensateHeaders === false ? { tables: 0, passes: 0, warnings: [] } : compensateRepeatedHeaders(strips);
|
|
1798
1918
|
const contentPages = measure(strips).totalPages;
|
|
1799
1919
|
const totalPages = padToSignature(strips, contentPages);
|
|
1920
|
+
fitVersoPinRoots(model, strips);
|
|
1800
1921
|
const api = {
|
|
1801
1922
|
model,
|
|
1802
1923
|
strips,
|
|
@@ -1810,6 +1931,7 @@
|
|
|
1810
1931
|
relayout: () => {
|
|
1811
1932
|
restoreFullHeightPageRoots();
|
|
1812
1933
|
restoreScrollContainers();
|
|
1934
|
+
restorePinRoots();
|
|
1813
1935
|
unwrapStrips(strips);
|
|
1814
1936
|
for (const spacer of Array.from(document.querySelectorAll(".gp-recto-spacer, .gp-pad-spacer")))
|
|
1815
1937
|
spacer.remove();
|
|
@@ -1828,6 +1950,7 @@
|
|
|
1828
1950
|
const content = measure(strips).totalPages;
|
|
1829
1951
|
padToSignature(strips, content);
|
|
1830
1952
|
const r = measure(strips);
|
|
1953
|
+
fitVersoPinRoots(model, strips);
|
|
1831
1954
|
api.totalPages = r.totalPages;
|
|
1832
1955
|
api.blankPageIndices = blankPageIndices(strips);
|
|
1833
1956
|
api.paddedPageIndices = pagesAfter(content, r.totalPages);
|
|
@@ -2174,30 +2297,6 @@
|
|
|
2174
2297
|
artSafePt: 0,
|
|
2175
2298
|
counts: { text: 0, art: 0, bleed: 0, offPage: 0, intended: 0 }
|
|
2176
2299
|
};
|
|
2177
|
-
function printAreaFromMeta() {
|
|
2178
|
-
const raw = document.querySelector('meta[name="gp-print-area"]')?.getAttribute("content");
|
|
2179
|
-
if (!raw)
|
|
2180
|
-
return null;
|
|
2181
|
-
try {
|
|
2182
|
-
const v = JSON.parse(raw);
|
|
2183
|
-
const n = (x) => typeof x === "number" && Number.isFinite(x) && x > 0 ? x : 0;
|
|
2184
|
-
if (!n(v.width) || !n(v.height))
|
|
2185
|
-
return null;
|
|
2186
|
-
const safe = n(v.safe);
|
|
2187
|
-
const spec = v.spec && typeof v.spec.label === "string" && typeof v.spec.url === "string" && /^https?:\/\//i.test(v.spec.url) ? v.spec : undefined;
|
|
2188
|
-
return {
|
|
2189
|
-
width: n(v.width),
|
|
2190
|
-
height: n(v.height),
|
|
2191
|
-
bleed: n(v.bleed),
|
|
2192
|
-
safe,
|
|
2193
|
-
artSafe: typeof v.artSafe === "number" ? n(v.artSafe) : safe,
|
|
2194
|
-
preset: typeof v.preset === "string" ? v.preset : undefined,
|
|
2195
|
-
spec
|
|
2196
|
-
};
|
|
2197
|
-
} catch {
|
|
2198
|
-
return null;
|
|
2199
|
-
}
|
|
2200
|
-
}
|
|
2201
2300
|
function sheetArea(sheet) {
|
|
2202
2301
|
const px = (name) => parseFloat(sheet.style.getPropertyValue(name)) || 0;
|
|
2203
2302
|
return { width: px("--gp-page-w") / PX_PER_PT, height: px("--gp-page-h") / PX_PER_PT, bleed: 0, safe: 0, artSafe: 0 };
|
|
@@ -2681,7 +2780,7 @@
|
|
|
2681
2780
|
let overlayPages = [];
|
|
2682
2781
|
let overlaySummary = OVERLAY_OFF;
|
|
2683
2782
|
const paintOverlayNow = () => {
|
|
2684
|
-
overlaySummary = paintOverlay(overlayPages, layout.strips, printAreaFromMeta(), overlayLayers);
|
|
2783
|
+
overlaySummary = paintOverlay(overlayPages, layout.strips, printAreaFromMeta(document), overlayLayers);
|
|
2685
2784
|
window.dispatchEvent(new CustomEvent("gp:overlay", { detail: overlaySummary }));
|
|
2686
2785
|
};
|
|
2687
2786
|
const api = {
|