Skip to content

[FIX] Cross-page links resolve in the merged PDF - #89

Merged
eleanorfrajka merged 4 commits into
mainfrom
feat/report-crosslinks
Aug 28, 2026
Merged

[FIX] Cross-page links resolve in the merged PDF#89
eleanorfrajka merged 4 commits into
mainfrom
feat/report-crosslinks

Conversation

@eleanorfrajka

@eleanorfrajka eleanorfrajka commented Aug 28, 2026

Copy link
Copy Markdown
Collaborator

Summary

Cross-page links in the merged mooring PDF (the Summary/Stack/Grid/serial header pills and the instrument links) were dead: combine_mooring_pdf rendered each source HTML file in its own render() call and page-concatenated them, and WeasyPrint only resolves internal links within a single render(). This rebuilds the combiner to assemble one HTML document and render it once, so the links resolve, and makes tall tables paginate sensibly.

What's changed

  • Single-document combine. combine_mooring_pdf now reads the ordered report files, assembles them into one HTML document via a pure, tested string transform (_build_combined_html + helpers in reports/_pdf.py), and renders that once.

  • Per-page id namespacing. Ids are reused across pages (top, qc, ts, vars, …), so the transform rewrites id="x"id="{slug}__x" and same-page href="#x"href="#{slug}__x" (slugs summary/stack/grid/instr-{serial}) before concatenation; otherwise every #top would resolve to the first page.

  • Inter-page link rewriting. Links to sibling report files ({mooring}_stack_report.html, the instrument/…#start and ../ forms) become in-document anchors targeting each page's masthead #{slug}__top (every page carries id="top" from base.html).

  • Regex, not an HTML parser. Safe because the report CSS has no id selectors and figures are base64 PNG, not inline SVG — a SAFETY CONDITION comment in _pdf.py records that SVG would also require rewriting url(#…)/xlink:href.

  • Table pagination. _PRINT_CSS now lets tables break at row boundaries (tr { break-inside: avoid }), repeats the header row on continuation pages (thead { display: table-header-group }), and keeps headings with their content (h2,h3,h4 { break-after: avoid }) — instead of forcing a tall table whole onto the next sheet.

  • Tests. test_pdf_report.py: slug derivation, the pure transform (namespacing, inter-page + fragment rewrite, style dedup, .pdf-page wrapping, a completeness tripwire scanning broader than the transform), and a WeasyPrint-gated end-to-end test asserting the link resolves to an internal /Dest with no dead .html. Verified on the real dune2 fixture.

Notes

  • No public API or CLI change: combine_mooring_pdf's signature and output path are unchanged. The PDF's internal layout changes (links now internal; tables paginate at rows), but nothing parses the PDF — no breaking change for callers.
  • Render/end-to-end tests are gated on importorskip("weasyprint") (the pdf extra); they skip without it, as the existing PDF tests already do.
  • Known limitation (deferred): on the "Global attributes" subhead the heading can still strand at a page bottom — WeasyPrint 69 does not honour break-after: avoid there and it is not reproducible in a minimal case. Logged for follow-up (candidate fix: emit the heading as a table <caption>).

@eleanorfrajka
eleanorfrajka merged commit 2c54bce into main Aug 28, 2026
9 checks passed
@eleanorfrajka
eleanorfrajka deleted the feat/report-crosslinks branch August 28, 2026 11:06
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant