electron/electron

Popup handling in BrowserViews doesn't work with WebContentsView

PalmerAL opened this issue · 4 comments

Preflight Checklist

Problem Description

Previously described in #41432 (comment)

#41432 added an API to set a custom callback on popup window creation. This is necessary to, for example, have popups open in a BrowserView, rather than a new window.

With a BrowserView, this looks like:

mainWindow.webContents.setWindowOpenHandler((details) => {
  return {
    action: 'allow',
    createWindow: (options) => {
      const browserView = new BrowserView(options)
      mainWindow.addBrowserView(browserView)
      browserView.setBounds({ x: 0, y: 0, width: 640, height: 480 })
      return browserView.webContents
    }
  }
})

options contains a WebContents, which is passed through to the BrowserView constructor.

The problem is that WebContentsView does not support passing in a WebContents during it's construction, which makes this API impossible to use.

For now, I'm continuing to use a BrowserView in my app, but as BrowserView is deprecated, I'm concerned that once it's removed, I won't have any migration path to a newer version.

Proposed Solution

  • Option 1: Allow passing in a WebContents to the WebContentsView constructor. This is already supported internally, and used by the BrowserView compatibility layer, it just isn't publicly exposed: https://github.com/electron/electron/blob/main/lib/browser/api/browser-view.ts#L13-L17. I'm not sure what the reason for hiding it was.
  • Option 2: Change the setWindowOpenHandler API to work around this somehow. I expect that would be harder; I'm not sure exactly what the correct API would look like in that case.

Alternatives Considered

None.

Additional Information

No response

Hiding the ability to construct a WebContentsView with a pre-existing WebContents was an oversight, not an intentional design decision. Let's fix it :)

My proposal would be:

diff --git a/docs/api/web-contents-view.md b/docs/api/web-contents-view.md
index b4d6b4c93c..66bb257cf0 100644
--- a/docs/api/web-contents-view.md
+++ b/docs/api/web-contents-view.md
@@ -35,10 +35,11 @@ Process: [Main](../glossary.md#main-process)
 ### `new WebContentsView([options])`

 * `options` Object (optional)
   * `webPreferences` [WebPreferences](structures/web-preferences.md) (optional) - Settings of web page's features.
+  * `webContents` [WebContents](web-contents.md) (optional) - If present, the given WebContents will be adopted by the WebContentsView. A WebContents may only be presented in one WebContentsView at a time.

-Creates an empty WebContentsView.
+Creates a WebContentsView.

That proposal looks good to me; I believe it matches how BrowserView works.

To resolve this the following BrowserWindow code can be copied: shell\browser\api\electron_api_browser_window.cc
i.e.: In the 31-x-x branch....

// Copy the webContents option to webPreferences.

  v8::Local<v8::Value> value;
  if (options.Get("webContents", &value)) {
    web_preferences.SetHidden("webContents", value);
  }
in shell\browser\api\electron_api_web_contents_view.cc at line 157

This allows us to simply pass the options argument of createWindow straight into as follows: new WebContentsView(options)

Not sure who can add this.

FYI: Here is the PR that attempts to add this functionality to WebContentsView: #42086