mirror of
https://github.com/electron/electron.git
synced 2026-04-10 03:01:51 -04:00
Compare commits
84 Commits
v15.5.3
...
v16.0.0-ni
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7132f36ddd | ||
|
|
d1bd9afbbf | ||
|
|
1e983e2a6e | ||
|
|
c5db7a9013 | ||
|
|
a48968c1ce | ||
|
|
d313ddbd3d | ||
|
|
6ad47322fa | ||
|
|
93b1d2d932 | ||
|
|
17615654e8 | ||
|
|
c6267d9fb0 | ||
|
|
52890e9efd | ||
|
|
7668507c9d | ||
|
|
439e83de6c | ||
|
|
08ff1c2cbf | ||
|
|
81c143318b | ||
|
|
c8f3324610 | ||
|
|
60650abf09 | ||
|
|
e11953b0e6 | ||
|
|
41646d1168 | ||
|
|
42936b07fe | ||
|
|
985f1b5c04 | ||
|
|
ac49e6af4a | ||
|
|
69f1c1b083 | ||
|
|
f17e6ae318 | ||
|
|
4f739d7837 | ||
|
|
590858a38d | ||
|
|
edb7413bae | ||
|
|
e223b4db94 | ||
|
|
08e9aea940 | ||
|
|
66c458a353 | ||
|
|
6a9cada98c | ||
|
|
d783e944d3 | ||
|
|
641260bc32 | ||
|
|
bc508c6113 | ||
|
|
ec6cd0053e | ||
|
|
8e1160fde4 | ||
|
|
320bea4c28 | ||
|
|
59ab79417d | ||
|
|
423172775e | ||
|
|
4703dc0a1d | ||
|
|
481b774fd7 | ||
|
|
acbd643e2a | ||
|
|
97929eab5f | ||
|
|
1c29734c91 | ||
|
|
8179349625 | ||
|
|
a17e48061a | ||
|
|
40e76dca07 | ||
|
|
6e43b0bcbf | ||
|
|
4519bc3cd1 | ||
|
|
2b897c8ad8 | ||
|
|
0cabff0a21 | ||
|
|
888ac65c72 | ||
|
|
c0e72bd335 | ||
|
|
ced2e8779f | ||
|
|
9693fb9a37 | ||
|
|
9a63d96e83 | ||
|
|
7b5deb2f3a | ||
|
|
8651c5d02d | ||
|
|
639f03977f | ||
|
|
9cc1b55663 | ||
|
|
3ee6326b93 | ||
|
|
39c3ff5292 | ||
|
|
4aa9455613 | ||
|
|
c5ad7ed0cd | ||
|
|
c3abbdefdd | ||
|
|
bd85b1d028 | ||
|
|
fa464286ee | ||
|
|
d63980edeb | ||
|
|
1c95d30c0f | ||
|
|
fc7ea75009 | ||
|
|
ceebae170e | ||
|
|
cce27a0961 | ||
|
|
10424c0149 | ||
|
|
a545cd3790 | ||
|
|
461db8f1ab | ||
|
|
d2989de5d9 | ||
|
|
385d0f590f | ||
|
|
64ba8feb93 | ||
|
|
a6ab702ae4 | ||
|
|
62711e23ad | ||
|
|
3cb06457c4 | ||
|
|
e3fe80e0e8 | ||
|
|
b24cfe17bc | ||
|
|
eca1098b55 |
1
.circleci/.gitignore
vendored
1
.circleci/.gitignore
vendored
@@ -1 +0,0 @@
|
||||
config-staging
|
||||
2600
.circleci/config.yml
2600
.circleci/config.yml
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,34 +0,0 @@
|
||||
const cp = require('child_process');
|
||||
const fs = require('fs-extra');
|
||||
const path = require('path');
|
||||
const yaml = require('js-yaml');
|
||||
|
||||
const STAGING_DIR = path.resolve(__dirname, '..', 'config-staging');
|
||||
|
||||
function copyAndExpand(dir = './') {
|
||||
const absDir = path.resolve(__dirname, dir);
|
||||
const targetDir = path.resolve(STAGING_DIR, dir);
|
||||
|
||||
if (!fs.existsSync(targetDir)) {
|
||||
fs.mkdirSync(targetDir);
|
||||
}
|
||||
|
||||
for (const file of fs.readdirSync(absDir)) {
|
||||
if (!file.endsWith('.yml')) {
|
||||
if (fs.statSync(path.resolve(absDir, file)).isDirectory()) {
|
||||
copyAndExpand(path.join(dir, file));
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
fs.writeFileSync(path.resolve(targetDir, file), yaml.dump(yaml.load(fs.readFileSync(path.resolve(absDir, file), 'utf8')), {
|
||||
noRefs: true,
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
if (fs.pathExists(STAGING_DIR)) fs.removeSync(STAGING_DIR);
|
||||
copyAndExpand();
|
||||
|
||||
const output = cp.spawnSync(process.env.CIRCLECI_BINARY || 'circleci', ['config', 'pack', STAGING_DIR]);
|
||||
fs.writeFileSync(path.resolve(STAGING_DIR, 'built.yml'), output.stdout.toString());
|
||||
@@ -1,51 +0,0 @@
|
||||
executor:
|
||||
name: linux-docker
|
||||
size: medium
|
||||
steps:
|
||||
- checkout:
|
||||
path: src/electron
|
||||
- run:
|
||||
name: Setup third_party Depot Tools
|
||||
command: |
|
||||
# "depot_tools" has to be checkout into "//third_party/depot_tools" so pylint.py can a "pylintrc" file.
|
||||
git clone https://chromium.googlesource.com/chromium/tools/depot_tools.git src/third_party/depot_tools
|
||||
echo 'export PATH="$PATH:'"$PWD"'/src/third_party/depot_tools"' >> $BASH_ENV
|
||||
- run:
|
||||
name: Download GN Binary
|
||||
command: |
|
||||
chromium_revision="$(grep -A1 chromium_version src/electron/DEPS | tr -d '\n' | cut -d\' -f4)"
|
||||
gn_version="$(curl -sL "https://chromium.googlesource.com/chromium/src/+/${chromium_revision}/DEPS?format=TEXT" | base64 -d | grep gn_version | head -n1 | cut -d\' -f4)"
|
||||
|
||||
cipd ensure -ensure-file - -root . \<<-CIPD
|
||||
\$ServiceURL https://chrome-infra-packages.appspot.com/
|
||||
@Subdir src/buildtools/linux64
|
||||
gn/gn/linux-amd64 $gn_version
|
||||
CIPD
|
||||
|
||||
echo 'export CHROMIUM_BUILDTOOLS_PATH="'"$PWD"'/src/buildtools"' >> $BASH_ENV
|
||||
- run:
|
||||
name: Download clang-format Binary
|
||||
command: |
|
||||
chromium_revision="$(grep -A1 chromium_version src/electron/DEPS | tr -d '\n' | cut -d\' -f4)"
|
||||
|
||||
sha1_path='buildtools/linux64/clang-format.sha1'
|
||||
curl -sL "https://chromium.googlesource.com/chromium/src/+/${chromium_revision}/${sha1_path}?format=TEXT" | base64 -d > "src/${sha1_path}"
|
||||
|
||||
download_from_google_storage.py --no_resume --no_auth --bucket chromium-clang-format -s "src/${sha1_path}"
|
||||
- run:
|
||||
name: Run Lint
|
||||
command: |
|
||||
# gn.py tries to find a gclient root folder starting from the current dir.
|
||||
# When it fails and returns "None" path, the whole script fails. Let's "fix" it.
|
||||
touch .gclient
|
||||
# Another option would be to checkout "buildtools" inside the Electron checkout,
|
||||
# but then we would lint its contents (at least gn format), and it doesn't pass it.
|
||||
|
||||
cd src/electron
|
||||
node script/yarn install --frozen-lockfile
|
||||
node script/yarn lint
|
||||
- run:
|
||||
name: Run Script Typechecker
|
||||
command: |
|
||||
cd src/electron
|
||||
node script/yarn tsc -p tsconfig.script.json
|
||||
@@ -1,10 +0,0 @@
|
||||
{
|
||||
"name": "@electron/circleci-config",
|
||||
"version": "0.0.0",
|
||||
"private": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"fs-extra": "^10.1.0",
|
||||
"js-yaml": "^4.1.0"
|
||||
}
|
||||
}
|
||||
@@ -1,43 +0,0 @@
|
||||
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
|
||||
# yarn lockfile v1
|
||||
|
||||
|
||||
argparse@^2.0.1:
|
||||
version "2.0.1"
|
||||
resolved "https://registry.yarnpkg.com/argparse/-/argparse-2.0.1.tgz#246f50f3ca78a3240f6c997e8a9bd1eac49e4b38"
|
||||
integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==
|
||||
|
||||
fs-extra@^10.1.0:
|
||||
version "10.1.0"
|
||||
resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-10.1.0.tgz#02873cfbc4084dde127eaa5f9905eef2325d1abf"
|
||||
integrity sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==
|
||||
dependencies:
|
||||
graceful-fs "^4.2.0"
|
||||
jsonfile "^6.0.1"
|
||||
universalify "^2.0.0"
|
||||
|
||||
graceful-fs@^4.1.6, graceful-fs@^4.2.0:
|
||||
version "4.2.10"
|
||||
resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.10.tgz#147d3a006da4ca3ce14728c7aefc287c367d7a6c"
|
||||
integrity sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==
|
||||
|
||||
js-yaml@^4.1.0:
|
||||
version "4.1.0"
|
||||
resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-4.1.0.tgz#c1fb65f8f5017901cdd2c951864ba18458a10602"
|
||||
integrity sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==
|
||||
dependencies:
|
||||
argparse "^2.0.1"
|
||||
|
||||
jsonfile@^6.0.1:
|
||||
version "6.1.0"
|
||||
resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-6.1.0.tgz#bc55b2634793c679ec6403094eb13698a6ec0aae"
|
||||
integrity sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==
|
||||
dependencies:
|
||||
universalify "^2.0.0"
|
||||
optionalDependencies:
|
||||
graceful-fs "^4.1.6"
|
||||
|
||||
universalify@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/universalify/-/universalify-2.0.0.tgz#75a4984efedc4b08975c5aeb73f530d02df25717"
|
||||
integrity sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==
|
||||
2
.github/CODEOWNERS
vendored
2
.github/CODEOWNERS
vendored
@@ -4,7 +4,7 @@
|
||||
# https://git-scm.com/docs/gitignore
|
||||
|
||||
# Upgrades WG
|
||||
/patches/ @electron/wg-upgrades @electron/wg-security
|
||||
/patches/ @electron/wg-upgrades
|
||||
DEPS @electron/wg-upgrades
|
||||
|
||||
# Releases WG
|
||||
|
||||
4
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
4
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
@@ -8,9 +8,9 @@ body:
|
||||
label: Preflight Checklist
|
||||
description: Please ensure you've completed all of the following.
|
||||
options:
|
||||
- label: I have read the [Contributing Guidelines](https://github.com/electron/electron/blob/main/CONTRIBUTING.md) for this project.
|
||||
- label: I have read the [Contributing Guidelines](https://github.com/electron/electron/blob/master/CONTRIBUTING.md) for this project.
|
||||
required: true
|
||||
- label: I agree to follow the [Code of Conduct](https://github.com/electron/electron/blob/main/CODE_OF_CONDUCT.md) that this project adheres to.
|
||||
- label: I agree to follow the [Code of Conduct](https://github.com/electron/electron/blob/master/CODE_OF_CONDUCT.md) that this project adheres to.
|
||||
required: true
|
||||
- label: I have searched the [issue tracker](https://www.github.com/electron/electron/issues) for a feature request that matches the one I want to file, without success.
|
||||
required: true
|
||||
|
||||
4
.github/ISSUE_TEMPLATE/feature_request.yml
vendored
4
.github/ISSUE_TEMPLATE/feature_request.yml
vendored
@@ -8,9 +8,9 @@ body:
|
||||
label: Preflight Checklist
|
||||
description: Please ensure you've completed all of the following.
|
||||
options:
|
||||
- label: I have read the [Contributing Guidelines](https://github.com/electron/electron/blob/main/CONTRIBUTING.md) for this project.
|
||||
- label: I have read the [Contributing Guidelines](https://github.com/electron/electron/blob/master/CONTRIBUTING.md) for this project.
|
||||
required: true
|
||||
- label: I agree to follow the [Code of Conduct](https://github.com/electron/electron/blob/main/CODE_OF_CONDUCT.md) that this project adheres to.
|
||||
- label: I agree to follow the [Code of Conduct](https://github.com/electron/electron/blob/master/CODE_OF_CONDUCT.md) that this project adheres to.
|
||||
required: true
|
||||
- label: I have searched the [issue tracker](https://www.github.com/electron/electron/issues) for a feature request that matches the one I want to file, without success.
|
||||
required: true
|
||||
|
||||
@@ -7,9 +7,9 @@ body:
|
||||
label: Preflight Checklist
|
||||
description: Please ensure you've completed all of the following.
|
||||
options:
|
||||
- label: I have read the [Contributing Guidelines](https://github.com/electron/electron/blob/main/CONTRIBUTING.md) for this project.
|
||||
- label: I have read the [Contributing Guidelines](https://github.com/electron/electron/blob/master/CONTRIBUTING.md) for this project.
|
||||
required: true
|
||||
- label: I agree to follow the [Code of Conduct](https://github.com/electron/electron/blob/main/CODE_OF_CONDUCT.md) that this project adheres to.
|
||||
- label: I agree to follow the [Code of Conduct](https://github.com/electron/electron/blob/master/CODE_OF_CONDUCT.md) that this project adheres to.
|
||||
required: true
|
||||
- type: input
|
||||
attributes:
|
||||
|
||||
4
.github/PULL_REQUEST_TEMPLATE.md
vendored
4
.github/PULL_REQUEST_TEMPLATE.md
vendored
@@ -3,7 +3,7 @@
|
||||
Thank you for your Pull Request. Please provide a description above and review
|
||||
the requirements below.
|
||||
|
||||
Contributors guide: https://github.com/electron/electron/blob/main/CONTRIBUTING.md
|
||||
Contributors guide: https://github.com/electron/electron/blob/master/CONTRIBUTING.md
|
||||
-->
|
||||
|
||||
#### Checklist
|
||||
@@ -11,7 +11,7 @@ Contributors guide: https://github.com/electron/electron/blob/main/CONTRIBUTING.
|
||||
|
||||
- [ ] PR description included and stakeholders cc'd
|
||||
- [ ] `npm test` passes
|
||||
- [ ] tests are [changed or added](https://github.com/electron/electron/blob/main/docs/development/testing.md)
|
||||
- [ ] tests are [changed or added](https://github.com/electron/electron/blob/master/docs/development/testing.md)
|
||||
- [ ] relevant documentation is changed or added
|
||||
- [ ] [PR release notes](https://github.com/electron/clerk/blob/master/README.md) describe the change in a way relevant to app developers, and are [capitalized, punctuated, and past tense](https://github.com/electron/clerk/blob/master/README.md#examples).
|
||||
|
||||
|
||||
6
.github/config.yml
vendored
6
.github/config.yml
vendored
@@ -2,7 +2,7 @@
|
||||
newPRWelcomeComment: |
|
||||
💖 Thanks for opening this pull request! 💖
|
||||
|
||||
We use [semantic commit messages](https://github.com/electron/electron/blob/main/docs/development/pull-requests.md#commit-message-guidelines) to streamline the release process. Before your pull request can be merged, you should **update your pull request title** to start with a semantic prefix.
|
||||
We use [semantic commit messages](https://github.com/electron/electron/blob/master/docs/development/pull-requests.md#commit-message-guidelines) to streamline the release process. Before your pull request can be merged, you should **update your pull request title** to start with a semantic prefix.
|
||||
|
||||
Examples of commit messages with semantic prefixes:
|
||||
|
||||
@@ -12,9 +12,9 @@ newPRWelcomeComment: |
|
||||
|
||||
Things that will help get your PR across the finish line:
|
||||
|
||||
- Follow the JavaScript, C++, and Python [coding style](https://github.com/electron/electron/blob/main/docs/development/coding-style.md).
|
||||
- Follow the JavaScript, C++, and Python [coding style](https://github.com/electron/electron/blob/master/docs/development/coding-style.md).
|
||||
- Run `npm run lint` locally to catch formatting errors earlier.
|
||||
- Document any user-facing changes you've made following the [documentation styleguide](https://github.com/electron/electron/blob/main/docs/styleguide.md).
|
||||
- Document any user-facing changes you've made following the [documentation styleguide](https://github.com/electron/electron/blob/master/docs/styleguide.md).
|
||||
- Include tests when adding/changing behavior.
|
||||
- Include screenshots and animated GIFs whenever possible.
|
||||
|
||||
|
||||
20
.github/workflows/semantic.yml
vendored
20
.github/workflows/semantic.yml
vendored
@@ -1,20 +0,0 @@
|
||||
name: "Check Semantic Commit"
|
||||
|
||||
on:
|
||||
pull_request_target:
|
||||
types:
|
||||
- opened
|
||||
- edited
|
||||
- synchronize
|
||||
|
||||
jobs:
|
||||
main:
|
||||
name: Validate PR Title
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: semantic-pull-request
|
||||
uses: amannn/action-semantic-pull-request@v4
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
with:
|
||||
validateSingleCommit: false
|
||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -26,7 +26,6 @@ compile_commands.json
|
||||
# npm package
|
||||
/npm/dist
|
||||
/npm/path.txt
|
||||
/npm/checksums.json
|
||||
|
||||
.npmrc
|
||||
|
||||
|
||||
28
BUILD.gn
28
BUILD.gn
@@ -187,12 +187,6 @@ action("electron_js2c") {
|
||||
rebase_path(sources, root_build_dir)
|
||||
}
|
||||
|
||||
action("generate_config_gypi") {
|
||||
outputs = [ "$root_gen_dir/config.gypi" ]
|
||||
script = "script/generate-config-gypi.py"
|
||||
args = rebase_path(outputs) + [ target_cpu ]
|
||||
}
|
||||
|
||||
target_gen_default_app_js = "$target_gen_dir/js/default_app"
|
||||
|
||||
typescript_build("default_app_js") {
|
||||
@@ -367,7 +361,6 @@ source_set("electron_lib") {
|
||||
"//ppapi/shared_impl",
|
||||
"//printing/buildflags",
|
||||
"//services/device/public/cpp/geolocation",
|
||||
"//services/device/public/cpp/hid",
|
||||
"//services/device/public/mojom",
|
||||
"//services/proxy_resolver:lib",
|
||||
"//services/video_capture/public/mojom:constants",
|
||||
@@ -1013,12 +1006,6 @@ if (is_mac) {
|
||||
outputs = [ "{{bundle_resources_dir}}/{{source_file_part}}" ]
|
||||
}
|
||||
|
||||
asar_hashed_info_plist("electron_app_plist") {
|
||||
keys = [ "DEFAULT_APP_ASAR_HEADER_SHA" ]
|
||||
hash_targets = [ ":default_app_asar_header_hash" ]
|
||||
plist_file = "shell/browser/resources/mac/Info.plist"
|
||||
}
|
||||
|
||||
mac_app_bundle("electron_app") {
|
||||
output_name = electron_product_name
|
||||
sources = filenames.app_sources
|
||||
@@ -1026,7 +1013,6 @@ if (is_mac) {
|
||||
include_dirs = [ "." ]
|
||||
deps = [
|
||||
":electron_app_framework_bundle_data",
|
||||
":electron_app_plist",
|
||||
":electron_app_resources",
|
||||
":electron_fuses",
|
||||
"//base",
|
||||
@@ -1035,7 +1021,7 @@ if (is_mac) {
|
||||
if (is_mas_build) {
|
||||
deps += [ ":electron_login_helper_app" ]
|
||||
}
|
||||
info_plist_target = ":electron_app_plist"
|
||||
info_plist = "shell/browser/resources/mac/Info.plist"
|
||||
extra_substitutions = [
|
||||
"ELECTRON_BUNDLE_ID=$electron_mac_bundle_id",
|
||||
"ELECTRON_VERSION=$electron_version",
|
||||
@@ -1145,7 +1131,6 @@ if (is_mac) {
|
||||
]
|
||||
|
||||
data = []
|
||||
data_deps = []
|
||||
|
||||
data += [ "$root_out_dir/resources.pak" ]
|
||||
data += [ "$root_out_dir/chrome_100_percent.pak" ]
|
||||
@@ -1164,10 +1149,6 @@ if (is_mac) {
|
||||
public_deps = [ "//tools/v8_context_snapshot:v8_context_snapshot" ]
|
||||
}
|
||||
|
||||
if (is_linux) {
|
||||
data_deps += [ "//components/crash/core/app:chrome_crashpad_handler" ]
|
||||
}
|
||||
|
||||
if (is_win) {
|
||||
sources += [
|
||||
# TODO: we should be generating our .rc files more like how chrome does
|
||||
@@ -1367,13 +1348,11 @@ dist_zip("electron_dist_zip") {
|
||||
if (is_linux) {
|
||||
data_deps += [ "//sandbox/linux:chrome_sandbox" ]
|
||||
}
|
||||
deps = data_deps
|
||||
outputs = [ "$root_build_dir/dist.zip" ]
|
||||
}
|
||||
|
||||
dist_zip("electron_ffmpeg_zip") {
|
||||
data_deps = [ "//third_party/ffmpeg" ]
|
||||
deps = data_deps
|
||||
outputs = [ "$root_build_dir/ffmpeg.zip" ]
|
||||
}
|
||||
|
||||
@@ -1391,7 +1370,6 @@ group("electron_chromedriver") {
|
||||
dist_zip("electron_chromedriver_zip") {
|
||||
testonly = true
|
||||
data_deps = electron_chromedriver_deps
|
||||
deps = data_deps
|
||||
outputs = [ "$root_build_dir/chromedriver.zip" ]
|
||||
}
|
||||
|
||||
@@ -1410,7 +1388,6 @@ group("electron_mksnapshot") {
|
||||
|
||||
dist_zip("electron_mksnapshot_zip") {
|
||||
data_deps = mksnapshot_deps
|
||||
deps = data_deps
|
||||
outputs = [ "$root_build_dir/mksnapshot.zip" ]
|
||||
}
|
||||
|
||||
@@ -1421,7 +1398,6 @@ copy("hunspell_dictionaries") {
|
||||
|
||||
dist_zip("hunspell_dictionaries_zip") {
|
||||
data_deps = [ ":hunspell_dictionaries" ]
|
||||
deps = data_deps
|
||||
flatten = true
|
||||
|
||||
outputs = [ "$root_build_dir/hunspell_dictionaries.zip" ]
|
||||
@@ -1435,7 +1411,6 @@ copy("libcxx_headers") {
|
||||
|
||||
dist_zip("libcxx_headers_zip") {
|
||||
data_deps = [ ":libcxx_headers" ]
|
||||
deps = data_deps
|
||||
flatten = true
|
||||
flatten_relative_to = rebase_path(
|
||||
"$target_gen_dir/electron_libcxx_include/buildtools/third_party/libc++/trunk",
|
||||
@@ -1451,7 +1426,6 @@ copy("libcxxabi_headers") {
|
||||
|
||||
dist_zip("libcxxabi_headers_zip") {
|
||||
data_deps = [ ":libcxxabi_headers" ]
|
||||
deps = data_deps
|
||||
flatten = true
|
||||
flatten_relative_to = rebase_path(
|
||||
"$target_gen_dir/electron_libcxxabi_include/buildtools/third_party/libc++abi/trunk",
|
||||
|
||||
@@ -36,7 +36,7 @@ Having the original text _as well as_ the translation can help mitigate translat
|
||||
|
||||
Responses to posted issues may or may not be in the original language.
|
||||
|
||||
**Please note** that using non-English as an attempt to circumvent our [Code of Conduct](https://github.com/electron/electron/blob/main/CODE_OF_CONDUCT.md) will be an immediate, and possibly indefinite, ban from the project.
|
||||
**Please note** that using non-English as an attempt to circumvent our [Code of Conduct](https://github.com/electron/electron/blob/master/CODE_OF_CONDUCT.md) will be an immediate, and possibly indefinite, ban from the project.
|
||||
|
||||
## [Pull Requests](https://electronjs.org/docs/development/pull-requests)
|
||||
|
||||
|
||||
2
DEPS
2
DEPS
@@ -15,7 +15,7 @@ gclient_gn_args = [
|
||||
|
||||
vars = {
|
||||
'chromium_version':
|
||||
'94.0.4606.81',
|
||||
'94.0.4590.2',
|
||||
'node_version':
|
||||
'v16.5.0',
|
||||
'nan_version':
|
||||
|
||||
@@ -1 +1 @@
|
||||
15.5.3
|
||||
16.0.0-nightly.20210813
|
||||
@@ -1,7 +1,7 @@
|
||||
[](https://electronjs.org)
|
||||
|
||||
[](https://circleci.com/gh/electron/electron/tree/main)
|
||||
[](https://ci.appveyor.com/project/electron-bot/electron-ljo26/branch/main)
|
||||
[](https://circleci.com/gh/electron/electron/tree/master)
|
||||
[](https://ci.appveyor.com/project/electron-bot/electron-ljo26/branch/master)
|
||||
[](https://discord.com/invite/electron)
|
||||
|
||||
:memo: Available Translations: 🇨🇳 🇧🇷 🇪🇸 🇯🇵 🇷🇺 🇫🇷 🇺🇸 🇩🇪.
|
||||
@@ -16,7 +16,7 @@ Follow [@ElectronJS](https://twitter.com/electronjs) on Twitter for important
|
||||
announcements.
|
||||
|
||||
This project adheres to the Contributor Covenant
|
||||
[code of conduct](https://github.com/electron/electron/tree/main/CODE_OF_CONDUCT.md).
|
||||
[code of conduct](https://github.com/electron/electron/tree/master/CODE_OF_CONDUCT.md).
|
||||
By participating, you are expected to uphold this code. Please report unacceptable
|
||||
behavior to [coc@electronjs.org](mailto:coc@electronjs.org).
|
||||
|
||||
@@ -98,6 +98,6 @@ and more can be found in the [support document](docs/tutorial/support.md#finding
|
||||
|
||||
## License
|
||||
|
||||
[MIT](https://github.com/electron/electron/blob/main/LICENSE)
|
||||
[MIT](https://github.com/electron/electron/blob/master/LICENSE)
|
||||
|
||||
When using the Electron or other GitHub logos, be sure to follow the [GitHub logo guidelines](https://github.com/logos).
|
||||
|
||||
@@ -10,7 +10,7 @@ Report security bugs in third-party modules to the person or team maintaining th
|
||||
|
||||
## The Electron Security Notification Process
|
||||
|
||||
For context on Electron's security notification process, please see the [Notifications](https://github.com/electron/governance/blob/main/wg-security/membership-and-notifications.md#notifications) section of the Security WG's [Membership and Notifications](https://github.com/electron/governance/blob/main/wg-security/membership-and-notifications.md) Governance document.
|
||||
For context on Electron's security notification process, please see the [Notifications](https://github.com/electron/governance/blob/master/wg-security/membership-and-notifications.md#notifications) section of the Security WG's [Membership and Notifications](https://github.com/electron/governance/blob/master/wg-security/membership-and-notifications.md) Governance document.
|
||||
|
||||
## Learning More About Security
|
||||
|
||||
|
||||
40
appveyor.yml
40
appveyor.yml
@@ -66,31 +66,6 @@ build_script:
|
||||
- mkdir src
|
||||
- update_depot_tools.bat
|
||||
- ps: Move-Item $env:APPVEYOR_BUILD_FOLDER -Destination src\electron
|
||||
- ps: >-
|
||||
if (Test-Path 'env:RAW_GOMA_AUTH') {
|
||||
$env:GOMA_OAUTH2_CONFIG_FILE = "$pwd\.goma_oauth2_config"
|
||||
$env:RAW_GOMA_AUTH | Set-Content $env:GOMA_OAUTH2_CONFIG_FILE
|
||||
}
|
||||
- git clone https://github.com/electron/build-tools.git
|
||||
- cd build-tools
|
||||
- npm install
|
||||
- mkdir third_party
|
||||
- ps: >-
|
||||
node -e "require('./src/utils/goma.js').downloadAndPrepare({ gomaOneForAll: true })"
|
||||
- ps: $env:GN_GOMA_FILE = node -e "console.log(require('./src/utils/goma.js').gnFilePath)"
|
||||
- ps: $env:LOCAL_GOMA_DIR = node -e "console.log(require('./src/utils/goma.js').dir)"
|
||||
- cd ..
|
||||
- ps: .\src\electron\script\start-goma.ps1 -gomaDir $env:LOCAL_GOMA_DIR
|
||||
- ps: >-
|
||||
if (Test-Path 'env:RAW_GOMA_AUTH') {
|
||||
$goma_login = python $env:LOCAL_GOMA_DIR\goma_auth.py info
|
||||
if ($goma_login -eq 'Login as Fermi Planck') {
|
||||
Write-warning "Goma authentication is correct";
|
||||
} else {
|
||||
Write-warning "WARNING!!!!!! Goma authentication is incorrect; please update Goma auth token.";
|
||||
$host.SetShouldExit(1)
|
||||
}
|
||||
}
|
||||
- ps: $env:CHROMIUM_BUILDTOOLS_PATH="$pwd\src\buildtools"
|
||||
- ps: >-
|
||||
if ($env:GN_CONFIG -ne 'release') {
|
||||
@@ -154,6 +129,21 @@ build_script:
|
||||
Write-warning "Failed to add third_party\angle\.git; continuing anyway"
|
||||
}
|
||||
}
|
||||
- ps: >-
|
||||
if (Test-Path 'env:RAW_GOMA_AUTH') {
|
||||
$env:GOMA_OAUTH2_CONFIG_FILE = "$pwd\.goma_oauth2_config"
|
||||
$env:RAW_GOMA_AUTH | Set-Content $env:GOMA_OAUTH2_CONFIG_FILE
|
||||
}
|
||||
- git clone https://github.com/electron/build-tools.git
|
||||
- cd build-tools
|
||||
- npm install
|
||||
- mkdir third_party
|
||||
- ps: >-
|
||||
node -e "require('./src/utils/goma.js').downloadAndPrepare({ gomaOneForAll: true })"
|
||||
- ps: $env:GN_GOMA_FILE = node -e "console.log(require('./src/utils/goma.js').gnFilePath)"
|
||||
- ps: $env:LOCAL_GOMA_DIR = node -e "console.log(require('./src/utils/goma.js').dir)"
|
||||
- cd ..
|
||||
- ps: .\src\electron\script\start-goma.ps1 -gomaDir $env:LOCAL_GOMA_DIR
|
||||
- cd src
|
||||
- set BUILD_CONFIG_PATH=//electron/build/args/%GN_CONFIG%.gn
|
||||
- gn gen out/Default "--args=import(\"%BUILD_CONFIG_PATH%\") import(\"%GN_GOMA_FILE%\") %GN_EXTRA_ARGS% "
|
||||
|
||||
@@ -54,17 +54,11 @@ steps:
|
||||
APPVEYOR_TOKEN: $(APPVEYOR_TOKEN)
|
||||
|
||||
- powershell: |
|
||||
try {
|
||||
$localArtifactPath = "$pwd\src\pdb.zip"
|
||||
$serverArtifactPath = "$env:APPVEYOR_URL/buildjobs/$env:APPVEYOR_JOB_ID/artifacts/pdb.zip"
|
||||
Invoke-RestMethod -Method Get -Uri $serverArtifactPath -OutFile $localArtifactPath -Headers @{ "Authorization" = "Bearer $env:APPVEYOR_TOKEN" }
|
||||
cd src
|
||||
& "${env:ProgramFiles(x86)}\7-Zip\7z.exe" x -y pdb.zip
|
||||
} catch {
|
||||
Write-Host "There was an exception encountered while downloading pdb files:" $_.Exception.Message
|
||||
} finally {
|
||||
$global:LASTEXITCODE = 0
|
||||
}
|
||||
$localArtifactPath = "$pwd\src\pdb.zip"
|
||||
$serverArtifactPath = "$env:APPVEYOR_URL/buildjobs/$env:APPVEYOR_JOB_ID/artifacts/pdb.zip"
|
||||
Invoke-RestMethod -Method Get -Uri $serverArtifactPath -OutFile $localArtifactPath -Headers @{ "Authorization" = "Bearer $env:APPVEYOR_TOKEN" }
|
||||
cd src
|
||||
& "${env:ProgramFiles(x86)}\7-Zip\7z.exe" x -y pdb.zip
|
||||
displayName: 'Download pdb files for detailed stacktraces'
|
||||
env:
|
||||
APPVEYOR_TOKEN: $(APPVEYOR_TOKEN)
|
||||
|
||||
@@ -2,7 +2,7 @@ is_electron_build = true
|
||||
root_extra_deps = [ "//electron" ]
|
||||
|
||||
# Registry of NMVs --> https://github.com/nodejs/node/blob/master/doc/abi_version_registry.json
|
||||
node_module_version = 98
|
||||
node_module_version = 89
|
||||
|
||||
v8_promise_internal_field_count = 1
|
||||
v8_typed_array_max_size_in_heap = 0
|
||||
|
||||
@@ -57,42 +57,4 @@ template("asar") {
|
||||
rebase_path(outputs[0]),
|
||||
]
|
||||
}
|
||||
|
||||
node_action(target_name + "_header_hash") {
|
||||
invoker_out = invoker.outputs
|
||||
|
||||
deps = [ ":" + invoker.target_name ]
|
||||
sources = invoker.outputs
|
||||
|
||||
script = "//electron/script/gn-asar-hash.js"
|
||||
outputs = [ "$target_gen_dir/asar_hashes/$target_name.hash" ]
|
||||
|
||||
args = [
|
||||
rebase_path(invoker_out[0]),
|
||||
rebase_path(outputs[0]),
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
template("asar_hashed_info_plist") {
|
||||
node_action(target_name) {
|
||||
assert(defined(invoker.plist_file),
|
||||
"Need plist_file to add hashed assets to")
|
||||
assert(defined(invoker.keys), "Need keys to replace with asset hash")
|
||||
assert(defined(invoker.hash_targets), "Need hash_targets to read hash from")
|
||||
|
||||
deps = invoker.hash_targets
|
||||
|
||||
script = "//electron/script/gn-plist-but-with-hashes.js"
|
||||
inputs = [ invoker.plist_file ]
|
||||
outputs = [ "$target_gen_dir/hashed_plists/$target_name.plist" ]
|
||||
hash_files = []
|
||||
foreach(hash_target, invoker.hash_targets) {
|
||||
hash_files += get_target_outputs(hash_target)
|
||||
}
|
||||
args = [
|
||||
rebase_path(invoker.plist_file),
|
||||
rebase_path(outputs[0]),
|
||||
] + invoker.keys + rebase_path(hash_files)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,7 +5,5 @@
|
||||
"run_as_node": "1",
|
||||
"cookie_encryption": "0",
|
||||
"node_options": "1",
|
||||
"node_cli_inspect": "1",
|
||||
"embedded_asar_integrity_validation": "0",
|
||||
"only_load_app_from_asar": "0"
|
||||
"node_cli_inspect": "1"
|
||||
}
|
||||
|
||||
@@ -5,8 +5,8 @@ template("npm_action") {
|
||||
|
||||
action("npm_pre_flight_" + target_name) {
|
||||
inputs = [
|
||||
"package.json",
|
||||
"yarn.lock",
|
||||
"//electron/package.json",
|
||||
"//electron/yarn.lock",
|
||||
]
|
||||
script = "//electron/build/npm-run.py"
|
||||
|
||||
|
||||
@@ -1,12 +1,9 @@
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from __future__ import with_statement
|
||||
import contextlib
|
||||
import sys
|
||||
import os
|
||||
import optparse
|
||||
import json
|
||||
import re
|
||||
import subprocess
|
||||
|
||||
sys.path.append("%s/../../build" % os.path.dirname(os.path.realpath(__file__)))
|
||||
|
||||
@@ -36,56 +33,36 @@ def calculate_hash(root):
|
||||
return CalculateHash('.', None)
|
||||
|
||||
def windows_installed_software():
|
||||
powershell_command = [
|
||||
"Get-CimInstance",
|
||||
"-Namespace",
|
||||
"root\cimv2",
|
||||
"-Class",
|
||||
"Win32_product",
|
||||
"|",
|
||||
"Select",
|
||||
"vendor,",
|
||||
"description,",
|
||||
"@{l='install_location';e='InstallLocation'},",
|
||||
"@{l='install_date';e='InstallDate'},",
|
||||
"@{l='install_date_2';e='InstallDate2'},",
|
||||
"caption,",
|
||||
"version,",
|
||||
"name,",
|
||||
"@{l='sku_number';e='SKUNumber'}",
|
||||
"|",
|
||||
"ConvertTo-Json",
|
||||
]
|
||||
import win32com.client
|
||||
strComputer = "."
|
||||
objWMIService = win32com.client.Dispatch("WbemScripting.SWbemLocator")
|
||||
objSWbemServices = objWMIService.ConnectServer(strComputer, "root\cimv2")
|
||||
colItems = objSWbemServices.ExecQuery("Select * from Win32_Product")
|
||||
items = []
|
||||
|
||||
proc = subprocess.Popen(
|
||||
["powershell.exe", "-Command", "-"],
|
||||
stdin=subprocess.PIPE,
|
||||
stdout=subprocess.PIPE,
|
||||
)
|
||||
for objItem in colItems:
|
||||
item = {}
|
||||
if objItem.Caption:
|
||||
item['caption'] = objItem.Caption
|
||||
if objItem.Caption:
|
||||
item['description'] = objItem.Description
|
||||
if objItem.InstallDate:
|
||||
item['install_date'] = objItem.InstallDate
|
||||
if objItem.InstallDate2:
|
||||
item['install_date_2'] = objItem.InstallDate2
|
||||
if objItem.InstallLocation:
|
||||
item['install_location'] = objItem.InstallLocation
|
||||
if objItem.Name:
|
||||
item['name'] = objItem.Name
|
||||
if objItem.SKUNumber:
|
||||
item['sku_number'] = objItem.SKUNumber
|
||||
if objItem.Vendor:
|
||||
item['vendor'] = objItem.Vendor
|
||||
if objItem.Version:
|
||||
item['version'] = objItem.Version
|
||||
items.append(item)
|
||||
|
||||
stdout, _ = proc.communicate(" ".join(powershell_command).encode("utf-8"))
|
||||
|
||||
if proc.returncode != 0:
|
||||
raise RuntimeError("Failed to get list of installed software")
|
||||
|
||||
# On AppVeyor there's other output related to PSReadline,
|
||||
# so grab only the JSON output and ignore everything else
|
||||
json_match = re.match(
|
||||
r".*(\[.*{.*}.*\]).*", stdout.decode("utf-8"), re.DOTALL
|
||||
)
|
||||
|
||||
if not json_match:
|
||||
raise RuntimeError(
|
||||
"Couldn't find JSON output for list of installed software"
|
||||
)
|
||||
|
||||
# Filter out missing keys
|
||||
return list(
|
||||
map(
|
||||
lambda info: {k: info[k] for k in info if info[k]},
|
||||
json.loads(json_match.group(1)),
|
||||
)
|
||||
)
|
||||
return items
|
||||
|
||||
|
||||
def windows_profile():
|
||||
@@ -112,7 +89,7 @@ def windows_profile():
|
||||
|
||||
def main(options):
|
||||
if sys.platform == 'win32':
|
||||
with open(options.output_json, 'w') as f:
|
||||
with open(options.output_json, 'wb') as f:
|
||||
json.dump(windows_profile(), f)
|
||||
else:
|
||||
raise OSError("Unsupported OS")
|
||||
|
||||
@@ -36,7 +36,7 @@ template("webpack_build") {
|
||||
rebase_path("$target_gen_dir/buildflags/buildflags.h"),
|
||||
"--env.mode=" + mode,
|
||||
]
|
||||
deps += [ "buildflags" ]
|
||||
deps += [ "//electron/buildflags" ]
|
||||
|
||||
outputs = [ invoker.out_file ]
|
||||
}
|
||||
|
||||
@@ -314,13 +314,17 @@ source_set("plugins") {
|
||||
sources += [
|
||||
"//chrome/renderer/pepper/chrome_renderer_pepper_host_factory.cc",
|
||||
"//chrome/renderer/pepper/chrome_renderer_pepper_host_factory.h",
|
||||
"//chrome/renderer/pepper/pepper_flash_font_file_host.cc",
|
||||
"//chrome/renderer/pepper/pepper_flash_font_file_host.h",
|
||||
"//chrome/renderer/pepper/pepper_shared_memory_message_filter.cc",
|
||||
"//chrome/renderer/pepper/pepper_shared_memory_message_filter.h",
|
||||
]
|
||||
if (enable_pdf_viewer) {
|
||||
deps += [ "//components/pdf/renderer" ]
|
||||
sources += [
|
||||
"//chrome/renderer/pepper/pepper_flash_font_file_host.cc",
|
||||
"//chrome/renderer/pepper/pepper_flash_font_file_host.h",
|
||||
]
|
||||
if (enable_pdf_viewer) {
|
||||
deps += [ "//components/pdf/renderer" ]
|
||||
}
|
||||
}
|
||||
deps += [
|
||||
"//components/strings",
|
||||
|
||||
@@ -59,9 +59,10 @@ an issue:
|
||||
* [Testing and Debugging](tutorial/application-debugging.md)
|
||||
* [Debugging the Main Process](tutorial/debugging-main-process.md)
|
||||
* [Debugging with Visual Studio Code](tutorial/debugging-vscode.md)
|
||||
* [Using Selenium and WebDriver](tutorial/using-selenium-and-webdriver.md)
|
||||
* [Testing on Headless CI Systems (Travis, Jenkins)](tutorial/testing-on-headless-ci.md)
|
||||
* [DevTools Extension](tutorial/devtools-extension.md)
|
||||
* [Automated Testing](tutorial/automated-testing.md)
|
||||
* [Automated Testing with a Custom Driver](tutorial/automated-testing-with-a-custom-driver.md)
|
||||
* [REPL](tutorial/repl.md)
|
||||
* [Distribution](tutorial/application-distribution.md)
|
||||
* [Supported Platforms](tutorial/support.md#supported-platforms)
|
||||
|
||||
@@ -36,10 +36,10 @@ Returns:
|
||||
* `launchInfo` Record<string, any> | [NotificationResponse](structures/notification-response.md) _macOS_
|
||||
|
||||
Emitted once, when Electron has finished initializing. On macOS, `launchInfo`
|
||||
holds the `userInfo` of the [`NSUserNotification`](https://developer.apple.com/documentation/foundation/nsusernotification)
|
||||
or information from [`UNNotificationResponse`](https://developer.apple.com/documentation/usernotifications/unnotificationresponse)
|
||||
that was used to open the application, if it was launched from Notification Center.
|
||||
You can also call `app.isReady()` to check if this event has already fired and `app.whenReady()`
|
||||
holds the `userInfo` of the `NSUserNotification` or information from
|
||||
[`UNNotificationResponse`](structures/notification-response.md) that was used to open the
|
||||
application, if it was launched from Notification Center. You can also call
|
||||
`app.isReady()` to check if this event has already fired and `app.whenReady()`
|
||||
to get a Promise that is fulfilled when Electron is initialized.
|
||||
|
||||
### Event: 'window-all-closed'
|
||||
@@ -277,7 +277,6 @@ Returns:
|
||||
* `certificate` [Certificate](structures/certificate.md)
|
||||
* `callback` Function
|
||||
* `isTrusted` Boolean - Whether to consider the certificate as trusted
|
||||
* `isMainFrame` Boolean
|
||||
|
||||
Emitted when failed to verify the `certificate` for `url`, to trust the
|
||||
certificate you should prevent the default behavior with
|
||||
@@ -1062,61 +1061,6 @@ Imports the certificate in pkcs12 format into the platform certificate store.
|
||||
`callback` is called with the `result` of import operation, a value of `0`
|
||||
indicates success while any other value indicates failure according to Chromium [net_error_list](https://source.chromium.org/chromium/chromium/src/+/master:net/base/net_error_list.h).
|
||||
|
||||
### `app.configureHostResolver(options)`
|
||||
|
||||
* `options` Object
|
||||
* `enableBuiltInResolver` Boolean (optional) - Whether the built-in host
|
||||
resolver is used in preference to getaddrinfo. When enabled, the built-in
|
||||
resolver will attempt to use the system's DNS settings to do DNS lookups
|
||||
itself. Enabled by default on macOS, disabled by default on Windows and
|
||||
Linux.
|
||||
* `secureDnsMode` String (optional) - Can be "off", "automatic" or "secure".
|
||||
Configures the DNS-over-HTTP mode. When "off", no DoH lookups will be
|
||||
performed. When "automatic", DoH lookups will be performed first if DoH is
|
||||
available, and insecure DNS lookups will be performed as a fallback. When
|
||||
"secure", only DoH lookups will be performed. Defaults to "automatic".
|
||||
* `secureDnsServers` String[] (optional) - A list of DNS-over-HTTP
|
||||
server templates. See [RFC8484 § 3][] for details on the template format.
|
||||
Most servers support the POST method; the template for such servers is
|
||||
simply a URI. Note that for [some DNS providers][doh-providers], the
|
||||
resolver will automatically upgrade to DoH unless DoH is explicitly
|
||||
disabled, even if there are no DoH servers provided in this list.
|
||||
* `enableAdditionalDnsQueryTypes` Boolean (optional) - Controls whether additional DNS
|
||||
query types, e.g. HTTPS (DNS type 65) will be allowed besides the
|
||||
traditional A and AAAA queries when a request is being made via insecure
|
||||
DNS. Has no effect on Secure DNS which always allows additional types.
|
||||
Defaults to true.
|
||||
|
||||
Configures host resolution (DNS and DNS-over-HTTPS). By default, the following
|
||||
resolvers will be used, in order:
|
||||
|
||||
1. DNS-over-HTTPS, if the [DNS provider supports it][doh-providers], then
|
||||
2. the built-in resolver (enabled on macOS only by default), then
|
||||
3. the system's resolver (e.g. `getaddrinfo`).
|
||||
|
||||
This can be configured to either restrict usage of non-encrypted DNS
|
||||
(`secureDnsMode: "secure"`), or disable DNS-over-HTTPS (`secureDnsMode:
|
||||
"off"`). It is also possible to enable or disable the built-in resolver.
|
||||
|
||||
To disable insecure DNS, you can specify a `secureDnsMode` of `"secure"`. If you do
|
||||
so, you should make sure to provide a list of DNS-over-HTTPS servers to use, in
|
||||
case the user's DNS configuration does not include a provider that supports
|
||||
DoH.
|
||||
|
||||
```js
|
||||
app.configureHostResolver({
|
||||
secureDnsMode: 'secure',
|
||||
secureDnsServers: [
|
||||
'https://cloudflare-dns.com/dns-query'
|
||||
]
|
||||
})
|
||||
```
|
||||
|
||||
This API must be called after the `ready` event is emitted.
|
||||
|
||||
[doh-providers]: https://source.chromium.org/chromium/chromium/src/+/main:net/dns/public/doh_provider_entry.cc;l=31?q=%22DohProviderEntry::GetList()%22&ss=chromium%2Fchromium%2Fsrc
|
||||
[RFC8484 § 3]: https://datatracker.ietf.org/doc/html/rfc8484#section-3
|
||||
|
||||
### `app.disableHardwareAcceleration()`
|
||||
|
||||
Disables hardware acceleration for current app.
|
||||
@@ -1193,8 +1137,8 @@ badge.
|
||||
|
||||
On macOS, it shows on the dock icon. On Linux, it only works for Unity launcher.
|
||||
|
||||
**Note:** Unity launcher requires a `.desktop` file to work. For more information,
|
||||
please read the [Unity integration documentation][unity-requirement].
|
||||
**Note:** Unity launcher requires the existence of a `.desktop` file to work,
|
||||
for more information please read [Desktop Environment Integration][unity-requirement].
|
||||
|
||||
### `app.getBadgeCount()` _Linux_ _macOS_
|
||||
|
||||
@@ -1432,8 +1376,8 @@ An `Integer` property that returns the badge count for current app. Setting the
|
||||
|
||||
On macOS, setting this with any nonzero integer shows on the dock icon. On Linux, this property only works for Unity launcher.
|
||||
|
||||
**Note:** Unity launcher requires a `.desktop` file to work. For more information,
|
||||
please read the [Unity integration documentation][unity-requirement].
|
||||
**Note:** Unity launcher requires the existence of a `.desktop` file to work,
|
||||
for more information please read [Desktop Environment Integration][unity-requirement].
|
||||
|
||||
**Note:** On macOS, you need to ensure that your application has the permission
|
||||
to display notifications for this property to take effect.
|
||||
@@ -1461,7 +1405,7 @@ A `Boolean` property that returns `true` if the app is packaged, `false` otherw
|
||||
[LSCopyDefaultHandlerForURLScheme]: https://developer.apple.com/library/mac/documentation/Carbon/Reference/LaunchServicesReference/#//apple_ref/c/func/LSCopyDefaultHandlerForURLScheme
|
||||
[handoff]: https://developer.apple.com/library/ios/documentation/UserExperience/Conceptual/Handoff/HandoffFundamentals/HandoffFundamentals.html
|
||||
[activity-type]: https://developer.apple.com/library/ios/documentation/Foundation/Reference/NSUserActivity_Class/index.html#//apple_ref/occ/instp/NSUserActivity/activityType
|
||||
[unity-requirement]: https://help.ubuntu.com/community/UnityLaunchersAndDesktopFiles#Adding_shortcuts_to_a_launcher
|
||||
[unity-requirement]: ../tutorial/desktop-environment-integration.md#unity-launcher
|
||||
[mas-builds]: ../tutorial/mac-app-store-submission-guide.md
|
||||
[Squirrel-Windows]: https://github.com/Squirrel/Squirrel.Windows
|
||||
[JumpListBeginListMSDN]: https://msdn.microsoft.com/en-us/library/windows/desktop/dd378398(v=vs.85).aspx
|
||||
|
||||
@@ -43,7 +43,7 @@ The installer generated with Squirrel will create a shortcut icon with an
|
||||
same ID for your app with `app.setAppUserModelId` API, otherwise Windows will
|
||||
not be able to pin your app properly in task bar.
|
||||
|
||||
Like Squirrel.Mac, Windows can host updates on S3 or any other static file host.
|
||||
Unlike Squirrel.Mac, Windows can host updates on S3 or any other static file host.
|
||||
You can read the documents of [Squirrel.Windows][squirrel-windows] to get more details
|
||||
about how Squirrel.Windows works.
|
||||
|
||||
|
||||
@@ -17,19 +17,17 @@ win.loadURL('https://github.com')
|
||||
win.loadFile('index.html')
|
||||
```
|
||||
|
||||
## Window customization
|
||||
## Frameless window
|
||||
|
||||
The `BrowserWindow` class exposes various ways to modify the look and behavior of
|
||||
your app's windows. For more details, see the [Window Customization](../tutorial/window-customization.md)
|
||||
tutorial.
|
||||
To create a window without chrome, or a transparent window in arbitrary shape,
|
||||
you can use the [Frameless Window](frameless-window.md) API.
|
||||
|
||||
## Showing the window gracefully
|
||||
## Showing window gracefully
|
||||
|
||||
When loading a page in the window directly, users may see the page load incrementally,
|
||||
which is not a good experience for a native app. To make the window display
|
||||
without a visual flash, there are two solutions for different situations.
|
||||
When loading a page in the window directly, users may see the page load incrementally, which is not a good experience for a native app. To make the window display
|
||||
without visual flash, there are two solutions for different situations.
|
||||
|
||||
### Using the `ready-to-show` event
|
||||
## Using `ready-to-show` event
|
||||
|
||||
While loading the page, the `ready-to-show` event will be emitted when the renderer
|
||||
process has rendered the page for the first time if the window has not been shown yet. Showing
|
||||
@@ -50,7 +48,7 @@ event.
|
||||
Please note that using this event implies that the renderer will be considered "visible" and
|
||||
paint even though `show` is false. This event will never fire if you use `paintWhenInitiallyHidden: false`
|
||||
|
||||
### Setting the `backgroundColor` property
|
||||
## Setting `backgroundColor`
|
||||
|
||||
For a complex app, the `ready-to-show` event could be emitted too late, making
|
||||
the app feel slow. In this case, it is recommended to show the window
|
||||
@@ -185,13 +183,13 @@ It creates a new `BrowserWindow` with native properties as set by the `options`.
|
||||
`true`.
|
||||
* `paintWhenInitiallyHidden` Boolean (optional) - Whether the renderer should be active when `show` is `false` and it has just been created. In order for `document.visibilityState` to work correctly on first load with `show: false` you should set this to `false`. Setting this to `false` will cause the `ready-to-show` event to not fire. Default is `true`.
|
||||
* `frame` Boolean (optional) - Specify `false` to create a
|
||||
[frameless window](../tutorial/window-customization.md#create-frameless-windows). Default is `true`.
|
||||
[Frameless Window](frameless-window.md). Default is `true`.
|
||||
* `parent` BrowserWindow (optional) - Specify parent window. Default is `null`.
|
||||
* `modal` Boolean (optional) - Whether this is a modal window. This only works when the
|
||||
window is a child window. Default is `false`.
|
||||
* `acceptFirstMouse` Boolean (optional) - Whether clicking an inactive window will also
|
||||
click through to the web contents. Default is `false` on macOS. This option is not
|
||||
configurable on other platforms.
|
||||
* `acceptFirstMouse` Boolean (optional) - Whether the web view accepts a single
|
||||
mouse-down event that simultaneously activates the window. Default is
|
||||
`false`.
|
||||
* `disableAutoHideCursor` Boolean (optional) - Whether to hide cursor when typing.
|
||||
Default is `false`.
|
||||
* `autoHideMenuBar` Boolean (optional) - Auto hide the menu bar unless the `Alt`
|
||||
@@ -207,7 +205,7 @@ It creates a new `BrowserWindow` with native properties as set by the `options`.
|
||||
transparent) and 1.0 (fully opaque). This is only implemented on Windows and macOS.
|
||||
* `darkTheme` Boolean (optional) - Forces using dark theme for the window, only works on
|
||||
some GTK+3 desktop environments. Default is `false`.
|
||||
* `transparent` Boolean (optional) - Makes the window [transparent](../tutorial/window-customization.md#create-transparent-windows).
|
||||
* `transparent` Boolean (optional) - Makes the window [transparent](frameless-window.md#transparent-window).
|
||||
Default is `false`. On Windows, does not work unless the window is frameless.
|
||||
* `type` String (optional) - The type of window, default is normal window. See more about
|
||||
this below.
|
||||
@@ -394,7 +392,6 @@ It creates a new `BrowserWindow` with native properties as set by the `options`.
|
||||
* `titleBarOverlay` Object | Boolean (optional) - When using a frameless window in conjuction with `win.setWindowButtonVisibility(true)` on macOS or using a `titleBarStyle` so that the standard window controls ("traffic lights" on macOS) are visible, this property enables the Window Controls Overlay [JavaScript APIs][overlay-javascript-apis] and [CSS Environment Variables][overlay-css-env-vars]. Specifying `true` will result in an overlay with default system colors. Default is `false`.
|
||||
* `color` String (optional) _Windows_ - The CSS color of the Window Controls Overlay when enabled. Default is the system color.
|
||||
* `symbolColor` String (optional) _Windows_ - The CSS color of the symbols on the Window Controls Overlay when enabled. Default is the system color.
|
||||
* `height` Integer (optional) _macOS_ _Windows_ - The height of the title bar and Window Controls Overlay in pixels. Default is system height.
|
||||
|
||||
When setting minimum or maximum window size with `minWidth`/`maxWidth`/
|
||||
`minHeight`/`maxHeight`, it only constrains the users. It won't prevent you from
|
||||
@@ -990,7 +987,7 @@ the player itself we would call this function with arguments of 16/9 and
|
||||
are within the content view--only that they exist. Sum any extra width and
|
||||
height areas you have within the overall content view.
|
||||
|
||||
The aspect ratio is not respected when window is resized programmatically with
|
||||
The aspect ratio is not respected when window is resized programmingly with
|
||||
APIs like `win.setSize`.
|
||||
|
||||
#### `win.setBackgroundColor(backgroundColor)`
|
||||
@@ -1000,7 +997,7 @@ APIs like `win.setSize`.
|
||||
is `true`). Default is `#FFF` (white).
|
||||
|
||||
Sets the background color of the window. See [Setting
|
||||
`backgroundColor`](#setting-the-backgroundcolor-property).
|
||||
`backgroundColor`](#setting-backgroundcolor).
|
||||
|
||||
#### `win.previewFile(path[, displayName])` _macOS_
|
||||
|
||||
@@ -1045,7 +1042,7 @@ Returns [`Rectangle`](structures/rectangle.md) - The `bounds` of the window as `
|
||||
#### `win.getBackgroundColor()`
|
||||
|
||||
Returns `String` - Gets the background color of the window. See [Setting
|
||||
`backgroundColor`](#setting-the-backgroundcolor-property).
|
||||
`backgroundColor`](#setting-backgroundcolor).
|
||||
|
||||
#### `win.setContentBounds(bounds[, animate])`
|
||||
|
||||
@@ -1698,7 +1695,7 @@ current window into a top-level window.
|
||||
|
||||
#### `win.getParentWindow()`
|
||||
|
||||
Returns `BrowserWindow | null` - The parent window or `null` if there is no parent.
|
||||
Returns `BrowserWindow` - The parent window.
|
||||
|
||||
#### `win.getChildWindows()`
|
||||
|
||||
|
||||
@@ -76,7 +76,7 @@ Writes `markup` to the clipboard.
|
||||
```js
|
||||
const { clipboard } = require('electron')
|
||||
|
||||
clipboard.writeHTML('<b>Hi</b>')
|
||||
clipboard.writeHTML('<b>Hi</b')
|
||||
```
|
||||
|
||||
### `clipboard.readImage([type])`
|
||||
@@ -197,7 +197,7 @@ Returns `Boolean` - Whether the clipboard supports the specified `format`.
|
||||
```js
|
||||
const { clipboard } = require('electron')
|
||||
|
||||
const hasFormat = clipboard.has('public/utf8-plain-text')
|
||||
const hasFormat = clipboard.has('<p>selection</p>')
|
||||
console.log(hasFormat)
|
||||
// 'true' or 'false'
|
||||
```
|
||||
|
||||
@@ -53,12 +53,3 @@ Returns `Boolean` - Whether the command-line switch is present.
|
||||
Returns `String` - The command-line switch value.
|
||||
|
||||
**Note:** When the switch is not present or has no value, it returns empty string.
|
||||
|
||||
#### `commandLine.removeSwitch(switch)`
|
||||
|
||||
* `switch` String - A command-line switch
|
||||
|
||||
Removes the specified switch from Chromium's command line.
|
||||
|
||||
**Note:** This will not affect `process.argv`. The intended usage of this function is to
|
||||
control Chromium's behavior.
|
||||
|
||||
@@ -102,8 +102,8 @@ has been included below for completeness:
|
||||
| `Boolean` | Simple | ✅ | ✅ | N/A |
|
||||
| `Object` | Complex | ✅ | ✅ | Keys must be supported using only "Simple" types in this table. Values must be supported in this table. Prototype modifications are dropped. Sending custom classes will copy values but not the prototype. |
|
||||
| `Array` | Complex | ✅ | ✅ | Same limitations as the `Object` type |
|
||||
| `Error` | Complex | ✅ | ✅ | Errors that are thrown are also copied, this can result in the message and stack trace of the error changing slightly due to being thrown in a different context, and any custom properties on the Error object [will be lost](https://github.com/electron/electron/issues/25596) |
|
||||
| `Promise` | Complex | ✅ | ✅ | N/A
|
||||
| `Error` | Complex | ✅ | ✅ | Errors that are thrown are also copied, this can result in the message and stack trace of the error changing slightly due to being thrown in a different context |
|
||||
| `Promise` | Complex | ✅ | ✅ | Promises are only proxied if they are the return value or exact parameter. Promises nested in arrays or objects will be dropped. |
|
||||
| `Function` | Complex | ✅ | ✅ | Prototype modifications are dropped. Sending classes or constructors will not work. |
|
||||
| [Cloneable Types](https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Structured_clone_algorithm) | Simple | ✅ | ✅ | See the linked document on cloneable types |
|
||||
| `Element` | Complex | ✅ | ✅ | Prototype modifications are dropped. Sending custom elements will not work. |
|
||||
|
||||
@@ -93,7 +93,7 @@ the response.
|
||||
* `domain` String (optional) - The domain of the cookie; this will be normalized with a preceding dot so that it's also valid for subdomains. Empty by default if omitted.
|
||||
* `path` String (optional) - The path of the cookie. Empty by default if omitted.
|
||||
* `secure` Boolean (optional) - Whether the cookie should be marked as Secure. Defaults to
|
||||
false unless [Same Site=None](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie/SameSite#samesitenone_requires_secure) attribute is used.
|
||||
false.
|
||||
* `httpOnly` Boolean (optional) - Whether the cookie should be marked as HTTP only.
|
||||
Defaults to false.
|
||||
* `expirationDate` Double (optional) - The expiration date of the cookie as the number of
|
||||
|
||||
@@ -19,6 +19,9 @@ following projects:
|
||||
* [socorro](https://github.com/mozilla/socorro)
|
||||
* [mini-breakpad-server](https://github.com/electron/mini-breakpad-server)
|
||||
|
||||
> **Note:** Electron uses Crashpad, not Breakpad, to collect and upload
|
||||
> crashes, but for the time being, the [upload protocol is the same](https://chromium.googlesource.com/crashpad/crashpad/+/HEAD/doc/overview_design.md#Upload-to-collection-server).
|
||||
|
||||
Or use a 3rd party hosted solution:
|
||||
|
||||
* [Backtrace](https://backtrace.io/electron/)
|
||||
@@ -26,49 +29,12 @@ Or use a 3rd party hosted solution:
|
||||
* [BugSplat](https://www.bugsplat.com/docs/platforms/electron)
|
||||
|
||||
Crash reports are stored temporarily before being uploaded in a directory
|
||||
underneath the app's user data directory (called 'Crashpad' on Windows and Mac,
|
||||
or 'Crash Reports' on Linux). You can override this directory by calling
|
||||
`app.setPath('crashDumps', '/path/to/crashes')` before starting the crash
|
||||
reporter.
|
||||
underneath the app's user data directory, called 'Crashpad'. You can override
|
||||
this directory by calling `app.setPath('crashDumps', '/path/to/crashes')`
|
||||
before starting the crash reporter.
|
||||
|
||||
On Windows and macOS, Electron uses
|
||||
[crashpad](https://chromium.googlesource.com/crashpad/crashpad/+/master/README.md)
|
||||
to monitor and report crashes. On Linux, Electron uses
|
||||
[breakpad](https://chromium.googlesource.com/breakpad/breakpad/+/master/). This
|
||||
is an implementation detail driven by Chromium, and it may change in future. In
|
||||
particular, crashpad is newer and will likely eventually replace breakpad on
|
||||
all platforms.
|
||||
|
||||
### Note about Node child processes on Linux
|
||||
|
||||
If you are using the Node.js `child_process` module and want to report crashes
|
||||
from those processes on Linux, there is an extra step you will need to take to
|
||||
properly initialize the crash reporter in the child process. This is not
|
||||
necessary on Mac or Windows, as those platforms use Crashpad, which
|
||||
automatically monitors child processes.
|
||||
|
||||
Since `require('electron')` is not available in Node child processes, the
|
||||
following APIs are available on the `process` object in Node child processes.
|
||||
Note that, on Linux, each Node child process has its own separate instance of
|
||||
the breakpad crash reporter. This is dissimilar to renderer child processes,
|
||||
which have a "stub" breakpad reporter which returns information to the main
|
||||
process for reporting.
|
||||
|
||||
#### `process.crashReporter.start(options)`
|
||||
|
||||
See [`crashReporter.start()`](#crashreporterstartoptions).
|
||||
|
||||
#### `process.crashReporter.getParameters()`
|
||||
|
||||
See [`crashReporter.getParameters()`](#crashreportergetparameters).
|
||||
|
||||
#### `process.crashReporter.addExtraParameter(key, value)`
|
||||
|
||||
See [`crashReporter.addExtraParameter(key, value)`](#crashreporteraddextraparameterkey-value).
|
||||
|
||||
#### `process.crashReporter.removeExtraParameter(key)`
|
||||
|
||||
See [`crashReporter.removeExtraParameter(key)`](#crashreporterremoveextraparameterkey).
|
||||
Electron uses [crashpad](https://chromium.googlesource.com/crashpad/crashpad/+/refs/heads/main/README.md)
|
||||
to monitor and report crashes.
|
||||
|
||||
## Methods
|
||||
|
||||
@@ -186,12 +152,6 @@ names must be no longer than 39 bytes, and values must be no longer than 20320
|
||||
bytes. Keys with names longer than the maximum will be silently ignored. Key
|
||||
values longer than the maximum length will be truncated.
|
||||
|
||||
**Note:** On linux values that are longer than 127 bytes will be chunked into
|
||||
multiple keys, each 127 bytes in length. E.g. `addExtraParameter('foo', 'a'.repeat(130))`
|
||||
will result in two chunked keys `foo__1` and `foo__2`, the first will contain
|
||||
the first 127 bytes and the second will contain the remaining 3 bytes. On
|
||||
your crash reporting backend you should stitch together keys in this format.
|
||||
|
||||
### `crashReporter.removeExtraParameter(key)`
|
||||
|
||||
* `key` String - Parameter key, must be no longer than 39 bytes.
|
||||
@@ -203,6 +163,32 @@ will not include this parameter.
|
||||
|
||||
Returns `Record<String, String>` - The current 'extra' parameters of the crash reporter.
|
||||
|
||||
## In Node child processes
|
||||
|
||||
Since `require('electron')` is not available in Node child processes, the
|
||||
following APIs are available on the `process` object in Node child processes.
|
||||
|
||||
#### `process.crashReporter.start(options)`
|
||||
|
||||
See [`crashReporter.start()`](#crashreporterstartoptions).
|
||||
|
||||
Note that if the crash reporter is started in the main process, it will
|
||||
automatically monitor child processes, so it should not be started in the child
|
||||
process. Only use this method if the main process does not initialize the crash
|
||||
reporter.
|
||||
|
||||
#### `process.crashReporter.getParameters()`
|
||||
|
||||
See [`crashReporter.getParameters()`](#crashreportergetparameters).
|
||||
|
||||
#### `process.crashReporter.addExtraParameter(key, value)`
|
||||
|
||||
See [`crashReporter.addExtraParameter(key, value)`](#crashreporteraddextraparameterkey-value).
|
||||
|
||||
#### `process.crashReporter.removeExtraParameter(key)`
|
||||
|
||||
See [`crashReporter.removeExtraParameter(key)`](#crashreporterremoveextraparameterkey).
|
||||
|
||||
## Crash Report Payload
|
||||
|
||||
The crash reporter will send the following data to the `submitURL` as
|
||||
|
||||
@@ -234,7 +234,6 @@ expanding and collapsing the dialog.
|
||||
* `title` String (optional) - Title of the message box, some platforms will not show it.
|
||||
* `detail` String (optional) - Extra information of the message.
|
||||
* `icon` ([NativeImage](native-image.md) | String) (optional)
|
||||
* `textWidth` Integer (optional) _macOS_ - Custom width of the text in the message box.
|
||||
* `cancelId` Integer (optional) - The index of the button to be used to cancel the dialog, via
|
||||
the `Esc` key. By default this is assigned to the first button with "cancel" or "no" as the
|
||||
label. If no such labeled buttons exist and this option is not set, `0` will be used as the
|
||||
@@ -286,7 +285,6 @@ If `browserWindow` is not shown dialog will not be attached to it. In such case
|
||||
* `checkboxChecked` Boolean (optional) - Initial checked state of the
|
||||
checkbox. `false` by default.
|
||||
* `icon` [NativeImage](native-image.md) (optional)
|
||||
* `textWidth` Integer (optional) _macOS_ - Custom width of the text in the message box.
|
||||
* `cancelId` Integer (optional) - The index of the button to be used to cancel the dialog, via
|
||||
the `Esc` key. By default this is assigned to the first button with "cancel" or "no" as the
|
||||
label. If no such labeled buttons exist and this option is not set, `0` will be used as the
|
||||
|
||||
@@ -122,7 +122,7 @@ Prints Chromium's internal logging to the console.
|
||||
|
||||
Setting this variable is the same as passing `--enable-logging`
|
||||
on the command line. For more info, see `--enable-logging` in [command-line
|
||||
switches](./command-line-switches.md#--enable-loggingfile).
|
||||
switches](./command-line-switches.md#enable-loggingfile).
|
||||
|
||||
### `ELECTRON_LOG_FILE`
|
||||
|
||||
@@ -130,7 +130,7 @@ Sets the file destination for Chromium's internal logging.
|
||||
|
||||
Setting this variable is the same as passing `--log-file`
|
||||
on the command line. For more info, see `--log-file` in [command-line
|
||||
switches](./command-line-switches.md#--log-filepath).
|
||||
switches](./command-line-switches.md#log-filepath).
|
||||
|
||||
### `ELECTRON_DEBUG_DRAG_REGIONS`
|
||||
|
||||
|
||||
@@ -100,6 +100,8 @@ The following methods of `chrome.tabs` are supported:
|
||||
|
||||
- `chrome.tabs.sendMessage`
|
||||
- `chrome.tabs.executeScript`
|
||||
- `chrome.tabs.update` (partial support)
|
||||
- supported properties: `url`, `muted`.
|
||||
|
||||
> **Note:** In Chrome, passing `-1` as a tab ID signifies the "currently active
|
||||
> tab". Since Electron has no such concept, passing `-1` as a tab ID is not
|
||||
|
||||
221
docs/api/frameless-window.md
Normal file
221
docs/api/frameless-window.md
Normal file
@@ -0,0 +1,221 @@
|
||||
# Frameless Window
|
||||
|
||||
> Open a window without toolbars, borders, or other graphical "chrome".
|
||||
|
||||
A frameless window is a window that has no
|
||||
[chrome](https://developer.mozilla.org/en-US/docs/Glossary/Chrome), the parts of
|
||||
the window, like toolbars, that are not a part of the web page. These are
|
||||
options on the [`BrowserWindow`](browser-window.md) class.
|
||||
|
||||
## Create a frameless window
|
||||
|
||||
To create a frameless window, you need to set `frame` to `false` in
|
||||
[BrowserWindow](browser-window.md)'s `options`:
|
||||
|
||||
```javascript
|
||||
const { BrowserWindow } = require('electron')
|
||||
const win = new BrowserWindow({ width: 800, height: 600, frame: false })
|
||||
win.show()
|
||||
```
|
||||
|
||||
### Alternatives
|
||||
|
||||
There's an alternative way to specify a chromeless window on macOS and Windows.
|
||||
Instead of setting `frame` to `false` which disables both the titlebar and window controls,
|
||||
you may want to have the title bar hidden and your content extend to the full window size,
|
||||
yet still preserve the window controls ("traffic lights" on macOS) for standard window actions.
|
||||
You can do so by specifying the `titleBarStyle` option:
|
||||
|
||||
#### `hidden`
|
||||
|
||||
Results in a hidden title bar and a full size content window. On macOS, the title bar still has the standard window controls (“traffic lights”) in the top left.
|
||||
|
||||
```javascript
|
||||
const { BrowserWindow } = require('electron')
|
||||
const win = new BrowserWindow({ titleBarStyle: 'hidden' })
|
||||
win.show()
|
||||
```
|
||||
|
||||
### Alternatives on macOS
|
||||
|
||||
#### `hiddenInset`
|
||||
|
||||
Results in a hidden title bar with an alternative look where the traffic light buttons are slightly more inset from the window edge.
|
||||
|
||||
```javascript
|
||||
const { BrowserWindow } = require('electron')
|
||||
const win = new BrowserWindow({ titleBarStyle: 'hiddenInset' })
|
||||
win.show()
|
||||
```
|
||||
|
||||
#### `customButtonsOnHover`
|
||||
|
||||
Uses custom drawn close, and miniaturize buttons that display
|
||||
when hovering in the top left of the window. The fullscreen button
|
||||
is not available due to restrictions of frameless windows as they
|
||||
interface with Apple's macOS window masks. These custom buttons prevent
|
||||
issues with mouse events that occur with the standard window toolbar buttons.
|
||||
This option is only applicable for frameless windows.
|
||||
|
||||
```javascript
|
||||
const { BrowserWindow } = require('electron')
|
||||
const win = new BrowserWindow({ titleBarStyle: 'customButtonsOnHover', frame: false })
|
||||
win.show()
|
||||
```
|
||||
|
||||
## Windows Control Overlay
|
||||
|
||||
When using a frameless window in conjuction with `win.setWindowButtonVisibility(true)` on macOS, using one of the `titleBarStyle`s as described above so
|
||||
that the traffic lights are visible, or using `titleBarStyle: hidden` on Windows, you can access the Window Controls Overlay [JavaScript APIs][overlay-javascript-apis] and
|
||||
[CSS Environment Variables][overlay-css-env-vars] by setting the `titleBarOverlay` option to true. Specifying `true` will result in an overlay with default system colors.
|
||||
|
||||
On Windows, you can also specify the color of the overlay and its symbols by setting `titleBarOverlay` to an object with the options `color` and `symbolColor`. If an option is not specified, the color will default to its system color for the window control buttons:
|
||||
|
||||
```javascript
|
||||
const { BrowserWindow } = require('electron')
|
||||
const win = new BrowserWindow({
|
||||
titleBarStyle: 'hidden',
|
||||
titleBarOverlay: true
|
||||
})
|
||||
win.show()
|
||||
```
|
||||
|
||||
```javascript
|
||||
const { BrowserWindow } = require('electron')
|
||||
const win = new BrowserWindow({
|
||||
titleBarStyle: 'hidden',
|
||||
titleBarOverlay: {
|
||||
color: '#2f3241',
|
||||
symbolColor: '#74b1be'
|
||||
}
|
||||
})
|
||||
win.show()
|
||||
```
|
||||
|
||||
## Transparent window
|
||||
|
||||
By setting the `transparent` option to `true`, you can also make the frameless
|
||||
window transparent:
|
||||
|
||||
```javascript
|
||||
const { BrowserWindow } = require('electron')
|
||||
const win = new BrowserWindow({ transparent: true, frame: false })
|
||||
win.show()
|
||||
```
|
||||
|
||||
### Limitations
|
||||
|
||||
* You can not click through the transparent area. We are going to introduce an
|
||||
API to set window shape to solve this, see
|
||||
[our issue](https://github.com/electron/electron/issues/1335) for details.
|
||||
* Transparent windows are not resizable. Setting `resizable` to `true` may make
|
||||
a transparent window stop working on some platforms.
|
||||
* The `blur` filter only applies to the web page, so there is no way to apply
|
||||
blur effect to the content below the window (i.e. other applications open on
|
||||
the user's system).
|
||||
* The window will not be transparent when DevTools is opened.
|
||||
* On Windows operating systems,
|
||||
* transparent windows will not work when DWM is
|
||||
disabled.
|
||||
* transparent windows can not be maximized using the Windows system menu or by double clicking the title bar. The reasoning behind this can be seen on [this pull request](https://github.com/electron/electron/pull/28207).
|
||||
* On Linux, users have to put `--enable-transparent-visuals --disable-gpu` in
|
||||
the command line to disable GPU and allow ARGB to make transparent window,
|
||||
this is caused by an upstream bug that [alpha channel doesn't work on some
|
||||
NVidia drivers](https://bugs.chromium.org/p/chromium/issues/detail?id=369209) on
|
||||
Linux.
|
||||
* On Mac, the native window shadow will not be shown on a transparent window.
|
||||
|
||||
## Click-through window
|
||||
|
||||
To create a click-through window, i.e. making the window ignore all mouse
|
||||
events, you can call the [win.setIgnoreMouseEvents(ignore)][ignore-mouse-events]
|
||||
API:
|
||||
|
||||
```javascript
|
||||
const { BrowserWindow } = require('electron')
|
||||
const win = new BrowserWindow()
|
||||
win.setIgnoreMouseEvents(true)
|
||||
```
|
||||
|
||||
### Forwarding
|
||||
|
||||
Ignoring mouse messages makes the web page oblivious to mouse movement, meaning
|
||||
that mouse movement events will not be emitted. On Windows operating systems an
|
||||
optional parameter can be used to forward mouse move messages to the web page,
|
||||
allowing events such as `mouseleave` to be emitted:
|
||||
|
||||
```javascript
|
||||
const { ipcRenderer } = require('electron')
|
||||
const el = document.getElementById('clickThroughElement')
|
||||
el.addEventListener('mouseenter', () => {
|
||||
ipcRenderer.send('set-ignore-mouse-events', true, { forward: true })
|
||||
})
|
||||
el.addEventListener('mouseleave', () => {
|
||||
ipcRenderer.send('set-ignore-mouse-events', false)
|
||||
})
|
||||
|
||||
// Main process
|
||||
const { ipcMain } = require('electron')
|
||||
ipcMain.on('set-ignore-mouse-events', (event, ...args) => {
|
||||
BrowserWindow.fromWebContents(event.sender).setIgnoreMouseEvents(...args)
|
||||
})
|
||||
```
|
||||
|
||||
This makes the web page click-through when over `el`, and returns to normal
|
||||
outside it.
|
||||
|
||||
## Draggable region
|
||||
|
||||
By default, the frameless window is non-draggable. Apps need to specify
|
||||
`-webkit-app-region: drag` in CSS to tell Electron which regions are draggable
|
||||
(like the OS's standard titlebar), and apps can also use
|
||||
`-webkit-app-region: no-drag` to exclude the non-draggable area from the
|
||||
draggable region. Note that only rectangular shapes are currently supported.
|
||||
|
||||
Note: `-webkit-app-region: drag` is known to have problems while the developer tools are open. See this [GitHub issue](https://github.com/electron/electron/issues/3647) for more information including a workaround.
|
||||
|
||||
To make the whole window draggable, you can add `-webkit-app-region: drag` as
|
||||
`body`'s style:
|
||||
|
||||
```html
|
||||
<body style="-webkit-app-region: drag">
|
||||
</body>
|
||||
```
|
||||
|
||||
And note that if you have made the whole window draggable, you must also mark
|
||||
buttons as non-draggable, otherwise it would be impossible for users to click on
|
||||
them:
|
||||
|
||||
```css
|
||||
button {
|
||||
-webkit-app-region: no-drag;
|
||||
}
|
||||
```
|
||||
|
||||
If you're only setting a custom titlebar as draggable, you also need to make all
|
||||
buttons in titlebar non-draggable.
|
||||
|
||||
## Text selection
|
||||
|
||||
In a frameless window the dragging behavior may conflict with selecting text.
|
||||
For example, when you drag the titlebar you may accidentally select the text on
|
||||
the titlebar. To prevent this, you need to disable text selection within a
|
||||
draggable area like this:
|
||||
|
||||
```css
|
||||
.titlebar {
|
||||
-webkit-user-select: none;
|
||||
-webkit-app-region: drag;
|
||||
}
|
||||
```
|
||||
|
||||
## Context menu
|
||||
|
||||
On some platforms, the draggable area will be treated as a non-client frame, so
|
||||
when you right click on it a system menu will pop up. To make the context menu
|
||||
behave correctly on all platforms you should never use a custom context menu on
|
||||
draggable areas.
|
||||
|
||||
[ignore-mouse-events]: browser-window.md#winsetignoremouseeventsignore-options
|
||||
[overlay-javascript-apis]: https://github.com/WICG/window-controls-overlay/blob/main/explainer.md#javascript-apis
|
||||
[overlay-css-env-vars]: https://github.com/WICG/window-controls-overlay/blob/main/explainer.md#css-environment-variables
|
||||
@@ -67,8 +67,3 @@ or is being instructed to show a high-contrast UI.
|
||||
|
||||
A `Boolean` for if the OS / Chromium currently has an inverted color scheme
|
||||
or is being instructed to use an inverted color scheme.
|
||||
|
||||
### `nativeTheme.inForcedColorsMode` _Windows_ _Readonly_
|
||||
|
||||
A `boolean` indicating whether Chromium is in forced colors mode, controlled by system accessibility settings.
|
||||
Currently, Windows high contrast is the only system setting that triggers forced colors mode.
|
||||
|
||||
@@ -178,6 +178,7 @@ Returns an object with V8 heap statistics. Note that all statistics are reported
|
||||
Returns `Object`:
|
||||
|
||||
* `allocated` Integer - Size of all allocated objects in Kilobytes.
|
||||
* `marked` Integer - Size of all marked objects in Kilobytes.
|
||||
* `total` Integer - Total allocated space in Kilobytes.
|
||||
|
||||
Returns an object with Blink memory information.
|
||||
|
||||
@@ -180,96 +180,6 @@ Emitted when a hunspell dictionary file download fails. For details
|
||||
on the failure you should collect a netlog and inspect the download
|
||||
request.
|
||||
|
||||
#### Event: 'select-hid-device'
|
||||
|
||||
Returns:
|
||||
|
||||
* `event` Event
|
||||
* `details` Object
|
||||
* `deviceList` [HIDDevice[]](structures/hid-device.md)
|
||||
* `frame` [WebFrameMain](web-frame-main.md)
|
||||
* `callback` Function
|
||||
* `deviceId` String | null (optional)
|
||||
|
||||
Emitted when a HID device needs to be selected when a call to
|
||||
`navigator.hid.requestDevice` is made. `callback` should be called with
|
||||
`deviceId` to be selected; passing no arguments to `callback` will
|
||||
cancel the request. Additionally, permissioning on `navigator.hid` can
|
||||
be further managed by using [ses.setPermissionCheckHandler(handler)](#sessetpermissioncheckhandlerhandler)
|
||||
and [ses.setDevicePermissionHandler(handler)`](#sessetdevicepermissionhandlerhandler).
|
||||
|
||||
```javascript
|
||||
const { app, BrowserWindow } = require('electron')
|
||||
|
||||
let win = null
|
||||
|
||||
app.whenReady().then(() => {
|
||||
win = new BrowserWindow()
|
||||
|
||||
win.webContents.session.setPermissionCheckHandler((webContents, permission, requestingOrigin, details) => {
|
||||
if (permission === 'hid') {
|
||||
// Add logic here to determine if permission should be given to allow HID selection
|
||||
return true
|
||||
}
|
||||
return false
|
||||
})
|
||||
|
||||
// Optionally, retrieve previously persisted devices from a persistent store
|
||||
const grantedDevices = fetchGrantedDevices()
|
||||
|
||||
win.webContents.session.setDevicePermissionHandler((details) => {
|
||||
if (new URL(details.origin).hostname === 'some-host' && details.deviceType === 'hid') {
|
||||
if (details.device.vendorId === 123 && details.device.productId === 345) {
|
||||
// Always allow this type of device (this allows skipping the call to `navigator.hid.requestDevice` first)
|
||||
return true
|
||||
}
|
||||
|
||||
// Search through the list of devices that have previously been granted permission
|
||||
return grantedDevices.some((grantedDevice) => {
|
||||
return grantedDevice.vendorId === details.device.vendorId &&
|
||||
grantedDevice.productId === details.device.productId &&
|
||||
grantedDevice.serialNumber && grantedDevice.serialNumber === details.device.serialNumber
|
||||
})
|
||||
}
|
||||
return false
|
||||
})
|
||||
|
||||
win.webContents.session.on('select-hid-device', (event, details, callback) => {
|
||||
event.preventDefault()
|
||||
const selectedDevice = details.deviceList.find((device) => {
|
||||
return device.vendorId === '9025' && device.productId === '67'
|
||||
})
|
||||
callback(selectedPort?.deviceId)
|
||||
})
|
||||
})
|
||||
```
|
||||
|
||||
#### Event: 'hid-device-added'
|
||||
|
||||
Returns:
|
||||
|
||||
* `event` Event
|
||||
* `details` Object
|
||||
* `device` [HIDDevice[]](structures/hid-device.md)
|
||||
* `frame` [WebFrameMain](web-frame-main.md)
|
||||
|
||||
Emitted when a new HID device becomes available. For example, when a new USB device is plugged in.
|
||||
|
||||
This event will only be emitted after `navigator.hid.requestDevice` has been called and `select-hid-device` has fired.
|
||||
|
||||
#### Event: 'hid-device-removed'
|
||||
|
||||
Returns:
|
||||
|
||||
* `event` Event
|
||||
* `details` Object
|
||||
* `device` [HIDDevice[]](structures/hid-device.md)
|
||||
* `frame` [WebFrameMain](web-frame-main.md)
|
||||
|
||||
Emitted when a HID device has been removed. For example, this event will fire when a USB device is unplugged.
|
||||
|
||||
This event will only be emitted after `navigator.hid.requestDevice` has been called and `select-hid-device` has fired.
|
||||
|
||||
#### Event: 'select-serial-port'
|
||||
|
||||
Returns:
|
||||
@@ -297,35 +207,6 @@ app.whenReady().then(() => {
|
||||
width: 800,
|
||||
height: 600
|
||||
})
|
||||
|
||||
win.webContents.session.setPermissionCheckHandler((webContents, permission, requestingOrigin, details) => {
|
||||
if (permission === 'serial') {
|
||||
// Add logic here to determine if permission should be given to allow serial selection
|
||||
return true
|
||||
}
|
||||
return false
|
||||
})
|
||||
|
||||
// Optionally, retrieve previously persisted devices from a persistent store
|
||||
const grantedDevices = fetchGrantedDevices()
|
||||
|
||||
win.webContents.session.setDevicePermissionHandler((details) => {
|
||||
if (new URL(details.origin).hostname === 'some-host' && details.deviceType === 'serial') {
|
||||
if (details.device.vendorId === 123 && details.device.productId === 345) {
|
||||
// Always allow this type of device (this allows skipping the call to `navigator.serial.requestPort` first)
|
||||
return true
|
||||
}
|
||||
|
||||
// Search through the list of devices that have previously been granted permission
|
||||
return grantedDevices.some((grantedDevice) => {
|
||||
return grantedDevice.vendorId === details.device.vendorId &&
|
||||
grantedDevice.productId === details.device.productId &&
|
||||
grantedDevice.serialNumber && grantedDevice.serialNumber === details.device.serialNumber
|
||||
})
|
||||
}
|
||||
return false
|
||||
})
|
||||
|
||||
win.webContents.session.on('select-serial-port', (event, portList, webContents, callback) => {
|
||||
event.preventDefault()
|
||||
const selectedPort = portList.find((device) => {
|
||||
@@ -562,7 +443,8 @@ the original network configuration.
|
||||
* `hostname` String
|
||||
* `certificate` [Certificate](structures/certificate.md)
|
||||
* `validatedCertificate` [Certificate](structures/certificate.md)
|
||||
* `verificationResult` String - Verification result from chromium.
|
||||
* `isIssuedByKnownRoot` Boolean - `true` if Chromium recognises the root CA as a standard root. If it isn't then it's probably the case that this certificate was generated by a MITM proxy whose root has been installed locally (for example, by a corporate proxy). This should not be trusted if the `verificationResult` is not `OK`.
|
||||
* `verificationResult` String - `OK` if the certificate is trusted, otherwise an error like `CERT_REVOKED`.
|
||||
* `errorCode` Integer - Error code.
|
||||
* `callback` Function
|
||||
* `verificationResult` Integer - Value can be one of certificate error codes
|
||||
@@ -617,7 +499,6 @@ win.webContents.session.setCertificateVerifyProc((request, callback) => {
|
||||
* `permissionGranted` Boolean - Allow or deny the permission.
|
||||
* `details` Object - Some properties are only available on certain permission types.
|
||||
* `externalURL` String (optional) - The url of the `openExternal` request.
|
||||
* `securityOrigin` String (optional) - The security origin of the `media` request.
|
||||
* `mediaTypes` String[] (optional) - The types of media access being requested, elements can be `video`
|
||||
or `audio`
|
||||
* `requestingUrl` String - The last URL the requesting frame loaded
|
||||
@@ -643,8 +524,8 @@ session.fromPartition('some-partition').setPermissionRequestHandler((webContents
|
||||
#### `ses.setPermissionCheckHandler(handler)`
|
||||
|
||||
* `handler` Function\<Boolean> | null
|
||||
* `webContents` ([WebContents](web-contents.md) | null) - WebContents checking the permission. Please note that if the request comes from a subframe you should use `requestingUrl` to check the request origin. All cross origin sub frames making permission checks will pass a `null` webContents to this handler, while certain other permission checks such as `notifications` checks will always pass `null`. You should use `embeddingOrigin` and `requestingOrigin` to determine what origin the owning frame and the requesting frame are on respectively.
|
||||
* `permission` String - Type of permission check. Valid values are `midiSysex`, `notifications`, `geolocation`, `media`,`mediaKeySystem`,`midi`, `pointerLock`, `fullscreen`, `openExternal`, `hid`, or `serial`.
|
||||
* `webContents` ([WebContents](web-contents.md) | null) - WebContents checking the permission. Please note that if the request comes from a subframe you should use `requestingUrl` to check the request origin. Cross origin sub frames making permission checks will pass a `null` webContents to this handler. You should use `embeddingOrigin` and `requestingOrigin` to determine what origin the owning frame and the requesting frame are on respectively.
|
||||
* `permission` String - Type of permission check. Valid values are `midiSysex`, `notifications`, `geolocation`, `media`,`mediaKeySystem`,`midi`, `pointerLock`, `fullscreen`, `openExternal`, or `serial`.
|
||||
* `requestingOrigin` String - The origin URL of the permission check
|
||||
* `details` Object - Some properties are only available on certain permission types.
|
||||
* `embeddingOrigin` String (optional) - The origin of the frame embedding the frame that made the permission check. Only set for cross-origin sub frames making permission checks.
|
||||
@@ -672,78 +553,6 @@ session.fromPartition('some-partition').setPermissionCheckHandler((webContents,
|
||||
})
|
||||
```
|
||||
|
||||
#### `ses.setDevicePermissionHandler(handler)`
|
||||
|
||||
* `handler` Function\<Boolean> | null
|
||||
* `details` Object
|
||||
* `deviceType` String - The type of device that permission is being requested on, can be `hid` or `serial`.
|
||||
* `origin` String - The origin URL of the device permission check.
|
||||
* `device` [HIDDevice](structures/hid-device.md) | [SerialPort](structures/serial-port.md)- the device that permission is being requested for.
|
||||
* `frame` [WebFrameMain](web-frame-main.md) - WebFrameMain checking the device permission.
|
||||
|
||||
Sets the handler which can be used to respond to device permission checks for the `session`.
|
||||
Returning `true` will allow the device to be permitted and `false` will reject it.
|
||||
To clear the handler, call `setDevicePermissionHandler(null)`.
|
||||
This handler can be used to provide default permissioning to devices without first calling for permission
|
||||
to devices (eg via `navigator.hid.requestDevice`). If this handler is not defined, the default device
|
||||
permissions as granted through device selection (eg via `navigator.hid.requestDevice`) will be used.
|
||||
Additionally, the default behavior of Electron is to store granted device permision through the lifetime
|
||||
of the corresponding WebContents. If longer term storage is needed, a developer can store granted device
|
||||
permissions (eg when handling the `select-hid-device` event) and then read from that storage with `setDevicePermissionHandler`.
|
||||
|
||||
```javascript
|
||||
const { app, BrowserWindow } = require('electron')
|
||||
|
||||
let win = null
|
||||
|
||||
app.whenReady().then(() => {
|
||||
win = new BrowserWindow()
|
||||
|
||||
win.webContents.session.setPermissionCheckHandler((webContents, permission, requestingOrigin, details) => {
|
||||
if (permission === 'hid') {
|
||||
// Add logic here to determine if permission should be given to allow HID selection
|
||||
return true
|
||||
} else if (permission === 'serial') {
|
||||
// Add logic here to determine if permission should be given to allow serial port selection
|
||||
}
|
||||
return false
|
||||
})
|
||||
|
||||
// Optionally, retrieve previously persisted devices from a persistent store
|
||||
const grantedDevices = fetchGrantedDevices()
|
||||
|
||||
win.webContents.session.setDevicePermissionHandler((details) => {
|
||||
if (new URL(details.origin).hostname === 'some-host' && details.deviceType === 'hid') {
|
||||
if (details.device.vendorId === 123 && details.device.productId === 345) {
|
||||
// Always allow this type of device (this allows skipping the call to `navigator.hid.requestDevice` first)
|
||||
return true
|
||||
}
|
||||
|
||||
// Search through the list of devices that have previously been granted permission
|
||||
return grantedDevices.some((grantedDevice) => {
|
||||
return grantedDevice.vendorId === details.device.vendorId &&
|
||||
grantedDevice.productId === details.device.productId &&
|
||||
grantedDevice.serialNumber && grantedDevice.serialNumber === details.device.serialNumber
|
||||
})
|
||||
} else if (details.deviceType === 'serial') {
|
||||
if (details.device.vendorId === 123 && details.device.productId === 345) {
|
||||
// Always allow this type of device (this allows skipping the call to `navigator.hid.requestDevice` first)
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
})
|
||||
|
||||
win.webContents.session.on('select-hid-device', (event, details, callback) => {
|
||||
event.preventDefault()
|
||||
const selectedDevice = details.deviceList.find((device) => {
|
||||
return device.vendorId === '9025' && device.productId === '67'
|
||||
})
|
||||
callback(selectedPort?.deviceId)
|
||||
})
|
||||
})
|
||||
```
|
||||
|
||||
#### `ses.clearHostResolverCache()`
|
||||
|
||||
Returns `Promise<void>` - Resolves when the operation is complete.
|
||||
|
||||
@@ -1,8 +0,0 @@
|
||||
# HIDDevice Object
|
||||
|
||||
* `deviceId` String - Unique identifier for the device.
|
||||
* `name` String - Name of the device.
|
||||
* `vendorId` Integer - The USB vendor ID.
|
||||
* `productId` Integer - The USB product ID.
|
||||
* `serialNumber` String (optional) - The USB device serial number.
|
||||
* `guid` String (optional) - Unique identifier for the HID interface. A device may have multiple HID interfaces.
|
||||
@@ -15,7 +15,7 @@ _This class is not exported from the `'electron'` module. It is only available a
|
||||
* `highlightedIndex` Integer - The index of the item the user touched.
|
||||
* `selectedStyle` String (optional) - Selected item style. Can be `background`, `outline` or `none`. Defaults to `none`.
|
||||
* `overlayStyle` String (optional) - Selected overlay item style. Can be `background`, `outline` or `none`. Defaults to `none`.
|
||||
* `showArrowButtons` Boolean (optional) - Whether to show arrow buttons. Defaults to `false` and is only shown if `items` is non-empty.
|
||||
* `showArrowButtons` Boolean (optional) - Defaults to `false`.
|
||||
* `mode` String (optional) - Can be `fixed` or `free`. The default is `free`.
|
||||
* `continuous` Boolean (optional) - Defaults to `true`.
|
||||
|
||||
|
||||
@@ -45,26 +45,6 @@ returns `null`.
|
||||
Returns `WebContents` | undefined - A WebContents instance with the given ID, or
|
||||
`undefined` if there is no WebContents associated with the given ID.
|
||||
|
||||
### `webContents.fromDevToolsTargetId(targetId)`
|
||||
|
||||
* `targetId` String - The Chrome DevTools Protocol [TargetID](https://chromedevtools.github.io/devtools-protocol/tot/Target/#type-TargetID) associated with the WebContents instance.
|
||||
|
||||
Returns `WebContents` | undefined - A WebContents instance with the given TargetID, or
|
||||
`undefined` if there is no WebContents associated with the given TargetID.
|
||||
|
||||
When communicating with the [Chrome DevTools Protocol](https://chromedevtools.github.io/devtools-protocol/),
|
||||
it can be useful to lookup a WebContents instance based on its assigned TargetID.
|
||||
|
||||
```js
|
||||
async function lookupTargetId (browserWindow) {
|
||||
const wc = browserWindow.webContents
|
||||
await wc.debugger.attach('1.3')
|
||||
const { targetInfo } = await wc.debugger.sendCommand('Target.getTargetInfo')
|
||||
const { targetId } = targetInfo
|
||||
const targetWebContents = await webContents.fromDevToolsTargetId(targetId)
|
||||
}
|
||||
```
|
||||
|
||||
## Class: WebContents
|
||||
|
||||
> Render and control the contents of a BrowserWindow instance.
|
||||
@@ -134,7 +114,7 @@ Returns:
|
||||
|
||||
* `event` Event
|
||||
|
||||
Emitted when the document in the top-level frame is loaded.
|
||||
Emitted when the document in the given frame is loaded.
|
||||
|
||||
#### Event: 'page-title-updated'
|
||||
|
||||
@@ -530,7 +510,6 @@ Returns:
|
||||
* `certificate` [Certificate](structures/certificate.md)
|
||||
* `callback` Function
|
||||
* `isTrusted` Boolean - Indicates whether the certificate can be considered trusted.
|
||||
* `isMainFrame` Boolean
|
||||
|
||||
Emitted when failed to verify the `certificate` for `url`.
|
||||
|
||||
@@ -651,7 +630,6 @@ Returns:
|
||||
* `params` Object
|
||||
* `x` Integer - x coordinate.
|
||||
* `y` Integer - y coordinate.
|
||||
* `frame` WebFrameMain - Frame from which the context menu was invoked.
|
||||
* `linkURL` String - URL of the link that encloses the node the context menu
|
||||
was invoked on.
|
||||
* `linkText` String - Text associated with the link. May be an empty
|
||||
@@ -736,8 +714,6 @@ first available device will be selected. `callback` should be called with
|
||||
`deviceId` to be selected, passing empty string to `callback` will
|
||||
cancel the request.
|
||||
|
||||
If no event listener is added for this event, all bluetooth requests will be cancelled.
|
||||
|
||||
```javascript
|
||||
const { app, BrowserWindow } = require('electron')
|
||||
|
||||
@@ -880,16 +856,6 @@ Emitted when the `WebContents` preferred size has changed.
|
||||
This event will only be emitted when `enablePreferredSizeMode` is set to `true`
|
||||
in `webPreferences`.
|
||||
|
||||
#### Event: 'frame-created'
|
||||
|
||||
Returns:
|
||||
|
||||
* `event` Event
|
||||
* `details` Object
|
||||
* `frame` WebFrameMain
|
||||
|
||||
Emitted when the [mainFrame](web-contents.md#contentsmainframe-readonly), an `<iframe>`, or a nested `<iframe>` is loaded within the page.
|
||||
|
||||
### Instance Methods
|
||||
|
||||
#### `contents.loadURL(url[, options])`
|
||||
@@ -1496,8 +1462,8 @@ win.loadURL('http://github.com')
|
||||
|
||||
win.webContents.on('did-finish-load', () => {
|
||||
// Use default printing options
|
||||
const pdfPath = path.join(os.homedir(), 'Desktop', 'temp.pdf')
|
||||
win.webContents.printToPDF({}).then(data => {
|
||||
const pdfPath = path.join(os.homedir(), 'Desktop', 'temp.pdf')
|
||||
fs.writeFile(pdfPath, data, (error) => {
|
||||
if (error) throw error
|
||||
console.log(`Wrote PDF successfully to ${pdfPath}`)
|
||||
@@ -1612,7 +1578,7 @@ app.whenReady().then(() => {
|
||||
|
||||
* `options` Object (optional)
|
||||
* `mode` String - Opens the devtools with specified dock state, can be
|
||||
`left`, `right`, `bottom`, `undocked`, `detach`. Defaults to last used dock state.
|
||||
`right`, `bottom`, `undocked`, `detach`. Defaults to last used dock state.
|
||||
In `undocked` mode it's possible to dock back. In `detach` mode it's not.
|
||||
* `activate` Boolean (optional) - Whether to bring the opened devtools window
|
||||
to the foreground. The default is `true`.
|
||||
@@ -1829,8 +1795,7 @@ End subscribing for frame presentation events.
|
||||
#### `contents.startDrag(item)`
|
||||
|
||||
* `item` Object
|
||||
* `file` String - The path to the file being dragged.
|
||||
* `files` String[] (optional) - The paths to the files being dragged. (`files` will override `file` field)
|
||||
* `file` String[] | String - The path(s) to the file(s) being dragged.
|
||||
* `icon` [NativeImage](native-image.md) | String - The image must be
|
||||
non-empty on macOS.
|
||||
|
||||
@@ -1840,7 +1805,7 @@ the cursor when dragging.
|
||||
|
||||
#### `contents.savePage(fullPath, saveType)`
|
||||
|
||||
* `fullPath` String - The absolute file path.
|
||||
* `fullPath` String - The full file path.
|
||||
* `saveType` String - Specify the save type.
|
||||
* `HTMLOnly` - Save only the HTML of the page.
|
||||
* `HTMLComplete` - Save complete-html page.
|
||||
@@ -2027,6 +1992,11 @@ when the DevTools has been closed.
|
||||
|
||||
A [`Debugger`](debugger.md) instance for this webContents.
|
||||
|
||||
[keyboardevent]: https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent
|
||||
[event-emitter]: https://nodejs.org/api/events.html#events_class_eventemitter
|
||||
[SCA]: https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Structured_clone_algorithm
|
||||
[`postMessage`]: https://developer.mozilla.org/en-US/docs/Web/API/Window/postMessage
|
||||
|
||||
#### `contents.backgroundThrottling`
|
||||
|
||||
A `Boolean` property that determines whether or not this WebContents will throttle animations and timers
|
||||
@@ -2035,8 +2005,3 @@ when the page becomes backgrounded. This also affects the Page Visibility API.
|
||||
#### `contents.mainFrame` _Readonly_
|
||||
|
||||
A [`WebFrameMain`](web-frame-main.md) property that represents the top frame of the page's frame hierarchy.
|
||||
|
||||
[keyboardevent]: https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent
|
||||
[event-emitter]: https://nodejs.org/api/events.html#events_class_eventemitter
|
||||
[SCA]: https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Structured_clone_algorithm
|
||||
[`postMessage`]: https://developer.mozilla.org/en-US/docs/Web/API/Window/postMessage
|
||||
|
||||
@@ -71,12 +71,6 @@ or `undefined` if there is no WebFrameMain associated with the given IDs.
|
||||
Process: [Main](../glossary.md#main-process)<br />
|
||||
_This class is not exported from the `'electron'` module. It is only available as a return value of other methods in the Electron API._
|
||||
|
||||
### Instance Events
|
||||
|
||||
#### Event: 'dom-ready'
|
||||
|
||||
Emitted when the document is loaded.
|
||||
|
||||
### Instance Methods
|
||||
|
||||
#### `frame.executeJavaScript(code[, userGesture])`
|
||||
|
||||
@@ -143,16 +143,12 @@ browser plugins. Plugins are disabled by default.
|
||||
### `preload`
|
||||
|
||||
```html
|
||||
<!-- from a file -->
|
||||
<webview src="https://www.github.com/" preload="./test.js"></webview>
|
||||
<!-- or if you want to load from an asar archive -->
|
||||
<webview src="https://www.github.com/" preload="./app.asar/test.js"></webview>
|
||||
```
|
||||
|
||||
A `String` that specifies a script that will be loaded before other scripts run in the guest
|
||||
page. The protocol of script's URL must be `file:` (even when using `asar:` archives) because
|
||||
it will be loaded by Node's `require` under the hood, which treats `asar:` archives as virtual
|
||||
directories.
|
||||
page. The protocol of script's URL must be either `file:` or `asar:`, because it
|
||||
will be loaded by `require` in guest page under the hood.
|
||||
|
||||
When the guest page doesn't have node integration this script will still have
|
||||
access to all Node APIs, but global objects injected by Node will be deleted
|
||||
@@ -610,21 +606,6 @@ listening to the `channel` event with the [`ipcRenderer`](ipc-renderer.md) modul
|
||||
See [webContents.send](web-contents.md#contentssendchannel-args) for
|
||||
examples.
|
||||
|
||||
### `<webview>.sendToFrame(frameId, channel, ...args)`
|
||||
|
||||
* `frameId` [number, number] - `[processId, frameId]`
|
||||
* `channel` String
|
||||
* `...args` any[]
|
||||
|
||||
Returns `Promise<void>`
|
||||
|
||||
Send an asynchronous message to renderer process via `channel`, you can also
|
||||
send arbitrary arguments. The renderer process can handle the message by
|
||||
listening to the `channel` event with the [`ipcRenderer`](ipc-renderer.md) module.
|
||||
|
||||
See [webContents.sendToFrame](web-contents.md#contentssendtoframeframeid-channel-args) for
|
||||
examples.
|
||||
|
||||
### `<webview>.sendInputEvent(event)`
|
||||
|
||||
* `event` [MouseInputEvent](structures/mouse-input-event.md) | [MouseWheelInputEvent](structures/mouse-wheel-input-event.md) | [KeyboardInputEvent](structures/keyboard-input-event.md)
|
||||
@@ -866,19 +847,6 @@ Returns:
|
||||
Emitted when any frame (including main) starts navigating. `isInPlace` will be
|
||||
`true` for in-page navigations.
|
||||
|
||||
### Event: 'did-redirect-navigation'
|
||||
|
||||
Returns:
|
||||
|
||||
* `url` String
|
||||
* `isInPlace` Boolean
|
||||
* `isMainFrame` Boolean
|
||||
* `frameProcessId` Integer
|
||||
* `frameRoutingId` Integer
|
||||
|
||||
Emitted after a server side redirect occurs during navigation. For example a 302
|
||||
redirect.
|
||||
|
||||
### Event: 'did-navigate'
|
||||
|
||||
Returns:
|
||||
@@ -939,7 +907,6 @@ webview.addEventListener('close', () => {
|
||||
|
||||
Returns:
|
||||
|
||||
* `frameId` [number, number] - pair of `[processId, frameId]`.
|
||||
* `channel` String
|
||||
* `args` any[]
|
||||
|
||||
@@ -1025,78 +992,3 @@ 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
|
||||
[chrome-webview]: https://developer.chrome.com/docs/extensions/reference/webviewTag/
|
||||
|
||||
### Event: 'context-menu'
|
||||
|
||||
Returns:
|
||||
|
||||
* `params` Object
|
||||
* `x` Integer - x coordinate.
|
||||
* `y` Integer - y coordinate.
|
||||
* `linkURL` String - URL of the link that encloses the node the context menu
|
||||
was invoked on.
|
||||
* `linkText` String - Text associated with the link. May be an empty
|
||||
string if the contents of the link are an image.
|
||||
* `pageURL` String - URL of the top level page that the context menu was
|
||||
invoked on.
|
||||
* `frameURL` String - URL of the subframe that the context menu was invoked
|
||||
on.
|
||||
* `srcURL` String - Source URL for the element that the context menu
|
||||
was invoked on. Elements with source URLs are images, audio and video.
|
||||
* `mediaType` String - Type of the node the context menu was invoked on. Can
|
||||
be `none`, `image`, `audio`, `video`, `canvas`, `file` or `plugin`.
|
||||
* `hasImageContents` Boolean - Whether the context menu was invoked on an image
|
||||
which has non-empty contents.
|
||||
* `isEditable` Boolean - Whether the context is editable.
|
||||
* `selectionText` String - Text of the selection that the context menu was
|
||||
invoked on.
|
||||
* `titleText` String - Title text of the selection that the context menu was
|
||||
invoked on.
|
||||
* `altText` String - Alt text of the selection that the context menu was
|
||||
invoked on.
|
||||
* `suggestedFilename` String - Suggested filename to be used when saving file through 'Save
|
||||
Link As' option of context menu.
|
||||
* `selectionRect` [Rectangle](structures/rectangle.md) - Rect representing the coordinates in the document space of the selection.
|
||||
* `selectionStartOffset` Number - Start position of the selection text.
|
||||
* `referrerPolicy` [Referrer](structures/referrer.md) - The referrer policy of the frame on which the menu is invoked.
|
||||
* `misspelledWord` String - The misspelled word under the cursor, if any.
|
||||
* `dictionarySuggestions` String[] - An array of suggested words to show the
|
||||
user to replace the `misspelledWord`. Only available if there is a misspelled
|
||||
word and spellchecker is enabled.
|
||||
* `frameCharset` String - The character encoding of the frame on which the
|
||||
menu was invoked.
|
||||
* `inputFieldType` String - If the context menu was invoked on an input
|
||||
field, the type of that field. Possible values are `none`, `plainText`,
|
||||
`password`, `other`.
|
||||
* `spellcheckEnabled` Boolean - If the context is editable, whether or not spellchecking is enabled.
|
||||
* `menuSourceType` String - Input source that invoked the context menu.
|
||||
Can be `none`, `mouse`, `keyboard`, `touch`, `touchMenu`, `longPress`, `longTap`, `touchHandle`, `stylus`, `adjustSelection`, or `adjustSelectionReset`.
|
||||
* `mediaFlags` Object - The flags for the media element the context menu was
|
||||
invoked on.
|
||||
* `inError` Boolean - Whether the media element has crashed.
|
||||
* `isPaused` Boolean - Whether the media element is paused.
|
||||
* `isMuted` Boolean - Whether the media element is muted.
|
||||
* `hasAudio` Boolean - Whether the media element has audio.
|
||||
* `isLooping` Boolean - Whether the media element is looping.
|
||||
* `isControlsVisible` Boolean - Whether the media element's controls are
|
||||
visible.
|
||||
* `canToggleControls` Boolean - Whether the media element's controls are
|
||||
toggleable.
|
||||
* `canPrint` Boolean - Whether the media element can be printed.
|
||||
* `canSave` Boolean - Whether or not the media element can be downloaded.
|
||||
* `canShowPictureInPicture` Boolean - Whether the media element can show picture-in-picture.
|
||||
* `isShowingPictureInPicture` Boolean - Whether the media element is currently showing picture-in-picture.
|
||||
* `canRotate` Boolean - Whether the media element can be rotated.
|
||||
* `canLoop` Boolean - Whether the media element can be looped.
|
||||
* `editFlags` Object - These flags indicate whether the renderer believes it
|
||||
is able to perform the corresponding action.
|
||||
* `canUndo` Boolean - Whether the renderer believes it can undo.
|
||||
* `canRedo` Boolean - Whether the renderer believes it can redo.
|
||||
* `canCut` Boolean - Whether the renderer believes it can cut.
|
||||
* `canCopy` Boolean - Whether the renderer believes it can copy.
|
||||
* `canPaste` Boolean - Whether the renderer believes it can paste.
|
||||
* `canDelete` Boolean - Whether the renderer believes it can delete.
|
||||
* `canSelectAll` Boolean - Whether the renderer believes it can select all.
|
||||
* `canEditRichly` Boolean - Whether the renderer believes it can edit text richly.
|
||||
|
||||
Emitted when there is a new context menu that needs to be handled.
|
||||
|
||||
@@ -64,9 +64,6 @@ window.open('https://github.com', '_blank', 'top=500,left=200,frame=false,nodeIn
|
||||
`features` will be passed to any registered `webContents`'s
|
||||
`did-create-window` event handler in the `options` argument.
|
||||
* `frameName` follows the specification of `windowName` located in the [native documentation](https://developer.mozilla.org/en-US/docs/Web/API/Window/open#parameters).
|
||||
* When opening `about:blank`, the child window's `WebPreferences` will be copied
|
||||
from the parent window, and there is no way to override it because Chromium
|
||||
skips browser side navigation in this case.
|
||||
|
||||
To customize or cancel the creation of the window, you can optionally set an
|
||||
override handler with `webContents.setWindowOpenHandler()` from the main
|
||||
|
||||
@@ -12,39 +12,23 @@ This document uses the following convention to categorize breaking changes:
|
||||
* **Deprecated:** An API was marked as deprecated. The API will continue to function, but will emit a deprecation warning, and will be removed in a future release.
|
||||
* **Removed:** An API or feature was removed, and is no longer supported by Electron.
|
||||
|
||||
## Planned Breaking API Changes (15.0)
|
||||
## Planned Breaking API Changes (16.0)
|
||||
|
||||
### Default Changed: `nativeWindowOpen` defaults to `true`
|
||||
### Behavior Changed: `crashReporter` implementation switched to Crashpad on Linux
|
||||
|
||||
Prior to Electron 15, `window.open` was by default shimmed to use
|
||||
`BrowserWindowProxy`. This meant that `window.open('about:blank')` did not work
|
||||
to open synchronously scriptable child windows, among other incompatibilities.
|
||||
`nativeWindowOpen` is no longer experimental, and is now the default.
|
||||
The underlying implementation of the `crashReporter` API on Linux has changed
|
||||
from Breakpad to Crashpad, bringing it in line with Windows and Mac. As a
|
||||
result of this, child processes are now automatically monitored, and calling
|
||||
`process.crashReporter.start` in Node child processes is no longer needed (and
|
||||
is not advisable, as it will start a second instance of the Crashpad reporter).
|
||||
|
||||
See the documentation for [window.open in Electron](api/window-open.md)
|
||||
for more details.
|
||||
There are also some subtle changes to how annotations will be reported on
|
||||
Linux, including that long values will no longer be split between annotations
|
||||
appended with `__1`, `__2` and so on, and instead will be truncated at the
|
||||
(new, longer) annotation value limit.
|
||||
|
||||
## Planned Breaking API Changes (14.0)
|
||||
|
||||
### Removed: `remote` module
|
||||
|
||||
The `remote` module was deprecated in Electron 12, and will be removed in
|
||||
Electron 14. It is replaced by the
|
||||
[`@electron/remote`](https://github.com/electron/remote) module.
|
||||
|
||||
```js
|
||||
// Deprecated in Electron 12:
|
||||
const { BrowserWindow } = require('electron').remote
|
||||
```
|
||||
|
||||
```js
|
||||
// Replace with:
|
||||
const { BrowserWindow } = require('@electron/remote')
|
||||
|
||||
// In the main process:
|
||||
require('@electron/remote/main').initialize()
|
||||
```
|
||||
|
||||
### Removed: `app.allowRendererProcessReuse`
|
||||
|
||||
The `app.allowRendererProcessReuse` property will be removed as part of our plan to
|
||||
@@ -74,6 +58,16 @@ ensure your code works with this property enabled. It has been enabled by defau
|
||||
|
||||
You will be affected by this change if you use either `webFrame.executeJavaScript` or `webFrame.executeJavaScriptInIsolatedWorld`. You will need to ensure that values returned by either of those methods are supported by the [Context Bridge API](api/context-bridge.md#parameter--error--return-type-support) as these methods use the same value passing semantics.
|
||||
|
||||
### Default Changed: `nativeWindowOpen` defaults to `true`
|
||||
|
||||
Prior to Electron 14, `window.open` was by default shimmed to use
|
||||
`BrowserWindowProxy`. This meant that `window.open('about:blank')` did not work
|
||||
to open synchronously scriptable child windows, among other incompatibilities.
|
||||
`nativeWindowOpen` is no longer experimental, and is now the default.
|
||||
|
||||
See the documentation for [window.open in Electron](api/window-open.md)
|
||||
for more details.
|
||||
|
||||
### Removed: BrowserWindowConstructorOptions inheriting from parent windows
|
||||
|
||||
Prior to Electron 14, windows opened with `window.open` would inherit
|
||||
@@ -577,7 +571,7 @@ error.
|
||||
### API Changed: `shell.openItem` is now `shell.openPath`
|
||||
|
||||
The `shell.openItem` API has been replaced with an asynchronous `shell.openPath` API.
|
||||
You can see the original API proposal and reasoning [here](https://github.com/electron/governance/blob/main/wg-api/spec-documents/shell-openitem.md).
|
||||
You can see the original API proposal and reasoning [here](https://github.com/electron/governance/blob/master/wg-api/spec-documents/shell-openitem.md).
|
||||
|
||||
## Planned Breaking API Changes (8.0)
|
||||
|
||||
|
||||
@@ -4,8 +4,8 @@ These guides are intended for people working on the Electron project itself.
|
||||
For guides on Electron app development, see
|
||||
[/docs/README.md](../README.md#guides-and-tutorials).
|
||||
|
||||
* [Code of Conduct](https://github.com/electron/electron/blob/main/CODE_OF_CONDUCT.md)
|
||||
* [Contributing to Electron](https://github.com/electron/electron/blob/main/CONTRIBUTING.md)
|
||||
* [Code of Conduct](https://github.com/electron/electron/blob/master/CODE_OF_CONDUCT.md)
|
||||
* [Contributing to Electron](https://github.com/electron/electron/blob/master/CONTRIBUTING.md)
|
||||
* [Issues](issues.md)
|
||||
* [Pull Requests](pull-requests.md)
|
||||
* [Documentation Styleguide](coding-style.md#documentation)
|
||||
|
||||
@@ -8,7 +8,7 @@ Example Use Case:
|
||||
* We need `VS15.9` and we have `VS15.7` installed; this would require us to update an Azure image.
|
||||
|
||||
1. Identify the image you wish to modify.
|
||||
* In [appveyor.yml](https://github.com/electron/electron/blob/main/appveyor.yml), the image is identified by the property *image*.
|
||||
* In [appveyor.yml](https://github.com/electron/electron/blob/master/appveyor.yml), the image is identified by the property *image*.
|
||||
* The names used correspond to the *"images"* defined for a build cloud, eg the [libcc-20 cloud](https://windows-ci.electronjs.org/build-clouds/8).
|
||||
* Find the image you wish to modify in the build cloud and make note of the **VHD Blob Path** for that image, which is the value for that corresponding key.
|
||||
* You will need this URI path to copy into a new image.
|
||||
|
||||
@@ -65,8 +65,8 @@ origin URLs.
|
||||
$ cd src/electron
|
||||
$ git remote remove origin
|
||||
$ git remote add origin https://github.com/electron/electron
|
||||
$ git checkout main
|
||||
$ git branch --set-upstream-to=origin/main
|
||||
$ git checkout master
|
||||
$ git branch --set-upstream-to=origin/master
|
||||
$ cd -
|
||||
```
|
||||
|
||||
|
||||
@@ -26,9 +26,7 @@ you prefer a graphical interface.
|
||||
* **.lldbinit**: Create or edit `~/.lldbinit` to allow Chromium code to be properly source-mapped.
|
||||
|
||||
```text
|
||||
# e.g: ['~/electron/src/tools/lldb']
|
||||
script sys.path[:0] = ['<...path/to/electron/src/tools/lldb>']
|
||||
script import lldbinit
|
||||
command script import ~/electron/src/tools/lldb/lldbinit.py
|
||||
```
|
||||
|
||||
## Attaching to and Debugging Electron
|
||||
|
||||
@@ -72,4 +72,4 @@ to try NW.js.
|
||||
|
||||
[nwjs]: https://nwjs.io/
|
||||
[electron-modules]: https://www.npmjs.com/search?q=electron
|
||||
[node-bindings]: https://github.com/electron/electron/tree/main/lib/common
|
||||
[node-bindings]: https://github.com/electron/electron/tree/master/lib/common
|
||||
|
||||
@@ -45,10 +45,10 @@ Once you've built the project locally, you're ready to start making changes!
|
||||
### Step 3: Branch
|
||||
|
||||
To keep your development environment organized, create local branches to
|
||||
hold your work. These should be branched directly off of the `main` branch.
|
||||
hold your work. These should be branched directly off of the `master` branch.
|
||||
|
||||
```sh
|
||||
$ git checkout -b my-branch -t upstream/main
|
||||
$ git checkout -b my-branch -t upstream/master
|
||||
```
|
||||
|
||||
## Making Changes
|
||||
@@ -134,11 +134,11 @@ Once you have committed your changes, it is a good idea to use `git rebase`
|
||||
|
||||
```sh
|
||||
$ git fetch upstream
|
||||
$ git rebase upstream/main
|
||||
$ git rebase upstream/master
|
||||
```
|
||||
|
||||
This ensures that your working branch has the latest changes from `electron/electron`
|
||||
main.
|
||||
master.
|
||||
|
||||
### Step 7: Test
|
||||
|
||||
@@ -189,7 +189,7 @@ the requirements below.
|
||||
|
||||
Bug fixes and new features should include tests and possibly benchmarks.
|
||||
|
||||
Contributors guide: https://github.com/electron/electron/blob/main/CONTRIBUTING.md
|
||||
Contributors guide: https://github.com/electron/electron/blob/master/CONTRIBUTING.md
|
||||
-->
|
||||
```
|
||||
|
||||
@@ -222,7 +222,7 @@ seem unfamiliar, refer to this
|
||||
#### Approval and Request Changes Workflow
|
||||
|
||||
All pull requests require approval from a
|
||||
[Code Owner](https://github.com/electron/electron/blob/main/.github/CODEOWNERS)
|
||||
[Code Owner](https://github.com/electron/electron/blob/master/.github/CODEOWNERS)
|
||||
of the area you modified in order to land. Whenever a maintainer reviews a pull
|
||||
request they may request changes. These may be small, such as fixing a typo, or
|
||||
may involve substantive changes. Such requests are intended to be helpful, but
|
||||
|
||||
@@ -43,9 +43,8 @@ SRV*c:\code\symbols\*https://msdl.microsoft.com/download/symbols;SRV*c:\code\sym
|
||||
|
||||
## Using the symbol server in Visual Studio
|
||||
|
||||

|
||||
|
||||

|
||||

|
||||

|
||||
|
||||
## Troubleshooting: Symbols will not load
|
||||
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta http-equiv="Content-Security-Policy" content="default-src 'self'; script-src 'self'">
|
||||
<title>Web Bluetooth API</title>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Web Bluetooth API</h1>
|
||||
|
||||
<button id="clickme">Test Bluetooth</button>
|
||||
|
||||
<p>Currently selected bluetooth device: <strong id="device-name""></strong></p>
|
||||
|
||||
<script src="./renderer.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,30 +0,0 @@
|
||||
const {app, BrowserWindow} = require('electron')
|
||||
const path = require('path')
|
||||
|
||||
function createWindow () {
|
||||
const mainWindow = new BrowserWindow({
|
||||
width: 800,
|
||||
height: 600
|
||||
})
|
||||
|
||||
mainWindow.webContents.on('select-bluetooth-device', (event, deviceList, callback) => {
|
||||
event.preventDefault()
|
||||
if (deviceList && deviceList.length > 0) {
|
||||
callback(deviceList[0].deviceId)
|
||||
}
|
||||
})
|
||||
|
||||
mainWindow.loadFile('index.html')
|
||||
}
|
||||
|
||||
app.whenReady().then(() => {
|
||||
createWindow()
|
||||
|
||||
app.on('activate', function () {
|
||||
if (BrowserWindow.getAllWindows().length === 0) createWindow()
|
||||
})
|
||||
})
|
||||
|
||||
app.on('window-all-closed', function () {
|
||||
if (process.platform !== 'darwin') app.quit()
|
||||
})
|
||||
@@ -1,8 +0,0 @@
|
||||
async function testIt() {
|
||||
const device = await navigator.bluetooth.requestDevice({
|
||||
acceptAllDevices: true
|
||||
})
|
||||
document.getElementById('device-name').innerHTML = device.name || `ID: ${device.id}`
|
||||
}
|
||||
|
||||
document.getElementById('clickme').addEventListener('click',testIt)
|
||||
@@ -1,21 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta http-equiv="Content-Security-Policy" content="default-src 'self'; script-src 'self'">
|
||||
<title>WebHID API</title>
|
||||
</head>
|
||||
<body>
|
||||
<h1>WebHID API</h1>
|
||||
|
||||
<button id="clickme">Test WebHID</button>
|
||||
|
||||
<h3>HID devices automatically granted access via <i>setDevicePermissionHandler</i></h3>
|
||||
<div id="granted-devices"></div>
|
||||
|
||||
<h3>HID devices automatically granted access via <i>select-hid-device</i></h3>
|
||||
<div id="granted-devices2"></div>
|
||||
|
||||
<script src="./renderer.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,50 +0,0 @@
|
||||
const {app, BrowserWindow} = require('electron')
|
||||
const path = require('path')
|
||||
|
||||
function createWindow () {
|
||||
const mainWindow = new BrowserWindow({
|
||||
width: 800,
|
||||
height: 600
|
||||
})
|
||||
|
||||
mainWindow.webContents.session.on('select-hid-device', (event, details, callback) => {
|
||||
event.preventDefault()
|
||||
if (details.deviceList && details.deviceList.length > 0) {
|
||||
callback(details.deviceList[0].deviceId)
|
||||
}
|
||||
})
|
||||
|
||||
mainWindow.webContents.session.on('hid-device-added', (event, device) => {
|
||||
console.log('hid-device-added FIRED WITH', device)
|
||||
})
|
||||
|
||||
mainWindow.webContents.session.on('hid-device-removed', (event, device) => {
|
||||
console.log('hid-device-removed FIRED WITH', device)
|
||||
})
|
||||
|
||||
mainWindow.webContents.session.setPermissionCheckHandler((webContents, permission, requestingOrigin, details) => {
|
||||
if (permission === 'hid' && details.securityOrigin === 'file:///') {
|
||||
return true
|
||||
}
|
||||
})
|
||||
|
||||
mainWindow.webContents.session.setDevicePermissionHandler((details) => {
|
||||
if (details.deviceType === 'hid' && details.origin === 'file://') {
|
||||
return true
|
||||
}
|
||||
})
|
||||
|
||||
mainWindow.loadFile('index.html')
|
||||
}
|
||||
|
||||
app.whenReady().then(() => {
|
||||
createWindow()
|
||||
|
||||
app.on('activate', function () {
|
||||
if (BrowserWindow.getAllWindows().length === 0) createWindow()
|
||||
})
|
||||
})
|
||||
|
||||
app.on('window-all-closed', function () {
|
||||
if (process.platform !== 'darwin') app.quit()
|
||||
})
|
||||
@@ -1,19 +0,0 @@
|
||||
async function testIt() {
|
||||
const grantedDevices = await navigator.hid.getDevices()
|
||||
let grantedDeviceList = ''
|
||||
grantedDevices.forEach(device => {
|
||||
grantedDeviceList += `<hr>${device.productName}</hr>`
|
||||
})
|
||||
document.getElementById('granted-devices').innerHTML = grantedDeviceList
|
||||
const grantedDevices2 = await navigator.hid.requestDevice({
|
||||
filters: []
|
||||
})
|
||||
|
||||
grantedDeviceList = ''
|
||||
grantedDevices2.forEach(device => {
|
||||
grantedDeviceList += `<hr>${device.productName}</hr>`
|
||||
})
|
||||
document.getElementById('granted-devices2').innerHTML = grantedDeviceList
|
||||
}
|
||||
|
||||
document.getElementById('clickme').addEventListener('click',testIt)
|
||||
@@ -1,16 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta http-equiv="Content-Security-Policy" content="default-src 'self'; script-src 'self'">
|
||||
<title>Web Serial API</title>
|
||||
<body>
|
||||
<h1>Web Serial API</h1>
|
||||
|
||||
<button id="clickme">Test Web Serial API</button>
|
||||
|
||||
<p>Matching Arduino Uno device: <strong id="device-name""></strong></p>
|
||||
|
||||
<script src="./renderer.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,54 +0,0 @@
|
||||
const {app, BrowserWindow} = require('electron')
|
||||
const path = require('path')
|
||||
|
||||
function createWindow () {
|
||||
const mainWindow = new BrowserWindow({
|
||||
width: 800,
|
||||
height: 600
|
||||
})
|
||||
|
||||
mainWindow.webContents.session.on('select-serial-port', (event, portList, webContents, callback) => {
|
||||
event.preventDefault()
|
||||
if (portList && portList.length > 0) {
|
||||
callback(portList[0].portId)
|
||||
} else {
|
||||
callback('') //Could not find any matching devices
|
||||
}
|
||||
})
|
||||
|
||||
mainWindow.webContents.session.on('serial-port-added', (event, port) => {
|
||||
console.log('serial-port-added FIRED WITH', port)
|
||||
})
|
||||
|
||||
mainWindow.webContents.session.on('serial-port-removed', (event, port) => {
|
||||
console.log('serial-port-removed FIRED WITH', port)
|
||||
})
|
||||
|
||||
mainWindow.webContents.session.setPermissionCheckHandler((webContents, permission, requestingOrigin, details) => {
|
||||
if (permission === 'serial' && details.securityOrigin === 'file:///') {
|
||||
return true
|
||||
}
|
||||
})
|
||||
|
||||
mainWindow.webContents.session.setDevicePermissionHandler((details) => {
|
||||
if (details.deviceType === 'serial' && details.origin === 'file://') {
|
||||
return true
|
||||
}
|
||||
})
|
||||
|
||||
mainWindow.loadFile('index.html')
|
||||
|
||||
mainWindow.webContents.openDevTools()
|
||||
}
|
||||
|
||||
app.whenReady().then(() => {
|
||||
createWindow()
|
||||
|
||||
app.on('activate', function () {
|
||||
if (BrowserWindow.getAllWindows().length === 0) createWindow()
|
||||
})
|
||||
})
|
||||
|
||||
app.on('window-all-closed', function () {
|
||||
if (process.platform !== 'darwin') app.quit()
|
||||
})
|
||||
@@ -1,19 +0,0 @@
|
||||
async function testIt() {
|
||||
const filters = [
|
||||
{ usbVendorId: 0x2341, usbProductId: 0x0043 },
|
||||
{ usbVendorId: 0x2341, usbProductId: 0x0001 }
|
||||
];
|
||||
try {
|
||||
const port = await navigator.serial.requestPort({filters});
|
||||
const portInfo = port.getInfo();
|
||||
document.getElementById('device-name').innerHTML = `vendorId: ${portInfo.usbVendorId} | productId: ${portInfo.usbProductId} `
|
||||
} catch (ex) {
|
||||
if (ex.name === 'NotFoundError') {
|
||||
document.getElementById('device-name').innerHTML = 'Device NOT found'
|
||||
} else {
|
||||
document.getElementById('device-name').innerHTML = ex
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
document.getElementById('clickme').addEventListener('click',testIt)
|
||||
@@ -1,5 +1,5 @@
|
||||
// Modules to control application life and create native browser window
|
||||
const { app, BrowserWindow, ipcMain, shell, dialog } = require('electron')
|
||||
const { app, BrowserWindow, ipcMain, shell } = require('electron')
|
||||
const path = require('path')
|
||||
|
||||
let mainWindow;
|
||||
|
||||
@@ -59,9 +59,8 @@
|
||||
|
||||
<p>
|
||||
For more details, see the
|
||||
<a href="https://electronjs.org/docs/tutorial/window-customization/">
|
||||
Window Customization
|
||||
|
||||
<a href="https://electronjs.org/docs/api/frameless-window/">
|
||||
Frameless Window
|
||||
</a>
|
||||
documentation.
|
||||
</p>
|
||||
|
||||
118
docs/glossary.md
118
docs/glossary.md
@@ -4,39 +4,15 @@ This page defines some terminology that is commonly used in Electron development
|
||||
|
||||
### ASAR
|
||||
|
||||
ASAR stands for Atom Shell Archive Format. An [asar] archive is a simple
|
||||
ASAR stands for Atom Shell Archive Format. An [asar][asar] archive is a simple
|
||||
`tar`-like format that concatenates files into a single file. Electron can read
|
||||
arbitrary files from it without unpacking the whole file.
|
||||
|
||||
The ASAR format was created primarily to improve performance on Windows when
|
||||
reading large quantities of small files (e.g. when loading your app's JavaScript
|
||||
dependency tree from `node_modules`).
|
||||
|
||||
### code signing
|
||||
|
||||
Code signing is a process where an app developer digitally signs their code to
|
||||
ensure that it hasn't been tampered with after packaging. Both Windows and
|
||||
macOS implement their own version of code signing. As a desktop app developer,
|
||||
it's important that you sign your code if you plan on distributing it to the
|
||||
general public.
|
||||
|
||||
For more information, read the [Code Signing] tutorial.
|
||||
|
||||
### context isolation
|
||||
|
||||
Context isolation is a security measure in Electron that ensures that your
|
||||
preload script cannot leak privileged Electron or Node.js APIs to the web
|
||||
contents in your renderer process. With context isolation enabled, the
|
||||
only way to expose APIs from your preload script is through the
|
||||
`contextBridge` API.
|
||||
|
||||
For more information, read the [Context Isolation] tutorial.
|
||||
|
||||
See also: [preload script](#preload-script), [renderer process](#renderer-process)
|
||||
The ASAR format was created primarily to improve performance on Windows... TODO
|
||||
|
||||
### CRT
|
||||
|
||||
The C Runtime Library (CRT) is the part of the C++ Standard Library that
|
||||
The C Run-time Library (CRT) is the part of the C++ Standard Library that
|
||||
incorporates the ISO C99 standard library. The Visual C++ libraries that
|
||||
implement the CRT support native code development, and both mixed native and
|
||||
managed code, and pure managed code for .NET development.
|
||||
@@ -44,7 +20,8 @@ managed code, and pure managed code for .NET development.
|
||||
### DMG
|
||||
|
||||
An Apple Disk Image is a packaging format used by macOS. DMG files are
|
||||
commonly used for distributing application "installers".
|
||||
commonly used for distributing application "installers". [electron-builder]
|
||||
supports `dmg` as a build target.
|
||||
|
||||
### IME
|
||||
|
||||
@@ -54,15 +31,19 @@ keyboards to input Chinese, Japanese, Korean and Indic characters.
|
||||
|
||||
### IDL
|
||||
|
||||
Interface description language. Write function signatures and data types in a
|
||||
format that can be used to generate interfaces in Java, C++, JavaScript, etc.
|
||||
Interface description language. Write function signatures and data types in a format that can be used to generate interfaces in Java, C++, JavaScript, etc.
|
||||
|
||||
### IPC
|
||||
|
||||
IPC stands for inter-process communication. Electron uses IPC to send
|
||||
serialized JSON messages between the main and renderer processes.
|
||||
IPC stands for Inter-Process Communication. Electron uses IPC to send
|
||||
serialized JSON messages between the [main] and [renderer] processes.
|
||||
|
||||
see also: [main process](#main-process), [renderer process](#renderer-process)
|
||||
### libchromiumcontent
|
||||
|
||||
A shared library that includes the [Chromium Content module] and all its
|
||||
dependencies (e.g., Blink, [V8], etc.). Also referred to as "libcc".
|
||||
|
||||
- [github.com/electron/libchromiumcontent](https://github.com/electron/libchromiumcontent)
|
||||
|
||||
### main process
|
||||
|
||||
@@ -87,22 +68,10 @@ MAS, see the [Mac App Store Submission Guide].
|
||||
|
||||
### Mojo
|
||||
|
||||
An IPC system for communicating intra- or inter-process, and that's important
|
||||
because Chrome is keen on being able to split its work into separate processes
|
||||
or not, depending on memory pressures etc.
|
||||
An IPC system for communicating intra- or inter-process, and that's important because Chrome is keen on being able to split its work into separate processes or not, depending on memory pressures etc.
|
||||
|
||||
See https://chromium.googlesource.com/chromium/src/+/master/mojo/README.md
|
||||
|
||||
See also: [IPC](#ipc)
|
||||
|
||||
### MSI
|
||||
|
||||
On Windows, MSI packages are used by the Windows Installer
|
||||
(also known as Microsoft Installer) service to install and configure
|
||||
applications.
|
||||
|
||||
More information can be found in [Microsoft's documentation][msi].
|
||||
|
||||
### native modules
|
||||
|
||||
Native modules (also called [addons] in
|
||||
@@ -116,33 +85,22 @@ likely to use a different V8 version from the Node binary installed in your
|
||||
system, you have to manually specify the location of Electron’s headers when
|
||||
building native modules.
|
||||
|
||||
For more information, read the [Native Node Modules] tutorial.
|
||||
See also [Using Native Node Modules].
|
||||
|
||||
### notarization
|
||||
### NSIS
|
||||
|
||||
Notarization is a macOS-specific process where a developer can send a
|
||||
code-signed app to Apple servers to get verified for malicious
|
||||
components through an automated service.
|
||||
|
||||
See also: [code signing](#code-signing)
|
||||
Nullsoft Scriptable Install System is a script-driven Installer
|
||||
authoring tool for Microsoft Windows. It is released under a combination of
|
||||
free software licenses, and is a widely-used alternative to commercial
|
||||
proprietary products like InstallShield. [electron-builder] supports NSIS
|
||||
as a build target.
|
||||
|
||||
### OSR
|
||||
|
||||
OSR (offscreen rendering) can be used for loading heavy page in
|
||||
OSR (Off-screen rendering) can be used for loading heavy page in
|
||||
background and then displaying it after (it will be much faster).
|
||||
It allows you to render page without showing it on screen.
|
||||
|
||||
For more information, read the [Offscreen Rendering][osr] tutorial.
|
||||
|
||||
### preload script
|
||||
|
||||
Preload scripts contain code that executes in a renderer process
|
||||
before its web contents begin loading. These scripts run within
|
||||
the renderer context, but are granted more privileges by having
|
||||
access to Node.js APIs.
|
||||
|
||||
See also: [renderer process](#renderer-process), [context isolation](#context-isolation)
|
||||
|
||||
### process
|
||||
|
||||
A process is an instance of a computer program that is being executed. Electron
|
||||
@@ -162,17 +120,13 @@ The renderer process is a browser window in your app. Unlike the main process,
|
||||
there can be multiple of these and each is run in a separate process.
|
||||
They can also be hidden.
|
||||
|
||||
In normal browsers, web pages usually run in a sandboxed environment and are not
|
||||
allowed access to native resources. Electron users, however, have the power to
|
||||
use Node.js APIs in web pages allowing lower level operating system
|
||||
interactions.
|
||||
|
||||
See also: [process](#process), [main process](#main-process)
|
||||
|
||||
### sandbox
|
||||
|
||||
The sandbox is a security feature inherited from Chromium that restricts
|
||||
your renderer processes to a limited set of permissions.
|
||||
|
||||
For more information, read the [Process Sandboxing] tutorial.
|
||||
|
||||
See also: [process](#process)
|
||||
|
||||
### Squirrel
|
||||
|
||||
Squirrel is an open-source framework that enables Electron apps to update
|
||||
@@ -220,15 +174,13 @@ embedded content.
|
||||
|
||||
[addons]: https://nodejs.org/api/addons.html
|
||||
[asar]: https://github.com/electron/asar
|
||||
[autoupdater]: api/auto-updater.md
|
||||
[code signing]: tutorial/code-signing.md
|
||||
[context isolation]: tutorial/context-isolation.md
|
||||
[mac app store submission guide]: tutorial/mac-app-store-submission-guide.md
|
||||
[autoUpdater]: api/auto-updater.md
|
||||
[Chromium Content module]: https://www.chromium.org/developers/content-module
|
||||
[electron-builder]: https://github.com/electron-userland/electron-builder
|
||||
[libchromiumcontent]: #libchromiumcontent
|
||||
[Mac App Store Submission Guide]: tutorial/mac-app-store-submission-guide.md
|
||||
[main]: #main-process
|
||||
[msi]: https://docs.microsoft.com/en-us/windows/win32/msi/windows-installer-portal
|
||||
[offscreen rendering]: tutorial/offscreen-rendering.md
|
||||
[process sandboxing]: tutorial/sandbox.md
|
||||
[renderer]: #renderer-process
|
||||
[userland]: #userland
|
||||
[using native node modules]: tutorial/using-native-node-modules.md
|
||||
[v8]: #v8
|
||||
[Using Native Node Modules]: tutorial/using-native-node-modules.md
|
||||
[V8]: #v8
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 32 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 15 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 19 KiB |
@@ -1,7 +1,48 @@
|
||||
# Accessibility
|
||||
|
||||
Making accessible applications is important and we're happy to provide
|
||||
functionality to [Devtron][devtron] and [Spectron][spectron] that gives
|
||||
developers the opportunity to make their apps better for everyone.
|
||||
|
||||
---
|
||||
|
||||
Accessibility concerns in Electron applications are similar to those of
|
||||
websites because they're both ultimately HTML.
|
||||
websites because they're both ultimately HTML. With Electron apps, however,
|
||||
you can't use the online resources for accessibility audits because your app
|
||||
doesn't have a URL to point the auditor to.
|
||||
|
||||
These features bring those auditing tools to your Electron app. You can
|
||||
choose to add audits to your tests with Spectron or use them within DevTools
|
||||
with Devtron. Read on for a summary of the tools.
|
||||
|
||||
## Spectron
|
||||
|
||||
In the testing framework Spectron, you can now audit each window and `<webview>`
|
||||
tag in your application. For example:
|
||||
|
||||
```javascript
|
||||
app.client.auditAccessibility().then((audit) => {
|
||||
if (audit.failed) {
|
||||
console.error(audit.message)
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
You can read more about this feature in [Spectron's documentation][spectron-a11y].
|
||||
|
||||
## Devtron
|
||||
|
||||
In Devtron, there is an accessibility tab which will allow you to audit a
|
||||
page in your app, sort and filter the results.
|
||||
|
||||
![devtron screenshot][devtron-screenshot]
|
||||
|
||||
Both of these tools are using the [Accessibility Developer Tools][a11y-devtools]
|
||||
library built by Google for Chrome. You can learn more about the accessibility
|
||||
audit rules this library uses on that [repository's wiki][a11y-devtools-wiki].
|
||||
|
||||
If you know of other great accessibility tools for Electron, add them to the
|
||||
accessibility documentation with a pull request.
|
||||
|
||||
## Manually enabling accessibility features
|
||||
|
||||
@@ -43,6 +84,10 @@ CFStringRef kAXManualAccessibility = CFSTR("AXManualAccessibility");
|
||||
}
|
||||
```
|
||||
|
||||
[devtron]: https://electronjs.org/devtron
|
||||
[devtron-screenshot]: https://cloud.githubusercontent.com/assets/1305617/17156618/9f9bcd72-533f-11e6-880d-389115f40a2a.png
|
||||
[spectron]: https://electronjs.org/spectron
|
||||
[spectron-a11y]: https://github.com/electron/spectron#accessibility-testing
|
||||
[a11y-docs]: https://www.chromium.org/developers/design-documents/accessibility#TOC-How-Chrome-detects-the-presence-of-Assistive-Technology
|
||||
[a11y-devtools]: https://github.com/GoogleChrome/accessibility-developer-tools
|
||||
[a11y-devtools-wiki]: https://github.com/GoogleChrome/accessibility-developer-tools/wiki/Audit-Rules
|
||||
|
||||
@@ -56,7 +56,7 @@ will then be your distribution to deliver to users.
|
||||
|
||||
### With an app source code archive
|
||||
|
||||
Instead of shipping your app by copying all of its source files, you can
|
||||
Instead of from shipping your app by copying all of its source files, you can
|
||||
package your app into an [asar] archive to improve the performance of reading
|
||||
files on platforms like Windows, if you are not already using a bundler such
|
||||
as Parcel or Webpack.
|
||||
|
||||
135
docs/tutorial/automated-testing-with-a-custom-driver.md
Normal file
135
docs/tutorial/automated-testing-with-a-custom-driver.md
Normal file
@@ -0,0 +1,135 @@
|
||||
# Automated Testing with a Custom Driver
|
||||
|
||||
To write automated tests for your Electron app, you will need a way to "drive" your application. [Spectron](https://electronjs.org/spectron) is a commonly-used solution which lets you emulate user actions via [WebDriver](https://webdriver.io/). However, it's also possible to write your own custom driver using node's builtin IPC-over-STDIO. The benefit of a custom driver is that it tends to require less overhead than Spectron, and lets you expose custom methods to your test suite.
|
||||
|
||||
To create a custom driver, we'll use Node.js' [child_process](https://nodejs.org/api/child_process.html) API. The test suite will spawn the Electron process, then establish a simple messaging protocol:
|
||||
|
||||
```js
|
||||
const childProcess = require('child_process')
|
||||
const electronPath = require('electron')
|
||||
|
||||
// spawn the process
|
||||
const env = { /* ... */ }
|
||||
const stdio = ['inherit', 'inherit', 'inherit', 'ipc']
|
||||
const appProcess = childProcess.spawn(electronPath, ['./app'], { stdio, env })
|
||||
|
||||
// listen for IPC messages from the app
|
||||
appProcess.on('message', (msg) => {
|
||||
// ...
|
||||
})
|
||||
|
||||
// send an IPC message to the app
|
||||
appProcess.send({ my: 'message' })
|
||||
```
|
||||
|
||||
From within the Electron app, you can listen for messages and send replies using the Node.js [process](https://nodejs.org/api/process.html) API:
|
||||
|
||||
```js
|
||||
// listen for IPC messages from the test suite
|
||||
process.on('message', (msg) => {
|
||||
// ...
|
||||
})
|
||||
|
||||
// send an IPC message to the test suite
|
||||
process.send({ my: 'message' })
|
||||
```
|
||||
|
||||
We can now communicate from the test suite to the Electron app using the `appProcess` object.
|
||||
|
||||
For convenience, you may want to wrap `appProcess` in a driver object that provides more high-level functions. Here is an example of how you can do this:
|
||||
|
||||
```js
|
||||
class TestDriver {
|
||||
constructor ({ path, args, env }) {
|
||||
this.rpcCalls = []
|
||||
|
||||
// start child process
|
||||
env.APP_TEST_DRIVER = 1 // let the app know it should listen for messages
|
||||
this.process = childProcess.spawn(path, args, { stdio: ['inherit', 'inherit', 'inherit', 'ipc'], env })
|
||||
|
||||
// handle rpc responses
|
||||
this.process.on('message', (message) => {
|
||||
// pop the handler
|
||||
const rpcCall = this.rpcCalls[message.msgId]
|
||||
if (!rpcCall) return
|
||||
this.rpcCalls[message.msgId] = null
|
||||
// reject/resolve
|
||||
if (message.reject) rpcCall.reject(message.reject)
|
||||
else rpcCall.resolve(message.resolve)
|
||||
})
|
||||
|
||||
// wait for ready
|
||||
this.isReady = this.rpc('isReady').catch((err) => {
|
||||
console.error('Application failed to start', err)
|
||||
this.stop()
|
||||
process.exit(1)
|
||||
})
|
||||
}
|
||||
|
||||
// simple RPC call
|
||||
// to use: driver.rpc('method', 1, 2, 3).then(...)
|
||||
async rpc (cmd, ...args) {
|
||||
// send rpc request
|
||||
const msgId = this.rpcCalls.length
|
||||
this.process.send({ msgId, cmd, args })
|
||||
return new Promise((resolve, reject) => this.rpcCalls.push({ resolve, reject }))
|
||||
}
|
||||
|
||||
stop () {
|
||||
this.process.kill()
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
In the app, you'd need to write a simple handler for the RPC calls:
|
||||
|
||||
```js
|
||||
const METHODS = {
|
||||
isReady () {
|
||||
// do any setup needed
|
||||
return true
|
||||
}
|
||||
// define your RPC-able methods here
|
||||
}
|
||||
|
||||
const onMessage = async ({ msgId, cmd, args }) => {
|
||||
let method = METHODS[cmd]
|
||||
if (!method) method = () => new Error('Invalid method: ' + cmd)
|
||||
try {
|
||||
const resolve = await method(...args)
|
||||
process.send({ msgId, resolve })
|
||||
} catch (err) {
|
||||
const reject = {
|
||||
message: err.message,
|
||||
stack: err.stack,
|
||||
name: err.name
|
||||
}
|
||||
process.send({ msgId, reject })
|
||||
}
|
||||
}
|
||||
|
||||
if (process.env.APP_TEST_DRIVER) {
|
||||
process.on('message', onMessage)
|
||||
}
|
||||
```
|
||||
|
||||
Then, in your test suite, you can use your test-driver as follows:
|
||||
|
||||
```js
|
||||
const test = require('ava')
|
||||
const electronPath = require('electron')
|
||||
|
||||
const app = new TestDriver({
|
||||
path: electronPath,
|
||||
args: ['./app'],
|
||||
env: {
|
||||
NODE_ENV: 'test'
|
||||
}
|
||||
})
|
||||
test.before(async t => {
|
||||
await app.isReady
|
||||
})
|
||||
test.after.always('cleanup', async t => {
|
||||
await app.stop()
|
||||
})
|
||||
```
|
||||
@@ -1,265 +0,0 @@
|
||||
# Automated Testing
|
||||
|
||||
Test automation is an efficient way of validating that your application code works as intended.
|
||||
While Electron doesn't actively maintain its own testing solution, this guide will go over a couple
|
||||
ways you can run end-to-end automated tests on your Electron app.
|
||||
|
||||
## Using the WebDriver interface
|
||||
|
||||
From [ChromeDriver - WebDriver for Chrome][chrome-driver]:
|
||||
|
||||
> WebDriver is an open source tool for automated testing of web apps across many
|
||||
> browsers. It provides capabilities for navigating to web pages, user input,
|
||||
> JavaScript execution, and more. ChromeDriver is a standalone server which
|
||||
> implements WebDriver's wire protocol for Chromium. It is being developed by
|
||||
> members of the Chromium and WebDriver teams.
|
||||
|
||||
There are a few ways that you can set up testing using WebDriver.
|
||||
|
||||
### With WebdriverIO
|
||||
|
||||
[WebdriverIO](https://webdriver.io/) (WDIO) is a test automation framework that provides a
|
||||
Node.js package for testing with WebDriver. Its ecosystem also includes various plugins
|
||||
(e.g. reporter and services) that can help you put together your test setup.
|
||||
|
||||
#### Install the testrunner
|
||||
|
||||
First you need to run the WebdriverIO starter toolkit in your project root directory:
|
||||
|
||||
```sh npm2yarn
|
||||
npx wdio . --yes
|
||||
```
|
||||
|
||||
This installs all necessary packages for you and generates a `wdio.conf.js` configuration file.
|
||||
|
||||
#### Connect WDIO to your Electron app
|
||||
|
||||
Update the capabilities in your configuration file to point to your Electron app binary:
|
||||
|
||||
```javascript title='wdio.conf.js'
|
||||
export.config = {
|
||||
// ...
|
||||
capabilities: [{
|
||||
browserName: 'chrome',
|
||||
'goog:chromeOptions': {
|
||||
binary: '/path/to/your/electron/binary', // Path to your Electron binary.
|
||||
args: [/* cli arguments */] // Optional, perhaps 'app=' + /path/to/your/app/
|
||||
}
|
||||
}]
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
#### Run your tests
|
||||
|
||||
To run your tests:
|
||||
|
||||
```sh
|
||||
$ npx wdio run wdio.conf.js
|
||||
```
|
||||
|
||||
[chrome-driver]: https://sites.google.com/chromium.org/driver/
|
||||
|
||||
### With Selenium
|
||||
|
||||
[Selenium](https://www.selenium.dev/) is a web automation framework that
|
||||
exposes bindings to WebDriver APIs in many languages. Their Node.js bindings
|
||||
are available under the `selenium-webdriver` package on NPM.
|
||||
|
||||
#### Run a ChromeDriver server
|
||||
|
||||
In order to use Selenium with Electron, you need to download the `electron-chromedriver`
|
||||
binary, and run it:
|
||||
|
||||
```sh npm2yarn
|
||||
npm install --save-dev electron-chromedriver
|
||||
./node_modules/.bin/chromedriver
|
||||
Starting ChromeDriver (v2.10.291558) on port 9515
|
||||
Only local connections are allowed.
|
||||
```
|
||||
|
||||
Remember the port number `9515`, which will be used later.
|
||||
|
||||
#### Connect Selenium to ChromeDriver
|
||||
|
||||
Next, install Selenium into your project:
|
||||
|
||||
```sh npm2yarn
|
||||
npm install --save-dev selenium-webdriver
|
||||
```
|
||||
|
||||
Usage of `selenium-webdriver` with Electron is the same as with
|
||||
normal websites, except that you have to manually specify how to connect
|
||||
ChromeDriver and where to find the binary of your Electron app:
|
||||
|
||||
```js title='test.js'
|
||||
const webdriver = require('selenium-webdriver')
|
||||
const driver = new webdriver.Builder()
|
||||
// The "9515" is the port opened by ChromeDriver.
|
||||
.usingServer('http://localhost:9515')
|
||||
.withCapabilities({
|
||||
'goog:chromeOptions': {
|
||||
// Here is the path to your Electron binary.
|
||||
binary: '/Path-to-Your-App.app/Contents/MacOS/Electron'
|
||||
}
|
||||
})
|
||||
.forBrowser('chrome') // note: use .forBrowser('electron') for selenium-webdriver <= 3.6.0
|
||||
.build()
|
||||
driver.get('http://www.google.com')
|
||||
driver.findElement(webdriver.By.name('q')).sendKeys('webdriver')
|
||||
driver.findElement(webdriver.By.name('btnG')).click()
|
||||
driver.wait(() => {
|
||||
return driver.getTitle().then((title) => {
|
||||
return title === 'webdriver - Google Search'
|
||||
})
|
||||
}, 1000)
|
||||
driver.quit()
|
||||
```
|
||||
|
||||
## Using a custom test driver
|
||||
|
||||
It's also possible to write your own custom driver using Node.js' built-in IPC-over-STDIO.
|
||||
Custom test drivers require you to write additional app code, but have lower overhead and let you
|
||||
expose custom methods to your test suite.
|
||||
|
||||
To create a custom driver, we'll use Node.js' [`child_process`](https://nodejs.org/api/child_process.html) API.
|
||||
The test suite will spawn the Electron process, then establish a simple messaging protocol:
|
||||
|
||||
```js title='testDriver.js'
|
||||
const childProcess = require('child_process')
|
||||
const electronPath = require('electron')
|
||||
|
||||
// spawn the process
|
||||
const env = { /* ... */ }
|
||||
const stdio = ['inherit', 'inherit', 'inherit', 'ipc']
|
||||
const appProcess = childProcess.spawn(electronPath, ['./app'], { stdio, env })
|
||||
|
||||
// listen for IPC messages from the app
|
||||
appProcess.on('message', (msg) => {
|
||||
// ...
|
||||
})
|
||||
|
||||
// send an IPC message to the app
|
||||
appProcess.send({ my: 'message' })
|
||||
```
|
||||
|
||||
From within the Electron app, you can listen for messages and send replies using the Node.js
|
||||
[`process`](https://nodejs.org/api/process.html) API:
|
||||
|
||||
```js title='main.js'
|
||||
// listen for messages from the test suite
|
||||
process.on('message', (msg) => {
|
||||
// ...
|
||||
})
|
||||
|
||||
// send a message to the test suite
|
||||
process.send({ my: 'message' })
|
||||
```
|
||||
|
||||
We can now communicate from the test suite to the Electron app using the `appProcess` object.
|
||||
|
||||
For convenience, you may want to wrap `appProcess` in a driver object that provides more
|
||||
high-level functions. Here is an example of how you can do this. Let's start by creating
|
||||
a `TestDriver` class:
|
||||
|
||||
```js title='testDriver.js'
|
||||
class TestDriver {
|
||||
constructor ({ path, args, env }) {
|
||||
this.rpcCalls = []
|
||||
|
||||
// start child process
|
||||
env.APP_TEST_DRIVER = 1 // let the app know it should listen for messages
|
||||
this.process = childProcess.spawn(path, args, { stdio: ['inherit', 'inherit', 'inherit', 'ipc'], env })
|
||||
|
||||
// handle rpc responses
|
||||
this.process.on('message', (message) => {
|
||||
// pop the handler
|
||||
const rpcCall = this.rpcCalls[message.msgId]
|
||||
if (!rpcCall) return
|
||||
this.rpcCalls[message.msgId] = null
|
||||
// reject/resolve
|
||||
if (message.reject) rpcCall.reject(message.reject)
|
||||
else rpcCall.resolve(message.resolve)
|
||||
})
|
||||
|
||||
// wait for ready
|
||||
this.isReady = this.rpc('isReady').catch((err) => {
|
||||
console.error('Application failed to start', err)
|
||||
this.stop()
|
||||
process.exit(1)
|
||||
})
|
||||
}
|
||||
|
||||
// simple RPC call
|
||||
// to use: driver.rpc('method', 1, 2, 3).then(...)
|
||||
async rpc (cmd, ...args) {
|
||||
// send rpc request
|
||||
const msgId = this.rpcCalls.length
|
||||
this.process.send({ msgId, cmd, args })
|
||||
return new Promise((resolve, reject) => this.rpcCalls.push({ resolve, reject }))
|
||||
}
|
||||
|
||||
stop () {
|
||||
this.process.kill()
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = { TestDriver };
|
||||
```
|
||||
|
||||
In your app code, can then write a simple handler to receive RPC calls:
|
||||
|
||||
```js title='main.js'
|
||||
const METHODS = {
|
||||
isReady () {
|
||||
// do any setup needed
|
||||
return true
|
||||
}
|
||||
// define your RPC-able methods here
|
||||
}
|
||||
|
||||
const onMessage = async ({ msgId, cmd, args }) => {
|
||||
let method = METHODS[cmd]
|
||||
if (!method) method = () => new Error('Invalid method: ' + cmd)
|
||||
try {
|
||||
const resolve = await method(...args)
|
||||
process.send({ msgId, resolve })
|
||||
} catch (err) {
|
||||
const reject = {
|
||||
message: err.message,
|
||||
stack: err.stack,
|
||||
name: err.name
|
||||
}
|
||||
process.send({ msgId, reject })
|
||||
}
|
||||
}
|
||||
|
||||
if (process.env.APP_TEST_DRIVER) {
|
||||
process.on('message', onMessage)
|
||||
}
|
||||
```
|
||||
|
||||
Then, in your test suite, you can use your `TestDriver` class with the test automation
|
||||
framework of your choosing. The following example uses
|
||||
[`ava`](https://www.npmjs.com/package/ava), but other popular choices like Jest
|
||||
or Mocha would work as well:
|
||||
|
||||
```js title='test.js'
|
||||
const test = require('ava')
|
||||
const electronPath = require('electron')
|
||||
const { TestDriver } = require('./testDriver')
|
||||
|
||||
const app = new TestDriver({
|
||||
path: electronPath,
|
||||
args: ['./app'],
|
||||
env: {
|
||||
NODE_ENV: 'test'
|
||||
}
|
||||
})
|
||||
test.before(async t => {
|
||||
await app.isReady
|
||||
})
|
||||
test.after.always('cleanup', async t => {
|
||||
await app.stop()
|
||||
})
|
||||
```
|
||||
@@ -88,15 +88,14 @@ without meaning any harm:
|
||||
<dict>
|
||||
<key>com.apple.security.cs.allow-jit</key>
|
||||
<true/>
|
||||
<key>com.apple.security.cs.allow-unsigned-executable-memory</key>
|
||||
<true/>
|
||||
<key>com.apple.security.cs.debugger</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</plist>
|
||||
```
|
||||
|
||||
Note that up until Electron 12, the `com.apple.security.cs.allow-unsigned-executable-memory` entitlement was required
|
||||
as well. However, it should not be used anymore if it can be avoided.
|
||||
|
||||
To see all of this in action, check out Electron Fiddle's source code,
|
||||
[especially its `electron-forge` configuration
|
||||
file](https://github.com/electron/fiddle/blob/master/forge.config.js).
|
||||
@@ -166,15 +165,14 @@ without meaning any harm:
|
||||
<dict>
|
||||
<key>com.apple.security.cs.allow-jit</key>
|
||||
<true/>
|
||||
<key>com.apple.security.cs.allow-unsigned-executable-memory</key>
|
||||
<true/>
|
||||
<key>com.apple.security.cs.debugger</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</plist>
|
||||
```
|
||||
|
||||
Up until Electron 12, the `com.apple.security.cs.allow-unsigned-executable-memory` entitlement was required
|
||||
as well. However, it should not be used anymore if it can be avoided.
|
||||
|
||||
## Mac App Store
|
||||
|
||||
See the [Mac App Store Guide].
|
||||
|
||||
@@ -4,38 +4,39 @@
|
||||
|
||||
Context Isolation is a feature that ensures that both your `preload` scripts and Electron's internal logic run in a separate context to the website you load in a [`webContents`](../api/web-contents.md). This is important for security purposes as it helps prevent the website from accessing Electron internals or the powerful APIs your preload script has access to.
|
||||
|
||||
This means that the `window` object that your preload script has access to is actually a **different** object than the website would have access to. For example, if you set `window.hello = 'wave'` in your preload script and context isolation is enabled, `window.hello` will be undefined if the website tries to access it.
|
||||
This means that the `window` object that your preload script has access to is actually a **different** object than the website would have access to. For example, if you set `window.hello = 'wave'` in your preload script and context isolation is enabled `window.hello` will be undefined if the website tries to access it.
|
||||
|
||||
Context isolation has been enabled by default since Electron 12, and it is a recommended security setting for _all applications_.
|
||||
Every single application should have context isolation enabled and from Electron 12 it will be enabled by default.
|
||||
|
||||
## How do I enable it?
|
||||
|
||||
From Electron 12, it will be enabled by default. For lower versions it is an option in the `webPreferences` option when constructing `new BrowserWindow`'s.
|
||||
|
||||
```javascript
|
||||
const mainWindow = new BrowserWindow({
|
||||
webPreferences: {
|
||||
contextIsolation: true
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
## Migration
|
||||
|
||||
> Without context isolation, I used to provide APIs from my preload script using `window.X = apiObject`. Now what?
|
||||
> I used to provide APIs from my preload script using `window.X = apiObject` now what?
|
||||
|
||||
### Before: context isolation disabled
|
||||
Exposing APIs from your preload script to the loaded website is a common usecase and there is a dedicated module in Electron to help you do this in a painless way.
|
||||
|
||||
Exposing APIs from your preload script to a loaded website in the renderer process is a common use-case. With context isolation disabled, your preload script would share a common global `window` object with the renderer. You could then attach arbitrary properties to a preload script:
|
||||
**Before: With context isolation disabled**
|
||||
|
||||
```javascript title='preload.js'
|
||||
// preload with contextIsolation disabled
|
||||
```javascript
|
||||
window.myAPI = {
|
||||
doAThing: () => {}
|
||||
}
|
||||
```
|
||||
|
||||
The `doAThing()` function could then be used directly in the renderer process:
|
||||
**After: With context isolation enabled**
|
||||
|
||||
```javascript title='renderer.js'
|
||||
// use the exposed API in the renderer
|
||||
window.myAPI.doAThing()
|
||||
```
|
||||
|
||||
### After: context isolation enabled
|
||||
|
||||
There is a dedicated module in Electron to help you do this in a painless way. The [`contextBridge`](../api/context-bridge.md) module can be used to **safely** expose APIs from your preload script's isolated context to the context the website is running in. The API will also be accessible from the website on `window.myAPI` just like it was before.
|
||||
|
||||
```javascript title='preload.js'
|
||||
// preload with contextIsolation enabled
|
||||
```javascript
|
||||
const { contextBridge } = require('electron')
|
||||
|
||||
contextBridge.exposeInMainWorld('myAPI', {
|
||||
@@ -43,63 +44,26 @@ contextBridge.exposeInMainWorld('myAPI', {
|
||||
})
|
||||
```
|
||||
|
||||
```javascript title='renderer.js'
|
||||
// use the exposed API in the renderer
|
||||
window.myAPI.doAThing()
|
||||
```
|
||||
The [`contextBridge`](../api/context-bridge.md) module can be used to **safely** expose APIs from the isolated context your preload script runs in to the context the website is running in. The API will also be accessible from the website on `window.myAPI` just like it was before.
|
||||
|
||||
Please read the `contextBridge` documentation linked above to fully understand its limitations. For instance, you can't send custom prototypes or symbols over the bridge.
|
||||
You should read the `contextBridge` documentation linked above to fully understand its limitations. For instance you can't send custom prototypes or symbols over the bridge.
|
||||
|
||||
## Security considerations
|
||||
## Security Considerations
|
||||
|
||||
Just enabling `contextIsolation` and using `contextBridge` does not automatically mean that everything you do is safe. For instance, this code is **unsafe**.
|
||||
Just enabling `contextIsolation` and using `contextBridge` does not automatically mean that everything you do is safe. For instance this code is **unsafe**.
|
||||
|
||||
```javascript title='preload.js'
|
||||
```javascript
|
||||
// ❌ Bad code
|
||||
contextBridge.exposeInMainWorld('myAPI', {
|
||||
send: ipcRenderer.send
|
||||
})
|
||||
```
|
||||
|
||||
It directly exposes a powerful API without any kind of argument filtering. This would allow any website to send arbitrary IPC messages, which you do not want to be possible. The correct way to expose IPC-based APIs would instead be to provide one method per IPC message.
|
||||
It directly exposes a powerful API without any kind of argument filtering. This would allow any website to send arbitrary IPC messages which you do not want to be possible. The correct way to expose IPC-based APIs would instead be to provide one method per IPC message.
|
||||
|
||||
```javascript title='preload.js'
|
||||
```javascript
|
||||
// ✅ Good code
|
||||
contextBridge.exposeInMainWorld('myAPI', {
|
||||
loadPreferences: () => ipcRenderer.invoke('load-prefs')
|
||||
})
|
||||
```
|
||||
|
||||
## Usage with TypeScript
|
||||
|
||||
If you're building your Electron app with TypeScript, you'll want to add types to your APIs exposed over the context bridge. The renderer's `window` object won't have the correct typings unless you extend the types with a [declaration file].
|
||||
|
||||
For example, given this `preload.ts` script:
|
||||
|
||||
```typescript title='preload.ts'
|
||||
contextBridge.exposeInMainWorld('electronAPI', {
|
||||
loadPreferences: () => ipcRenderer.invoke('load-prefs')
|
||||
})
|
||||
```
|
||||
|
||||
You can create a `renderer.d.ts` declaration file and globally augment the `Window` interface:
|
||||
|
||||
```typescript title='renderer.d.ts'
|
||||
export interface IElectronAPI {
|
||||
loadPreferences: () => Promise<void>,
|
||||
}
|
||||
|
||||
declare global {
|
||||
interface Window {
|
||||
electronAPI: IElectronAPI
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Doing so will ensure that the TypeScript compiler will know about the `electronAPI` property on your global `window` object when writing scripts in your renderer process:
|
||||
|
||||
```typescript title='renderer.ts'
|
||||
window.electronAPI.loadPreferences()
|
||||
```
|
||||
|
||||
[declaration file]: https://www.typescriptlang.org/docs/handbook/declaration-files/introduction.html
|
||||
|
||||
175
docs/tutorial/creating-api.md
Normal file
175
docs/tutorial/creating-api.md
Normal file
@@ -0,0 +1,175 @@
|
||||
# Creating an Electron Browser Module API
|
||||
|
||||
Welcome to the Electron API guide! If you are unfamiliar with creating electron APIs within the `browser` module, this guide serves as a checklist for some of the necessary steps that you will need to implement.
|
||||
|
||||
This is not a comprehensive end-all guide to creating an Electron Browser API, rather an outline documenting some of the more unintuitive steps.
|
||||
|
||||
## Adding Your Files To Electron's Project Configuration
|
||||
|
||||
Electron uses [GN](https://gn.googlesource.com/gn) as a meta build system to generate files for its compiler, [Ninja](https://ninja-build.org/). This means that in order to tell Electron to compile your code, we have to add your API's code and header file names into [`filenames.gni`](https://github.com/electron/electron/blob/main/filenames.gni).
|
||||
|
||||
You will need to append your api file names alphabetically into the appropriate files like so:
|
||||
|
||||
```cpp
|
||||
lib_sources = [
|
||||
"path/to/api/api_name.cc",
|
||||
"path/to/api/api_name.h",
|
||||
]
|
||||
|
||||
lib_sources_mac = [
|
||||
"path/to/api/api_name_mac.h",
|
||||
"path/to/api/api_name_mac.mm",
|
||||
]
|
||||
|
||||
lib_sources_win = [
|
||||
"path/to/api/api_name_win.cc",
|
||||
"path/to/api/api_name_win.h",
|
||||
]
|
||||
|
||||
lib_sources_linux = [
|
||||
"path/to/api/api_name_linux.cc",
|
||||
"path/to/api/api_name_linux.h",
|
||||
]
|
||||
```
|
||||
|
||||
Note that the Windows, MacOS and Linux array additions are optional and should only be added if your API has specific platform implementations.
|
||||
|
||||
## Create API Documentation
|
||||
|
||||
Type definitions are generated by Electron using [`docs-parser`](https://github.com/electron/docs-parser) and [`typescript-definitions`](https://github.com/electron/typescript-definitions). This step is necessary to ensure consistency across Electron's API documentation. This means that for your API type definition to appear in the `electron.d.ts` file, we must create a `.md` file. Examples can be found in [this folder](https://github.com/electron/electron/tree/main/docs/api).
|
||||
|
||||
## Setting Up `ObjectTemplateBuilder` and `Wrappable`
|
||||
|
||||
Electron constructs its modules using [`object_template_builder`](https://www.electronjs.org/blog/from-native-to-js#mateobjecttemplatebuilder).
|
||||
|
||||
[`wrappable`](https://chromium.googlesource.com/chromium/src/+/refs/heads/main/gin/wrappable.h) is a base class for C++ objects that have corresponding v8 wrapper objects.
|
||||
|
||||
Here is a basic example of code that you may need to add, in order to incorporate `object_template_builder` and `wrappable` into your API. For further reference, you can find more implementations [here](https://github.com/electron/electron/tree/main/shell/browser/api).
|
||||
|
||||
In your `api_name.h` file:
|
||||
|
||||
```cpp
|
||||
|
||||
#ifndef SHELL_BROWSER_API_ELECTRON_API_{API_NAME}_H_
|
||||
#define SHELL_BROWSER_API_ELECTRON_API_{API_NAME}_H_
|
||||
|
||||
#include "gin/handle.h"
|
||||
#include "gin/wrappable.h"
|
||||
|
||||
namespace electron {
|
||||
|
||||
namespace api {
|
||||
|
||||
class ApiName : public gin::Wrappable<ApiName> {
|
||||
public:
|
||||
static gin::Handle<ApiName> Create(v8::Isolate* isolate);
|
||||
|
||||
// gin::Wrappable
|
||||
static gin::WrapperInfo kWrapperInfo;
|
||||
gin::ObjectTemplateBuilder GetObjectTemplateBuilder(
|
||||
v8::Isolate* isolate) override;
|
||||
const char* GetTypeName() override;
|
||||
} // namespace api
|
||||
} // namespace electron
|
||||
```
|
||||
|
||||
In your `api_name.cc` file:
|
||||
|
||||
```cpp
|
||||
#include "shell/browser/api/electron_api_safe_storage.h"
|
||||
|
||||
#include "shell/browser/browser.h"
|
||||
#include "shell/common/gin_converters/base_converter.h"
|
||||
#include "shell/common/gin_converters/callback_converter.h"
|
||||
#include "shell/common/gin_helper/dictionary.h"
|
||||
#include "shell/common/gin_helper/object_template_builder.h"
|
||||
#include "shell/common/node_includes.h"
|
||||
#include "shell/common/platform_util.h"
|
||||
|
||||
namespace electron {
|
||||
|
||||
namespace api {
|
||||
|
||||
gin::WrapperInfo ApiName::kWrapperInfo = {gin::kEmbedderNativeGin};
|
||||
|
||||
gin::ObjectTemplateBuilder ApiName::GetObjectTemplateBuilder(
|
||||
v8::Isolate* isolate) {
|
||||
return gin::ObjectTemplateBuilder(isolate)
|
||||
.SetMethod("methodName", &ApiName::methodName);
|
||||
}
|
||||
|
||||
const char* ApiName::GetTypeName() {
|
||||
return "ApiName";
|
||||
}
|
||||
|
||||
// static
|
||||
gin::Handle<ApiName> ApiName::Create(v8::Isolate* isolate) {
|
||||
return gin::CreateHandle(isolate, new ApiName());
|
||||
}
|
||||
|
||||
} // namespace api
|
||||
|
||||
} // namespace electron
|
||||
|
||||
namespace {
|
||||
|
||||
void Initialize(v8::Local<v8::Object> exports,
|
||||
v8::Local<v8::Value> unused,
|
||||
v8::Local<v8::Context> context,
|
||||
void* priv) {
|
||||
v8::Isolate* isolate = context->GetIsolate();
|
||||
gin_helper::Dictionary dict(isolate, exports);
|
||||
dict.Set("apiName", electron::api::ApiName::Create(isolate));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
```
|
||||
|
||||
## Link Your Electron API With Node
|
||||
|
||||
To learn about how Electron links with Node, [click here.](https://www.electronjs.org/blog/electron-internals-using-node-as-a-library#link-node-with-electron)
|
||||
|
||||
In the [`internal-ambient.d.ts`](https://github.com/electron/electron/blob/main/typings/internal-ambient.d.ts) file:
|
||||
|
||||
We need to append a new property onto the `Process` interface found in this file like so:
|
||||
|
||||
```ts
|
||||
interface Process {
|
||||
_linkedBinding(name: 'electron_browser_{api_name}', Electron.ApiName);
|
||||
}
|
||||
```
|
||||
|
||||
At the very bottom of your `api_name.cc` file:
|
||||
|
||||
```cpp
|
||||
NODE_LINKED_MODULE_CONTEXT_AWARE(electron_browser_{api_name},Initialize)
|
||||
```
|
||||
|
||||
In your [`shell/common/node_bindings.cc`](https://github.com/electron/electron/blob/main/shell/common/node_bindings.cc) file:
|
||||
|
||||
Add your node binding name to Electron's built-in modules.
|
||||
|
||||
```cpp
|
||||
#define ELECTRON_BUILTIN_MODULES(V) \
|
||||
V(electron_browser_{api_name})
|
||||
```
|
||||
|
||||
## Expose Your API to TypeScript
|
||||
|
||||
### Export Your API as a module
|
||||
|
||||
We will need to create a new TypeScript file in the path that follows:
|
||||
|
||||
`"lib/browser/api/{electron_browser_{api_name}}.ts"`
|
||||
|
||||
An example of the contents of this file can be found [here](https://github.com/electron/electron/blob/main/lib/browser/api/native-image.ts).
|
||||
|
||||
### Expose Your module to TypeScript
|
||||
|
||||
Add your module to the module list found at `"lib/browser/api/module-list.ts"` like so:
|
||||
|
||||
```typescript
|
||||
export const browserModuleList: ElectronInternal.ModuleEntry[] = [
|
||||
{ name: 'apiName', loader: () => require('./api-name') },
|
||||
];
|
||||
```
|
||||
@@ -138,7 +138,7 @@ Finally, the `main.js` file represents the main process and contains the actual
|
||||
const { app, BrowserWindow, ipcMain, nativeTheme } = require('electron')
|
||||
const path = require('path')
|
||||
|
||||
function createWindow () {
|
||||
const createWindow = () => {
|
||||
const win = new BrowserWindow({
|
||||
width: 800,
|
||||
height: 600,
|
||||
|
||||
35
docs/tutorial/desktop-environment-integration.md
Normal file
35
docs/tutorial/desktop-environment-integration.md
Normal file
@@ -0,0 +1,35 @@
|
||||
# Desktop Environment Integration
|
||||
|
||||
Different operating systems provide different features for integrating desktop
|
||||
applications into their desktop environments. For example, on Windows,
|
||||
applications can put shortcuts in the JumpList of task bar, and on Mac,
|
||||
applications can put a custom menu in the dock menu.
|
||||
|
||||
This guide explains how to integrate your application into those desktop
|
||||
environments with Electron APIs.
|
||||
|
||||
## Notifications
|
||||
|
||||
See the [Notifications documentation](notifications.md).
|
||||
|
||||
## Recent Documents
|
||||
|
||||
See [Recent Documents documentation](recent-documents.md).
|
||||
|
||||
## Progress Bar
|
||||
|
||||
See the [Progress Bar documentation](progress-bar.md).
|
||||
|
||||
## Unity Launcher
|
||||
|
||||
See the [Unity Launcher documentation][unity-launcher].
|
||||
|
||||
## Represented File for macOS Window
|
||||
|
||||
See the [Represented File documentation](represented-file.md).
|
||||
|
||||
## Dragging files out of the window
|
||||
|
||||
See the [Native File Drag & Drop documentation](native-file-drag-drop.md).
|
||||
|
||||
[unity-launcher]: https://help.ubuntu.com/community/UnityLaunchersAndDesktopFiles#Adding_shortcuts_to_a_launcher
|
||||
@@ -1,108 +0,0 @@
|
||||
# Device Access
|
||||
|
||||
Like Chromium based browsers, Electron provides access to device hardware
|
||||
through web APIs. For the most part these APIs work like they do in a browser,
|
||||
but there are some differences that need to be taken into account. The primary
|
||||
difference between Electron and browsers is what happens when device access is
|
||||
requested. In a browser, users are presented with a popup where they can grant
|
||||
access to an individual device. In Electron APIs are provided which can be
|
||||
used by a developer to either automatically pick a device or prompt users to
|
||||
pick a device via a developer created interface.
|
||||
|
||||
## Web Bluetooth API
|
||||
|
||||
The [Web Bluetooth API](https://web.dev/bluetooth/) can be used to communicate
|
||||
with bluetooth devices. In order to use this API in Electron, developers will
|
||||
need to handle the [`select-bluetooth-device` event on the webContents](../api/web-contents.md#event-select-bluetooth-device)
|
||||
associated with the device request.
|
||||
|
||||
### Example
|
||||
|
||||
This example demonstrates an Electron application that automatically selects
|
||||
the first available bluetooth device when the `Test Bluetooth` button is
|
||||
clicked.
|
||||
|
||||
```javascript fiddle='docs/fiddles/features/web-bluetooth'
|
||||
|
||||
```
|
||||
|
||||
## WebHID API
|
||||
|
||||
The [WebHID API](https://web.dev/hid/) can be used to access HID devices such
|
||||
as keyboards and gamepads. Electron provides several APIs for working with
|
||||
the WebHID API:
|
||||
|
||||
* The [`select-hid-device` event on the Session](../api/session.md#event-select-hid-device)
|
||||
can be used to select a HID device when a call to
|
||||
`navigator.hid.requestDevice` is made. Additionally the [`hid-device-added`](../api/session.md#event-hid-device-added)
|
||||
and [`hid-device-removed`](../api/session.md#event-hid-device-removed) events
|
||||
on the Session can be used to handle devices being plugged in or unplugged during the
|
||||
`navigator.hid.requestDevice` process.
|
||||
* [`ses.setDevicePermissionHandler(handler)`](../api/session.md#sessetdevicepermissionhandlerhandler)
|
||||
can be used to provide default permissioning to devices without first calling
|
||||
for permission to devices via `navigator.hid.requestDevice`. Additionally,
|
||||
the default behavior of Electron is to store granted device permision through
|
||||
the lifetime of the corresponding WebContents. If longer term storage is
|
||||
needed, a developer can store granted device permissions (eg when handling
|
||||
the `select-hid-device` event) and then read from that storage with
|
||||
`setDevicePermissionHandler`.
|
||||
* [`ses.setPermissionCheckHandler(handler)`](../api/session.md#sessetpermissioncheckhandlerhandler)
|
||||
can be used to disable HID access for specific origins.
|
||||
|
||||
### Blocklist
|
||||
|
||||
By default Electron employs the same [blocklist](https://github.com/WICG/webhid/blob/main/blocklist.txt)
|
||||
used by Chromium. If you wish to override this behavior, you can do so by
|
||||
setting the `disable-hid-blocklist` flag:
|
||||
|
||||
```javascript
|
||||
app.commandLine.appendSwitch('disable-hid-blocklist')
|
||||
```
|
||||
|
||||
### Example
|
||||
|
||||
This example demonstrates an Electron application that automatically selects
|
||||
HID devices through [`ses.setDevicePermissionHandler(handler)`](../api/session.md#sessetdevicepermissionhandlerhandler)
|
||||
and through [`select-hid-device` event on the Session](../api/session.md#event-select-hid-device)
|
||||
when the `Test WebHID` button is clicked.
|
||||
|
||||
```javascript fiddle='docs/fiddles/features/web-hid'
|
||||
|
||||
```
|
||||
|
||||
## Web Serial API
|
||||
|
||||
The [Web Serial API](https://web.dev/serial/) can be used to access serial
|
||||
devices that are connected via serial port, USB, or Bluetooth. In order to use
|
||||
this API in Electron, developers will need to handle the
|
||||
[`select-serial-port` event on the Session](../api/session.md#event-select-serial-port)
|
||||
associated with the serial port request.
|
||||
|
||||
There are several additional APIs for working with the Web Serial API:
|
||||
|
||||
* The [`serial-port-added`](../api/session.md#event-serial-port-added)
|
||||
and [`serial-port-removed`](../api/session.md#event-serial-port-removed) events
|
||||
on the Session can be used to handle devices being plugged in or unplugged during the
|
||||
`navigator.serial.requestPort` process.
|
||||
* [`ses.setDevicePermissionHandler(handler)`](../api/session.md#sessetdevicepermissionhandlerhandler)
|
||||
can be used to provide default permissioning to devices without first calling
|
||||
for permission to devices via `navigator.serial.requestPort`. Additionally,
|
||||
the default behavior of Electron is to store granted device permision through
|
||||
the lifetime of the corresponding WebContents. If longer term storage is
|
||||
needed, a developer can store granted device permissions (eg when handling
|
||||
the `select-serial-port` event) and then read from that storage with
|
||||
`setDevicePermissionHandler`.
|
||||
* [`ses.setPermissionCheckHandler(handler)`](../api/session.md#sessetpermissioncheckhandlerhandler)
|
||||
can be used to disable serial access for specific origins.
|
||||
|
||||
### Example
|
||||
|
||||
This example demonstrates an Electron application that automatically selects
|
||||
serial devices through [`ses.setDevicePermissionHandler(handler)`](../api/session.md#sessetdevicepermissionhandlerhandler)
|
||||
as well as demonstrating selecting the first available Arduino Uno serial device (if connected) through
|
||||
[`select-serial-port` event on the Session](../api/session.md#event-select-serial-port)
|
||||
when the `Test Web Serial` button is clicked.
|
||||
|
||||
```javascript fiddle='docs/fiddles/features/web-serial'
|
||||
|
||||
```
|
||||
@@ -23,6 +23,5 @@ Special notes:
|
||||
| 11.0.0 | -- | 2020-Aug-27 | 2020-Nov-17 | M87 | v12.18 |
|
||||
| 12.0.0 | -- | 2020-Nov-19 | 2021-Mar-02 | M89 | v14.16 |
|
||||
| 13.0.0 | -- | 2021-Mar-04 | 2021-May-25 | M91 | v14.16 |
|
||||
| 14.0.0 | -- | 2021-May-27 | 2021-Aug-31 | M93 | v14.17 |
|
||||
| 15.0.0 | 2021-Jul-20 | 2021-Sep-01 | 2021-Sep-21 | M94 | v16.5 |
|
||||
| 16.0.0 | -- | 2021-Sep-23 | 2021-Nov-16 | M96 | TBD |
|
||||
| 14.0.0 | -- | 2021-May-27 | 2021-Aug-31 | M93 | TBD |
|
||||
| 15.0.0 | 2021-Jul-20 | 2021-Sep-01 | 2021-Sep-21 | M94 | TBD |
|
||||
|
||||
@@ -2,31 +2,43 @@
|
||||
|
||||
> A detailed look at our versioning policy and implementation.
|
||||
|
||||
As of version 2.0.0, Electron follows the [SemVer](#semver) spec. The following command will install the most recent stable build of Electron:
|
||||
As of version 2.0.0, Electron follows [SemVer](#semver). The following command will install the most recent stable build of Electron:
|
||||
|
||||
```sh npm2yarn
|
||||
```sh
|
||||
npm install --save-dev electron
|
||||
```
|
||||
|
||||
To update an existing project to use the latest stable version:
|
||||
|
||||
```sh npm2yarn
|
||||
```sh
|
||||
npm install --save-dev electron@latest
|
||||
```
|
||||
|
||||
## Versioning scheme
|
||||
## Version 1.x
|
||||
|
||||
Electron versions *< 2.0* did not conform to the [SemVer](https://semver.org) spec: major versions corresponded to end-user API changes, minor versions corresponded to Chromium major releases, and patch versions corresponded to new features and bug fixes. While convenient for developers merging features, it creates problems for developers of client-facing applications. The QA testing cycles of major apps like Slack, Stride, Teams, Skype, VS Code, Atom, and Desktop can be lengthy and stability is a highly desired outcome. There is a high risk in adopting new features while trying to absorb bug fixes.
|
||||
|
||||
Here is an example of the 1.x strategy:
|
||||
|
||||

|
||||
|
||||
An app developed with `1.8.1` cannot take the `1.8.3` bug fix without either absorbing the `1.8.2` feature, or by backporting the fix and maintaining a new release line.
|
||||
|
||||
## Version 2.0 and Beyond
|
||||
|
||||
There are several major changes from our 1.x strategy outlined below. Each change is intended to satisfy the needs and priorities of developers/maintainers and app developers.
|
||||
|
||||
1. Strict use of the [SemVer](#semver) spec
|
||||
1. Strict use of SemVer
|
||||
2. Introduction of semver-compliant `-beta` tags
|
||||
3. Introduction of [conventional commit messages](https://conventionalcommits.org/)
|
||||
4. Well-defined stabilization branches
|
||||
5. The `main` branch is versionless; only stabilization branches contain version information
|
||||
5. The `master` branch is versionless; only stabilization branches contain version information
|
||||
|
||||
We will cover in detail how git branching works, how npm tagging works, what developers should expect to see, and how one can backport changes.
|
||||
|
||||
## SemVer
|
||||
# SemVer
|
||||
|
||||
From 2.0 onward, Electron will follow SemVer.
|
||||
|
||||
Below is a table explicitly mapping types of changes to their corresponding category of SemVer (e.g. Major, Minor, Patch).
|
||||
|
||||
@@ -36,25 +48,22 @@ Below is a table explicitly mapping types of changes to their corresponding cate
|
||||
| Node.js major version updates | Node.js minor version updates | Node.js patch version updates |
|
||||
| Chromium version updates | | fix-related chromium patches |
|
||||
|
||||
For more information, see the [Semantic Versioning 2.0.0](https://semver.org/) spec.
|
||||
|
||||
Note that most Chromium updates will be considered breaking. Fixes that can be backported will likely be cherry-picked as patches.
|
||||
|
||||
## Stabilization branches
|
||||
# Stabilization Branches
|
||||
|
||||
Stabilization branches are branches that run parallel to `main`, taking in only cherry-picked commits that are related to security or stability. These branches are never merged back to `main`.
|
||||
Stabilization branches are branches that run parallel to master, taking in only cherry-picked commits that are related to security or stability. These branches are never merged back to master.
|
||||
|
||||

|
||||
|
||||
Since Electron 8, stabilization branches are always **major** version lines, and named against the following template `$MAJOR-x-y` e.g. `8-x-y`. Prior to that we used **minor** version lines and named them as `$MAJOR-$MINOR-x` e.g. `2-0-x`.
|
||||
|
||||
We allow for multiple stabilization branches to exist simultaneously, one for each supported version. For more details on which versions are supported, see our [Electron Release Timelines](./electron-timelines.md) doc.
|
||||
Since Electron 8, stabilization branches are always **major** version lines, and named against the following template `$MAJOR-x-y` e.g. `8-x-y`. Prior to that we used **minor** version lines and named them as `$MAJOR-$MINOR-x` e.g. `2-0-x`
|
||||
|
||||
We allow for multiple stabilization branches to exist simultaneously, and intend to support at least two in parallel at all times, backporting security fixes as necessary.
|
||||

|
||||
|
||||
Older lines will not be supported by the Electron project, but other groups can take ownership and backport stability and security fixes on their own. We discourage this, but recognize that it makes life easier for many app developers.
|
||||
Older lines will not be supported by GitHub, but other groups can take ownership and backport stability and security fixes on their own. We discourage this, but recognize that it makes life easier for many app developers.
|
||||
|
||||
## Beta releases and bug fixes
|
||||
# Beta Releases and Bug Fixes
|
||||
|
||||
Developers want to know which releases are _safe_ to use. Even seemingly innocent features can introduce regressions in complex applications. At the same time, locking to a fixed version is dangerous because you’re ignoring security patches and bug fixes that may have come out since your version. Our goal is to allow the following standard semver ranges in `package.json` :
|
||||
|
||||
@@ -107,7 +116,15 @@ A few examples of how various SemVer ranges will pick up new releases:
|
||||
|
||||

|
||||
|
||||
## Feature flags
|
||||
# Missing Features: Alphas
|
||||
|
||||
Our strategy has a few tradeoffs, which for now we feel are appropriate. Most importantly that new features in master may take a while before reaching a stable release line. If you want to try a new feature immediately, you will have to build Electron yourself.
|
||||
|
||||
As a future consideration, we may introduce one or both of the following:
|
||||
|
||||
* alpha releases that have looser stability constraints to betas; for example it would be allowable to admit new features while a stability channel is in _alpha_
|
||||
|
||||
# Feature Flags
|
||||
|
||||
Feature flags are a common practice in Chromium, and are well-established in the web-development ecosystem. In the context of Electron, a feature flag or **soft branch** must have the following properties:
|
||||
|
||||
@@ -115,29 +132,20 @@ Feature flags are a common practice in Chromium, and are well-established in the
|
||||
* it completely segments new and old code paths; refactoring old code to support a new feature _violates_ the feature-flag contract
|
||||
* feature flags are eventually removed after the feature is released
|
||||
|
||||
## Semantic commits
|
||||
# Semantic Commits
|
||||
|
||||
All pull requests must adhere to the [Conventional Commits](https://conventionalcommits.org/) spec, which can be summarized as follows:
|
||||
We seek to increase clarity at all levels of the update and releases process. Starting with `2.0.0` we will require pull requests adhere to the [Conventional Commits](https://conventionalcommits.org/) spec, which can be summarized as follows:
|
||||
|
||||
* Commits that would result in a SemVer **major** bump must start their body with `BREAKING CHANGE:`.
|
||||
* Commits that would result in a SemVer **minor** bump must start with `feat:`.
|
||||
* Commits that would result in a SemVer **patch** bump must start with `fix:`.
|
||||
|
||||
The `electron/electron` repository also enforces squash merging, so you only need to make sure that your pull request has the correct title prefix.
|
||||
* We allow squashing of commits, provided that the squashed message adheres to the above message format.
|
||||
* It is acceptable for some commits in a pull request to not include a semantic prefix, as long as the pull request title contains a meaningful encompassing semantic message.
|
||||
|
||||
## Versioned `main` branch
|
||||
# Versioned `master`
|
||||
|
||||
* The `main` branch will always contain the next major version `X.0.0-nightly.DATE` in its `package.json`.
|
||||
* Release branches are never merged back to `main`.
|
||||
* Release branches _do_ contain the correct version in their `package.json`.
|
||||
* As soon as a release branch is cut for a major, `main` must be bumped to the next major (i.e. `main` is always versioned as the next theoretical release branch).
|
||||
|
||||
## Historical versioning (Electron 1.X)
|
||||
|
||||
Electron versions *< 2.0* did not conform to the [SemVer](https://semver.org) spec: major versions corresponded to end-user API changes, minor versions corresponded to Chromium major releases, and patch versions corresponded to new features and bug fixes. While convenient for developers merging features, it creates problems for developers of client-facing applications. The QA testing cycles of major apps like Slack, Teams, Skype, VS Code, and GitHub Desktop can be lengthy and stability is a highly desired outcome. There is a high risk in adopting new features while trying to absorb bug fixes.
|
||||
|
||||
Here is an example of the 1.x strategy:
|
||||
|
||||

|
||||
|
||||
An app developed with `1.8.1` cannot take the `1.8.3` bug fix without either absorbing the `1.8.2` feature, or by backporting the fix and maintaining a new release line.
|
||||
* The `master` branch will always contain the next major version `X.0.0-nightly.DATE` in its `package.json`
|
||||
* Release branches are never merged back to master
|
||||
* Release branches _do_ contain the correct version in their `package.json`
|
||||
* As soon as a release branch is cut for a major, master must be bumped to the next major. I.e. `master` is always versioned as the next theoretical release branch
|
||||
|
||||
@@ -51,4 +51,4 @@ Somewhere in the Electron binary there will be a sequence of bytes that look lik
|
||||
|
||||
To flip a fuse you find its position in the fuse wire and change it to "0" or "1" depending on the state you'd like.
|
||||
|
||||
You can view the current schema [here](https://github.com/electron/electron/blob/main/build/fuses/fuses.json5).
|
||||
You can view the current schema [here](https://github.com/electron/electron/blob/master/build/fuses/fuses.json5).
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# In-App Purchases (macOS)
|
||||
# In-App Purchase (macOS)
|
||||
|
||||
## Preparing
|
||||
|
||||
@@ -39,7 +39,7 @@ inAppPurchase.on('transactions-updated', (event, transactions) => {
|
||||
}
|
||||
|
||||
// Check each transaction.
|
||||
transactions.forEach(function (transaction) {
|
||||
transactions.forEach((transaction) => {
|
||||
const payment = transaction.payment
|
||||
|
||||
switch (transaction.transactionState) {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# Advanced Installation Instructions
|
||||
# Installation
|
||||
|
||||
To install prebuilt Electron binaries, use [`npm`][npm].
|
||||
The preferred method is to install Electron as a development dependency in your
|
||||
@@ -90,11 +90,6 @@ ELECTRON_CUSTOM_DIR="{{ version }}"
|
||||
The above configuration will download from URLs such as
|
||||
`https://npm.taobao.org/mirrors/electron/8.0.0/electron-v8.0.0-linux-x64.zip`.
|
||||
|
||||
If your mirror serves artifacts with different checksums to the official
|
||||
Electron release you may have to set `electron_use_remote_checksums=1` to
|
||||
force Electron to use the remote `SHASUMS256.txt` file to verify the checksum
|
||||
instead of the embedded checksums.
|
||||
|
||||
#### Cache
|
||||
|
||||
Alternatively, you can override the local cache. `@electron/get` will cache
|
||||
|
||||
@@ -82,7 +82,7 @@ listen for the `keyup` and `keydown` [DOM events][dom-events] inside the
|
||||
renderer process using the [addEventListener() API][addEventListener-api].
|
||||
|
||||
```javascript fiddle='docs/fiddles/features/keyboard-shortcuts/web-apis|focus=renderer.js'
|
||||
function handleKeyPress(event) {
|
||||
const handleKeyPress = (event) => {
|
||||
// You can put code here to handle the keypress.
|
||||
document.getElementById("last-keypress").innerText = event.key;
|
||||
console.log(`You pressed ${event.key}`);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
---
|
||||
title: Launching Your Electron App From a URL In Another App
|
||||
title: Launching Your Electron App From A URL In Another App
|
||||
description: This guide will take you through the process of setting your electron app as the default handler for a specific protocol.
|
||||
slug: launch-app-from-url-in-another-app
|
||||
hide_title: true
|
||||
@@ -11,7 +11,7 @@ hide_title: true
|
||||
|
||||
<!-- ✍ Update this section if you want to provide more details -->
|
||||
|
||||
This guide will take you through the process of setting your Electron app as the default
|
||||
This guide will take you through the process of setting your electron app as the default
|
||||
handler for a specific [protocol](https://www.electronjs.org/docs/api/protocol).
|
||||
|
||||
By the end of this tutorial, we will have set our app to intercept and handle
|
||||
@@ -22,17 +22,16 @@ we will use will be "`electron-fiddle://`".
|
||||
|
||||
### Main Process (main.js)
|
||||
|
||||
First, we will import the required modules from `electron`. These modules help
|
||||
control our application lifecycle and create a native browser window.
|
||||
First we will import the required modules from `electron`. These modules help control our application life and create a native browser window.
|
||||
|
||||
```javascript
|
||||
```js
|
||||
const { app, BrowserWindow, shell } = require('electron')
|
||||
const path = require('path')
|
||||
```
|
||||
|
||||
Next, we will proceed to register our application to handle all "`electron-fiddle://`" protocols.
|
||||
|
||||
```javascript
|
||||
```js
|
||||
if (process.defaultApp) {
|
||||
if (process.argv.length >= 2) {
|
||||
app.setAsDefaultProtocolClient('electron-fiddle', process.execPath, [path.resolve(process.argv[1])])
|
||||
@@ -44,7 +43,7 @@ if (process.defaultApp) {
|
||||
|
||||
We will now define the function in charge of creating our browser window and load our application's `index.html` file.
|
||||
|
||||
```javascript
|
||||
```js
|
||||
const createWindow = () => {
|
||||
// Create the browser window.
|
||||
mainWindow = new BrowserWindow({
|
||||
@@ -61,11 +60,11 @@ const createWindow = () => {
|
||||
|
||||
In this next step, we will create our `BrowserWindow` and tell our application how to handle an event in which an external protocol is clicked.
|
||||
|
||||
This code will be different in Windows compared to MacOS and Linux. This is due to Windows requiring additional code in order to open the contents of the protocol link within the same Electron instance. Read more about this [here](https://www.electronjs.org/docs/api/app#apprequestsingleinstancelock).
|
||||
This code will be different in WindowsOS compared to MacOS and Linux. This is due to Windows requiring additional code in order to open the contents of the protocol link within the same electron instance. Read more about this [here](https://www.electronjs.org/docs/api/app#apprequestsingleinstancelock).
|
||||
|
||||
#### Windows code:
|
||||
### Windows code:
|
||||
|
||||
```javascript
|
||||
```js
|
||||
const gotTheLock = app.requestSingleInstanceLock()
|
||||
|
||||
if (!gotTheLock) {
|
||||
@@ -84,16 +83,16 @@ if (!gotTheLock) {
|
||||
createWindow()
|
||||
})
|
||||
|
||||
// Handle the protocol. In this case, we choose to show an Error Box.
|
||||
// handling the protocol. In this case, we choose to show an Error Box.
|
||||
app.on('open-url', (event, url) => {
|
||||
dialog.showErrorBox('Welcome Back', `You arrived from: ${url}`)
|
||||
})
|
||||
}
|
||||
```
|
||||
|
||||
#### MacOS and Linux code:
|
||||
### MacOS and Linux code:
|
||||
|
||||
```javascript
|
||||
```js
|
||||
// This method will be called when Electron has finished
|
||||
// initialization and is ready to create browser windows.
|
||||
// Some APIs can only be used after this event occurs.
|
||||
@@ -101,15 +100,15 @@ app.whenReady().then(() => {
|
||||
createWindow()
|
||||
})
|
||||
|
||||
// Handle the protocol. In this case, we choose to show an Error Box.
|
||||
// handling the protocol. In this case, we choose to show an Error Box.
|
||||
app.on('open-url', (event, url) => {
|
||||
dialog.showErrorBox('Welcome Back', `You arrived from: ${url}`)
|
||||
})
|
||||
```
|
||||
|
||||
Finally, we will add some additional code to handle when someone closes our application.
|
||||
Finally, we will add some additional code to handle when someone closes our application
|
||||
|
||||
```javascript
|
||||
```js
|
||||
// Quit when all windows are closed, except on macOS. There, it's common
|
||||
// for applications and their menu bar to stay active until the user quits
|
||||
// explicitly with Cmd + Q.
|
||||
@@ -118,84 +117,46 @@ app.on('window-all-closed', () => {
|
||||
})
|
||||
```
|
||||
|
||||
## Important notes
|
||||
## Important Note:
|
||||
|
||||
### Packaging
|
||||
|
||||
On macOS and Linux, this feature will only work when your app is packaged. It will not work when
|
||||
you're launching it in development from the command-line. When you package your app you'll need to
|
||||
make sure the macOS `Info.plist` and the Linux `.desktop` files for the app are updated to include
|
||||
the new protocol handler. Some of the Electron tools for bundling and distributing apps handle
|
||||
this for you.
|
||||
This feature will only work on macOS when your app is packaged. It will not work when you're launching it in development from the command-line. When you package your app you'll need to make sure the macOS `plist` for the app is updated to include the new protocol handler. If you're using [`electron-packager`](https://github.com/electron/electron-packager) then you
|
||||
can add the flag `--extend-info` with a path to the `plist` you've created. The one for this app is below:
|
||||
|
||||
#### [Electron Forge](https://electronforge.io)
|
||||
### Plist
|
||||
|
||||
If you're using Electron Forge, adjust `packagerConfig` for macOS support, and the configuration for
|
||||
the appropriate Linux makers for Linux support, in your [Forge
|
||||
configuration](https://www.electronforge.io/configuration) _(please note the following example only
|
||||
shows the bare minimum needed to add the configuration changes)_:
|
||||
|
||||
```json
|
||||
{
|
||||
"config": {
|
||||
"forge": {
|
||||
"packagerConfig": {
|
||||
"protocols": [
|
||||
{
|
||||
"name": "Electron Fiddle",
|
||||
"schemes": ["electron-fiddle"]
|
||||
}
|
||||
]
|
||||
},
|
||||
"makers": [
|
||||
{
|
||||
"name": "@electron-forge/maker-deb",
|
||||
"config": {
|
||||
"mimeType": ["x-scheme-handler/electron-fiddle"]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### [Electron Packager](https://github.com/electron/electron-packager)
|
||||
|
||||
For macOS support:
|
||||
|
||||
If you're using Electron Packager's API, adding support for protocol handlers is similar to how
|
||||
Electron Forge is handled, except
|
||||
`protocols` is part of the Packager options passed to the `packager` function.
|
||||
|
||||
```javascript
|
||||
const packager = require('electron-packager')
|
||||
|
||||
packager({
|
||||
// ...other options...
|
||||
protocols: [
|
||||
{
|
||||
name: 'Electron Fiddle',
|
||||
schemes: ['electron-fiddle']
|
||||
}
|
||||
]
|
||||
|
||||
}).then(paths => console.log(`SUCCESS: Created ${paths.join(', ')}`))
|
||||
.catch(err => console.error(`ERROR: ${err.message}`))
|
||||
```
|
||||
|
||||
If you're using Electron Packager's CLI, use the `--protocol` and `--protocol-name` flags. For
|
||||
example:
|
||||
|
||||
```shell
|
||||
npx electron-packager . --protocol=electron-fiddle --protocol-name="Electron Fiddle"
|
||||
```XML
|
||||
<p>
|
||||
<h5>macOS plist</h5>
|
||||
<pre><code>
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleURLTypes</key>
|
||||
<array>
|
||||
<dict>
|
||||
<key>CFBundleURLSchemes</key>
|
||||
<array>
|
||||
<string>electron-api-demos</string>
|
||||
</array>
|
||||
<key>CFBundleURLName</key>
|
||||
<string>Electron API Demos Protocol</string>
|
||||
</dict>
|
||||
</array>
|
||||
<key>ElectronTeamID</key>
|
||||
<string>VEKTX9H2N7</string>
|
||||
</dict>
|
||||
</plist>
|
||||
</code>
|
||||
</pre>
|
||||
<p>
|
||||
```
|
||||
|
||||
## Conclusion
|
||||
|
||||
After you start your Electron app, you can enter in a URL in your browser that contains the custom
|
||||
protocol, for example `"electron-fiddle://open"` and observe that the application will respond and
|
||||
show an error dialog box.
|
||||
After you start your electron app, you can now enter in a URL in your browser that contains the custom protocol, for example `"electron-fiddle://open"` and observe that the application will respond and show an error dialog box.
|
||||
|
||||
<!--
|
||||
Because Electron examples usually require multiple files (HTML, CSS, JS
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# Desktop Launcher Actions (Linux)
|
||||
# Custom Linux Desktop Launcher Actions
|
||||
|
||||
## Overview
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# Dock (macOS)
|
||||
# Configuring the macOS Dock
|
||||
|
||||
Electron has APIs to configure the app's icon in the macOS Dock. A macOS-only
|
||||
API exists to create a custom dock menu, but Electron also uses the app dock
|
||||
@@ -25,7 +25,7 @@ Starting with a working application from the
|
||||
```javascript fiddle='docs/fiddles/features/macos-dock-menu'
|
||||
const { app, BrowserWindow, Menu } = require('electron')
|
||||
|
||||
function createWindow () {
|
||||
const createWindow = () => {
|
||||
const win = new BrowserWindow({
|
||||
width: 800,
|
||||
height: 600,
|
||||
|
||||
@@ -134,7 +134,7 @@ app.whenReady().then(async () => {
|
||||
<script>
|
||||
const { ipcRenderer } = require('electron')
|
||||
|
||||
function doWork(input) {
|
||||
const doWork = (input) => {
|
||||
// Something cpu-intensive.
|
||||
return input * 2
|
||||
}
|
||||
@@ -185,7 +185,7 @@ stream of data.
|
||||
```js
|
||||
// renderer.js ///////////////////////////////////////////////////////////////
|
||||
|
||||
function makeStreamingRequest (element, callback) {
|
||||
const makeStreamingRequest = (element, callback) => {
|
||||
// MessageChannels are lightweight--it's cheap to create a new one for each
|
||||
// request.
|
||||
const { port1, port2 } = new MessageChannel()
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# Notifications
|
||||
# Notifications (Windows, Linux, macOS)
|
||||
|
||||
## Overview
|
||||
|
||||
@@ -54,7 +54,7 @@ const { Notification } = require('electron')
|
||||
const NOTIFICATION_TITLE = 'Basic Notification'
|
||||
const NOTIFICATION_BODY = 'Notification from the Main process'
|
||||
|
||||
function showNotification () {
|
||||
const showNotification = () => {
|
||||
new Notification({ title: NOTIFICATION_TITLE, body: NOTIFICATION_BODY }).show()
|
||||
}
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@ the dirty area is passed to the `paint` event to be more efficient.
|
||||
losses with no benefits.
|
||||
* When nothing is happening on a webpage, no frames are generated.
|
||||
* An offscreen window is always created as a
|
||||
[Frameless Window](../tutorial/window-customization.md)..
|
||||
[Frameless Window](../api/frameless-window.md).
|
||||
|
||||
### Rendering Modes
|
||||
|
||||
|
||||
@@ -41,7 +41,7 @@ Starting with an HTML file `index.html`, this example will demonstrate how the `
|
||||
In order to mutate the DOM, create a `renderer.js` file that adds event listeners to the `'online'` and `'offline'` `window` events. The event handler sets the content of the `<strong id='status'>` element depending on the result of `navigator.onLine`.
|
||||
|
||||
```js title='renderer.js'
|
||||
function updateOnlineStatus () {
|
||||
const updateOnlineStatus = () => {
|
||||
document.getElementById('status').innerHTML = navigator.onLine ? 'online' : 'offline'
|
||||
}
|
||||
|
||||
@@ -56,7 +56,7 @@ Finally, create a `main.js` file for main process that creates the window.
|
||||
```js title='main.js'
|
||||
const { app, BrowserWindow } = require('electron')
|
||||
|
||||
function createWindow () {
|
||||
const createWindow = () => {
|
||||
const onlineStatusWindow = new BrowserWindow({
|
||||
width: 400,
|
||||
height: 100
|
||||
|
||||
@@ -120,9 +120,9 @@ file in the directory you executed it in. Both files can be analyzed using
|
||||
the Chrome Developer Tools, using the `Performance` and `Memory` tabs
|
||||
respectively.
|
||||
|
||||

|
||||
![Performance CPU Profile][performance-cpu-prof]
|
||||
|
||||

|
||||
![Performance Heap Memory Profile][performance-heap-prof]
|
||||
|
||||
In this example, on the author's machine, we saw that loading `request` took
|
||||
almost half a second, whereas `node-fetch` took dramatically less memory
|
||||
@@ -412,6 +412,8 @@ As of writing this article, the popular choices include [Webpack][webpack],
|
||||
[Parcel][parcel], and [rollup.js][rollup].
|
||||
|
||||
[security]: ./security.md
|
||||
[performance-cpu-prof]: ../images/performance-cpu-prof.png
|
||||
[performance-heap-prof]: ../images/performance-heap-prof.png
|
||||
[chrome-devtools-tutorial]: https://developers.google.com/web/tools/chrome-devtools/evaluate-performance/
|
||||
[worker-threads]: https://nodejs.org/api/worker_threads.html
|
||||
[web-workers]: https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Using_web_workers
|
||||
|
||||
@@ -83,8 +83,8 @@ As a practical example, the app shown in the [quick start guide][quick-start-lif
|
||||
uses `app` APIs to create a more native application window experience.
|
||||
|
||||
```js title='main.js'
|
||||
// quitting the app when no windows are open on non-macOS platforms
|
||||
app.on('window-all-closed', function () {
|
||||
// quitting the app when no windows are open on macOS
|
||||
app.on('window-all-closed', () => {
|
||||
if (process.platform !== 'darwin') app.quit()
|
||||
})
|
||||
```
|
||||
@@ -148,9 +148,7 @@ A preload script can be attached to the main process in the `BrowserWindow` cons
|
||||
const { BrowserWindow } = require('electron')
|
||||
//...
|
||||
const win = new BrowserWindow({
|
||||
webPreferences: {
|
||||
preload: 'path/to/preload.js'
|
||||
}
|
||||
preload: 'path/to/preload.js'
|
||||
})
|
||||
//...
|
||||
```
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user