Skip to content

fix: open links in the browser or markpad, never inside the app window - #160

Merged
lezli01 merged 2 commits into
masterfrom
fix/external-links-in-browser
Oct 25, 2026
Merged

lezli01 merged 2 commits into
masterfrom
fix/external-links-in-browser

Conversation

@lezli01

@lezli01 lezli01 commented Oct 25, 2026

Copy link
Copy Markdown
Owner

Summary

Clicking a link in the preview used to point markpad's own window at the link's target, hiding the editor and turning the window into a browser. Now the window only ever shows markpad.

Native guard (src-tauri/src/navigation.rs)

The main window is now built in Rust, with "create": false in tauri.conf.json, so that navigation and new-window guards can be attached:

  • Navigation: only the app's own page is allowed: tauri://localhost/, http(s)://tauri.localhost/, and the Vite dev server in dev builds only. Any other path on the app origin is blocked, since that is a relative link resolved against the app. http, https, mailto and tel URLs go to the system's default handler, and everything else is refused.
  • New windows: always denied, with external URLs sent to the browser. Without a handler, WebView2 on Windows opens target="_blank" / window.open in a popup window of its own.

This catches forms, scripts, dropped URLs, and context-menu "Open Link" actions, whatever the frontend misses.

Preview link handling (src/lib/previewLinks.ts)

Every link activation is now handled explicitly: click and middle-click, HTML <a>, image-map <area>, and SVG <a xlink:href> from Graphviz URL= attributes.

  • Web / mail / phone links open via @tauri-apps/plugin-opener.
  • Links to .md / .markdown / .json / .yaml / .yml files open in markpad. This covers relative, absolute and local file:// links, resolved against the current document's folder, with Windows paths supported. A missing target shows an error banner instead of adding a broken recent item.
  • #heading links keep scrolling the preview.
  • Anything else does nothing, and raw-HTML <form>s never submit.

README feature list updated.

Not included

  • other.md#section opens the file but doesn't scroll to the heading.
  • Non-document files (images, PDFs) aren't opened in their default app.

Test plan

  • npm run lint, npm test (284 passed, 11 new), npm run build
  • cargo test (4 new navigation tests), cargo clippy -D warnings, cargo fmt --check
  • Manual check in tauri dev: web, mail, target=_blank and Graphviz links open in the browser; relative .md, .json and nested links with spaces open in markpad; a missing file shows an error; image links, /index.html, file:///etc/passwd and form submits do nothing; #anchor scrolls

🤖 Generated with Claude Code

lezli01 and others added 2 commits October 25, 2026 10:09
Build the main window in Rust with navigation and new-window guards. The
webview may only show the app's own page; web, mail and phone links are
handed to the system's default handler, and every other navigation or
pop-up (forms, target=_blank, window.open, dropped URLs, relative paths
resolved against the app origin) is refused.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Every link click in the preview is now handled explicitly, including
middle-clicks, image-map areas and SVG links in Graphviz diagrams:

- web, mail and phone links open in the system's default app;
- links to .md/.markdown/.json/.yaml/.yml files open them in markpad,
  resolved relative to the current document (a missing file reports an
  error instead of adding a broken recent);
- #heading links keep scrolling the preview;
- anything else does nothing, and raw-HTML forms never submit.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@lezli01
lezli01 merged commit 457a915 into master Oct 25, 2026
8 checks passed
@lezli01
lezli01 deleted the fix/external-links-in-browser branch October 25, 2026 09:26
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