mirror of
https://github.com/electron/electron.git
synced 2026-02-19 03:14:51 -05:00
Compare commits
32 Commits
roller/chr
...
v24.0.0-al
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
03285c8faf | ||
|
|
f02d262d32 | ||
|
|
1ff589976c | ||
|
|
9e3a44edf7 | ||
|
|
71803a5dd4 | ||
|
|
f72a812db6 | ||
|
|
4c368be0a9 | ||
|
|
a6a8622257 | ||
|
|
9be3acd24c | ||
|
|
886a5032cf | ||
|
|
b05d385f4a | ||
|
|
8edfa03ac7 | ||
|
|
b156ffb25a | ||
|
|
a1255ae20f | ||
|
|
de5ee7e60e | ||
|
|
85802682b5 | ||
|
|
f04ad15b65 | ||
|
|
38ca7c0860 | ||
|
|
309349a020 | ||
|
|
f3d50c674c | ||
|
|
8e74a37505 | ||
|
|
426c23446c | ||
|
|
52adfe2137 | ||
|
|
4911476787 | ||
|
|
7a62411ad1 | ||
|
|
99d648faaa | ||
|
|
91776c5484 | ||
|
|
1a48e36313 | ||
|
|
97c66e5985 | ||
|
|
4ce69207b0 | ||
|
|
cf4f6285c8 | ||
|
|
253a60f8ae |
@@ -51,7 +51,7 @@ jobs:
|
||||
steps:
|
||||
- checkout
|
||||
- path-filtering/set-parameters:
|
||||
base-revision: main
|
||||
base-revision: origin/24-x-y
|
||||
mapping: |
|
||||
^((?!docs/).)*$ run-build-mac true
|
||||
^((?!docs/).)*$ run-build-linux true
|
||||
|
||||
@@ -1054,6 +1054,8 @@ commands:
|
||||
parameters:
|
||||
artifact-key:
|
||||
type: string
|
||||
build-type:
|
||||
type: string
|
||||
build-nonproprietary-ffmpeg:
|
||||
type: boolean
|
||||
default: true
|
||||
@@ -1061,6 +1063,7 @@ commands:
|
||||
- *step-gn-gen-default
|
||||
- ninja_build_electron:
|
||||
clean-prebuilt-snapshot: false
|
||||
build-type: << parameters.build-type >>
|
||||
- *step-maybe-electron-dist-strip
|
||||
- step-electron-dist-build:
|
||||
additional-targets: shell_browser_ui_unittests third_party/electron_node:headers third_party/electron_node:overlapped-checker electron:hunspell_dictionaries_zip
|
||||
@@ -1222,9 +1225,12 @@ commands:
|
||||
clean-prebuilt-snapshot:
|
||||
type: boolean
|
||||
default: true
|
||||
build-type:
|
||||
type: string
|
||||
|
||||
steps:
|
||||
- run:
|
||||
name: Electron build
|
||||
name: Electron << parameters.build-type >> build
|
||||
no_output_timeout: 60m
|
||||
command: |
|
||||
cd src
|
||||
@@ -1292,6 +1298,8 @@ commands:
|
||||
default: true
|
||||
artifact-key:
|
||||
type: string
|
||||
build-type:
|
||||
type: string
|
||||
after-build-and-save:
|
||||
type: steps
|
||||
default: []
|
||||
@@ -1418,6 +1426,7 @@ commands:
|
||||
steps:
|
||||
- build_and_save_artifacts:
|
||||
artifact-key: << parameters.artifact-key >>
|
||||
build-type: << parameters.build-type >>
|
||||
build-nonproprietary-ffmpeg: << parameters.build-nonproprietary-ffmpeg >>
|
||||
- steps: << parameters.after-build-and-save >>
|
||||
|
||||
@@ -1563,6 +1572,8 @@ commands:
|
||||
checkout:
|
||||
type: boolean
|
||||
default: true
|
||||
build-type:
|
||||
type: string
|
||||
steps:
|
||||
- when:
|
||||
condition: << parameters.attach >>
|
||||
@@ -1594,7 +1605,8 @@ commands:
|
||||
- *step-gn-gen-default
|
||||
|
||||
# Electron app
|
||||
- ninja_build_electron
|
||||
- ninja_build_electron:
|
||||
build-type: << parameters.build-type >>
|
||||
- *step-show-goma-stats
|
||||
- *step-maybe-generate-breakpad-symbols
|
||||
- *step-maybe-electron-dist-strip
|
||||
@@ -1657,6 +1669,7 @@ jobs:
|
||||
save-git-cache: true
|
||||
checkout-to-create-src-cache: true
|
||||
artifact-key: 'nil'
|
||||
build-type: 'nil'
|
||||
|
||||
mac-checkout:
|
||||
executor:
|
||||
@@ -1675,6 +1688,7 @@ jobs:
|
||||
persist-checkout: true
|
||||
restore-src-cache: false
|
||||
artifact-key: 'nil'
|
||||
build-type: 'nil'
|
||||
|
||||
mac-make-src-cache:
|
||||
executor:
|
||||
@@ -1693,6 +1707,7 @@ jobs:
|
||||
save-git-cache: true
|
||||
checkout-to-create-src-cache: true
|
||||
artifact-key: 'nil'
|
||||
build-type: 'nil'
|
||||
|
||||
# Layer 2: Builds.
|
||||
linux-x64-testing:
|
||||
@@ -1710,6 +1725,7 @@ jobs:
|
||||
checkout: false
|
||||
checkout-and-assume-cache: true
|
||||
artifact-key: 'linux-x64'
|
||||
build-type: 'Linux'
|
||||
|
||||
linux-x64-testing-asan:
|
||||
executor:
|
||||
@@ -1728,6 +1744,7 @@ jobs:
|
||||
checkout: true
|
||||
build-nonproprietary-ffmpeg: false
|
||||
artifact-key: 'linux-x64-asan'
|
||||
build-type: 'Linux'
|
||||
|
||||
linux-x64-testing-no-run-as-node:
|
||||
executor:
|
||||
@@ -1744,6 +1761,7 @@ jobs:
|
||||
persist: false
|
||||
checkout: true
|
||||
artifact-key: 'linux-x64-no-run-as-node'
|
||||
build-type: 'Linux'
|
||||
|
||||
linux-x64-testing-gn-check:
|
||||
executor:
|
||||
@@ -1775,6 +1793,7 @@ jobs:
|
||||
- electron-publish:
|
||||
attach: false
|
||||
checkout: true
|
||||
build-type: 'Linux'
|
||||
|
||||
|
||||
linux-arm-testing:
|
||||
@@ -1795,6 +1814,7 @@ jobs:
|
||||
checkout: false
|
||||
checkout-and-assume-cache: true
|
||||
artifact-key: 'linux-arm'
|
||||
build-type: 'Linux ARM'
|
||||
|
||||
linux-arm-publish:
|
||||
executor:
|
||||
@@ -1819,6 +1839,7 @@ jobs:
|
||||
- electron-publish:
|
||||
attach: false
|
||||
checkout: true
|
||||
build-type: 'Linux ARM'
|
||||
|
||||
linux-arm64-testing:
|
||||
executor:
|
||||
@@ -1838,6 +1859,7 @@ jobs:
|
||||
checkout: false
|
||||
checkout-and-assume-cache: true
|
||||
artifact-key: 'linux-arm64'
|
||||
build-type: 'Linux ARM64'
|
||||
|
||||
linux-arm64-testing-gn-check:
|
||||
executor:
|
||||
@@ -1872,6 +1894,7 @@ jobs:
|
||||
- electron-publish:
|
||||
attach: false
|
||||
checkout: true
|
||||
build-type: 'Linux ARM64'
|
||||
|
||||
osx-testing-x64:
|
||||
executor:
|
||||
@@ -1890,6 +1913,7 @@ jobs:
|
||||
checkout-and-assume-cache: true
|
||||
attach: true
|
||||
artifact-key: 'darwin-x64'
|
||||
build-type: 'Darwin'
|
||||
after-build-and-save:
|
||||
- run:
|
||||
name: Configuring MAS build
|
||||
@@ -1900,6 +1924,7 @@ jobs:
|
||||
rm -rf src/out/Default/Electron*.app
|
||||
- build_and_save_artifacts:
|
||||
artifact-key: 'mas-x64'
|
||||
build-type: 'MAS'
|
||||
after-persist:
|
||||
- persist_to_workspace:
|
||||
root: .
|
||||
@@ -1936,6 +1961,7 @@ jobs:
|
||||
- electron-publish:
|
||||
attach: true
|
||||
checkout: false
|
||||
build-type: 'Darwin'
|
||||
|
||||
osx-publish-arm64:
|
||||
executor:
|
||||
@@ -1958,6 +1984,7 @@ jobs:
|
||||
- electron-publish:
|
||||
attach: true
|
||||
checkout: false
|
||||
build-type: 'Darwin ARM64'
|
||||
|
||||
osx-testing-arm64:
|
||||
executor:
|
||||
@@ -1978,6 +2005,7 @@ jobs:
|
||||
checkout-and-assume-cache: true
|
||||
attach: true
|
||||
artifact-key: 'darwin-arm64'
|
||||
build-type: 'Darwin ARM64'
|
||||
after-build-and-save:
|
||||
- run:
|
||||
name: Configuring MAS build
|
||||
@@ -1988,6 +2016,7 @@ jobs:
|
||||
rm -rf src/out/Default/Electron*.app
|
||||
- build_and_save_artifacts:
|
||||
artifact-key: 'mas-arm64'
|
||||
build-type: 'MAS ARM64'
|
||||
after-persist:
|
||||
- persist_to_workspace:
|
||||
root: .
|
||||
@@ -2014,6 +2043,7 @@ jobs:
|
||||
- electron-publish:
|
||||
attach: true
|
||||
checkout: false
|
||||
build-type: 'MAS'
|
||||
|
||||
mas-publish-arm64:
|
||||
executor:
|
||||
@@ -2036,6 +2066,7 @@ jobs:
|
||||
- electron-publish:
|
||||
attach: true
|
||||
checkout: false
|
||||
build-type: 'MAS ARM64'
|
||||
|
||||
# Layer 3: Tests.
|
||||
linux-x64-testing-tests:
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
|
||||
version: 1.0.{build}
|
||||
build_cloud: electronhq-16-core
|
||||
image: e-110.0.5451.0
|
||||
image: e-111.0.5560.0-node18
|
||||
environment:
|
||||
GIT_CACHE_PATH: C:\Users\appveyor\libcc_cache
|
||||
ELECTRON_OUT_DIR: Default
|
||||
@@ -16,22 +16,58 @@ environment:
|
||||
GOMA_FALLBACK_ON_AUTH_FAILURE: true
|
||||
DEPOT_TOOLS_WIN_TOOLCHAIN: 0
|
||||
PYTHONIOENCODING: UTF-8
|
||||
# Uncomment these lines and set APPVEYOR_RDP_PASSWORD in project settings to enable RDP before bake begins
|
||||
# install:
|
||||
# - ps: $blockRdp = $true; iex ((new-object net.webclient).DownloadString('https://raw.githubusercontent.com/appveyor/ci/master/scripts/enable-rdp.ps1'))
|
||||
|
||||
# The following lines are needed when baking from a completely new image (eg MicrosoftWindowsServer:WindowsServer:2019-Datacenter:latest via image: base-windows-server2019)
|
||||
# init:
|
||||
# - ps: $blockRdp = $true; iex ((new-object net.webclient).DownloadString('https://raw.githubusercontent.com/appveyor/ci/master/scripts/enable-rdp.ps1'))
|
||||
# - appveyor version
|
||||
# - ps: $ErrorActionPreference = 'Stop'
|
||||
# - ps: 'Write-Host "OS Build: $((Get-CimInstance Win32_OperatingSystem).BuildNumber)"'
|
||||
|
||||
# clone_folder: '%USERPROFILE%\image-bake-scripts'
|
||||
|
||||
# clone_script:
|
||||
# - ps: Invoke-WebRequest "https://github.com/appveyor/build-images/archive/1f90d94e74c8243c909a09b994e527584dfcb838.zip" -OutFile "$env:temp\scripts.zip"
|
||||
# - ps: Expand-Archive -Path "$env:temp\scripts.zip" -DestinationPath "$env:temp\scripts" -Force
|
||||
# - ps: Copy-Item -Path "$env:temp\scripts\build-images-1f90d94e74c8243c909a09b994e527584dfcb838\scripts\Windows\*" -Destination $env:APPVEYOR_BUILD_FOLDER -Recurse
|
||||
|
||||
build_script:
|
||||
# Uncomment/change the following line if the hard drive/partition size needs to change
|
||||
# - ps: Resize-Partition -DriveLetter C -Size (256GB) # ensure initial partition size
|
||||
# The following lines are needed when baking from a completely new image (eg MicrosoftWindowsServer:WindowsServer:2019-Datacenter:latest via image: base-windows-server2019)
|
||||
# - ps: .\init_server.ps1
|
||||
# - ps: .\extend_system_volume.ps1
|
||||
|
||||
# # Restart VM
|
||||
# - ps: Start-Sleep -s 5; Restart-Computer
|
||||
# - ps: Start-Sleep -s 5
|
||||
|
||||
# - appveyor version
|
||||
# - ps: .\install_path_utils.ps1
|
||||
# - ps: .\install_powershell_core.ps1
|
||||
# - ps: .\install_powershell_get.ps1
|
||||
# - ps: .\install_7zip.ps1
|
||||
# - ps: .\install_chocolatey.ps1
|
||||
# - ps: .\install_webpi.ps1
|
||||
# - ps: .\install_nuget.ps1
|
||||
# - ps: .\install_pstools.ps1
|
||||
|
||||
# - ps: .\install_git.ps1
|
||||
# - ps: .\install_git_lfs.ps1
|
||||
|
||||
# # Restart VM
|
||||
# - ps: Start-Sleep -s 5; Restart-Computer
|
||||
# - ps: Start-Sleep -s 5
|
||||
# END LINES FOR COMPLETELY NEW IMAGE
|
||||
|
||||
- git config --global core.longpaths true
|
||||
- cd ..
|
||||
- ps: >-
|
||||
if (-not (Test-Path -Path .\src)) {
|
||||
New-Item -Path .\src -ItemType Directory
|
||||
if (-not (Test-Path -Path C:\projects\src)) {
|
||||
New-Item -Path C:\projects\src -ItemType Directory
|
||||
}
|
||||
- ps: git clone --depth=1 https://chromium.googlesource.com/chromium/tools/depot_tools.git
|
||||
- cd C:\projects\
|
||||
- git clone -q --branch=%APPVEYOR_REPO_BRANCH% https://github.com/electron/electron.git C:\projects\src\electron
|
||||
- git clone --depth=1 https://chromium.googlesource.com/chromium/tools/depot_tools.git
|
||||
- ps: $env:PATH="$pwd\depot_tools;$env:PATH"
|
||||
- update_depot_tools.bat
|
||||
- ps: Move-Item $env:APPVEYOR_BUILD_FOLDER -Destination src\electron
|
||||
# Uncomment the following line if windows deps change
|
||||
# - src\electron\script\setup-win-for-dev.bat
|
||||
- >-
|
||||
@@ -47,20 +83,25 @@ build_script:
|
||||
- ps: cd ..\..
|
||||
- gclient sync --with_branch_heads --with_tags --nohooks
|
||||
- ps: regsvr32 /s "C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\DIA SDK\bin\amd64\msdia140.dll"
|
||||
- ps: |
|
||||
$env:appveyor_user = "appveyor"
|
||||
|
||||
$env:appveyor_password = [Guid]::NewGuid().ToString('B')
|
||||
# The following lines are needed when baking from a completely new image (eg MicrosoftWindowsServer:WindowsServer:2019-Datacenter:latest via image: base-windows-server2019)
|
||||
# # Restart VM
|
||||
# - ps: Start-Sleep -s 5; Restart-Computer
|
||||
# - ps: Start-Sleep -s 5
|
||||
|
||||
Set-LocalUser -Name $env:appveyor_user -Password (ConvertTo-SecureString -AsPlainText $env:appveyor_password -Force) -PasswordNeverExpires:$true
|
||||
|
||||
iex ((new-object net.webclient).DownloadString('https://raw.githubusercontent.com/appveyor/build-images/master/scripts/Windows/enable_autologon.ps1'))
|
||||
# - cd %USERPROFILE%\image-bake-scripts
|
||||
# - appveyor version
|
||||
# - ps: .\optimize_dotnet_runtime.ps1
|
||||
# - ps: .\disable_windows_background_services.ps1
|
||||
# - ps: .\enforce_windows_firewall.ps1
|
||||
# - ps: .\cleanup_windows.ps1
|
||||
# END LINES FOR COMPLETELY NEW IMAGE
|
||||
on_image_bake:
|
||||
- ps: >-
|
||||
echo "Baking image: $env:APPVEYOR_BAKE_IMAGE at dir $PWD"
|
||||
- ps: Remove-Item -Recurse -Force $pwd\depot_tools
|
||||
- ps: Remove-Item -Recurse -Force $pwd\src\electron
|
||||
- ps: Remove-Item -Recurse -Force C:\projects\depot_tools
|
||||
- ps: Remove-Item -Recurse -Force C:\projects\src\electron
|
||||
# Uncomment these lines and set APPVEYOR_RDP_PASSWORD in project settings to enable RDP after bake is done
|
||||
#on_finish:
|
||||
# - ps: >-
|
||||
# $blockRdp = $true; iex ((new-object net.webclient).DownloadString('https://raw.githubusercontent.com/appveyor/ci/master/scripts/enable-rdp.ps1'))
|
||||
# # on_finish:
|
||||
# - ps: >-
|
||||
# $blockRdp = $true; iex ((new-object net.webclient).DownloadString('https://raw.githubusercontent.com/appveyor/ci/master/scripts/enable-rdp.ps1'))
|
||||
@@ -29,7 +29,7 @@
|
||||
|
||||
version: 1.0.{build}
|
||||
build_cloud: electronhq-16-core
|
||||
image: e-111.0.5518.0
|
||||
image: e-111.0.5560.0-2
|
||||
environment:
|
||||
GIT_CACHE_PATH: C:\Users\appveyor\libcc_cache
|
||||
ELECTRON_OUT_DIR: Default
|
||||
@@ -82,7 +82,7 @@ for:
|
||||
if (Test-Path -Path "$pwd\build-tools") {
|
||||
Remove-Item -Recurse -Force $pwd\build-tools
|
||||
}
|
||||
- ps: git clone --depth=1 https://chromium.googlesource.com/chromium/tools/depot_tools.git
|
||||
- git clone --depth=1 https://chromium.googlesource.com/chromium/tools/depot_tools.git
|
||||
- ps: $env:PATH="$pwd\depot_tools;$env:PATH"
|
||||
- ps: >-
|
||||
if (Test-Path -Path "$pwd\src\electron") {
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
|
||||
version: 1.0.{build}
|
||||
build_cloud: electronhq-16-core
|
||||
image: e-111.0.5560.0
|
||||
image: e-111.0.5560.0-node18
|
||||
environment:
|
||||
GIT_CACHE_PATH: C:\Users\appveyor\libcc_cache
|
||||
ELECTRON_OUT_DIR: Default
|
||||
@@ -80,7 +80,7 @@ for:
|
||||
if (Test-Path -Path "$pwd\build-tools") {
|
||||
Remove-Item -Recurse -Force $pwd\build-tools
|
||||
}
|
||||
- ps: git clone --depth=1 https://chromium.googlesource.com/chromium/tools/depot_tools.git
|
||||
- git clone --depth=1 https://chromium.googlesource.com/chromium/tools/depot_tools.git
|
||||
- ps: $env:PATH="$pwd\depot_tools;$env:PATH"
|
||||
- ps: >-
|
||||
if (Test-Path -Path "$pwd\src\electron") {
|
||||
|
||||
@@ -269,7 +269,7 @@ It creates a new `BrowserWindow` with native properties as set by the `options`.
|
||||
zoom to the width of the screen. This will also affect the behavior when
|
||||
calling `maximize()` directly. Default is `false`.
|
||||
* `tabbingIdentifier` string (optional) _macOS_ - Tab group name, allows
|
||||
opening the window as a native tab on macOS 10.12+. Windows with the same
|
||||
opening the window as a native tab. Windows with the same
|
||||
tabbing identifier will be grouped together. This also adds a native new
|
||||
tab button to your window's tab bar and allows your `app` and window to
|
||||
receive the `new-window-for-tab` event.
|
||||
@@ -1776,7 +1776,7 @@ On macOS it does not remove the focus from the window.
|
||||
|
||||
#### `win.isFocusable()` _macOS_ _Windows_
|
||||
|
||||
Returns whether the window can be focused.
|
||||
Returns `boolean` - Whether the window can be focused.
|
||||
|
||||
#### `win.setParentWindow(parent)`
|
||||
|
||||
@@ -1859,7 +1859,7 @@ frameless window.
|
||||
|
||||
Sets the touchBar layout for the current window. Specifying `null` or
|
||||
`undefined` clears the touch bar. This method only has an effect if the
|
||||
machine has a touch bar and is running on macOS 10.12.1+.
|
||||
machine has a touch bar.
|
||||
|
||||
**Note:** The TouchBar API is currently experimental and may change or be
|
||||
removed in future Electron releases.
|
||||
@@ -1910,7 +1910,7 @@ removed in future Electron releases.
|
||||
On a Window with Window Controls Overlay already enabled, this method updates
|
||||
the style of the title bar overlay.
|
||||
|
||||
[runtime-enabled-features]: https://cs.chromium.org/chromium/src/third_party/blink/renderer/platform/runtime_enabled_features.json5?l=70
|
||||
[runtime-enabled-features]: https://source.chromium.org/chromium/chromium/src/+/main:third_party/blink/renderer/platform/runtime_enabled_features.json5
|
||||
[page-visibility-api]: https://developer.mozilla.org/en-US/docs/Web/API/Page_Visibility_API
|
||||
[quick-look]: https://en.wikipedia.org/wiki/Quick_Look
|
||||
[vibrancy-docs]: https://developer.apple.com/documentation/appkit/nsvisualeffectview?preferredLanguage=objc
|
||||
|
||||
@@ -78,6 +78,7 @@ The following methods are available on instances of `Cookies`:
|
||||
* `path` string (optional) - Retrieves cookies whose path matches `path`.
|
||||
* `secure` boolean (optional) - Filters cookies by their Secure property.
|
||||
* `session` boolean (optional) - Filters out session or persistent cookies.
|
||||
* `httpOnly` boolean (optional) - Filters cookies by httpOnly.
|
||||
|
||||
Returns `Promise<Cookie[]>` - A promise which resolves an array of cookie objects.
|
||||
|
||||
|
||||
@@ -51,7 +51,7 @@ See [`Menu`](menu.md) for examples.
|
||||
the placement of their containing group after the containing group of the item
|
||||
with the specified label.
|
||||
|
||||
**Note:** `acceleratorWorksWhenHidden` is specified as being macOS-only because accelerators always work when items are hidden on Windows and Linux. The option is exposed to users to give them the option to turn it off, as this is possible in native macOS development. This property is only usable on macOS High Sierra 10.13 or newer.
|
||||
**Note:** `acceleratorWorksWhenHidden` is specified as being macOS-only because accelerators always work when items are hidden on Windows and Linux. The option is exposed to users to give them the option to turn it off, as this is possible in native macOS development.
|
||||
|
||||
### Roles
|
||||
|
||||
|
||||
@@ -40,6 +40,8 @@ Open the given file in the desktop's default manner.
|
||||
* `options` Object (optional)
|
||||
* `activate` boolean (optional) _macOS_ - `true` to bring the opened application to the foreground. The default is `true`.
|
||||
* `workingDirectory` string (optional) _Windows_ - The working directory.
|
||||
* `logUsage` boolean (optional) _Windows_ - Indicates a user initiated launch that enables tracking of frequently used programs and other behaviors.
|
||||
The default is `false`.
|
||||
|
||||
Returns `Promise<void>`
|
||||
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
# WebRequestFilter Object
|
||||
|
||||
* `urls` string[] - Array of [URL patterns](https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/Match_patterns) that will be used to filter out the requests that do not match the URL patterns.
|
||||
* `types` String[] (optional) - Array of types that will be used to filter out the requests that do not match the types. When not specified, all types will be matched. Can be `mainFrame`, `subFrame`, `stylesheet`, `script`, `image`, `font`, `object`, `xhr`, `ping`, `cspReport`, `media` or `webSocket`.
|
||||
|
||||
@@ -394,8 +394,6 @@ system default and override the value of `getEffectiveAppearance`.
|
||||
|
||||
Returns `boolean` - whether or not this device has the ability to use Touch ID.
|
||||
|
||||
**NOTE:** This API will return `false` on macOS systems older than Sierra 10.12.2.
|
||||
|
||||
### `systemPreferences.promptTouchID(reason)` _macOS_
|
||||
|
||||
* `reason` string - The reason you are asking for Touch ID authentication
|
||||
@@ -414,8 +412,6 @@ systemPreferences.promptTouchID('To get consent for a Security-Gated Thing').the
|
||||
|
||||
This API itself will not protect your user data; rather, it is a mechanism to allow you to do so. Native apps will need to set [Access Control Constants](https://developer.apple.com/documentation/security/secaccesscontrolcreateflags?language=objc) like [`kSecAccessControlUserPresence`](https://developer.apple.com/documentation/security/secaccesscontrolcreateflags/ksecaccesscontroluserpresence?language=objc) on their keychain entry so that reading it would auto-prompt for Touch ID biometric consent. This could be done with [`node-keytar`](https://github.com/atom/node-keytar), such that one would store an encryption key with `node-keytar` and only fetch it if `promptTouchID()` resolves.
|
||||
|
||||
**NOTE:** This API will return a rejected Promise on macOS systems older than Sierra 10.12.2.
|
||||
|
||||
### `systemPreferences.isTrustedAccessibilityClient(prompt)` _macOS_
|
||||
|
||||
* `prompt` boolean - whether or not the user will be informed via prompt if the current process is untrusted.
|
||||
@@ -428,7 +424,7 @@ Returns `boolean` - `true` if the current process is a trusted accessibility cli
|
||||
|
||||
Returns `string` - Can be `not-determined`, `granted`, `denied`, `restricted` or `unknown`.
|
||||
|
||||
This user consent was not required on macOS 10.13 High Sierra or lower so this method will always return `granted`.
|
||||
This user consent was not required on macOS 10.13 High Sierra so this method will always return `granted`.
|
||||
macOS 10.14 Mojave or higher requires consent for `microphone` and `camera` access.
|
||||
macOS 10.15 Catalina or higher requires consent for `screen` access.
|
||||
|
||||
@@ -443,7 +439,7 @@ Returns `Promise<boolean>` - A promise that resolves with `true` if consent was
|
||||
|
||||
**Important:** In order to properly leverage this API, you [must set](https://developer.apple.com/documentation/avfoundation/cameras_and_media_capture/requesting_authorization_for_media_capture_on_macos?language=objc) the `NSMicrophoneUsageDescription` and `NSCameraUsageDescription` strings in your app's `Info.plist` file. The values for these keys will be used to populate the permission dialogs so that the user will be properly informed as to the purpose of the permission request. See [Electron Application Distribution](../tutorial/application-distribution.md#rebranding-with-downloaded-binaries) for more information about how to set these in the context of Electron.
|
||||
|
||||
This user consent was not required until macOS 10.14 Mojave, so this method will always return `true` if your system is running 10.13 High Sierra or lower.
|
||||
This user consent was not required until macOS 10.14 Mojave, so this method will always return `true` if your system is running 10.13 High Sierra.
|
||||
|
||||
### `systemPreferences.getAnimationSettings()`
|
||||
|
||||
|
||||
@@ -235,7 +235,7 @@ Sets the hover text for this tray icon.
|
||||
|
||||
* `title` string
|
||||
* `options` Object (optional)
|
||||
* `fontType` string (optional) - The font family variant to display, can be `monospaced` or `monospacedDigit`. `monospaced` is available in macOS 10.15+ and `monospacedDigit` is available in macOS 10.11+. When left blank, the title uses the default system font.
|
||||
* `fontType` string (optional) - The font family variant to display, can be `monospaced` or `monospacedDigit`. `monospaced` is available in macOS 10.15+ When left blank, the title uses the default system font.
|
||||
|
||||
Sets the title displayed next to the tray icon in the status bar (Support ANSI colors).
|
||||
|
||||
|
||||
@@ -1409,8 +1409,8 @@ Returns `Promise<PrinterInfo[]>` - Resolves with a [`PrinterInfo[]`](structures/
|
||||
* `vertical` number (optional) - The vertical dpi.
|
||||
* `header` string (optional) - string to be printed as page header.
|
||||
* `footer` string (optional) - string to be printed as page footer.
|
||||
* `pageSize` string | Size (optional) - Specify page size of the printed document. Can be `A3`,
|
||||
`A4`, `A5`, `Legal`, `Letter`, `Tabloid` or an Object containing `height` and `width`.
|
||||
* `pageSize` string | Size (optional) - Specify page size of the printed document. Can be `A0`, `A1`, `A2`, `A3`,
|
||||
`A4`, `A5`, `A6`, `Legal`, `Letter`, `Tabloid` or an Object containing `height` and `width`.
|
||||
* `callback` Function (optional)
|
||||
* `success` boolean - Indicates success of the print call.
|
||||
* `failureReason` string - Error description called back if the print fails.
|
||||
|
||||
@@ -1001,7 +1001,7 @@ Emitted when DevTools is closed.
|
||||
|
||||
Emitted when DevTools is focused / opened.
|
||||
|
||||
[runtime-enabled-features]: https://cs.chromium.org/chromium/src/third_party/blink/renderer/platform/runtime_enabled_features.json5?l=70
|
||||
[runtime-enabled-features]: https://source.chromium.org/chromium/chromium/src/+/main:third_party/blink/renderer/platform/runtime_enabled_features.json5
|
||||
[chrome-webview]: https://developer.chrome.com/docs/extensions/reference/webviewTag/
|
||||
|
||||
### Event: 'context-menu'
|
||||
|
||||
@@ -14,6 +14,14 @@ This document uses the following convention to categorize breaking changes:
|
||||
|
||||
## Planned Breaking API Changes (23.0)
|
||||
|
||||
### Behavior Changed: Draggable Regions on macOS
|
||||
|
||||
The implementation of draggable regions (using the CSS property `-webkit-app-region: drag`) has changed on macOS to bring it in line with Windows and Linux. Previously, when a region with `-webkit-app-region: no-drag` overlapped a region with `-webkit-app-region: drag`, the `no-drag` region would always take precedence on macOS, regardless of CSS layering. That is, if a `drag` region was above a `no-drag` region, it would be ignored. Beginning in Electron 23, a `drag` region on top of a `no-drag` region will correctly cause the region to be draggable.
|
||||
|
||||
Additionally, the `customButtonsOnHover` BrowserWindow property previously created a draggable region which ignored the `-webkit-app-region` CSS property. This has now been fixed (see [#37210](https://github.com/electron/electron/issues/37210#issuecomment-1440509592) for discussion).
|
||||
|
||||
As a result, if your app uses a frameless window with draggable regions on macOS, the regions which are draggable in your app may change in Electron 23.
|
||||
|
||||
### Removed: Windows 7 / 8 / 8.1 support
|
||||
|
||||
[Windows 7, Windows 8, and Windows 8.1 are no longer supported](https://www.electronjs.org/blog/windows-7-to-8-1-deprecation-notice). Electron follows the planned Chromium deprecation policy, which will [deprecate Windows 7 support beginning in Chromium 109](https://support.google.com/chrome/thread/185534985/sunsetting-support-for-windows-7-8-8-1-in-early-2023?hl=en).
|
||||
@@ -236,6 +244,13 @@ webContents.printToPDF({
|
||||
|
||||
## Planned Breaking API Changes (20.0)
|
||||
|
||||
### Removed: macOS 10.11 / 10.12 support
|
||||
|
||||
macOS 10.11 (El Capitan) and macOS 10.12 (Sierra) are no longer supported by [Chromium](https://chromium-review.googlesource.com/c/chromium/src/+/3646050).
|
||||
|
||||
Older versions of Electron will continue to run on these operating systems, but macOS 10.13 (High Sierra)
|
||||
or later will be required to run Electron v20.0.0 and higher.
|
||||
|
||||
### Default Changed: renderers without `nodeIntegration: true` are sandboxed by default
|
||||
|
||||
Previously, renderers that specified a preload script defaulted to being
|
||||
|
||||
@@ -18,8 +18,8 @@ See also [V8 Development](v8-development.md)
|
||||
|
||||
### Code Resources
|
||||
|
||||
- [Code Search](https://cs.chromium.org/) - Indexed and searchable source code for Chromium and associated projects.
|
||||
- [Source Code](https://cs.chromium.org/chromium/src/) - The source code for Chromium itself.
|
||||
- [Code Search](https://source.chromium.org/chromium) - Indexed and searchable source code for Chromium and associated projects.
|
||||
- [Source Code](https://source.chromium.org/chromium/chromium/src) - The source code for Chromium itself.
|
||||
- [Chromium Review](https://chromium-review.googlesource.com) - The searchable code host which facilitates code reviews for Chromium and related projects.
|
||||
|
||||
### Informational Resources
|
||||
|
||||
@@ -153,7 +153,7 @@ filenames = {
|
||||
"shell/browser/notifications/mac/notification_presenter_mac.mm",
|
||||
"shell/browser/relauncher_mac.cc",
|
||||
"shell/browser/ui/certificate_trust_mac.mm",
|
||||
"shell/browser/ui/cocoa/delayed_native_view_host.cc",
|
||||
"shell/browser/ui/cocoa/delayed_native_view_host.mm",
|
||||
"shell/browser/ui/cocoa/delayed_native_view_host.h",
|
||||
"shell/browser/ui/cocoa/electron_bundle_mover.h",
|
||||
"shell/browser/ui/cocoa/electron_bundle_mover.mm",
|
||||
|
||||
@@ -28,11 +28,47 @@ type PostData = LoadURLOptions['postData']
|
||||
|
||||
// Stock page sizes
|
||||
const PDFPageSizes: Record<string, ElectronInternal.MediaSize> = {
|
||||
A5: {
|
||||
custom_display_name: 'A5',
|
||||
height_microns: 210000,
|
||||
name: 'ISO_A5',
|
||||
width_microns: 148000
|
||||
Letter: {
|
||||
custom_display_name: 'Letter',
|
||||
height_microns: 279400,
|
||||
name: 'NA_LETTER',
|
||||
width_microns: 215900
|
||||
},
|
||||
Legal: {
|
||||
custom_display_name: 'Legal',
|
||||
height_microns: 355600,
|
||||
name: 'NA_LEGAL',
|
||||
width_microns: 215900
|
||||
},
|
||||
Tabloid: {
|
||||
height_microns: 431800,
|
||||
name: 'NA_LEDGER',
|
||||
width_microns: 279400,
|
||||
custom_display_name: 'Tabloid'
|
||||
},
|
||||
A0: {
|
||||
custom_display_name: 'A0',
|
||||
height_microns: 1189000,
|
||||
name: 'ISO_A0',
|
||||
width_microns: 841000
|
||||
},
|
||||
A1: {
|
||||
custom_display_name: 'A1',
|
||||
height_microns: 841000,
|
||||
name: 'ISO_A1',
|
||||
width_microns: 594000
|
||||
},
|
||||
A2: {
|
||||
custom_display_name: 'A2',
|
||||
height_microns: 594000,
|
||||
name: 'ISO_A2',
|
||||
width_microns: 420000
|
||||
},
|
||||
A3: {
|
||||
custom_display_name: 'A3',
|
||||
height_microns: 420000,
|
||||
name: 'ISO_A3',
|
||||
width_microns: 297000
|
||||
},
|
||||
A4: {
|
||||
custom_display_name: 'A4',
|
||||
@@ -41,29 +77,17 @@ const PDFPageSizes: Record<string, ElectronInternal.MediaSize> = {
|
||||
is_default: 'true',
|
||||
width_microns: 210000
|
||||
},
|
||||
A3: {
|
||||
custom_display_name: 'A3',
|
||||
height_microns: 420000,
|
||||
name: 'ISO_A3',
|
||||
width_microns: 297000
|
||||
A5: {
|
||||
custom_display_name: 'A5',
|
||||
height_microns: 210000,
|
||||
name: 'ISO_A5',
|
||||
width_microns: 148000
|
||||
},
|
||||
Legal: {
|
||||
custom_display_name: 'Legal',
|
||||
height_microns: 355600,
|
||||
name: 'NA_LEGAL',
|
||||
width_microns: 215900
|
||||
},
|
||||
Letter: {
|
||||
custom_display_name: 'Letter',
|
||||
height_microns: 279400,
|
||||
name: 'NA_LETTER',
|
||||
width_microns: 215900
|
||||
},
|
||||
Tabloid: {
|
||||
height_microns: 431800,
|
||||
name: 'NA_LEDGER',
|
||||
width_microns: 279400,
|
||||
custom_display_name: 'Tabloid'
|
||||
A6: {
|
||||
custom_display_name: 'A6',
|
||||
height_microns: 148000,
|
||||
name: 'ISO_A6',
|
||||
width_microns: 105000
|
||||
}
|
||||
} as const;
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
"@electron/fiddle-core": "^1.0.4",
|
||||
"@electron/github-app-auth": "^1.5.0",
|
||||
"@electron/typescript-definitions": "^8.10.0",
|
||||
"@octokit/rest": "^18.0.3",
|
||||
"@octokit/rest": "^19.0.7",
|
||||
"@primer/octicons": "^10.0.0",
|
||||
"@types/basic-auth": "^1.1.3",
|
||||
"@types/busboy": "^1.5.0",
|
||||
|
||||
@@ -125,3 +125,4 @@ chore_introduce_blocking_api_for_electron.patch
|
||||
chore_patch_out_partition_attribute_dcheck_for_webviews.patch
|
||||
expose_v8initializer_codegenerationcheckcallbackinmainthread.patch
|
||||
chore_patch_out_profile_methods_in_profile_selections_cc.patch
|
||||
fix_x11_window_restore_minimized_maximized_window.patch
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Cheng Zhao <zcbenz@gmail.com>
|
||||
Date: Wed, 15 Feb 2023 11:30:56 +0900
|
||||
Subject: fix: restoring a X11 window should not remove its previous maximized
|
||||
state
|
||||
|
||||
On Linux after minimizing a maximized window, it will have both the
|
||||
"maximized" and "hidden" states, and restoring the window should only remove
|
||||
the "hidden" state, which makes it back a maximized window.
|
||||
|
||||
However in the implementation of `X11Window::Restore`, both "maximized" and
|
||||
"hidden" states are removed, and a maximized window that was minimized will
|
||||
be resized to its normal size after calling Restore, while the correct
|
||||
behavior should be going back to the maximized state.
|
||||
|
||||
Backported from:
|
||||
https://chromium-review.googlesource.com/c/chromium/src/+/4252946
|
||||
|
||||
diff --git a/ui/ozone/platform/x11/x11_window.cc b/ui/ozone/platform/x11/x11_window.cc
|
||||
index cbf300db6ec3aa6c108233006c8249231b9a8aa1..f681a199951f448604f887e1c1c64250608f095e 100644
|
||||
--- a/ui/ozone/platform/x11/x11_window.cc
|
||||
+++ b/ui/ozone/platform/x11/x11_window.cc
|
||||
@@ -731,11 +731,16 @@ void X11Window::Minimize() {
|
||||
}
|
||||
|
||||
void X11Window::Restore() {
|
||||
- should_maximize_after_map_ = false;
|
||||
- restore_in_flight_ = true;
|
||||
- SetWMSpecState(false, x11::GetAtom("_NET_WM_STATE_MAXIMIZED_VERT"),
|
||||
- x11::GetAtom("_NET_WM_STATE_MAXIMIZED_HORZ"));
|
||||
- SetWMSpecState(false, x11::GetAtom("_NET_WM_STATE_HIDDEN"), x11::Atom::None);
|
||||
+ if (IsMinimized()) {
|
||||
+ restore_in_flight_ = true;
|
||||
+ SetWMSpecState(false, x11::GetAtom("_NET_WM_STATE_HIDDEN"),
|
||||
+ x11::Atom::None);
|
||||
+ } else if (IsMaximized()) {
|
||||
+ restore_in_flight_ = true;
|
||||
+ should_maximize_after_map_ = false;
|
||||
+ SetWMSpecState(false, x11::GetAtom("_NET_WM_STATE_MAXIMIZED_VERT"),
|
||||
+ x11::GetAtom("_NET_WM_STATE_MAXIMIZED_HORZ"));
|
||||
+ }
|
||||
}
|
||||
|
||||
PlatformWindowState X11Window::GetPlatformWindowState() const {
|
||||
@@ -1890,6 +1895,10 @@ bool X11Window::IsMinimized() const {
|
||||
}
|
||||
|
||||
bool X11Window::IsMaximized() const {
|
||||
+ // In X11, if a maximized window is minimized, it will have both the "hidden"
|
||||
+ // and "maximized" states.
|
||||
+ if (IsMinimized())
|
||||
+ return false;
|
||||
return (HasWMSpecProperty(window_properties_,
|
||||
x11::GetAtom("_NET_WM_STATE_MAXIMIZED_VERT")) &&
|
||||
HasWMSpecProperty(window_properties_,
|
||||
@@ -222,10 +222,159 @@ index f35d9ef2a2df3db8ecbf1d7b909c7b1cf33f3cd9..a710b8b4f851666fd65bb37f69ec2fa7
|
||||
|
||||
bool SandboxCompiler::CompilePolicyToProto(mac::SandboxPolicy& policy,
|
||||
diff --git a/sandbox/mac/seatbelt.cc b/sandbox/mac/seatbelt.cc
|
||||
index 15c835e118456394c0a00ac98c11241c14ca75bd..49332a94219fc3e64ab05baa04681325edddfeb0 100644
|
||||
index 15c835e118456394c0a00ac98c11241c14ca75bd..83759e5fbc252fa57ca2fa122873dfac3d61d46d 100644
|
||||
--- a/sandbox/mac/seatbelt.cc
|
||||
+++ b/sandbox/mac/seatbelt.cc
|
||||
@@ -175,7 +175,11 @@ void Seatbelt::FreeError(char* errorbuf) {
|
||||
@@ -9,7 +9,7 @@
|
||||
|
||||
extern "C" {
|
||||
#include <sandbox.h>
|
||||
-
|
||||
+#if !IS_MAS_BUILD()
|
||||
int sandbox_init_with_parameters(const char* profile,
|
||||
uint64_t flags,
|
||||
const char* const parameters[],
|
||||
@@ -40,13 +40,13 @@ sandbox_profile_t* sandbox_compile_string(const char* data,
|
||||
char** error);
|
||||
int sandbox_apply(sandbox_profile_t*);
|
||||
void sandbox_free_profile(sandbox_profile_t*);
|
||||
-
|
||||
+#endif
|
||||
} // extern "C"
|
||||
|
||||
namespace sandbox {
|
||||
|
||||
namespace {
|
||||
-
|
||||
+#if !IS_MAS_BUILD()
|
||||
bool HandleSandboxResult(int rv, char* errorbuf, std::string* error) {
|
||||
if (rv == 0) {
|
||||
if (error)
|
||||
@@ -74,36 +74,48 @@ bool HandleSandboxErrno(int rv, const char* message, std::string* error) {
|
||||
}
|
||||
return false;
|
||||
}
|
||||
-
|
||||
+#endif
|
||||
} // namespace
|
||||
|
||||
// static
|
||||
Seatbelt::Parameters Seatbelt::Parameters::Create() {
|
||||
Parameters params;
|
||||
+#if !IS_MAS_BUILD()
|
||||
params.params_ = ::sandbox_create_params();
|
||||
+#endif
|
||||
return params;
|
||||
}
|
||||
|
||||
Seatbelt::Parameters::Parameters() = default;
|
||||
|
||||
Seatbelt::Parameters::Parameters(Seatbelt::Parameters&& other) {
|
||||
+#if !IS_MAS_BUILD()
|
||||
params_ = std::exchange(other.params_, nullptr);
|
||||
+#endif
|
||||
}
|
||||
|
||||
Seatbelt::Parameters& Seatbelt::Parameters::operator=(
|
||||
Seatbelt::Parameters&& other) {
|
||||
+#if !IS_MAS_BUILD()
|
||||
params_ = std::exchange(other.params_, nullptr);
|
||||
+#endif
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool Seatbelt::Parameters::Set(const char* key, const char* value) {
|
||||
+#if !IS_MAS_BUILD()
|
||||
return ::sandbox_set_param(params_, key, value) == 0;
|
||||
+#else
|
||||
+ return true;
|
||||
+#endif
|
||||
}
|
||||
|
||||
Seatbelt::Parameters::~Parameters() {
|
||||
+#if !IS_MAS_BUILD()
|
||||
if (params_) {
|
||||
::sandbox_free_params(params_);
|
||||
}
|
||||
+#endif
|
||||
}
|
||||
|
||||
// Initialize the static member variables.
|
||||
@@ -114,6 +126,7 @@ const char* Seatbelt::kProfilePureComputation = kSBXProfilePureComputation;
|
||||
|
||||
// static
|
||||
bool Seatbelt::Init(const char* profile, uint64_t flags, std::string* error) {
|
||||
+#if !IS_MAS_BUILD()
|
||||
// OS X deprecated these functions, but did not provide a suitable replacement,
|
||||
// so ignore the deprecation warning.
|
||||
#pragma clang diagnostic push
|
||||
@@ -122,6 +135,9 @@ bool Seatbelt::Init(const char* profile, uint64_t flags, std::string* error) {
|
||||
int rv = ::sandbox_init(profile, flags, &errorbuf);
|
||||
return HandleSandboxResult(rv, errorbuf, error);
|
||||
#pragma clang diagnostic pop
|
||||
+#else
|
||||
+ return true;
|
||||
+#endif
|
||||
}
|
||||
|
||||
// static
|
||||
@@ -129,10 +145,14 @@ bool Seatbelt::InitWithParams(const char* profile,
|
||||
uint64_t flags,
|
||||
const char* const parameters[],
|
||||
std::string* error) {
|
||||
+#if !IS_MAS_BUILD()
|
||||
char* errorbuf = nullptr;
|
||||
int rv =
|
||||
::sandbox_init_with_parameters(profile, flags, parameters, &errorbuf);
|
||||
return HandleSandboxResult(rv, errorbuf, error);
|
||||
+#else
|
||||
+ return true;
|
||||
+#endif
|
||||
}
|
||||
|
||||
// static
|
||||
@@ -140,6 +160,7 @@ bool Seatbelt::Compile(const char* profile,
|
||||
const Seatbelt::Parameters& params,
|
||||
std::string& compiled_profile,
|
||||
std::string* error) {
|
||||
+#if !IS_MAS_BUILD()
|
||||
char* errorbuf = nullptr;
|
||||
sandbox_profile_t* sandbox_profile =
|
||||
::sandbox_compile_string(profile, params.params(), &errorbuf);
|
||||
@@ -149,33 +170,44 @@ bool Seatbelt::Compile(const char* profile,
|
||||
compiled_profile.assign(reinterpret_cast<const char*>(sandbox_profile->data),
|
||||
sandbox_profile->size);
|
||||
::sandbox_free_profile(sandbox_profile);
|
||||
+#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
// static
|
||||
bool Seatbelt::ApplyCompiledProfile(const std::string& profile,
|
||||
std::string* error) {
|
||||
+#if !IS_MAS_BUILD()
|
||||
sandbox_profile_t sbox_profile = {
|
||||
.builtin = nullptr,
|
||||
.data = reinterpret_cast<const uint8_t*>(profile.data()),
|
||||
.size = profile.size()};
|
||||
return HandleSandboxErrno(::sandbox_apply(&sbox_profile),
|
||||
"sandbox_apply: ", error);
|
||||
+#else
|
||||
+ return true;
|
||||
+#endif
|
||||
}
|
||||
|
||||
// static
|
||||
void Seatbelt::FreeError(char* errorbuf) {
|
||||
+#if !IS_MAS_BUILD()
|
||||
// OS X deprecated these functions, but did not provide a suitable replacement,
|
||||
// so ignore the deprecation warning.
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
|
||||
return ::sandbox_free_error(errorbuf);
|
||||
#pragma clang diagnostic pop
|
||||
+#endif
|
||||
}
|
||||
|
||||
// static
|
||||
bool Seatbelt::IsSandboxed() {
|
||||
|
||||
@@ -25,7 +25,6 @@ build_ensure_native_module_compilation_fails_if_not_using_a_new.patch
|
||||
fix_override_createjob_in_node_platform.patch
|
||||
v8_api_advance_api_deprecation.patch
|
||||
fixup_for_error_declaration_shadows_a_local_variable.patch
|
||||
fixup_for_wc_98-compat-extra-semi.patch
|
||||
fix_parallel_test-v8-stats.patch
|
||||
fix_expose_the_built-in_electron_module_via_the_esm_loader.patch
|
||||
heap_remove_allocationspace_map_space_enum_constant.patch
|
||||
@@ -36,3 +35,4 @@ enable_crashpad_linux_node_processes.patch
|
||||
allow_embedder_to_control_codegenerationfromstringscallback.patch
|
||||
src_allow_optional_isolation_termination_in_node.patch
|
||||
test_mark_cpu_prof_tests_as_flaky_in_electron.patch
|
||||
lib_fix_broadcastchannel_initialization_location.patch
|
||||
|
||||
@@ -1,21 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: John Kleinschmidt <jkleinsc@electronjs.org>
|
||||
Date: Thu, 1 Sep 2022 21:55:57 -0400
|
||||
Subject: fixup for Wc++98-compat-extra-semi
|
||||
|
||||
Wc++98-compat-extra-semi is turned on for Electron so this
|
||||
patch fixes that error in node.
|
||||
|
||||
diff --git a/src/node_serdes.cc b/src/node_serdes.cc
|
||||
index 1cdd436b343861a96582a803b460aefe1e81cdd0..0249574c4431fb5b98852699f1368f71b49691c1 100644
|
||||
--- a/src/node_serdes.cc
|
||||
+++ b/src/node_serdes.cc
|
||||
@@ -32,7 +32,7 @@ namespace serdes {
|
||||
v8::ArrayBuffer::Allocator* GetAllocator() {
|
||||
static v8::ArrayBuffer::Allocator* allocator = v8::ArrayBuffer::Allocator::NewDefaultAllocator();
|
||||
return allocator;
|
||||
-};
|
||||
+}
|
||||
|
||||
class SerializerContext : public BaseObject,
|
||||
public ValueSerializer::Delegate {
|
||||
@@ -0,0 +1,44 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Shelley Vohr <shelley.vohr@gmail.com>
|
||||
Date: Mon, 27 Feb 2023 12:56:15 +0100
|
||||
Subject: lib: fix BroadcastChannel initialization location
|
||||
|
||||
Refs https://github.com/nodejs/node/pull/40532.
|
||||
|
||||
Fixes a bug in the above, wherein BroadcastChannel should have been
|
||||
initialized in bootstrap/browser instead of bootstrap/node. That
|
||||
inadvertently made it such that there was incorrect handling of the
|
||||
DOM vs Node.js implementations of BroadcastChannel.
|
||||
|
||||
This will be upstreamed.
|
||||
|
||||
diff --git a/lib/internal/bootstrap/browser.js b/lib/internal/bootstrap/browser.js
|
||||
index d0c01ca2a512be549b0fea8a829c05eabbec799a..210a1bb7e929021725b04786bc11d9b3ce09ad04 100644
|
||||
--- a/lib/internal/bootstrap/browser.js
|
||||
+++ b/lib/internal/bootstrap/browser.js
|
||||
@@ -12,6 +12,10 @@ const {
|
||||
} = require('internal/util');
|
||||
const config = internalBinding('config');
|
||||
|
||||
+// Non-standard extensions:
|
||||
+const { BroadcastChannel } = require('internal/worker/io');
|
||||
+exposeInterface(globalThis, 'BroadcastChannel', BroadcastChannel);
|
||||
+
|
||||
// https://console.spec.whatwg.org/#console-namespace
|
||||
exposeNamespace(globalThis, 'console',
|
||||
createGlobalConsole());
|
||||
diff --git a/lib/internal/bootstrap/node.js b/lib/internal/bootstrap/node.js
|
||||
index 7dd89d5f134b09da2678dd54fa9139466fea179c..f235545b6433c0f1dd335e0bb97cd3dc77616c0f 100644
|
||||
--- a/lib/internal/bootstrap/node.js
|
||||
+++ b/lib/internal/bootstrap/node.js
|
||||
@@ -237,10 +237,6 @@ const {
|
||||
queueMicrotask
|
||||
} = require('internal/process/task_queues');
|
||||
|
||||
-// Non-standard extensions:
|
||||
-const { BroadcastChannel } = require('internal/worker/io');
|
||||
-exposeInterface(globalThis, 'BroadcastChannel', BroadcastChannel);
|
||||
-
|
||||
defineOperation(globalThis, 'queueMicrotask', queueMicrotask);
|
||||
|
||||
const timers = require('timers');
|
||||
@@ -155,7 +155,7 @@ index ece9a4cfd45bf885169fdd278e09c467c6b4bbab..0c0dac67c0834ab7feba426079629245
|
||||
|
||||
// Delegate to V8's allocator for compatibility with the V8 memory cage.
|
||||
diff --git a/src/node_serdes.cc b/src/node_serdes.cc
|
||||
index 6864f2d88b34abfa4090780d6993684cd0b366a3..1cdd436b343861a96582a803b460aefe1e81cdd0 100644
|
||||
index 6864f2d88b34abfa4090780d6993684cd0b366a3..0249574c4431fb5b98852699f1368f71b49691c1 100644
|
||||
--- a/src/node_serdes.cc
|
||||
+++ b/src/node_serdes.cc
|
||||
@@ -29,6 +29,11 @@ using v8::ValueSerializer;
|
||||
@@ -165,7 +165,7 @@ index 6864f2d88b34abfa4090780d6993684cd0b366a3..1cdd436b343861a96582a803b460aefe
|
||||
+v8::ArrayBuffer::Allocator* GetAllocator() {
|
||||
+ static v8::ArrayBuffer::Allocator* allocator = v8::ArrayBuffer::Allocator::NewDefaultAllocator();
|
||||
+ return allocator;
|
||||
+};
|
||||
+}
|
||||
+
|
||||
class SerializerContext : public BaseObject,
|
||||
public ValueSerializer::Delegate {
|
||||
|
||||
@@ -30,10 +30,6 @@ def get_target_arch():
|
||||
return arch
|
||||
|
||||
|
||||
def get_env_var(name):
|
||||
return os.environ.get('ELECTRON_' + name, '')
|
||||
|
||||
|
||||
def enable_verbose_mode():
|
||||
print('Running in verbose mode')
|
||||
global verbose_mode
|
||||
|
||||
@@ -121,11 +121,6 @@ class TestsList():
|
||||
for binary in binaries])
|
||||
return suite_returncode
|
||||
|
||||
def run_only(self, binary_name, output_dir=None, verbosity=Verbosity.CHATTY,
|
||||
disabled_tests_policy=DisabledTestsPolicy.DISABLE):
|
||||
return self.run([binary_name], output_dir, verbosity,
|
||||
disabled_tests_policy)
|
||||
|
||||
def run_all(self, output_dir=None, verbosity=Verbosity.CHATTY,
|
||||
disabled_tests_policy=DisabledTestsPolicy.DISABLE):
|
||||
return self.run(self.get_for_current_platform(), output_dir, verbosity,
|
||||
|
||||
@@ -25,12 +25,9 @@ ELECTRON_DIR = os.path.abspath(
|
||||
TS_NODE = os.path.join(ELECTRON_DIR, 'node_modules', '.bin', 'ts-node')
|
||||
SRC_DIR = os.path.abspath(os.path.join(__file__, '..', '..', '..', '..'))
|
||||
|
||||
NPM = 'npm'
|
||||
if sys.platform in ['win32', 'cygwin']:
|
||||
NPM += '.cmd'
|
||||
TS_NODE += '.cmd'
|
||||
|
||||
|
||||
@contextlib.contextmanager
|
||||
def scoped_cwd(path):
|
||||
cwd = os.getcwd()
|
||||
@@ -41,18 +38,6 @@ def scoped_cwd(path):
|
||||
os.chdir(cwd)
|
||||
|
||||
|
||||
@contextlib.contextmanager
|
||||
def scoped_env(key, value):
|
||||
origin = ''
|
||||
if key in os.environ:
|
||||
origin = os.environ[key]
|
||||
os.environ[key] = value
|
||||
try:
|
||||
yield
|
||||
finally:
|
||||
os.environ[key] = origin
|
||||
|
||||
|
||||
def download(text, url, path):
|
||||
safe_mkdir(os.path.dirname(path))
|
||||
with open(path, 'wb') as local_file:
|
||||
|
||||
@@ -134,9 +134,6 @@
|
||||
"parallel/test-webcrypto-export-import-cfrg",
|
||||
"parallel/test-webcrypto-keygen",
|
||||
"parallel/test-webcrypto-sign-verify-eddsa",
|
||||
"parallel/test-worker-debug",
|
||||
"parallel/test-worker-init-failure",
|
||||
"parallel/test-worker-stdio",
|
||||
"parallel/test-zlib-unused-weak",
|
||||
"report/test-report-fatalerror-oomerror-set",
|
||||
"report/test-report-fatalerror-oomerror-directory",
|
||||
|
||||
@@ -14,8 +14,8 @@ const ROLLER_BRANCH_PATTERN = /^roller\/chromium$/;
|
||||
|
||||
const DEFAULT_BUILD_CLOUD_ID = '1598';
|
||||
const DEFAULT_BUILD_CLOUD = 'electronhq-16-core';
|
||||
const DEFAULT_BAKE_BASE_IMAGE = 'e-110.0.5451.0';
|
||||
const DEFAULT_BUILD_IMAGE = 'e-110.0.5451.0';
|
||||
const DEFAULT_BAKE_BASE_IMAGE = 'e-111.0.5560.0-node18';
|
||||
const DEFAULT_BUILD_IMAGE = 'e-111.0.5560.0-node18';
|
||||
|
||||
const appveyorBakeJob = 'electron-bake-image';
|
||||
const appVeyorJobs = {
|
||||
|
||||
@@ -13,6 +13,7 @@ const fs = require('fs');
|
||||
const { execSync } = require('child_process');
|
||||
const got = require('got');
|
||||
const path = require('path');
|
||||
const semver = require('semver');
|
||||
const temp = require('temp').track();
|
||||
const { URL } = require('url');
|
||||
const { BlobServiceClient } = require('@azure/storage-blob');
|
||||
@@ -317,12 +318,20 @@ function saveShaSumFile (checksums, fileName) {
|
||||
}
|
||||
|
||||
async function publishRelease (release) {
|
||||
const currentLatest = await octokit.repos.getLatestRelease({
|
||||
owner: 'electron',
|
||||
repo: targetRepo
|
||||
});
|
||||
|
||||
const makeLatest = !release.prerelease && semver.gte(release.tag_name, currentLatest.data.tag_name);
|
||||
|
||||
return octokit.repos.updateRelease({
|
||||
owner: 'electron',
|
||||
repo: targetRepo,
|
||||
release_id: release.id,
|
||||
tag_name: release.tag_name,
|
||||
draft: false
|
||||
draft: false,
|
||||
make_latest: makeLatest ? 'true' : 'false'
|
||||
}).catch(err => {
|
||||
console.log(`${fail} Error publishing release:`, err);
|
||||
process.exit(1);
|
||||
|
||||
@@ -56,7 +56,8 @@ REM Install Windows SDK
|
||||
choco install windows-sdk-10-version-2104-all
|
||||
|
||||
REM Install nodejs python git and yarn needed dependencies
|
||||
choco install -y nodejs-lts python2 git yarn
|
||||
choco install -y --force nodejs --version=18.12.1
|
||||
choco install -y python2 git yarn
|
||||
choco install python --version 3.7.9
|
||||
call C:\ProgramData\chocolatey\bin\RefreshEnv.cmd
|
||||
SET PATH=C:\Python27\;C:\Python27\Scripts;C:\Python39\;C:\Python39\Scripts;%PATH%
|
||||
|
||||
@@ -260,37 +260,9 @@ int NodeMain(int argc, char* argv[]) {
|
||||
v8::HandleScope scope(isolate);
|
||||
node::LoadEnvironment(env, node::StartExecutionCallback{});
|
||||
|
||||
env->set_trace_sync_io(env->options()->trace_sync_io);
|
||||
|
||||
{
|
||||
v8::SealHandleScope seal(isolate);
|
||||
bool more;
|
||||
env->performance_state()->Mark(
|
||||
node::performance::NODE_PERFORMANCE_MILESTONE_LOOP_START);
|
||||
do {
|
||||
uv_run(env->event_loop(), UV_RUN_DEFAULT);
|
||||
|
||||
gin_env.platform()->DrainTasks(isolate);
|
||||
|
||||
more = uv_loop_alive(env->event_loop());
|
||||
if (more && !env->is_stopping())
|
||||
continue;
|
||||
|
||||
if (!uv_loop_alive(env->event_loop())) {
|
||||
EmitBeforeExit(env);
|
||||
}
|
||||
|
||||
// Emit `beforeExit` if the loop became alive either after emitting
|
||||
// event, or after running some callbacks.
|
||||
more = uv_loop_alive(env->event_loop());
|
||||
} while (more && !env->is_stopping());
|
||||
env->performance_state()->Mark(
|
||||
node::performance::NODE_PERFORMANCE_MILESTONE_LOOP_EXIT);
|
||||
}
|
||||
|
||||
env->set_trace_sync_io(false);
|
||||
|
||||
exit_code = node::EmitExit(env);
|
||||
// Potential reasons we get Nothing here may include: the env
|
||||
// is stopping, or the user hooks process.emit('exit').
|
||||
exit_code = node::SpinEventLoop(env).FromMaybe(1);
|
||||
|
||||
node::ResetStdio();
|
||||
|
||||
|
||||
@@ -126,6 +126,9 @@ BrowserView::~BrowserView() {
|
||||
}
|
||||
|
||||
void BrowserView::WebContentsDestroyed() {
|
||||
if (owner_window())
|
||||
owner_window()->window()->RemoveDraggableRegionProvider(this);
|
||||
|
||||
api_web_contents_ = nullptr;
|
||||
web_contents_.Reset();
|
||||
Unpin();
|
||||
|
||||
@@ -198,7 +198,11 @@ void BrowserWindow::OnCloseButtonClicked(bool* prevent_default) {
|
||||
|
||||
// Trigger beforeunload events for associated BrowserViews.
|
||||
for (NativeBrowserView* view : window_->browser_views()) {
|
||||
auto* vwc = view->GetInspectableWebContents()->GetWebContents();
|
||||
auto* iwc = view->GetInspectableWebContents();
|
||||
if (!iwc)
|
||||
continue;
|
||||
|
||||
auto* vwc = iwc->GetWebContents();
|
||||
auto* api_web_contents = api::WebContents::From(vwc);
|
||||
|
||||
// Required to make beforeunload handler work.
|
||||
|
||||
@@ -128,10 +128,13 @@ bool MatchesCookie(const base::Value::Dict& filter,
|
||||
!MatchesDomain(*str, cookie.Domain()))
|
||||
return false;
|
||||
absl::optional<bool> secure_filter = filter.FindBool("secure");
|
||||
if (secure_filter && *secure_filter == cookie.IsSecure())
|
||||
if (secure_filter && *secure_filter != cookie.IsSecure())
|
||||
return false;
|
||||
absl::optional<bool> session_filter = filter.FindBool("session");
|
||||
if (session_filter && *session_filter != !cookie.IsPersistent())
|
||||
if (session_filter && *session_filter == cookie.IsPersistent())
|
||||
return false;
|
||||
absl::optional<bool> httpOnly_filter = filter.FindBool("httpOnly");
|
||||
if (httpOnly_filter && *httpOnly_filter != cookie.IsHttpOnly())
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -1305,7 +1305,10 @@ Profile* WebContents::GetProfile() {
|
||||
}
|
||||
|
||||
bool WebContents::IsFullscreen() const {
|
||||
return owner_window_ && owner_window_->IsFullscreen();
|
||||
if (!owner_window())
|
||||
return false;
|
||||
|
||||
return owner_window()->IsFullscreen() || is_html_fullscreen();
|
||||
}
|
||||
|
||||
void WebContents::EnterFullscreen(const GURL& url,
|
||||
@@ -1351,7 +1354,7 @@ void WebContents::OnEnterFullscreenModeForTab(
|
||||
content::RenderFrameHost* requesting_frame,
|
||||
const blink::mojom::FullscreenOptions& options,
|
||||
bool allowed) {
|
||||
if (!allowed || !owner_window_)
|
||||
if (!allowed || !owner_window())
|
||||
return;
|
||||
|
||||
auto* source = content::WebContents::FromRenderFrameHost(requesting_frame);
|
||||
@@ -1375,7 +1378,7 @@ void WebContents::OnEnterFullscreenModeForTab(
|
||||
}
|
||||
|
||||
void WebContents::ExitFullscreenModeForTab(content::WebContents* source) {
|
||||
if (!owner_window_)
|
||||
if (!owner_window())
|
||||
return;
|
||||
|
||||
// This needs to be called before we exit fullscreen on the native window,
|
||||
@@ -3509,18 +3512,26 @@ v8::Local<v8::Promise> WebContents::TakeHeapSnapshot(
|
||||
flags = base::File::AddFlagsForPassingToUntrustedProcess(flags);
|
||||
base::File file(file_path, flags);
|
||||
if (!file.IsValid()) {
|
||||
promise.RejectWithErrorMessage("takeHeapSnapshot failed");
|
||||
promise.RejectWithErrorMessage(
|
||||
"Failed to take heap snapshot with invalid file path " +
|
||||
#if BUILDFLAG(IS_WIN)
|
||||
base::WideToUTF8(file_path.value()));
|
||||
#else
|
||||
file_path.value());
|
||||
#endif
|
||||
return handle;
|
||||
}
|
||||
|
||||
auto* frame_host = web_contents()->GetPrimaryMainFrame();
|
||||
if (!frame_host) {
|
||||
promise.RejectWithErrorMessage("takeHeapSnapshot failed");
|
||||
promise.RejectWithErrorMessage(
|
||||
"Failed to take heap snapshot with invalid webContents main frame");
|
||||
return handle;
|
||||
}
|
||||
|
||||
if (!frame_host->IsRenderFrameLive()) {
|
||||
promise.RejectWithErrorMessage("takeHeapSnapshot failed");
|
||||
promise.RejectWithErrorMessage(
|
||||
"Failed to take heap snapshot with nonexistent render frame");
|
||||
return handle;
|
||||
}
|
||||
|
||||
@@ -3540,7 +3551,7 @@ v8::Local<v8::Promise> WebContents::TakeHeapSnapshot(
|
||||
if (success) {
|
||||
promise.Resolve();
|
||||
} else {
|
||||
promise.RejectWithErrorMessage("takeHeapSnapshot failed");
|
||||
promise.RejectWithErrorMessage("Failed to take heap snapshot");
|
||||
}
|
||||
},
|
||||
base::Owned(std::move(electron_renderer)), std::move(promise)));
|
||||
@@ -3580,14 +3591,14 @@ void WebContents::EnumerateDirectory(
|
||||
bool WebContents::IsFullscreenForTabOrPending(
|
||||
const content::WebContents* source) {
|
||||
if (!owner_window())
|
||||
return html_fullscreen_;
|
||||
return is_html_fullscreen();
|
||||
|
||||
bool in_transition = owner_window()->fullscreen_transition_state() !=
|
||||
NativeWindow::FullScreenTransitionState::NONE;
|
||||
bool is_html_transition = owner_window()->fullscreen_transition_type() ==
|
||||
NativeWindow::FullScreenTransitionType::HTML;
|
||||
|
||||
return html_fullscreen_ || (in_transition && is_html_transition);
|
||||
return is_html_fullscreen() || (in_transition && is_html_transition);
|
||||
}
|
||||
|
||||
bool WebContents::TakeFocus(content::WebContents* source, bool reverse) {
|
||||
@@ -3877,7 +3888,7 @@ void WebContents::OnDevToolsSearchCompleted(
|
||||
|
||||
void WebContents::SetHtmlApiFullscreen(bool enter_fullscreen) {
|
||||
// Window is already in fullscreen mode, save the state.
|
||||
if (enter_fullscreen && owner_window_->IsFullscreen()) {
|
||||
if (enter_fullscreen && owner_window()->IsFullscreen()) {
|
||||
native_fullscreen_ = true;
|
||||
UpdateHtmlApiFullscreen(true);
|
||||
return;
|
||||
|
||||
@@ -436,7 +436,13 @@ class WebContents : public ExclusiveAccessContext,
|
||||
// content::RenderWidgetHost::InputEventObserver:
|
||||
void OnInputEvent(const blink::WebInputEvent& event) override;
|
||||
|
||||
SkRegion* draggable_region() { return draggable_region_.get(); }
|
||||
SkRegion* draggable_region() {
|
||||
return force_non_draggable_ ? nullptr : draggable_region_.get();
|
||||
}
|
||||
|
||||
void SetForceNonDraggable(bool force_non_draggable) {
|
||||
force_non_draggable_ = force_non_draggable;
|
||||
}
|
||||
|
||||
// disable copy
|
||||
WebContents(const WebContents&) = delete;
|
||||
@@ -820,6 +826,8 @@ class WebContents : public ExclusiveAccessContext,
|
||||
|
||||
std::unique_ptr<SkRegion> draggable_region_;
|
||||
|
||||
bool force_non_draggable_ = false;
|
||||
|
||||
base::WeakPtrFactory<WebContents> weak_factory_{this};
|
||||
};
|
||||
|
||||
|
||||
@@ -94,17 +94,34 @@ struct UserData : public base::SupportsUserData::Data {
|
||||
WebRequest* data;
|
||||
};
|
||||
|
||||
// Test whether the URL of |request| matches |patterns|.
|
||||
bool MatchesFilterCondition(extensions::WebRequestInfo* info,
|
||||
const std::set<URLPattern>& patterns) {
|
||||
if (patterns.empty())
|
||||
return true;
|
||||
|
||||
for (const auto& pattern : patterns) {
|
||||
if (pattern.MatchesURL(info->url))
|
||||
return true;
|
||||
extensions::WebRequestResourceType ParseResourceType(const std::string& value) {
|
||||
if (value == "mainFrame") {
|
||||
return extensions::WebRequestResourceType::MAIN_FRAME;
|
||||
} else if (value == "subFrame") {
|
||||
return extensions::WebRequestResourceType::SUB_FRAME;
|
||||
} else if (value == "stylesheet") {
|
||||
return extensions::WebRequestResourceType::STYLESHEET;
|
||||
} else if (value == "script") {
|
||||
return extensions::WebRequestResourceType::SCRIPT;
|
||||
} else if (value == "image") {
|
||||
return extensions::WebRequestResourceType::IMAGE;
|
||||
} else if (value == "font") {
|
||||
return extensions::WebRequestResourceType::FONT;
|
||||
} else if (value == "object") {
|
||||
return extensions::WebRequestResourceType::OBJECT;
|
||||
} else if (value == "xhr") {
|
||||
return extensions::WebRequestResourceType::XHR;
|
||||
} else if (value == "ping") {
|
||||
return extensions::WebRequestResourceType::PING;
|
||||
} else if (value == "cspReport") {
|
||||
return extensions::WebRequestResourceType::CSP_REPORT;
|
||||
} else if (value == "media") {
|
||||
return extensions::WebRequestResourceType::MEDIA;
|
||||
} else if (value == "webSocket") {
|
||||
return extensions::WebRequestResourceType::WEB_SOCKET;
|
||||
} else {
|
||||
return extensions::WebRequestResourceType::OTHER;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Convert HttpResponseHeaders to V8.
|
||||
@@ -247,17 +264,54 @@ void ReadFromResponse(v8::Isolate* isolate,
|
||||
|
||||
gin::WrapperInfo WebRequest::kWrapperInfo = {gin::kEmbedderNativeGin};
|
||||
|
||||
WebRequest::SimpleListenerInfo::SimpleListenerInfo(
|
||||
std::set<URLPattern> patterns_,
|
||||
SimpleListener listener_)
|
||||
: url_patterns(std::move(patterns_)), listener(listener_) {}
|
||||
WebRequest::RequestFilter::RequestFilter(
|
||||
std::set<URLPattern> url_patterns,
|
||||
std::set<extensions::WebRequestResourceType> types)
|
||||
: url_patterns_(std::move(url_patterns)), types_(std::move(types)) {}
|
||||
WebRequest::RequestFilter::RequestFilter(const RequestFilter&) = default;
|
||||
WebRequest::RequestFilter::RequestFilter() = default;
|
||||
WebRequest::RequestFilter::~RequestFilter() = default;
|
||||
|
||||
void WebRequest::RequestFilter::AddUrlPattern(URLPattern pattern) {
|
||||
url_patterns_.emplace(std::move(pattern));
|
||||
}
|
||||
|
||||
void WebRequest::RequestFilter::AddType(
|
||||
extensions::WebRequestResourceType type) {
|
||||
types_.insert(type);
|
||||
}
|
||||
|
||||
bool WebRequest::RequestFilter::MatchesURL(const GURL& url) const {
|
||||
if (url_patterns_.empty())
|
||||
return true;
|
||||
|
||||
for (const auto& pattern : url_patterns_) {
|
||||
if (pattern.MatchesURL(url))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool WebRequest::RequestFilter::MatchesType(
|
||||
extensions::WebRequestResourceType type) const {
|
||||
return types_.empty() || types_.find(type) != types_.end();
|
||||
}
|
||||
|
||||
bool WebRequest::RequestFilter::MatchesRequest(
|
||||
extensions::WebRequestInfo* info) const {
|
||||
return MatchesURL(info->url) && MatchesType(info->web_request_type);
|
||||
}
|
||||
|
||||
WebRequest::SimpleListenerInfo::SimpleListenerInfo(RequestFilter filter_,
|
||||
SimpleListener listener_)
|
||||
: filter(std::move(filter_)), listener(listener_) {}
|
||||
WebRequest::SimpleListenerInfo::SimpleListenerInfo() = default;
|
||||
WebRequest::SimpleListenerInfo::~SimpleListenerInfo() = default;
|
||||
|
||||
WebRequest::ResponseListenerInfo::ResponseListenerInfo(
|
||||
std::set<URLPattern> patterns_,
|
||||
RequestFilter filter_,
|
||||
ResponseListener listener_)
|
||||
: url_patterns(std::move(patterns_)), listener(listener_) {}
|
||||
: filter(std::move(filter_)), listener(listener_) {}
|
||||
WebRequest::ResponseListenerInfo::ResponseListenerInfo() = default;
|
||||
WebRequest::ResponseListenerInfo::~ResponseListenerInfo() = default;
|
||||
|
||||
@@ -392,8 +446,8 @@ void WebRequest::SetListener(Event event,
|
||||
gin::Arguments* args) {
|
||||
v8::Local<v8::Value> arg;
|
||||
|
||||
// { urls }.
|
||||
std::set<std::string> filter_patterns;
|
||||
// { urls, types }.
|
||||
std::set<std::string> filter_patterns, filter_types;
|
||||
gin::Dictionary dict(args->isolate());
|
||||
if (args->GetNext(&arg) && !arg->IsFunction()) {
|
||||
// Note that gin treats Function as Dictionary when doing conversions, so we
|
||||
@@ -404,16 +458,18 @@ void WebRequest::SetListener(Event event,
|
||||
args->ThrowTypeError("Parameter 'filter' must have property 'urls'.");
|
||||
return;
|
||||
}
|
||||
dict.Get("types", &filter_types);
|
||||
args->GetNext(&arg);
|
||||
}
|
||||
}
|
||||
|
||||
std::set<URLPattern> patterns;
|
||||
RequestFilter filter;
|
||||
|
||||
for (const std::string& filter_pattern : filter_patterns) {
|
||||
URLPattern pattern(URLPattern::SCHEME_ALL);
|
||||
const URLPattern::ParseResult result = pattern.Parse(filter_pattern);
|
||||
if (result == URLPattern::ParseResult::kSuccess) {
|
||||
patterns.insert(pattern);
|
||||
filter.AddUrlPattern(std::move(pattern));
|
||||
} else {
|
||||
const char* error_type = URLPattern::GetParseResultString(result);
|
||||
args->ThrowTypeError("Invalid url pattern " + filter_pattern + ": " +
|
||||
@@ -422,6 +478,16 @@ void WebRequest::SetListener(Event event,
|
||||
}
|
||||
}
|
||||
|
||||
for (const std::string& filter_type : filter_types) {
|
||||
auto type = ParseResourceType(filter_type);
|
||||
if (type != extensions::WebRequestResourceType::OTHER) {
|
||||
filter.AddType(type);
|
||||
} else {
|
||||
args->ThrowTypeError("Invalid type " + filter_type);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Function or null.
|
||||
Listener listener;
|
||||
if (arg.IsEmpty() ||
|
||||
@@ -433,7 +499,7 @@ void WebRequest::SetListener(Event event,
|
||||
if (listener.is_null())
|
||||
listeners->erase(event);
|
||||
else
|
||||
(*listeners)[event] = {std::move(patterns), std::move(listener)};
|
||||
(*listeners)[event] = {std::move(filter), std::move(listener)};
|
||||
}
|
||||
|
||||
template <typename... Args>
|
||||
@@ -445,7 +511,7 @@ void WebRequest::HandleSimpleEvent(SimpleEvent event,
|
||||
return;
|
||||
|
||||
const auto& info = iter->second;
|
||||
if (!MatchesFilterCondition(request_info, info.url_patterns))
|
||||
if (!info.filter.MatchesRequest(request_info))
|
||||
return;
|
||||
|
||||
v8::Isolate* isolate = JavascriptEnvironment::GetIsolate();
|
||||
@@ -466,7 +532,7 @@ int WebRequest::HandleResponseEvent(ResponseEvent event,
|
||||
return net::OK;
|
||||
|
||||
const auto& info = iter->second;
|
||||
if (!MatchesFilterCondition(request_info, info.url_patterns))
|
||||
if (!info.filter.MatchesRequest(request_info))
|
||||
return net::OK;
|
||||
|
||||
callbacks_[request_info->id] = std::move(callback);
|
||||
|
||||
@@ -123,20 +123,41 @@ class WebRequest : public gin::Wrappable<WebRequest>, public WebRequestAPI {
|
||||
template <typename T>
|
||||
void OnListenerResult(uint64_t id, T out, v8::Local<v8::Value> response);
|
||||
|
||||
class RequestFilter {
|
||||
public:
|
||||
RequestFilter(std::set<URLPattern>,
|
||||
std::set<extensions::WebRequestResourceType>);
|
||||
RequestFilter(const RequestFilter&);
|
||||
RequestFilter();
|
||||
~RequestFilter();
|
||||
|
||||
void AddUrlPattern(URLPattern pattern);
|
||||
void AddType(extensions::WebRequestResourceType type);
|
||||
|
||||
bool MatchesRequest(extensions::WebRequestInfo* info) const;
|
||||
|
||||
private:
|
||||
bool MatchesURL(const GURL& url) const;
|
||||
bool MatchesType(extensions::WebRequestResourceType type) const;
|
||||
|
||||
std::set<URLPattern> url_patterns_;
|
||||
std::set<extensions::WebRequestResourceType> types_;
|
||||
};
|
||||
|
||||
struct SimpleListenerInfo {
|
||||
std::set<URLPattern> url_patterns;
|
||||
RequestFilter filter;
|
||||
SimpleListener listener;
|
||||
|
||||
SimpleListenerInfo(std::set<URLPattern>, SimpleListener);
|
||||
SimpleListenerInfo(RequestFilter, SimpleListener);
|
||||
SimpleListenerInfo();
|
||||
~SimpleListenerInfo();
|
||||
};
|
||||
|
||||
struct ResponseListenerInfo {
|
||||
std::set<URLPattern> url_patterns;
|
||||
RequestFilter filter;
|
||||
ResponseListener listener;
|
||||
|
||||
ResponseListenerInfo(std::set<URLPattern>, ResponseListener);
|
||||
ResponseListenerInfo(RequestFilter, ResponseListener);
|
||||
ResponseListenerInfo();
|
||||
~ResponseListenerInfo();
|
||||
};
|
||||
|
||||
@@ -363,7 +363,7 @@ class Browser : public WindowListObserver {
|
||||
base::Time last_dock_show_;
|
||||
#endif
|
||||
|
||||
base::Value about_panel_options_;
|
||||
base::Value::Dict about_panel_options_;
|
||||
|
||||
#if BUILDFLAG(IS_WIN)
|
||||
void UpdateBadgeContents(HWND hwnd,
|
||||
|
||||
@@ -162,31 +162,25 @@ bool Browser::IsEmojiPanelSupported() {
|
||||
void Browser::ShowAboutPanel() {
|
||||
const auto& opts = about_panel_options_;
|
||||
|
||||
if (!opts.is_dict()) {
|
||||
LOG(WARNING) << "Called showAboutPanel(), but didn't use "
|
||||
"setAboutPanelSettings() first";
|
||||
return;
|
||||
}
|
||||
|
||||
GtkWidget* dialogWidget = gtk_about_dialog_new();
|
||||
GtkAboutDialog* dialog = GTK_ABOUT_DIALOG(dialogWidget);
|
||||
|
||||
const std::string* str;
|
||||
const base::Value* val;
|
||||
const base::Value::List* list;
|
||||
|
||||
if ((str = opts.FindStringKey("applicationName"))) {
|
||||
if ((str = opts.FindString("applicationName"))) {
|
||||
gtk_about_dialog_set_program_name(dialog, str->c_str());
|
||||
}
|
||||
if ((str = opts.FindStringKey("applicationVersion"))) {
|
||||
if ((str = opts.FindString("applicationVersion"))) {
|
||||
gtk_about_dialog_set_version(dialog, str->c_str());
|
||||
}
|
||||
if ((str = opts.FindStringKey("copyright"))) {
|
||||
if ((str = opts.FindString("copyright"))) {
|
||||
gtk_about_dialog_set_copyright(dialog, str->c_str());
|
||||
}
|
||||
if ((str = opts.FindStringKey("website"))) {
|
||||
if ((str = opts.FindString("website"))) {
|
||||
gtk_about_dialog_set_website(dialog, str->c_str());
|
||||
}
|
||||
if ((str = opts.FindStringKey("iconPath"))) {
|
||||
if ((str = opts.FindString("iconPath"))) {
|
||||
GError* error = nullptr;
|
||||
constexpr int width = 64; // width of about panel icon in pixels
|
||||
constexpr int height = 64; // height of about panel icon in pixels
|
||||
@@ -203,9 +197,9 @@ void Browser::ShowAboutPanel() {
|
||||
}
|
||||
}
|
||||
|
||||
if ((val = opts.FindListKey("authors"))) {
|
||||
if ((list = opts.FindList("authors"))) {
|
||||
std::vector<const char*> cstrs;
|
||||
for (const auto& authorVal : val->GetList()) {
|
||||
for (const auto& authorVal : *list) {
|
||||
if (authorVal.is_string()) {
|
||||
cstrs.push_back(authorVal.GetString().c_str());
|
||||
}
|
||||
@@ -223,7 +217,7 @@ void Browser::ShowAboutPanel() {
|
||||
}
|
||||
|
||||
void Browser::SetAboutPanelOptions(base::Value::Dict options) {
|
||||
about_panel_options_ = base::Value(std::move(options));
|
||||
about_panel_options_ = std::move(options);
|
||||
}
|
||||
|
||||
} // namespace electron
|
||||
|
||||
@@ -513,8 +513,7 @@ void Browser::DockSetIcon(v8::Isolate* isolate, v8::Local<v8::Value> icon) {
|
||||
}
|
||||
|
||||
void Browser::ShowAboutPanel() {
|
||||
NSDictionary* options =
|
||||
DictionaryValueToNSDictionary(about_panel_options_.GetDict());
|
||||
NSDictionary* options = DictionaryValueToNSDictionary(about_panel_options_);
|
||||
|
||||
// Credits must be a NSAttributedString instead of NSString
|
||||
NSString* credits = (NSString*)options[@"Credits"];
|
||||
@@ -537,13 +536,13 @@ void Browser::ShowAboutPanel() {
|
||||
}
|
||||
|
||||
void Browser::SetAboutPanelOptions(base::Value::Dict options) {
|
||||
about_panel_options_.GetDict().clear();
|
||||
about_panel_options_.clear();
|
||||
|
||||
for (const auto pair : options) {
|
||||
std::string key = pair.first;
|
||||
if (!key.empty() && pair.second.is_string()) {
|
||||
key[0] = base::ToUpperASCII(key[0]);
|
||||
about_panel_options_.GetDict().Set(key, pair.second.Clone());
|
||||
about_panel_options_.Set(key, pair.second.Clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -734,30 +734,29 @@ void Browser::ShowEmojiPanel() {
|
||||
}
|
||||
|
||||
void Browser::ShowAboutPanel() {
|
||||
base::Value dict(base::Value::Type::DICTIONARY);
|
||||
base::Value::Dict dict;
|
||||
std::string aboutMessage = "";
|
||||
gfx::ImageSkia image;
|
||||
|
||||
// grab defaults from Windows .EXE file
|
||||
std::unique_ptr<FileVersionInfo> exe_info = FetchFileVersionInfo();
|
||||
dict.SetStringKey("applicationName", exe_info->file_description());
|
||||
dict.SetStringKey("applicationVersion", exe_info->product_version());
|
||||
dict.Set("applicationName", exe_info->file_description());
|
||||
dict.Set("applicationVersion", exe_info->product_version());
|
||||
|
||||
if (about_panel_options_.is_dict()) {
|
||||
dict.MergeDictionary(&about_panel_options_);
|
||||
}
|
||||
// Merge user-provided options, overwriting any of the above
|
||||
dict.Merge(about_panel_options_.Clone());
|
||||
|
||||
std::vector<std::string> stringOptions = {
|
||||
"applicationName", "applicationVersion", "copyright", "credits"};
|
||||
|
||||
const std::string* str;
|
||||
for (std::string opt : stringOptions) {
|
||||
if ((str = dict.FindStringKey(opt))) {
|
||||
if ((str = dict.FindString(opt))) {
|
||||
aboutMessage.append(*str).append("\r\n");
|
||||
}
|
||||
}
|
||||
|
||||
if ((str = dict.FindStringKey("iconPath"))) {
|
||||
if ((str = dict.FindString("iconPath"))) {
|
||||
base::FilePath path = base::FilePath::FromUTF8Unsafe(*str);
|
||||
electron::util::PopulateImageSkiaRepsFromPath(&image, path);
|
||||
}
|
||||
@@ -770,7 +769,7 @@ void Browser::ShowAboutPanel() {
|
||||
}
|
||||
|
||||
void Browser::SetAboutPanelOptions(base::Value::Dict options) {
|
||||
about_panel_options_ = base::Value(std::move(options));
|
||||
about_panel_options_ = std::move(options);
|
||||
}
|
||||
|
||||
} // namespace electron
|
||||
|
||||
@@ -619,7 +619,7 @@ void NativeWindowMac::SetFullScreen(bool fullscreen) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (fullscreen == IsFullscreen())
|
||||
if (fullscreen == IsFullscreen() || !IsFullScreenable())
|
||||
return;
|
||||
|
||||
// Take note of the current window size
|
||||
|
||||
@@ -58,7 +58,11 @@ void CocoaNotification::Show(const NotificationOptions& options) {
|
||||
[notification_ setSoundName:base::SysUTF16ToNSString(options.sound)];
|
||||
}
|
||||
|
||||
[notification_ setHasActionButton:false];
|
||||
if (options.has_reply) {
|
||||
[notification_ setHasReplyButton:true];
|
||||
[notification_ setResponsePlaceholder:base::SysUTF16ToNSString(
|
||||
options.reply_placeholder)];
|
||||
}
|
||||
|
||||
int i = 0;
|
||||
action_index_ = UINT_MAX;
|
||||
@@ -66,7 +70,10 @@ void CocoaNotification::Show(const NotificationOptions& options) {
|
||||
[[[NSMutableArray alloc] init] autorelease];
|
||||
for (const auto& action : options.actions) {
|
||||
if (action.type == u"button") {
|
||||
if (action_index_ == UINT_MAX) {
|
||||
// If the notification has both a reply and actions,
|
||||
// the reply takes precedence and the actions all
|
||||
// become additional actions.
|
||||
if (!options.has_reply && action_index_ == UINT_MAX) {
|
||||
// First button observed is the displayed action
|
||||
[notification_ setHasActionButton:true];
|
||||
[notification_
|
||||
@@ -86,16 +93,11 @@ void CocoaNotification::Show(const NotificationOptions& options) {
|
||||
}
|
||||
i++;
|
||||
}
|
||||
|
||||
if ([additionalActions count] > 0) {
|
||||
[notification_ setAdditionalActions:additionalActions];
|
||||
}
|
||||
|
||||
if (options.has_reply) {
|
||||
[notification_ setResponsePlaceholder:base::SysUTF16ToNSString(
|
||||
options.reply_placeholder)];
|
||||
[notification_ setHasReplyButton:true];
|
||||
}
|
||||
|
||||
if (!options.close_button_text.empty()) {
|
||||
[notification_ setOtherButtonTitle:base::SysUTF16ToNSString(
|
||||
options.close_button_text)];
|
||||
|
||||
@@ -1,21 +0,0 @@
|
||||
// Copyright (c) 2018 GitHub, Inc.
|
||||
// Use of this source code is governed by the MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "shell/browser/ui/cocoa/delayed_native_view_host.h"
|
||||
|
||||
namespace electron {
|
||||
|
||||
DelayedNativeViewHost::DelayedNativeViewHost(gfx::NativeView native_view)
|
||||
: native_view_(native_view) {}
|
||||
|
||||
DelayedNativeViewHost::~DelayedNativeViewHost() = default;
|
||||
|
||||
void DelayedNativeViewHost::ViewHierarchyChanged(
|
||||
const views::ViewHierarchyChangedDetails& details) {
|
||||
NativeViewHost::ViewHierarchyChanged(details);
|
||||
if (details.is_add && GetWidget())
|
||||
Attach(native_view_);
|
||||
}
|
||||
|
||||
} // namespace electron
|
||||
@@ -23,6 +23,7 @@ class DelayedNativeViewHost : public views::NativeViewHost {
|
||||
// views::View:
|
||||
void ViewHierarchyChanged(
|
||||
const views::ViewHierarchyChangedDetails& details) override;
|
||||
bool OnMousePressed(const ui::MouseEvent& event) override;
|
||||
|
||||
private:
|
||||
gfx::NativeView native_view_;
|
||||
|
||||
37
shell/browser/ui/cocoa/delayed_native_view_host.mm
Normal file
37
shell/browser/ui/cocoa/delayed_native_view_host.mm
Normal file
@@ -0,0 +1,37 @@
|
||||
// Copyright (c) 2018 GitHub, Inc.
|
||||
// Use of this source code is governed by the MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "shell/browser/ui/cocoa/delayed_native_view_host.h"
|
||||
#include "shell/browser/ui/cocoa/electron_inspectable_web_contents_view.h"
|
||||
|
||||
namespace electron {
|
||||
|
||||
DelayedNativeViewHost::DelayedNativeViewHost(gfx::NativeView native_view)
|
||||
: native_view_(native_view) {}
|
||||
|
||||
DelayedNativeViewHost::~DelayedNativeViewHost() = default;
|
||||
|
||||
void DelayedNativeViewHost::ViewHierarchyChanged(
|
||||
const views::ViewHierarchyChangedDetails& details) {
|
||||
NativeViewHost::ViewHierarchyChanged(details);
|
||||
if (details.is_add && GetWidget())
|
||||
Attach(native_view_);
|
||||
}
|
||||
|
||||
bool DelayedNativeViewHost::OnMousePressed(const ui::MouseEvent& ui_event) {
|
||||
// NativeViewHost::OnMousePressed normally isn't called, but
|
||||
// NativeWidgetMacNSWindow specifically carves out an event here for
|
||||
// right-mouse-button clicks. We want to forward them to the web content, so
|
||||
// handle them here.
|
||||
// See:
|
||||
// https://source.chromium.org/chromium/chromium/src/+/main:components/remote_cocoa/app_shim/native_widget_mac_nswindow.mm;l=415-421;drc=a5af91924bafb85426e091c6035801990a6dc697
|
||||
ElectronInspectableWebContentsView* inspectable_web_contents_view =
|
||||
(ElectronInspectableWebContentsView*)native_view_.GetNativeNSView();
|
||||
[inspectable_web_contents_view
|
||||
redispatchContextMenuEvent:ui_event.native_event()];
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace electron
|
||||
@@ -46,6 +46,8 @@ using electron::InspectableWebContentsViewMac;
|
||||
(const DevToolsContentsResizingStrategy&)strategy;
|
||||
- (void)setTitle:(NSString*)title;
|
||||
|
||||
- (void)redispatchContextMenuEvent:(NSEvent*)theEvent;
|
||||
|
||||
@end
|
||||
|
||||
#endif // ELECTRON_SHELL_BROWSER_UI_COCOA_ELECTRON_INSPECTABLE_WEB_CONTENTS_VIEW_H_
|
||||
|
||||
@@ -5,10 +5,12 @@
|
||||
#include "shell/browser/ui/cocoa/electron_inspectable_web_contents_view.h"
|
||||
|
||||
#include "content/public/browser/render_widget_host_view.h"
|
||||
#include "shell/browser/api/electron_api_web_contents.h"
|
||||
#include "shell/browser/ui/cocoa/event_dispatching_window.h"
|
||||
#include "shell/browser/ui/inspectable_web_contents.h"
|
||||
#include "shell/browser/ui/inspectable_web_contents_view_delegate.h"
|
||||
#include "shell/browser/ui/inspectable_web_contents_view_mac.h"
|
||||
#include "ui/base/cocoa/base_view.h"
|
||||
#include "ui/gfx/mac/scoped_cocoa_disable_screen_updates.h"
|
||||
|
||||
@implementation ElectronInspectableWebContentsView
|
||||
@@ -273,6 +275,27 @@
|
||||
[self notifyDevToolsFocused];
|
||||
}
|
||||
|
||||
- (void)redispatchContextMenuEvent:(NSEvent*)event {
|
||||
DCHECK(event.type == NSEventTypeRightMouseDown ||
|
||||
(event.type == NSEventTypeLeftMouseDown &&
|
||||
(event.modifierFlags & NSEventModifierFlagControl)));
|
||||
content::WebContents* contents =
|
||||
inspectableWebContentsView_->inspectable_web_contents()->GetWebContents();
|
||||
electron::api::WebContents* api_contents =
|
||||
electron::api::WebContents::From(contents);
|
||||
if (api_contents) {
|
||||
// Temporarily pretend that the WebContents is fully non-draggable while we
|
||||
// re-send the mouse event. This allows the re-dispatched event to "land"
|
||||
// on the WebContents, instead of "falling through" back to the window.
|
||||
api_contents->SetForceNonDraggable(true);
|
||||
BaseView* contentsView = (BaseView*)contents->GetRenderWidgetHostView()
|
||||
->GetNativeView()
|
||||
.GetNativeNSView();
|
||||
[contentsView mouseEvent:event];
|
||||
api_contents->SetForceNonDraggable(false);
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - NSWindowDelegate
|
||||
|
||||
- (void)windowWillClose:(NSNotification*)notification {
|
||||
|
||||
@@ -128,16 +128,17 @@ using FullScreenTransitionState =
|
||||
- (NSSize)windowWillResize:(NSWindow*)sender toSize:(NSSize)frameSize {
|
||||
NSSize newSize = frameSize;
|
||||
double aspectRatio = shell_->GetAspectRatio();
|
||||
NSWindow* window = shell_->GetNativeWindow().GetNativeNSWindow();
|
||||
|
||||
if (aspectRatio > 0.0) {
|
||||
gfx::Size windowSize = shell_->GetSize();
|
||||
gfx::Size contentSize = shell_->GetContentSize();
|
||||
gfx::Size extraSize = shell_->GetAspectRatioExtraSize();
|
||||
|
||||
double titleBarHeight = windowSize.height() - contentSize.height();
|
||||
double extraWidthPlusFrame =
|
||||
windowSize.width() - contentSize.width() + extraSize.width();
|
||||
double extraHeightPlusFrame =
|
||||
windowSize.height() - contentSize.height() + extraSize.height();
|
||||
double extraHeightPlusFrame = titleBarHeight + extraSize.height();
|
||||
|
||||
newSize.width =
|
||||
roundf((frameSize.height - extraHeightPlusFrame) * aspectRatio +
|
||||
@@ -145,10 +146,44 @@ using FullScreenTransitionState =
|
||||
newSize.height =
|
||||
roundf((newSize.width - extraWidthPlusFrame) / aspectRatio +
|
||||
extraHeightPlusFrame);
|
||||
|
||||
// Clamp to minimum width/height while ensuring aspect ratio remains.
|
||||
NSSize minSize = [window minSize];
|
||||
NSSize zeroSize =
|
||||
shell_->has_frame() ? NSMakeSize(0, titleBarHeight) : NSZeroSize;
|
||||
if (!NSEqualSizes(minSize, zeroSize)) {
|
||||
double minWidthForAspectRatio =
|
||||
(minSize.height - titleBarHeight) * aspectRatio;
|
||||
bool atMinHeight =
|
||||
minSize.height > zeroSize.height && newSize.height <= minSize.height;
|
||||
newSize.width = atMinHeight ? minWidthForAspectRatio
|
||||
: std::max(newSize.width, minSize.width);
|
||||
|
||||
double minHeightForAspectRatio = minSize.width / aspectRatio;
|
||||
bool atMinWidth =
|
||||
minSize.width > zeroSize.width && newSize.width <= minSize.width;
|
||||
newSize.height = atMinWidth ? minHeightForAspectRatio
|
||||
: std::max(newSize.height, minSize.height);
|
||||
}
|
||||
|
||||
// Clamp to maximum width/height while ensuring aspect ratio remains.
|
||||
NSSize maxSize = [window maxSize];
|
||||
if (!NSEqualSizes(maxSize, NSMakeSize(FLT_MAX, FLT_MAX))) {
|
||||
double maxWidthForAspectRatio = maxSize.height * aspectRatio;
|
||||
bool atMaxHeight =
|
||||
maxSize.height < FLT_MAX && newSize.height >= maxSize.height;
|
||||
newSize.width = atMaxHeight ? maxWidthForAspectRatio
|
||||
: std::min(newSize.width, maxSize.width);
|
||||
|
||||
double maxHeightForAspectRatio = maxSize.width / aspectRatio;
|
||||
bool atMaxWidth =
|
||||
maxSize.width < FLT_MAX && newSize.width >= maxSize.width;
|
||||
newSize.height = atMaxWidth ? maxHeightForAspectRatio
|
||||
: std::min(newSize.height, maxSize.height);
|
||||
}
|
||||
}
|
||||
|
||||
if (!resizingHorizontally_) {
|
||||
NSWindow* window = shell_->GetNativeWindow().GetNativeNSWindow();
|
||||
const auto widthDelta = frameSize.width - [window frame].size.width;
|
||||
const auto heightDelta = frameSize.height - [window frame].size.height;
|
||||
resizingHorizontally_ = std::abs(widthDelta) > std::abs(heightDelta);
|
||||
|
||||
@@ -64,6 +64,7 @@ v8::Local<v8::Promise> OpenExternal(const GURL& url, gin::Arguments* args) {
|
||||
if (args->GetNext(&obj)) {
|
||||
obj.Get("activate", &options.activate);
|
||||
obj.Get("workingDirectory", &options.working_dir);
|
||||
obj.Get("logUsage", &options.log_usage);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -28,6 +28,7 @@ void OpenPath(const base::FilePath& full_path, OpenCallback callback);
|
||||
struct OpenExternalOptions {
|
||||
bool activate = true;
|
||||
base::FilePath working_dir;
|
||||
bool log_usage = false;
|
||||
};
|
||||
|
||||
// Open the given external protocol URL in the desktop's default manner.
|
||||
|
||||
@@ -246,10 +246,19 @@ std::string OpenExternalOnWorkerThread(
|
||||
L"\"";
|
||||
std::wstring working_dir = options.working_dir.value();
|
||||
|
||||
if (reinterpret_cast<ULONG_PTR>(
|
||||
ShellExecuteW(nullptr, L"open", escaped_url.c_str(), nullptr,
|
||||
working_dir.empty() ? nullptr : working_dir.c_str(),
|
||||
SW_SHOWNORMAL)) <= 32) {
|
||||
SHELLEXECUTEINFO info = {};
|
||||
info.cbSize = sizeof(SHELLEXECUTEINFO);
|
||||
info.fMask = SEE_MASK_NOASYNC | SEE_MASK_FLAG_NO_UI;
|
||||
info.lpVerb = L"open";
|
||||
info.lpFile = escaped_url.c_str();
|
||||
info.lpDirectory = working_dir.empty() ? nullptr : working_dir.c_str();
|
||||
info.nShow = SW_SHOWNORMAL;
|
||||
|
||||
if (options.log_usage) {
|
||||
info.fMask |= SEE_MASK_FLAG_LOG_USAGE;
|
||||
}
|
||||
|
||||
if (!ShellExecuteEx(&info)) {
|
||||
return "Failed to open: " +
|
||||
logging::SystemErrorCodeToString(logging::GetLastSystemErrorCode());
|
||||
}
|
||||
|
||||
@@ -84,8 +84,7 @@ ElectronContentUtilityClient::ElectronContentUtilityClient() = default;
|
||||
ElectronContentUtilityClient::~ElectronContentUtilityClient() = default;
|
||||
|
||||
// The guts of this came from the chromium implementation
|
||||
// https://cs.chromium.org/chromium/src/chrome/utility/
|
||||
// chrome_content_utility_client.cc?sq=package:chromium&dr=CSs&g=0&l=142
|
||||
// https://source.chromium.org/chromium/chromium/src/+/main:chrome/utility/chrome_content_utility_client.cc
|
||||
void ElectronContentUtilityClient::ExposeInterfacesToBrowser(
|
||||
mojo::BinderMap* binders) {
|
||||
#if BUILDFLAG(IS_WIN)
|
||||
|
||||
@@ -1863,6 +1863,15 @@ describe('app module', () => {
|
||||
})).to.eventually.be.rejectedWith(/ERR_NAME_NOT_RESOLVED/);
|
||||
});
|
||||
});
|
||||
|
||||
describe('about panel', () => {
|
||||
it('app.setAboutPanelOptions() does not crash', () => {
|
||||
app.setAboutPanelOptions({
|
||||
applicationName: 'electron!!',
|
||||
version: '1.2.3'
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('default behavior', () => {
|
||||
|
||||
@@ -41,7 +41,7 @@ describe('BrowserView module', () => {
|
||||
});
|
||||
|
||||
it('can be created with an existing webContents', async () => {
|
||||
const wc = (webContents as any).create({ sandbox: true });
|
||||
const wc = (webContents as typeof ElectronInternal.WebContents).create({ sandbox: true });
|
||||
await wc.loadURL('about:blank');
|
||||
|
||||
view = new BrowserView({ webContents: wc } as any);
|
||||
@@ -345,6 +345,24 @@ describe('BrowserView module', () => {
|
||||
const [code] = await emittedOnce(rc.process, 'exit');
|
||||
expect(code).to.equal(0);
|
||||
});
|
||||
|
||||
it('emits the destroyed event when webContents.close() is called', async () => {
|
||||
view = new BrowserView();
|
||||
w.setBrowserView(view);
|
||||
await view.webContents.loadFile(path.join(fixtures, 'pages', 'a.html'));
|
||||
|
||||
view.webContents.close();
|
||||
await emittedOnce(view.webContents, 'destroyed');
|
||||
});
|
||||
|
||||
it('emits the destroyed event when window.close() is called', async () => {
|
||||
view = new BrowserView();
|
||||
w.setBrowserView(view);
|
||||
await view.webContents.loadFile(path.join(fixtures, 'pages', 'a.html'));
|
||||
|
||||
view.webContents.executeJavaScript('window.close()');
|
||||
await emittedOnce(view.webContents, 'destroyed');
|
||||
});
|
||||
});
|
||||
|
||||
describe('window.open()', () => {
|
||||
|
||||
@@ -2184,7 +2184,7 @@ describe('BrowserWindow module', () => {
|
||||
});
|
||||
|
||||
it('returns null for webContents without a BrowserWindow', () => {
|
||||
const contents = (webContents as any).create({});
|
||||
const contents = (webContents as typeof ElectronInternal.WebContents).create();
|
||||
try {
|
||||
expect(BrowserWindow.fromWebContents(contents)).to.be.null('BrowserWindow.fromWebContents(contents)');
|
||||
} finally {
|
||||
@@ -3990,6 +3990,24 @@ describe('BrowserWindow module', () => {
|
||||
w.hide();
|
||||
w.show();
|
||||
});
|
||||
|
||||
// TODO(zcbenz):
|
||||
// This test does not run on Linux CI. See:
|
||||
// https://github.com/electron/electron/issues/28699
|
||||
ifit(process.platform === 'linux' && !process.env.CI)('should bring a minimized maximized window back to maximized state', async () => {
|
||||
const w = new BrowserWindow({});
|
||||
const maximize = emittedOnce(w, 'maximize');
|
||||
w.maximize();
|
||||
await maximize;
|
||||
const minimize = emittedOnce(w, 'minimize');
|
||||
w.minimize();
|
||||
await minimize;
|
||||
expect(w.isMaximized()).to.equal(false);
|
||||
const restore = emittedOnce(w, 'restore');
|
||||
w.restore();
|
||||
await restore;
|
||||
expect(w.isMaximized()).to.equal(true);
|
||||
});
|
||||
});
|
||||
|
||||
// TODO(dsanders11): Enable once maximize event works on Linux again on CI
|
||||
@@ -5026,6 +5044,42 @@ describe('BrowserWindow module', () => {
|
||||
await done;
|
||||
});
|
||||
|
||||
it('handles HTML fullscreen transitions when fullscreenable is false', async () => {
|
||||
const w = new BrowserWindow({ fullscreenable: false });
|
||||
await w.loadFile(path.join(fixtures, 'pages', 'a.html'));
|
||||
|
||||
expect(w.isFullScreen()).to.be.false('is fullscreen');
|
||||
|
||||
let enterCount = 0;
|
||||
let exitCount = 0;
|
||||
|
||||
const done = new Promise<void>((resolve, reject) => {
|
||||
const checkDone = () => {
|
||||
if (enterCount === 2 && exitCount === 2) resolve();
|
||||
};
|
||||
|
||||
w.webContents.on('enter-html-full-screen', async () => {
|
||||
enterCount++;
|
||||
if (w.isFullScreen()) reject(new Error('w.isFullScreen should be false'));
|
||||
const isFS = await w.webContents.executeJavaScript('!!document.fullscreenElement');
|
||||
if (!isFS) reject(new Error('Document should have fullscreen element'));
|
||||
checkDone();
|
||||
});
|
||||
|
||||
w.webContents.on('leave-html-full-screen', () => {
|
||||
exitCount++;
|
||||
if (w.isFullScreen()) reject(new Error('w.isFullScreen should be false'));
|
||||
checkDone();
|
||||
});
|
||||
});
|
||||
|
||||
await w.webContents.executeJavaScript('document.getElementById("div").requestFullscreen()', true);
|
||||
await w.webContents.executeJavaScript('document.exitFullscreen()');
|
||||
await w.webContents.executeJavaScript('document.getElementById("div").requestFullscreen()', true);
|
||||
await w.webContents.executeJavaScript('document.exitFullscreen()');
|
||||
await expect(done).to.eventually.be.fulfilled();
|
||||
});
|
||||
|
||||
it('does not crash when exiting simpleFullScreen (properties)', async () => {
|
||||
const w = new BrowserWindow();
|
||||
w.setSimpleFullScreen(true);
|
||||
|
||||
@@ -80,7 +80,7 @@ describe('dialog module', () => {
|
||||
afterEach(closeAllWindows);
|
||||
|
||||
// parentless message boxes are synchronous on macOS
|
||||
// dangling message boxes on windows cause a DCHECK: https://cs.chromium.org/chromium/src/base/win/message_window.cc?l=68&rcl=7faa4bf236a866d007dc5672c9ce42660e67a6a6
|
||||
// dangling message boxes on windows cause a DCHECK: https://source.chromium.org/chromium/chromium/src/+/main:base/win/message_window.cc;drc=7faa4bf236a866d007dc5672c9ce42660e67a6a6;l=68
|
||||
ifit(process.platform !== 'darwin' && process.platform !== 'win32')('should not throw for a parentless message box', () => {
|
||||
expect(() => {
|
||||
dialog.showMessageBox({ message: 'i am message' });
|
||||
|
||||
@@ -135,7 +135,7 @@ describe('ipcRenderer module', () => {
|
||||
const payload = 'Hello World!';
|
||||
|
||||
before(async () => {
|
||||
contents = (webContents as any).create({
|
||||
contents = (webContents as typeof ElectronInternal.WebContents).create({
|
||||
preload: path.join(fixtures, 'module', 'preload-ipc-ping-pong.js'),
|
||||
...webPreferences
|
||||
});
|
||||
|
||||
@@ -813,6 +813,104 @@ describe('net module', () => {
|
||||
});
|
||||
}
|
||||
|
||||
it('should be able correctly filter out cookies that are secure', async () => {
|
||||
const sess = session.fromPartition(`cookie-tests-${Math.random()}`);
|
||||
|
||||
await Promise.all([
|
||||
sess.cookies.set({
|
||||
url: 'https://electronjs.org',
|
||||
domain: 'electronjs.org',
|
||||
name: 'cookie1',
|
||||
value: '1',
|
||||
secure: true
|
||||
}),
|
||||
sess.cookies.set({
|
||||
url: 'https://electronjs.org',
|
||||
domain: 'electronjs.org',
|
||||
name: 'cookie2',
|
||||
value: '2',
|
||||
secure: false
|
||||
})
|
||||
]);
|
||||
|
||||
const secureCookies = await sess.cookies.get({
|
||||
secure: true
|
||||
});
|
||||
expect(secureCookies).to.have.lengthOf(1);
|
||||
expect(secureCookies[0].name).to.equal('cookie1');
|
||||
|
||||
const cookies = await sess.cookies.get({
|
||||
secure: false
|
||||
});
|
||||
expect(cookies).to.have.lengthOf(1);
|
||||
expect(cookies[0].name).to.equal('cookie2');
|
||||
});
|
||||
|
||||
it('should be able correctly filter out cookies that are session', async () => {
|
||||
const sess = session.fromPartition(`cookie-tests-${Math.random()}`);
|
||||
|
||||
await Promise.all([
|
||||
sess.cookies.set({
|
||||
url: 'https://electronjs.org',
|
||||
domain: 'electronjs.org',
|
||||
name: 'cookie1',
|
||||
value: '1'
|
||||
}),
|
||||
sess.cookies.set({
|
||||
url: 'https://electronjs.org',
|
||||
domain: 'electronjs.org',
|
||||
name: 'cookie2',
|
||||
value: '2',
|
||||
expirationDate: Math.round(Date.now() / 1000) + 10000
|
||||
})
|
||||
]);
|
||||
|
||||
const sessionCookies = await sess.cookies.get({
|
||||
session: true
|
||||
});
|
||||
expect(sessionCookies).to.have.lengthOf(1);
|
||||
expect(sessionCookies[0].name).to.equal('cookie1');
|
||||
|
||||
const cookies = await sess.cookies.get({
|
||||
session: false
|
||||
});
|
||||
expect(cookies).to.have.lengthOf(1);
|
||||
expect(cookies[0].name).to.equal('cookie2');
|
||||
});
|
||||
|
||||
it('should be able correctly filter out cookies that are httpOnly', async () => {
|
||||
const sess = session.fromPartition(`cookie-tests-${Math.random()}`);
|
||||
|
||||
await Promise.all([
|
||||
sess.cookies.set({
|
||||
url: 'https://electronjs.org',
|
||||
domain: 'electronjs.org',
|
||||
name: 'cookie1',
|
||||
value: '1',
|
||||
httpOnly: true
|
||||
}),
|
||||
sess.cookies.set({
|
||||
url: 'https://electronjs.org',
|
||||
domain: 'electronjs.org',
|
||||
name: 'cookie2',
|
||||
value: '2',
|
||||
httpOnly: false
|
||||
})
|
||||
]);
|
||||
|
||||
const httpOnlyCookies = await sess.cookies.get({
|
||||
httpOnly: true
|
||||
});
|
||||
expect(httpOnlyCookies).to.have.lengthOf(1);
|
||||
expect(httpOnlyCookies[0].name).to.equal('cookie1');
|
||||
|
||||
const cookies = await sess.cookies.get({
|
||||
httpOnly: false
|
||||
});
|
||||
expect(cookies).to.have.lengthOf(1);
|
||||
expect(cookies[0].name).to.equal('cookie2');
|
||||
});
|
||||
|
||||
describe('when {"credentials":"omit"}', () => {
|
||||
it('should not send cookies');
|
||||
it('should not store cookies');
|
||||
|
||||
@@ -73,7 +73,7 @@ function defer (): Promise<any> & {resolve: Function, reject: Function} {
|
||||
describe('protocol module', () => {
|
||||
let contents: WebContents = null as unknown as WebContents;
|
||||
// NB. sandbox: true is used because it makes navigations much (~8x) faster.
|
||||
before(() => { contents = (webContents as any).create({ sandbox: true }); });
|
||||
before(() => { contents = (webContents as typeof ElectronInternal.WebContents).create({ sandbox: true }); });
|
||||
after(() => contents.destroy());
|
||||
|
||||
async function ajax (url: string, options = {}) {
|
||||
@@ -952,7 +952,10 @@ describe('protocol module', () => {
|
||||
callback('');
|
||||
});
|
||||
|
||||
const newContents: WebContents = (webContents as any).create({ nodeIntegration: true, contextIsolation: false });
|
||||
const newContents = (webContents as typeof ElectronInternal.WebContents).create({
|
||||
nodeIntegration: true,
|
||||
contextIsolation: false
|
||||
});
|
||||
const consoleMessages: string[] = [];
|
||||
newContents.on('console-message', (e, level, message) => consoleMessages.push(message));
|
||||
try {
|
||||
@@ -1053,7 +1056,11 @@ describe('protocol module', () => {
|
||||
await registerStreamProtocol(standardScheme, protocolHandler);
|
||||
await registerStreamProtocol('stream', protocolHandler);
|
||||
|
||||
const newContents: WebContents = (webContents as any).create({ nodeIntegration: true, contextIsolation: false });
|
||||
const newContents = (webContents as typeof ElectronInternal.WebContents).create({
|
||||
nodeIntegration: true,
|
||||
contextIsolation: false
|
||||
});
|
||||
|
||||
try {
|
||||
newContents.loadURL(testingScheme + '://fake-host');
|
||||
const [, response] = await emittedOnce(ipcMain, 'result');
|
||||
|
||||
@@ -39,7 +39,7 @@ describe('session.serviceWorkers', () => {
|
||||
});
|
||||
});
|
||||
|
||||
w = (webContents as any).create({ session: ses });
|
||||
w = (webContents as typeof ElectronInternal.WebContents).create({ session: ses });
|
||||
});
|
||||
|
||||
afterEach(async () => {
|
||||
|
||||
@@ -3,7 +3,7 @@ import { AddressInfo } from 'net';
|
||||
import * as path from 'path';
|
||||
import * as fs from 'fs';
|
||||
import * as http from 'http';
|
||||
import { BrowserWindow, ipcMain, webContents, session, WebContents, app, BrowserView } from 'electron/main';
|
||||
import { BrowserWindow, ipcMain, webContents, session, app, BrowserView } from 'electron/main';
|
||||
import { emittedOnce } from './lib/events-helpers';
|
||||
import { closeAllWindows } from './lib/window-helpers';
|
||||
import { ifdescribe, delay, defer, waitUntil } from './lib/spec-helpers';
|
||||
@@ -48,11 +48,11 @@ describe('webContents module', () => {
|
||||
|
||||
describe('fromFrame()', () => {
|
||||
it('returns WebContents for mainFrame', () => {
|
||||
const contents = (webContents as any).create() as WebContents;
|
||||
const contents = (webContents as typeof ElectronInternal.WebContents).create();
|
||||
expect(webContents.fromFrame(contents.mainFrame)).to.equal(contents);
|
||||
});
|
||||
it('returns undefined for disposed frame', async () => {
|
||||
const contents = (webContents as any).create() as WebContents;
|
||||
const contents = (webContents as typeof ElectronInternal.WebContents).create();
|
||||
const { mainFrame } = contents;
|
||||
contents.destroy();
|
||||
await waitUntil(() => typeof webContents.fromFrame(mainFrame) === 'undefined');
|
||||
@@ -1549,7 +1549,7 @@ describe('webContents module', () => {
|
||||
// is fine to retry this test for a few times.
|
||||
this.retries(3);
|
||||
|
||||
const contents = (webContents as any).create() as WebContents;
|
||||
const contents = (webContents as typeof ElectronInternal.WebContents).create();
|
||||
const originalEmit = contents.emit.bind(contents);
|
||||
contents.emit = (...args) => { return originalEmit(...args); };
|
||||
contents.once(e.name as any, () => contents.destroy());
|
||||
@@ -1812,8 +1812,24 @@ describe('webContents module', () => {
|
||||
|
||||
await w.loadURL('about:blank');
|
||||
|
||||
const promise = w.webContents.takeHeapSnapshot('');
|
||||
return expect(promise).to.be.eventually.rejectedWith(Error, 'takeHeapSnapshot failed');
|
||||
const badPath = path.join('i', 'am', 'a', 'super', 'bad', 'path');
|
||||
const promise = w.webContents.takeHeapSnapshot(badPath);
|
||||
return expect(promise).to.be.eventually.rejectedWith(Error, `Failed to take heap snapshot with invalid file path ${badPath}`);
|
||||
});
|
||||
|
||||
it('fails with invalid render process', async () => {
|
||||
const w = new BrowserWindow({
|
||||
show: false,
|
||||
webPreferences: {
|
||||
sandbox: true
|
||||
}
|
||||
});
|
||||
|
||||
const filePath = path.join(app.getPath('temp'), 'test.heapsnapshot');
|
||||
|
||||
w.webContents.destroy();
|
||||
const promise = w.webContents.takeHeapSnapshot(filePath);
|
||||
return expect(promise).to.be.eventually.rejectedWith(Error, 'Failed to take heap snapshot with nonexistent render frame');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -2226,8 +2242,8 @@ describe('webContents module', () => {
|
||||
|
||||
describe('crashed event', () => {
|
||||
it('does not crash main process when destroying WebContents in it', (done) => {
|
||||
const contents = (webContents as any).create({ nodeIntegration: true });
|
||||
contents.once('crashed', () => {
|
||||
const contents = (webContents as typeof ElectronInternal.WebContents).create({ nodeIntegration: true });
|
||||
contents.once('render-process-gone', () => {
|
||||
contents.destroy();
|
||||
done();
|
||||
});
|
||||
@@ -2261,7 +2277,7 @@ describe('webContents module', () => {
|
||||
afterEach(closeAllWindows);
|
||||
|
||||
it('closes when close() is called', async () => {
|
||||
const w = (webContents as any).create() as WebContents;
|
||||
const w = (webContents as typeof ElectronInternal.WebContents).create();
|
||||
const destroyed = emittedOnce(w, 'destroyed');
|
||||
w.close();
|
||||
await destroyed;
|
||||
@@ -2269,7 +2285,7 @@ describe('webContents module', () => {
|
||||
});
|
||||
|
||||
it('closes when close() is called after loading a page', async () => {
|
||||
const w = (webContents as any).create() as WebContents;
|
||||
const w = (webContents as typeof ElectronInternal.WebContents).create();
|
||||
await w.loadURL('about:blank');
|
||||
const destroyed = emittedOnce(w, 'destroyed');
|
||||
w.close();
|
||||
@@ -2284,7 +2300,7 @@ describe('webContents module', () => {
|
||||
registry = new FinalizationRegistry(resolve as any);
|
||||
});
|
||||
(() => {
|
||||
const w = (webContents as any).create() as WebContents;
|
||||
const w = (webContents as typeof ElectronInternal.WebContents).create();
|
||||
registry!.register(w, 42);
|
||||
})();
|
||||
const i = setInterval(() => v8Util.requestGarbageCollectionForTesting(), 100);
|
||||
@@ -2302,7 +2318,7 @@ describe('webContents module', () => {
|
||||
});
|
||||
|
||||
it('ignores beforeunload if waitForBeforeUnload not specified', async () => {
|
||||
const w = (webContents as any).create() as WebContents;
|
||||
const w = (webContents as typeof ElectronInternal.WebContents).create();
|
||||
await w.loadURL('about:blank');
|
||||
await w.executeJavaScript('window.onbeforeunload = () => "hello"; null');
|
||||
w.on('will-prevent-unload', () => { throw new Error('unexpected will-prevent-unload'); });
|
||||
@@ -2313,7 +2329,7 @@ describe('webContents module', () => {
|
||||
});
|
||||
|
||||
it('runs beforeunload if waitForBeforeUnload is specified', async () => {
|
||||
const w = (webContents as any).create() as WebContents;
|
||||
const w = (webContents as typeof ElectronInternal.WebContents).create();
|
||||
await w.loadURL('about:blank');
|
||||
await w.executeJavaScript('window.onbeforeunload = () => "hello"; null');
|
||||
const willPreventUnload = emittedOnce(w, 'will-prevent-unload');
|
||||
@@ -2323,7 +2339,7 @@ describe('webContents module', () => {
|
||||
});
|
||||
|
||||
it('overriding beforeunload prevention results in webcontents close', async () => {
|
||||
const w = (webContents as any).create() as WebContents;
|
||||
const w = (webContents as typeof ElectronInternal.WebContents).create();
|
||||
await w.loadURL('about:blank');
|
||||
await w.executeJavaScript('window.onbeforeunload = () => "hello"; null');
|
||||
w.once('will-prevent-unload', e => e.preventDefault());
|
||||
|
||||
@@ -52,7 +52,7 @@ describe('webRequest module', () => {
|
||||
let contents: WebContents = null as unknown as WebContents;
|
||||
// NB. sandbox: true is used because it makes navigations much (~8x) faster.
|
||||
before(async () => {
|
||||
contents = (webContents as any).create({ sandbox: true });
|
||||
contents = (webContents as typeof ElectronInternal.WebContents).create({ sandbox: true });
|
||||
await contents.loadFile(path.join(fixturesPath, 'pages', 'fetch.html'));
|
||||
});
|
||||
after(() => contents.destroy());
|
||||
@@ -66,25 +66,36 @@ describe('webRequest module', () => {
|
||||
ses.webRequest.onBeforeRequest(null);
|
||||
});
|
||||
|
||||
const cancel = (details: Electron.OnBeforeRequestListenerDetails, callback: (response: Electron.CallbackResponse) => void) => {
|
||||
callback({ cancel: true });
|
||||
};
|
||||
|
||||
it('can cancel the request', async () => {
|
||||
ses.webRequest.onBeforeRequest((details, callback) => {
|
||||
callback({
|
||||
cancel: true
|
||||
});
|
||||
});
|
||||
ses.webRequest.onBeforeRequest(cancel);
|
||||
await expect(ajax(defaultURL)).to.eventually.be.rejected();
|
||||
});
|
||||
|
||||
it('can filter URLs', async () => {
|
||||
const filter = { urls: [defaultURL + 'filter/*'] };
|
||||
ses.webRequest.onBeforeRequest(filter, (details, callback) => {
|
||||
callback({ cancel: true });
|
||||
});
|
||||
ses.webRequest.onBeforeRequest(filter, cancel);
|
||||
const { data } = await ajax(`${defaultURL}nofilter/test`);
|
||||
expect(data).to.equal('/nofilter/test');
|
||||
await expect(ajax(`${defaultURL}filter/test`)).to.eventually.be.rejected();
|
||||
});
|
||||
|
||||
it('can filter URLs and types', async () => {
|
||||
const filter1: Electron.WebRequestFilter = { urls: [defaultURL + 'filter/*'], types: ['xhr'] };
|
||||
ses.webRequest.onBeforeRequest(filter1, cancel);
|
||||
const { data } = await ajax(`${defaultURL}nofilter/test`);
|
||||
expect(data).to.equal('/nofilter/test');
|
||||
await expect(ajax(`${defaultURL}filter/test`)).to.eventually.be.rejected();
|
||||
|
||||
const filter2: Electron.WebRequestFilter = { urls: [defaultURL + 'filter/*'], types: ['stylesheet'] };
|
||||
ses.webRequest.onBeforeRequest(filter2, cancel);
|
||||
expect((await ajax(`${defaultURL}nofilter/test`)).data).to.equal('/nofilter/test');
|
||||
expect((await ajax(`${defaultURL}filter/test`)).data).to.equal('/filter/test');
|
||||
});
|
||||
|
||||
it('receives details object', async () => {
|
||||
ses.webRequest.onBeforeRequest((details, callback) => {
|
||||
expect(details.id).to.be.a('number');
|
||||
@@ -529,7 +540,7 @@ describe('webRequest module', () => {
|
||||
}
|
||||
});
|
||||
|
||||
const contents = (webContents as any).create({
|
||||
const contents = (webContents as typeof ElectronInternal.WebContents).create({
|
||||
session: ses,
|
||||
nodeIntegration: true,
|
||||
webSecurity: false,
|
||||
|
||||
@@ -518,7 +518,7 @@ describe('chromium features', () => {
|
||||
it('does not crash', (done) => {
|
||||
const w = new BrowserWindow({ show: false });
|
||||
w.webContents.once('did-finish-load', () => { done(); });
|
||||
w.webContents.once('crashed', () => done(new Error('WebContents crashed.')));
|
||||
w.webContents.once('render-process-gone', () => done(new Error('WebContents crashed.')));
|
||||
w.loadFile(path.join(fixturesPath, 'pages', 'external-string.html'));
|
||||
});
|
||||
});
|
||||
@@ -558,7 +558,7 @@ describe('chromium features', () => {
|
||||
it('does not crash', (done) => {
|
||||
const w = new BrowserWindow({ show: false });
|
||||
w.webContents.once('did-finish-load', () => { done(); });
|
||||
w.webContents.once('crashed', () => done(new Error('WebContents crashed.')));
|
||||
w.webContents.once('render-process-gone', () => done(new Error('WebContents crashed.')));
|
||||
w.loadFile(path.join(__dirname, 'fixtures', 'pages', 'jquery.html'));
|
||||
});
|
||||
});
|
||||
@@ -596,7 +596,7 @@ describe('chromium features', () => {
|
||||
}).then(() => done());
|
||||
}
|
||||
});
|
||||
w.webContents.on('crashed', () => done(new Error('WebContents crashed.')));
|
||||
w.webContents.on('render-process-gone', () => done(new Error('WebContents crashed.')));
|
||||
w.loadFile(path.join(fixturesPath, 'pages', 'service-worker', 'index.html'));
|
||||
});
|
||||
|
||||
@@ -637,7 +637,7 @@ describe('chromium features', () => {
|
||||
});
|
||||
}
|
||||
});
|
||||
w.webContents.on('crashed', () => done(new Error('WebContents crashed.')));
|
||||
w.webContents.on('render-process-gone', () => done(new Error('WebContents crashed.')));
|
||||
w.loadFile(path.join(fixturesPath, 'pages', 'service-worker', 'index.html'));
|
||||
});
|
||||
|
||||
@@ -673,7 +673,7 @@ describe('chromium features', () => {
|
||||
});
|
||||
}
|
||||
});
|
||||
w.webContents.on('crashed', () => done(new Error('WebContents crashed.')));
|
||||
w.webContents.on('render-process-gone', () => done(new Error('WebContents crashed.')));
|
||||
w.loadFile(path.join(fixturesPath, 'pages', 'service-worker', 'custom-scheme-index.html'));
|
||||
});
|
||||
|
||||
@@ -1472,7 +1472,7 @@ describe('chromium features', () => {
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
contents = (webContents as any).create({
|
||||
contents = (webContents as typeof ElectronInternal.WebContents).create({
|
||||
nodeIntegration: true,
|
||||
contextIsolation: false
|
||||
});
|
||||
@@ -1559,7 +1559,7 @@ describe('chromium features', () => {
|
||||
...extraPreferences
|
||||
});
|
||||
let redirected = false;
|
||||
w.webContents.on('crashed', () => {
|
||||
w.webContents.on('render-process-gone', () => {
|
||||
expect.fail('renderer crashed / was killed');
|
||||
});
|
||||
w.webContents.on('did-redirect-navigation', (event, url) => {
|
||||
@@ -1603,7 +1603,7 @@ describe('chromium features', () => {
|
||||
});
|
||||
|
||||
it('default value allows websql', async () => {
|
||||
contents = (webContents as any).create({
|
||||
contents = (webContents as typeof ElectronInternal.WebContents).create({
|
||||
session: sqlSession,
|
||||
nodeIntegration: true,
|
||||
contextIsolation: false
|
||||
@@ -1614,7 +1614,7 @@ describe('chromium features', () => {
|
||||
});
|
||||
|
||||
it('when set to false can disallow websql', async () => {
|
||||
contents = (webContents as any).create({
|
||||
contents = (webContents as typeof ElectronInternal.WebContents).create({
|
||||
session: sqlSession,
|
||||
nodeIntegration: true,
|
||||
enableWebSQL: false,
|
||||
@@ -1626,7 +1626,7 @@ describe('chromium features', () => {
|
||||
});
|
||||
|
||||
it('when set to false does not disable indexedDB', async () => {
|
||||
contents = (webContents as any).create({
|
||||
contents = (webContents as typeof ElectronInternal.WebContents).create({
|
||||
session: sqlSession,
|
||||
nodeIntegration: true,
|
||||
enableWebSQL: false,
|
||||
@@ -2730,7 +2730,7 @@ ifdescribe((process.platform !== 'linux' || app.isUnityRunning()))('navigator.se
|
||||
}).then(() => done());
|
||||
}
|
||||
});
|
||||
w.webContents.on('crashed', () => done(new Error('WebContents crashed.')));
|
||||
w.webContents.on('render-process-gone', () => done(new Error('WebContents crashed.')));
|
||||
w.loadFile(path.join(fixturesPath, 'pages', 'service-worker', 'badge-index.html'), { search: '?setBadge' });
|
||||
});
|
||||
|
||||
@@ -2751,7 +2751,7 @@ ifdescribe((process.platform !== 'linux' || app.isUnityRunning()))('navigator.se
|
||||
}).then(() => done());
|
||||
}
|
||||
});
|
||||
w.webContents.on('crashed', () => done(new Error('WebContents crashed.')));
|
||||
w.webContents.on('render-process-gone', () => done(new Error('WebContents crashed.')));
|
||||
w.loadFile(path.join(fixturesPath, 'pages', 'service-worker', 'badge-index.html'), { search: '?clearBadge' });
|
||||
});
|
||||
});
|
||||
|
||||
@@ -8,7 +8,7 @@ const fixturePath = path.resolve(__dirname, 'fixtures', 'crash-cases');
|
||||
|
||||
let children: cp.ChildProcessWithoutNullStreams[] = [];
|
||||
|
||||
const runFixtureAndEnsureCleanExit = (args: string[]) => {
|
||||
const runFixtureAndEnsureCleanExit = async (args: string[]) => {
|
||||
let out = '';
|
||||
const child = cp.spawn(process.execPath, args);
|
||||
children.push(child);
|
||||
@@ -18,17 +18,20 @@ const runFixtureAndEnsureCleanExit = (args: string[]) => {
|
||||
child.stderr.on('data', (chunk: Buffer) => {
|
||||
out += chunk.toString();
|
||||
});
|
||||
return new Promise<void>((resolve) => {
|
||||
|
||||
type CodeAndSignal = {code: number | null, signal: NodeJS.Signals | null};
|
||||
const { code, signal } = await new Promise<CodeAndSignal>((resolve) => {
|
||||
child.on('exit', (code, signal) => {
|
||||
if (code !== 0 || signal !== null) {
|
||||
console.error(out);
|
||||
}
|
||||
expect(signal).to.equal(null, 'exit signal should be null');
|
||||
expect(code).to.equal(0, 'should have exited with code 0');
|
||||
children = children.filter(c => c !== child);
|
||||
resolve();
|
||||
resolve({ code, signal });
|
||||
});
|
||||
});
|
||||
if (code !== 0 || signal !== null) {
|
||||
console.error(out);
|
||||
}
|
||||
children = children.filter(c => c !== child);
|
||||
|
||||
expect(signal).to.equal(null, 'exit signal should be null');
|
||||
expect(code).to.equal(0, 'should have exited with code 0');
|
||||
};
|
||||
|
||||
const shouldRunCase = (crashCase: string) => {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
const { app, webContents } = require('electron');
|
||||
app.whenReady().then(function () {
|
||||
webContents.create({});
|
||||
webContents.create();
|
||||
|
||||
app.quit();
|
||||
});
|
||||
|
||||
4
spec/fixtures/no-proprietary-codecs.js
vendored
4
spec/fixtures/no-proprietary-codecs.js
vendored
@@ -21,8 +21,8 @@ app.whenReady().then(() => {
|
||||
}
|
||||
});
|
||||
|
||||
window.webContents.on('crashed', (event, killed) => {
|
||||
console.log(`WebContents crashed (killed=${killed})`);
|
||||
window.webContents.on('render-process-gone', (event, details) => {
|
||||
console.log(`WebContents crashed ${JSON.stringify(details)}`);
|
||||
app.exit(1);
|
||||
});
|
||||
|
||||
|
||||
@@ -62,10 +62,10 @@ describe('modules support', () => {
|
||||
|
||||
ifit(features.isRunAsNodeEnabled())('can be required in node binary', async function () {
|
||||
const child = childProcess.fork(path.join(fixtures, 'module', 'uv-dlopen.js'));
|
||||
await new Promise<void>(resolve => child.once('exit', (exitCode) => {
|
||||
expect(exitCode).to.equal(0);
|
||||
resolve();
|
||||
const exitCode = await new Promise<number | null>(resolve => child.once('exit', (exitCode) => {
|
||||
resolve(exitCode);
|
||||
}));
|
||||
expect(exitCode).to.equal(0);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@ import * as path from 'path';
|
||||
import * as util from 'util';
|
||||
import { emittedOnce } from './lib/events-helpers';
|
||||
import { getRemoteContext, ifdescribe, ifit, itremote, useRemoteContext } from './lib/spec-helpers';
|
||||
import { webContents, WebContents } from 'electron/main';
|
||||
import { webContents } from 'electron/main';
|
||||
import { EventEmitter } from 'stream';
|
||||
|
||||
const features = process._linkedBinding('electron_common_features');
|
||||
@@ -780,7 +780,7 @@ describe('node feature', () => {
|
||||
// NOTE: temporary debug logging to try to catch flake.
|
||||
child.stderr.on('data', (m) => console.log(m.toString()));
|
||||
child.stdout.on('data', (m) => console.log(m.toString()));
|
||||
const w = (webContents as any).create({}) as WebContents;
|
||||
const w = (webContents as typeof ElectronInternal.WebContents).create();
|
||||
w.loadURL('about:blank')
|
||||
.then(() => w.executeJavaScript(`new Promise(resolve => {
|
||||
const connection = new WebSocket(${JSON.stringify(match[1])})
|
||||
|
||||
21
spec/parse-features-string-spec.ts
Normal file
21
spec/parse-features-string-spec.ts
Normal file
@@ -0,0 +1,21 @@
|
||||
import { expect } from 'chai';
|
||||
import { parseCommaSeparatedKeyValue } from '../lib/browser/parse-features-string';
|
||||
|
||||
describe('feature-string parsing', () => {
|
||||
it('is indifferent to whitespace around keys and values', () => {
|
||||
const checkParse = (string: string, parsed: Record<string, string | boolean>) => {
|
||||
const features = parseCommaSeparatedKeyValue(string);
|
||||
expect(features).to.deep.equal(parsed);
|
||||
};
|
||||
checkParse('a=yes,c=d', { a: true, c: 'd' });
|
||||
checkParse('a=yes ,c=d', { a: true, c: 'd' });
|
||||
checkParse('a=yes, c=d', { a: true, c: 'd' });
|
||||
checkParse('a=yes , c=d', { a: true, c: 'd' });
|
||||
checkParse(' a=yes , c=d', { a: true, c: 'd' });
|
||||
checkParse(' a= yes , c=d', { a: true, c: 'd' });
|
||||
checkParse(' a = yes , c=d', { a: true, c: 'd' });
|
||||
checkParse(' a = yes , c =d', { a: true, c: 'd' });
|
||||
checkParse(' a = yes , c = d', { a: true, c: 'd' });
|
||||
checkParse(' a = yes , c = d ', { a: true, c: 'd' });
|
||||
});
|
||||
});
|
||||
@@ -2,26 +2,6 @@ import { expect } from 'chai';
|
||||
import { BrowserWindow } from 'electron/main';
|
||||
import { closeAllWindows } from './lib/window-helpers';
|
||||
|
||||
describe('feature-string parsing', () => {
|
||||
it('is indifferent to whitespace around keys and values', () => {
|
||||
const { parseCommaSeparatedKeyValue } = require('../lib/browser/parse-features-string');
|
||||
const checkParse = (string: string, parsed: Record<string, string | boolean>) => {
|
||||
const features = parseCommaSeparatedKeyValue(string);
|
||||
expect(features).to.deep.equal(parsed);
|
||||
};
|
||||
checkParse('a=yes,c=d', { a: true, c: 'd' });
|
||||
checkParse('a=yes ,c=d', { a: true, c: 'd' });
|
||||
checkParse('a=yes, c=d', { a: true, c: 'd' });
|
||||
checkParse('a=yes , c=d', { a: true, c: 'd' });
|
||||
checkParse(' a=yes , c=d', { a: true, c: 'd' });
|
||||
checkParse(' a= yes , c=d', { a: true, c: 'd' });
|
||||
checkParse(' a = yes , c=d', { a: true, c: 'd' });
|
||||
checkParse(' a = yes , c =d', { a: true, c: 'd' });
|
||||
checkParse(' a = yes , c = d', { a: true, c: 'd' });
|
||||
checkParse(' a = yes , c = d ', { a: true, c: 'd' });
|
||||
});
|
||||
});
|
||||
|
||||
describe('process._linkedBinding', () => {
|
||||
describe('in the main process', () => {
|
||||
it('can access electron_browser bindings', () => {
|
||||
3
typings/internal-electron.d.ts
vendored
3
typings/internal-electron.d.ts
vendored
@@ -251,7 +251,6 @@ declare namespace ElectronInternal {
|
||||
|
||||
interface ModuleEntry {
|
||||
name: string;
|
||||
private?: boolean;
|
||||
loader: ModuleLoader;
|
||||
}
|
||||
|
||||
@@ -282,7 +281,7 @@ declare namespace ElectronInternal {
|
||||
}
|
||||
|
||||
class WebContents extends Electron.WebContents {
|
||||
static create(opts: Electron.WebPreferences): Electron.WebContents;
|
||||
static create(opts?: Electron.WebPreferences): Electron.WebContents;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
156
yarn.lock
156
yarn.lock
@@ -349,13 +349,6 @@
|
||||
btoa-lite "^1.0.0"
|
||||
universal-user-agent "^6.0.0"
|
||||
|
||||
"@octokit/auth-token@^2.4.0":
|
||||
version "2.4.2"
|
||||
resolved "https://registry.yarnpkg.com/@octokit/auth-token/-/auth-token-2.4.2.tgz#10d0ae979b100fa6b72fa0e8e63e27e6d0dbff8a"
|
||||
integrity sha512-jE/lE/IKIz2v1+/P0u4fJqv0kYwXOTujKemJMFr6FeopsxlIK3+wKDCJGnysg81XID5TgZQbIfuJ5J0lnTiuyQ==
|
||||
dependencies:
|
||||
"@octokit/types" "^5.0.0"
|
||||
|
||||
"@octokit/auth-token@^2.4.4":
|
||||
version "2.5.0"
|
||||
resolved "https://registry.yarnpkg.com/@octokit/auth-token/-/auth-token-2.5.0.tgz#27c37ea26c205f28443402477ffd261311f21e36"
|
||||
@@ -363,17 +356,12 @@
|
||||
dependencies:
|
||||
"@octokit/types" "^6.0.3"
|
||||
|
||||
"@octokit/core@^3.0.0":
|
||||
version "3.1.1"
|
||||
resolved "https://registry.yarnpkg.com/@octokit/core/-/core-3.1.1.tgz#1856745aa8fb154cf1544a2a1b82586c809c5e66"
|
||||
integrity sha512-cQ2HGrtyNJ1IBxpTP1U5m/FkMAJvgw7d2j1q3c9P0XUuYilEgF6e4naTpsgm4iVcQeOnccZlw7XHRIUBy0ymcg==
|
||||
"@octokit/auth-token@^3.0.0":
|
||||
version "3.0.3"
|
||||
resolved "https://registry.yarnpkg.com/@octokit/auth-token/-/auth-token-3.0.3.tgz#ce7e48a3166731f26068d7a7a7996b5da58cbe0c"
|
||||
integrity sha512-/aFM2M4HVDBT/jjDBa84sJniv1t9Gm/rLkalaz9htOm+L+8JMj1k9w0CkUdcxNyNxZPlTxKPVko+m1VlM58ZVA==
|
||||
dependencies:
|
||||
"@octokit/auth-token" "^2.4.0"
|
||||
"@octokit/graphql" "^4.3.1"
|
||||
"@octokit/request" "^5.4.0"
|
||||
"@octokit/types" "^5.0.0"
|
||||
before-after-hook "^2.1.0"
|
||||
universal-user-agent "^6.0.0"
|
||||
"@octokit/types" "^9.0.0"
|
||||
|
||||
"@octokit/core@^3.5.1":
|
||||
version "3.6.0"
|
||||
@@ -388,6 +376,19 @@
|
||||
before-after-hook "^2.2.0"
|
||||
universal-user-agent "^6.0.0"
|
||||
|
||||
"@octokit/core@^4.1.0":
|
||||
version "4.2.0"
|
||||
resolved "https://registry.yarnpkg.com/@octokit/core/-/core-4.2.0.tgz#8c253ba9605aca605bc46187c34fcccae6a96648"
|
||||
integrity sha512-AgvDRUg3COpR82P7PBdGZF/NNqGmtMq2NiPqeSsDIeCfYFOZ9gddqWNQHnFdEUf+YwOj4aZYmJnlPp7OXmDIDg==
|
||||
dependencies:
|
||||
"@octokit/auth-token" "^3.0.0"
|
||||
"@octokit/graphql" "^5.0.0"
|
||||
"@octokit/request" "^6.0.0"
|
||||
"@octokit/request-error" "^3.0.0"
|
||||
"@octokit/types" "^9.0.0"
|
||||
before-after-hook "^2.2.0"
|
||||
universal-user-agent "^6.0.0"
|
||||
|
||||
"@octokit/endpoint@^6.0.1":
|
||||
version "6.0.5"
|
||||
resolved "https://registry.yarnpkg.com/@octokit/endpoint/-/endpoint-6.0.5.tgz#43a6adee813c5ffd2f719e20cfd14a1fee7c193a"
|
||||
@@ -406,15 +407,6 @@
|
||||
is-plain-object "^5.0.0"
|
||||
universal-user-agent "^6.0.0"
|
||||
|
||||
"@octokit/graphql@^4.3.1":
|
||||
version "4.5.3"
|
||||
resolved "https://registry.yarnpkg.com/@octokit/graphql/-/graphql-4.5.3.tgz#d5ff0d4a8a33e98614a2a7359dac98bc285e062f"
|
||||
integrity sha512-JyYvi3j2tOb5ofASEpcg1Advs07H+Ag+I+ez7buuZfNVAmh1IYcDTuxd4gnYH8S2PSGu+f5IdDGxMmkK+5zsdA==
|
||||
dependencies:
|
||||
"@octokit/request" "^5.3.0"
|
||||
"@octokit/types" "^5.0.0"
|
||||
universal-user-agent "^6.0.0"
|
||||
|
||||
"@octokit/graphql@^4.5.8":
|
||||
version "4.8.0"
|
||||
resolved "https://registry.yarnpkg.com/@octokit/graphql/-/graphql-4.8.0.tgz#664d9b11c0e12112cbf78e10f49a05959aa22cc3"
|
||||
@@ -424,6 +416,15 @@
|
||||
"@octokit/types" "^6.0.3"
|
||||
universal-user-agent "^6.0.0"
|
||||
|
||||
"@octokit/graphql@^5.0.0":
|
||||
version "5.0.5"
|
||||
resolved "https://registry.yarnpkg.com/@octokit/graphql/-/graphql-5.0.5.tgz#a4cb3ea73f83b861893a6370ee82abb36e81afd2"
|
||||
integrity sha512-Qwfvh3xdqKtIznjX9lz2D458r7dJPP8l6r4GQkIdWQouZwHQK0mVT88uwiU2bdTU2OtT1uOlKpRciUWldpG0yQ==
|
||||
dependencies:
|
||||
"@octokit/request" "^6.0.0"
|
||||
"@octokit/types" "^9.0.0"
|
||||
universal-user-agent "^6.0.0"
|
||||
|
||||
"@octokit/oauth-authorization-url@^4.3.1":
|
||||
version "4.3.3"
|
||||
resolved "https://registry.yarnpkg.com/@octokit/oauth-authorization-url/-/oauth-authorization-url-4.3.3.tgz#6a6ef38f243086fec882b62744f39b517528dfb9"
|
||||
@@ -466,6 +467,11 @@
|
||||
resolved "https://registry.yarnpkg.com/@octokit/openapi-types/-/openapi-types-14.0.0.tgz#949c5019028c93f189abbc2fb42f333290f7134a"
|
||||
integrity sha512-HNWisMYlR8VCnNurDU6os2ikx0s0VyEjDYHNS/h4cgb8DeOxQ0n72HyinUtdDVxJhFy3FWLGl0DJhfEWk3P5Iw==
|
||||
|
||||
"@octokit/openapi-types@^16.0.0":
|
||||
version "16.0.0"
|
||||
resolved "https://registry.yarnpkg.com/@octokit/openapi-types/-/openapi-types-16.0.0.tgz#d92838a6cd9fb4639ca875ddb3437f1045cc625e"
|
||||
integrity sha512-JbFWOqTJVLHZSUUoF4FzAZKYtqdxWu9Z5m2QQnOyEa04fOFljvyh7D3GYKbfuaSWisqehImiVIMG4eyJeP5VEA==
|
||||
|
||||
"@octokit/plugin-paginate-rest@^2.16.8":
|
||||
version "2.21.3"
|
||||
resolved "https://registry.yarnpkg.com/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-2.21.3.tgz#7f12532797775640dbb8224da577da7dc210c87e"
|
||||
@@ -473,31 +479,18 @@
|
||||
dependencies:
|
||||
"@octokit/types" "^6.40.0"
|
||||
|
||||
"@octokit/plugin-paginate-rest@^2.2.0":
|
||||
version "2.3.0"
|
||||
resolved "https://registry.yarnpkg.com/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-2.3.0.tgz#7d1073e56cfd15d3f99dcfe81fa5d2b466f3a6f6"
|
||||
integrity sha512-Ye2ZJreP0ZlqJQz8fz+hXvrEAEYK4ay7br1eDpWzr6j76VXs/gKqxFcH8qRzkB3fo/2xh4Vy9VtGii4ZDc9qlA==
|
||||
"@octokit/plugin-paginate-rest@^6.0.0":
|
||||
version "6.0.0"
|
||||
resolved "https://registry.yarnpkg.com/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-6.0.0.tgz#f34b5a7d9416019126042cd7d7b811e006c0d561"
|
||||
integrity sha512-Sq5VU1PfT6/JyuXPyt04KZNVsFOSBaYOAq2QRZUwzVlI10KFvcbUo8lR258AAQL1Et60b0WuVik+zOWKLuDZxw==
|
||||
dependencies:
|
||||
"@octokit/types" "^5.2.0"
|
||||
|
||||
"@octokit/plugin-request-log@^1.0.0":
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/@octokit/plugin-request-log/-/plugin-request-log-1.0.0.tgz#eef87a431300f6148c39a7f75f8cfeb218b2547e"
|
||||
integrity sha512-ywoxP68aOT3zHCLgWZgwUJatiENeHE7xJzYjfz8WI0goynp96wETBF+d95b8g/uL4QmS6owPVlaxiz3wyMAzcw==
|
||||
"@octokit/types" "^9.0.0"
|
||||
|
||||
"@octokit/plugin-request-log@^1.0.4":
|
||||
version "1.0.4"
|
||||
resolved "https://registry.yarnpkg.com/@octokit/plugin-request-log/-/plugin-request-log-1.0.4.tgz#5e50ed7083a613816b1e4a28aeec5fb7f1462e85"
|
||||
integrity sha512-mLUsMkgP7K/cnFEw07kWqXGF5LKrOkD+lhCrKvPHXWDywAwuDUeDwWBpc69XK3pNX0uKiVt8g5z96PJ6z9xCFA==
|
||||
|
||||
"@octokit/plugin-rest-endpoint-methods@4.1.2":
|
||||
version "4.1.2"
|
||||
resolved "https://registry.yarnpkg.com/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-4.1.2.tgz#546a8f3e0b514f434a4ad4ef926005f1c81a5a5a"
|
||||
integrity sha512-PTI7wpbGEZ2IR87TVh+TNWaLcgX/RsZQalFbQCq8XxYUrQ36RHyERrHSNXFy5gkWpspUAOYRSV707JJv6BhqJA==
|
||||
dependencies:
|
||||
"@octokit/types" "^5.1.1"
|
||||
deprecation "^2.3.1"
|
||||
|
||||
"@octokit/plugin-rest-endpoint-methods@^5.12.0":
|
||||
version "5.16.2"
|
||||
resolved "https://registry.yarnpkg.com/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-5.16.2.tgz#7ee8bf586df97dd6868cf68f641354e908c25342"
|
||||
@@ -506,14 +499,13 @@
|
||||
"@octokit/types" "^6.39.0"
|
||||
deprecation "^2.3.1"
|
||||
|
||||
"@octokit/request-error@^2.0.0":
|
||||
version "2.0.2"
|
||||
resolved "https://registry.yarnpkg.com/@octokit/request-error/-/request-error-2.0.2.tgz#0e76b83f5d8fdda1db99027ea5f617c2e6ba9ed0"
|
||||
integrity sha512-2BrmnvVSV1MXQvEkrb9zwzP0wXFNbPJij922kYBTLIlIafukrGOb+ABBT2+c6wZiuyWDH1K1zmjGQ0toN/wMWw==
|
||||
"@octokit/plugin-rest-endpoint-methods@^7.0.0":
|
||||
version "7.0.1"
|
||||
resolved "https://registry.yarnpkg.com/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-7.0.1.tgz#f7ebe18144fd89460f98f35a587b056646e84502"
|
||||
integrity sha512-pnCaLwZBudK5xCdrR823xHGNgqOzRnJ/mpC/76YPpNP7DybdsJtP7mdOwh+wYZxK5jqeQuhu59ogMI4NRlBUvA==
|
||||
dependencies:
|
||||
"@octokit/types" "^5.0.1"
|
||||
deprecation "^2.0.0"
|
||||
once "^1.4.0"
|
||||
"@octokit/types" "^9.0.0"
|
||||
deprecation "^2.3.1"
|
||||
|
||||
"@octokit/request-error@^2.0.5", "@octokit/request-error@^2.1.0":
|
||||
version "2.1.0"
|
||||
@@ -533,20 +525,6 @@
|
||||
deprecation "^2.0.0"
|
||||
once "^1.4.0"
|
||||
|
||||
"@octokit/request@^5.3.0", "@octokit/request@^5.4.0":
|
||||
version "5.4.7"
|
||||
resolved "https://registry.yarnpkg.com/@octokit/request/-/request-5.4.7.tgz#fd703ee092e0463ceba49ff7a3e61cb4cf8a0fde"
|
||||
integrity sha512-FN22xUDP0i0uF38YMbOfx6TotpcENP5W8yJM1e/LieGXn6IoRxDMnBf7tx5RKSW4xuUZ/1P04NFZy5iY3Rax1A==
|
||||
dependencies:
|
||||
"@octokit/endpoint" "^6.0.1"
|
||||
"@octokit/request-error" "^2.0.0"
|
||||
"@octokit/types" "^5.0.0"
|
||||
deprecation "^2.0.0"
|
||||
is-plain-object "^4.0.0"
|
||||
node-fetch "^2.3.0"
|
||||
once "^1.4.0"
|
||||
universal-user-agent "^6.0.0"
|
||||
|
||||
"@octokit/request@^5.4.14", "@octokit/request@^5.6.0", "@octokit/request@^5.6.3":
|
||||
version "5.6.3"
|
||||
resolved "https://registry.yarnpkg.com/@octokit/request/-/request-5.6.3.tgz#19a022515a5bba965ac06c9d1334514eb50c48b0"
|
||||
@@ -571,16 +549,6 @@
|
||||
node-fetch "^2.6.7"
|
||||
universal-user-agent "^6.0.0"
|
||||
|
||||
"@octokit/rest@^18.0.3":
|
||||
version "18.0.3"
|
||||
resolved "https://registry.yarnpkg.com/@octokit/rest/-/rest-18.0.3.tgz#96a15ddb3a38dca5de9d75121378d6aa4a234fa5"
|
||||
integrity sha512-GubgemnLvUJlkhouTM2BtX+g/voYT/Mqh0SASGwTnLvSkW1irjt14N911/ABb6m1Hru0TwScOgFgMFggp3igfQ==
|
||||
dependencies:
|
||||
"@octokit/core" "^3.0.0"
|
||||
"@octokit/plugin-paginate-rest" "^2.2.0"
|
||||
"@octokit/plugin-request-log" "^1.0.0"
|
||||
"@octokit/plugin-rest-endpoint-methods" "4.1.2"
|
||||
|
||||
"@octokit/rest@^18.12.0":
|
||||
version "18.12.0"
|
||||
resolved "https://registry.yarnpkg.com/@octokit/rest/-/rest-18.12.0.tgz#f06bc4952fc87130308d810ca9d00e79f6988881"
|
||||
@@ -591,7 +559,17 @@
|
||||
"@octokit/plugin-request-log" "^1.0.4"
|
||||
"@octokit/plugin-rest-endpoint-methods" "^5.12.0"
|
||||
|
||||
"@octokit/types@^5.0.0", "@octokit/types@^5.0.1", "@octokit/types@^5.1.1", "@octokit/types@^5.2.0":
|
||||
"@octokit/rest@^19.0.7":
|
||||
version "19.0.7"
|
||||
resolved "https://registry.yarnpkg.com/@octokit/rest/-/rest-19.0.7.tgz#d2e21b4995ab96ae5bfae50b4969da7e04e0bb70"
|
||||
integrity sha512-HRtSfjrWmWVNp2uAkEpQnuGMJsu/+dBr47dRc5QVgsCbnIc1+GFEaoKBWkYG+zjrsHpSqcAElMio+n10c0b5JA==
|
||||
dependencies:
|
||||
"@octokit/core" "^4.1.0"
|
||||
"@octokit/plugin-paginate-rest" "^6.0.0"
|
||||
"@octokit/plugin-request-log" "^1.0.4"
|
||||
"@octokit/plugin-rest-endpoint-methods" "^7.0.0"
|
||||
|
||||
"@octokit/types@^5.0.0":
|
||||
version "5.2.0"
|
||||
resolved "https://registry.yarnpkg.com/@octokit/types/-/types-5.2.0.tgz#d075dc23bf293f540739250b6879e2c1be2fc20c"
|
||||
integrity sha512-XjOk9y4m8xTLIKPe1NFxNWBdzA2/z3PFFA/bwf4EoH6oS8hM0Y46mEa4Cb+KCyj/tFDznJFahzQ0Aj3o1FYq4A==
|
||||
@@ -612,6 +590,13 @@
|
||||
dependencies:
|
||||
"@octokit/openapi-types" "^14.0.0"
|
||||
|
||||
"@octokit/types@^9.0.0":
|
||||
version "9.0.0"
|
||||
resolved "https://registry.yarnpkg.com/@octokit/types/-/types-9.0.0.tgz#6050db04ddf4188ec92d60e4da1a2ce0633ff635"
|
||||
integrity sha512-LUewfj94xCMH2rbD5YJ+6AQ4AVjFYTgpp6rboWM5T7N3IsIF65SBEOVcYMGAEzO/kKNiNaW4LoWtoThOhH06gw==
|
||||
dependencies:
|
||||
"@octokit/openapi-types" "^16.0.0"
|
||||
|
||||
"@opentelemetry/api@^1.0.1":
|
||||
version "1.0.4"
|
||||
resolved "https://registry.yarnpkg.com/@opentelemetry/api/-/api-1.0.4.tgz#a167e46c10d05a07ab299fc518793b0cff8f6924"
|
||||
@@ -1550,11 +1535,6 @@ base64-js@^1.3.1:
|
||||
resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a"
|
||||
integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==
|
||||
|
||||
before-after-hook@^2.1.0:
|
||||
version "2.1.0"
|
||||
resolved "https://registry.yarnpkg.com/before-after-hook/-/before-after-hook-2.1.0.tgz#b6c03487f44e24200dd30ca5e6a1979c5d2fb635"
|
||||
integrity sha512-IWIbu7pMqyw3EAJHzzHbWa85b6oud/yfKYg5rqB5hNE8CeMi3nX+2C2sj0HswfblST86hpVEOAb9x34NZd6P7A==
|
||||
|
||||
before-after-hook@^2.2.0:
|
||||
version "2.2.3"
|
||||
resolved "https://registry.yarnpkg.com/before-after-hook/-/before-after-hook-2.2.3.tgz#c51e809c81a4e354084422b9b26bad88249c517c"
|
||||
@@ -4608,13 +4588,6 @@ nice-try@^1.0.4:
|
||||
resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.5.tgz#a3378a7696ce7d223e88fc9b764bd7ef1089e366"
|
||||
integrity sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==
|
||||
|
||||
node-fetch@^2.3.0, node-fetch@^2.6.7:
|
||||
version "2.6.7"
|
||||
resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.7.tgz#24de9fba827e3b4ae44dc8b20256a379160052ad"
|
||||
integrity sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==
|
||||
dependencies:
|
||||
whatwg-url "^5.0.0"
|
||||
|
||||
node-fetch@^2.6.1:
|
||||
version "2.6.8"
|
||||
resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.8.tgz#a68d30b162bc1d8fd71a367e81b997e1f4d4937e"
|
||||
@@ -4622,6 +4595,13 @@ node-fetch@^2.6.1:
|
||||
dependencies:
|
||||
whatwg-url "^5.0.0"
|
||||
|
||||
node-fetch@^2.6.7:
|
||||
version "2.6.7"
|
||||
resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.7.tgz#24de9fba827e3b4ae44dc8b20256a379160052ad"
|
||||
integrity sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==
|
||||
dependencies:
|
||||
whatwg-url "^5.0.0"
|
||||
|
||||
node-releases@^2.0.6:
|
||||
version "2.0.6"
|
||||
resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.6.tgz#8a7088c63a55e493845683ebf3c828d8c51c5503"
|
||||
|
||||
Reference in New Issue
Block a user