Skip to content

fix(html): drop the blanket link target, and mark only external links - #758

Merged
andiwand merged 1 commit into
mainfrom
feat/link-targets
Aug 29, 2026
Merged

fix(html): drop the blanket link target, and mark only external links#758
andiwand merged 1 commit into
mainfrom
feat/link-targets

Conversation

@andiwand

@andiwand andiwand commented Aug 29, 2026

Copy link
Copy Markdown
Member

🤖 Generated with Claude Code

Fixes #730. Rebased onto main now that #756 and #757 are merged.

Every view was written with <base target="_blank">, so every link was a new tab. A browser has one; an embedded web view does not, and unless the host implements window opening the tap does nothing at all. Worst on the archive listing, where the links are the whole point: a zip rendered as a table of its entries and none of them could be opened.

Why not a config

The blanket base threw away a distinction the renderer already has and the host doesn't — whether a link points back into the same service or out to the web. pdf_file.cpp was already paying to undo it:

// Internal `#pN` links must override the document's `<base
// target="_blank">` or they open a new copy instead of scrolling.
<< (link.internal ? " target=\"_self\"" : "")

So the fix encodes the distinction instead of asking the embedder to re-answer it. is_safe_uri's scan becomes uri_kindrelative / external / refused, and the target follows from it:

markup browser embedded web view
relative (content.xml, #p2, other.html) no target navigates in place navigates in place — the listing works with no host code
external (https:, mailto:, …) target="_blank" rel="noopener noreferrer" new tab, as before raises createWebViewWith / onCreateWindow — the host's hand-off-to-system-browser hook
refused (javascript:, …) no href (#756)

<base target> goes, and with it the PDF's _self workaround and HtmlWriter::write_header_target, which nothing else used. OpenDocument.ios can drop its current WKUIDelegate workaround and just open Safari there — internal links no longer reach the delegate at all.

Test

  • a_link_that_is_navigable_keeps_its_href extended: external links carry the target, and #bookmark / other.html / a/b.html carry none.
  • New no_view_declares_a_document_wide_link_target across the csv, xml, text and markdown writers.
  • PdfFile.link_annotations_render_as_anchors and the two page-view link tests updated: #pN and page1.html name no target, the /URI action names _blank.
  • Full suite green.

Reference output

1525 files — every view carried the base tag. I verified mechanically that after stripping <base target="_blank"/>, target="_blank" rel="noopener noreferrer" and target="_self" from both sides, zero files differ; the pins are advanced to the regenerated commits.

@andiwand
andiwand force-pushed the feat/spreadsheet-cut-reporting branch from a9e5ca9 to 6daf61b Compare August 29, 2026 08:29
@andiwand
andiwand force-pushed the feat/spreadsheet-cut-reporting branch 2 times, most recently from 8424d2d to 183ab1f Compare August 29, 2026 08:41
@andiwand
andiwand force-pushed the feat/spreadsheet-cut-reporting branch from 183ab1f to f552d1e Compare August 29, 2026 08:49
Base automatically changed from feat/spreadsheet-cut-reporting to main August 29, 2026 08:50
Every view was written with `<base target="_blank">`, so every link was a
new tab. A browser has one; an embedded web view does not, and unless the
host implements window opening the tap does nothing at all. It showed
worst on the archive listing, where the links are the whole point: a zip
rendered as a table of its entries and none of them could be opened.

The base threw away a distinction the renderer already has. `pdf_file.cpp`
was paying to undo it, writing `target="_self"` on every `#pN` anchor so
an internal link would scroll instead of opening a copy of the page.

`uri_kind` - the scan `is_safe_uri` already did - now says relative,
external or refused, and the target follows: a link that leaves the page
carries `target="_blank" rel="noopener noreferrer"`, which is what a
browser makes a tab of and what an embedded web view raises its window
delegate for, and a link back into what serves the page carries nothing
and navigates in place. `<base target>` goes, and with it the pdf's
`_self` workaround and `HtmlWriter::write_header_target`.

Reference output moves in 1525 files, in the base tag and link targets
alone - nothing else differs.

Fixes #730

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Re7MMYiM7fL58uELzKGy77
@andiwand
andiwand merged commit a9f17a7 into main Aug 29, 2026
32 checks passed
@andiwand
andiwand deleted the feat/link-targets branch August 29, 2026 09:08
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.

Views set target="_blank", so links are dead in an embedded web view

1 participant