Skip to content

Comments

fix(ui): openURL() should not invoke rejectFn when noopener is set (#18221)#18229

Open
arosstale wants to merge 1 commit intoquasarframework:devfrom
arosstale:fix/open-url-noopener-false-reject
Open

fix(ui): openURL() should not invoke rejectFn when noopener is set (#18221)#18229
arosstale wants to merge 1 commit intoquasarframework:devfrom
arosstale:fix/open-url-noopener-false-reject

Conversation

@arosstale
Copy link

What kind of change does this PR introduce?

  • Bugfix

Does this PR introduce a breaking change?

  • No

The PR fulfills these requirements:

  • It's submitted to the dev branch
  • When resolving a specific issue, it's referenced in the PR's title

Problem

openURL(url, rejectFn) always calls rejectFn even when the window was successfully opened.

Root cause: when noopener is included in the window features (which is the default — added for security in parseFeatures), the browser intentionally returns null from window.open() even though the window opened successfully. The caller has no reference to it for security reasons. The current code treats null as a failure and calls `reject?.().

const win = open(url, '_blank', parseFeatures(windowFeatures))
if (win) { ... }
else { reject?.() }  // ← always fires when noopener is set

Fix

Track whether noopener is in effect (it is by default). Only call reject when noopener is false, so a null return can still be treated as a genuine blocked-popup signal in that case.

const cfg = Object.assign({ noopener: true }, windowFeatures)
const hasNoopener = cfg.noopener === true

const win = open(url, '_blank', parseFeatures(windowFeatures))
if (win) { Platform.is.desktop && win.focus(); return win }
else if (hasNoopener === false) { reject?.() }

Callers that explicitly pass { noopener: false } in windowFeatures still get rejectFn called on genuine popup-blocked cases.

Other information: Reproducer: https://codepen.io/escodoy/pen/bNeamxG

When 'noopener' is present in the window features (which is the default),
`window.open()` intentionally returns `null` even though the window was
successfully opened — the browser withholds the reference for security.
Checking `win === null` as a failure signal is therefore incorrect and
causes `rejectFn` to always fire on successful opens.

Fix: only call `reject` when noopener is not in effect, so null can be
treated as a genuine blocked-popup signal.

Fixes quasarframework#18221
Copilot AI review requested due to automatic review settings February 19, 2026 08:17
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Fixes openURL()’s popup-block detection so that rejectFn is not called when window.open() returns null due to noopener being enabled (default behavior for security).

Changes:

  • Track whether noopener is in effect and only call rejectFn when it is explicitly disabled.
  • Add inline documentation explaining why window.open() can return null even on success.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +35 to 41
// When "noopener" is set (default), window.open() intentionally returns null
// even when the window was successfully opened. Only reject if noopener is
// not in effect, so that the null return can be treated as a blocked popup.
const cfg = Object.assign({ noopener: true }, windowFeatures)
const hasNoopener = cfg.noopener === true

const win = open(url, '_blank', parseFeatures(windowFeatures))
Copy link

Copilot AI Feb 19, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hasNoopener only checks cfg.noopener === true, but parseFeatures() can also include noreferrer (and in browsers noreferrer implies noopener). If a caller sets { noopener: false, noreferrer: true }, window.open() may still return null even when the popup opened, and this code would call reject?.() again. Consider treating noreferrer === true as equivalent to noopener being in effect (or folding both into a single hasNoopenerLikeProtection flag).

Copilot uses AI. Check for mistakes.
// even when the window was successfully opened. Only reject if noopener is
// not in effect, so that the null return can be treated as a blocked popup.
const cfg = Object.assign({ noopener: true }, windowFeatures)
const hasNoopener = cfg.noopener === true
Copy link

Copilot AI Feb 19, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hasNoopener is computed with a strict === true check, but parseFeatures() will treat non-boolean values like 1 or 'yes' as enabled and serialize them (e.g. noopener=1). If such values are passed, window.open() can still return null while this code would think noopener is off and call reject?.(). Consider defining the flag as cfg.noopener !== false (or otherwise matching the same semantics as parseFeatures()).

Suggested change
const hasNoopener = cfg.noopener === true
const hasNoopener = cfg.noopener !== false

Copilot uses AI. Check for mistakes.
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