Keep SPA internal target=_blank links inside the app#1272
Open
Frexxty wants to merge 1 commit into
Open
Conversation
Single-page apps such as Plane mark in-app links with target="_blank" and handle the click themselves in JS (preventDefault plus client-side routing). The webview opens any unhandled target="_blank" navigation in the system browser, so the injected link guard tried to compensate by forcing a full window.location reload and calling stopImmediatePropagation on internal _blank links. That stop call defeated the page's own click handler, and the click could still escape to the native new-window path, so opening a project or a task peek view in Plane launched the system browser instead of navigating in place. For internal target="_blank" links without --new-window, retarget the anchor to _self and let the event proceed. The webview no longer escalates the click to a browser window, the page's own handler runs (so the SPA navigation and peek view work), and links without a handler fall back to a normal in-app _self navigation. External _blank links, OAuth/SSO, and --new-window paths are unchanged. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Opening a project or expanding a task (the peek view) in a self-hosted Plane instance launched the system browser instead of navigating inside the Pake window. The same problem affects any single-page app that follows this pattern.
The cause is how these apps build their links. Plane (via its
ControlLinkcomponent) putstarget="_blank"on in-app links and then handles the click itself in JavaScript, callingpreventDefaultand doing client-side routing. So these are ordinary same-origin internal links that only look like "open in a new tab".The webview opens any unhandled
target="_blank"navigation in the system browser by default. To compensate, the injected link guard inevent.jsintercepted internal_blanklinks, forced a fullwindow.location.hrefreload, and calledstopImmediatePropagation. That stop call defeated the page's own click handler, and the click could still reach the native new-window path, so the link ended up in the browser instead of the app.The fix: for internal
target="_blank"links (when--new-windowis not used), retarget the anchor to_selfand let the event proceed normally. The webview no longer escalates the click to a browser window, the page's own handler still runs so the SPA navigation and peek view work as intended, and a link without any handler falls back to a normal in-app_selfnavigation. External_blanklinks, OAuth/SSO handling, and the--new-windowpath are all unchanged.How it was tested
tests/unit/event-link-guard.test.jsto cover the new behavior (internal_blankretargeted to_self, no forced reload) and added a test confirming external_blanklinks still open in the system browser.Files changed
src-tauri/src/inject/event.jstests/unit/event-link-guard.test.js