Compare commits

..

18 Commits

Author SHA1 Message Date
Sudowoodo Release Bot
16a3a456a6 Bump v21.1.1 2022-10-12 08:31:33 -07:00
trop[bot]
7727b7ecba fix: drag and drop should copy on macOS (#35977)
fix: drag and drop should copy on macOS (#35963)

Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com>

Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com>
2022-10-12 11:15:33 -04:00
trop[bot]
595ed3e128 fix: webContents.printToPDF option plumbing (#35992)
fix: contents.printToPDF option plumbing

Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com>

Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com>
2022-10-12 10:05:10 -04:00
trop[bot]
fd52089635 docs: remove references to Widevine (#35990)
Co-authored-by: John Kleinschmidt <jkleinsc@electronjs.org>

Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: John Kleinschmidt <jkleinsc@electronjs.org>
2022-10-12 10:02:39 -04:00
trop[bot]
77bc03e051 fix: on-screen-keyboard hides on input blurred in webview (#35982)
* fix: on-screen-keyboard hides on input blurred in webview

Co-authored-by: Kyrylo Hrechykhin <khrechykhin@microsoft.com>

* chore: update patches

Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: Kyrylo Hrechykhin <khrechykhin@microsoft.com>
Co-authored-by: PatchUp <73610968+patchup[bot]@users.noreply.github.com>
2022-10-11 23:20:11 +02:00
Raymond Zhao
9f99f4ed0e chore: cherry-pick 30a32e6 from chromium (#35370) (#35970)
chore: apply chromium commit 30a32e6 (#35370)

chore: Apply Chromium commit 30a32e6
2022-10-11 14:55:31 -04:00
trop[bot]
bc27dc4597 fix: expose the built-in electron module via the ESM loader (#35958)
* fix: expose the built-in electron module via the ESM loader

Co-authored-by: Samuel Attard <sattard@salesforce.com>

* Update .patches

* chore: update patches

Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: Samuel Attard <sattard@salesforce.com>
Co-authored-by: Samuel Attard <sam@electronjs.org>
Co-authored-by: PatchUp <73610968+patchup[bot]@users.noreply.github.com>
2022-10-11 12:32:49 -04:00
trop[bot]
9048de7cab fix: override content::ContentMainDelegate::CreateContentClient() (#35965)
* fix: override content::ContentMainDelegate::CreateContentClient()

Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com>

* chore: remove extra call

Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com>

Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com>
2022-10-11 02:37:18 -07:00
electron-roller[bot]
cef4f6a8e7 chore: bump chromium to 106.0.5249.103 (21-x-y) (#35933)
chore: bump chromium in DEPS to 106.0.5249.103

Co-authored-by: electron-roller[bot] <84116207+electron-roller[bot]@users.noreply.github.com>
2022-10-06 14:56:20 -04:00
Samuel Attard
80a4ea2601 chore: cherry-pick c83640db21b5 from chromium (#35925)
* chore: cherry-pick c83640db21b5 from chromium

* chore: update patches

Co-authored-by: PatchUp <73610968+patchup[bot]@users.noreply.github.com>
2022-10-06 04:28:52 -07:00
Samuel Attard
0b733793c3 build: fix filesystem permissions from bad trop commits
Ref: 572a9b16a1
Ref: 38955998f5
Ref: 63beca3002
2022-10-05 12:11:06 -07:00
Sudowoodo Release Bot
2b69b32c1d Bump v21.1.0 2022-10-05 08:31:26 -07:00
trop[bot]
63beca3002 docs: update supported Mac versions (#35914)
Co-authored-by: VerteDinde <vertedinde@electronjs.org>

Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: VerteDinde <vertedinde@electronjs.org>
2022-10-05 11:05:59 +02:00
electron-roller[bot]
4cd78dfccc chore: bump chromium to 106.0.5249.91 (21-x-y) (#35871)
chore: bump chromium in DEPS to 106.0.5249.91

Co-authored-by: electron-roller[bot] <84116207+electron-roller[bot]@users.noreply.github.com>
2022-10-04 20:31:39 -07:00
trop[bot]
38955998f5 docs: update bluetooth fiddle example event name to trigger correct event (#35907)
Fix event type spelling for bluetooth fiddle example

Co-authored-by: sam <sam.leider@hotmail.com>

Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: sam <sam.leider@hotmail.com>
2022-10-04 20:31:25 -07:00
trop[bot]
572a9b16a1 fix: TryCatch scope in node_bindings (#35895)
fix: TryCatch scope in node_bindings

Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com>

Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com>
2022-10-04 15:43:19 +02:00
trop[bot]
12d9fe3ab7 fix: set display_id in desktop capturer on Linux (#35836)
fix: set display_id in desktop capturer on Linux (#33861)

Previously, display_id was an empty string, pending Chrome support for
sharing individual screens. Now that this has been added, it is
desirable to have this property set correctly.

Co-authored-by: John Kleinschmidt <jkleinsc@electronjs.org>

Co-authored-by: James Cash <james.nvc@gmail.com>
Co-authored-by: John Kleinschmidt <jkleinsc@electronjs.org>
2022-09-28 22:22:43 +02:00
trop[bot]
32b64170b9 feat: add WebContents.opener and webContents.fromFrame() (#35819)
* feat: add WebContents.opener

* feat: add webContents.fromFrame(frame)

* fix: unknown type name

* test: fix and add more fromFrame cases

* docs: clarified terminology

Co-authored-by: Samuel Maddock <smaddock@salesforce.com>
2022-09-28 12:55:18 -04:00
26 changed files with 568 additions and 148 deletions

2
DEPS
View File

@@ -2,7 +2,7 @@ gclient_gn_args_from = 'src'
vars = {
'chromium_version':
'106.0.5249.61',
'106.0.5249.103',
'node_version':
'v16.16.0',
'nan_version':

View File

@@ -1 +1 @@
21.0.1
21.1.1

View File

@@ -38,7 +38,7 @@ For more installation options and troubleshooting tips, see
Each Electron release provides binaries for macOS, Windows, and Linux.
* macOS (El Capitan and up): Electron provides 64-bit Intel and ARM binaries for macOS. Apple Silicon support was added in Electron 11.
* macOS (High Sierra and up): Electron provides 64-bit Intel and ARM binaries for macOS. Apple Silicon support was added in Electron 11.
* Windows (Windows 7 and up): Electron provides `ia32` (`x86`), `x64` (`amd64`), and `arm64` binaries for Windows. Windows on ARM support was added in Electron 5.0.8.
* Linux: The prebuilt binaries of Electron are built on Ubuntu 20.04. They have also been verified to work on:
* Ubuntu 14.04 and newer

View File

@@ -83,7 +83,6 @@ These individual tutorials expand on topics discussed in the guide above.
* Electron Releases & Developer Feedback
* [Versioning Policy](tutorial/electron-versioning.md)
* [Release Timelines](tutorial/electron-timelines.md)
* [Testing Widevine CDM](tutorial/testing-widevine-cdm.md)
---

View File

@@ -45,6 +45,13 @@ returns `null`.
Returns `WebContents` | undefined - A WebContents instance with the given ID, or
`undefined` if there is no WebContents associated with the given ID.
### `webContents.fromFrame(frame)`
* `frame` WebFrameMain
Returns `WebContents` | undefined - A WebContents instance with the given WebFrameMain, or
`undefined` if there is no WebContents associated with the given WebFrameMain.
### `webContents.fromDevToolsTargetId(targetId)`
* `targetId` string - The Chrome DevTools Protocol [TargetID](https://chromedevtools.github.io/devtools-protocol/tot/Target/#type-TargetID) associated with the WebContents instance.
@@ -2079,6 +2086,11 @@ when the page becomes backgrounded. This also affects the Page Visibility API.
A [`WebFrameMain`](web-frame-main.md) property that represents the top frame of the page's frame hierarchy.
#### `contents.opener` _Readonly_
A [`WebFrameMain`](web-frame-main.md) property that represents the frame that opened this WebContents, either
with open(), or by navigating a link with a target attribute.
[keyboardevent]: https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent
[event-emitter]: https://nodejs.org/api/events.html#events_class_eventemitter
[SCA]: https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Structured_clone_algorithm

View File

@@ -2,5 +2,5 @@ const { contextBridge, ipcRenderer } = require('electron')
contextBridge.exposeInMainWorld('electronAPI', {
bluetoothPairingRequest: (callback) => ipcRenderer.on('bluetooth-pairing-request', callback),
bluetoothPairingResponse: (response) => ipcRenderer.send('bluetooth-pairing-respnse', response)
bluetoothPairingResponse: (response) => ipcRenderer.send('bluetooth-pairing-response', response)
})

View File

@@ -1,95 +0,0 @@
# Testing Widevine CDM
In Electron you can use the Widevine CDM library shipped with Chrome browser.
Widevine Content Decryption Modules (CDMs) are how streaming services protect
content using HTML5 video to web browsers without relying on an NPAPI plugin
like Flash or Silverlight. Widevine support is an alternative solution for
streaming services that currently rely on Silverlight for playback of
DRM-protected video content. It will allow websites to show DRM-protected video
content in Firefox without the use of NPAPI plugins. The Widevine CDM runs in an
open-source CDM sandbox providing better user security than NPAPI plugins.
#### Note on VMP
As of [`Electron v1.8.0 (Chrome v59)`](https://electronjs.org/releases#1.8.1),
the below steps are may only be some of the necessary steps to enable Widevine;
any app on or after that version intending to use the Widevine CDM may need to
be signed using a license obtained from [Widevine](https://www.widevine.com/)
itself.
Per [Widevine](https://www.widevine.com/):
> Chrome 59 (and later) includes support for Verified Media Path (VMP). VMP
> provides a method to verify the authenticity of a device platform. For browser
> deployments, this will provide an additional signal to determine if a
> browser-based implementation is reliable and secure.
>
> The proxy integration guide has been updated with information about VMP and
> how to issue licenses.
>
> Widevine recommends our browser-based integrations (vendors and browser-based
> applications) add support for VMP.
To enable video playback with this new restriction,
[castLabs](https://castlabs.com/open-source/downstream/) has created a
[fork](https://github.com/castlabs/electron-releases) that has implemented the
necessary changes to enable Widevine to be played in an Electron application if
one has obtained the necessary licenses from widevine.
## Getting the library
Open `chrome://components/` in Chrome browser, find `Widevine Content Decryption Module`
and make sure it is up to date, then you can find the library files from the
application directory.
### On Windows
The library file `widevinecdm.dll` will be under
`Program Files(x86)/Google/Chrome/Application/CHROME_VERSION/WidevineCdm/_platform_specific/win_(x86|x64)/`
directory.
### On macOS
The library file `libwidevinecdm.dylib` will be under
`/Applications/Google Chrome.app/Contents/Versions/CHROME_VERSION/Google Chrome Framework.framework/Versions/A/Libraries/WidevineCdm/_platform_specific/mac_(x86|x64)/`
directory.
**Note:** Make sure that chrome version used by Electron is greater than or
equal to the `min_chrome_version` value of Chrome's widevine cdm component.
The value can be found in `manifest.json` under `WidevineCdm` directory.
## Using the library
After getting the library files, you should pass the path to the file
with `--widevine-cdm-path` command line switch, and the library's version
with `--widevine-cdm-version` switch. The command line switches have to be
passed before the `ready` event of `app` module gets emitted.
Example code:
```javascript
const { app, BrowserWindow } = require('electron')
// You have to pass the directory that contains widevine library here, it is
// * `libwidevinecdm.dylib` on macOS,
// * `widevinecdm.dll` on Windows.
app.commandLine.appendSwitch('widevine-cdm-path', '/path/to/widevine_library')
// The version of plugin can be got from `chrome://components` page in Chrome.
app.commandLine.appendSwitch('widevine-cdm-version', '1.4.8.866')
let win = null
app.whenReady().then(() => {
win = new BrowserWindow()
win.show()
})
```
## Verifying Widevine CDM support
To verify whether widevine works, you can use following ways:
* Open https://shaka-player-demo.appspot.com/ and load a manifest that uses
`Widevine`.
* Open http://www.dash-player.com/demo/drm-test-area/, check whether the page
says `bitdash uses Widevine in your browser`, then play the video.

View File

@@ -173,13 +173,13 @@ WebContents.prototype.printToPDF = async function (options) {
headerTemplate: '',
footerTemplate: '',
printBackground: false,
scale: 1,
scale: 1.0,
paperWidth: 8.5,
paperHeight: 11,
marginTop: 0,
marginBottom: 0,
marginLeft: 0,
marginRight: 0,
paperHeight: 11.0,
marginTop: 0.0,
marginBottom: 0.0,
marginLeft: 0.0,
marginRight: 0.0,
pageRanges: '',
preferCSSPageSize: false
};
@@ -209,7 +209,7 @@ WebContents.prototype.printToPDF = async function (options) {
if (typeof options.scale !== 'number') {
return Promise.reject(new Error('scale must be a Number'));
}
printSettings.scaleFactor = options.scale;
printSettings.scale = options.scale;
}
const { pageSize } = options;
@@ -838,6 +838,10 @@ export function fromId (id: string) {
return binding.fromId(id);
}
export function fromFrame (frame: Electron.WebFrameMain) {
return binding.fromFrame(frame);
}
export function fromDevToolsTargetId (targetId: string) {
return binding.fromDevToolsTargetId(targetId);
}

View File

@@ -1,6 +1,6 @@
{
"name": "electron",
"version": "21.0.1",
"version": "21.1.1",
"repository": "https://github.com/electron/electron",
"description": "Build cross platform desktop apps with JavaScript, HTML, and CSS",
"devDependencies": {

View File

@@ -123,3 +123,5 @@ disable_optimization_guide_for_preconnect_feature.patch
fix_the_gn_gen_for_components_segmentation_platform.patch
fix_crash_loading_non-standard_schemes_in_iframes.patch
create_browser_v8_snapshot_file_name_fuse.patch
cherry-pick-c83640db21b5.patch
fix_on-screen-keyboard_hides_on_input_blur_in_webview.patch

View File

@@ -0,0 +1,122 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Samuel Attard <samuel.r.attard@gmail.com>
Date: Wed, 5 Oct 2022 06:03:23 +0000
Subject: build: set DTSDKBuild correctly when generating plist files
Currently we set DTSDKBuild to the version of the SDK used to build
Chromium. This value is supposed to be the build version (this is
what xcode sets it to for instance). We read this value out of the
SDK directly and use it instead.
Change-Id: Ieb7990f13095683ad8c026f027b2605ae39523a4
diff --git a/build/config/mac/mac_sdk.gni b/build/config/mac/mac_sdk.gni
index 43577925d2ef9cd79970d8307104e0abc1756583..0819d4cc1b17f216eae8c1a562b0301ba6298d57 100644
--- a/build/config/mac/mac_sdk.gni
+++ b/build/config/mac/mac_sdk.gni
@@ -40,6 +40,11 @@ declare_args() {
# will fail.
mac_sdk_official_version = "12.3"
+ # The SDK build version used when making official builds. This is a single
+ # exact version found at "System/Library/CoreServices/SystemVersion.plist"
+ # inside the SDK.
+ mac_sdk_official_build_version = "21E226"
+
# Production builds should use hermetic Xcode. If you want to do production
# builds with system Xcode to test new SDKs, set this.
# Don't set this on any bots.
@@ -103,11 +108,13 @@ if (use_system_xcode) {
find_sdk_args = [
"--print_sdk_path",
"--print_bin_path",
+ "--print_sdk_build",
mac_sdk_min,
]
find_sdk_lines =
exec_script("//build/mac/find_sdk.py", find_sdk_args, "list lines")
- mac_sdk_version = find_sdk_lines[2]
+ mac_sdk_version = find_sdk_lines[3]
+ mac_sdk_build_version = find_sdk_lines[2]
if (mac_sdk_path == "") {
mac_sdk_path = find_sdk_lines[0]
mac_bin_path = find_sdk_lines[1]
@@ -116,6 +123,7 @@ if (use_system_xcode) {
}
} else {
mac_sdk_version = mac_sdk_official_version
+ mac_sdk_build_version = mac_sdk_official_build_version
_dev = _hermetic_xcode_path + "/Contents/Developer"
_sdk = "MacOSX${mac_sdk_version}.sdk"
mac_sdk_path = _dev + "/Platforms/MacOSX.platform/Developer/SDKs/$_sdk"
diff --git a/build/config/mac/rules.gni b/build/config/mac/rules.gni
index 03073f830401c4891376a3b59e2e7a870e3d34b7..04d403054c1a83fcbbc70be7cfd239ecbec315d3 100644
--- a/build/config/mac/rules.gni
+++ b/build/config/mac/rules.gni
@@ -41,7 +41,7 @@ template("mac_info_plist") {
apple_info_plist(target_name) {
format = "xml1"
extra_substitutions = [
- "MAC_SDK_BUILD=$mac_sdk_version",
+ "MAC_SDK_BUILD=$mac_sdk_build_version",
"MAC_SDK_NAME=$mac_sdk_name$mac_sdk_version",
"MACOSX_DEPLOYMENT_TARGET=$mac_deployment_target",
"CHROMIUM_MIN_SYSTEM_VERSION=$mac_min_system_version",
diff --git a/build/mac/find_sdk.py b/build/mac/find_sdk.py
index d86f3109357a9246d570cb02992dc82552ba7c20..b2400c7e8c70957e364444f509880900ce3b641f 100755
--- a/build/mac/find_sdk.py
+++ b/build/mac/find_sdk.py
@@ -24,6 +24,7 @@ Sample Output:
from __future__ import print_function
import os
+import plistlib
import re
import subprocess
import sys
@@ -51,6 +52,9 @@ def main():
parser.add_option("--print_bin_path",
action="store_true", dest="print_bin_path", default=False,
help="Additionally print the path the toolchain bin dir.")
+ parser.add_option("--print_sdk_build",
+ action="store_true", dest="print_sdk_build", default=False,
+ help="Additionally print the build version of the SDK.")
options, args = parser.parse_args()
if len(args) != 1:
parser.error('Please specify a minimum SDK version')
@@ -80,20 +84,30 @@ def main():
if not sdks:
raise Exception('No %s+ SDK found' % min_sdk_version)
best_sdk = sorted(sdks, key=parse_version)[0]
+ sdk_name = 'MacOSX' + best_sdk + '.sdk'
+ sdk_path = os.path.join(sdk_dir, sdk_name)
if options.print_sdk_path:
- sdk_name = 'MacOSX' + best_sdk + '.sdk'
- print(os.path.join(sdk_dir, sdk_name))
+ print(sdk_path)
if options.print_bin_path:
bin_path = 'Toolchains/XcodeDefault.xctoolchain/usr/bin/'
print(os.path.join(dev_dir, bin_path))
- return best_sdk
+ if options.print_sdk_build:
+ system_version_plist = os.path.join(sdk_path,
+ 'System/Library/CoreServices/SystemVersion.plist')
+ with open(system_version_plist, 'rb') as f:
+ system_version_info = plistlib.load(f)
+ if 'ProductBuildVersion' not in system_version_info:
+ raise Exception('Failed to determine ProductBuildVersion' +
+ 'for SDK at path %s' % system_version_plist)
+ print(system_version_info['ProductBuildVersion'])
+
+ print(best_sdk)
if __name__ == '__main__':
if sys.platform != 'darwin':
raise Exception("This script only runs on Mac")
- print(main())
- sys.exit(0)
+ sys.exit(main())

View File

@@ -0,0 +1,59 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Kyrylo Hrechykhin <khrechykhin@microsoft.com>
Date: Thu, 6 Oct 2022 18:30:53 +0200
Subject: fix: on-screen-keyboard hides on input blur in webview
Changes introduced by this patch fix issue where OSK does not hide on
input rendered inside webview is blurred. This patch should be removed
when proper fix in chromium repo is available.
Note: the issue still occurs if input rendered in webview blurred due
to touch outside of webview. It is caused by webview implementation
details. Specificaly due to webview has its own tree nodes and focused
node does not change in this case.
chromium-bug: https://crbug.com/1369605
diff --git a/content/browser/renderer_host/render_widget_host_view_child_frame.cc b/content/browser/renderer_host/render_widget_host_view_child_frame.cc
index 4e6d62be68d59c8a49159fda4d1e68f101a6f0a3..cfd5a01ea84a1f454a5172da3e96e66a50c82939 100644
--- a/content/browser/renderer_host/render_widget_host_view_child_frame.cc
+++ b/content/browser/renderer_host/render_widget_host_view_child_frame.cc
@@ -992,6 +992,12 @@ RenderWidgetHostViewChildFrame::DidUpdateVisualProperties(
return viz::ScopedSurfaceIdAllocator(std::move(allocation_task));
}
+void RenderWidgetHostViewChildFrame::FocusedNodeChanged(
+ bool is_editable_node,
+ const gfx::Rect& node_bounds_in_screen) {
+ NOTREACHED();
+}
+
ui::TextInputType RenderWidgetHostViewChildFrame::GetTextInputType() const {
if (!text_input_manager_)
return ui::TEXT_INPUT_TYPE_NONE;
diff --git a/content/browser/renderer_host/render_widget_host_view_child_frame.h b/content/browser/renderer_host/render_widget_host_view_child_frame.h
index 70b151bcb8e3b1964d316bf2e169dbe0f28f24c7..c3857298974a0c2761efcd3924587607997e3117 100644
--- a/content/browser/renderer_host/render_widget_host_view_child_frame.h
+++ b/content/browser/renderer_host/render_widget_host_view_child_frame.h
@@ -181,6 +181,8 @@ class CONTENT_EXPORT RenderWidgetHostViewChildFrame
void DisableAutoResize(const gfx::Size& new_size) override;
viz::ScopedSurfaceIdAllocator DidUpdateVisualProperties(
const cc::RenderFrameMetadata& metadata) override;
+ void FocusedNodeChanged(bool is_editable_node,
+ const gfx::Rect& node_bounds_in_screen) override;
// RenderFrameMetadataProvider::Observer implementation.
void OnRenderFrameMetadataChangedBeforeActivation(
diff --git a/content/browser/web_contents/web_contents_impl.cc b/content/browser/web_contents/web_contents_impl.cc
index 74993d461cbd0885a709cf8b663b9c69650aa3cf..940045d9bbb62676811f55f5d30a93a352f43ede 100644
--- a/content/browser/web_contents/web_contents_impl.cc
+++ b/content/browser/web_contents/web_contents_impl.cc
@@ -7928,7 +7928,7 @@ void WebContentsImpl::OnFocusedElementChangedInFrame(
"WebContentsImpl::OnFocusedElementChangedInFrame",
"render_frame_host", frame);
RenderWidgetHostViewBase* root_view =
- static_cast<RenderWidgetHostViewBase*>(GetRenderWidgetHostView());
+ static_cast<RenderWidgetHostViewBase*>(GetTopLevelRenderWidgetHostView());
if (!root_view || !frame->GetView())
return;
// Convert to screen coordinates from window coordinates by adding the

View File

@@ -49,3 +49,4 @@ fix_override_createjob_in_node_platform.patch
buffer_fix_atob_input_validation.patch
v8_api_advance_api_deprecation.patch
enable_-wunqualified-std-cast-call.patch
fix_expose_the_built-in_electron_module_via_the_esm_loader.patch

View File

@@ -0,0 +1,87 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Samuel Attard <sattard@salesforce.com>
Date: Thu, 6 Oct 2022 04:09:16 -0700
Subject: fix: expose the built-in electron module via the ESM loader
This allows usage of `import { app } from 'electron'` and `import('electron')` natively in the browser + non-sandboxed renderer
diff --git a/lib/internal/modules/esm/get_format.js b/lib/internal/modules/esm/get_format.js
index 5ae0e17dcfb5e24a1a117c33c4d42891686e693f..619fe6cef3b02eb575410225f41d3e7d51f37b93 100644
--- a/lib/internal/modules/esm/get_format.js
+++ b/lib/internal/modules/esm/get_format.js
@@ -31,6 +31,7 @@ const protocolHandlers = ObjectAssign(ObjectCreate(null), {
'http:': getHttpProtocolModuleFormat,
'https:': getHttpProtocolModuleFormat,
'node:'() { return 'builtin'; },
+ 'electron:'() { return 'commonjs'; },
});
function getDataProtocolModuleFormat(parsed) {
diff --git a/lib/internal/modules/esm/resolve.js b/lib/internal/modules/esm/resolve.js
index 3576f75f0a40a64dceb7e2649b344b83ebc04b39..314fbb78931eef154a1e47c655e2d4bafe11bac3 100644
--- a/lib/internal/modules/esm/resolve.js
+++ b/lib/internal/modules/esm/resolve.js
@@ -888,6 +888,8 @@ function parsePackageName(specifier, base) {
return { packageName, packageSubpath, isScoped };
}
+const electronSpecifiers = new SafeSet(['electron', 'electron/main', 'electron/common', 'electron/renderer']);
+
/**
* @param {string} specifier
* @param {string | URL | undefined} base
@@ -898,6 +900,10 @@ function packageResolve(specifier, base, conditions) {
if (NativeModule.canBeRequiredByUsers(specifier))
return new URL('node:' + specifier);
+ if (electronSpecifiers.has(specifier)) {
+ return new URL('electron:electron');
+ }
+
const { packageName, packageSubpath, isScoped } =
parsePackageName(specifier, base);
@@ -1099,7 +1105,7 @@ function checkIfDisallowedImport(specifier, parsed, parsedParentURL) {
function throwIfUnsupportedURLProtocol(url) {
if (url.protocol !== 'file:' && url.protocol !== 'data:' &&
- url.protocol !== 'node:') {
+ url.protocol !== 'node:' && url.protocol !== 'electron:') {
throw new ERR_UNSUPPORTED_ESM_URL_SCHEME(url);
}
}
diff --git a/lib/internal/modules/esm/translators.js b/lib/internal/modules/esm/translators.js
index d7f4c7edec63d3ce500955a37c6eac00e3e524fd..b97cac53365b121f8e232f0085ff166511c3dda3 100644
--- a/lib/internal/modules/esm/translators.js
+++ b/lib/internal/modules/esm/translators.js
@@ -155,7 +155,7 @@ translators.set('commonjs', async function commonjsStrategy(url, source,
if (!cjsParse) await initCJSParse();
const { module, exportNames } = cjsPreparseModuleExports(filename);
- const namesWithDefault = exportNames.has('default') ?
+ const namesWithDefault = filename === 'electron' ? ['default', ...Object.keys(module.exports)] : exportNames.has('default') ?
[...exportNames] : ['default', ...exportNames];
return new ModuleWrap(url, undefined, namesWithDefault, function() {
@@ -174,7 +174,7 @@ translators.set('commonjs', async function commonjsStrategy(url, source,
}
}
- for (const exportName of exportNames) {
+ for (const exportName of namesWithDefault) {
if (!ObjectPrototypeHasOwnProperty(exports, exportName) ||
exportName === 'default')
continue;
diff --git a/lib/internal/url.js b/lib/internal/url.js
index 939374a495856cf2b9c573fa98dc1895eee5e143..c37258ac29e8b7558c1f9a2af7ba6bdd0eab1355 100644
--- a/lib/internal/url.js
+++ b/lib/internal/url.js
@@ -1418,6 +1418,8 @@ function fileURLToPath(path) {
path = new URL(path);
else if (!isURLInstance(path))
throw new ERR_INVALID_ARG_TYPE('path', ['string', 'URL'], path);
+ if (path.protocol === 'electron:')
+ return 'electron';
if (path.protocol !== 'file:')
throw new ERR_INVALID_URL_SCHEME('file');
return isWindows ? getPathFromURLWin32(path) : getPathFromURLPosix(path);

View File

@@ -316,9 +316,6 @@ absl::optional<int> ElectronMainDelegate::BasicStartupComplete() {
::switches::kDisableGpuMemoryBufferCompositorResources);
#endif
content_client_ = std::make_unique<ElectronContentClient>();
SetContentClient(content_client_.get());
return absl::nullopt;
}
@@ -437,6 +434,11 @@ base::StringPiece ElectronMainDelegate::GetBrowserV8SnapshotFilename() {
return ContentMainDelegate::GetBrowserV8SnapshotFilename();
}
content::ContentClient* ElectronMainDelegate::CreateContentClient() {
content_client_ = std::make_unique<ElectronContentClient>();
return content_client_.get();
}
content::ContentBrowserClient*
ElectronMainDelegate::CreateContentBrowserClient() {
browser_client_ = std::make_unique<ElectronBrowserClient>();

View File

@@ -38,6 +38,7 @@ class ElectronMainDelegate : public content::ContentMainDelegate {
void PreSandboxStartup() override;
void SandboxInitialized(const std::string& process_type) override;
absl::optional<int> PreBrowserMain() override;
content::ContentClient* CreateContentClient() override;
content::ContentBrowserClient* CreateContentBrowserClient() override;
content::ContentGpuClient* CreateContentGpuClient() override;
content::ContentRendererClient* CreateContentRendererClient() override;

View File

@@ -4,6 +4,7 @@
#include "shell/browser/api/electron_api_desktop_capturer.h"
#include <map>
#include <memory>
#include <utility>
#include <vector>
@@ -24,12 +25,125 @@
#include "third_party/webrtc/modules/desktop_capture/desktop_capture_options.h"
#include "third_party/webrtc/modules/desktop_capture/desktop_capturer.h"
#if defined(USE_OZONE)
#include "ui/ozone/buildflags.h"
#if BUILDFLAG(OZONE_PLATFORM_X11)
#define USE_OZONE_PLATFORM_X11
#endif
#endif
#if BUILDFLAG(IS_WIN)
#include "third_party/webrtc/modules/desktop_capture/win/dxgi_duplicator_controller.h"
#include "third_party/webrtc/modules/desktop_capture/win/screen_capturer_win_directx.h"
#include "ui/display/win/display_info.h"
#elif BUILDFLAG(IS_LINUX)
#if defined(USE_OZONE_PLATFORM_X11)
#include "base/logging.h"
#include "ui/base/x/x11_display_util.h"
#include "ui/base/x/x11_util.h"
#include "ui/display/util/edid_parser.h" // nogncheck
#include "ui/gfx/x/randr.h"
#include "ui/gfx/x/x11_atom_cache.h"
#include "ui/gfx/x/xproto_util.h"
#endif // defined(USE_OZONE_PLATFORM_X11)
#endif // BUILDFLAG(IS_WIN)
#if BUILDFLAG(IS_LINUX)
// Private function in ui/base/x/x11_display_util.cc
std::map<x11::RandR::Output, int> GetMonitors(int version,
x11::RandR* randr,
x11::Window window) {
std::map<x11::RandR::Output, int> output_to_monitor;
if (version >= 105) {
if (auto reply = randr->GetMonitors({window}).Sync()) {
for (size_t monitor = 0; monitor < reply->monitors.size(); monitor++) {
for (x11::RandR::Output output : reply->monitors[monitor].outputs)
output_to_monitor[output] = monitor;
}
}
}
return output_to_monitor;
}
// Get the EDID data from the |output| and stores to |edid|.
// Private function in ui/base/x/x11_display_util.cc
std::vector<uint8_t> GetEDIDProperty(x11::RandR* randr,
x11::RandR::Output output) {
constexpr const char kRandrEdidProperty[] = "EDID";
auto future = randr->GetOutputProperty(x11::RandR::GetOutputPropertyRequest{
.output = output,
.property = x11::GetAtom(kRandrEdidProperty),
.long_length = 128});
auto response = future.Sync();
std::vector<uint8_t> edid;
if (response && response->format == 8 && response->type != x11::Atom::None)
edid = std::move(response->data);
return edid;
}
// Find the mapping from monitor name atom to the display identifier
// that the screen API uses. Based on the logic in BuildDisplaysFromXRandRInfo
// in ui/base/x/x11_display_util.cc
std::map<int32_t, uint32_t> MonitorAtomIdToDisplayId() {
auto* connection = x11::Connection::Get();
auto& randr = connection->randr();
auto x_root_window = ui::GetX11RootWindow();
int version = ui::GetXrandrVersion();
std::map<int32_t, uint32_t> monitor_atom_to_display;
auto resources = randr.GetScreenResourcesCurrent({x_root_window}).Sync();
if (!resources) {
LOG(ERROR) << "XRandR returned no displays; don't know how to map ids";
return monitor_atom_to_display;
}
std::map<x11::RandR::Output, int> output_to_monitor =
GetMonitors(version, &randr, x_root_window);
auto monitors_reply = randr.GetMonitors({x_root_window}).Sync();
for (size_t i = 0; i < resources->outputs.size(); i++) {
x11::RandR::Output output_id = resources->outputs[i];
auto output_info =
randr.GetOutputInfo({output_id, resources->config_timestamp}).Sync();
if (!output_info)
continue;
if (output_info->connection != x11::RandR::RandRConnection::Connected)
continue;
if (output_info->crtc == static_cast<x11::RandR::Crtc>(0))
continue;
auto crtc =
randr.GetCrtcInfo({output_info->crtc, resources->config_timestamp})
.Sync();
if (!crtc)
continue;
display::EdidParser edid_parser(
GetEDIDProperty(&randr, static_cast<x11::RandR::Output>(output_id)));
auto output_32 = static_cast<uint32_t>(output_id);
int64_t display_id =
output_32 > 0xff ? 0 : edid_parser.GetIndexBasedDisplayId(output_32);
// It isn't ideal, but if we can't parse the EDID data, fall back on the
// display number.
if (!display_id)
display_id = i;
// Find the mapping between output identifier and the monitor name atom
// Note this isn't the atom string, but the numeric atom identifier,
// since this is what the WebRTC system uses as the display identifier
auto output_monitor_iter = output_to_monitor.find(output_id);
if (output_monitor_iter != output_to_monitor.end()) {
x11::Atom atom =
monitors_reply->monitors[output_monitor_iter->second].name;
monitor_atom_to_display[static_cast<int32_t>(atom)] = display_id;
}
}
return monitor_atom_to_display;
}
#endif
namespace gin {
template <>
@@ -178,10 +292,22 @@ void DesktopCapturer::UpdateSourcesList(DesktopMediaList* list) {
for (auto& source : screen_sources) {
source.display_id = base::NumberToString(source.media_list_source.id.id);
}
#elif BUILDFLAG(IS_LINUX)
#if defined(USE_OZONE_PLATFORM_X11)
// On Linux, with X11, the source id is the numeric value of the
// display name atom and the display id is either the EDID or the
// loop index when that display was found (see
// BuildDisplaysFromXRandRInfo in ui/base/x/x11_display_util.cc)
std::map<int32_t, uint32_t> monitor_atom_to_display_id =
MonitorAtomIdToDisplayId();
for (auto& source : screen_sources) {
auto display_id_iter =
monitor_atom_to_display_id.find(source.media_list_source.id.id);
if (display_id_iter != monitor_atom_to_display_id.end())
source.display_id = base::NumberToString(display_id_iter->second);
}
#endif // defined(USE_OZONE_PLATFORM_X11)
#endif // BUILDFLAG(IS_WIN)
// TODO(ajmacd): Add Linux support. The IDs across APIs differ but Chrome
// only supports capturing the entire desktop on Linux. Revisit this if
// individual screen support is added.
std::move(screen_sources.begin(), screen_sources.end(),
std::back_inserter(captured_sources_));
}

View File

@@ -2821,12 +2821,12 @@ v8::Local<v8::Promise> WebContents::PrintToPDF(const base::Value& settings) {
settings.GetDict().FindBool("displayHeaderFooter");
auto print_background = settings.GetDict().FindBool("shouldPrintBackgrounds");
auto scale = settings.GetDict().FindDouble("scale");
auto paper_width = settings.GetDict().FindInt("paperWidth");
auto paper_height = settings.GetDict().FindInt("paperHeight");
auto margin_top = settings.GetDict().FindIntByDottedPath("margins.top");
auto margin_bottom = settings.GetDict().FindIntByDottedPath("margins.bottom");
auto margin_left = settings.GetDict().FindIntByDottedPath("margins.left");
auto margin_right = settings.GetDict().FindIntByDottedPath("margins.right");
auto paper_width = settings.GetDict().FindDouble("paperWidth");
auto paper_height = settings.GetDict().FindDouble("paperHeight");
auto margin_top = settings.GetDict().FindDouble("marginTop");
auto margin_bottom = settings.GetDict().FindDouble("marginBottom");
auto margin_left = settings.GetDict().FindDouble("marginLeft");
auto margin_right = settings.GetDict().FindDouble("marginRight");
auto page_ranges = *settings.GetDict().FindString("pageRanges");
auto header_template = *settings.GetDict().FindString("headerTemplate");
auto footer_template = *settings.GetDict().FindString("footerTemplate");
@@ -3435,6 +3435,10 @@ content::RenderFrameHost* WebContents::MainFrame() {
return web_contents()->GetPrimaryMainFrame();
}
content::RenderFrameHost* WebContents::Opener() {
return web_contents()->GetOpener();
}
void WebContents::NotifyUserActivation() {
content::RenderFrameHost* frame = web_contents()->GetPrimaryMainFrame();
if (frame)
@@ -4045,6 +4049,7 @@ v8::Local<v8::ObjectTemplate> WebContents::FillObjectTemplate(
.SetProperty("devToolsWebContents", &WebContents::DevToolsWebContents)
.SetProperty("debugger", &WebContents::Debugger)
.SetProperty("mainFrame", &WebContents::MainFrame)
.SetProperty("opener", &WebContents::Opener)
.Build();
}
@@ -4159,6 +4164,7 @@ namespace {
using electron::api::GetAllWebContents;
using electron::api::WebContents;
using electron::api::WebFrameMain;
gin::Handle<WebContents> WebContentsFromID(v8::Isolate* isolate, int32_t id) {
WebContents* contents = WebContents::FromID(id);
@@ -4166,6 +4172,15 @@ gin::Handle<WebContents> WebContentsFromID(v8::Isolate* isolate, int32_t id) {
: gin::Handle<WebContents>();
}
gin::Handle<WebContents> WebContentsFromFrame(v8::Isolate* isolate,
WebFrameMain* web_frame) {
content::RenderFrameHost* rfh = web_frame->render_frame_host();
content::WebContents* source = content::WebContents::FromRenderFrameHost(rfh);
WebContents* contents = WebContents::From(source);
return contents ? gin::CreateHandle(isolate, contents)
: gin::Handle<WebContents>();
}
gin::Handle<WebContents> WebContentsFromDevToolsTargetID(
v8::Isolate* isolate,
std::string target_id) {
@@ -4194,6 +4209,7 @@ void Initialize(v8::Local<v8::Object> exports,
gin_helper::Dictionary dict(isolate, exports);
dict.Set("WebContents", WebContents::GetConstructor(context));
dict.SetMethod("fromId", &WebContentsFromID);
dict.SetMethod("fromFrame", &WebContentsFromFrame);
dict.SetMethod("fromDevToolsTargetId", &WebContentsFromDevToolsTargetID);
dict.SetMethod("getAllWebContents", &GetAllWebContentsAsV8);
}

View File

@@ -332,6 +332,7 @@ class WebContents : public ExclusiveAccessContext,
v8::Local<v8::Value> DevToolsWebContents(v8::Isolate* isolate);
v8::Local<v8::Value> Debugger(v8::Isolate* isolate);
content::RenderFrameHost* MainFrame();
content::RenderFrameHost* Opener();
WebContentsZoomController* GetZoomController() { return zoom_controller_; }

View File

@@ -50,8 +50,8 @@ END
//
VS_VERSION_INFO VERSIONINFO
FILEVERSION 21,0,1,0
PRODUCTVERSION 21,0,1,0
FILEVERSION 21,1,1,0
PRODUCTVERSION 21,1,1,0
FILEFLAGSMASK 0x3fL
#ifdef _DEBUG
FILEFLAGS 0x1L
@@ -68,12 +68,12 @@ BEGIN
BEGIN
VALUE "CompanyName", "GitHub, Inc."
VALUE "FileDescription", "Electron"
VALUE "FileVersion", "21.0.1"
VALUE "FileVersion", "21.1.1"
VALUE "InternalName", "electron.exe"
VALUE "LegalCopyright", "Copyright (C) 2015 GitHub, Inc. All rights reserved."
VALUE "OriginalFilename", "electron.exe"
VALUE "ProductName", "Electron"
VALUE "ProductVersion", "21.0.1"
VALUE "ProductVersion", "21.1.1"
VALUE "SquirrelAwareVersion", "1"
END
END

View File

@@ -20,7 +20,8 @@
- (NSDragOperation)draggingSession:(NSDraggingSession*)session
sourceOperationMaskForDraggingContext:(NSDraggingContext)context {
return NSDragOperationEvery;
return context == NSDraggingContextOutsideApplication ? NSDragOperationCopy
: NSDragOperationEvery;
}
@end
@@ -70,7 +71,7 @@ void DragFileItems(const std::vector<base::FilePath>& files,
NSEvent* dragEvent =
[NSEvent mouseEventWithType:NSEventTypeLeftMouseDragged
location:position
modifierFlags:NSEventMaskLeftMouseDragged
modifierFlags:0
timestamp:eventTime
windowNumber:[[native_view window] windowNumber]
context:nil

View File

@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Modified from chrome/browser/ui/views/frame/windows_10_caption_button.cc
// Modified from chrome/browser/ui/views/frame/windows_caption_button.cc
#include "shell/browser/ui/views/win_caption_button.h"

View File

@@ -25,7 +25,7 @@ void DrawRect(gfx::Canvas* canvas,
void DrawRoundRect(gfx::Canvas* canvas,
const gfx::Rect& rect,
int radius,
float radius,
const cc::PaintFlags& flags) {
gfx::RectF rect_f(rect);
float stroke_half_width = flags.getStrokeWidth() / 2;
@@ -74,7 +74,7 @@ void WinIconPainter::PaintMaximizeIcon(gfx::Canvas* canvas,
void WinIconPainter::PaintRestoreIcon(gfx::Canvas* canvas,
const gfx::Rect& symbol_rect,
const cc::PaintFlags& flags) {
const int separation = std::floor(2 * canvas->image_scale());
const int separation = base::ClampFloor(2 * canvas->image_scale());
gfx::Rect icon_rect = symbol_rect;
icon_rect.Inset(gfx::Insets::TLBR(separation, 0, 0, separation));
@@ -113,14 +113,14 @@ void Win11IconPainter::PaintMaximizeIcon(gfx::Canvas* canvas,
cc::PaintFlags paint_flags = flags;
paint_flags.setAntiAlias(true);
const float corner_radius = 2 * canvas->image_scale();
const float corner_radius = canvas->image_scale();
DrawRoundRect(canvas, symbol_rect, corner_radius, flags);
}
void Win11IconPainter::PaintRestoreIcon(gfx::Canvas* canvas,
const gfx::Rect& symbol_rect,
const cc::PaintFlags& flags) {
const int separation = std::floor(2 * canvas->image_scale());
const int separation = base::ClampFloor(2 * canvas->image_scale());
gfx::Rect icon_rect = symbol_rect;
icon_rect.Inset(gfx::Insets::TLBR(separation, 0, 0, separation));
@@ -128,14 +128,11 @@ void Win11IconPainter::PaintRestoreIcon(gfx::Canvas* canvas,
paint_flags.setAntiAlias(true);
// Bottom left ("in front") rounded square.
const float bottom_rect_radius = 1 * canvas->image_scale();
const float bottom_rect_radius = canvas->image_scale();
DrawRoundRect(canvas, icon_rect, bottom_rect_radius, flags);
// Top right ("behind") top+right edges of rounded square (2.5x).
icon_rect.Offset(separation, -separation);
// Apply inset to left+bottom edges since we don't draw arcs for those edges
constexpr int top_rect_inset = 1;
icon_rect.Inset(gfx::Insets::TLBR(0, top_rect_inset, top_rect_inset, 0));
const float top_rect_radius = 2.5f * canvas->image_scale();
DrawRoundRectEdges(canvas, icon_rect, top_rect_radius, flags);

View File

@@ -492,19 +492,22 @@ node::Environment* NodeBindings::CreateEnvironment(
flags |= node::EnvironmentFlags::kNoStartDebugSignalHandler;
}
v8::TryCatch try_catch(isolate);
env = node::CreateEnvironment(
isolate_data_, context, args, exec_args,
static_cast<node::EnvironmentFlags::Flags>(flags));
{
v8::TryCatch try_catch(isolate);
env = node::CreateEnvironment(
isolate_data_, context, args, exec_args,
static_cast<node::EnvironmentFlags::Flags>(flags));
if (try_catch.HasCaught()) {
std::string err_msg =
"Failed to initialize node environment in process: " + process_type;
v8::Local<v8::Message> message = try_catch.Message();
std::string msg;
if (!message.IsEmpty() && gin::ConvertFromV8(isolate, message->Get(), &msg))
err_msg += " , with error: " + msg;
LOG(ERROR) << err_msg;
if (try_catch.HasCaught()) {
std::string err_msg =
"Failed to initialize node environment in process: " + process_type;
v8::Local<v8::Message> message = try_catch.Message();
std::string msg;
if (!message.IsEmpty() &&
gin::ConvertFromV8(isolate, message->Get(), &msg))
err_msg += " , with error: " + msg;
LOG(ERROR) << err_msg;
}
}
DCHECK(env);

View File

@@ -6,7 +6,7 @@ import * as http from 'http';
import { BrowserWindow, ipcMain, webContents, session, WebContents, app, BrowserView } from 'electron/main';
import { emittedOnce } from './events-helpers';
import { closeAllWindows } from './window-helpers';
import { ifdescribe, delay, defer } from './spec-helpers';
import { ifdescribe, delay, defer, waitUntil } from './spec-helpers';
const pdfjs = require('pdfjs-dist');
const fixturesPath = path.resolve(__dirname, '..', 'spec', 'fixtures');
@@ -46,6 +46,28 @@ describe('webContents module', () => {
});
});
describe('fromFrame()', () => {
it('returns WebContents for mainFrame', () => {
const contents = (webContents as any).create() as WebContents;
expect(webContents.fromFrame(contents.mainFrame)).to.equal(contents);
});
it('returns undefined for disposed frame', async () => {
const contents = (webContents as any).create() as WebContents;
const { mainFrame } = contents;
contents.destroy();
await waitUntil(() => typeof webContents.fromFrame(mainFrame) === 'undefined');
});
it('throws when passing invalid argument', async () => {
let errored = false;
try {
webContents.fromFrame({} as any);
} catch {
errored = true;
}
expect(errored).to.be.true();
});
});
describe('fromDevToolsTargetId()', () => {
it('returns WebContents for attached DevTools target', async () => {
const w = new BrowserWindow({ show: false });
@@ -1281,6 +1303,54 @@ describe('webContents module', () => {
});
});
describe('opener api', () => {
afterEach(closeAllWindows);
it('can get opener with window.open()', async () => {
const w = new BrowserWindow({ show: false, webPreferences: { sandbox: true } });
await w.loadURL('about:blank');
const childPromise = emittedOnce(w.webContents, 'did-create-window');
w.webContents.executeJavaScript('window.open("about:blank")', true);
const [childWindow] = await childPromise;
expect(childWindow.webContents.opener).to.equal(w.webContents.mainFrame);
});
it('has no opener when using "noopener"', async () => {
const w = new BrowserWindow({ show: false, webPreferences: { sandbox: true } });
await w.loadURL('about:blank');
const childPromise = emittedOnce(w.webContents, 'did-create-window');
w.webContents.executeJavaScript('window.open("about:blank", undefined, "noopener")', true);
const [childWindow] = await childPromise;
expect(childWindow.webContents.opener).to.be.null();
});
it('can get opener with a[target=_blank][rel=opener]', async () => {
const w = new BrowserWindow({ show: false, webPreferences: { sandbox: true } });
await w.loadURL('about:blank');
const childPromise = emittedOnce(w.webContents, 'did-create-window');
w.webContents.executeJavaScript(`(function() {
const a = document.createElement('a');
a.target = '_blank';
a.rel = 'opener';
a.href = 'about:blank';
a.click();
}())`, true);
const [childWindow] = await childPromise;
expect(childWindow.webContents.opener).to.equal(w.webContents.mainFrame);
});
it('has no opener with a[target=_blank][rel=noopener]', async () => {
const w = new BrowserWindow({ show: false, webPreferences: { sandbox: true } });
await w.loadURL('about:blank');
const childPromise = emittedOnce(w.webContents, 'did-create-window');
w.webContents.executeJavaScript(`(function() {
const a = document.createElement('a');
a.target = '_blank';
a.rel = 'noopener';
a.href = 'about:blank';
a.click();
}())`, true);
const [childWindow] = await childPromise;
expect(childWindow.webContents.opener).to.be.null();
});
});
describe('render view deleted events', () => {
let server: http.Server;
let serverUrl: string;

View File

@@ -183,4 +183,16 @@ describe('modules support', () => {
});
});
});
describe('esm', () => {
it('can load the built-in "electron" module via ESM import', async () => {
await expect(import('electron')).to.eventually.be.ok();
});
it('the built-in "electron" module loaded via ESM import has the same exports as the CJS module', async () => {
const esmElectron = await import('electron');
const cjsElectron = require('electron');
expect(Object.keys(esmElectron)).to.deep.equal(Object.keys(cjsElectron));
});
});
});