mirror of
https://github.com/electron/electron.git
synced 2026-02-26 03:01:17 -05:00
Compare commits
332 Commits
refactor/a
...
v8.2.3
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
663d389925 | ||
|
|
b8e3477092 | ||
|
|
035c784b6c | ||
|
|
8faf8a3535 | ||
|
|
331125d35a | ||
|
|
7316ebde79 | ||
|
|
c3340ad21c | ||
|
|
1e84816c96 | ||
|
|
58c6ea5de8 | ||
|
|
34be80602c | ||
|
|
ce40be475b | ||
|
|
5f7bd36119 | ||
|
|
0f19193afd | ||
|
|
06b3b0ea15 | ||
|
|
32f973b010 | ||
|
|
ad2c2a055b | ||
|
|
3069ef3827 | ||
|
|
d70b1c68fe | ||
|
|
3ba4a35c9c | ||
|
|
2c4c1a3dd9 | ||
|
|
a4d8974556 | ||
|
|
b7d4759c19 | ||
|
|
d6ecc65df3 | ||
|
|
98b67cdb69 | ||
|
|
eb37822e03 | ||
|
|
8751f485c5 | ||
|
|
bfef6a54f0 | ||
|
|
5fd403b571 | ||
|
|
abe8c7168a | ||
|
|
5c32d18248 | ||
|
|
c1da7b5238 | ||
|
|
5b75a4a4be | ||
|
|
57e36afc7e | ||
|
|
a4ea27de36 | ||
|
|
7ba879711a | ||
|
|
f057b0e494 | ||
|
|
fa01a20f9b | ||
|
|
579f7a1899 | ||
|
|
920a82a4de | ||
|
|
b501c40bd6 | ||
|
|
672aa1c67f | ||
|
|
b305784aa3 | ||
|
|
c4efeef92c | ||
|
|
96b41d0930 | ||
|
|
1f652f08f8 | ||
|
|
d12c157242 | ||
|
|
68873fbadb | ||
|
|
526d748b7e | ||
|
|
54109cb04d | ||
|
|
542f30b54b | ||
|
|
07ea340314 | ||
|
|
524d6a5d79 | ||
|
|
a0431e1265 | ||
|
|
647299fa9f | ||
|
|
ee5d52440b | ||
|
|
d4a79bc4c0 | ||
|
|
e37f69c467 | ||
|
|
df6faec72e | ||
|
|
691ddb3f67 | ||
|
|
b4e1b840cd | ||
|
|
6f12b67582 | ||
|
|
33f5fa3c56 | ||
|
|
6f88108132 | ||
|
|
05a7f5f492 | ||
|
|
b878a5ea4c | ||
|
|
8756ff0349 | ||
|
|
20c5a3b9e1 | ||
|
|
ddb62e8d7c | ||
|
|
077e35c576 | ||
|
|
eb63062889 | ||
|
|
cac6db76a0 | ||
|
|
9257c315ac | ||
|
|
031480c3db | ||
|
|
9f9d3e98bf | ||
|
|
ae639186e3 | ||
|
|
6e4690574d | ||
|
|
c83dc5be92 | ||
|
|
63cb360df0 | ||
|
|
b311235165 | ||
|
|
6cd2623a87 | ||
|
|
9aa81de83d | ||
|
|
0f246b6be7 | ||
|
|
5be76fd4ea | ||
|
|
a315283f88 | ||
|
|
b741cbf3d7 | ||
|
|
031c0d6951 | ||
|
|
3639a82915 | ||
|
|
7fe2cad354 | ||
|
|
de2e12343e | ||
|
|
69598ae5c6 | ||
|
|
0f0a7e6b1e | ||
|
|
a0dcb55d6c | ||
|
|
ee35482d97 | ||
|
|
8317553cd4 | ||
|
|
ebf98e8af4 | ||
|
|
cfe350a534 | ||
|
|
854dcb3247 | ||
|
|
882ce295ee | ||
|
|
1ac31e18b7 | ||
|
|
957717e483 | ||
|
|
d1ccfea882 | ||
|
|
232ca04edd | ||
|
|
2888e46b7a | ||
|
|
4464a04f35 | ||
|
|
37baff1e31 | ||
|
|
dde19b0583 | ||
|
|
e2b9cd7b7c | ||
|
|
ecd398f8bd | ||
|
|
21f544392b | ||
|
|
5c93682a89 | ||
|
|
1db64c9e51 | ||
|
|
3a747eddbb | ||
|
|
51504aee64 | ||
|
|
360e8a2eb8 | ||
|
|
4447a63f20 | ||
|
|
ceb3b0cf54 | ||
|
|
89607e647d | ||
|
|
c8e2a6261e | ||
|
|
e9814e016b | ||
|
|
dc9654c03c | ||
|
|
fce3426675 | ||
|
|
637cf8a02b | ||
|
|
daab432fb6 | ||
|
|
50dac1d908 | ||
|
|
d4f915e428 | ||
|
|
72bccd1305 | ||
|
|
9439388b7b | ||
|
|
b0fee4b067 | ||
|
|
7c33fc0c5c | ||
|
|
f263a3f755 | ||
|
|
1af3a71fdb | ||
|
|
9f2371fc4e | ||
|
|
f658c1aeb4 | ||
|
|
c196121467 | ||
|
|
133ac9a323 | ||
|
|
a326408bce | ||
|
|
2085111c43 | ||
|
|
7ae8d54265 | ||
|
|
c5574c8667 | ||
|
|
6cf8abc3b3 | ||
|
|
46a4864b08 | ||
|
|
7956b45323 | ||
|
|
63bcbd4ff5 | ||
|
|
3b5ca91a40 | ||
|
|
80282ba972 | ||
|
|
7ddb3dd184 | ||
|
|
0cee5cc1c1 | ||
|
|
048d770a0e | ||
|
|
b3fdb242f0 | ||
|
|
38d908ee6a | ||
|
|
416b850dd2 | ||
|
|
714e068cba | ||
|
|
0a0689587a | ||
|
|
83c4633b21 | ||
|
|
a33063c8a7 | ||
|
|
c478d45713 | ||
|
|
74686a9cb3 | ||
|
|
473a90f99f | ||
|
|
15e9f22fda | ||
|
|
ee44155f7a | ||
|
|
bf64b34475 | ||
|
|
26dbd2218e | ||
|
|
38e46abf0b | ||
|
|
67f7bf4a23 | ||
|
|
02f040c765 | ||
|
|
9b841e4594 | ||
|
|
a40957f2bc | ||
|
|
a6121f527c | ||
|
|
71a31d553f | ||
|
|
1a309fd55f | ||
|
|
73527e54c5 | ||
|
|
2ef0827767 | ||
|
|
76bcab07e6 | ||
|
|
5a5b6abd2c | ||
|
|
4ce5a48076 | ||
|
|
7b61e6044a | ||
|
|
048f06c7f5 | ||
|
|
06868c938f | ||
|
|
22e8fc6379 | ||
|
|
427c139eff | ||
|
|
6a881520ee | ||
|
|
5a2c451c0b | ||
|
|
f47fbccf1a | ||
|
|
eb419946ad | ||
|
|
1b204a4369 | ||
|
|
ee2de310f5 | ||
|
|
e81aa83a14 | ||
|
|
96cae44f32 | ||
|
|
757e7a91a9 | ||
|
|
6faef05095 | ||
|
|
ee65a190fa | ||
|
|
da45f0341a | ||
|
|
c6517c0b7f | ||
|
|
2c92573978 | ||
|
|
fa7326af64 | ||
|
|
aca96553fc | ||
|
|
37592cdaee | ||
|
|
64e48ad0e6 | ||
|
|
68566583f0 | ||
|
|
6a56aa2240 | ||
|
|
7e8c1108e0 | ||
|
|
f5ce5f8218 | ||
|
|
28e44b31ca | ||
|
|
606ca98df0 | ||
|
|
acd2eabdfd | ||
|
|
07972c2892 | ||
|
|
70079d1c8a | ||
|
|
4def69876f | ||
|
|
61a2c7bd16 | ||
|
|
f53262d58f | ||
|
|
8c15619905 | ||
|
|
4a66bed930 | ||
|
|
8dabb3fe33 | ||
|
|
3f88934025 | ||
|
|
296dcc3405 | ||
|
|
5f6de7053a | ||
|
|
6c1eb46f68 | ||
|
|
05cde0d945 | ||
|
|
696c94c08a | ||
|
|
4284691cb3 | ||
|
|
2ab56802cb | ||
|
|
353d12b231 | ||
|
|
cbd734faf9 | ||
|
|
cf282c177f | ||
|
|
e8c8afb1b4 | ||
|
|
dd0d06448c | ||
|
|
3527fdc291 | ||
|
|
a6b9d68897 | ||
|
|
e1e7ec737f | ||
|
|
4fd03f59f4 | ||
|
|
e64e0f00ca | ||
|
|
1bfead2f6b | ||
|
|
c79f1ee720 | ||
|
|
e18c369e4a | ||
|
|
1953ab3bf2 | ||
|
|
d998bf9fed | ||
|
|
40eff3a778 | ||
|
|
9dd089fc56 | ||
|
|
5e2bd0e55f | ||
|
|
95b8be4cc4 | ||
|
|
d48f99fd6e | ||
|
|
3a9b934cc5 | ||
|
|
768f372675 | ||
|
|
9e3f0d5190 | ||
|
|
5a297f409f | ||
|
|
57335cea69 | ||
|
|
3331f51571 | ||
|
|
f122268ca8 | ||
|
|
bfc817fd28 | ||
|
|
2bd83d0e89 | ||
|
|
f29f3418ed | ||
|
|
c87a0077dd | ||
|
|
23c1dcea46 | ||
|
|
41e64d2469 | ||
|
|
5fdc24d3bf | ||
|
|
64dc86c8c2 | ||
|
|
9d1ec6b0eb | ||
|
|
8919480ebc | ||
|
|
bb9e68beee | ||
|
|
88c1f2caf7 | ||
|
|
88375be2b2 | ||
|
|
2aa69505f9 | ||
|
|
e78fe7c8da | ||
|
|
7a7b944c74 | ||
|
|
09f5a2b741 | ||
|
|
cbf50eabd9 | ||
|
|
90a74139c1 | ||
|
|
3a6cc1b786 | ||
|
|
f5fde13b14 | ||
|
|
c6d429d533 | ||
|
|
73df925241 | ||
|
|
269f4ba2bb | ||
|
|
9b304beb54 | ||
|
|
5ffad09e91 | ||
|
|
b694315cd3 | ||
|
|
8566315902 | ||
|
|
cd94ab9de3 | ||
|
|
09ebadaf5b | ||
|
|
990189ab35 | ||
|
|
049e536c5f | ||
|
|
7fe2f25341 | ||
|
|
c79809ddb9 | ||
|
|
b3edf86914 | ||
|
|
7044122f5d | ||
|
|
b7bcce9576 | ||
|
|
2560776888 | ||
|
|
d5d5fef931 | ||
|
|
6b158872fc | ||
|
|
a4ef2d4356 | ||
|
|
14cc902ad8 | ||
|
|
a62a367b9f | ||
|
|
8d67f16512 | ||
|
|
59cb78e9aa | ||
|
|
032552df57 | ||
|
|
1913926ebc | ||
|
|
dc979388ba | ||
|
|
bcabc25b93 | ||
|
|
ab6d22c958 | ||
|
|
806925ee79 | ||
|
|
a46b50fc7b | ||
|
|
517a5915d7 | ||
|
|
1de38af8cc | ||
|
|
66a95db3df | ||
|
|
7b779c6e6a | ||
|
|
429dfd7054 | ||
|
|
03f7a85cfb | ||
|
|
2d2a753dd9 | ||
|
|
028e3889f0 | ||
|
|
47eb123649 | ||
|
|
45ab098079 | ||
|
|
6cfc05ded2 | ||
|
|
40e0e8e499 | ||
|
|
beff8b8b51 | ||
|
|
311723396a | ||
|
|
d39d75321a | ||
|
|
55201d7db6 | ||
|
|
ac46d5b16e | ||
|
|
a1fb069624 | ||
|
|
3aa33dd220 | ||
|
|
9b74d0d54a | ||
|
|
018fc2ca46 | ||
|
|
e286b78df7 | ||
|
|
f77bd19a70 | ||
|
|
cff63d32a0 | ||
|
|
a8e7696674 | ||
|
|
5fc689dc4e | ||
|
|
895bdc0ee0 | ||
|
|
c99f1d317e | ||
|
|
315e3e325d | ||
|
|
8acce4279b | ||
|
|
c8943cdc3c | ||
|
|
f74f009648 |
File diff suppressed because it is too large
Load Diff
@@ -6,9 +6,11 @@
|
|||||||
"browser": true
|
"browser": true
|
||||||
},
|
},
|
||||||
"rules": {
|
"rules": {
|
||||||
|
"semi": ["error", "always"],
|
||||||
"no-var": "error",
|
"no-var": "error",
|
||||||
"no-unused-vars": 0,
|
"no-unused-vars": 0,
|
||||||
"no-global-assign": 0,
|
"no-global-assign": 0,
|
||||||
|
"guard-for-in": 2,
|
||||||
"@typescript-eslint/no-unused-vars": ["error", {
|
"@typescript-eslint/no-unused-vars": ["error", {
|
||||||
"vars": "all",
|
"vars": "all",
|
||||||
"args": "after-used",
|
"args": "after-used",
|
||||||
|
|||||||
1
.gitattributes
vendored
1
.gitattributes
vendored
@@ -1,3 +1,4 @@
|
|||||||
# `git apply` and friends don't understand CRLF, even on windows. Force those
|
# `git apply` and friends don't understand CRLF, even on windows. Force those
|
||||||
# files to be checked out with LF endings even if core.autocrlf is true.
|
# files to be checked out with LF endings even if core.autocrlf is true.
|
||||||
*.patch text eol=lf
|
*.patch text eol=lf
|
||||||
|
patches/**/.patches merge=union
|
||||||
|
|||||||
105
BUILD.gn
105
BUILD.gn
@@ -1,6 +1,7 @@
|
|||||||
import("//build/config/locales.gni")
|
import("//build/config/locales.gni")
|
||||||
import("//build/config/ui.gni")
|
import("//build/config/ui.gni")
|
||||||
import("//build/config/win/manifest.gni")
|
import("//build/config/win/manifest.gni")
|
||||||
|
import("//components/spellcheck/spellcheck_build_features.gni")
|
||||||
import("//content/public/app/mac_helpers.gni")
|
import("//content/public/app/mac_helpers.gni")
|
||||||
import("//pdf/features.gni")
|
import("//pdf/features.gni")
|
||||||
import("//printing/buildflags/buildflags.gni")
|
import("//printing/buildflags/buildflags.gni")
|
||||||
@@ -21,6 +22,7 @@ import("buildflags/buildflags.gni")
|
|||||||
import("electron_paks.gni")
|
import("electron_paks.gni")
|
||||||
import("filenames.auto.gni")
|
import("filenames.auto.gni")
|
||||||
import("filenames.gni")
|
import("filenames.gni")
|
||||||
|
import("filenames.hunspell.gni")
|
||||||
|
|
||||||
if (is_mac) {
|
if (is_mac) {
|
||||||
import("//build/config/mac/rules.gni")
|
import("//build/config/mac/rules.gni")
|
||||||
@@ -147,7 +149,7 @@ webpack_build("electron_content_script_bundle") {
|
|||||||
out_file = "$target_gen_dir/js2c/content_script_bundle.js"
|
out_file = "$target_gen_dir/js2c/content_script_bundle.js"
|
||||||
}
|
}
|
||||||
|
|
||||||
copy("atom_js2c_copy") {
|
copy("electron_js2c_copy") {
|
||||||
sources = [
|
sources = [
|
||||||
"lib/common/asar.js",
|
"lib/common/asar.js",
|
||||||
"lib/common/asar_init.js",
|
"lib/common/asar_init.js",
|
||||||
@@ -157,12 +159,12 @@ copy("atom_js2c_copy") {
|
|||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
action("atom_js2c") {
|
action("electron_js2c") {
|
||||||
deps = [
|
deps = [
|
||||||
":atom_js2c_copy",
|
|
||||||
":electron_browser_bundle",
|
":electron_browser_bundle",
|
||||||
":electron_content_script_bundle",
|
":electron_content_script_bundle",
|
||||||
":electron_isolated_renderer_bundle",
|
":electron_isolated_renderer_bundle",
|
||||||
|
":electron_js2c_copy",
|
||||||
":electron_renderer_bundle",
|
":electron_renderer_bundle",
|
||||||
":electron_sandboxed_renderer_bundle",
|
":electron_sandboxed_renderer_bundle",
|
||||||
":electron_worker_bundle",
|
":electron_worker_bundle",
|
||||||
@@ -184,7 +186,7 @@ action("atom_js2c") {
|
|||||||
|
|
||||||
inputs = sources + [ "//third_party/electron_node/tools/js2c.py" ]
|
inputs = sources + [ "//third_party/electron_node/tools/js2c.py" ]
|
||||||
outputs = [
|
outputs = [
|
||||||
"$root_gen_dir/atom_natives.cc",
|
"$root_gen_dir/electron_natives.cc",
|
||||||
]
|
]
|
||||||
|
|
||||||
script = "tools/js2c.py"
|
script = "tools/js2c.py"
|
||||||
@@ -345,12 +347,13 @@ source_set("electron_lib") {
|
|||||||
]
|
]
|
||||||
|
|
||||||
deps = [
|
deps = [
|
||||||
":atom_js2c",
|
":electron_js2c",
|
||||||
":electron_version_header",
|
":electron_version_header",
|
||||||
":manifests",
|
":manifests",
|
||||||
":resources",
|
":resources",
|
||||||
"buildflags",
|
"buildflags",
|
||||||
"chromium_src:chrome",
|
"chromium_src:chrome",
|
||||||
|
"chromium_src:chrome_spellchecker",
|
||||||
"native_mate",
|
"native_mate",
|
||||||
"shell/common/api:mojo",
|
"shell/common/api:mojo",
|
||||||
"//base:base_static",
|
"//base:base_static",
|
||||||
@@ -358,12 +361,13 @@ source_set("electron_lib") {
|
|||||||
"//chrome/app/resources:platform_locale_settings",
|
"//chrome/app/resources:platform_locale_settings",
|
||||||
"//chrome/services/printing/public/mojom",
|
"//chrome/services/printing/public/mojom",
|
||||||
"//components/certificate_transparency",
|
"//components/certificate_transparency",
|
||||||
|
"//components/language/core/browser",
|
||||||
"//components/net_log",
|
"//components/net_log",
|
||||||
"//components/network_hints/common",
|
"//components/network_hints/browser",
|
||||||
|
"//components/network_hints/common:mojo_bindings",
|
||||||
"//components/network_hints/renderer",
|
"//components/network_hints/renderer",
|
||||||
"//components/network_session_configurator/common",
|
"//components/network_session_configurator/common",
|
||||||
"//components/prefs",
|
"//components/prefs",
|
||||||
"//components/spellcheck/renderer",
|
|
||||||
"//components/viz/host",
|
"//components/viz/host",
|
||||||
"//components/viz/service",
|
"//components/viz/service",
|
||||||
"//content/public/browser",
|
"//content/public/browser",
|
||||||
@@ -379,12 +383,10 @@ source_set("electron_lib") {
|
|||||||
"//media/mojo/mojom",
|
"//media/mojo/mojom",
|
||||||
"//net:extras",
|
"//net:extras",
|
||||||
"//net:net_resources",
|
"//net:net_resources",
|
||||||
"//net:net_with_v8",
|
|
||||||
"//ppapi/host",
|
"//ppapi/host",
|
||||||
"//ppapi/proxy",
|
"//ppapi/proxy",
|
||||||
"//ppapi/shared_impl",
|
"//ppapi/shared_impl",
|
||||||
"//printing/buildflags",
|
"//printing/buildflags",
|
||||||
"//services/audio/public/mojom:constants",
|
|
||||||
"//services/device/public/cpp/geolocation",
|
"//services/device/public/cpp/geolocation",
|
||||||
"//services/device/public/mojom",
|
"//services/device/public/mojom",
|
||||||
"//services/proxy_resolver:lib",
|
"//services/proxy_resolver:lib",
|
||||||
@@ -396,7 +398,7 @@ source_set("electron_lib") {
|
|||||||
"//third_party/electron_node:node_lib",
|
"//third_party/electron_node:node_lib",
|
||||||
"//third_party/leveldatabase",
|
"//third_party/leveldatabase",
|
||||||
"//third_party/libyuv",
|
"//third_party/libyuv",
|
||||||
"//third_party/webrtc_overrides:init_webrtc",
|
"//third_party/webrtc_overrides:webrtc_component",
|
||||||
"//third_party/widevine/cdm:headers",
|
"//third_party/widevine/cdm:headers",
|
||||||
"//ui/base/idle",
|
"//ui/base/idle",
|
||||||
"//ui/events:dom_keycode_converter",
|
"//ui/events:dom_keycode_converter",
|
||||||
@@ -502,7 +504,7 @@ source_set("electron_lib") {
|
|||||||
"shell/browser/ui/views/autofill_popup_view.h",
|
"shell/browser/ui/views/autofill_popup_view.h",
|
||||||
]
|
]
|
||||||
if (is_mas_build) {
|
if (is_mas_build) {
|
||||||
sources += [ "shell/browser/api/atom_api_app_mas.mm" ]
|
sources += [ "shell/browser/api/electron_api_app_mas.mm" ]
|
||||||
sources -= [
|
sources -= [
|
||||||
"shell/browser/auto_updater_mac.mm",
|
"shell/browser/auto_updater_mac.mm",
|
||||||
"shell/common/crash_reporter/crash_reporter_mac.h",
|
"shell/common/crash_reporter/crash_reporter_mac.h",
|
||||||
@@ -546,6 +548,10 @@ source_set("electron_lib") {
|
|||||||
]
|
]
|
||||||
|
|
||||||
sources += filenames.lib_sources_nss
|
sources += filenames.lib_sources_nss
|
||||||
|
sources += [
|
||||||
|
"shell/browser/ui/gtk_util.cc",
|
||||||
|
"shell/browser/ui/gtk_util.h",
|
||||||
|
]
|
||||||
}
|
}
|
||||||
if (is_win) {
|
if (is_win) {
|
||||||
libs += [ "dwmapi.lib" ]
|
libs += [ "dwmapi.lib" ]
|
||||||
@@ -621,27 +627,27 @@ source_set("electron_lib") {
|
|||||||
deps += [ "//third_party/webrtc/modules/desktop_capture" ]
|
deps += [ "//third_party/webrtc/modules/desktop_capture" ]
|
||||||
}
|
}
|
||||||
sources += [
|
sources += [
|
||||||
"shell/browser/api/atom_api_desktop_capturer.cc",
|
"shell/browser/api/electron_api_desktop_capturer.cc",
|
||||||
"shell/browser/api/atom_api_desktop_capturer.h",
|
"shell/browser/api/electron_api_desktop_capturer.h",
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
if (enable_view_api) {
|
if (enable_view_api) {
|
||||||
sources += [
|
sources += [
|
||||||
"shell/browser/api/views/atom_api_box_layout.cc",
|
"shell/browser/api/views/electron_api_box_layout.cc",
|
||||||
"shell/browser/api/views/atom_api_box_layout.h",
|
"shell/browser/api/views/electron_api_box_layout.h",
|
||||||
"shell/browser/api/views/atom_api_button.cc",
|
"shell/browser/api/views/electron_api_button.cc",
|
||||||
"shell/browser/api/views/atom_api_button.h",
|
"shell/browser/api/views/electron_api_button.h",
|
||||||
"shell/browser/api/views/atom_api_label_button.cc",
|
"shell/browser/api/views/electron_api_label_button.cc",
|
||||||
"shell/browser/api/views/atom_api_label_button.h",
|
"shell/browser/api/views/electron_api_label_button.h",
|
||||||
"shell/browser/api/views/atom_api_layout_manager.cc",
|
"shell/browser/api/views/electron_api_layout_manager.cc",
|
||||||
"shell/browser/api/views/atom_api_layout_manager.h",
|
"shell/browser/api/views/electron_api_layout_manager.h",
|
||||||
"shell/browser/api/views/atom_api_md_text_button.cc",
|
"shell/browser/api/views/electron_api_md_text_button.cc",
|
||||||
"shell/browser/api/views/atom_api_md_text_button.h",
|
"shell/browser/api/views/electron_api_md_text_button.h",
|
||||||
"shell/browser/api/views/atom_api_resize_area.cc",
|
"shell/browser/api/views/electron_api_resize_area.cc",
|
||||||
"shell/browser/api/views/atom_api_resize_area.h",
|
"shell/browser/api/views/electron_api_resize_area.h",
|
||||||
"shell/browser/api/views/atom_api_text_field.cc",
|
"shell/browser/api/views/electron_api_text_field.cc",
|
||||||
"shell/browser/api/views/atom_api_text_field.h",
|
"shell/browser/api/views/electron_api_text_field.h",
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -705,7 +711,6 @@ if (is_mac) {
|
|||||||
public_deps += [ "//third_party/icu:icudata" ]
|
public_deps += [ "//third_party/icu:icudata" ]
|
||||||
}
|
}
|
||||||
if (v8_use_external_startup_data) {
|
if (v8_use_external_startup_data) {
|
||||||
sources += [ "$root_out_dir/natives_blob.bin" ]
|
|
||||||
public_deps += [ "//v8" ]
|
public_deps += [ "//v8" ]
|
||||||
if (use_v8_context_snapshot) {
|
if (use_v8_context_snapshot) {
|
||||||
sources += [ "$root_out_dir/v8_context_snapshot.bin" ]
|
sources += [ "$root_out_dir/v8_context_snapshot.bin" ]
|
||||||
@@ -824,6 +829,7 @@ if (is_mac) {
|
|||||||
|
|
||||||
include_dirs = [ "." ]
|
include_dirs = [ "." ]
|
||||||
sources = filenames.framework_sources
|
sources = filenames.framework_sources
|
||||||
|
libs = []
|
||||||
|
|
||||||
if (enable_osr) {
|
if (enable_osr) {
|
||||||
libs += [ "IOSurface.framework" ]
|
libs += [ "IOSurface.framework" ]
|
||||||
@@ -857,7 +863,7 @@ if (is_mac) {
|
|||||||
}
|
}
|
||||||
defines = [ "HELPER_EXECUTABLE" ]
|
defines = [ "HELPER_EXECUTABLE" ]
|
||||||
sources = filenames.app_sources
|
sources = filenames.app_sources
|
||||||
sources += [ "shell/common/atom_constants.cc" ]
|
sources += [ "shell/common/electron_constants.cc" ]
|
||||||
include_dirs = [ "." ]
|
include_dirs = [ "." ]
|
||||||
info_plist = "shell/renderer/resources/mac/Info.plist"
|
info_plist = "shell/renderer/resources/mac/Info.plist"
|
||||||
extra_substitutions =
|
extra_substitutions =
|
||||||
@@ -978,7 +984,7 @@ if (is_mac) {
|
|||||||
mac_app_bundle("electron_app") {
|
mac_app_bundle("electron_app") {
|
||||||
output_name = electron_product_name
|
output_name = electron_product_name
|
||||||
sources = filenames.app_sources
|
sources = filenames.app_sources
|
||||||
sources += [ "shell/common/atom_constants.cc" ]
|
sources += [ "shell/common/electron_constants.cc" ]
|
||||||
include_dirs = [ "." ]
|
include_dirs = [ "." ]
|
||||||
deps = [
|
deps = [
|
||||||
":electron_app_framework_bundle_data",
|
":electron_app_framework_bundle_data",
|
||||||
@@ -1265,9 +1271,14 @@ template("dist_zip") {
|
|||||||
"outputs",
|
"outputs",
|
||||||
"testonly",
|
"testonly",
|
||||||
])
|
])
|
||||||
|
flatten = false
|
||||||
|
if (defined(invoker.flatten)) {
|
||||||
|
flatten = invoker.flatten
|
||||||
|
}
|
||||||
args = rebase_path(outputs + [ _runtime_deps_file ], root_build_dir) + [
|
args = rebase_path(outputs + [ _runtime_deps_file ], root_build_dir) + [
|
||||||
target_cpu,
|
target_cpu,
|
||||||
target_os,
|
target_os,
|
||||||
|
"$flatten",
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1342,17 +1353,41 @@ dist_zip("electron_chromedriver_zip") {
|
|||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mksnapshot_deps = [
|
||||||
|
":licenses",
|
||||||
|
"//tools/v8_context_snapshot:v8_context_snapshot_generator",
|
||||||
|
"//v8:mksnapshot($v8_snapshot_toolchain)",
|
||||||
|
]
|
||||||
|
|
||||||
|
group("electron_mksnapshot") {
|
||||||
|
public_deps = mksnapshot_deps
|
||||||
|
}
|
||||||
|
|
||||||
dist_zip("electron_mksnapshot_zip") {
|
dist_zip("electron_mksnapshot_zip") {
|
||||||
data_deps = [
|
data_deps = mksnapshot_deps
|
||||||
"//v8:mksnapshot($v8_snapshot_toolchain)",
|
|
||||||
"//tools/v8_context_snapshot:v8_context_snapshot_generator",
|
|
||||||
":licenses",
|
|
||||||
]
|
|
||||||
outputs = [
|
outputs = [
|
||||||
"$root_build_dir/mksnapshot.zip",
|
"$root_build_dir/mksnapshot.zip",
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
copy("hunspell_dictionaries") {
|
||||||
|
sources = hunspell_dictionaries + hunspell_licenses
|
||||||
|
outputs = [
|
||||||
|
"$target_gen_dir/electron_hunspell/{{source_file_part}}",
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
dist_zip("hunspell_dictionaries_zip") {
|
||||||
|
data_deps = [
|
||||||
|
":hunspell_dictionaries",
|
||||||
|
]
|
||||||
|
flatten = true
|
||||||
|
|
||||||
|
outputs = [
|
||||||
|
"$root_build_dir/hunspell_dictionaries.zip",
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
group("electron") {
|
group("electron") {
|
||||||
public_deps = [
|
public_deps = [
|
||||||
":electron_app",
|
":electron_app",
|
||||||
|
|||||||
6
DEPS
6
DEPS
@@ -11,7 +11,7 @@ gclient_gn_args = [
|
|||||||
|
|
||||||
vars = {
|
vars = {
|
||||||
'chromium_version':
|
'chromium_version':
|
||||||
'c3a0220e7bde049d599a8332b9b2785b0178be74',
|
'80.0.3987.163',
|
||||||
'node_version':
|
'node_version':
|
||||||
'v12.13.0',
|
'v12.13.0',
|
||||||
'nan_version':
|
'nan_version':
|
||||||
@@ -114,7 +114,7 @@ hooks = [
|
|||||||
'pattern': 'src/electron/script/update-external-binaries.py',
|
'pattern': 'src/electron/script/update-external-binaries.py',
|
||||||
'condition': 'download_external_binaries',
|
'condition': 'download_external_binaries',
|
||||||
'action': [
|
'action': [
|
||||||
'python',
|
'python3',
|
||||||
'src/electron/script/update-external-binaries.py',
|
'src/electron/script/update-external-binaries.py',
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
@@ -152,3 +152,5 @@ hooks = [
|
|||||||
recursedeps = [
|
recursedeps = [
|
||||||
'src',
|
'src',
|
||||||
]
|
]
|
||||||
|
|
||||||
|
# Touch DEPS to bust cache
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
8.0.0-nightly.20191023
|
8.2.3
|
||||||
43
appveyor.yml
43
appveyor.yml
@@ -29,7 +29,7 @@
|
|||||||
|
|
||||||
version: 1.0.{build}
|
version: 1.0.{build}
|
||||||
build_cloud: libcc-20
|
build_cloud: libcc-20
|
||||||
image: vs2017-15.9-10.0.18362
|
image: vs2019-16.3-10.0.18362
|
||||||
environment:
|
environment:
|
||||||
GIT_CACHE_PATH: C:\Users\electron\libcc_cache
|
GIT_CACHE_PATH: C:\Users\electron\libcc_cache
|
||||||
ELECTRON_OUT_DIR: Default
|
ELECTRON_OUT_DIR: Default
|
||||||
@@ -50,6 +50,12 @@ build_script:
|
|||||||
- ps: >-
|
- ps: >-
|
||||||
if(($env:APPVEYOR_PULL_REQUEST_HEAD_REPO_NAME -split "/")[0] -eq ($env:APPVEYOR_REPO_NAME -split "/")[0]) {
|
if(($env:APPVEYOR_PULL_REQUEST_HEAD_REPO_NAME -split "/")[0] -eq ($env:APPVEYOR_REPO_NAME -split "/")[0]) {
|
||||||
Write-warning "Skipping PR build for branch"; Exit-AppveyorBuild
|
Write-warning "Skipping PR build for branch"; Exit-AppveyorBuild
|
||||||
|
} else {
|
||||||
|
node script/yarn.js install --frozen-lockfile
|
||||||
|
|
||||||
|
if ($(node script/doc-only-change.js --prNumber=$env:APPVEYOR_PULL_REQUEST_NUMBER --prBranch=$env:APPVEYOR_REPO_BRANCH;$LASTEXITCODE -eq 0)) {
|
||||||
|
Write-warning "Skipping build for doc only change"; Exit-AppveyorBuild
|
||||||
|
}
|
||||||
}
|
}
|
||||||
- echo "Building $env:GN_CONFIG build"
|
- echo "Building $env:GN_CONFIG build"
|
||||||
- git config --global core.longpaths true
|
- git config --global core.longpaths true
|
||||||
@@ -70,23 +76,49 @@ build_script:
|
|||||||
--unmanaged
|
--unmanaged
|
||||||
%GCLIENT_EXTRA_ARGS%
|
%GCLIENT_EXTRA_ARGS%
|
||||||
"https://github.com/electron/electron"
|
"https://github.com/electron/electron"
|
||||||
- gclient sync --with_branch_heads --with_tags --reset
|
- gclient sync --with_branch_heads --with_tags --ignore_locks --break_repo_locks
|
||||||
|
- ps: >-
|
||||||
|
if ($env:SAVE_GCLIENT_SRC -eq 'true') {
|
||||||
|
# archive current source for future use
|
||||||
|
# only run on x64/woa to avoid contention saving
|
||||||
|
if ($(7z a $zipfile src -xr!android_webview -xr!electron -xr'!*\.git' -xr!third_party\WebKit\LayoutTests! -xr!third_party\blink\web_tests -xr!third_party\blink\perf_tests -slp -t7z -mmt=30;$LASTEXITCODE -ne 0)) {
|
||||||
|
Write-warning "Could not save source to shared drive; continuing anyway"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
- ps: >-
|
||||||
|
if ($env:GN_CONFIG -ne 'release') {
|
||||||
|
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
|
||||||
|
node -e "require('./src/utils/goma.js').downloadAndPrepare()"
|
||||||
|
$env:GN_GOMA_FILE = node -e "console.log(require('./src/utils/goma.js').gnFilePath)"
|
||||||
|
$env:LOCAL_GOMA_DIR = node -e "console.log(require('./src/utils/goma.js').dir)"
|
||||||
|
cd ..
|
||||||
|
.\src\electron\script\start-goma.ps1 -gomaDir $env:LOCAL_GOMA_DIR
|
||||||
|
}
|
||||||
- cd src
|
- cd src
|
||||||
- ps: $env:BUILD_CONFIG_PATH="//electron/build/args/%GN_CONFIG%.gn"
|
- set BUILD_CONFIG_PATH=//electron/build/args/%GN_CONFIG%.gn
|
||||||
- gn gen out/Default "--args=import(\"%BUILD_CONFIG_PATH%\") %GN_EXTRA_ARGS%"
|
- if DEFINED GN_GOMA_FILE (gn gen out/Default "--args=import(\"%BUILD_CONFIG_PATH%\") import(\"%GN_GOMA_FILE%\") %GN_EXTRA_ARGS% ") else (gn gen out/Default "--args=import(\"%BUILD_CONFIG_PATH%\") %GN_EXTRA_ARGS% cc_wrapper=\"%SCCACHE_PATH%\"")
|
||||||
- gn check out/Default //electron:electron_lib
|
- gn check out/Default //electron:electron_lib
|
||||||
- gn check out/Default //electron:electron_app
|
- gn check out/Default //electron:electron_app
|
||||||
- gn check out/Default //electron:manifests
|
- gn check out/Default //electron:manifests
|
||||||
- gn check out/Default //electron/shell/common/api:mojo
|
- gn check out/Default //electron/shell/common/api:mojo
|
||||||
- ninja -C out/Default electron:electron_app
|
- if DEFINED GN_GOMA_FILE (ninja -j 300 -C out/Default electron:electron_app) else (ninja -C out/Default electron:electron_app)
|
||||||
- if "%GN_CONFIG%"=="testing" ( python C:\Users\electron\depot_tools\post_build_ninja_summary.py -C out\Default )
|
- if "%GN_CONFIG%"=="testing" ( python C:\Users\electron\depot_tools\post_build_ninja_summary.py -C out\Default )
|
||||||
- gn gen out/ffmpeg "--args=import(\"//electron/build/args/ffmpeg.gn\") %GN_EXTRA_ARGS%"
|
- gn gen out/ffmpeg "--args=import(\"//electron/build/args/ffmpeg.gn\") %GN_EXTRA_ARGS%"
|
||||||
- ninja -C out/ffmpeg electron:electron_ffmpeg_zip
|
- ninja -C out/ffmpeg electron:electron_ffmpeg_zip
|
||||||
- ninja -C out/Default electron:electron_dist_zip
|
- ninja -C out/Default electron:electron_dist_zip
|
||||||
- ninja -C out/Default shell_browser_ui_unittests
|
- ninja -C out/Default shell_browser_ui_unittests
|
||||||
- ninja -C out/Default electron:electron_mksnapshot_zip
|
- ninja -C out/Default electron:electron_mksnapshot_zip
|
||||||
|
- ninja -C out/Default electron:hunspell_dictionaries_zip
|
||||||
- ninja -C out/Default electron:electron_chromedriver_zip
|
- ninja -C out/Default electron:electron_chromedriver_zip
|
||||||
- ninja -C out/Default third_party/electron_node:headers
|
- ninja -C out/Default third_party/electron_node:headers
|
||||||
|
- if "%GN_CONFIG%"=="testing" ( python %LOCAL_GOMA_DIR%\goma_ctl.py stat )
|
||||||
- appveyor PushArtifact out/Default/dist.zip
|
- appveyor PushArtifact out/Default/dist.zip
|
||||||
- appveyor PushArtifact out/Default/shell_browser_ui_unittests.exe
|
- appveyor PushArtifact out/Default/shell_browser_ui_unittests.exe
|
||||||
- appveyor PushArtifact out/Default/chromedriver.zip
|
- appveyor PushArtifact out/Default/chromedriver.zip
|
||||||
@@ -94,6 +126,7 @@ build_script:
|
|||||||
- 7z a node_headers.zip out\Default\gen\node_headers
|
- 7z a node_headers.zip out\Default\gen\node_headers
|
||||||
- appveyor PushArtifact node_headers.zip
|
- appveyor PushArtifact node_headers.zip
|
||||||
- appveyor PushArtifact out/Default/mksnapshot.zip
|
- appveyor PushArtifact out/Default/mksnapshot.zip
|
||||||
|
- appveyor PushArtifact out/Default/hunspell_dictionaries.zip
|
||||||
- appveyor PushArtifact out/Default/electron.lib
|
- appveyor PushArtifact out/Default/electron.lib
|
||||||
- ps: >-
|
- ps: >-
|
||||||
if ($env:GN_CONFIG -eq 'release') {
|
if ($env:GN_CONFIG -eq 'release') {
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
is_electron_build = true
|
is_electron_build = true
|
||||||
use_jumbo_build = true
|
|
||||||
root_extra_deps = [ "//electron" ]
|
root_extra_deps = [ "//electron" ]
|
||||||
|
|
||||||
# Registry of NMVs --> https://github.com/nodejs/node/blob/master/doc/abi_version_registry.json
|
# Registry of NMVs --> https://github.com/nodejs/node/blob/master/doc/abi_version_registry.json
|
||||||
@@ -9,6 +8,12 @@ v8_promise_internal_field_count = 1
|
|||||||
v8_typed_array_max_size_in_heap = 0
|
v8_typed_array_max_size_in_heap = 0
|
||||||
v8_embedder_string = "-electron.0"
|
v8_embedder_string = "-electron.0"
|
||||||
|
|
||||||
|
# TODO: this breaks native modules. See e.g. https://www.github.com/nodejs/node/pull/30463
|
||||||
|
# We can probably enable this as long as we make sure node native modules
|
||||||
|
# also build with the relevant #defines (V8_COMPRESS_POINTERS etc.)
|
||||||
|
v8_enable_pointer_compression = false
|
||||||
|
v8_enable_31bit_smis_on_64bit_arch = false
|
||||||
|
|
||||||
# TODO: this breaks mksnapshot
|
# TODO: this breaks mksnapshot
|
||||||
v8_enable_snapshot_native_code_counters = false
|
v8_enable_snapshot_native_code_counters = false
|
||||||
|
|
||||||
@@ -18,12 +23,8 @@ ffmpeg_branding = "Chrome"
|
|||||||
|
|
||||||
enable_basic_printing = true
|
enable_basic_printing = true
|
||||||
angle_enable_vulkan_validation_layers = false
|
angle_enable_vulkan_validation_layers = false
|
||||||
|
dawn_enable_vulkan_validation_layers = false
|
||||||
|
|
||||||
is_cfi = false
|
is_cfi = false
|
||||||
|
|
||||||
# TODO: Remove this and update CI to contain 10.14 SDK once
|
enable_osr = true
|
||||||
# crbug.com/986701 is fixed.
|
|
||||||
mac_sdk_min = "10.13"
|
|
||||||
|
|
||||||
# TODO: disabled due to crashes. re-enable.
|
|
||||||
enable_osr = false
|
|
||||||
|
|||||||
@@ -5,4 +5,3 @@ is_debug = false
|
|||||||
is_component_build = false
|
is_component_build = false
|
||||||
is_component_ffmpeg = false
|
is_component_ffmpeg = false
|
||||||
symbol_level = 1
|
symbol_level = 1
|
||||||
use_jumbo_build = true
|
|
||||||
|
|||||||
@@ -1,9 +1,50 @@
|
|||||||
import("//build/config/mac/mac_sdk.gni")
|
import("//build/config/mac/mac_sdk.gni")
|
||||||
|
|
||||||
# This is imported from /ios becuase this functionality was moved
|
# Template to compile .xib and .storyboard files.
|
||||||
# after Chromium stopped using xib files for macOS menu functionality
|
# (copied from src/build/config/ios/rules.gni)
|
||||||
# See https://chromium-review.googlesource.com/c/chromium/src/+/1648695
|
#
|
||||||
import("//build/config/ios/rules.gni")
|
# Arguments
|
||||||
|
#
|
||||||
|
# sources:
|
||||||
|
# list of string, sources to compile
|
||||||
|
#
|
||||||
|
# ibtool_flags:
|
||||||
|
# (optional) list of string, additional flags to pass to the ibtool
|
||||||
|
template("compile_ib_files") {
|
||||||
|
action_foreach(target_name) {
|
||||||
|
forward_variables_from(invoker,
|
||||||
|
[
|
||||||
|
"testonly",
|
||||||
|
"visibility",
|
||||||
|
])
|
||||||
|
assert(defined(invoker.sources),
|
||||||
|
"sources must be specified for $target_name")
|
||||||
|
assert(defined(invoker.output_extension),
|
||||||
|
"output_extension must be specified for $target_name")
|
||||||
|
|
||||||
|
ibtool_flags = []
|
||||||
|
if (defined(invoker.ibtool_flags)) {
|
||||||
|
ibtool_flags = invoker.ibtool_flags
|
||||||
|
}
|
||||||
|
|
||||||
|
_output_extension = invoker.output_extension
|
||||||
|
|
||||||
|
script = "//build/config/ios/compile_ib_files.py"
|
||||||
|
sources = invoker.sources
|
||||||
|
outputs = [
|
||||||
|
"$target_gen_dir/$target_name/{{source_name_part}}.$_output_extension",
|
||||||
|
]
|
||||||
|
args = [
|
||||||
|
"--input",
|
||||||
|
"{{source}}",
|
||||||
|
"--output",
|
||||||
|
rebase_path(
|
||||||
|
"$target_gen_dir/$target_name/{{source_name_part}}.$_output_extension",
|
||||||
|
root_build_dir),
|
||||||
|
]
|
||||||
|
args += ibtool_flags
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
# Template is copied here from Chromium but was removed in
|
# Template is copied here from Chromium but was removed in
|
||||||
# https://chromium-review.googlesource.com/c/chromium/src/+/1637981
|
# https://chromium-review.googlesource.com/c/chromium/src/+/1637981
|
||||||
|
|||||||
@@ -74,7 +74,10 @@ module.exports = ({
|
|||||||
global: ['@electron/internal/renderer/webpack-provider', '_global'],
|
global: ['@electron/internal/renderer/webpack-provider', '_global'],
|
||||||
Buffer: ['@electron/internal/renderer/webpack-provider', 'Buffer'],
|
Buffer: ['@electron/internal/renderer/webpack-provider', 'Buffer'],
|
||||||
})
|
})
|
||||||
] : [])
|
] : []),
|
||||||
|
new webpack.ProvidePlugin({
|
||||||
|
Promise: ['@electron/internal/common/webpack-globals-provider', 'Promise'],
|
||||||
|
}),
|
||||||
]
|
]
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
16
build/zip.py
16
build/zip.py
@@ -16,6 +16,10 @@ PATHS_TO_SKIP = [
|
|||||||
'./libVkICD_mock_', #Skipping because these are outputs that we don't need
|
'./libVkICD_mock_', #Skipping because these are outputs that we don't need
|
||||||
'./VkICD_mock_', #Skipping because these are outputs that we don't need
|
'./VkICD_mock_', #Skipping because these are outputs that we don't need
|
||||||
|
|
||||||
|
# Skipping because its an output of create_bundle from //build/config/mac/rules.gni
|
||||||
|
# that we don't need
|
||||||
|
'Electron.dSYM',
|
||||||
|
|
||||||
# //chrome/browser:resources depends on this via
|
# //chrome/browser:resources depends on this via
|
||||||
# //chrome/browser/resources/ssl/ssl_error_assistant, but we don't need to
|
# //chrome/browser/resources/ssl/ssl_error_assistant, but we don't need to
|
||||||
# ship it.
|
# ship it.
|
||||||
@@ -46,19 +50,19 @@ def execute(argv):
|
|||||||
raise e
|
raise e
|
||||||
|
|
||||||
def main(argv):
|
def main(argv):
|
||||||
dist_zip, runtime_deps, target_cpu, target_os = argv
|
dist_zip, runtime_deps, target_cpu, target_os, flatten_val = argv
|
||||||
|
should_flatten = flatten_val == "true"
|
||||||
dist_files = set()
|
dist_files = set()
|
||||||
with open(runtime_deps) as f:
|
with open(runtime_deps) as f:
|
||||||
for dep in f.readlines():
|
for dep in f.readlines():
|
||||||
dep = dep.strip()
|
dep = dep.strip()
|
||||||
dist_files.add(dep)
|
if not skip_path(dep, dist_zip, target_cpu):
|
||||||
if sys.platform == 'darwin':
|
dist_files.add(dep)
|
||||||
|
if sys.platform == 'darwin' and not should_flatten:
|
||||||
execute(['zip', '-r', '-y', dist_zip] + list(dist_files))
|
execute(['zip', '-r', '-y', dist_zip] + list(dist_files))
|
||||||
else:
|
else:
|
||||||
with zipfile.ZipFile(dist_zip, 'w', zipfile.ZIP_DEFLATED, allowZip64=True) as z:
|
with zipfile.ZipFile(dist_zip, 'w', zipfile.ZIP_DEFLATED, allowZip64=True) as z:
|
||||||
for dep in dist_files:
|
for dep in dist_files:
|
||||||
if skip_path(dep, dist_zip, target_cpu):
|
|
||||||
continue
|
|
||||||
if os.path.isdir(dep):
|
if os.path.isdir(dep):
|
||||||
for root, dirs, files in os.walk(dep):
|
for root, dirs, files in os.walk(dep):
|
||||||
for file in files:
|
for file in files:
|
||||||
@@ -67,7 +71,7 @@ def main(argv):
|
|||||||
basename = os.path.basename(dep)
|
basename = os.path.basename(dep)
|
||||||
dirname = os.path.dirname(dep)
|
dirname = os.path.dirname(dep)
|
||||||
arcname = os.path.join(dirname, 'chrome-sandbox') if basename == 'chrome_sandbox' else dep
|
arcname = os.path.join(dirname, 'chrome-sandbox') if basename == 'chrome_sandbox' else dep
|
||||||
z.write(dep, arcname)
|
z.write(dep, os.path.basename(arcname) if should_flatten else arcname)
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
sys.exit(main(sys.argv[1:]))
|
sys.exit(main(sys.argv[1:]))
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ buildflag_header("buildflags") {
|
|||||||
"ENABLE_TTS=$enable_tts",
|
"ENABLE_TTS=$enable_tts",
|
||||||
"ENABLE_COLOR_CHOOSER=$enable_color_chooser",
|
"ENABLE_COLOR_CHOOSER=$enable_color_chooser",
|
||||||
"ENABLE_ELECTRON_EXTENSIONS=$enable_electron_extensions",
|
"ENABLE_ELECTRON_EXTENSIONS=$enable_electron_extensions",
|
||||||
|
"ENABLE_BUILTIN_SPELLCHECKER=$enable_builtin_spellchecker",
|
||||||
"ENABLE_PICTURE_IN_PICTURE=$enable_picture_in_picture",
|
"ENABLE_PICTURE_IN_PICTURE=$enable_picture_in_picture",
|
||||||
"OVERRIDE_LOCATION_PROVIDER=$enable_fake_location_provider",
|
"OVERRIDE_LOCATION_PROVIDER=$enable_fake_location_provider",
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -33,4 +33,7 @@ declare_args() {
|
|||||||
|
|
||||||
# Enable Chrome extensions support.
|
# Enable Chrome extensions support.
|
||||||
enable_electron_extensions = false
|
enable_electron_extensions = false
|
||||||
|
|
||||||
|
# Enable Spellchecker support
|
||||||
|
enable_builtin_spellchecker = true
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
# found in the LICENSE file.
|
# found in the LICENSE file.
|
||||||
|
|
||||||
import("//build/config/ui.gni")
|
import("//build/config/ui.gni")
|
||||||
|
import("//components/spellcheck/spellcheck_build_features.gni")
|
||||||
import("//electron/buildflags/buildflags.gni")
|
import("//electron/buildflags/buildflags.gni")
|
||||||
import("//printing/buildflags/buildflags.gni")
|
import("//printing/buildflags/buildflags.gni")
|
||||||
import("//third_party/widevine/cdm/widevine.gni")
|
import("//third_party/widevine/cdm/widevine.gni")
|
||||||
@@ -31,6 +32,8 @@ static_library("chrome") {
|
|||||||
"//chrome/browser/icon_loader_win.cc",
|
"//chrome/browser/icon_loader_win.cc",
|
||||||
"//chrome/browser/icon_manager.cc",
|
"//chrome/browser/icon_manager.cc",
|
||||||
"//chrome/browser/icon_manager.h",
|
"//chrome/browser/icon_manager.h",
|
||||||
|
"//chrome/browser/media/webrtc/system_media_capture_permissions_mac.h",
|
||||||
|
"//chrome/browser/media/webrtc/system_media_capture_permissions_mac.mm",
|
||||||
"//chrome/browser/net/chrome_mojo_proxy_resolver_factory.cc",
|
"//chrome/browser/net/chrome_mojo_proxy_resolver_factory.cc",
|
||||||
"//chrome/browser/net/chrome_mojo_proxy_resolver_factory.h",
|
"//chrome/browser/net/chrome_mojo_proxy_resolver_factory.h",
|
||||||
"//chrome/browser/net/proxy_config_monitor.cc",
|
"//chrome/browser/net/proxy_config_monitor.cc",
|
||||||
@@ -39,6 +42,8 @@ static_library("chrome") {
|
|||||||
"//chrome/browser/net/proxy_service_factory.h",
|
"//chrome/browser/net/proxy_service_factory.h",
|
||||||
"//chrome/browser/predictors/preconnect_manager.cc",
|
"//chrome/browser/predictors/preconnect_manager.cc",
|
||||||
"//chrome/browser/predictors/preconnect_manager.h",
|
"//chrome/browser/predictors/preconnect_manager.h",
|
||||||
|
"//chrome/browser/predictors/predictors_features.cc",
|
||||||
|
"//chrome/browser/predictors/predictors_features.h",
|
||||||
"//chrome/browser/predictors/proxy_lookup_client_impl.cc",
|
"//chrome/browser/predictors/proxy_lookup_client_impl.cc",
|
||||||
"//chrome/browser/predictors/proxy_lookup_client_impl.h",
|
"//chrome/browser/predictors/proxy_lookup_client_impl.h",
|
||||||
"//chrome/browser/predictors/resolve_host_client_impl.cc",
|
"//chrome/browser/predictors/resolve_host_client_impl.cc",
|
||||||
@@ -225,3 +230,58 @@ static_library("chrome") {
|
|||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# This source set is just so we don't have to depend on all of //chrome/browser
|
||||||
|
# You may have to add new files here during the upgrade if //chrome/browser/spellchecker
|
||||||
|
# gets more files
|
||||||
|
source_set("chrome_spellchecker") {
|
||||||
|
sources = []
|
||||||
|
deps = []
|
||||||
|
libs = []
|
||||||
|
|
||||||
|
if (enable_builtin_spellchecker) {
|
||||||
|
sources += [
|
||||||
|
"//chrome/browser/spellchecker/spell_check_host_chrome_impl.cc",
|
||||||
|
"//chrome/browser/spellchecker/spell_check_host_chrome_impl.h",
|
||||||
|
"//chrome/browser/spellchecker/spellcheck_custom_dictionary.cc",
|
||||||
|
"//chrome/browser/spellchecker/spellcheck_custom_dictionary.h",
|
||||||
|
"//chrome/browser/spellchecker/spellcheck_factory.cc",
|
||||||
|
"//chrome/browser/spellchecker/spellcheck_factory.h",
|
||||||
|
"//chrome/browser/spellchecker/spellcheck_hunspell_dictionary.cc",
|
||||||
|
"//chrome/browser/spellchecker/spellcheck_hunspell_dictionary.h",
|
||||||
|
"//chrome/browser/spellchecker/spellcheck_language_blacklist_policy_handler.cc",
|
||||||
|
"//chrome/browser/spellchecker/spellcheck_language_blacklist_policy_handler.h",
|
||||||
|
"//chrome/browser/spellchecker/spellcheck_language_policy_handler.cc",
|
||||||
|
"//chrome/browser/spellchecker/spellcheck_language_policy_handler.h",
|
||||||
|
"//chrome/browser/spellchecker/spellcheck_service.cc",
|
||||||
|
"//chrome/browser/spellchecker/spellcheck_service.h",
|
||||||
|
]
|
||||||
|
|
||||||
|
if (has_spellcheck_panel) {
|
||||||
|
sources += [
|
||||||
|
"//chrome/browser/spellchecker/spell_check_panel_host_impl.cc",
|
||||||
|
"//chrome/browser/spellchecker/spell_check_panel_host_impl.h",
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
if (use_browser_spellchecker) {
|
||||||
|
sources += [
|
||||||
|
"//chrome/browser/spellchecker/spelling_request.cc",
|
||||||
|
"//chrome/browser/spellchecker/spelling_request.h",
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
deps += [
|
||||||
|
"//base:base_static",
|
||||||
|
"//components/language/core/browser",
|
||||||
|
"//components/spellcheck:buildflags",
|
||||||
|
"//components/sync",
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
public_deps = [
|
||||||
|
"//components/spellcheck/browser",
|
||||||
|
"//components/spellcheck/common",
|
||||||
|
"//components/spellcheck/renderer",
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|||||||
@@ -37,10 +37,8 @@ net::NSSCertDatabase* GetNSSCertDatabaseForResourceContext(
|
|||||||
// public and private slot.
|
// public and private slot.
|
||||||
// Redirect any slot usage to this persistent slot on Linux.
|
// Redirect any slot usage to this persistent slot on Linux.
|
||||||
g_nss_cert_database = new net::NSSCertDatabase(
|
g_nss_cert_database = new net::NSSCertDatabase(
|
||||||
crypto::ScopedPK11Slot(
|
crypto::ScopedPK11Slot(PK11_GetInternalKeySlot()) /* public slot */,
|
||||||
crypto::GetPersistentNSSKeySlot()) /* public slot */,
|
crypto::ScopedPK11Slot(PK11_GetInternalKeySlot()) /* private slot */);
|
||||||
crypto::ScopedPK11Slot(
|
|
||||||
crypto::GetPersistentNSSKeySlot()) /* private slot */);
|
|
||||||
}
|
}
|
||||||
return g_nss_cert_database;
|
return g_nss_cert_database;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -56,7 +56,7 @@
|
|||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
|
|
||||||
#include "shell/browser/browser.h"
|
#include "shell/browser/browser.h"
|
||||||
#include "shell/common/atom_command_line.h"
|
#include "shell/common/electron_command_line.h"
|
||||||
|
|
||||||
#include "base/base_paths.h"
|
#include "base/base_paths.h"
|
||||||
#include "base/bind.h"
|
#include "base/bind.h"
|
||||||
@@ -826,7 +826,7 @@ ProcessSingleton::NotifyResult ProcessSingleton::NotifyOtherProcessWithTimeout(
|
|||||||
return PROCESS_NONE;
|
return PROCESS_NONE;
|
||||||
to_send.append(current_dir.value());
|
to_send.append(current_dir.value());
|
||||||
|
|
||||||
const std::vector<std::string>& argv = electron::AtomCommandLine::argv();
|
const std::vector<std::string>& argv = electron::ElectronCommandLine::argv();
|
||||||
for (std::vector<std::string>::const_iterator it = argv.begin();
|
for (std::vector<std::string>::const_iterator it = argv.begin();
|
||||||
it != argv.end(); ++it) {
|
it != argv.end(); ++it) {
|
||||||
to_send.push_back(kTokenDelimiter);
|
to_send.push_back(kTokenDelimiter);
|
||||||
|
|||||||
@@ -1,48 +1,50 @@
|
|||||||
import { app, dialog, BrowserWindow, shell, ipcMain } from 'electron'
|
import { app, dialog, BrowserWindow, shell, ipcMain } from 'electron';
|
||||||
import * as path from 'path'
|
import * as path from 'path';
|
||||||
|
|
||||||
let mainWindow: BrowserWindow | null = null
|
let mainWindow: BrowserWindow | null = null;
|
||||||
|
|
||||||
|
app.allowRendererProcessReuse = true;
|
||||||
|
|
||||||
// Quit when all windows are closed.
|
// Quit when all windows are closed.
|
||||||
app.on('window-all-closed', () => {
|
app.on('window-all-closed', () => {
|
||||||
app.quit()
|
app.quit();
|
||||||
})
|
});
|
||||||
|
|
||||||
function decorateURL (url: string) {
|
function decorateURL (url: string) {
|
||||||
// safely add `?utm_source=default_app
|
// safely add `?utm_source=default_app
|
||||||
const parsedUrl = new URL(url)
|
const parsedUrl = new URL(url);
|
||||||
parsedUrl.searchParams.append('utm_source', 'default_app')
|
parsedUrl.searchParams.append('utm_source', 'default_app');
|
||||||
return parsedUrl.toString()
|
return parsedUrl.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Find the shortest path to the electron binary
|
// Find the shortest path to the electron binary
|
||||||
const absoluteElectronPath = process.execPath
|
const absoluteElectronPath = process.execPath;
|
||||||
const relativeElectronPath = path.relative(process.cwd(), absoluteElectronPath)
|
const relativeElectronPath = path.relative(process.cwd(), absoluteElectronPath);
|
||||||
const electronPath = absoluteElectronPath.length < relativeElectronPath.length
|
const electronPath = absoluteElectronPath.length < relativeElectronPath.length
|
||||||
? absoluteElectronPath
|
? absoluteElectronPath
|
||||||
: relativeElectronPath
|
: relativeElectronPath;
|
||||||
|
|
||||||
const indexPath = path.resolve(app.getAppPath(), 'index.html')
|
const indexPath = path.resolve(app.getAppPath(), 'index.html');
|
||||||
|
|
||||||
function isTrustedSender (webContents: Electron.WebContents) {
|
function isTrustedSender (webContents: Electron.WebContents) {
|
||||||
if (webContents !== (mainWindow && mainWindow.webContents)) {
|
if (webContents !== (mainWindow && mainWindow.webContents)) {
|
||||||
return false
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
const parsedUrl = new URL(webContents.getURL())
|
const parsedUrl = new URL(webContents.getURL());
|
||||||
const urlPath = process.platform === 'win32'
|
const urlPath = process.platform === 'win32'
|
||||||
// Strip the prefixed "/" that occurs on windows
|
// Strip the prefixed "/" that occurs on windows
|
||||||
? path.resolve(parsedUrl.pathname.substr(1))
|
? path.resolve(parsedUrl.pathname.substr(1))
|
||||||
: parsedUrl.pathname
|
: parsedUrl.pathname;
|
||||||
return parsedUrl.protocol === 'file:' && urlPath === indexPath
|
return parsedUrl.protocol === 'file:' && urlPath === indexPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
ipcMain.handle('bootstrap', (event) => {
|
ipcMain.handle('bootstrap', (event) => {
|
||||||
return isTrustedSender(event.sender) ? electronPath : null
|
return isTrustedSender(event.sender) ? electronPath : null;
|
||||||
})
|
});
|
||||||
|
|
||||||
async function createWindow () {
|
async function createWindow () {
|
||||||
await app.whenReady()
|
await app.whenReady();
|
||||||
|
|
||||||
const options: Electron.BrowserWindowConstructorOptions = {
|
const options: Electron.BrowserWindowConstructorOptions = {
|
||||||
width: 900,
|
width: 900,
|
||||||
@@ -57,46 +59,46 @@ async function createWindow () {
|
|||||||
},
|
},
|
||||||
useContentSize: true,
|
useContentSize: true,
|
||||||
show: false
|
show: false
|
||||||
}
|
};
|
||||||
|
|
||||||
if (process.platform === 'linux') {
|
if (process.platform === 'linux') {
|
||||||
options.icon = path.join(__dirname, 'icon.png')
|
options.icon = path.join(__dirname, 'icon.png');
|
||||||
}
|
}
|
||||||
|
|
||||||
mainWindow = new BrowserWindow(options)
|
mainWindow = new BrowserWindow(options);
|
||||||
mainWindow.on('ready-to-show', () => mainWindow!.show())
|
mainWindow.on('ready-to-show', () => mainWindow!.show());
|
||||||
|
|
||||||
mainWindow.webContents.on('new-window', (event, url) => {
|
mainWindow.webContents.on('new-window', (event, url) => {
|
||||||
event.preventDefault()
|
event.preventDefault();
|
||||||
shell.openExternal(decorateURL(url))
|
shell.openExternal(decorateURL(url));
|
||||||
})
|
});
|
||||||
|
|
||||||
mainWindow.webContents.session.setPermissionRequestHandler((webContents, permission, done) => {
|
mainWindow.webContents.session.setPermissionRequestHandler((webContents, permission, done) => {
|
||||||
const parsedUrl = new URL(webContents.getURL())
|
const parsedUrl = new URL(webContents.getURL());
|
||||||
|
|
||||||
const options: Electron.MessageBoxOptions = {
|
const options: Electron.MessageBoxOptions = {
|
||||||
title: 'Permission Request',
|
title: 'Permission Request',
|
||||||
message: `Allow '${parsedUrl.origin}' to access '${permission}'?`,
|
message: `Allow '${parsedUrl.origin}' to access '${permission}'?`,
|
||||||
buttons: ['OK', 'Cancel'],
|
buttons: ['OK', 'Cancel'],
|
||||||
cancelId: 1
|
cancelId: 1
|
||||||
}
|
};
|
||||||
|
|
||||||
dialog.showMessageBox(mainWindow!, options).then(({ response }) => {
|
dialog.showMessageBox(mainWindow!, options).then(({ response }) => {
|
||||||
done(response === 0)
|
done(response === 0);
|
||||||
})
|
});
|
||||||
})
|
});
|
||||||
|
|
||||||
return mainWindow
|
return mainWindow;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const loadURL = async (appUrl: string) => {
|
export const loadURL = async (appUrl: string) => {
|
||||||
mainWindow = await createWindow()
|
mainWindow = await createWindow();
|
||||||
mainWindow.loadURL(appUrl)
|
mainWindow.loadURL(appUrl);
|
||||||
mainWindow.focus()
|
mainWindow.focus();
|
||||||
}
|
};
|
||||||
|
|
||||||
export const loadFile = async (appPath: string) => {
|
export const loadFile = async (appPath: string) => {
|
||||||
mainWindow = await createWindow()
|
mainWindow = await createWindow();
|
||||||
mainWindow.loadFile(appPath)
|
mainWindow.loadFile(appPath);
|
||||||
mainWindow.focus()
|
mainWindow.focus();
|
||||||
}
|
};
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
import { app, dialog } from 'electron'
|
import { app, dialog } from 'electron';
|
||||||
|
|
||||||
import * as fs from 'fs'
|
import * as fs from 'fs';
|
||||||
import * as path from 'path'
|
import * as path from 'path';
|
||||||
import * as url from 'url'
|
import * as url from 'url';
|
||||||
|
|
||||||
type DefaultAppOptions = {
|
type DefaultAppOptions = {
|
||||||
file: null | string;
|
file: null | string;
|
||||||
@@ -14,10 +14,10 @@ type DefaultAppOptions = {
|
|||||||
modules: string[];
|
modules: string[];
|
||||||
}
|
}
|
||||||
|
|
||||||
const Module = require('module')
|
const Module = require('module');
|
||||||
|
|
||||||
// Parse command line options.
|
// Parse command line options.
|
||||||
const argv = process.argv.slice(1)
|
const argv = process.argv.slice(1);
|
||||||
|
|
||||||
const option: DefaultAppOptions = {
|
const option: DefaultAppOptions = {
|
||||||
file: null,
|
file: null,
|
||||||
@@ -27,50 +27,50 @@ const option: DefaultAppOptions = {
|
|||||||
interactive: false,
|
interactive: false,
|
||||||
abi: false,
|
abi: false,
|
||||||
modules: []
|
modules: []
|
||||||
}
|
};
|
||||||
|
|
||||||
let nextArgIsRequire = false
|
let nextArgIsRequire = false;
|
||||||
|
|
||||||
for (const arg of argv) {
|
for (const arg of argv) {
|
||||||
if (nextArgIsRequire) {
|
if (nextArgIsRequire) {
|
||||||
option.modules.push(arg)
|
option.modules.push(arg);
|
||||||
nextArgIsRequire = false
|
nextArgIsRequire = false;
|
||||||
continue
|
continue;
|
||||||
} else if (arg === '--version' || arg === '-v') {
|
} else if (arg === '--version' || arg === '-v') {
|
||||||
option.version = true
|
option.version = true;
|
||||||
break
|
break;
|
||||||
} else if (arg.match(/^--app=/)) {
|
} else if (arg.match(/^--app=/)) {
|
||||||
option.file = arg.split('=')[1]
|
option.file = arg.split('=')[1];
|
||||||
break
|
break;
|
||||||
} else if (arg === '--interactive' || arg === '-i' || arg === '-repl') {
|
} else if (arg === '--interactive' || arg === '-i' || arg === '-repl') {
|
||||||
option.interactive = true
|
option.interactive = true;
|
||||||
} else if (arg === '--test-type=webdriver') {
|
} else if (arg === '--test-type=webdriver') {
|
||||||
option.webdriver = true
|
option.webdriver = true;
|
||||||
} else if (arg === '--require' || arg === '-r') {
|
} else if (arg === '--require' || arg === '-r') {
|
||||||
nextArgIsRequire = true
|
nextArgIsRequire = true;
|
||||||
continue
|
continue;
|
||||||
} else if (arg === '--abi' || arg === '-a') {
|
} else if (arg === '--abi' || arg === '-a') {
|
||||||
option.abi = true
|
option.abi = true;
|
||||||
continue
|
continue;
|
||||||
} else if (arg === '--no-help') {
|
} else if (arg === '--no-help') {
|
||||||
option.noHelp = true
|
option.noHelp = true;
|
||||||
continue
|
continue;
|
||||||
} else if (arg[0] === '-') {
|
} else if (arg[0] === '-') {
|
||||||
continue
|
continue;
|
||||||
} else {
|
} else {
|
||||||
option.file = arg
|
option.file = arg;
|
||||||
break
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (nextArgIsRequire) {
|
if (nextArgIsRequire) {
|
||||||
console.error('Invalid Usage: --require [file]\n\n"file" is required')
|
console.error('Invalid Usage: --require [file]\n\n"file" is required');
|
||||||
process.exit(1)
|
process.exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set up preload modules
|
// Set up preload modules
|
||||||
if (option.modules.length > 0) {
|
if (option.modules.length > 0) {
|
||||||
Module._preloadModules(option.modules)
|
Module._preloadModules(option.modules);
|
||||||
}
|
}
|
||||||
|
|
||||||
function loadApplicationPackage (packagePath: string) {
|
function loadApplicationPackage (packagePath: string) {
|
||||||
@@ -79,102 +79,102 @@ function loadApplicationPackage (packagePath: string) {
|
|||||||
configurable: false,
|
configurable: false,
|
||||||
enumerable: true,
|
enumerable: true,
|
||||||
value: true
|
value: true
|
||||||
})
|
});
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Override app name and version.
|
// Override app name and version.
|
||||||
packagePath = path.resolve(packagePath)
|
packagePath = path.resolve(packagePath);
|
||||||
const packageJsonPath = path.join(packagePath, 'package.json')
|
const packageJsonPath = path.join(packagePath, 'package.json');
|
||||||
let appPath
|
let appPath;
|
||||||
if (fs.existsSync(packageJsonPath)) {
|
if (fs.existsSync(packageJsonPath)) {
|
||||||
let packageJson
|
let packageJson;
|
||||||
try {
|
try {
|
||||||
packageJson = require(packageJsonPath)
|
packageJson = require(packageJsonPath);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
showErrorMessage(`Unable to parse ${packageJsonPath}\n\n${e.message}`)
|
showErrorMessage(`Unable to parse ${packageJsonPath}\n\n${e.message}`);
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (packageJson.version) {
|
if (packageJson.version) {
|
||||||
app.setVersion(packageJson.version)
|
app.setVersion(packageJson.version);
|
||||||
}
|
}
|
||||||
if (packageJson.productName) {
|
if (packageJson.productName) {
|
||||||
app.name = packageJson.productName
|
app.name = packageJson.productName;
|
||||||
} else if (packageJson.name) {
|
} else if (packageJson.name) {
|
||||||
app.name = packageJson.name
|
app.name = packageJson.name;
|
||||||
}
|
}
|
||||||
appPath = packagePath
|
appPath = packagePath;
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const filePath = Module._resolveFilename(packagePath, module, true)
|
const filePath = Module._resolveFilename(packagePath, module, true);
|
||||||
app._setDefaultAppPaths(appPath || path.dirname(filePath))
|
app._setDefaultAppPaths(appPath || path.dirname(filePath));
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
showErrorMessage(`Unable to find Electron app at ${packagePath}\n\n${e.message}`)
|
showErrorMessage(`Unable to find Electron app at ${packagePath}\n\n${e.message}`);
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Run the app.
|
// Run the app.
|
||||||
Module._load(packagePath, module, true)
|
Module._load(packagePath, module, true);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error('App threw an error during load')
|
console.error('App threw an error during load');
|
||||||
console.error(e.stack || e)
|
console.error(e.stack || e);
|
||||||
throw e
|
throw e;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function showErrorMessage (message: string) {
|
function showErrorMessage (message: string) {
|
||||||
app.focus()
|
app.focus();
|
||||||
dialog.showErrorBox('Error launching app', message)
|
dialog.showErrorBox('Error launching app', message);
|
||||||
process.exit(1)
|
process.exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
async function loadApplicationByURL (appUrl: string) {
|
async function loadApplicationByURL (appUrl: string) {
|
||||||
const { loadURL } = await import('./default_app')
|
const { loadURL } = await import('./default_app');
|
||||||
loadURL(appUrl)
|
loadURL(appUrl);
|
||||||
}
|
}
|
||||||
|
|
||||||
async function loadApplicationByFile (appPath: string) {
|
async function loadApplicationByFile (appPath: string) {
|
||||||
const { loadFile } = await import('./default_app')
|
const { loadFile } = await import('./default_app');
|
||||||
loadFile(appPath)
|
loadFile(appPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
function startRepl () {
|
function startRepl () {
|
||||||
if (process.platform === 'win32') {
|
if (process.platform === 'win32') {
|
||||||
console.error('Electron REPL not currently supported on Windows')
|
console.error('Electron REPL not currently supported on Windows');
|
||||||
process.exit(1)
|
process.exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
// prevent quitting
|
// prevent quitting
|
||||||
app.on('window-all-closed', () => {})
|
app.on('window-all-closed', () => {});
|
||||||
|
|
||||||
const repl = require('repl')
|
const repl = require('repl');
|
||||||
repl.start('> ').on('exit', () => {
|
repl.start('> ').on('exit', () => {
|
||||||
process.exit(0)
|
process.exit(0);
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Start the specified app if there is one specified in command line, otherwise
|
// Start the specified app if there is one specified in command line, otherwise
|
||||||
// start the default app.
|
// start the default app.
|
||||||
if (option.file && !option.webdriver) {
|
if (option.file && !option.webdriver) {
|
||||||
const file = option.file
|
const file = option.file;
|
||||||
const protocol = url.parse(file).protocol
|
const protocol = url.parse(file).protocol;
|
||||||
const extension = path.extname(file)
|
const extension = path.extname(file);
|
||||||
if (protocol === 'http:' || protocol === 'https:' || protocol === 'file:' || protocol === 'chrome:') {
|
if (protocol === 'http:' || protocol === 'https:' || protocol === 'file:' || protocol === 'chrome:') {
|
||||||
loadApplicationByURL(file)
|
loadApplicationByURL(file);
|
||||||
} else if (extension === '.html' || extension === '.htm') {
|
} else if (extension === '.html' || extension === '.htm') {
|
||||||
loadApplicationByFile(path.resolve(file))
|
loadApplicationByFile(path.resolve(file));
|
||||||
} else {
|
} else {
|
||||||
loadApplicationPackage(file)
|
loadApplicationPackage(file);
|
||||||
}
|
}
|
||||||
} else if (option.version) {
|
} else if (option.version) {
|
||||||
console.log('v' + process.versions.electron)
|
console.log('v' + process.versions.electron);
|
||||||
process.exit(0)
|
process.exit(0);
|
||||||
} else if (option.abi) {
|
} else if (option.abi) {
|
||||||
console.log(process.versions.modules)
|
console.log(process.versions.modules);
|
||||||
process.exit(0)
|
process.exit(0);
|
||||||
} else if (option.interactive) {
|
} else if (option.interactive) {
|
||||||
startRepl()
|
startRepl();
|
||||||
} else {
|
} else {
|
||||||
if (!option.noHelp) {
|
if (!option.noHelp) {
|
||||||
const welcomeMessage = `
|
const welcomeMessage = `
|
||||||
@@ -192,10 +192,10 @@ Options:
|
|||||||
-i, --interactive Open a REPL to the main process.
|
-i, --interactive Open a REPL to the main process.
|
||||||
-r, --require Module to preload (option can be repeated).
|
-r, --require Module to preload (option can be repeated).
|
||||||
-v, --version Print the version.
|
-v, --version Print the version.
|
||||||
-a, --abi Print the Node ABI version.`
|
-a, --abi Print the Node ABI version.`;
|
||||||
|
|
||||||
console.log(welcomeMessage)
|
console.log(welcomeMessage);
|
||||||
}
|
}
|
||||||
|
|
||||||
loadApplicationByFile('index.html')
|
loadApplicationByFile('index.html');
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,53 +1,53 @@
|
|||||||
import { ipcRenderer, contextBridge } from 'electron'
|
import { ipcRenderer, contextBridge } from 'electron';
|
||||||
|
|
||||||
async function getOcticonSvg (name: string) {
|
async function getOcticonSvg (name: string) {
|
||||||
try {
|
try {
|
||||||
const response = await fetch(`octicon/${name}.svg`)
|
const response = await fetch(`octicon/${name}.svg`);
|
||||||
const div = document.createElement('div')
|
const div = document.createElement('div');
|
||||||
div.innerHTML = await response.text()
|
div.innerHTML = await response.text();
|
||||||
return div
|
return div;
|
||||||
} catch {
|
} catch {
|
||||||
return null
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function loadSVG (element: HTMLSpanElement) {
|
async function loadSVG (element: HTMLSpanElement) {
|
||||||
for (const cssClass of element.classList) {
|
for (const cssClass of element.classList) {
|
||||||
if (cssClass.startsWith('octicon-')) {
|
if (cssClass.startsWith('octicon-')) {
|
||||||
const icon = await getOcticonSvg(cssClass.substr(8))
|
const icon = await getOcticonSvg(cssClass.substr(8));
|
||||||
if (icon) {
|
if (icon) {
|
||||||
for (const elemClass of element.classList) {
|
for (const elemClass of element.classList) {
|
||||||
icon.classList.add(elemClass)
|
icon.classList.add(elemClass);
|
||||||
}
|
}
|
||||||
element.before(icon)
|
element.before(icon);
|
||||||
element.remove()
|
element.remove();
|
||||||
break
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function initialize () {
|
async function initialize () {
|
||||||
const electronPath = await ipcRenderer.invoke('bootstrap')
|
const electronPath = await ipcRenderer.invoke('bootstrap');
|
||||||
|
|
||||||
function replaceText (selector: string, text: string) {
|
function replaceText (selector: string, text: string) {
|
||||||
const element = document.querySelector<HTMLElement>(selector)
|
const element = document.querySelector<HTMLElement>(selector);
|
||||||
if (element) {
|
if (element) {
|
||||||
element.innerText = text
|
element.innerText = text;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
replaceText('.electron-version', `Electron v${process.versions.electron}`)
|
replaceText('.electron-version', `Electron v${process.versions.electron}`);
|
||||||
replaceText('.chrome-version', `Chromium v${process.versions.chrome}`)
|
replaceText('.chrome-version', `Chromium v${process.versions.chrome}`);
|
||||||
replaceText('.node-version', `Node v${process.versions.node}`)
|
replaceText('.node-version', `Node v${process.versions.node}`);
|
||||||
replaceText('.v8-version', `v8 v${process.versions.v8}`)
|
replaceText('.v8-version', `v8 v${process.versions.v8}`);
|
||||||
replaceText('.command-example', `${electronPath} path-to-app`)
|
replaceText('.command-example', `${electronPath} path-to-app`);
|
||||||
|
|
||||||
for (const element of document.querySelectorAll<HTMLSpanElement>('.octicon')) {
|
for (const element of document.querySelectorAll<HTMLSpanElement>('.octicon')) {
|
||||||
loadSVG(element)
|
loadSVG(element);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
contextBridge.exposeInMainWorld('electronDefaultApp', {
|
contextBridge.exposeInMainWorld('electronDefaultApp', {
|
||||||
initialize
|
initialize
|
||||||
})
|
});
|
||||||
|
|||||||
@@ -314,10 +314,8 @@ Returns:
|
|||||||
|
|
||||||
* `event` Event
|
* `event` Event
|
||||||
* `webContents` [WebContents](web-contents.md)
|
* `webContents` [WebContents](web-contents.md)
|
||||||
* `request` Object
|
* `authenticationResponseDetails` Object
|
||||||
* `method` String
|
|
||||||
* `url` URL
|
* `url` URL
|
||||||
* `referrer` URL
|
|
||||||
* `authInfo` Object
|
* `authInfo` Object
|
||||||
* `isProxy` Boolean
|
* `isProxy` Boolean
|
||||||
* `scheme` String
|
* `scheme` String
|
||||||
@@ -325,8 +323,8 @@ Returns:
|
|||||||
* `port` Integer
|
* `port` Integer
|
||||||
* `realm` String
|
* `realm` String
|
||||||
* `callback` Function
|
* `callback` Function
|
||||||
* `username` String
|
* `username` String (optional)
|
||||||
* `password` String
|
* `password` String (optional)
|
||||||
|
|
||||||
Emitted when `webContents` wants to do basic auth.
|
Emitted when `webContents` wants to do basic auth.
|
||||||
|
|
||||||
@@ -337,12 +335,16 @@ should prevent the default behavior with `event.preventDefault()` and call
|
|||||||
```javascript
|
```javascript
|
||||||
const { app } = require('electron')
|
const { app } = require('electron')
|
||||||
|
|
||||||
app.on('login', (event, webContents, request, authInfo, callback) => {
|
app.on('login', (event, webContents, details, authInfo, callback) => {
|
||||||
event.preventDefault()
|
event.preventDefault()
|
||||||
callback('username', 'secret')
|
callback('username', 'secret')
|
||||||
})
|
})
|
||||||
```
|
```
|
||||||
|
|
||||||
|
If `callback` is called without a username or password, the authentication
|
||||||
|
request will be cancelled and the authentication error will be returned to the
|
||||||
|
page.
|
||||||
|
|
||||||
### Event: 'gpu-info-update'
|
### Event: 'gpu-info-update'
|
||||||
|
|
||||||
Emitted whenever there is a GPU info update.
|
Emitted whenever there is a GPU info update.
|
||||||
@@ -711,34 +713,34 @@ Clears the recent documents list.
|
|||||||
|
|
||||||
### `app.setAsDefaultProtocolClient(protocol[, path, args])`
|
### `app.setAsDefaultProtocolClient(protocol[, path, args])`
|
||||||
|
|
||||||
* `protocol` String - The name of your protocol, without `://`. If you want your
|
* `protocol` String - The name of your protocol, without `://`. For example,
|
||||||
app to handle `electron://` links, call this method with `electron` as the
|
if you want your app to handle `electron://` links, call this method with
|
||||||
parameter.
|
`electron` as the parameter.
|
||||||
* `path` String (optional) _Windows_ - Defaults to `process.execPath`
|
* `path` String (optional) _Windows_ - The path to the Electron executable.
|
||||||
* `args` String[] (optional) _Windows_ - Defaults to an empty array
|
Defaults to `process.execPath`
|
||||||
|
* `args` String[] (optional) _Windows_ - Arguments passed to the executable.
|
||||||
|
Defaults to an empty array
|
||||||
|
|
||||||
Returns `Boolean` - Whether the call succeeded.
|
Returns `Boolean` - Whether the call succeeded.
|
||||||
|
|
||||||
This method sets the current executable as the default handler for a protocol
|
Sets the current executable as the default handler for a protocol (aka URI
|
||||||
(aka URI scheme). It allows you to integrate your app deeper into the operating
|
scheme). It allows you to integrate your app deeper into the operating system.
|
||||||
system. Once registered, all links with `your-protocol://` will be opened with
|
Once registered, all links with `your-protocol://` will be opened with the
|
||||||
the current executable. The whole link, including protocol, will be passed to
|
current executable. The whole link, including protocol, will be passed to your
|
||||||
your application as a parameter.
|
application as a parameter.
|
||||||
|
|
||||||
On Windows, you can provide optional parameters path, the path to your executable,
|
|
||||||
and args, an array of arguments to be passed to your executable when it launches.
|
|
||||||
|
|
||||||
**Note:** On macOS, you can only register protocols that have been added to
|
**Note:** On macOS, you can only register protocols that have been added to
|
||||||
your app's `info.plist`, which can not be modified at runtime. You can however
|
your app's `info.plist`, which cannot be modified at runtime. However, you can
|
||||||
change the file with a simple text editor or script during build time.
|
change the file during build time via [Electron Forge][electron-forge],
|
||||||
Please refer to [Apple's documentation][CFBundleURLTypes] for details.
|
[Electron Packager][electron-packager], or by editing `info.plist` with a text
|
||||||
|
editor. Please refer to [Apple's documentation][CFBundleURLTypes] for details.
|
||||||
|
|
||||||
**Note:** In a Windows Store environment (when packaged as an `appx`) this API
|
**Note:** In a Windows Store environment (when packaged as an `appx`) this API
|
||||||
will return `true` for all calls but the registry key it sets won't be accessible
|
will return `true` for all calls but the registry key it sets won't be accessible
|
||||||
by other applications. In order to register your Windows Store application
|
by other applications. In order to register your Windows Store application
|
||||||
as a default protocol handler you must [declare the protocol in your manifest](https://docs.microsoft.com/en-us/uwp/schemas/appxpackage/uapmanifestschema/element-uap-protocol).
|
as a default protocol handler you must [declare the protocol in your manifest](https://docs.microsoft.com/en-us/uwp/schemas/appxpackage/uapmanifestschema/element-uap-protocol).
|
||||||
|
|
||||||
The API uses the Windows Registry and LSSetDefaultHandlerForURLScheme internally.
|
The API uses the Windows Registry and `LSSetDefaultHandlerForURLScheme` internally.
|
||||||
|
|
||||||
### `app.removeAsDefaultProtocolClient(protocol[, path, args])` _macOS_ _Windows_
|
### `app.removeAsDefaultProtocolClient(protocol[, path, args])` _macOS_ _Windows_
|
||||||
|
|
||||||
@@ -757,10 +759,8 @@ protocol (aka URI scheme). If so, it will remove the app as the default handler.
|
|||||||
* `path` String (optional) _Windows_ - Defaults to `process.execPath`
|
* `path` String (optional) _Windows_ - Defaults to `process.execPath`
|
||||||
* `args` String[] (optional) _Windows_ - Defaults to an empty array
|
* `args` String[] (optional) _Windows_ - Defaults to an empty array
|
||||||
|
|
||||||
Returns `Boolean`
|
Returns `Boolean` - Whether the current executable is the default handler for a
|
||||||
|
protocol (aka URI scheme).
|
||||||
This method checks if the current executable is the default handler for a protocol
|
|
||||||
(aka URI scheme). If so, it will return true. Otherwise, it will return false.
|
|
||||||
|
|
||||||
**Note:** On macOS, you can use this method to check if the app has been
|
**Note:** On macOS, you can use this method to check if the app has been
|
||||||
registered as the default protocol handler for a protocol. You can also verify
|
registered as the default protocol handler for a protocol. You can also verify
|
||||||
@@ -768,7 +768,22 @@ this by checking `~/Library/Preferences/com.apple.LaunchServices.plist` on the
|
|||||||
macOS machine. Please refer to
|
macOS machine. Please refer to
|
||||||
[Apple's documentation][LSCopyDefaultHandlerForURLScheme] for details.
|
[Apple's documentation][LSCopyDefaultHandlerForURLScheme] for details.
|
||||||
|
|
||||||
The API uses the Windows Registry and LSCopyDefaultHandlerForURLScheme internally.
|
The API uses the Windows Registry and `LSCopyDefaultHandlerForURLScheme` internally.
|
||||||
|
|
||||||
|
### `app.getApplicationNameForProtocol(url)`
|
||||||
|
|
||||||
|
* `url` String - a URL with the protocol name to check. Unlike the other
|
||||||
|
methods in this family, this accepts an entire URL, including `://` at a
|
||||||
|
minimum (e.g. `https://`).
|
||||||
|
|
||||||
|
Returns `String` - Name of the application handling the protocol, or an empty
|
||||||
|
string if there is no handler. For instance, if Electron is the default
|
||||||
|
handler of the URL, this could be `Electron` on Windows and Mac. However,
|
||||||
|
don't rely on the precise format which is not guaranteed to remain unchanged.
|
||||||
|
Expect a different format on Linux, possibly with a `.desktop` suffix.
|
||||||
|
|
||||||
|
This method returns the application name of the default handler for the protocol
|
||||||
|
(aka URI scheme) of a URL.
|
||||||
|
|
||||||
### `app.setUserTasks(tasks)` _Windows_
|
### `app.setUserTasks(tasks)` _Windows_
|
||||||
|
|
||||||
@@ -1186,8 +1201,9 @@ Show the app's about panel options. These options can be overridden with `app.se
|
|||||||
* `website` String (optional) _Linux_ - The app's website.
|
* `website` String (optional) _Linux_ - The app's website.
|
||||||
* `iconPath` String (optional) _Linux_ _Windows_ - Path to the app's icon. On Linux, will be shown as 64x64 pixels while retaining aspect ratio.
|
* `iconPath` String (optional) _Linux_ _Windows_ - Path to the app's icon. On Linux, will be shown as 64x64 pixels while retaining aspect ratio.
|
||||||
|
|
||||||
Set the about panel options. This will override the values defined in the app's
|
Set the about panel options. This will override the values defined in the app's `.plist` file on MacOS. See the [Apple docs][about-panel-options] for more details. On Linux, values must be set in order to be shown; there are no defaults.
|
||||||
`.plist` file on MacOS. See the [Apple docs][about-panel-options] for more details. On Linux, values must be set in order to be shown; there are no defaults.
|
|
||||||
|
If you do not set `credits` but still wish to surface them in your app, AppKit will look for a file named "Credits.html", "Credits.rtf", and "Credits.rtfd", in that order, in the bundle returned by the NSBundle class method main. The first file found is used, and if none is found, the info area is left blank. See Apple [documentation](https://developer.apple.com/documentation/appkit/nsaboutpaneloptioncredits?language=objc) for more information.
|
||||||
|
|
||||||
### `app.isEmojiPanelSupported()`
|
### `app.isEmojiPanelSupported()`
|
||||||
|
|
||||||
@@ -1308,6 +1324,8 @@ A `Boolean` property that returns `true` if the app is packaged, `false` otherw
|
|||||||
[dock-menu]:https://developer.apple.com/macos/human-interface-guidelines/menus/dock-menus/
|
[dock-menu]:https://developer.apple.com/macos/human-interface-guidelines/menus/dock-menus/
|
||||||
[tasks]:https://msdn.microsoft.com/en-us/library/windows/desktop/dd378460(v=vs.85).aspx#tasks
|
[tasks]:https://msdn.microsoft.com/en-us/library/windows/desktop/dd378460(v=vs.85).aspx#tasks
|
||||||
[app-user-model-id]: https://msdn.microsoft.com/en-us/library/windows/desktop/dd378459(v=vs.85).aspx
|
[app-user-model-id]: https://msdn.microsoft.com/en-us/library/windows/desktop/dd378459(v=vs.85).aspx
|
||||||
|
[electron-forge]: https://www.electronforge.io/
|
||||||
|
[electron-packager]: https://github.com/electron/electron-packager
|
||||||
[CFBundleURLTypes]: https://developer.apple.com/library/ios/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html#//apple_ref/doc/uid/TP40009249-102207-TPXREF115
|
[CFBundleURLTypes]: https://developer.apple.com/library/ios/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html#//apple_ref/doc/uid/TP40009249-102207-TPXREF115
|
||||||
[LSCopyDefaultHandlerForURLScheme]: https://developer.apple.com/library/mac/documentation/Carbon/Reference/LaunchServicesReference/#//apple_ref/c/func/LSCopyDefaultHandlerForURLScheme
|
[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
|
[handoff]: https://developer.apple.com/library/ios/documentation/UserExperience/Conceptual/Handoff/HandoffFundamentals/HandoffFundamentals.html
|
||||||
|
|||||||
@@ -59,6 +59,55 @@ these kinds of objects will throw a 'could not be cloned' error.
|
|||||||
|
|
||||||
[SCA]: https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Structured_clone_algorithm
|
[SCA]: https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Structured_clone_algorithm
|
||||||
|
|
||||||
|
### `<webview>.getWebContents()`
|
||||||
|
|
||||||
|
This API is implemented using the `remote` module, which has both performance
|
||||||
|
and security implications. Therefore its usage should be explicit.
|
||||||
|
|
||||||
|
```js
|
||||||
|
// Deprecated
|
||||||
|
webview.getWebContents()
|
||||||
|
// Replace with
|
||||||
|
const { remote } = require('electron')
|
||||||
|
remote.webContents.fromId(webview.getWebContentsId())
|
||||||
|
```
|
||||||
|
|
||||||
|
However, it is recommended to avoid using the `remote` module altogether.
|
||||||
|
|
||||||
|
```js
|
||||||
|
// main
|
||||||
|
const { ipcMain, webContents } = require('electron')
|
||||||
|
|
||||||
|
const getGuestForWebContents = function (webContentsId, contents) {
|
||||||
|
const guest = webContents.fromId(webContentsId)
|
||||||
|
if (!guest) {
|
||||||
|
throw new Error(`Invalid webContentsId: ${webContentsId}`)
|
||||||
|
}
|
||||||
|
if (guest.hostWebContents !== contents) {
|
||||||
|
throw new Error(`Access denied to webContents`)
|
||||||
|
}
|
||||||
|
return guest
|
||||||
|
}
|
||||||
|
|
||||||
|
ipcMain.handle('openDevTools', (event, webContentsId) => {
|
||||||
|
const guest = getGuestForWebContents(webContentsId, event.sender)
|
||||||
|
guest.openDevTools()
|
||||||
|
})
|
||||||
|
|
||||||
|
// renderer
|
||||||
|
const { ipcRenderer } = require('electron')
|
||||||
|
|
||||||
|
ipcRenderer.invoke('openDevTools', webview.getWebContentsId())
|
||||||
|
```
|
||||||
|
|
||||||
|
### `webFrame.setLayoutZoomLevelLimits()`
|
||||||
|
|
||||||
|
Chromium has removed support for changing the layout zoom level limits, and it
|
||||||
|
is beyond Electron's capacity to maintain it. The function will emit a warning
|
||||||
|
in Electron 8.x, and cease to exist in Electron 9.x. The layout zoom level
|
||||||
|
limits are now fixed at a minimum of 0.25 and a maximum of 5.0, as defined
|
||||||
|
[here](https://chromium.googlesource.com/chromium/src/+/938b37a6d2886bf8335fc7db792f1eb46c65b2ae/third_party/blink/common/page/page_zoom.cc#11).
|
||||||
|
|
||||||
## Planned Breaking API Changes (7.0)
|
## Planned Breaking API Changes (7.0)
|
||||||
|
|
||||||
### Node Headers URL
|
### Node Headers URL
|
||||||
@@ -103,7 +152,7 @@ const idleTime = getSystemIdleTime()
|
|||||||
### webFrame Isolated World APIs
|
### webFrame Isolated World APIs
|
||||||
|
|
||||||
```js
|
```js
|
||||||
// Removed in Elecron 7.0
|
// Removed in Electron 7.0
|
||||||
webFrame.setIsolatedWorldContentSecurityPolicy(worldId, csp)
|
webFrame.setIsolatedWorldContentSecurityPolicy(worldId, csp)
|
||||||
webFrame.setIsolatedWorldHumanReadableName(worldId, name)
|
webFrame.setIsolatedWorldHumanReadableName(worldId, name)
|
||||||
webFrame.setIsolatedWorldSecurityOrigin(worldId, securityOrigin)
|
webFrame.setIsolatedWorldSecurityOrigin(worldId, securityOrigin)
|
||||||
@@ -121,6 +170,40 @@ webFrame.setIsolatedWorldInfo(
|
|||||||
|
|
||||||
This property was removed in Chromium 77, and as such is no longer available.
|
This property was removed in Chromium 77, and as such is no longer available.
|
||||||
|
|
||||||
|
### `webkitdirectory` attribute for `<input type="file"/>`
|
||||||
|

|
||||||
|
The `webkitdirectory` property on HTML file inputs allows them to select folders.
|
||||||
|
Previous versions of Electron had an incorrect implementation where the `event.target.files`
|
||||||
|
of the input returned a `FileList` that returned one `File` corresponding to the selected folder.
|
||||||
|

|
||||||
|
As of Electron 7, that `FileList` is now list of all files contained within
|
||||||
|
the folder, similarly to Chrome, Firefox, and Edge
|
||||||
|
([link to MDN docs](https://developer.mozilla.org/en-US/docs/Web/API/HTMLInputElement/webkitdirectory)).
|
||||||
|

|
||||||
|
As an illustration, take a folder with this structure:
|
||||||
|
```console
|
||||||
|
folder
|
||||||
|
├── file1
|
||||||
|
├── file2
|
||||||
|
└── file3
|
||||||
|
```
|
||||||
|

|
||||||
|
In Electron <=6, this would return a `FileList` with a `File` object for:
|
||||||
|
```console
|
||||||
|
path/to/folder
|
||||||
|
```
|
||||||
|

|
||||||
|
In Electron 7, this now returns a `FileList` with a `File` object for:
|
||||||
|
```console
|
||||||
|
/path/to/folder/file3
|
||||||
|
/path/to/folder/file2
|
||||||
|
/path/to/folder/file1
|
||||||
|
```
|
||||||
|

|
||||||
|
Note that `webkitdirectory` no longer exposes the path to the selected folder.
|
||||||
|
If you require the path to the selected folder rather than the folder contents,
|
||||||
|
see the `dialog.showOpenDialog` API ([link](https://github.com/electron/electron/blob/master/docs/api/dialog.md#dialogshowopendialogbrowserwindow-options)).
|
||||||
|
|
||||||
## Planned Breaking API Changes (6.0)
|
## Planned Breaking API Changes (6.0)
|
||||||
|
|
||||||
### `win.setMenu(null)`
|
### `win.setMenu(null)`
|
||||||
|
|||||||
@@ -229,6 +229,7 @@ It creates a new `BrowserWindow` with native properties as set by the `options`.
|
|||||||
unless hovered over in the top left of the window. These custom buttons prevent
|
unless hovered over in the top left of the window. These custom buttons prevent
|
||||||
issues with mouse events that occur with the standard window toolbar buttons.
|
issues with mouse events that occur with the standard window toolbar buttons.
|
||||||
**Note:** This option is currently experimental.
|
**Note:** This option is currently experimental.
|
||||||
|
* `trafficLightPosition` [Point](structures/point.md) (optional) - Set a custom position for the traffic light buttons. Can only be used with `titleBarStyle` set to `hidden`
|
||||||
* `fullscreenWindowTitle` Boolean (optional) - Shows the title in the
|
* `fullscreenWindowTitle` Boolean (optional) - Shows the title in the
|
||||||
title bar in full screen mode on macOS for all `titleBarStyle` options.
|
title bar in full screen mode on macOS for all `titleBarStyle` options.
|
||||||
Default is `false`.
|
Default is `false`.
|
||||||
@@ -272,8 +273,6 @@ It creates a new `BrowserWindow` with native properties as set by the `options`.
|
|||||||
OS-level sandbox and disabling the Node.js engine. This is not the same as
|
OS-level sandbox and disabling the Node.js engine. This is not the same as
|
||||||
the `nodeIntegration` option and the APIs available to the preload script
|
the `nodeIntegration` option and the APIs available to the preload script
|
||||||
are more limited. Read more about the option [here](sandbox-option.md).
|
are more limited. Read more about the option [here](sandbox-option.md).
|
||||||
**Note:** This option is currently experimental and may change or be
|
|
||||||
removed in future Electron releases.
|
|
||||||
* `enableRemoteModule` Boolean (optional) - Whether to enable the [`remote`](remote.md) module.
|
* `enableRemoteModule` Boolean (optional) - Whether to enable the [`remote`](remote.md) module.
|
||||||
Default is `true`.
|
Default is `true`.
|
||||||
* `session` [Session](session.md#class-session) (optional) - Sets the session used by the
|
* `session` [Session](session.md#class-session) (optional) - Sets the session used by the
|
||||||
@@ -373,6 +372,8 @@ It creates a new `BrowserWindow` with native properties as set by the `options`.
|
|||||||
consecutive dialog protection is triggered. If not defined the default
|
consecutive dialog protection is triggered. If not defined the default
|
||||||
message would be used, note that currently the default message is in
|
message would be used, note that currently the default message is in
|
||||||
English and not localized.
|
English and not localized.
|
||||||
|
* `disableDialogs` Boolean (optional) - Whether to disable dialogs
|
||||||
|
completely. Overrides `safeDialogs`. Default is `false`.
|
||||||
* `navigateOnDragDrop` Boolean (optional) - Whether dragging and dropping a
|
* `navigateOnDragDrop` Boolean (optional) - Whether dragging and dropping a
|
||||||
file or link onto the page causes a navigation. Default is `false`.
|
file or link onto the page causes a navigation. Default is `false`.
|
||||||
* `autoplayPolicy` String (optional) - Autoplay policy to apply to
|
* `autoplayPolicy` String (optional) - Autoplay policy to apply to
|
||||||
@@ -385,6 +386,8 @@ It creates a new `BrowserWindow` with native properties as set by the `options`.
|
|||||||
* `accessibleTitle` String (optional) - An alternative title string provided only
|
* `accessibleTitle` String (optional) - An alternative title string provided only
|
||||||
to accessibility tools such as screen readers. This string is not directly
|
to accessibility tools such as screen readers. This string is not directly
|
||||||
visible to users.
|
visible to users.
|
||||||
|
* `spellcheck` Boolean (optional) - Whether to enable the builtin spellchecker.
|
||||||
|
Default is `false`.
|
||||||
|
|
||||||
When setting minimum or maximum window size with `minWidth`/`maxWidth`/
|
When setting minimum or maximum window size with `minWidth`/`maxWidth`/
|
||||||
`minHeight`/`maxHeight`, it only constrains the users. It won't prevent you from
|
`minHeight`/`maxHeight`, it only constrains the users. It won't prevent you from
|
||||||
@@ -515,7 +518,7 @@ Emitted when the window is restored from a minimized state.
|
|||||||
Returns:
|
Returns:
|
||||||
|
|
||||||
* `event` Event
|
* `event` Event
|
||||||
* `newBounds` [`Rectangle`](structures/rectangle.md) - Size the window is being resized to.
|
* `newBounds` [Rectangle](structures/rectangle.md) - Size the window is being resized to.
|
||||||
|
|
||||||
Emitted before the window is resized. Calling `event.preventDefault()` will prevent the window from being resized.
|
Emitted before the window is resized. Calling `event.preventDefault()` will prevent the window from being resized.
|
||||||
|
|
||||||
@@ -530,7 +533,7 @@ Emitted after the window has been resized.
|
|||||||
Returns:
|
Returns:
|
||||||
|
|
||||||
* `event` Event
|
* `event` Event
|
||||||
* `newBounds` [`Rectangle`](structures/rectangle.md) - Location the window is being moved to.
|
* `newBounds` [Rectangle](structures/rectangle.md) - Location the window is being moved to.
|
||||||
|
|
||||||
Emitted before the window is moved. On Windows, calling `event.preventDefault()` will prevent the window from being moved.
|
Emitted before the window is moved. On Windows, calling `event.preventDefault()` will prevent the window from being moved.
|
||||||
|
|
||||||
@@ -623,6 +626,12 @@ Returns:
|
|||||||
|
|
||||||
Emitted on 3-finger swipe. Possible directions are `up`, `right`, `down`, `left`.
|
Emitted on 3-finger swipe. Possible directions are `up`, `right`, `down`, `left`.
|
||||||
|
|
||||||
|
The method underlying this event is built to handle older macOS-style trackpad swiping,
|
||||||
|
where the content on the screen doesn't move with the swipe. Most macOS trackpads are not
|
||||||
|
configured to allow this kind of swiping anymore, so in order for it to emit properly the
|
||||||
|
'Swipe between pages' preference in `System Preferences > Trackpad > More Gestures` must be
|
||||||
|
set to 'Swipe with two or three fingers'.
|
||||||
|
|
||||||
#### Event: 'rotate-gesture' _macOS_
|
#### Event: 'rotate-gesture' _macOS_
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
@@ -1579,7 +1588,7 @@ Same as `webContents.showDefinitionForSelection()`.
|
|||||||
|
|
||||||
#### `win.setIcon(icon)` _Windows_ _Linux_
|
#### `win.setIcon(icon)` _Windows_ _Linux_
|
||||||
|
|
||||||
* `icon` [NativeImage](native-image.md)
|
* `icon` [NativeImage](native-image.md) | String
|
||||||
|
|
||||||
Changes window icon.
|
Changes window icon.
|
||||||
|
|
||||||
@@ -1625,7 +1634,7 @@ Returns `Boolean` - Whether the menu bar is visible.
|
|||||||
* `visible` Boolean
|
* `visible` Boolean
|
||||||
* `options` Object (optional)
|
* `options` Object (optional)
|
||||||
* `visibleOnFullScreen` Boolean (optional) _macOS_ - Sets whether
|
* `visibleOnFullScreen` Boolean (optional) _macOS_ - Sets whether
|
||||||
the window should be visible above fullscreen windows
|
the window should be visible above fullscreen windows _deprecated_
|
||||||
|
|
||||||
Sets whether the window should be visible on all workspaces.
|
Sets whether the window should be visible on all workspaces.
|
||||||
|
|
||||||
@@ -1733,6 +1742,17 @@ will remove the vibrancy effect on the window.
|
|||||||
Note that `appearance-based`, `light`, `dark`, `medium-light`, and `ultra-dark` have been
|
Note that `appearance-based`, `light`, `dark`, `medium-light`, and `ultra-dark` have been
|
||||||
deprecated and will be removed in an upcoming version of macOS.
|
deprecated and will be removed in an upcoming version of macOS.
|
||||||
|
|
||||||
|
#### `win.setTrafficLightPosition(position)` _macOS_
|
||||||
|
|
||||||
|
* `position` [Point](structures/point.md)
|
||||||
|
|
||||||
|
Set a custom position for the traffic light buttons. Can only be used with `titleBarStyle` set to `hidden`.
|
||||||
|
|
||||||
|
#### `win.getTrafficLightPosition()` _macOS_
|
||||||
|
|
||||||
|
Returns `Point` - The current position for the traffic light buttons. Can only be used with `titleBarStyle`
|
||||||
|
set to `hidden`.
|
||||||
|
|
||||||
#### `win.setTouchBar(touchBar)` _macOS_ _Experimental_
|
#### `win.setTouchBar(touchBar)` _macOS_ _Experimental_
|
||||||
|
|
||||||
* `touchBar` TouchBar | null
|
* `touchBar` TouchBar | null
|
||||||
|
|||||||
@@ -22,6 +22,9 @@ which the request is associated.
|
|||||||
with which the request is associated. Defaults to the empty string. The
|
with which the request is associated. Defaults to the empty string. The
|
||||||
`session` option prevails on `partition`. Thus if a `session` is explicitly
|
`session` option prevails on `partition`. Thus if a `session` is explicitly
|
||||||
specified, `partition` is ignored.
|
specified, `partition` is ignored.
|
||||||
|
* `useSessionCookies` Boolean (optional) - Whether to send cookies with this
|
||||||
|
request from the provided session. This will make the `net` request's
|
||||||
|
cookie behavior match a `fetch` request. Default is `false`.
|
||||||
* `protocol` String (optional) - The protocol scheme in the form 'scheme:'.
|
* `protocol` String (optional) - The protocol scheme in the form 'scheme:'.
|
||||||
Currently supported values are 'http:' or 'https:'. Defaults to 'http:'.
|
Currently supported values are 'http:' or 'https:'. Defaults to 'http:'.
|
||||||
* `host` String (optional) - The server host provided as a concatenation of
|
* `host` String (optional) - The server host provided as a concatenation of
|
||||||
@@ -32,8 +35,8 @@ the hostname and the port number 'hostname:port'.
|
|||||||
* `redirect` String (optional) - The redirect mode for this request. Should be
|
* `redirect` String (optional) - The redirect mode for this request. Should be
|
||||||
one of `follow`, `error` or `manual`. Defaults to `follow`. When mode is `error`,
|
one of `follow`, `error` or `manual`. Defaults to `follow`. When mode is `error`,
|
||||||
any redirection will be aborted. When mode is `manual` the redirection will be
|
any redirection will be aborted. When mode is `manual` the redirection will be
|
||||||
deferred until [`request.followRedirect`](#requestfollowredirect) is invoked. Listen for the [`redirect`](#event-redirect) event in
|
cancelled unless [`request.followRedirect`](#requestfollowredirect) is invoked
|
||||||
this mode to get more details about the redirect request.
|
synchronously during the [`redirect`](#event-redirect) event.
|
||||||
|
|
||||||
`options` properties such as `protocol`, `host`, `hostname`, `port` and `path`
|
`options` properties such as `protocol`, `host`, `hostname`, `port` and `path`
|
||||||
strictly follow the Node.js model as described in the
|
strictly follow the Node.js model as described in the
|
||||||
@@ -70,8 +73,8 @@ Returns:
|
|||||||
* `port` Integer
|
* `port` Integer
|
||||||
* `realm` String
|
* `realm` String
|
||||||
* `callback` Function
|
* `callback` Function
|
||||||
* `username` String
|
* `username` String (optional)
|
||||||
* `password` String
|
* `password` String (optional)
|
||||||
|
|
||||||
Emitted when an authenticating proxy is asking for user credentials.
|
Emitted when an authenticating proxy is asking for user credentials.
|
||||||
|
|
||||||
@@ -136,8 +139,11 @@ Returns:
|
|||||||
* `redirectUrl` String
|
* `redirectUrl` String
|
||||||
* `responseHeaders` Record<String, String[]>
|
* `responseHeaders` Record<String, String[]>
|
||||||
|
|
||||||
Emitted when there is redirection and the mode is `manual`. Calling
|
Emitted when the server returns a redirect response (e.g. 301 Moved
|
||||||
[`request.followRedirect`](#requestfollowredirect) will continue with the redirection.
|
Permanently). Calling [`request.followRedirect`](#requestfollowredirect) will
|
||||||
|
continue with the redirection. If this event is handled,
|
||||||
|
[`request.followRedirect`](#requestfollowredirect) must be called
|
||||||
|
**synchronously**, otherwise the request will be cancelled.
|
||||||
|
|
||||||
### Instance Properties
|
### Instance Properties
|
||||||
|
|
||||||
@@ -214,7 +220,8 @@ response object,it will emit the `aborted` event.
|
|||||||
|
|
||||||
#### `request.followRedirect()`
|
#### `request.followRedirect()`
|
||||||
|
|
||||||
Continues any deferred redirection request when the redirection mode is `manual`.
|
Continues any pending redirection. Can only be called during a `'redirect'`
|
||||||
|
event.
|
||||||
|
|
||||||
#### `request.getUploadProgress()`
|
#### `request.getUploadProgress()`
|
||||||
|
|
||||||
|
|||||||
@@ -28,13 +28,14 @@ window.electron.doThing()
|
|||||||
|
|
||||||
### Main World
|
### Main World
|
||||||
|
|
||||||
The "Main World" is the javascript context that your main renderer code runs in. By default the page you load in your renderer
|
The "Main World" is the JavaScript context that your main renderer code runs in. By default, the
|
||||||
executes code in this world.
|
page you load in your renderer executes code in this world.
|
||||||
|
|
||||||
### Isolated World
|
### Isolated World
|
||||||
|
|
||||||
When `contextIsolation` is enabled in your `webPreferences` your `preload` scripts run in an "Isolated World". You can read more about
|
When `contextIsolation` is enabled in your `webPreferences`, your `preload` scripts run in an
|
||||||
context isolation and what it affects in the [BrowserWindow](browser-window.md) docs.
|
"Isolated World". You can read more about context isolation and what it affects in the
|
||||||
|
[security](../tutorial/security.md#3-enable-context-isolation-for-remote-content) docs.
|
||||||
|
|
||||||
## Methods
|
## Methods
|
||||||
|
|
||||||
@@ -50,12 +51,12 @@ The `contextBridge` module has the following methods:
|
|||||||
### API Objects
|
### API Objects
|
||||||
|
|
||||||
The `api` object provided to [`exposeInMainWorld`](#contextbridgeexposeinmainworldapikey-api-experimental) must be an object
|
The `api` object provided to [`exposeInMainWorld`](#contextbridgeexposeinmainworldapikey-api-experimental) must be an object
|
||||||
whose keys are strings and values are a `Function`, `String`, `Number`, `Array`, `Boolean` or another nested object that meets the same conditions.
|
whose keys are strings and values are a `Function`, `String`, `Number`, `Array`, `Boolean`, or another nested object that meets the same conditions.
|
||||||
|
|
||||||
`Function` values are proxied to the other context and all other values are **copied** and **frozen**. I.e. Any data / primitives sent in
|
`Function` values are proxied to the other context and all other values are **copied** and **frozen**. Any data / primitives sent in
|
||||||
the API object become immutable and updates on either side of the bridge do not result in an update on the other side.
|
the API object become immutable and updates on either side of the bridge do not result in an update on the other side.
|
||||||
|
|
||||||
An example of a complex API object is shown below.
|
An example of a complex API object is shown below:
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
const { contextBridge } = require('electron')
|
const { contextBridge } = require('electron')
|
||||||
@@ -90,22 +91,22 @@ results in some key limitations that we've outlined below.
|
|||||||
|
|
||||||
#### Parameter / Error / Return Type support
|
#### Parameter / Error / Return Type support
|
||||||
|
|
||||||
Because parameters, errors and return values are **copied** when they are sent over the bridge there are only certain types that can be used.
|
Because parameters, errors and return values are **copied** when they are sent over the bridge, there are only certain types that can be used.
|
||||||
At a high level if the type you want to use can be serialized and un-serialized into the same object it will work. A table of type support
|
At a high level, if the type you want to use can be serialized and deserialized into the same object it will work. A table of type support
|
||||||
has been included below for completeness.
|
has been included below for completeness:
|
||||||
|
|
||||||
| Type | Complexity | Parameter Support | Return Value Support | Limitations |
|
| Type | Complexity | Parameter Support | Return Value Support | Limitations |
|
||||||
| ---- | ---------- | ----------------- | -------------------- | ----------- |
|
| ---- | ---------- | ----------------- | -------------------- | ----------- |
|
||||||
| `String` | Simple | ✅ | ✅ | N/A |
|
| `String` | Simple | ✅ | ✅ | N/A |
|
||||||
| `Number` | Simple | ✅ | ✅ | N/A |
|
| `Number` | Simple | ✅ | ✅ | N/A |
|
||||||
| `Boolean` | Simple | ✅ | ✅ | N/A |
|
| `Boolean` | Simple | ✅ | ✅ | N/A |
|
||||||
| `Object` | Complex | ✅ | ✅ | Keys must be supported "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. |
|
| `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 |
|
| `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 |
|
| `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 a the return value or exact parameter. Promises nested in arrays or obejcts will be dropped. |
|
| `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. |
|
| `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 |
|
| [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 |
|
||||||
| `Symbol` | N/A | ❌ | ❌ | Symbols cannot be copied across contexts so they are dropped |
|
| `Symbol` | N/A | ❌ | ❌ | Symbols cannot be copied across contexts so they are dropped |
|
||||||
|
|
||||||
|
|
||||||
If the type you care about is not in the above table it is probably not supported.
|
If the type you care about is not in the above table, it is probably not supported.
|
||||||
|
|||||||
@@ -91,7 +91,11 @@ The `desktopCapturer` module has the following methods:
|
|||||||
|
|
||||||
Returns `Promise<DesktopCapturerSource[]>` - Resolves with an array of [`DesktopCapturerSource`](structures/desktop-capturer-source.md) objects, each `DesktopCapturerSource` represents a screen or an individual window that can be captured.
|
Returns `Promise<DesktopCapturerSource[]>` - Resolves with an array of [`DesktopCapturerSource`](structures/desktop-capturer-source.md) objects, each `DesktopCapturerSource` represents a screen or an individual window that can be captured.
|
||||||
|
|
||||||
|
**Note** Capturing the screen contents requires user consent on macOS 10.15 Catalina or higher,
|
||||||
|
which can detected by [`systemPreferences.getMediaAccessStatus`].
|
||||||
|
|
||||||
[`navigator.mediaDevices.getUserMedia`]: https://developer.mozilla.org/en/docs/Web/API/MediaDevices/getUserMedia
|
[`navigator.mediaDevices.getUserMedia`]: https://developer.mozilla.org/en/docs/Web/API/MediaDevices/getUserMedia
|
||||||
|
[`systemPreferences.getMediaAccessStatus`]: system-preferences.md#systempreferencesgetmediaaccessstatusmediatype-macos
|
||||||
|
|
||||||
## Caveats
|
## Caveats
|
||||||
|
|
||||||
|
|||||||
@@ -120,7 +120,7 @@ Returns `Promise<Object>` - Resolve with an object containing the following:
|
|||||||
|
|
||||||
* `canceled` Boolean - whether or not the dialog was canceled.
|
* `canceled` Boolean - whether or not the dialog was canceled.
|
||||||
* `filePaths` String[] - An array of file paths chosen by the user. If the dialog is cancelled this will be an empty array.
|
* `filePaths` String[] - An array of file paths chosen by the user. If the dialog is cancelled this will be an empty array.
|
||||||
* `bookmarks` String[] (optional) _macOS_ _mas_ - An array matching the `filePaths` array of base64 encoded strings which contains security scoped bookmark data. `securityScopedBookmarks` must be enabled for this to be populated.
|
* `bookmarks` String[] (optional) _macOS_ _mas_ - An array matching the `filePaths` array of base64 encoded strings which contains security scoped bookmark data. `securityScopedBookmarks` must be enabled for this to be populated. (For return values, see [table here](#bookmarks-array).)
|
||||||
|
|
||||||
The `browserWindow` argument allows the dialog to attach itself to a parent window, making it modal.
|
The `browserWindow` argument allows the dialog to attach itself to a parent window, making it modal.
|
||||||
|
|
||||||
@@ -215,7 +215,7 @@ The `filters` specifies an array of file types that can be displayed, see
|
|||||||
Returns `Promise<Object>` - Resolve with an object containing the following:
|
Returns `Promise<Object>` - Resolve with an object containing the following:
|
||||||
* `canceled` Boolean - whether or not the dialog was canceled.
|
* `canceled` Boolean - whether or not the dialog was canceled.
|
||||||
* `filePath` String (optional) - If the dialog is canceled, this will be `undefined`.
|
* `filePath` String (optional) - If the dialog is canceled, this will be `undefined`.
|
||||||
* `bookmark` String (optional) _macOS_ _mas_ - Base64 encoded string which contains the security scoped bookmark data for the saved file. `securityScopedBookmarks` must be enabled for this to be present.
|
* `bookmark` String (optional) _macOS_ _mas_ - Base64 encoded string which contains the security scoped bookmark data for the saved file. `securityScopedBookmarks` must be enabled for this to be present. (For return values, see [table here](#bookmarks-array).)
|
||||||
|
|
||||||
The `browserWindow` argument allows the dialog to attach itself to a parent window, making it modal.
|
The `browserWindow` argument allows the dialog to attach itself to a parent window, making it modal.
|
||||||
|
|
||||||
@@ -269,6 +269,7 @@ Shows a message box, it will block the process until the message box is closed.
|
|||||||
It returns the index of the clicked button.
|
It returns the index of the clicked button.
|
||||||
|
|
||||||
The `browserWindow` argument allows the dialog to attach itself to a parent window, making it modal.
|
The `browserWindow` argument allows the dialog to attach itself to a parent window, making it modal.
|
||||||
|
If `browserWindow` is not shown dialog will not be attached to it. In such case It will be displayed as independed window.
|
||||||
|
|
||||||
### `dialog.showMessageBox([browserWindow, ]options)`
|
### `dialog.showMessageBox([browserWindow, ]options)`
|
||||||
|
|
||||||
@@ -350,6 +351,17 @@ On Windows the options are more limited, due to the Win32 APIs used:
|
|||||||
* The `browserWindow` argument is ignored since it is not possible to make
|
* The `browserWindow` argument is ignored since it is not possible to make
|
||||||
this confirmation dialog modal.
|
this confirmation dialog modal.
|
||||||
|
|
||||||
|
## Bookmarks array
|
||||||
|
|
||||||
|
`showOpenDialog`, `showOpenDialogSync`, `showSaveDialog`, and `showSaveDialogSync` will return a `bookmarks` array.
|
||||||
|
|
||||||
|
| Build Type | securityScopedBookmarks boolean | Return Type | Return Value |
|
||||||
|
|------------|---------------------------------|:-----------:|--------------------------------|
|
||||||
|
| macOS mas | True | Success | `['LONGBOOKMARKSTRING']` |
|
||||||
|
| macOS mas | True | Error | `['']` (array of empty string) |
|
||||||
|
| macOS mas | False | NA | `[]` (empty array) |
|
||||||
|
| non mas | any | NA | `[]` (empty array) |
|
||||||
|
|
||||||
## Sheets
|
## Sheets
|
||||||
|
|
||||||
On macOS, dialogs are presented as sheets attached to a window if you provide
|
On macOS, dialogs are presented as sheets attached to a window if you provide
|
||||||
|
|||||||
@@ -44,7 +44,12 @@ Unsupported options are:
|
|||||||
--use-openssl-ca
|
--use-openssl-ca
|
||||||
```
|
```
|
||||||
|
|
||||||
`NODE_OPTIONS` are explicitly disallowed in packaged apps.
|
`NODE_OPTIONS` are explicitly disallowed in packaged apps, except for the following:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
--max-http-header-size
|
||||||
|
--http-parser
|
||||||
|
```
|
||||||
|
|
||||||
### `GOOGLE_API_KEY`
|
### `GOOGLE_API_KEY`
|
||||||
|
|
||||||
|
|||||||
@@ -77,6 +77,7 @@ only the next time a message is sent to `channel`, after which it is removed.
|
|||||||
|
|
||||||
* `channel` String
|
* `channel` String
|
||||||
* `listener` Function
|
* `listener` Function
|
||||||
|
* `...args` any[]
|
||||||
|
|
||||||
Removes the specified `listener` from the listener array for the specified
|
Removes the specified `listener` from the listener array for the specified
|
||||||
`channel`.
|
`channel`.
|
||||||
|
|||||||
@@ -329,9 +329,9 @@ can be called on empty images.
|
|||||||
|
|
||||||
[buffer]: https://nodejs.org/api/buffer.html#buffer_class_buffer
|
[buffer]: https://nodejs.org/api/buffer.html#buffer_class_buffer
|
||||||
|
|
||||||
## Properties
|
### Instance Properties
|
||||||
|
|
||||||
### `nativeImage.isMacTemplateImage` _macOS_
|
#### `nativeImage.isMacTemplateImage` _macOS_
|
||||||
|
|
||||||
A `Boolean` property that determines whether the image is considered a [template image](https://developer.apple.com/documentation/appkit/nsimage/1520017-template).
|
A `Boolean` property that determines whether the image is considered a [template image](https://developer.apple.com/documentation/appkit/nsimage/1520017-template).
|
||||||
|
|
||||||
|
|||||||
@@ -217,11 +217,15 @@ that all statistics are reported in Kilobytes.
|
|||||||
|
|
||||||
Returns `String` - The version of the host operating system.
|
Returns `String` - The version of the host operating system.
|
||||||
|
|
||||||
Examples:
|
Example:
|
||||||
|
|
||||||
* `macOS` -> `10.13.6`
|
```js
|
||||||
* `Windows` -> `10.0.17763`
|
const version = process.getSystemVersion()
|
||||||
* `Linux` -> `4.15.0-45-generic`
|
console.log(version)
|
||||||
|
// On macOS -> '10.13.6'
|
||||||
|
// On Windows -> '10.0.17763'
|
||||||
|
// On Linux -> '4.15.0-45-generic'
|
||||||
|
```
|
||||||
|
|
||||||
**Note:** It returns the actual operating system version instead of kernel version on macOS unlike `os.release()`.
|
**Note:** It returns the actual operating system version instead of kernel version on macOS unlike `os.release()`.
|
||||||
|
|
||||||
|
|||||||
@@ -389,9 +389,7 @@ which sends a `Buffer` as a response.
|
|||||||
* `url` String
|
* `url` String
|
||||||
* `method` String (optional)
|
* `method` String (optional)
|
||||||
* `session` Session | null (optional)
|
* `session` Session | null (optional)
|
||||||
* `uploadData` Object (optional)
|
* `uploadData` [ProtocolResponseUploadData](structures/protocol-response-upload-data.md) (optional)
|
||||||
* `contentType` String - MIME type of the content.
|
|
||||||
* `data` String - Content to be sent.
|
|
||||||
* `completion` Function (optional)
|
* `completion` Function (optional)
|
||||||
* `error` Error
|
* `error` Error
|
||||||
|
|
||||||
|
|||||||
@@ -105,6 +105,45 @@ Returns:
|
|||||||
Emitted when a render process requests preconnection to a URL, generally due to
|
Emitted when a render process requests preconnection to a URL, generally due to
|
||||||
a [resource hint](https://w3c.github.io/resource-hints/).
|
a [resource hint](https://w3c.github.io/resource-hints/).
|
||||||
|
|
||||||
|
#### Event: 'spellcheck-dictionary-initialized'
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
|
||||||
|
* `event` Event
|
||||||
|
* `languageCode` String - The language code of the dictionary file
|
||||||
|
|
||||||
|
Emitted when a hunspell dictionary file has been successfully initialized. This
|
||||||
|
occurs after the file has been downloaded.
|
||||||
|
|
||||||
|
#### Event: 'spellcheck-dictionary-download-begin'
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
|
||||||
|
* `event` Event
|
||||||
|
* `languageCode` String - The language code of the dictionary file
|
||||||
|
|
||||||
|
Emitted when a hunspell dictionary file starts downloading
|
||||||
|
|
||||||
|
#### Event: 'spellcheck-dictionary-download-success'
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
|
||||||
|
* `event` Event
|
||||||
|
* `languageCode` String - The language code of the dictionary file
|
||||||
|
|
||||||
|
Emitted when a hunspell dictionary file has been successfully downloaded
|
||||||
|
|
||||||
|
#### Event: 'spellcheck-dictionary-download-failure'
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
|
||||||
|
* `event` Event
|
||||||
|
* `languageCode` String - The language code of the dictionary file
|
||||||
|
|
||||||
|
Emitted when a hunspell dictionary file download fails. For details
|
||||||
|
on the failure you should collect a netlog and inspect the download
|
||||||
|
request.
|
||||||
|
|
||||||
### Instance Methods
|
### Instance Methods
|
||||||
|
|
||||||
The following methods are available on instances of `Session`:
|
The following methods are available on instances of `Session`:
|
||||||
@@ -456,10 +495,57 @@ this session just before normal `preload` scripts run.
|
|||||||
Returns `String[]` an array of paths to preload scripts that have been
|
Returns `String[]` an array of paths to preload scripts that have been
|
||||||
registered.
|
registered.
|
||||||
|
|
||||||
|
#### `ses.setSpellCheckerLanguages(languages)`
|
||||||
|
|
||||||
|
* `languages` String[] - An array of language codes to enable the spellchecker for.
|
||||||
|
|
||||||
|
The built in spellchecker does not automatically detect what language a user is typing in. In order for the
|
||||||
|
spell checker to correctly check their words you must call this API with an array of language codes. You can
|
||||||
|
get the list of supported language codes with the `ses.availableSpellCheckerLanguages` property.
|
||||||
|
|
||||||
|
**Note:** On macOS the OS spellchecker is used and will detect your language automatically. This API is a no-op on macOS.
|
||||||
|
|
||||||
|
#### `ses.getSpellCheckerLanguages()`
|
||||||
|
|
||||||
|
Returns `String[]` - An array of language codes the spellchecker is enabled for. If this list is empty the spellchecker
|
||||||
|
will fallback to using `en-US`. By default on launch if this setting is an empty list Electron will try to populate this
|
||||||
|
setting with the current OS locale. This setting is persisted across restarts.
|
||||||
|
|
||||||
|
**Note:** On macOS the OS spellchecker is used and has it's own list of languages. This API is a no-op on macOS.
|
||||||
|
|
||||||
|
#### `ses.setSpellCheckerDictionaryDownloadURL(url)`
|
||||||
|
|
||||||
|
* `url` String - A base URL for Electron to download hunspell dictionaries from.
|
||||||
|
|
||||||
|
By default Electron will download hunspell dictionaries from the Chromium CDN. If you want to override this
|
||||||
|
behavior you can use this API to point the dictionary downloader at your own hosted version of the hunspell
|
||||||
|
dictionaries. We publish a `hunspell_dictionaries.zip` file with each release which contains the files you need
|
||||||
|
to host here, the file server must be **case insensitive** you must upload each file twice, once with the case it
|
||||||
|
has in the ZIP file and once with the filename as all lower case.
|
||||||
|
|
||||||
|
If the files present in `hunspell_dictionaries.zip` are available at `https://example.com/dictionaries/language-code.bdic`
|
||||||
|
then you should call this api with `ses.setSpellCheckerDictionaryDownloadURL('https://example.com/dictionaries/')`. Please
|
||||||
|
note the trailing slash. The URL to the dictionaries is formed as `${url}${filename}`.
|
||||||
|
|
||||||
|
**Note:** On macOS the OS spellchecker is used and therefore we do not download any dictionary files. This API is a no-op on macOS.
|
||||||
|
|
||||||
|
#### `ses.addWordToSpellCheckerDictionary(word)`
|
||||||
|
|
||||||
|
* `word` String - The word you want to add to the dictionary
|
||||||
|
|
||||||
|
Returns `Boolean` - Whether the word was successfully written to the custom dictionary.
|
||||||
|
|
||||||
|
**Note:** On macOS and Windows 10 this word will be written to the OS custom dictionary as well
|
||||||
|
|
||||||
### Instance Properties
|
### Instance Properties
|
||||||
|
|
||||||
The following properties are available on instances of `Session`:
|
The following properties are available on instances of `Session`:
|
||||||
|
|
||||||
|
#### `ses.availableSpellCheckerLanguages` _Readonly_
|
||||||
|
|
||||||
|
A `String[]` array which consists of all the known available spell checker languages. Providing a language
|
||||||
|
code to the `setSpellCheckerLanaguages` API that isn't in this array will result in an error.
|
||||||
|
|
||||||
#### `ses.cookies` _Readonly_
|
#### `ses.cookies` _Readonly_
|
||||||
|
|
||||||
A [`Cookies`](cookies.md) object for this session.
|
A [`Cookies`](cookies.md) object for this session.
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
# ProtocolResponseUploadData Object
|
# ProtocolResponseUploadData Object
|
||||||
|
|
||||||
* `contentType` String - MIME type of the content.
|
* `contentType` String - MIME type of the content.
|
||||||
* `data` String - Content to be sent.
|
* `data` String | Buffer - Content to be sent.
|
||||||
|
|||||||
@@ -369,14 +369,6 @@ Returns `String` - Can be `dark`, `light` or `unknown`.
|
|||||||
Gets the macOS appearance setting that is currently applied to your application,
|
Gets the macOS appearance setting that is currently applied to your application,
|
||||||
maps to [NSApplication.effectiveAppearance](https://developer.apple.com/documentation/appkit/nsapplication/2967171-effectiveappearance?language=objc)
|
maps to [NSApplication.effectiveAppearance](https://developer.apple.com/documentation/appkit/nsapplication/2967171-effectiveappearance?language=objc)
|
||||||
|
|
||||||
Please note that until Electron is built targeting the 10.14 SDK, your application's
|
|
||||||
`effectiveAppearance` will default to 'light' and won't inherit the OS preference. In
|
|
||||||
the interim in order for your application to inherit the OS preference you must set the
|
|
||||||
`NSRequiresAquaSystemAppearance` key in your apps `Info.plist` to `false`. If you are
|
|
||||||
using `electron-packager` or `electron-forge` just set the `enableDarwinDarkMode`
|
|
||||||
packager option to `true`. See the [Electron Packager API](https://github.com/electron/electron-packager/blob/master/docs/api.md#darwindarkmodesupport)
|
|
||||||
for more details.
|
|
||||||
|
|
||||||
**[Deprecated](modernization/property-updates.md)**
|
**[Deprecated](modernization/property-updates.md)**
|
||||||
|
|
||||||
### `systemPreferences.getAppLevelAppearance()` _macOS_ _Deprecated_
|
### `systemPreferences.getAppLevelAppearance()` _macOS_ _Deprecated_
|
||||||
@@ -404,8 +396,6 @@ Returns `Boolean` - whether or not this device has the ability to use Touch ID.
|
|||||||
|
|
||||||
**NOTE:** This API will return `false` on macOS systems older than Sierra 10.12.2.
|
**NOTE:** This API will return `false` on macOS systems older than Sierra 10.12.2.
|
||||||
|
|
||||||
**[Deprecated](modernization/property-updates.md)**
|
|
||||||
|
|
||||||
### `systemPreferences.promptTouchID(reason)` _macOS_
|
### `systemPreferences.promptTouchID(reason)` _macOS_
|
||||||
|
|
||||||
* `reason` String - The reason you are asking for Touch ID authentication
|
* `reason` String - The reason you are asking for Touch ID authentication
|
||||||
@@ -434,11 +424,13 @@ Returns `Boolean` - `true` if the current process is a trusted accessibility cli
|
|||||||
|
|
||||||
### `systemPreferences.getMediaAccessStatus(mediaType)` _macOS_
|
### `systemPreferences.getMediaAccessStatus(mediaType)` _macOS_
|
||||||
|
|
||||||
* `mediaType` String - `microphone` or `camera`.
|
* `mediaType` String - Can be `microphone`, `camera` or `screen`.
|
||||||
|
|
||||||
Returns `String` - Can be `not-determined`, `granted`, `denied`, `restricted` or `unknown`.
|
Returns `String` - Can be `not-determined`, `granted`, `denied`, `restricted` or `unknown`.
|
||||||
|
|
||||||
This user consent was not required until macOS 10.14 Mojave, so this method will always return `granted` if your system is running 10.13 High Sierra or lower.
|
This user consent was not required on macOS 10.13 High Sierra or lower so this method will always return `granted`.
|
||||||
|
macOS 10.14 Mojave or higher requires consent for `microphone` and `camera` access.
|
||||||
|
macOS 10.15 Catalina or higher requires consent for `screen` access.
|
||||||
|
|
||||||
### `systemPreferences.askForMediaAccess(mediaType)` _macOS_
|
### `systemPreferences.askForMediaAccess(mediaType)` _macOS_
|
||||||
|
|
||||||
@@ -478,11 +470,3 @@ A `String` property that can be `dark`, `light` or `unknown`.
|
|||||||
|
|
||||||
Returns the macOS appearance setting that is currently applied to your application,
|
Returns the macOS appearance setting that is currently applied to your application,
|
||||||
maps to [NSApplication.effectiveAppearance](https://developer.apple.com/documentation/appkit/nsapplication/2967171-effectiveappearance?language=objc)
|
maps to [NSApplication.effectiveAppearance](https://developer.apple.com/documentation/appkit/nsapplication/2967171-effectiveappearance?language=objc)
|
||||||
|
|
||||||
Please note that until Electron is built targeting the 10.14 SDK, your application's
|
|
||||||
`effectiveAppearance` will default to 'light' and won't inherit the OS preference. In
|
|
||||||
the interim in order for your application to inherit the OS preference you must set the
|
|
||||||
`NSRequiresAquaSystemAppearance` key in your apps `Info.plist` to `false`. If you are
|
|
||||||
using `electron-packager` or `electron-forge` just set the `enableDarwinDarkMode`
|
|
||||||
packager option to `true`. See the [Electron Packager API](https://github.com/electron/electron-packager/blob/master/docs/api.md#darwindarkmodesupport)
|
|
||||||
for more details.
|
|
||||||
|
|||||||
@@ -454,10 +454,8 @@ The usage is the same with [the `select-client-certificate` event of
|
|||||||
Returns:
|
Returns:
|
||||||
|
|
||||||
* `event` Event
|
* `event` Event
|
||||||
* `request` Object
|
* `authenticationResponseDetails` Object
|
||||||
* `method` String
|
|
||||||
* `url` URL
|
* `url` URL
|
||||||
* `referrer` URL
|
|
||||||
* `authInfo` Object
|
* `authInfo` Object
|
||||||
* `isProxy` Boolean
|
* `isProxy` Boolean
|
||||||
* `scheme` String
|
* `scheme` String
|
||||||
@@ -465,8 +463,8 @@ Returns:
|
|||||||
* `port` Integer
|
* `port` Integer
|
||||||
* `realm` String
|
* `realm` String
|
||||||
* `callback` Function
|
* `callback` Function
|
||||||
* `username` String
|
* `username` String (optional)
|
||||||
* `password` String
|
* `password` String (optional)
|
||||||
|
|
||||||
Emitted when `webContents` wants to do basic auth.
|
Emitted when `webContents` wants to do basic auth.
|
||||||
|
|
||||||
@@ -570,6 +568,9 @@ Returns:
|
|||||||
* `titleText` String - Title or alt text of the selection that the context
|
* `titleText` String - Title or alt text of the selection that the context
|
||||||
was invoked on.
|
was invoked on.
|
||||||
* `misspelledWord` String - The misspelled word under the cursor, if any.
|
* `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
|
* `frameCharset` String - The character encoding of the frame on which the
|
||||||
menu was invoked.
|
menu was invoked.
|
||||||
* `inputFieldType` String - If the context menu was invoked on an input
|
* `inputFieldType` String - If the context menu was invoked on an input
|
||||||
@@ -1041,6 +1042,17 @@ contents.executeJavaScript('fetch("https://jsonplaceholder.typicode.com/users/1"
|
|||||||
})
|
})
|
||||||
```
|
```
|
||||||
|
|
||||||
|
#### `contents.executeJavaScriptInIsolatedWorld(worldId, scripts[, userGesture])`
|
||||||
|
|
||||||
|
* `worldId` Integer - The ID of the world to run the javascript in, `0` is the default world, `999` is the world used by Electron's `contextIsolation` feature. You can provide any integer here.
|
||||||
|
* `scripts` [WebSource[]](structures/web-source.md)
|
||||||
|
* `userGesture` Boolean (optional) - Default is `false`.
|
||||||
|
|
||||||
|
Returns `Promise<any>` - A promise that resolves with the result of the executed code
|
||||||
|
or is rejected if the result of the code is a rejected promise.
|
||||||
|
|
||||||
|
Works like `executeJavaScript` but evaluates `scripts` in an isolated context.
|
||||||
|
|
||||||
#### `contents.setIgnoreMenuShortcuts(ignore)` _Experimental_
|
#### `contents.setIgnoreMenuShortcuts(ignore)` _Experimental_
|
||||||
|
|
||||||
* `ignore` Boolean
|
* `ignore` Boolean
|
||||||
@@ -1067,11 +1079,13 @@ Returns `Boolean` - Whether audio is currently playing.
|
|||||||
|
|
||||||
#### `contents.setZoomFactor(factor)`
|
#### `contents.setZoomFactor(factor)`
|
||||||
|
|
||||||
* `factor` Number - Zoom factor.
|
* `factor` Double - Zoom factor; default is 1.0.
|
||||||
|
|
||||||
Changes the zoom factor to the specified factor. Zoom factor is
|
Changes the zoom factor to the specified factor. Zoom factor is
|
||||||
zoom percent divided by 100, so 300% = 3.0.
|
zoom percent divided by 100, so 300% = 3.0.
|
||||||
|
|
||||||
|
The factor must be greater than 0.0.
|
||||||
|
|
||||||
**[Deprecated](modernization/property-updates.md)**
|
**[Deprecated](modernization/property-updates.md)**
|
||||||
|
|
||||||
#### `contents.getZoomFactor()`
|
#### `contents.getZoomFactor()`
|
||||||
@@ -1112,7 +1126,7 @@ Sets the maximum and minimum pinch-to-zoom level.
|
|||||||
> contents.setVisualZoomLevelLimits(1, 3)
|
> contents.setVisualZoomLevelLimits(1, 3)
|
||||||
> ```
|
> ```
|
||||||
|
|
||||||
#### `contents.setLayoutZoomLevelLimits(minimumLevel, maximumLevel)`
|
#### `contents.setLayoutZoomLevelLimits(minimumLevel, maximumLevel)` _Deprecated_
|
||||||
|
|
||||||
* `minimumLevel` Number
|
* `minimumLevel` Number
|
||||||
* `maximumLevel` Number
|
* `maximumLevel` Number
|
||||||
@@ -1121,6 +1135,8 @@ Returns `Promise<void>`
|
|||||||
|
|
||||||
Sets the maximum and minimum layout-based (i.e. non-visual) zoom level.
|
Sets the maximum and minimum layout-based (i.e. non-visual) zoom level.
|
||||||
|
|
||||||
|
**Deprecated:** This API is no longer supported by Chromium.
|
||||||
|
|
||||||
#### `contents.undo()`
|
#### `contents.undo()`
|
||||||
|
|
||||||
Executes the editing command `undo` in web page.
|
Executes the editing command `undo` in web page.
|
||||||
@@ -1233,11 +1249,34 @@ Returns `Promise<NativeImage>` - Resolves with a [NativeImage](native-image.md)
|
|||||||
|
|
||||||
Captures a snapshot of the page within `rect`. Omitting `rect` will capture the whole visible page.
|
Captures a snapshot of the page within `rect`. Omitting `rect` will capture the whole visible page.
|
||||||
|
|
||||||
|
#### `contents.isBeingCaptured()`
|
||||||
|
|
||||||
|
Returns `Boolean` - Whether this page is being captured. It returns true when the capturer count
|
||||||
|
is large then 0.
|
||||||
|
|
||||||
|
#### `contents.incrementCapturerCount([size, stayHidden])`
|
||||||
|
|
||||||
|
* `size` [Size](structures/size.md) (optional) - The perferred size for the capturer.
|
||||||
|
* `stayHidden` Boolean (optional) - Keep the page hidden instead of visible.
|
||||||
|
|
||||||
|
Increase the capturer count by one. The page is considered visible when its browser window is
|
||||||
|
hidden and the capturer count is non-zero. If you would like the page to stay hidden, you should ensure that `stayHidden` is set to true.
|
||||||
|
|
||||||
|
This also affects the Page Visibility API.
|
||||||
|
|
||||||
|
#### `contents.decrementCapturerCount([stayHidden])`
|
||||||
|
|
||||||
|
* `stayHidden` Boolean (optional) - Keep the page in hidden state instead of visible.
|
||||||
|
|
||||||
|
Decrease the capturer count by one. The page will be set to hidden or occluded state when its
|
||||||
|
browser window is hidden or occluded and the capturer count reaches zero. If you want to
|
||||||
|
decrease the hidden capturer count instead you should set `stayHidden` to true.
|
||||||
|
|
||||||
#### `contents.getPrinters()`
|
#### `contents.getPrinters()`
|
||||||
|
|
||||||
Get the system printer list.
|
Get the system printer list.
|
||||||
|
|
||||||
Returns [`PrinterInfo[]`](structures/printer-info.md).
|
Returns [`PrinterInfo[]`](structures/printer-info.md)
|
||||||
|
|
||||||
#### `contents.print([options], [callback])`
|
#### `contents.print([options], [callback])`
|
||||||
|
|
||||||
@@ -1245,7 +1284,7 @@ Returns [`PrinterInfo[]`](structures/printer-info.md).
|
|||||||
* `silent` Boolean (optional) - Don't ask user for print settings. Default is `false`.
|
* `silent` Boolean (optional) - Don't ask user for print settings. Default is `false`.
|
||||||
* `printBackground` Boolean (optional) - Prints the background color and image of
|
* `printBackground` Boolean (optional) - Prints the background color and image of
|
||||||
the web page. Default is `false`.
|
the web page. Default is `false`.
|
||||||
* `deviceName` String (optional) - Set the printer device name to use. Default is `''`.
|
* `deviceName` String (optional) - Set the printer device name to use. Must be the system-defined name and not the 'friendly' name, e.g 'Brother_QL_820NWB' and not 'Brother QL-820NWB'.
|
||||||
* `color` Boolean (optional) - Set whether the printed web page will be in color or grayscale. Default is `true`.
|
* `color` Boolean (optional) - Set whether the printed web page will be in color or grayscale. Default is `true`.
|
||||||
* `margins` Object (optional)
|
* `margins` Object (optional)
|
||||||
* `marginType` String (optional) - Can be `default`, `none`, `printableArea`, or `custom`. If `custom` is chosen, you will also need to specify `top`, `bottom`, `left`, and `right`.
|
* `marginType` String (optional) - Can be `default`, `none`, `printableArea`, or `custom`. If `custom` is chosen, you will also need to specify `top`, `bottom`, `left`, and `right`.
|
||||||
@@ -1267,7 +1306,7 @@ Returns [`PrinterInfo[]`](structures/printer-info.md).
|
|||||||
* `footer` String (optional) - String to be printed as page footer.
|
* `footer` String (optional) - String to be printed as page footer.
|
||||||
* `callback` Function (optional)
|
* `callback` Function (optional)
|
||||||
* `success` Boolean - Indicates success of the print call.
|
* `success` Boolean - Indicates success of the print call.
|
||||||
* `failureReason` String - Called back if the print fails; can be `cancelled` or `failed`.
|
* `failureReason` String - Error description called back if the print fails.
|
||||||
|
|
||||||
Prints window's web page. When `silent` is set to `true`, Electron will pick
|
Prints window's web page. When `silent` is set to `true`, Electron will pick
|
||||||
the system's default printer if `deviceName` is empty and the default settings for printing.
|
the system's default printer if `deviceName` is empty and the default settings for printing.
|
||||||
@@ -1326,12 +1365,13 @@ win.loadURL('http://github.com')
|
|||||||
|
|
||||||
win.webContents.on('did-finish-load', () => {
|
win.webContents.on('did-finish-load', () => {
|
||||||
// Use default printing options
|
// Use default printing options
|
||||||
win.webContents.printToPDF({}, (error, data) => {
|
win.webContents.printToPDF({}).then(data => {
|
||||||
if (error) throw error
|
|
||||||
fs.writeFile('/tmp/print.pdf', data, (error) => {
|
fs.writeFile('/tmp/print.pdf', data, (error) => {
|
||||||
if (error) throw error
|
if (error) throw error
|
||||||
console.log('Write PDF successfully.')
|
console.log('Write PDF successfully.')
|
||||||
})
|
})
|
||||||
|
}).catch(error => {
|
||||||
|
console.log(error)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
```
|
```
|
||||||
|
|||||||
@@ -22,11 +22,13 @@ The `WebFrame` class has the following instance methods:
|
|||||||
|
|
||||||
### `webFrame.setZoomFactor(factor)`
|
### `webFrame.setZoomFactor(factor)`
|
||||||
|
|
||||||
* `factor` Number - Zoom factor.
|
* `factor` Double - Zoom factor; default is 1.0.
|
||||||
|
|
||||||
Changes the zoom factor to the specified factor. Zoom factor is
|
Changes the zoom factor to the specified factor. Zoom factor is
|
||||||
zoom percent divided by 100, so 300% = 3.0.
|
zoom percent divided by 100, so 300% = 3.0.
|
||||||
|
|
||||||
|
The factor must be greater than 0.0.
|
||||||
|
|
||||||
### `webFrame.getZoomFactor()`
|
### `webFrame.getZoomFactor()`
|
||||||
|
|
||||||
Returns `Number` - The current zoom factor.
|
Returns `Number` - The current zoom factor.
|
||||||
@@ -56,13 +58,15 @@ Sets the maximum and minimum pinch-to-zoom level.
|
|||||||
> webFrame.setVisualZoomLevelLimits(1, 3)
|
> webFrame.setVisualZoomLevelLimits(1, 3)
|
||||||
> ```
|
> ```
|
||||||
|
|
||||||
### `webFrame.setLayoutZoomLevelLimits(minimumLevel, maximumLevel)`
|
### `webFrame.setLayoutZoomLevelLimits(minimumLevel, maximumLevel)` _Deprecated_
|
||||||
|
|
||||||
* `minimumLevel` Number
|
* `minimumLevel` Number
|
||||||
* `maximumLevel` Number
|
* `maximumLevel` Number
|
||||||
|
|
||||||
Sets the maximum and minimum layout-based (i.e. non-visual) zoom level.
|
Sets the maximum and minimum layout-based (i.e. non-visual) zoom level.
|
||||||
|
|
||||||
|
**Deprecated:** This API is no longer supported by Chromium.
|
||||||
|
|
||||||
### `webFrame.setSpellCheckProvider(language, provider)`
|
### `webFrame.setSpellCheckProvider(language, provider)`
|
||||||
|
|
||||||
* `language` String
|
* `language` String
|
||||||
@@ -74,6 +78,17 @@ Sets the maximum and minimum layout-based (i.e. non-visual) zoom level.
|
|||||||
|
|
||||||
Sets a provider for spell checking in input fields and text areas.
|
Sets a provider for spell checking in input fields and text areas.
|
||||||
|
|
||||||
|
If you want to use this method you must disable the builtin spellchecker when you
|
||||||
|
construct the window.
|
||||||
|
|
||||||
|
```js
|
||||||
|
const mainWindow = new BrowserWindow({
|
||||||
|
webPreferences: {
|
||||||
|
spellcheck: false
|
||||||
|
}
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
The `provider` must be an object that has a `spellCheck` method that accepts
|
The `provider` must be an object that has a `spellCheck` method that accepts
|
||||||
an array of individual words for spellchecking.
|
an array of individual words for spellchecking.
|
||||||
The `spellCheck` function runs asynchronously and calls the `callback` function
|
The `spellCheck` function runs asynchronously and calls the `callback` function
|
||||||
|
|||||||
@@ -146,7 +146,8 @@ response are visible by the time this listener is fired.
|
|||||||
* `timestamp` Double
|
* `timestamp` Double
|
||||||
* `statusLine` String
|
* `statusLine` String
|
||||||
* `statusCode` Integer
|
* `statusCode` Integer
|
||||||
* `responseHeaders` Record<string, string> (optional)
|
* `requestHeaders` Record<string, string>
|
||||||
|
* `responseHeaders` Record<string, string[]> (optional)
|
||||||
* `callback` Function
|
* `callback` Function
|
||||||
* `headersReceivedResponse` Object
|
* `headersReceivedResponse` Object
|
||||||
* `cancel` Boolean (optional)
|
* `cancel` Boolean (optional)
|
||||||
@@ -175,7 +176,7 @@ The `callback` has to be called with a `response` object.
|
|||||||
* `resourceType` String
|
* `resourceType` String
|
||||||
* `referrer` String
|
* `referrer` String
|
||||||
* `timestamp` Double
|
* `timestamp` Double
|
||||||
* `responseHeaders` Record<string, string> (optional)
|
* `responseHeaders` Record<string, string[]> (optional)
|
||||||
* `fromCache` Boolean - Indicates whether the response was fetched from disk
|
* `fromCache` Boolean - Indicates whether the response was fetched from disk
|
||||||
cache.
|
cache.
|
||||||
* `statusCode` Integer
|
* `statusCode` Integer
|
||||||
@@ -205,7 +206,7 @@ and response headers are available.
|
|||||||
* `ip` String (optional) - The server IP address that the request was
|
* `ip` String (optional) - The server IP address that the request was
|
||||||
actually sent to.
|
actually sent to.
|
||||||
* `fromCache` Boolean
|
* `fromCache` Boolean
|
||||||
* `responseHeaders` Record<string, string> (optional)
|
* `responseHeaders` Record<string, string[]> (optional)
|
||||||
|
|
||||||
The `listener` will be called with `listener(details)` when a server initiated
|
The `listener` will be called with `listener(details)` when a server initiated
|
||||||
redirect is about to occur.
|
redirect is about to occur.
|
||||||
@@ -224,10 +225,11 @@ redirect is about to occur.
|
|||||||
* `resourceType` String
|
* `resourceType` String
|
||||||
* `referrer` String
|
* `referrer` String
|
||||||
* `timestamp` Double
|
* `timestamp` Double
|
||||||
* `responseHeaders` Record<string, string> (optional)
|
* `responseHeaders` Record<string, string[]> (optional)
|
||||||
* `fromCache` Boolean
|
* `fromCache` Boolean
|
||||||
* `statusCode` Integer
|
* `statusCode` Integer
|
||||||
* `statusLine` String
|
* `statusLine` String
|
||||||
|
* `error` String
|
||||||
|
|
||||||
The `listener` will be called with `listener(details)` when a request is
|
The `listener` will be called with `listener(details)` when a request is
|
||||||
completed.
|
completed.
|
||||||
|
|||||||
@@ -635,7 +635,7 @@ Returns `Promise<void>`
|
|||||||
|
|
||||||
Sets the maximum and minimum pinch-to-zoom level.
|
Sets the maximum and minimum pinch-to-zoom level.
|
||||||
|
|
||||||
### `<webview>.setLayoutZoomLevelLimits(minimumLevel, maximumLevel)`
|
### `<webview>.setLayoutZoomLevelLimits(minimumLevel, maximumLevel)` _Deprecated_
|
||||||
|
|
||||||
* `minimumLevel` Number
|
* `minimumLevel` Number
|
||||||
* `maximumLevel` Number
|
* `maximumLevel` Number
|
||||||
@@ -644,11 +644,13 @@ Returns `Promise<void>`
|
|||||||
|
|
||||||
Sets the maximum and minimum layout-based (i.e. non-visual) zoom level.
|
Sets the maximum and minimum layout-based (i.e. non-visual) zoom level.
|
||||||
|
|
||||||
|
**Deprecated:** This API is no longer supported by Chromium.
|
||||||
|
|
||||||
### `<webview>.showDefinitionForSelection()` _macOS_
|
### `<webview>.showDefinitionForSelection()` _macOS_
|
||||||
|
|
||||||
Shows pop-up dictionary that searches the selected word on the page.
|
Shows pop-up dictionary that searches the selected word on the page.
|
||||||
|
|
||||||
### `<webview>.getWebContents()`
|
### `<webview>.getWebContents()` _Deprecated_
|
||||||
|
|
||||||
Returns [`WebContents`](web-contents.md) - The web contents associated with
|
Returns [`WebContents`](web-contents.md) - The web contents associated with
|
||||||
this `webview`.
|
this `webview`.
|
||||||
|
|||||||
@@ -38,11 +38,15 @@ npm install --platform=win32 electron
|
|||||||
|
|
||||||
## Proxies
|
## Proxies
|
||||||
|
|
||||||
If you need to use an HTTP proxy you can [set these environment variables][proxy-env].
|
If you need to use an HTTP proxy, you need to set the `ELECTRON_GET_USE_PROXY` variable to any
|
||||||
|
value, plus additional environment variables depending on your host system's Node version:
|
||||||
|
|
||||||
|
* [Node 10 and above][proxy-env-10]
|
||||||
|
* [Before Node 10][proxy-env]
|
||||||
|
|
||||||
## Custom Mirrors and Caches
|
## Custom Mirrors and Caches
|
||||||
During installation, the `electron` module will call out to
|
During installation, the `electron` module will call out to
|
||||||
[`electron-download`][electron-download] to download prebuilt binaries of
|
[`@electron/get`][electron-get] to download prebuilt binaries of
|
||||||
Electron for your platform. It will do so by contacting GitHub's
|
Electron for your platform. It will do so by contacting GitHub's
|
||||||
release download page (`https://github.com/electron/electron/releases/tag/v$VERSION`,
|
release download page (`https://github.com/electron/electron/releases/tag/v$VERSION`,
|
||||||
where `$VERSION` is the exact version of Electron).
|
where `$VERSION` is the exact version of Electron).
|
||||||
@@ -52,7 +56,7 @@ can do so by either providing a mirror or an existing cache directory.
|
|||||||
|
|
||||||
#### Mirror
|
#### Mirror
|
||||||
You can use environment variables to override the base URL, the path at which to
|
You can use environment variables to override the base URL, the path at which to
|
||||||
look for Electron binaries, and the binary filename. The url used by `electron-download`
|
look for Electron binaries, and the binary filename. The url used by `@electron/get`
|
||||||
is composed as follows:
|
is composed as follows:
|
||||||
|
|
||||||
```plaintext
|
```plaintext
|
||||||
@@ -62,11 +66,11 @@ url = ELECTRON_MIRROR + ELECTRON_CUSTOM_DIR + '/' + ELECTRON_CUSTOM_FILENAME
|
|||||||
For instance, to use the China mirror:
|
For instance, to use the China mirror:
|
||||||
|
|
||||||
```plaintext
|
```plaintext
|
||||||
ELECTRON_MIRROR="https://npm.taobao.org/mirrors/electron/"
|
ELECTRON_MIRROR="https://cdn.npm.taobao.org/dist/electron/"
|
||||||
```
|
```
|
||||||
|
|
||||||
#### Cache
|
#### Cache
|
||||||
Alternatively, you can override the local cache. `electron-download` will cache
|
Alternatively, you can override the local cache. `@electron/get` will cache
|
||||||
downloaded binaries in a local directory to not stress your network. You can use
|
downloaded binaries in a local directory to not stress your network. You can use
|
||||||
that cache folder to provide custom builds of Electron or to avoid making contact
|
that cache folder to provide custom builds of Electron or to avoid making contact
|
||||||
with the network at all.
|
with the network at all.
|
||||||
@@ -85,16 +89,26 @@ The cache contains the version's official zip file as well as a checksum, stored
|
|||||||
a text file. A typical cache might look like this:
|
a text file. A typical cache might look like this:
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
├── electron-v1.7.9-darwin-x64.zip
|
├── httpsgithub.comelectronelectronreleasesdownloadv1.7.9electron-v1.7.9-darwin-x64.zip
|
||||||
├── electron-v1.8.1-darwin-x64.zip
|
│ └── electron-v1.7.9-darwin-x64.zip
|
||||||
├── electron-v1.8.2-beta.1-darwin-x64.zip
|
├── httpsgithub.comelectronelectronreleasesdownloadv1.7.9SHASUMS256.txt
|
||||||
├── electron-v1.8.2-beta.2-darwin-x64.zip
|
│ └── SHASUMS256.txt
|
||||||
├── electron-v1.8.2-beta.3-darwin-x64.zip
|
├── httpsgithub.comelectronelectronreleasesdownloadv1.8.1electron-v1.8.1-darwin-x64.zip
|
||||||
├── SHASUMS256.txt-1.7.9
|
│ └── electron-v1.8.1-darwin-x64.zip
|
||||||
├── SHASUMS256.txt-1.8.1
|
├── httpsgithub.comelectronelectronreleasesdownloadv1.8.1SHASUMS256.txt
|
||||||
├── SHASUMS256.txt-1.8.2-beta.1
|
│ └── SHASUMS256.txt
|
||||||
├── SHASUMS256.txt-1.8.2-beta.2
|
├── httpsgithub.comelectronelectronreleasesdownloadv1.8.2-beta.1electron-v1.8.2-beta.1-darwin-x64.zip
|
||||||
├── SHASUMS256.txt-1.8.2-beta.3
|
│ └── electron-v1.8.2-beta.1-darwin-x64.zip
|
||||||
|
├── httpsgithub.comelectronelectronreleasesdownloadv1.8.2-beta.1SHASUMS256.txt
|
||||||
|
│ └── SHASUMS256.txt
|
||||||
|
├── httpsgithub.comelectronelectronreleasesdownloadv1.8.2-beta.2electron-v1.8.2-beta.2-darwin-x64.zip
|
||||||
|
│ └── electron-v1.8.2-beta.2-darwin-x64.zip
|
||||||
|
├── httpsgithub.comelectronelectronreleasesdownloadv1.8.2-beta.2SHASUMS256.txt
|
||||||
|
│ └── SHASUMS256.txt
|
||||||
|
├── httpsgithub.comelectronelectronreleasesdownloadv1.8.2-beta.3electron-v1.8.2-beta.3-darwin-x64.zip
|
||||||
|
│ └── electron-v1.8.2-beta.3-darwin-x64.zip
|
||||||
|
└── httpsgithub.comelectronelectronreleasesdownloadv1.8.2-beta.3SHASUMS256.txt
|
||||||
|
└── SHASUMS256.txt
|
||||||
```
|
```
|
||||||
|
|
||||||
## Skip binary download
|
## Skip binary download
|
||||||
@@ -146,7 +160,8 @@ If you need to force a re-download of the asset and the SHASUM file set the
|
|||||||
[npm]: https://docs.npmjs.com
|
[npm]: https://docs.npmjs.com
|
||||||
[versioning]: ./electron-versioning.md
|
[versioning]: ./electron-versioning.md
|
||||||
[releases]: https://github.com/electron/electron/releases
|
[releases]: https://github.com/electron/electron/releases
|
||||||
[proxy-env]: https://github.com/request/request/tree/f0c4ec061141051988d1216c24936ad2e7d5c45d#controlling-proxy-behaviour-using-environment-variables
|
[proxy-env-10]: https://github.com/gajus/global-agent/blob/v2.1.5/README.md#environment-variables
|
||||||
[electron-download]: https://github.com/electron-userland/electron-download
|
[proxy-env]: https://github.com/np-maintain/global-tunnel/blob/v2.7.1/README.md#auto-config
|
||||||
|
[electron-get]: https://github.com/electron/get
|
||||||
[npm-permissions]: https://docs.npmjs.com/getting-started/fixing-npm-permissions
|
[npm-permissions]: https://docs.npmjs.com/getting-started/fixing-npm-permissions
|
||||||
[unsafe-perm]: https://docs.npmjs.com/misc/config#unsafe-perm
|
[unsafe-perm]: https://docs.npmjs.com/misc/config#unsafe-perm
|
||||||
|
|||||||
@@ -54,13 +54,13 @@ at once, consider the [Chrome Tracing] tool.
|
|||||||
Chances are that your app could be a little leaner, faster, and generally less
|
Chances are that your app could be a little leaner, faster, and generally less
|
||||||
resource-hungry if you attempt these steps.
|
resource-hungry if you attempt these steps.
|
||||||
|
|
||||||
1) [Carelessly including modules](#1-carelessly-including-modules)
|
1. [Carelessly including modules](#1-carelessly-including-modules)
|
||||||
2) [Loading and running code too soon](#2-loading-and-running-code-too-soon)
|
2. [Loading and running code too soon](#2-loading-and-running-code-too-soon)
|
||||||
3) [Blocking the main process](#3-blocking-the-main-process)
|
3. [Blocking the main process](#3-blocking-the-main-process)
|
||||||
4) [Blocking the renderer process](#4-blocking-the-renderer-process)
|
4. [Blocking the renderer process](#4-blocking-the-renderer-process)
|
||||||
5) [Unnecessary polyfills](#5-unnecessary-polyfills)
|
5. [Unnecessary polyfills](#5-unnecessary-polyfills)
|
||||||
6) [Unnecessary or blocking network requests](#6-unnecessary-or-blocking-network-requests)
|
6. [Unnecessary or blocking network requests](#6-unnecessary-or-blocking-network-requests)
|
||||||
7) [Bundle your code](#7-bundle-your-code)
|
7. [Bundle your code](#7-bundle-your-code)
|
||||||
|
|
||||||
## 1) Carelessly including modules
|
## 1) Carelessly including modules
|
||||||
|
|
||||||
@@ -418,7 +418,6 @@ As of writing this article, the popular choices include [Webpack][webpack],
|
|||||||
[performance-cpu-prof]: ../images/performance-cpu-prof.png
|
[performance-cpu-prof]: ../images/performance-cpu-prof.png
|
||||||
[performance-heap-prof]: ../images/performance-heap-prof.png
|
[performance-heap-prof]: ../images/performance-heap-prof.png
|
||||||
[chrome-devtools-tutorial]: https://developers.google.com/web/tools/chrome-devtools/evaluate-performance/
|
[chrome-devtools-tutorial]: https://developers.google.com/web/tools/chrome-devtools/evaluate-performance/
|
||||||
[chrome-tracing-tutorial]:
|
|
||||||
[worker-threads]: https://nodejs.org/api/worker_threads.html
|
[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
|
[web-workers]: https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Using_web_workers
|
||||||
[request-idle-callback]: https://developer.mozilla.org/en-US/docs/Web/API/Window/requestIdleCallback
|
[request-idle-callback]: https://developer.mozilla.org/en-US/docs/Web/API/Window/requestIdleCallback
|
||||||
|
|||||||
@@ -61,7 +61,6 @@ The output should look roughly like this:
|
|||||||
├── libgcrypt.so.11
|
├── libgcrypt.so.11
|
||||||
├── libnode.so
|
├── libnode.so
|
||||||
├── locales
|
├── locales
|
||||||
├── natives_blob.bin
|
|
||||||
├── resources
|
├── resources
|
||||||
├── v8_context_snapshot.bin
|
├── v8_context_snapshot.bin
|
||||||
└── version
|
└── version
|
||||||
|
|||||||
@@ -62,7 +62,6 @@ The output should look roughly like this:
|
|||||||
│ ├── am.pak
|
│ ├── am.pak
|
||||||
│ ├── ar.pak
|
│ ├── ar.pak
|
||||||
│ ├── [...]
|
│ ├── [...]
|
||||||
├── natives_blob.bin
|
|
||||||
├── node.dll
|
├── node.dll
|
||||||
├── resources
|
├── resources
|
||||||
│ ├── app
|
│ ├── app
|
||||||
|
|||||||
@@ -69,4 +69,10 @@
|
|||||||
<message name="IDS_PICTURE_IN_PICTURE_PREVIOUS_TRACK_CONTROL_ACCESSIBLE_TEXT" desc="Accessible text label used for the controls button in the Picture-in-Picture window. The button invokes previous track action.">
|
<message name="IDS_PICTURE_IN_PICTURE_PREVIOUS_TRACK_CONTROL_ACCESSIBLE_TEXT" desc="Accessible text label used for the controls button in the Picture-in-Picture window. The button invokes previous track action.">
|
||||||
Previous track
|
Previous track
|
||||||
</message>
|
</message>
|
||||||
|
<message name="IDS_SPELLCHECK_DICTIONARY" use_name_for_id="true">
|
||||||
|
en-US
|
||||||
|
</message>
|
||||||
|
<message name="IDS_ACCEPT_LANGUAGES" use_name_for_id="true">
|
||||||
|
en-US,en
|
||||||
|
</message>
|
||||||
</grit-part>
|
</grit-part>
|
||||||
|
|||||||
@@ -135,12 +135,12 @@ auto_filenames = {
|
|||||||
"lib/common/api/module-list.ts",
|
"lib/common/api/module-list.ts",
|
||||||
"lib/common/api/native-image.js",
|
"lib/common/api/native-image.js",
|
||||||
"lib/common/api/shell.js",
|
"lib/common/api/shell.js",
|
||||||
"lib/common/clipboard-utils.ts",
|
|
||||||
"lib/common/crash-reporter.js",
|
"lib/common/crash-reporter.js",
|
||||||
"lib/common/define-properties.ts",
|
"lib/common/define-properties.ts",
|
||||||
"lib/common/electron-binding-setup.ts",
|
"lib/common/electron-binding-setup.ts",
|
||||||
"lib/common/remote/type-utils.ts",
|
"lib/common/type-utils.ts",
|
||||||
"lib/common/web-view-methods.ts",
|
"lib/common/web-view-methods.ts",
|
||||||
|
"lib/common/webpack-globals-provider.ts",
|
||||||
"lib/renderer/api/context-bridge.ts",
|
"lib/renderer/api/context-bridge.ts",
|
||||||
"lib/renderer/api/crash-reporter.js",
|
"lib/renderer/api/crash-reporter.js",
|
||||||
"lib/renderer/api/desktop-capturer.ts",
|
"lib/renderer/api/desktop-capturer.ts",
|
||||||
@@ -165,6 +165,7 @@ auto_filenames = {
|
|||||||
"lib/renderer/web-view/web-view-element.ts",
|
"lib/renderer/web-view/web-view-element.ts",
|
||||||
"lib/renderer/web-view/web-view-impl.ts",
|
"lib/renderer/web-view/web-view-impl.ts",
|
||||||
"lib/renderer/web-view/web-view-init.ts",
|
"lib/renderer/web-view/web-view-init.ts",
|
||||||
|
"lib/renderer/window-setup.ts",
|
||||||
"lib/sandboxed_renderer/api/exports/electron.ts",
|
"lib/sandboxed_renderer/api/exports/electron.ts",
|
||||||
"lib/sandboxed_renderer/api/module-list.ts",
|
"lib/sandboxed_renderer/api/module-list.ts",
|
||||||
"lib/sandboxed_renderer/init.js",
|
"lib/sandboxed_renderer/init.js",
|
||||||
@@ -188,6 +189,7 @@ auto_filenames = {
|
|||||||
|
|
||||||
content_script_bundle_deps = [
|
content_script_bundle_deps = [
|
||||||
"lib/common/electron-binding-setup.ts",
|
"lib/common/electron-binding-setup.ts",
|
||||||
|
"lib/common/webpack-globals-provider.ts",
|
||||||
"lib/content_script/init.js",
|
"lib/content_script/init.js",
|
||||||
"lib/renderer/chrome-api.ts",
|
"lib/renderer/chrome-api.ts",
|
||||||
"lib/renderer/extensions/event.ts",
|
"lib/renderer/extensions/event.ts",
|
||||||
@@ -266,15 +268,15 @@ auto_filenames = {
|
|||||||
"lib/common/api/module-list.ts",
|
"lib/common/api/module-list.ts",
|
||||||
"lib/common/api/native-image.js",
|
"lib/common/api/native-image.js",
|
||||||
"lib/common/api/shell.js",
|
"lib/common/api/shell.js",
|
||||||
"lib/common/clipboard-utils.ts",
|
|
||||||
"lib/common/crash-reporter.js",
|
"lib/common/crash-reporter.js",
|
||||||
"lib/common/define-properties.ts",
|
"lib/common/define-properties.ts",
|
||||||
"lib/common/electron-binding-setup.ts",
|
"lib/common/electron-binding-setup.ts",
|
||||||
"lib/common/init.ts",
|
"lib/common/init.ts",
|
||||||
"lib/common/parse-features-string.js",
|
"lib/common/parse-features-string.js",
|
||||||
"lib/common/remote/type-utils.ts",
|
|
||||||
"lib/common/reset-search-paths.ts",
|
"lib/common/reset-search-paths.ts",
|
||||||
|
"lib/common/type-utils.ts",
|
||||||
"lib/common/web-view-methods.ts",
|
"lib/common/web-view-methods.ts",
|
||||||
|
"lib/common/webpack-globals-provider.ts",
|
||||||
"lib/renderer/ipc-renderer-internal-utils.ts",
|
"lib/renderer/ipc-renderer-internal-utils.ts",
|
||||||
"lib/renderer/ipc-renderer-internal.ts",
|
"lib/renderer/ipc-renderer-internal.ts",
|
||||||
"package.json",
|
"package.json",
|
||||||
@@ -289,14 +291,14 @@ auto_filenames = {
|
|||||||
"lib/common/api/module-list.ts",
|
"lib/common/api/module-list.ts",
|
||||||
"lib/common/api/native-image.js",
|
"lib/common/api/native-image.js",
|
||||||
"lib/common/api/shell.js",
|
"lib/common/api/shell.js",
|
||||||
"lib/common/clipboard-utils.ts",
|
|
||||||
"lib/common/crash-reporter.js",
|
"lib/common/crash-reporter.js",
|
||||||
"lib/common/define-properties.ts",
|
"lib/common/define-properties.ts",
|
||||||
"lib/common/electron-binding-setup.ts",
|
"lib/common/electron-binding-setup.ts",
|
||||||
"lib/common/init.ts",
|
"lib/common/init.ts",
|
||||||
"lib/common/remote/type-utils.ts",
|
|
||||||
"lib/common/reset-search-paths.ts",
|
"lib/common/reset-search-paths.ts",
|
||||||
|
"lib/common/type-utils.ts",
|
||||||
"lib/common/web-view-methods.ts",
|
"lib/common/web-view-methods.ts",
|
||||||
|
"lib/common/webpack-globals-provider.ts",
|
||||||
"lib/renderer/api/context-bridge.ts",
|
"lib/renderer/api/context-bridge.ts",
|
||||||
"lib/renderer/api/crash-reporter.js",
|
"lib/renderer/api/crash-reporter.js",
|
||||||
"lib/renderer/api/desktop-capturer.ts",
|
"lib/renderer/api/desktop-capturer.ts",
|
||||||
@@ -338,13 +340,13 @@ auto_filenames = {
|
|||||||
"lib/common/api/module-list.ts",
|
"lib/common/api/module-list.ts",
|
||||||
"lib/common/api/native-image.js",
|
"lib/common/api/native-image.js",
|
||||||
"lib/common/api/shell.js",
|
"lib/common/api/shell.js",
|
||||||
"lib/common/clipboard-utils.ts",
|
|
||||||
"lib/common/crash-reporter.js",
|
"lib/common/crash-reporter.js",
|
||||||
"lib/common/define-properties.ts",
|
"lib/common/define-properties.ts",
|
||||||
"lib/common/electron-binding-setup.ts",
|
"lib/common/electron-binding-setup.ts",
|
||||||
"lib/common/init.ts",
|
"lib/common/init.ts",
|
||||||
"lib/common/remote/type-utils.ts",
|
|
||||||
"lib/common/reset-search-paths.ts",
|
"lib/common/reset-search-paths.ts",
|
||||||
|
"lib/common/type-utils.ts",
|
||||||
|
"lib/common/webpack-globals-provider.ts",
|
||||||
"lib/renderer/api/context-bridge.ts",
|
"lib/renderer/api/context-bridge.ts",
|
||||||
"lib/renderer/api/crash-reporter.js",
|
"lib/renderer/api/crash-reporter.js",
|
||||||
"lib/renderer/api/desktop-capturer.ts",
|
"lib/renderer/api/desktop-capturer.ts",
|
||||||
|
|||||||
566
filenames.gni
566
filenames.gni
@@ -22,100 +22,99 @@ filenames = {
|
|||||||
]
|
]
|
||||||
|
|
||||||
lib_sources = [
|
lib_sources = [
|
||||||
"shell/app/atom_content_client.cc",
|
"chromium_src/chrome/browser/process_singleton.h",
|
||||||
"shell/app/atom_content_client.h",
|
"chromium_src/chrome/browser/process_singleton_posix.cc",
|
||||||
"shell/app/atom_main_delegate.cc",
|
"chromium_src/chrome/browser/process_singleton_win.cc",
|
||||||
"shell/app/atom_main_delegate.h",
|
"chromium_src/chrome/browser/ui/views/frame/global_menu_bar_registrar_x11.cc",
|
||||||
"shell/app/atom_main_delegate_mac.h",
|
"chromium_src/chrome/browser/ui/views/frame/global_menu_bar_registrar_x11.h",
|
||||||
"shell/app/atom_main_delegate_mac.mm",
|
"shell/app/electron_content_client.cc",
|
||||||
|
"shell/app/electron_content_client.h",
|
||||||
|
"shell/app/electron_main_delegate.cc",
|
||||||
|
"shell/app/electron_main_delegate.h",
|
||||||
|
"shell/app/electron_main_delegate_mac.h",
|
||||||
|
"shell/app/electron_main_delegate_mac.mm",
|
||||||
"shell/app/command_line_args.cc",
|
"shell/app/command_line_args.cc",
|
||||||
"shell/app/command_line_args.h",
|
"shell/app/command_line_args.h",
|
||||||
"shell/app/uv_task_runner.cc",
|
"shell/app/uv_task_runner.cc",
|
||||||
"shell/app/uv_task_runner.h",
|
"shell/app/uv_task_runner.h",
|
||||||
"shell/browser/api/atom_api_app_mac.mm",
|
"shell/browser/api/electron_api_app.cc",
|
||||||
"shell/browser/api/atom_api_app.cc",
|
"shell/browser/api/electron_api_app.h",
|
||||||
"shell/browser/font_defaults.cc",
|
"shell/browser/api/electron_api_app_mac.mm",
|
||||||
"shell/browser/font_defaults.h",
|
"shell/browser/api/electron_api_auto_updater.cc",
|
||||||
"shell/browser/feature_list.cc",
|
"shell/browser/api/electron_api_auto_updater.h",
|
||||||
"shell/browser/feature_list.h",
|
"shell/browser/api/electron_api_browser_view.cc",
|
||||||
"shell/browser/api/atom_api_app.h",
|
"shell/browser/api/electron_api_browser_view.h",
|
||||||
"shell/browser/api/atom_api_auto_updater.cc",
|
"shell/browser/api/electron_api_browser_window.cc",
|
||||||
"shell/browser/api/atom_api_auto_updater.h",
|
"shell/browser/api/electron_api_browser_window.h",
|
||||||
"shell/browser/api/atom_api_browser_view.cc",
|
"shell/browser/api/electron_api_browser_window_mac.mm",
|
||||||
"shell/browser/api/atom_api_browser_view.h",
|
"shell/browser/api/electron_api_browser_window_views.cc",
|
||||||
"shell/browser/api/atom_api_content_tracing.cc",
|
"shell/browser/api/electron_api_content_tracing.cc",
|
||||||
"shell/browser/api/atom_api_cookies.cc",
|
"shell/browser/api/electron_api_cookies.cc",
|
||||||
"shell/browser/api/atom_api_cookies.h",
|
"shell/browser/api/electron_api_cookies.h",
|
||||||
"shell/browser/api/atom_api_data_pipe_holder.cc",
|
"shell/browser/api/electron_api_data_pipe_holder.cc",
|
||||||
"shell/browser/api/atom_api_data_pipe_holder.h",
|
"shell/browser/api/electron_api_data_pipe_holder.h",
|
||||||
"shell/browser/api/atom_api_debugger.cc",
|
"shell/browser/api/electron_api_debugger.cc",
|
||||||
"shell/browser/api/atom_api_debugger.h",
|
"shell/browser/api/electron_api_debugger.h",
|
||||||
"shell/browser/api/atom_api_dialog.cc",
|
"shell/browser/api/electron_api_dialog.cc",
|
||||||
"shell/browser/api/atom_api_download_item.cc",
|
"shell/browser/api/electron_api_download_item.cc",
|
||||||
"shell/browser/api/atom_api_download_item.h",
|
"shell/browser/api/electron_api_download_item.h",
|
||||||
"shell/browser/api/atom_api_event.cc",
|
"shell/browser/api/electron_api_event.cc",
|
||||||
"shell/browser/api/atom_api_global_shortcut.cc",
|
"shell/browser/api/electron_api_global_shortcut.cc",
|
||||||
"shell/browser/api/atom_api_global_shortcut.h",
|
"shell/browser/api/electron_api_global_shortcut.h",
|
||||||
"shell/browser/api/atom_api_in_app_purchase.cc",
|
"shell/browser/api/electron_api_in_app_purchase.cc",
|
||||||
"shell/browser/api/atom_api_in_app_purchase.h",
|
"shell/browser/api/electron_api_in_app_purchase.h",
|
||||||
"shell/browser/api/atom_api_menu.cc",
|
"shell/browser/api/electron_api_menu.cc",
|
||||||
"shell/browser/api/atom_api_menu.h",
|
"shell/browser/api/electron_api_menu.h",
|
||||||
"shell/browser/api/atom_api_menu_mac.h",
|
"shell/browser/api/electron_api_menu_mac.h",
|
||||||
"shell/browser/api/atom_api_menu_mac.mm",
|
"shell/browser/api/electron_api_menu_mac.mm",
|
||||||
"shell/browser/api/atom_api_menu_views.cc",
|
"shell/browser/api/electron_api_menu_views.cc",
|
||||||
"shell/browser/api/atom_api_menu_views.h",
|
"shell/browser/api/electron_api_menu_views.h",
|
||||||
"shell/browser/api/atom_api_native_theme.cc",
|
"shell/browser/api/electron_api_native_theme.cc",
|
||||||
"shell/browser/api/atom_api_native_theme.h",
|
"shell/browser/api/electron_api_native_theme.h",
|
||||||
"shell/browser/api/atom_api_native_theme_mac.mm",
|
"shell/browser/api/electron_api_native_theme_mac.mm",
|
||||||
"shell/browser/api/atom_api_net.cc",
|
"shell/browser/api/electron_api_net.cc",
|
||||||
"shell/browser/api/atom_api_net.h",
|
"shell/browser/api/electron_api_net.h",
|
||||||
"shell/browser/api/atom_api_net_log.cc",
|
"shell/browser/api/electron_api_net_log.cc",
|
||||||
"shell/browser/api/atom_api_net_log.h",
|
"shell/browser/api/electron_api_net_log.h",
|
||||||
"shell/browser/api/atom_api_notification.cc",
|
"shell/browser/api/electron_api_notification.cc",
|
||||||
"shell/browser/api/atom_api_notification.h",
|
"shell/browser/api/electron_api_notification.h",
|
||||||
"shell/browser/api/atom_api_power_monitor_mac.mm",
|
"shell/browser/api/electron_api_power_monitor.cc",
|
||||||
"shell/browser/api/atom_api_power_monitor_win.cc",
|
"shell/browser/api/electron_api_power_monitor.h",
|
||||||
"shell/browser/api/atom_api_power_monitor.cc",
|
"shell/browser/api/electron_api_power_monitor_mac.mm",
|
||||||
"shell/browser/api/atom_api_power_monitor.h",
|
"shell/browser/api/electron_api_power_monitor_win.cc",
|
||||||
"shell/browser/api/atom_api_power_save_blocker.cc",
|
"shell/browser/api/electron_api_power_save_blocker.cc",
|
||||||
"shell/browser/api/atom_api_power_save_blocker.h",
|
"shell/browser/api/electron_api_power_save_blocker.h",
|
||||||
"shell/browser/api/atom_api_protocol_ns.cc",
|
"shell/browser/api/electron_api_protocol_ns.cc",
|
||||||
"shell/browser/api/atom_api_protocol_ns.h",
|
"shell/browser/api/electron_api_protocol_ns.h",
|
||||||
"shell/browser/api/atom_api_screen.cc",
|
"shell/browser/api/electron_api_screen.cc",
|
||||||
"shell/browser/api/atom_api_screen.h",
|
"shell/browser/api/electron_api_screen.h",
|
||||||
"shell/browser/api/atom_api_session.cc",
|
"shell/browser/api/electron_api_session.cc",
|
||||||
"shell/browser/api/atom_api_session.h",
|
"shell/browser/api/electron_api_session.h",
|
||||||
"shell/browser/api/atom_api_system_preferences.cc",
|
"shell/browser/api/electron_api_system_preferences.cc",
|
||||||
"shell/browser/api/atom_api_system_preferences.h",
|
"shell/browser/api/electron_api_system_preferences.h",
|
||||||
"shell/browser/api/atom_api_system_preferences_mac.mm",
|
"shell/browser/api/electron_api_system_preferences_mac.mm",
|
||||||
"shell/browser/api/atom_api_system_preferences_win.cc",
|
"shell/browser/api/electron_api_system_preferences_win.cc",
|
||||||
"shell/browser/api/atom_api_top_level_window.cc",
|
"shell/browser/api/electron_api_top_level_window.cc",
|
||||||
"shell/browser/api/atom_api_top_level_window.h",
|
"shell/browser/api/electron_api_top_level_window.h",
|
||||||
"shell/browser/api/atom_api_tray.cc",
|
"shell/browser/api/electron_api_tray.cc",
|
||||||
"shell/browser/api/atom_api_tray.h",
|
"shell/browser/api/electron_api_tray.h",
|
||||||
"shell/browser/api/atom_api_url_request_ns.cc",
|
"shell/browser/api/electron_api_url_loader.cc",
|
||||||
"shell/browser/api/atom_api_url_request_ns.h",
|
"shell/browser/api/electron_api_url_loader.h",
|
||||||
"shell/browser/api/atom_api_view.cc",
|
"shell/browser/api/electron_api_view.cc",
|
||||||
"shell/browser/api/atom_api_view.h",
|
"shell/browser/api/electron_api_view.h",
|
||||||
"shell/browser/api/atom_api_web_contents.cc",
|
"shell/browser/api/electron_api_web_contents.cc",
|
||||||
"shell/browser/api/atom_api_web_contents.h",
|
"shell/browser/api/electron_api_web_contents.h",
|
||||||
"shell/browser/api/atom_api_web_contents_impl.cc",
|
"shell/browser/api/electron_api_web_contents_impl.cc",
|
||||||
"shell/browser/api/atom_api_web_contents_mac.mm",
|
"shell/browser/api/electron_api_web_contents_mac.mm",
|
||||||
"shell/browser/api/atom_api_web_contents_view.cc",
|
"shell/browser/api/electron_api_web_contents_view.cc",
|
||||||
"shell/browser/api/atom_api_web_contents_view.h",
|
"shell/browser/api/electron_api_web_contents_view.h",
|
||||||
"shell/browser/api/atom_api_web_request_ns.cc",
|
"shell/browser/api/electron_api_web_request_ns.cc",
|
||||||
"shell/browser/api/atom_api_web_request_ns.h",
|
"shell/browser/api/electron_api_web_request_ns.h",
|
||||||
"shell/browser/api/atom_api_web_view_manager.cc",
|
"shell/browser/api/electron_api_web_view_manager.cc",
|
||||||
"shell/browser/api/atom_api_browser_window.cc",
|
|
||||||
"shell/browser/api/atom_api_browser_window.h",
|
|
||||||
"shell/browser/api/atom_api_browser_window_mac.mm",
|
|
||||||
"shell/browser/api/atom_api_browser_window_views.cc",
|
|
||||||
"shell/browser/api/event.cc",
|
"shell/browser/api/event.cc",
|
||||||
"shell/browser/api/event.h",
|
"shell/browser/api/event.h",
|
||||||
"shell/browser/api/event_emitter_deprecated.cc",
|
"shell/browser/api/event_emitter_deprecated.cc",
|
||||||
"shell/browser/api/event_emitter_deprecated.h",
|
"shell/browser/api/event_emitter_deprecated.h",
|
||||||
"shell/browser/api/trackable_object.cc",
|
|
||||||
"shell/browser/api/trackable_object.h",
|
|
||||||
"shell/browser/api/frame_subscriber.cc",
|
"shell/browser/api/frame_subscriber.cc",
|
||||||
"shell/browser/api/frame_subscriber.h",
|
"shell/browser/api/frame_subscriber.h",
|
||||||
"shell/browser/api/gpu_info_enumerator.cc",
|
"shell/browser/api/gpu_info_enumerator.cc",
|
||||||
@@ -126,67 +125,75 @@ filenames = {
|
|||||||
"shell/browser/api/process_metric.h",
|
"shell/browser/api/process_metric.h",
|
||||||
"shell/browser/api/save_page_handler.cc",
|
"shell/browser/api/save_page_handler.cc",
|
||||||
"shell/browser/api/save_page_handler.h",
|
"shell/browser/api/save_page_handler.h",
|
||||||
|
"shell/browser/api/trackable_object.cc",
|
||||||
|
"shell/browser/api/trackable_object.h",
|
||||||
|
"shell/browser/electron_autofill_driver.cc",
|
||||||
|
"shell/browser/electron_autofill_driver.h",
|
||||||
|
"shell/browser/electron_autofill_driver_factory.cc",
|
||||||
|
"shell/browser/electron_autofill_driver_factory.h",
|
||||||
|
"shell/browser/electron_browser_client.cc",
|
||||||
|
"shell/browser/electron_browser_client.h",
|
||||||
|
"shell/browser/electron_browser_context.cc",
|
||||||
|
"shell/browser/electron_browser_context.h",
|
||||||
|
"shell/browser/electron_browser_main_parts.cc",
|
||||||
|
"shell/browser/electron_browser_main_parts.h",
|
||||||
|
"shell/browser/electron_browser_main_parts_mac.mm",
|
||||||
|
"shell/browser/electron_browser_main_parts_posix.cc",
|
||||||
|
"shell/browser/electron_download_manager_delegate.cc",
|
||||||
|
"shell/browser/electron_download_manager_delegate.h",
|
||||||
|
"shell/browser/electron_gpu_client.cc",
|
||||||
|
"shell/browser/electron_gpu_client.h",
|
||||||
|
"shell/browser/electron_javascript_dialog_manager.cc",
|
||||||
|
"shell/browser/electron_javascript_dialog_manager.h",
|
||||||
|
"shell/browser/electron_navigation_throttle.cc",
|
||||||
|
"shell/browser/electron_navigation_throttle.h",
|
||||||
|
"shell/browser/electron_paths.h",
|
||||||
|
"shell/browser/electron_permission_manager.cc",
|
||||||
|
"shell/browser/electron_permission_manager.h",
|
||||||
|
"shell/browser/electron_quota_permission_context.cc",
|
||||||
|
"shell/browser/electron_quota_permission_context.h",
|
||||||
|
"shell/browser/electron_speech_recognition_manager_delegate.cc",
|
||||||
|
"shell/browser/electron_speech_recognition_manager_delegate.h",
|
||||||
|
"shell/browser/electron_web_ui_controller_factory.cc",
|
||||||
|
"shell/browser/electron_web_ui_controller_factory.h",
|
||||||
"shell/browser/auto_updater.cc",
|
"shell/browser/auto_updater.cc",
|
||||||
"shell/browser/auto_updater.h",
|
"shell/browser/auto_updater.h",
|
||||||
"shell/browser/auto_updater_mac.mm",
|
"shell/browser/auto_updater_mac.mm",
|
||||||
"shell/browser/atom_autofill_driver_factory.cc",
|
|
||||||
"shell/browser/atom_autofill_driver_factory.h",
|
|
||||||
"shell/browser/atom_autofill_driver.cc",
|
|
||||||
"shell/browser/atom_autofill_driver.h",
|
|
||||||
"shell/browser/atom_browser_client.cc",
|
|
||||||
"shell/browser/atom_browser_client.h",
|
|
||||||
"shell/browser/atom_browser_context.cc",
|
|
||||||
"shell/browser/atom_browser_context.h",
|
|
||||||
"shell/browser/atom_download_manager_delegate.cc",
|
|
||||||
"shell/browser/atom_download_manager_delegate.h",
|
|
||||||
"shell/browser/atom_gpu_client.cc",
|
|
||||||
"shell/browser/atom_gpu_client.h",
|
|
||||||
"shell/browser/atom_browser_main_parts.cc",
|
|
||||||
"shell/browser/atom_browser_main_parts.h",
|
|
||||||
"shell/browser/atom_browser_main_parts_mac.mm",
|
|
||||||
"shell/browser/atom_browser_main_parts_posix.cc",
|
|
||||||
"shell/browser/atom_javascript_dialog_manager.cc",
|
|
||||||
"shell/browser/atom_javascript_dialog_manager.h",
|
|
||||||
"shell/browser/atom_navigation_throttle.h",
|
|
||||||
"shell/browser/atom_navigation_throttle.cc",
|
|
||||||
"shell/browser/atom_paths.h",
|
|
||||||
"shell/browser/atom_permission_manager.cc",
|
|
||||||
"shell/browser/atom_permission_manager.h",
|
|
||||||
"shell/browser/atom_quota_permission_context.cc",
|
|
||||||
"shell/browser/atom_quota_permission_context.h",
|
|
||||||
"shell/browser/atom_speech_recognition_manager_delegate.cc",
|
|
||||||
"shell/browser/atom_speech_recognition_manager_delegate.h",
|
|
||||||
"shell/browser/atom_web_ui_controller_factory.cc",
|
|
||||||
"shell/browser/atom_web_ui_controller_factory.h",
|
|
||||||
"shell/browser/browser.cc",
|
"shell/browser/browser.cc",
|
||||||
"shell/browser/browser.h",
|
"shell/browser/browser.h",
|
||||||
"shell/browser/browser_linux.cc",
|
"shell/browser/browser_linux.cc",
|
||||||
"shell/browser/browser_mac.mm",
|
"shell/browser/browser_mac.mm",
|
||||||
"shell/browser/browser_win.cc",
|
|
||||||
"shell/browser/browser_observer.h",
|
"shell/browser/browser_observer.h",
|
||||||
"shell/browser/browser_process_impl.cc",
|
"shell/browser/browser_process_impl.cc",
|
||||||
"shell/browser/browser_process_impl.h",
|
"shell/browser/browser_process_impl.h",
|
||||||
|
"shell/browser/browser_win.cc",
|
||||||
"shell/browser/child_web_contents_tracker.cc",
|
"shell/browser/child_web_contents_tracker.cc",
|
||||||
"shell/browser/child_web_contents_tracker.h",
|
"shell/browser/child_web_contents_tracker.h",
|
||||||
"shell/browser/common_web_contents_delegate_mac.mm",
|
|
||||||
"shell/browser/common_web_contents_delegate_views.cc",
|
|
||||||
"shell/browser/common_web_contents_delegate.cc",
|
"shell/browser/common_web_contents_delegate.cc",
|
||||||
"shell/browser/common_web_contents_delegate.h",
|
"shell/browser/common_web_contents_delegate.h",
|
||||||
|
"shell/browser/common_web_contents_delegate_mac.mm",
|
||||||
|
"shell/browser/common_web_contents_delegate_views.cc",
|
||||||
"shell/browser/cookie_change_notifier.cc",
|
"shell/browser/cookie_change_notifier.cc",
|
||||||
"shell/browser/cookie_change_notifier.h",
|
"shell/browser/cookie_change_notifier.h",
|
||||||
|
"shell/browser/feature_list.cc",
|
||||||
|
"shell/browser/feature_list.h",
|
||||||
|
"shell/browser/font_defaults.cc",
|
||||||
|
"shell/browser/font_defaults.h",
|
||||||
"shell/browser/javascript_environment.cc",
|
"shell/browser/javascript_environment.cc",
|
||||||
"shell/browser/javascript_environment.h",
|
"shell/browser/javascript_environment.h",
|
||||||
"shell/browser/lib/bluetooth_chooser.cc",
|
"shell/browser/lib/bluetooth_chooser.cc",
|
||||||
"shell/browser/lib/bluetooth_chooser.h",
|
"shell/browser/lib/bluetooth_chooser.h",
|
||||||
"shell/browser/lib/power_observer.h",
|
"shell/browser/lib/power_observer.h",
|
||||||
"shell/browser/lib/power_observer_linux.h",
|
|
||||||
"shell/browser/lib/power_observer_linux.cc",
|
"shell/browser/lib/power_observer_linux.cc",
|
||||||
|
"shell/browser/lib/power_observer_linux.h",
|
||||||
|
"shell/browser/linux/unity_service.cc",
|
||||||
|
"shell/browser/linux/unity_service.h",
|
||||||
"shell/browser/login_handler.cc",
|
"shell/browser/login_handler.cc",
|
||||||
"shell/browser/login_handler.h",
|
"shell/browser/login_handler.h",
|
||||||
"shell/browser/mac/atom_application.h",
|
"shell/browser/mac/electron_application.h",
|
||||||
"shell/browser/mac/atom_application.mm",
|
"shell/browser/mac/electron_application.mm",
|
||||||
"shell/browser/mac/atom_application_delegate.h",
|
"shell/browser/mac/electron_application_delegate.h",
|
||||||
"shell/browser/mac/atom_application_delegate.mm",
|
"shell/browser/mac/electron_application_delegate.mm",
|
||||||
"shell/browser/mac/dict_util.h",
|
"shell/browser/mac/dict_util.h",
|
||||||
"shell/browser/mac/dict_util.mm",
|
"shell/browser/mac/dict_util.mm",
|
||||||
"shell/browser/mac/in_app_purchase.h",
|
"shell/browser/mac/in_app_purchase.h",
|
||||||
@@ -195,48 +202,55 @@ filenames = {
|
|||||||
"shell/browser/mac/in_app_purchase_observer.mm",
|
"shell/browser/mac/in_app_purchase_observer.mm",
|
||||||
"shell/browser/mac/in_app_purchase_product.h",
|
"shell/browser/mac/in_app_purchase_product.h",
|
||||||
"shell/browser/mac/in_app_purchase_product.mm",
|
"shell/browser/mac/in_app_purchase_product.mm",
|
||||||
"shell/browser/microtasks_runner.cc",
|
|
||||||
"shell/browser/microtasks_runner.h",
|
|
||||||
"shell/browser/native_browser_view.cc",
|
|
||||||
"shell/browser/native_browser_view.h",
|
|
||||||
"shell/browser/native_browser_view_mac.h",
|
|
||||||
"shell/browser/native_browser_view_mac.mm",
|
|
||||||
"shell/browser/native_browser_view_views.h",
|
|
||||||
"shell/browser/native_browser_view_views.cc",
|
|
||||||
"shell/browser/native_window.cc",
|
|
||||||
"shell/browser/native_window.h",
|
|
||||||
"shell/browser/native_window_views_win.cc",
|
|
||||||
"shell/browser/native_window_views.cc",
|
|
||||||
"shell/browser/native_window_views.h",
|
|
||||||
"shell/browser/native_window_mac.h",
|
|
||||||
"shell/browser/native_window_mac.mm",
|
|
||||||
"shell/browser/native_window_observer.h",
|
|
||||||
"shell/browser/media/media_capture_devices_dispatcher.cc",
|
"shell/browser/media/media_capture_devices_dispatcher.cc",
|
||||||
"shell/browser/media/media_capture_devices_dispatcher.h",
|
"shell/browser/media/media_capture_devices_dispatcher.h",
|
||||||
"shell/browser/media/media_device_id_salt.cc",
|
"shell/browser/media/media_device_id_salt.cc",
|
||||||
"shell/browser/media/media_device_id_salt.h",
|
"shell/browser/media/media_device_id_salt.h",
|
||||||
"shell/browser/media/media_stream_devices_controller.cc",
|
"shell/browser/media/media_stream_devices_controller.cc",
|
||||||
"shell/browser/media/media_stream_devices_controller.h",
|
"shell/browser/media/media_stream_devices_controller.h",
|
||||||
|
"shell/browser/microtasks_runner.cc",
|
||||||
|
"shell/browser/microtasks_runner.h",
|
||||||
|
"shell/browser/native_browser_view.cc",
|
||||||
|
"shell/browser/native_browser_view.h",
|
||||||
|
"shell/browser/native_browser_view_mac.h",
|
||||||
|
"shell/browser/native_browser_view_mac.mm",
|
||||||
|
"shell/browser/native_browser_view_views.cc",
|
||||||
|
"shell/browser/native_browser_view_views.h",
|
||||||
|
"shell/browser/native_window.cc",
|
||||||
|
"shell/browser/native_window.h",
|
||||||
|
"shell/browser/native_window_mac.h",
|
||||||
|
"shell/browser/native_window_mac.mm",
|
||||||
|
"shell/browser/native_window_observer.h",
|
||||||
|
"shell/browser/native_window_views.cc",
|
||||||
|
"shell/browser/native_window_views.h",
|
||||||
|
"shell/browser/native_window_views_win.cc",
|
||||||
"shell/browser/net/asar/asar_url_loader.cc",
|
"shell/browser/net/asar/asar_url_loader.cc",
|
||||||
"shell/browser/net/asar/asar_url_loader.h",
|
"shell/browser/net/asar/asar_url_loader.h",
|
||||||
"shell/browser/net/atom_url_loader_factory.cc",
|
"shell/browser/net/electron_url_loader_factory.cc",
|
||||||
"shell/browser/net/atom_url_loader_factory.h",
|
"shell/browser/net/electron_url_loader_factory.h",
|
||||||
"shell/browser/net/cert_verifier_client.cc",
|
"shell/browser/net/cert_verifier_client.cc",
|
||||||
"shell/browser/net/cert_verifier_client.h",
|
"shell/browser/net/cert_verifier_client.h",
|
||||||
"shell/browser/net/proxying_url_loader_factory.cc",
|
|
||||||
"shell/browser/net/proxying_url_loader_factory.h",
|
|
||||||
"shell/browser/net/network_context_service_factory.cc",
|
|
||||||
"shell/browser/net/network_context_service_factory.h",
|
|
||||||
"shell/browser/net/network_context_service.cc",
|
"shell/browser/net/network_context_service.cc",
|
||||||
"shell/browser/net/network_context_service.h",
|
"shell/browser/net/network_context_service.h",
|
||||||
|
"shell/browser/net/network_context_service_factory.cc",
|
||||||
|
"shell/browser/net/network_context_service_factory.h",
|
||||||
"shell/browser/net/node_stream_loader.cc",
|
"shell/browser/net/node_stream_loader.cc",
|
||||||
"shell/browser/net/node_stream_loader.h",
|
"shell/browser/net/node_stream_loader.h",
|
||||||
|
"shell/browser/net/proxying_url_loader_factory.cc",
|
||||||
|
"shell/browser/net/proxying_url_loader_factory.h",
|
||||||
|
"shell/browser/net/proxying_websocket.cc",
|
||||||
|
"shell/browser/net/proxying_websocket.h",
|
||||||
"shell/browser/net/resolve_proxy_helper.cc",
|
"shell/browser/net/resolve_proxy_helper.cc",
|
||||||
"shell/browser/net/resolve_proxy_helper.h",
|
"shell/browser/net/resolve_proxy_helper.h",
|
||||||
"shell/browser/net/system_network_context_manager.cc",
|
"shell/browser/net/system_network_context_manager.cc",
|
||||||
"shell/browser/net/system_network_context_manager.h",
|
"shell/browser/net/system_network_context_manager.h",
|
||||||
"shell/browser/net/url_pipe_loader.cc",
|
"shell/browser/net/url_pipe_loader.cc",
|
||||||
"shell/browser/net/url_pipe_loader.h",
|
"shell/browser/net/url_pipe_loader.h",
|
||||||
|
"shell/browser/net/web_request_api_interface.h",
|
||||||
|
"shell/browser/network_hints_handler_impl.cc",
|
||||||
|
"shell/browser/network_hints_handler_impl.h",
|
||||||
|
"shell/browser/node_debugger.cc",
|
||||||
|
"shell/browser/node_debugger.h",
|
||||||
"shell/browser/notifications/linux/libnotify_notification.cc",
|
"shell/browser/notifications/linux/libnotify_notification.cc",
|
||||||
"shell/browser/notifications/linux/libnotify_notification.h",
|
"shell/browser/notifications/linux/libnotify_notification.h",
|
||||||
"shell/browser/notifications/linux/notification_presenter_linux.cc",
|
"shell/browser/notifications/linux/notification_presenter_linux.cc",
|
||||||
@@ -269,67 +283,65 @@ filenames = {
|
|||||||
"shell/browser/notifications/win/win32_notification.h",
|
"shell/browser/notifications/win/win32_notification.h",
|
||||||
"shell/browser/notifications/win/windows_toast_notification.cc",
|
"shell/browser/notifications/win/windows_toast_notification.cc",
|
||||||
"shell/browser/notifications/win/windows_toast_notification.h",
|
"shell/browser/notifications/win/windows_toast_notification.h",
|
||||||
"shell/browser/node_debugger.cc",
|
|
||||||
"shell/browser/node_debugger.h",
|
|
||||||
"shell/browser/pref_store_delegate.cc",
|
"shell/browser/pref_store_delegate.cc",
|
||||||
"shell/browser/pref_store_delegate.h",
|
"shell/browser/pref_store_delegate.h",
|
||||||
|
"shell/browser/relauncher.cc",
|
||||||
|
"shell/browser/relauncher.h",
|
||||||
"shell/browser/relauncher_linux.cc",
|
"shell/browser/relauncher_linux.cc",
|
||||||
"shell/browser/relauncher_mac.cc",
|
"shell/browser/relauncher_mac.cc",
|
||||||
"shell/browser/relauncher_win.cc",
|
"shell/browser/relauncher_win.cc",
|
||||||
"shell/browser/relauncher.cc",
|
|
||||||
"shell/browser/relauncher.h",
|
|
||||||
"shell/browser/renderer_host/electron_render_message_filter.cc",
|
|
||||||
"shell/browser/renderer_host/electron_render_message_filter.h",
|
|
||||||
"shell/browser/session_preferences.cc",
|
"shell/browser/session_preferences.cc",
|
||||||
"shell/browser/session_preferences.h",
|
"shell/browser/session_preferences.h",
|
||||||
"shell/browser/special_storage_policy.cc",
|
"shell/browser/special_storage_policy.cc",
|
||||||
"shell/browser/special_storage_policy.h",
|
"shell/browser/special_storage_policy.h",
|
||||||
"shell/browser/ui/accelerator_util.cc",
|
"shell/browser/ui/accelerator_util.cc",
|
||||||
"shell/browser/ui/accelerator_util.h",
|
"shell/browser/ui/accelerator_util.h",
|
||||||
"shell/browser/ui/atom_menu_model.cc",
|
"shell/browser/ui/electron_menu_model.cc",
|
||||||
"shell/browser/ui/atom_menu_model.h",
|
"shell/browser/ui/electron_menu_model.h",
|
||||||
"shell/browser/ui/autofill_popup.cc",
|
"shell/browser/ui/autofill_popup.cc",
|
||||||
"shell/browser/ui/autofill_popup.h",
|
"shell/browser/ui/autofill_popup.h",
|
||||||
"shell/browser/ui/certificate_trust.h",
|
"shell/browser/ui/certificate_trust.h",
|
||||||
"shell/browser/ui/certificate_trust_mac.mm",
|
"shell/browser/ui/certificate_trust_mac.mm",
|
||||||
"shell/browser/ui/certificate_trust_win.cc",
|
"shell/browser/ui/certificate_trust_win.cc",
|
||||||
"shell/browser/ui/cocoa/atom_bundle_mover.h",
|
"shell/browser/ui/cocoa/NSColor+Hex.h",
|
||||||
"shell/browser/ui/cocoa/atom_bundle_mover.mm",
|
"shell/browser/ui/cocoa/NSColor+Hex.mm",
|
||||||
"shell/browser/ui/cocoa/atom_menu_controller.h",
|
"shell/browser/ui/cocoa/NSString+ANSI.h",
|
||||||
"shell/browser/ui/cocoa/atom_menu_controller.mm",
|
"shell/browser/ui/cocoa/NSString+ANSI.mm",
|
||||||
"shell/browser/ui/cocoa/atom_native_widget_mac.h",
|
"shell/browser/ui/cocoa/electron_bundle_mover.h",
|
||||||
"shell/browser/ui/cocoa/atom_native_widget_mac.mm",
|
"shell/browser/ui/cocoa/electron_bundle_mover.mm",
|
||||||
"shell/browser/ui/cocoa/atom_ns_window.h",
|
"shell/browser/ui/cocoa/electron_inspectable_web_contents_view.h",
|
||||||
"shell/browser/ui/cocoa/atom_ns_window.mm",
|
"shell/browser/ui/cocoa/electron_inspectable_web_contents_view.mm",
|
||||||
"shell/browser/ui/cocoa/atom_ns_window_delegate.h",
|
"shell/browser/ui/cocoa/electron_menu_controller.h",
|
||||||
"shell/browser/ui/cocoa/atom_ns_window_delegate.mm",
|
"shell/browser/ui/cocoa/electron_menu_controller.mm",
|
||||||
"shell/browser/ui/cocoa/atom_preview_item.h",
|
"shell/browser/ui/cocoa/electron_native_widget_mac.h",
|
||||||
"shell/browser/ui/cocoa/atom_preview_item.mm",
|
"shell/browser/ui/cocoa/electron_native_widget_mac.mm",
|
||||||
"shell/browser/ui/cocoa/atom_touch_bar.h",
|
"shell/browser/ui/cocoa/electron_ns_window.h",
|
||||||
"shell/browser/ui/cocoa/atom_touch_bar.mm",
|
"shell/browser/ui/cocoa/electron_ns_window.mm",
|
||||||
|
"shell/browser/ui/cocoa/electron_ns_window_delegate.h",
|
||||||
|
"shell/browser/ui/cocoa/electron_ns_window_delegate.mm",
|
||||||
|
"shell/browser/ui/cocoa/electron_preview_item.h",
|
||||||
|
"shell/browser/ui/cocoa/electron_preview_item.mm",
|
||||||
|
"shell/browser/ui/cocoa/electron_touch_bar.h",
|
||||||
|
"shell/browser/ui/cocoa/electron_touch_bar.mm",
|
||||||
"shell/browser/ui/cocoa/delayed_native_view_host.cc",
|
"shell/browser/ui/cocoa/delayed_native_view_host.cc",
|
||||||
"shell/browser/ui/cocoa/delayed_native_view_host.h",
|
"shell/browser/ui/cocoa/delayed_native_view_host.h",
|
||||||
"shell/browser/ui/cocoa/views_delegate_mac.h",
|
|
||||||
"shell/browser/ui/cocoa/views_delegate_mac.mm",
|
|
||||||
"shell/browser/ui/cocoa/root_view_mac.mm",
|
|
||||||
"shell/browser/ui/cocoa/root_view_mac.h",
|
|
||||||
"shell/browser/ui/cocoa/atom_inspectable_web_contents_view.h",
|
|
||||||
"shell/browser/ui/cocoa/atom_inspectable_web_contents_view.mm",
|
|
||||||
"shell/browser/ui/cocoa/event_dispatching_window.h",
|
"shell/browser/ui/cocoa/event_dispatching_window.h",
|
||||||
"shell/browser/ui/cocoa/event_dispatching_window.mm",
|
"shell/browser/ui/cocoa/event_dispatching_window.mm",
|
||||||
|
"shell/browser/ui/cocoa/root_view_mac.h",
|
||||||
|
"shell/browser/ui/cocoa/root_view_mac.mm",
|
||||||
|
"shell/browser/ui/cocoa/views_delegate_mac.h",
|
||||||
|
"shell/browser/ui/cocoa/views_delegate_mac.mm",
|
||||||
"shell/browser/ui/devtools_manager_delegate.cc",
|
"shell/browser/ui/devtools_manager_delegate.cc",
|
||||||
"shell/browser/ui/devtools_manager_delegate.h",
|
"shell/browser/ui/devtools_manager_delegate.h",
|
||||||
"shell/browser/ui/devtools_ui.cc",
|
"shell/browser/ui/devtools_ui.cc",
|
||||||
"shell/browser/ui/devtools_ui.h",
|
"shell/browser/ui/devtools_ui.h",
|
||||||
|
"shell/browser/ui/drag_util.h",
|
||||||
"shell/browser/ui/drag_util_mac.mm",
|
"shell/browser/ui/drag_util_mac.mm",
|
||||||
"shell/browser/ui/drag_util_views.cc",
|
"shell/browser/ui/drag_util_views.cc",
|
||||||
"shell/browser/ui/drag_util.h",
|
|
||||||
"shell/browser/ui/file_dialog.h",
|
"shell/browser/ui/file_dialog.h",
|
||||||
"shell/browser/ui/file_dialog_gtk.cc",
|
"shell/browser/ui/file_dialog_gtk.cc",
|
||||||
"shell/browser/ui/file_dialog_mac.mm",
|
"shell/browser/ui/file_dialog_mac.mm",
|
||||||
"shell/browser/ui/file_dialog_win.cc",
|
"shell/browser/ui/file_dialog_win.cc",
|
||||||
"shell/browser/ui/util_gtk.cc",
|
|
||||||
"shell/browser/ui/util_gtk.h",
|
|
||||||
"shell/browser/ui/inspectable_web_contents.cc",
|
"shell/browser/ui/inspectable_web_contents.cc",
|
||||||
"shell/browser/ui/inspectable_web_contents.h",
|
"shell/browser/ui/inspectable_web_contents.h",
|
||||||
"shell/browser/ui/inspectable_web_contents_delegate.h",
|
"shell/browser/ui/inspectable_web_contents_delegate.h",
|
||||||
@@ -344,20 +356,17 @@ filenames = {
|
|||||||
"shell/browser/ui/message_box_gtk.cc",
|
"shell/browser/ui/message_box_gtk.cc",
|
||||||
"shell/browser/ui/message_box_mac.mm",
|
"shell/browser/ui/message_box_mac.mm",
|
||||||
"shell/browser/ui/message_box_win.cc",
|
"shell/browser/ui/message_box_win.cc",
|
||||||
"shell/browser/ui/cocoa/NSColor+Hex.mm",
|
|
||||||
"shell/browser/ui/cocoa/NSColor+Hex.h",
|
|
||||||
"shell/browser/ui/cocoa/NSString+ANSI.mm",
|
|
||||||
"shell/browser/ui/cocoa/NSString+ANSI.h",
|
|
||||||
"shell/browser/ui/tray_icon.cc",
|
"shell/browser/ui/tray_icon.cc",
|
||||||
"shell/browser/ui/tray_icon.h",
|
"shell/browser/ui/tray_icon.h",
|
||||||
"shell/browser/ui/tray_icon_gtk.cc",
|
|
||||||
"shell/browser/ui/tray_icon_gtk.h",
|
|
||||||
"shell/browser/ui/tray_icon_cocoa.h",
|
"shell/browser/ui/tray_icon_cocoa.h",
|
||||||
"shell/browser/ui/tray_icon_cocoa.mm",
|
"shell/browser/ui/tray_icon_cocoa.mm",
|
||||||
|
"shell/browser/ui/tray_icon_gtk.cc",
|
||||||
|
"shell/browser/ui/tray_icon_gtk.h",
|
||||||
"shell/browser/ui/tray_icon_observer.h",
|
"shell/browser/ui/tray_icon_observer.h",
|
||||||
"shell/browser/ui/tray_icon_win.cc",
|
"shell/browser/ui/tray_icon_win.cc",
|
||||||
"shell/browser/ui/views/atom_views_delegate.cc",
|
"shell/browser/ui/views/electron_views_delegate.cc",
|
||||||
"shell/browser/ui/views/atom_views_delegate.h",
|
"shell/browser/ui/views/electron_views_delegate_win.cc",
|
||||||
|
"shell/browser/ui/views/electron_views_delegate.h",
|
||||||
"shell/browser/ui/views/autofill_popup_view.cc",
|
"shell/browser/ui/views/autofill_popup_view.cc",
|
||||||
"shell/browser/ui/views/autofill_popup_view.h",
|
"shell/browser/ui/views/autofill_popup_view.h",
|
||||||
"shell/browser/ui/views/frameless_view.cc",
|
"shell/browser/ui/views/frameless_view.cc",
|
||||||
@@ -380,16 +389,16 @@ filenames = {
|
|||||||
"shell/browser/ui/views/submenu_button.h",
|
"shell/browser/ui/views/submenu_button.h",
|
||||||
"shell/browser/ui/views/win_frame_view.cc",
|
"shell/browser/ui/views/win_frame_view.cc",
|
||||||
"shell/browser/ui/views/win_frame_view.h",
|
"shell/browser/ui/views/win_frame_view.h",
|
||||||
"shell/browser/ui/win/atom_desktop_native_widget_aura.cc",
|
"shell/browser/ui/win/electron_desktop_native_widget_aura.cc",
|
||||||
"shell/browser/ui/win/atom_desktop_native_widget_aura.h",
|
"shell/browser/ui/win/electron_desktop_native_widget_aura.h",
|
||||||
"shell/browser/ui/win/atom_desktop_window_tree_host_win.cc",
|
"shell/browser/ui/win/electron_desktop_window_tree_host_win.cc",
|
||||||
"shell/browser/ui/win/atom_desktop_window_tree_host_win.h",
|
"shell/browser/ui/win/electron_desktop_window_tree_host_win.h",
|
||||||
"shell/browser/ui/win/jump_list.cc",
|
"shell/browser/ui/win/jump_list.cc",
|
||||||
"shell/browser/ui/win/jump_list.h",
|
"shell/browser/ui/win/jump_list.h",
|
||||||
"shell/browser/ui/win/notify_icon_host.cc",
|
|
||||||
"shell/browser/ui/win/notify_icon_host.h",
|
|
||||||
"shell/browser/ui/win/notify_icon.cc",
|
"shell/browser/ui/win/notify_icon.cc",
|
||||||
"shell/browser/ui/win/notify_icon.h",
|
"shell/browser/ui/win/notify_icon.h",
|
||||||
|
"shell/browser/ui/win/notify_icon_host.cc",
|
||||||
|
"shell/browser/ui/win/notify_icon_host.h",
|
||||||
"shell/browser/ui/win/taskbar_host.cc",
|
"shell/browser/ui/win/taskbar_host.cc",
|
||||||
"shell/browser/ui/win/taskbar_host.h",
|
"shell/browser/ui/win/taskbar_host.h",
|
||||||
"shell/browser/ui/x/event_disabler.cc",
|
"shell/browser/ui/x/event_disabler.cc",
|
||||||
@@ -400,8 +409,6 @@ filenames = {
|
|||||||
"shell/browser/ui/x/x_window_utils.h",
|
"shell/browser/ui/x/x_window_utils.h",
|
||||||
"shell/browser/unresponsive_suppressor.cc",
|
"shell/browser/unresponsive_suppressor.cc",
|
||||||
"shell/browser/unresponsive_suppressor.h",
|
"shell/browser/unresponsive_suppressor.h",
|
||||||
"shell/browser/win/scoped_hstring.cc",
|
|
||||||
"shell/browser/win/scoped_hstring.h",
|
|
||||||
"shell/browser/web_contents_permission_helper.cc",
|
"shell/browser/web_contents_permission_helper.cc",
|
||||||
"shell/browser/web_contents_permission_helper.h",
|
"shell/browser/web_contents_permission_helper.h",
|
||||||
"shell/browser/web_contents_preferences.cc",
|
"shell/browser/web_contents_preferences.cc",
|
||||||
@@ -414,46 +421,48 @@ filenames = {
|
|||||||
"shell/browser/web_view_guest_delegate.h",
|
"shell/browser/web_view_guest_delegate.h",
|
||||||
"shell/browser/web_view_manager.cc",
|
"shell/browser/web_view_manager.cc",
|
||||||
"shell/browser/web_view_manager.h",
|
"shell/browser/web_view_manager.h",
|
||||||
|
"shell/browser/win/scoped_hstring.cc",
|
||||||
|
"shell/browser/win/scoped_hstring.h",
|
||||||
"shell/browser/window_list.cc",
|
"shell/browser/window_list.cc",
|
||||||
"shell/browser/window_list.h",
|
"shell/browser/window_list.h",
|
||||||
"shell/browser/window_list_observer.h",
|
"shell/browser/window_list_observer.h",
|
||||||
"shell/browser/zoom_level_delegate.cc",
|
"shell/browser/zoom_level_delegate.cc",
|
||||||
"shell/browser/zoom_level_delegate.h",
|
"shell/browser/zoom_level_delegate.h",
|
||||||
"shell/common/api/atom_api_asar.cc",
|
"shell/common/api/electron_api_asar.cc",
|
||||||
"shell/common/api/atom_api_clipboard.cc",
|
"shell/common/api/electron_api_clipboard.cc",
|
||||||
"shell/common/api/atom_api_clipboard.h",
|
"shell/common/api/electron_api_clipboard.h",
|
||||||
"shell/common/api/atom_api_clipboard_mac.mm",
|
"shell/common/api/electron_api_clipboard_mac.mm",
|
||||||
"shell/common/api/atom_api_command_line.cc",
|
"shell/common/api/electron_api_command_line.cc",
|
||||||
"shell/common/api/atom_api_crash_reporter.cc",
|
"shell/common/api/electron_api_crash_reporter.cc",
|
||||||
"shell/common/api/atom_api_key_weak_map.h",
|
"shell/common/api/electron_api_key_weak_map.h",
|
||||||
"shell/common/api/atom_api_native_image.cc",
|
"shell/common/api/electron_api_native_image.cc",
|
||||||
"shell/common/api/atom_api_native_image.h",
|
"shell/common/api/electron_api_native_image.h",
|
||||||
"shell/common/api/atom_api_native_image_mac.mm",
|
"shell/common/api/electron_api_native_image_mac.mm",
|
||||||
"shell/common/api/atom_api_shell.cc",
|
"shell/common/api/electron_api_shell.cc",
|
||||||
"shell/common/api/atom_api_v8_util.cc",
|
"shell/common/api/electron_api_v8_util.cc",
|
||||||
|
"shell/common/api/constructor.h",
|
||||||
"shell/common/api/electron_bindings.cc",
|
"shell/common/api/electron_bindings.cc",
|
||||||
"shell/common/api/electron_bindings.h",
|
"shell/common/api/electron_bindings.h",
|
||||||
"shell/common/api/constructor.h",
|
|
||||||
"shell/common/api/event_emitter_caller_deprecated.cc",
|
"shell/common/api/event_emitter_caller_deprecated.cc",
|
||||||
"shell/common/api/event_emitter_caller_deprecated.h",
|
"shell/common/api/event_emitter_caller_deprecated.h",
|
||||||
"shell/common/api/features.cc",
|
"shell/common/api/features.cc",
|
||||||
"shell/common/api/locker.cc",
|
"shell/common/api/locker.cc",
|
||||||
"shell/common/api/locker.h",
|
"shell/common/api/locker.h",
|
||||||
|
"shell/common/application_info.cc",
|
||||||
|
"shell/common/application_info.h",
|
||||||
|
"shell/common/application_info_linux.cc",
|
||||||
|
"shell/common/application_info_mac.mm",
|
||||||
|
"shell/common/application_info_win.cc",
|
||||||
"shell/common/asar/archive.cc",
|
"shell/common/asar/archive.cc",
|
||||||
"shell/common/asar/archive.h",
|
"shell/common/asar/archive.h",
|
||||||
"shell/common/asar/asar_util.cc",
|
"shell/common/asar/asar_util.cc",
|
||||||
"shell/common/asar/asar_util.h",
|
"shell/common/asar/asar_util.h",
|
||||||
"shell/common/asar/scoped_temporary_file.cc",
|
"shell/common/asar/scoped_temporary_file.cc",
|
||||||
"shell/common/asar/scoped_temporary_file.h",
|
"shell/common/asar/scoped_temporary_file.h",
|
||||||
"shell/common/application_info_linux.cc",
|
"shell/common/electron_command_line.cc",
|
||||||
"shell/common/application_info_mac.mm",
|
"shell/common/electron_command_line.h",
|
||||||
"shell/common/application_info_win.cc",
|
"shell/common/electron_constants.cc",
|
||||||
"shell/common/application_info.cc",
|
"shell/common/electron_constants.h",
|
||||||
"shell/common/application_info.h",
|
|
||||||
"shell/common/atom_command_line.cc",
|
|
||||||
"shell/common/atom_command_line.h",
|
|
||||||
"shell/common/atom_constants.cc",
|
|
||||||
"shell/common/atom_constants.h",
|
|
||||||
"shell/common/color_util.cc",
|
"shell/common/color_util.cc",
|
||||||
"shell/common/color_util.h",
|
"shell/common/color_util.h",
|
||||||
"shell/common/crash_reporter/crash_reporter.cc",
|
"shell/common/crash_reporter/crash_reporter.cc",
|
||||||
@@ -462,12 +471,15 @@ filenames = {
|
|||||||
"shell/common/crash_reporter/crash_reporter_linux.h",
|
"shell/common/crash_reporter/crash_reporter_linux.h",
|
||||||
"shell/common/crash_reporter/crash_reporter_mac.h",
|
"shell/common/crash_reporter/crash_reporter_mac.h",
|
||||||
"shell/common/crash_reporter/crash_reporter_mac.mm",
|
"shell/common/crash_reporter/crash_reporter_mac.mm",
|
||||||
"shell/common/crash_reporter/crash_reporter_win.h",
|
|
||||||
"shell/common/crash_reporter/crash_reporter_win.cc",
|
"shell/common/crash_reporter/crash_reporter_win.cc",
|
||||||
|
"shell/common/crash_reporter/crash_reporter_win.h",
|
||||||
"shell/common/crash_reporter/linux/crash_dump_handler.cc",
|
"shell/common/crash_reporter/linux/crash_dump_handler.cc",
|
||||||
"shell/common/crash_reporter/linux/crash_dump_handler.h",
|
"shell/common/crash_reporter/linux/crash_dump_handler.h",
|
||||||
"shell/common/crash_reporter/win/crash_service_main.cc",
|
"shell/common/crash_reporter/win/crash_service_main.cc",
|
||||||
"shell/common/crash_reporter/win/crash_service_main.h",
|
"shell/common/crash_reporter/win/crash_service_main.h",
|
||||||
|
"shell/common/deprecate_util.cc",
|
||||||
|
"shell/common/deprecate_util.h",
|
||||||
|
"shell/common/gin_converters/blink_converter_gin_adapter.h",
|
||||||
"shell/common/gin_converters/callback_converter.h",
|
"shell/common/gin_converters/callback_converter.h",
|
||||||
"shell/common/gin_converters/file_dialog_converter.cc",
|
"shell/common/gin_converters/file_dialog_converter.cc",
|
||||||
"shell/common/gin_converters/file_dialog_converter.h",
|
"shell/common/gin_converters/file_dialog_converter.h",
|
||||||
@@ -483,7 +495,6 @@ filenames = {
|
|||||||
"shell/common/gin_converters/net_converter.cc",
|
"shell/common/gin_converters/net_converter.cc",
|
||||||
"shell/common/gin_converters/net_converter.h",
|
"shell/common/gin_converters/net_converter.h",
|
||||||
"shell/common/gin_converters/std_converter.h",
|
"shell/common/gin_converters/std_converter.h",
|
||||||
"shell/common/gin_converters/blink_converter_gin_adapter.h",
|
|
||||||
"shell/common/gin_converters/value_converter_gin_adapter.h",
|
"shell/common/gin_converters/value_converter_gin_adapter.h",
|
||||||
"shell/common/gin_helper/arguments.cc",
|
"shell/common/gin_helper/arguments.cc",
|
||||||
"shell/common/gin_helper/arguments.h",
|
"shell/common/gin_helper/arguments.h",
|
||||||
@@ -494,10 +505,10 @@ filenames = {
|
|||||||
"shell/common/gin_helper/dictionary.h",
|
"shell/common/gin_helper/dictionary.h",
|
||||||
"shell/common/gin_helper/error_thrower.cc",
|
"shell/common/gin_helper/error_thrower.cc",
|
||||||
"shell/common/gin_helper/error_thrower.h",
|
"shell/common/gin_helper/error_thrower.h",
|
||||||
"shell/common/gin_helper/event_emitter_caller.cc",
|
|
||||||
"shell/common/gin_helper/event_emitter_caller.h",
|
|
||||||
"shell/common/gin_helper/event_emitter.cc",
|
"shell/common/gin_helper/event_emitter.cc",
|
||||||
"shell/common/gin_helper/event_emitter.h",
|
"shell/common/gin_helper/event_emitter.h",
|
||||||
|
"shell/common/gin_helper/event_emitter_caller.cc",
|
||||||
|
"shell/common/gin_helper/event_emitter_caller.h",
|
||||||
"shell/common/gin_helper/function_template.cc",
|
"shell/common/gin_helper/function_template.cc",
|
||||||
"shell/common/gin_helper/function_template.h",
|
"shell/common/gin_helper/function_template.h",
|
||||||
"shell/common/gin_helper/object_template_builder.cc",
|
"shell/common/gin_helper/object_template_builder.cc",
|
||||||
@@ -507,12 +518,10 @@ filenames = {
|
|||||||
"shell/common/key_weak_map.h",
|
"shell/common/key_weak_map.h",
|
||||||
"shell/common/keyboard_util.cc",
|
"shell/common/keyboard_util.cc",
|
||||||
"shell/common/keyboard_util.h",
|
"shell/common/keyboard_util.h",
|
||||||
"shell/common/deprecate_util.cc",
|
|
||||||
"shell/common/deprecate_util.h",
|
|
||||||
"shell/common/mouse_util.cc",
|
|
||||||
"shell/common/mouse_util.h",
|
|
||||||
"shell/common/mac/main_application_bundle.h",
|
"shell/common/mac/main_application_bundle.h",
|
||||||
"shell/common/mac/main_application_bundle.mm",
|
"shell/common/mac/main_application_bundle.mm",
|
||||||
|
"shell/common/mouse_util.cc",
|
||||||
|
"shell/common/mouse_util.h",
|
||||||
"shell/common/native_mate_converters/accelerator_converter.cc",
|
"shell/common/native_mate_converters/accelerator_converter.cc",
|
||||||
"shell/common/native_mate_converters/accelerator_converter.h",
|
"shell/common/native_mate_converters/accelerator_converter.h",
|
||||||
"shell/common/native_mate_converters/blink_converter.cc",
|
"shell/common/native_mate_converters/blink_converter.cc",
|
||||||
@@ -545,51 +554,50 @@ filenames = {
|
|||||||
"shell/common/node_bindings_win.cc",
|
"shell/common/node_bindings_win.cc",
|
||||||
"shell/common/node_bindings_win.h",
|
"shell/common/node_bindings_win.h",
|
||||||
"shell/common/node_includes.h",
|
"shell/common/node_includes.h",
|
||||||
"shell/common/node_util.h",
|
|
||||||
"shell/common/node_util.cc",
|
"shell/common/node_util.cc",
|
||||||
|
"shell/common/node_util.h",
|
||||||
"shell/common/options_switches.cc",
|
"shell/common/options_switches.cc",
|
||||||
"shell/common/options_switches.h",
|
"shell/common/options_switches.h",
|
||||||
"shell/common/platform_util.h",
|
"shell/common/platform_util.h",
|
||||||
"shell/common/platform_util_linux.cc",
|
"shell/common/platform_util_linux.cc",
|
||||||
"shell/common/platform_util_mac.mm",
|
"shell/common/platform_util_mac.mm",
|
||||||
"shell/common/platform_util_win.cc",
|
"shell/common/platform_util_win.cc",
|
||||||
"shell/common/promise_util.h",
|
|
||||||
"shell/common/promise_util.cc",
|
"shell/common/promise_util.cc",
|
||||||
"shell/common/skia_util.h",
|
"shell/common/promise_util.h",
|
||||||
"shell/common/skia_util.cc",
|
"shell/common/skia_util.cc",
|
||||||
"shell/renderer/api/context_bridge/render_frame_context_bridge_store.cc",
|
"shell/common/skia_util.h",
|
||||||
"shell/renderer/api/context_bridge/render_frame_context_bridge_store.h",
|
"shell/renderer/api/context_bridge/object_cache.cc",
|
||||||
"shell/renderer/api/atom_api_context_bridge.cc",
|
"shell/renderer/api/context_bridge/object_cache.h",
|
||||||
"shell/renderer/api/atom_api_context_bridge.h",
|
"shell/renderer/api/context_bridge/render_frame_function_store.cc",
|
||||||
"shell/renderer/api/atom_api_renderer_ipc.cc",
|
"shell/renderer/api/context_bridge/render_frame_function_store.h",
|
||||||
"shell/renderer/api/atom_api_spell_check_client.cc",
|
"shell/renderer/api/electron_api_context_bridge.cc",
|
||||||
"shell/renderer/api/atom_api_spell_check_client.h",
|
"shell/renderer/api/electron_api_context_bridge.h",
|
||||||
"shell/renderer/api/atom_api_web_frame.cc",
|
"shell/renderer/api/electron_api_renderer_ipc.cc",
|
||||||
"shell/renderer/atom_autofill_agent.cc",
|
"shell/renderer/api/electron_api_spell_check_client.cc",
|
||||||
"shell/renderer/atom_autofill_agent.h",
|
"shell/renderer/api/electron_api_spell_check_client.h",
|
||||||
"shell/renderer/atom_render_frame_observer.cc",
|
"shell/renderer/api/electron_api_web_frame.cc",
|
||||||
"shell/renderer/atom_render_frame_observer.h",
|
"shell/renderer/electron_autofill_agent.cc",
|
||||||
"shell/renderer/atom_renderer_client.cc",
|
"shell/renderer/electron_autofill_agent.h",
|
||||||
"shell/renderer/atom_renderer_client.h",
|
"shell/renderer/electron_render_frame_observer.cc",
|
||||||
|
"shell/renderer/electron_render_frame_observer.h",
|
||||||
|
"shell/renderer/electron_renderer_client.cc",
|
||||||
|
"shell/renderer/electron_renderer_client.h",
|
||||||
|
"shell/renderer/electron_sandboxed_renderer_client.cc",
|
||||||
|
"shell/renderer/electron_sandboxed_renderer_client.h",
|
||||||
|
"shell/renderer/browser_exposed_renderer_interfaces.cc",
|
||||||
|
"shell/renderer/browser_exposed_renderer_interfaces.h",
|
||||||
"shell/renderer/content_settings_observer.cc",
|
"shell/renderer/content_settings_observer.cc",
|
||||||
"shell/renderer/content_settings_observer.h",
|
"shell/renderer/content_settings_observer.h",
|
||||||
"shell/renderer/electron_api_service_impl.cc",
|
"shell/renderer/electron_api_service_impl.cc",
|
||||||
"shell/renderer/electron_api_service_impl.h",
|
"shell/renderer/electron_api_service_impl.h",
|
||||||
"shell/renderer/atom_sandboxed_renderer_client.cc",
|
|
||||||
"shell/renderer/atom_sandboxed_renderer_client.h",
|
|
||||||
"shell/renderer/guest_view_container.cc",
|
"shell/renderer/guest_view_container.cc",
|
||||||
"shell/renderer/guest_view_container.h",
|
"shell/renderer/guest_view_container.h",
|
||||||
"shell/renderer/renderer_client_base.cc",
|
"shell/renderer/renderer_client_base.cc",
|
||||||
"shell/renderer/renderer_client_base.h",
|
"shell/renderer/renderer_client_base.h",
|
||||||
"shell/renderer/web_worker_observer.cc",
|
"shell/renderer/web_worker_observer.cc",
|
||||||
"shell/renderer/web_worker_observer.h",
|
"shell/renderer/web_worker_observer.h",
|
||||||
"shell/utility/atom_content_utility_client.cc",
|
"shell/utility/electron_content_utility_client.cc",
|
||||||
"shell/utility/atom_content_utility_client.h",
|
"shell/utility/electron_content_utility_client.h",
|
||||||
"chromium_src/chrome/browser/process_singleton_posix.cc",
|
|
||||||
"chromium_src/chrome/browser/process_singleton_win.cc",
|
|
||||||
"chromium_src/chrome/browser/process_singleton.h",
|
|
||||||
"chromium_src/chrome/browser/ui/views/frame/global_menu_bar_registrar_x11.cc",
|
|
||||||
"chromium_src/chrome/browser/ui/views/frame/global_menu_bar_registrar_x11.h",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
lib_sources_nss = [
|
lib_sources_nss = [
|
||||||
@@ -598,43 +606,43 @@ filenames = {
|
|||||||
]
|
]
|
||||||
|
|
||||||
lib_sources_extensions = [
|
lib_sources_extensions = [
|
||||||
"shell/browser/extensions/api/runtime/atom_runtime_api_delegate.cc",
|
"shell/browser/extensions/api/runtime/electron_runtime_api_delegate.cc",
|
||||||
"shell/browser/extensions/api/runtime/atom_runtime_api_delegate.h",
|
"shell/browser/extensions/api/runtime/electron_runtime_api_delegate.h",
|
||||||
"shell/browser/extensions/atom_extensions_browser_client.cc",
|
"shell/browser/extensions/electron_extensions_browser_client.cc",
|
||||||
"shell/browser/extensions/atom_extensions_browser_client.h",
|
"shell/browser/extensions/electron_extensions_browser_client.h",
|
||||||
"shell/browser/extensions/atom_browser_context_keyed_service_factories.cc",
|
"shell/browser/extensions/electron_browser_context_keyed_service_factories.cc",
|
||||||
"shell/browser/extensions/atom_browser_context_keyed_service_factories.h",
|
"shell/browser/extensions/electron_browser_context_keyed_service_factories.h",
|
||||||
"shell/browser/extensions/atom_display_info_provider.cc",
|
"shell/browser/extensions/electron_display_info_provider.cc",
|
||||||
"shell/browser/extensions/atom_display_info_provider.h",
|
"shell/browser/extensions/electron_display_info_provider.h",
|
||||||
"shell/browser/extensions/atom_extension_host_delegate.cc",
|
"shell/browser/extensions/electron_extension_host_delegate.cc",
|
||||||
"shell/browser/extensions/atom_extension_host_delegate.h",
|
"shell/browser/extensions/electron_extension_host_delegate.h",
|
||||||
"shell/browser/extensions/atom_extension_loader.cc",
|
"shell/browser/extensions/electron_extension_loader.cc",
|
||||||
"shell/browser/extensions/atom_extension_loader.h",
|
"shell/browser/extensions/electron_extension_loader.h",
|
||||||
"shell/browser/extensions/atom_extension_system.cc",
|
"shell/browser/extensions/electron_extension_system.cc",
|
||||||
"shell/browser/extensions/atom_extension_system.h",
|
"shell/browser/extensions/electron_extension_system.h",
|
||||||
"shell/browser/extensions/atom_extension_system_factory.cc",
|
"shell/browser/extensions/electron_extension_system_factory.cc",
|
||||||
"shell/browser/extensions/atom_extension_system_factory.h",
|
"shell/browser/extensions/electron_extension_system_factory.h",
|
||||||
"shell/browser/extensions/atom_extension_web_contents_observer.cc",
|
"shell/browser/extensions/electron_extension_web_contents_observer.cc",
|
||||||
"shell/browser/extensions/atom_extension_web_contents_observer.h",
|
"shell/browser/extensions/electron_extension_web_contents_observer.h",
|
||||||
"shell/browser/extensions/atom_navigation_ui_data.cc",
|
"shell/browser/extensions/electron_navigation_ui_data.cc",
|
||||||
"shell/browser/extensions/atom_navigation_ui_data.h",
|
"shell/browser/extensions/electron_navigation_ui_data.h",
|
||||||
"shell/common/extensions/atom_extensions_api_provider.cc",
|
"shell/common/extensions/electron_extensions_api_provider.cc",
|
||||||
"shell/common/extensions/atom_extensions_api_provider.h",
|
"shell/common/extensions/electron_extensions_api_provider.h",
|
||||||
"shell/common/extensions/atom_extensions_client.cc",
|
"shell/common/extensions/electron_extensions_client.cc",
|
||||||
"shell/common/extensions/atom_extensions_client.h",
|
"shell/common/extensions/electron_extensions_client.h",
|
||||||
"shell/renderer/extensions/atom_extensions_renderer_client.cc",
|
"shell/renderer/extensions/electron_extensions_renderer_client.cc",
|
||||||
"shell/renderer/extensions/atom_extensions_renderer_client.h",
|
"shell/renderer/extensions/electron_extensions_renderer_client.h",
|
||||||
]
|
]
|
||||||
|
|
||||||
app_sources = [
|
app_sources = [
|
||||||
"shell/app/atom_main.cc",
|
"shell/app/electron_main.cc",
|
||||||
"shell/app/atom_main.h",
|
"shell/app/electron_main.h",
|
||||||
]
|
]
|
||||||
|
|
||||||
framework_sources = [
|
framework_sources = [
|
||||||
"shell/app/atom_library_main.h",
|
"shell/app/electron_library_main.h",
|
||||||
"shell/app/atom_library_main.mm",
|
"shell/app/electron_library_main.mm",
|
||||||
]
|
]
|
||||||
|
|
||||||
login_helper_sources = [ "shell/app/atom_login_helper.mm" ]
|
login_helper_sources = [ "shell/app/electron_login_helper.mm" ]
|
||||||
}
|
}
|
||||||
|
|||||||
60
filenames.hunspell.gni
Normal file
60
filenames.hunspell.gni
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
hunspell_dictionaries = [
|
||||||
|
"//third_party/hunspell_dictionaries/af-ZA-3-0.bdic",
|
||||||
|
"//third_party/hunspell_dictionaries/bg-BG-3-0.bdic",
|
||||||
|
"//third_party/hunspell_dictionaries/ca-ES-3-0.bdic",
|
||||||
|
"//third_party/hunspell_dictionaries/cs-CZ-3-0.bdic",
|
||||||
|
"//third_party/hunspell_dictionaries/cy-GB-1-0.bdic",
|
||||||
|
"//third_party/hunspell_dictionaries/da-DK-3-0.bdic",
|
||||||
|
"//third_party/hunspell_dictionaries/de-DE-3-0.bdic",
|
||||||
|
"//third_party/hunspell_dictionaries/el-GR-3-0.bdic",
|
||||||
|
"//third_party/hunspell_dictionaries/en-AU-8-0.bdic",
|
||||||
|
"//third_party/hunspell_dictionaries/en-CA-8-0.bdic",
|
||||||
|
"//third_party/hunspell_dictionaries/en-GB-8-0.bdic",
|
||||||
|
"//third_party/hunspell_dictionaries/en-US-8-0.bdic",
|
||||||
|
"//third_party/hunspell_dictionaries/es-ES-3-0.bdic",
|
||||||
|
"//third_party/hunspell_dictionaries/et-EE-3-0.bdic",
|
||||||
|
"//third_party/hunspell_dictionaries/fa-IR-8-0.bdic",
|
||||||
|
"//third_party/hunspell_dictionaries/fo-FO-3-0.bdic",
|
||||||
|
"//third_party/hunspell_dictionaries/fr-FR-3-0.bdic",
|
||||||
|
"//third_party/hunspell_dictionaries/he-IL-3-0.bdic",
|
||||||
|
"//third_party/hunspell_dictionaries/hi-IN-3-0.bdic",
|
||||||
|
"//third_party/hunspell_dictionaries/hr-HR-3-0.bdic",
|
||||||
|
"//third_party/hunspell_dictionaries/hu-HU-3-0.bdic",
|
||||||
|
"//third_party/hunspell_dictionaries/hy-1-0.bdic",
|
||||||
|
"//third_party/hunspell_dictionaries/id-ID-3-0.bdic",
|
||||||
|
"//third_party/hunspell_dictionaries/it-IT-3-0.bdic",
|
||||||
|
"//third_party/hunspell_dictionaries/ko-3-0.bdic",
|
||||||
|
"//third_party/hunspell_dictionaries/lt-LT-3-0.bdic",
|
||||||
|
"//third_party/hunspell_dictionaries/lv-LV-3-0.bdic",
|
||||||
|
"//third_party/hunspell_dictionaries/nb-NO-3-0.bdic",
|
||||||
|
"//third_party/hunspell_dictionaries/nl-NL-3-0.bdic",
|
||||||
|
"//third_party/hunspell_dictionaries/pl-PL-3-0.bdic",
|
||||||
|
"//third_party/hunspell_dictionaries/pt-BR-3-0.bdic",
|
||||||
|
"//third_party/hunspell_dictionaries/pt-PT-3-0.bdic",
|
||||||
|
"//third_party/hunspell_dictionaries/ro-RO-3-0.bdic",
|
||||||
|
"//third_party/hunspell_dictionaries/ru-RU-3-0.bdic",
|
||||||
|
"//third_party/hunspell_dictionaries/sh-3-0.bdic",
|
||||||
|
"//third_party/hunspell_dictionaries/sh-4-0.bdic",
|
||||||
|
"//third_party/hunspell_dictionaries/sk-SK-3-0.bdic",
|
||||||
|
"//third_party/hunspell_dictionaries/sl-SI-3-0.bdic",
|
||||||
|
"//third_party/hunspell_dictionaries/sq-3-0.bdic",
|
||||||
|
"//third_party/hunspell_dictionaries/sr-3-0.bdic",
|
||||||
|
"//third_party/hunspell_dictionaries/sr-4-0.bdic",
|
||||||
|
"//third_party/hunspell_dictionaries/sv-SE-3-0.bdic",
|
||||||
|
"//third_party/hunspell_dictionaries/ta-IN-3-0.bdic",
|
||||||
|
"//third_party/hunspell_dictionaries/tg-TG-5-0.bdic",
|
||||||
|
"//third_party/hunspell_dictionaries/tr-TR-4-0.bdic",
|
||||||
|
"//third_party/hunspell_dictionaries/uk-UA-3-0.bdic",
|
||||||
|
"//third_party/hunspell_dictionaries/vi-VN-3-0.bdic",
|
||||||
|
"//third_party/hunspell_dictionaries/xx-XX-3-0.bdic",
|
||||||
|
]
|
||||||
|
|
||||||
|
hunspell_licenses = [
|
||||||
|
"//third_party/hunspell_dictionaries/COPYING",
|
||||||
|
"//third_party/hunspell_dictionaries/COPYING.Apache",
|
||||||
|
"//third_party/hunspell_dictionaries/COPYING.LESSER",
|
||||||
|
"//third_party/hunspell_dictionaries/COPYING.LGPL",
|
||||||
|
"//third_party/hunspell_dictionaries/COPYING.MIT",
|
||||||
|
"//third_party/hunspell_dictionaries/COPYING.MPL",
|
||||||
|
"//third_party/hunspell_dictionaries/LICENSE",
|
||||||
|
]
|
||||||
@@ -1,21 +1,21 @@
|
|||||||
import * as fs from 'fs'
|
import * as fs from 'fs';
|
||||||
import * as path from 'path'
|
import * as path from 'path';
|
||||||
|
|
||||||
import { deprecate, Menu } from 'electron'
|
import { deprecate, Menu } from 'electron';
|
||||||
import { EventEmitter } from 'events'
|
import { EventEmitter } from 'events';
|
||||||
|
|
||||||
const bindings = process.electronBinding('app')
|
const bindings = process.electronBinding('app');
|
||||||
const commandLine = process.electronBinding('command_line')
|
const commandLine = process.electronBinding('command_line');
|
||||||
const { app, App } = bindings
|
const { app, App } = bindings;
|
||||||
|
|
||||||
// Only one app object permitted.
|
// Only one app object permitted.
|
||||||
export default app
|
export default app;
|
||||||
|
|
||||||
let dockMenu: Electron.Menu | null = null
|
let dockMenu: Electron.Menu | null = null;
|
||||||
|
|
||||||
// App is an EventEmitter.
|
// App is an EventEmitter.
|
||||||
Object.setPrototypeOf(App.prototype, EventEmitter.prototype)
|
Object.setPrototypeOf(App.prototype, EventEmitter.prototype);
|
||||||
EventEmitter.call(app as any)
|
EventEmitter.call(app as any);
|
||||||
|
|
||||||
Object.assign(app, {
|
Object.assign(app, {
|
||||||
commandLine: {
|
commandLine: {
|
||||||
@@ -24,99 +24,99 @@ Object.assign(app, {
|
|||||||
appendSwitch: (theSwitch: string, value?: string) => commandLine.appendSwitch(String(theSwitch), typeof value === 'undefined' ? value : String(value)),
|
appendSwitch: (theSwitch: string, value?: string) => commandLine.appendSwitch(String(theSwitch), typeof value === 'undefined' ? value : String(value)),
|
||||||
appendArgument: (arg: string) => commandLine.appendArgument(String(arg))
|
appendArgument: (arg: string) => commandLine.appendArgument(String(arg))
|
||||||
} as Electron.CommandLine
|
} as Electron.CommandLine
|
||||||
})
|
});
|
||||||
|
|
||||||
// we define this here because it'd be overly complicated to
|
// we define this here because it'd be overly complicated to
|
||||||
// do in native land
|
// do in native land
|
||||||
Object.defineProperty(app, 'applicationMenu', {
|
Object.defineProperty(app, 'applicationMenu', {
|
||||||
get () {
|
get () {
|
||||||
return Menu.getApplicationMenu()
|
return Menu.getApplicationMenu();
|
||||||
},
|
},
|
||||||
set (menu: Electron.Menu | null) {
|
set (menu: Electron.Menu | null) {
|
||||||
return Menu.setApplicationMenu(menu)
|
return Menu.setApplicationMenu(menu);
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
|
|
||||||
App.prototype.isPackaged = (() => {
|
App.prototype.isPackaged = (() => {
|
||||||
const execFile = path.basename(process.execPath).toLowerCase()
|
const execFile = path.basename(process.execPath).toLowerCase();
|
||||||
if (process.platform === 'win32') {
|
if (process.platform === 'win32') {
|
||||||
return execFile !== 'electron.exe'
|
return execFile !== 'electron.exe';
|
||||||
}
|
}
|
||||||
return execFile !== 'electron'
|
return execFile !== 'electron';
|
||||||
})()
|
})();
|
||||||
|
|
||||||
app._setDefaultAppPaths = (packagePath) => {
|
app._setDefaultAppPaths = (packagePath) => {
|
||||||
// Set the user path according to application's name.
|
// Set the user path according to application's name.
|
||||||
app.setPath('userData', path.join(app.getPath('appData'), app.name!))
|
app.setPath('userData', path.join(app.getPath('appData'), app.name!));
|
||||||
app.setPath('userCache', path.join(app.getPath('cache'), app.name!))
|
app.setPath('userCache', path.join(app.getPath('cache'), app.name!));
|
||||||
app.setAppPath(packagePath)
|
app.setAppPath(packagePath);
|
||||||
|
|
||||||
// Add support for --user-data-dir=
|
// Add support for --user-data-dir=
|
||||||
if (app.commandLine.hasSwitch('user-data-dir')) {
|
if (app.commandLine.hasSwitch('user-data-dir')) {
|
||||||
const userDataDir = app.commandLine.getSwitchValue('user-data-dir')
|
const userDataDir = app.commandLine.getSwitchValue('user-data-dir');
|
||||||
if (path.isAbsolute(userDataDir)) app.setPath('userData', userDataDir)
|
if (path.isAbsolute(userDataDir)) app.setPath('userData', userDataDir);
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
if (process.platform === 'darwin') {
|
if (process.platform === 'darwin') {
|
||||||
const setDockMenu = app.dock!.setMenu
|
const setDockMenu = app.dock!.setMenu;
|
||||||
app.dock!.setMenu = (menu) => {
|
app.dock!.setMenu = (menu) => {
|
||||||
dockMenu = menu
|
dockMenu = menu;
|
||||||
setDockMenu(menu)
|
setDockMenu(menu);
|
||||||
}
|
};
|
||||||
app.dock!.getMenu = () => dockMenu
|
app.dock!.getMenu = () => dockMenu;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (process.platform === 'linux') {
|
if (process.platform === 'linux') {
|
||||||
const patternVmRSS = /^VmRSS:\s*(\d+) kB$/m
|
const patternVmRSS = /^VmRSS:\s*(\d+) kB$/m;
|
||||||
const patternVmHWM = /^VmHWM:\s*(\d+) kB$/m
|
const patternVmHWM = /^VmHWM:\s*(\d+) kB$/m;
|
||||||
|
|
||||||
const getStatus = (pid: number) => {
|
const getStatus = (pid: number) => {
|
||||||
try {
|
try {
|
||||||
return fs.readFileSync(`/proc/${pid}/status`, 'utf8')
|
return fs.readFileSync(`/proc/${pid}/status`, 'utf8');
|
||||||
} catch {
|
} catch {
|
||||||
return ''
|
return '';
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
const getEntry = (file: string, pattern: RegExp) => {
|
const getEntry = (file: string, pattern: RegExp) => {
|
||||||
const match = file.match(pattern)
|
const match = file.match(pattern);
|
||||||
return match ? parseInt(match[1], 10) : 0
|
return match ? parseInt(match[1], 10) : 0;
|
||||||
}
|
};
|
||||||
|
|
||||||
const getProcessMemoryInfo = (pid: number) => {
|
const getProcessMemoryInfo = (pid: number) => {
|
||||||
const file = getStatus(pid)
|
const file = getStatus(pid);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
workingSetSize: getEntry(file, patternVmRSS),
|
workingSetSize: getEntry(file, patternVmRSS),
|
||||||
peakWorkingSetSize: getEntry(file, patternVmHWM)
|
peakWorkingSetSize: getEntry(file, patternVmHWM)
|
||||||
}
|
};
|
||||||
}
|
};
|
||||||
|
|
||||||
const nativeFn = app.getAppMetrics
|
const nativeFn = app.getAppMetrics;
|
||||||
app.getAppMetrics = () => {
|
app.getAppMetrics = () => {
|
||||||
const metrics = nativeFn.call(app)
|
const metrics = nativeFn.call(app);
|
||||||
for (const metric of metrics) {
|
for (const metric of metrics) {
|
||||||
metric.memory = getProcessMemoryInfo(metric.pid)
|
metric.memory = getProcessMemoryInfo(metric.pid);
|
||||||
}
|
}
|
||||||
|
|
||||||
return metrics
|
return metrics;
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// Routes the events to webContents.
|
// Routes the events to webContents.
|
||||||
const events = ['login', 'certificate-error', 'select-client-certificate']
|
const events = ['certificate-error', 'select-client-certificate'];
|
||||||
for (const name of events) {
|
for (const name of events) {
|
||||||
app.on(name as 'login', (event, webContents, ...args: any[]) => {
|
app.on(name as 'certificate-error', (event, webContents, ...args: any[]) => {
|
||||||
webContents.emit(name, event, ...args)
|
webContents.emit(name, event, ...args);
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Property Deprecations
|
// Property Deprecations
|
||||||
deprecate.fnToProperty(App.prototype, 'accessibilitySupportEnabled', '_isAccessibilitySupportEnabled', '_setAccessibilitySupportEnabled')
|
deprecate.fnToProperty(App.prototype, 'accessibilitySupportEnabled', '_isAccessibilitySupportEnabled', '_setAccessibilitySupportEnabled');
|
||||||
deprecate.fnToProperty(App.prototype, 'badgeCount', '_getBadgeCount', '_setBadgeCount')
|
deprecate.fnToProperty(App.prototype, 'badgeCount', '_getBadgeCount', '_setBadgeCount');
|
||||||
deprecate.fnToProperty(App.prototype, 'name', '_getName', '_setName')
|
deprecate.fnToProperty(App.prototype, 'name', '_getName', '_setName');
|
||||||
|
|
||||||
// Wrappers for native classes.
|
// Wrappers for native classes.
|
||||||
const { DownloadItem } = process.electronBinding('download_item')
|
const { DownloadItem } = process.electronBinding('download_item');
|
||||||
Object.setPrototypeOf(DownloadItem.prototype, EventEmitter.prototype)
|
Object.setPrototypeOf(DownloadItem.prototype, EventEmitter.prototype);
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
'use strict'
|
'use strict';
|
||||||
|
|
||||||
if (process.platform === 'win32') {
|
if (process.platform === 'win32') {
|
||||||
module.exports = require('@electron/internal/browser/api/auto-updater/auto-updater-win')
|
module.exports = require('@electron/internal/browser/api/auto-updater/auto-updater-win');
|
||||||
} else {
|
} else {
|
||||||
module.exports = require('@electron/internal/browser/api/auto-updater/auto-updater-native')
|
module.exports = require('@electron/internal/browser/api/auto-updater/auto-updater-native');
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
'use strict'
|
'use strict';
|
||||||
|
|
||||||
const EventEmitter = require('events').EventEmitter
|
const EventEmitter = require('events').EventEmitter;
|
||||||
const { autoUpdater, AutoUpdater } = process.electronBinding('auto_updater')
|
const { autoUpdater, AutoUpdater } = process.electronBinding('auto_updater');
|
||||||
|
|
||||||
// AutoUpdater is an EventEmitter.
|
// AutoUpdater is an EventEmitter.
|
||||||
Object.setPrototypeOf(AutoUpdater.prototype, EventEmitter.prototype)
|
Object.setPrototypeOf(AutoUpdater.prototype, EventEmitter.prototype);
|
||||||
EventEmitter.call(autoUpdater)
|
EventEmitter.call(autoUpdater);
|
||||||
|
|
||||||
module.exports = autoUpdater
|
module.exports = autoUpdater;
|
||||||
|
|||||||
@@ -1,74 +1,74 @@
|
|||||||
'use strict'
|
'use strict';
|
||||||
|
|
||||||
const { app } = require('electron')
|
const { app } = require('electron');
|
||||||
const { EventEmitter } = require('events')
|
const { EventEmitter } = require('events');
|
||||||
const squirrelUpdate = require('@electron/internal/browser/api/auto-updater/squirrel-update-win')
|
const squirrelUpdate = require('@electron/internal/browser/api/auto-updater/squirrel-update-win');
|
||||||
|
|
||||||
class AutoUpdater extends EventEmitter {
|
class AutoUpdater extends EventEmitter {
|
||||||
quitAndInstall () {
|
quitAndInstall () {
|
||||||
if (!this.updateAvailable) {
|
if (!this.updateAvailable) {
|
||||||
return this.emitError('No update available, can\'t quit and install')
|
return this.emitError('No update available, can\'t quit and install');
|
||||||
}
|
}
|
||||||
squirrelUpdate.processStart()
|
squirrelUpdate.processStart();
|
||||||
app.quit()
|
app.quit();
|
||||||
}
|
}
|
||||||
|
|
||||||
getFeedURL () {
|
getFeedURL () {
|
||||||
return this.updateURL
|
return this.updateURL;
|
||||||
}
|
}
|
||||||
|
|
||||||
setFeedURL (options) {
|
setFeedURL (options) {
|
||||||
let updateURL
|
let updateURL;
|
||||||
if (typeof options === 'object') {
|
if (typeof options === 'object') {
|
||||||
if (typeof options.url === 'string') {
|
if (typeof options.url === 'string') {
|
||||||
updateURL = options.url
|
updateURL = options.url;
|
||||||
} else {
|
} else {
|
||||||
throw new Error('Expected options object to contain a \'url\' string property in setFeedUrl call')
|
throw new Error('Expected options object to contain a \'url\' string property in setFeedUrl call');
|
||||||
}
|
}
|
||||||
} else if (typeof options === 'string') {
|
} else if (typeof options === 'string') {
|
||||||
updateURL = options
|
updateURL = options;
|
||||||
} else {
|
} else {
|
||||||
throw new Error('Expected an options object with a \'url\' property to be provided')
|
throw new Error('Expected an options object with a \'url\' property to be provided');
|
||||||
}
|
}
|
||||||
this.updateURL = updateURL
|
this.updateURL = updateURL;
|
||||||
}
|
}
|
||||||
|
|
||||||
checkForUpdates () {
|
checkForUpdates () {
|
||||||
if (!this.updateURL) {
|
if (!this.updateURL) {
|
||||||
return this.emitError('Update URL is not set')
|
return this.emitError('Update URL is not set');
|
||||||
}
|
}
|
||||||
if (!squirrelUpdate.supported()) {
|
if (!squirrelUpdate.supported()) {
|
||||||
return this.emitError('Can not find Squirrel')
|
return this.emitError('Can not find Squirrel');
|
||||||
}
|
}
|
||||||
this.emit('checking-for-update')
|
this.emit('checking-for-update');
|
||||||
squirrelUpdate.checkForUpdate(this.updateURL, (error, update) => {
|
squirrelUpdate.checkForUpdate(this.updateURL, (error, update) => {
|
||||||
if (error != null) {
|
if (error != null) {
|
||||||
return this.emitError(error)
|
return this.emitError(error);
|
||||||
}
|
}
|
||||||
if (update == null) {
|
if (update == null) {
|
||||||
return this.emit('update-not-available')
|
return this.emit('update-not-available');
|
||||||
}
|
}
|
||||||
this.updateAvailable = true
|
this.updateAvailable = true;
|
||||||
this.emit('update-available')
|
this.emit('update-available');
|
||||||
squirrelUpdate.update(this.updateURL, (error) => {
|
squirrelUpdate.update(this.updateURL, (error) => {
|
||||||
if (error != null) {
|
if (error != null) {
|
||||||
return this.emitError(error)
|
return this.emitError(error);
|
||||||
}
|
}
|
||||||
const { releaseNotes, version } = update
|
const { releaseNotes, version } = update;
|
||||||
// Date is not available on Windows, so fake it.
|
// Date is not available on Windows, so fake it.
|
||||||
const date = new Date()
|
const date = new Date();
|
||||||
this.emit('update-downloaded', {}, releaseNotes, version, date, this.updateURL, () => {
|
this.emit('update-downloaded', {}, releaseNotes, version, date, this.updateURL, () => {
|
||||||
this.quitAndInstall()
|
this.quitAndInstall();
|
||||||
})
|
});
|
||||||
})
|
});
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Private: Emit both error object and message, this is to keep compatibility
|
// Private: Emit both error object and message, this is to keep compatibility
|
||||||
// with Old APIs.
|
// with Old APIs.
|
||||||
emitError (message) {
|
emitError (message) {
|
||||||
this.emit('error', new Error(message), message)
|
this.emit('error', new Error(message), message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = new AutoUpdater()
|
module.exports = new AutoUpdater();
|
||||||
|
|||||||
@@ -1,24 +1,24 @@
|
|||||||
'use strict'
|
'use strict';
|
||||||
|
|
||||||
const fs = require('fs')
|
const fs = require('fs');
|
||||||
const path = require('path')
|
const path = require('path');
|
||||||
const spawn = require('child_process').spawn
|
const spawn = require('child_process').spawn;
|
||||||
|
|
||||||
// i.e. my-app/app-0.1.13/
|
// i.e. my-app/app-0.1.13/
|
||||||
const appFolder = path.dirname(process.execPath)
|
const appFolder = path.dirname(process.execPath);
|
||||||
|
|
||||||
// i.e. my-app/Update.exe
|
// i.e. my-app/Update.exe
|
||||||
const updateExe = path.resolve(appFolder, '..', 'Update.exe')
|
const updateExe = path.resolve(appFolder, '..', 'Update.exe');
|
||||||
const exeName = path.basename(process.execPath)
|
const exeName = path.basename(process.execPath);
|
||||||
let spawnedArgs = []
|
let spawnedArgs = [];
|
||||||
let spawnedProcess
|
let spawnedProcess;
|
||||||
|
|
||||||
const isSameArgs = (args) => args.length === spawnedArgs.length && args.every((e, i) => e === spawnedArgs[i])
|
const isSameArgs = (args) => args.length === spawnedArgs.length && args.every((e, i) => e === spawnedArgs[i]);
|
||||||
|
|
||||||
// Spawn a command and invoke the callback when it completes with an error
|
// Spawn a command and invoke the callback when it completes with an error
|
||||||
// and the output from standard out.
|
// and the output from standard out.
|
||||||
const spawnUpdate = function (args, detached, callback) {
|
const spawnUpdate = function (args, detached, callback) {
|
||||||
let error, errorEmitted, stderr, stdout
|
let error, errorEmitted, stderr, stdout;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Ensure we don't spawn multiple squirrel processes
|
// Ensure we don't spawn multiple squirrel processes
|
||||||
@@ -28,92 +28,92 @@ const spawnUpdate = function (args, detached, callback) {
|
|||||||
if (spawnedProcess && !isSameArgs(args)) {
|
if (spawnedProcess && !isSameArgs(args)) {
|
||||||
// Disabled for backwards compatibility:
|
// Disabled for backwards compatibility:
|
||||||
// eslint-disable-next-line standard/no-callback-literal
|
// eslint-disable-next-line standard/no-callback-literal
|
||||||
return callback(`AutoUpdater process with arguments ${args} is already running`)
|
return callback(`AutoUpdater process with arguments ${args} is already running`);
|
||||||
} else if (!spawnedProcess) {
|
} else if (!spawnedProcess) {
|
||||||
spawnedProcess = spawn(updateExe, args, {
|
spawnedProcess = spawn(updateExe, args, {
|
||||||
detached: detached,
|
detached: detached,
|
||||||
windowsHide: true
|
windowsHide: true
|
||||||
})
|
});
|
||||||
spawnedArgs = args || []
|
spawnedArgs = args || [];
|
||||||
}
|
}
|
||||||
} catch (error1) {
|
} catch (error1) {
|
||||||
error = error1
|
error = error1;
|
||||||
|
|
||||||
// Shouldn't happen, but still guard it.
|
// Shouldn't happen, but still guard it.
|
||||||
process.nextTick(function () {
|
process.nextTick(function () {
|
||||||
return callback(error)
|
return callback(error);
|
||||||
})
|
});
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
stdout = ''
|
stdout = '';
|
||||||
stderr = ''
|
stderr = '';
|
||||||
|
|
||||||
spawnedProcess.stdout.on('data', (data) => { stdout += data })
|
spawnedProcess.stdout.on('data', (data) => { stdout += data; });
|
||||||
spawnedProcess.stderr.on('data', (data) => { stderr += data })
|
spawnedProcess.stderr.on('data', (data) => { stderr += data; });
|
||||||
|
|
||||||
errorEmitted = false
|
errorEmitted = false;
|
||||||
spawnedProcess.on('error', (error) => {
|
spawnedProcess.on('error', (error) => {
|
||||||
errorEmitted = true
|
errorEmitted = true;
|
||||||
callback(error)
|
callback(error);
|
||||||
})
|
});
|
||||||
|
|
||||||
return spawnedProcess.on('exit', function (code, signal) {
|
return spawnedProcess.on('exit', function (code, signal) {
|
||||||
spawnedProcess = undefined
|
spawnedProcess = undefined;
|
||||||
spawnedArgs = []
|
spawnedArgs = [];
|
||||||
|
|
||||||
// We may have already emitted an error.
|
// We may have already emitted an error.
|
||||||
if (errorEmitted) {
|
if (errorEmitted) {
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Process terminated with error.
|
// Process terminated with error.
|
||||||
if (code !== 0) {
|
if (code !== 0) {
|
||||||
// Disabled for backwards compatibility:
|
// Disabled for backwards compatibility:
|
||||||
// eslint-disable-next-line standard/no-callback-literal
|
// eslint-disable-next-line standard/no-callback-literal
|
||||||
return callback(`Command failed: ${signal != null ? signal : code}\n${stderr}`)
|
return callback(`Command failed: ${signal != null ? signal : code}\n${stderr}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Success.
|
// Success.
|
||||||
callback(null, stdout)
|
callback(null, stdout);
|
||||||
})
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
// Start an instance of the installed app.
|
// Start an instance of the installed app.
|
||||||
exports.processStart = function () {
|
exports.processStart = function () {
|
||||||
return spawnUpdate(['--processStartAndWait', exeName], true, function () {})
|
return spawnUpdate(['--processStartAndWait', exeName], true, function () {});
|
||||||
}
|
};
|
||||||
|
|
||||||
// Download the releases specified by the URL and write new results to stdout.
|
// Download the releases specified by the URL and write new results to stdout.
|
||||||
exports.checkForUpdate = function (updateURL, callback) {
|
exports.checkForUpdate = function (updateURL, callback) {
|
||||||
return spawnUpdate(['--checkForUpdate', updateURL], false, function (error, stdout) {
|
return spawnUpdate(['--checkForUpdate', updateURL], false, function (error, stdout) {
|
||||||
let ref, ref1, update
|
let ref, ref1, update;
|
||||||
if (error != null) {
|
if (error != null) {
|
||||||
return callback(error)
|
return callback(error);
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
// Last line of output is the JSON details about the releases
|
// Last line of output is the JSON details about the releases
|
||||||
const json = stdout.trim().split('\n').pop()
|
const json = stdout.trim().split('\n').pop();
|
||||||
update = (ref = JSON.parse(json)) != null ? (ref1 = ref.releasesToApply) != null ? typeof ref1.pop === 'function' ? ref1.pop() : void 0 : void 0 : void 0
|
update = (ref = JSON.parse(json)) != null ? (ref1 = ref.releasesToApply) != null ? typeof ref1.pop === 'function' ? ref1.pop() : void 0 : void 0 : void 0;
|
||||||
} catch {
|
} catch {
|
||||||
// Disabled for backwards compatibility:
|
// Disabled for backwards compatibility:
|
||||||
// eslint-disable-next-line standard/no-callback-literal
|
// eslint-disable-next-line standard/no-callback-literal
|
||||||
return callback(`Invalid result:\n${stdout}`)
|
return callback(`Invalid result:\n${stdout}`);
|
||||||
}
|
}
|
||||||
return callback(null, update)
|
return callback(null, update);
|
||||||
})
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
// Update the application to the latest remote version specified by URL.
|
// Update the application to the latest remote version specified by URL.
|
||||||
exports.update = function (updateURL, callback) {
|
exports.update = function (updateURL, callback) {
|
||||||
return spawnUpdate(['--update', updateURL], false, callback)
|
return spawnUpdate(['--update', updateURL], false, callback);
|
||||||
}
|
};
|
||||||
|
|
||||||
// Is the Update.exe installed with the current application?
|
// Is the Update.exe installed with the current application?
|
||||||
exports.supported = function () {
|
exports.supported = function () {
|
||||||
try {
|
try {
|
||||||
fs.accessSync(updateExe, fs.R_OK)
|
fs.accessSync(updateExe, fs.R_OK);
|
||||||
return true
|
return true;
|
||||||
} catch {
|
} catch {
|
||||||
return false
|
return false;
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|||||||
@@ -1,16 +1,16 @@
|
|||||||
'use strict'
|
'use strict';
|
||||||
|
|
||||||
const { EventEmitter } = require('events')
|
const { EventEmitter } = require('events');
|
||||||
const { BrowserView } = process.electronBinding('browser_view')
|
const { BrowserView } = process.electronBinding('browser_view');
|
||||||
|
|
||||||
Object.setPrototypeOf(BrowserView.prototype, EventEmitter.prototype)
|
Object.setPrototypeOf(BrowserView.prototype, EventEmitter.prototype);
|
||||||
|
|
||||||
BrowserView.fromWebContents = (webContents) => {
|
BrowserView.fromWebContents = (webContents) => {
|
||||||
for (const view of BrowserView.getAllViews()) {
|
for (const view of BrowserView.getAllViews()) {
|
||||||
if (view.webContents.equal(webContents)) return view
|
if (view.webContents.equal(webContents)) return view;
|
||||||
}
|
}
|
||||||
|
|
||||||
return null
|
return null;
|
||||||
}
|
};
|
||||||
|
|
||||||
module.exports = BrowserView
|
module.exports = BrowserView;
|
||||||
|
|||||||
@@ -1,49 +1,49 @@
|
|||||||
'use strict'
|
'use strict';
|
||||||
|
|
||||||
const electron = require('electron')
|
const electron = require('electron');
|
||||||
const { WebContentsView, TopLevelWindow, deprecate } = electron
|
const { WebContentsView, TopLevelWindow, deprecate } = electron;
|
||||||
const { BrowserWindow } = process.electronBinding('window')
|
const { BrowserWindow } = process.electronBinding('window');
|
||||||
|
|
||||||
Object.setPrototypeOf(BrowserWindow.prototype, TopLevelWindow.prototype)
|
Object.setPrototypeOf(BrowserWindow.prototype, TopLevelWindow.prototype);
|
||||||
|
|
||||||
BrowserWindow.prototype._init = function () {
|
BrowserWindow.prototype._init = function () {
|
||||||
// Call parent class's _init.
|
// Call parent class's _init.
|
||||||
TopLevelWindow.prototype._init.call(this)
|
TopLevelWindow.prototype._init.call(this);
|
||||||
|
|
||||||
// Avoid recursive require.
|
// Avoid recursive require.
|
||||||
const { app } = electron
|
const { app } = electron;
|
||||||
|
|
||||||
// Create WebContentsView.
|
// Create WebContentsView.
|
||||||
this.setContentView(new WebContentsView(this.webContents))
|
this.setContentView(new WebContentsView(this.webContents));
|
||||||
|
|
||||||
const nativeSetBounds = this.setBounds
|
const nativeSetBounds = this.setBounds;
|
||||||
this.setBounds = (bounds, ...opts) => {
|
this.setBounds = (bounds, ...opts) => {
|
||||||
bounds = {
|
bounds = {
|
||||||
...this.getBounds(),
|
...this.getBounds(),
|
||||||
...bounds
|
...bounds
|
||||||
}
|
};
|
||||||
nativeSetBounds.call(this, bounds, ...opts)
|
nativeSetBounds.call(this, bounds, ...opts);
|
||||||
}
|
};
|
||||||
|
|
||||||
// window.resizeTo(...)
|
// window.resizeTo(...)
|
||||||
// window.moveTo(...)
|
// window.moveTo(...)
|
||||||
this.webContents.on('move', (event, size) => {
|
this.webContents.on('move', (event, size) => {
|
||||||
this.setBounds(size)
|
this.setBounds(size);
|
||||||
})
|
});
|
||||||
|
|
||||||
// Hide the auto-hide menu when webContents is focused.
|
// Hide the auto-hide menu when webContents is focused.
|
||||||
this.webContents.on('activate', () => {
|
this.webContents.on('activate', () => {
|
||||||
if (process.platform !== 'darwin' && this.isMenuBarAutoHide() && this.isMenuBarVisible()) {
|
if (process.platform !== 'darwin' && this.autoHideMenuBar && this.isMenuBarVisible()) {
|
||||||
this.setMenuBarVisibility(false)
|
this.setMenuBarVisibility(false);
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
|
|
||||||
// Change window title to page title.
|
// Change window title to page title.
|
||||||
this.webContents.on('page-title-updated', (event, title, ...args) => {
|
this.webContents.on('page-title-updated', (event, title, ...args) => {
|
||||||
// Route the event to BrowserWindow.
|
// Route the event to BrowserWindow.
|
||||||
this.emit('page-title-updated', event, title, ...args)
|
this.emit('page-title-updated', event, title, ...args);
|
||||||
if (!this.isDestroyed() && !event.defaultPrevented) this.setTitle(title)
|
if (!this.isDestroyed() && !event.defaultPrevented) this.setTitle(title);
|
||||||
})
|
});
|
||||||
|
|
||||||
// Sometimes the webContents doesn't get focus when window is shown, so we
|
// Sometimes the webContents doesn't get focus when window is shown, so we
|
||||||
// have to force focusing on webContents in this case. The safest way is to
|
// have to force focusing on webContents in this case. The safest way is to
|
||||||
@@ -54,144 +54,144 @@ BrowserWindow.prototype._init = function () {
|
|||||||
// Finder, we still do it on all platforms in case of other bugs we don't
|
// Finder, we still do it on all platforms in case of other bugs we don't
|
||||||
// know.
|
// know.
|
||||||
this.webContents.once('load-url', function () {
|
this.webContents.once('load-url', function () {
|
||||||
this.focus()
|
this.focus();
|
||||||
})
|
});
|
||||||
|
|
||||||
// Redirect focus/blur event to app instance too.
|
// Redirect focus/blur event to app instance too.
|
||||||
this.on('blur', (event) => {
|
this.on('blur', (event) => {
|
||||||
app.emit('browser-window-blur', event, this)
|
app.emit('browser-window-blur', event, this);
|
||||||
})
|
});
|
||||||
this.on('focus', (event) => {
|
this.on('focus', (event) => {
|
||||||
app.emit('browser-window-focus', event, this)
|
app.emit('browser-window-focus', event, this);
|
||||||
})
|
});
|
||||||
|
|
||||||
// Subscribe to visibilityState changes and pass to renderer process.
|
// Subscribe to visibilityState changes and pass to renderer process.
|
||||||
let isVisible = this.isVisible() && !this.isMinimized()
|
let isVisible = this.isVisible() && !this.isMinimized();
|
||||||
const visibilityChanged = () => {
|
const visibilityChanged = () => {
|
||||||
const newState = this.isVisible() && !this.isMinimized()
|
const newState = this.isVisible() && !this.isMinimized();
|
||||||
if (isVisible !== newState) {
|
if (isVisible !== newState) {
|
||||||
isVisible = newState
|
isVisible = newState;
|
||||||
const visibilityState = isVisible ? 'visible' : 'hidden'
|
const visibilityState = isVisible ? 'visible' : 'hidden';
|
||||||
this.webContents.emit('-window-visibility-change', visibilityState)
|
this.webContents.emit('-window-visibility-change', visibilityState);
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
const visibilityEvents = ['show', 'hide', 'minimize', 'maximize', 'restore']
|
const visibilityEvents = ['show', 'hide', 'minimize', 'maximize', 'restore'];
|
||||||
for (const event of visibilityEvents) {
|
for (const event of visibilityEvents) {
|
||||||
this.on(event, visibilityChanged)
|
this.on(event, visibilityChanged);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Notify the creation of the window.
|
// Notify the creation of the window.
|
||||||
const event = process.electronBinding('event').createEmpty()
|
const event = process.electronBinding('event').createEmpty();
|
||||||
app.emit('browser-window-created', event, this)
|
app.emit('browser-window-created', event, this);
|
||||||
|
|
||||||
Object.defineProperty(this, 'devToolsWebContents', {
|
Object.defineProperty(this, 'devToolsWebContents', {
|
||||||
enumerable: true,
|
enumerable: true,
|
||||||
configurable: false,
|
configurable: false,
|
||||||
get () {
|
get () {
|
||||||
return this.webContents.devToolsWebContents
|
return this.webContents.devToolsWebContents;
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
const isBrowserWindow = (win) => {
|
const isBrowserWindow = (win) => {
|
||||||
return win && win.constructor.name === 'BrowserWindow'
|
return win && win.constructor.name === 'BrowserWindow';
|
||||||
}
|
};
|
||||||
|
|
||||||
BrowserWindow.fromId = (id) => {
|
BrowserWindow.fromId = (id) => {
|
||||||
const win = TopLevelWindow.fromId(id)
|
const win = TopLevelWindow.fromId(id);
|
||||||
return isBrowserWindow(win) ? win : null
|
return isBrowserWindow(win) ? win : null;
|
||||||
}
|
};
|
||||||
|
|
||||||
BrowserWindow.getAllWindows = () => {
|
BrowserWindow.getAllWindows = () => {
|
||||||
return TopLevelWindow.getAllWindows().filter(isBrowserWindow)
|
return TopLevelWindow.getAllWindows().filter(isBrowserWindow);
|
||||||
}
|
};
|
||||||
|
|
||||||
BrowserWindow.getFocusedWindow = () => {
|
BrowserWindow.getFocusedWindow = () => {
|
||||||
for (const window of BrowserWindow.getAllWindows()) {
|
for (const window of BrowserWindow.getAllWindows()) {
|
||||||
if (window.isFocused() || window.isDevToolsFocused()) return window
|
if (window.isFocused() || window.isDevToolsFocused()) return window;
|
||||||
}
|
}
|
||||||
return null
|
return null;
|
||||||
}
|
};
|
||||||
|
|
||||||
BrowserWindow.fromWebContents = (webContents) => {
|
BrowserWindow.fromWebContents = (webContents) => {
|
||||||
for (const window of BrowserWindow.getAllWindows()) {
|
for (const window of BrowserWindow.getAllWindows()) {
|
||||||
if (window.webContents.equal(webContents)) return window
|
if (window.webContents && window.webContents.equal(webContents)) return window;
|
||||||
}
|
}
|
||||||
|
|
||||||
return null
|
return null;
|
||||||
}
|
};
|
||||||
|
|
||||||
BrowserWindow.fromBrowserView = (browserView) => {
|
BrowserWindow.fromBrowserView = (browserView) => {
|
||||||
for (const window of BrowserWindow.getAllWindows()) {
|
for (const window of BrowserWindow.getAllWindows()) {
|
||||||
if (window.getBrowserView() === browserView) return window
|
if (window.getBrowserView() === browserView) return window;
|
||||||
}
|
}
|
||||||
|
|
||||||
return null
|
return null;
|
||||||
}
|
};
|
||||||
|
|
||||||
// Helpers.
|
// Helpers.
|
||||||
Object.assign(BrowserWindow.prototype, {
|
Object.assign(BrowserWindow.prototype, {
|
||||||
loadURL (...args) {
|
loadURL (...args) {
|
||||||
return this.webContents.loadURL(...args)
|
return this.webContents.loadURL(...args);
|
||||||
},
|
},
|
||||||
getURL (...args) {
|
getURL (...args) {
|
||||||
return this.webContents.getURL()
|
return this.webContents.getURL();
|
||||||
},
|
},
|
||||||
loadFile (...args) {
|
loadFile (...args) {
|
||||||
return this.webContents.loadFile(...args)
|
return this.webContents.loadFile(...args);
|
||||||
},
|
},
|
||||||
reload (...args) {
|
reload (...args) {
|
||||||
return this.webContents.reload(...args)
|
return this.webContents.reload(...args);
|
||||||
},
|
},
|
||||||
send (...args) {
|
send (...args) {
|
||||||
return this.webContents.send(...args)
|
return this.webContents.send(...args);
|
||||||
},
|
},
|
||||||
openDevTools (...args) {
|
openDevTools (...args) {
|
||||||
return this.webContents.openDevTools(...args)
|
return this.webContents.openDevTools(...args);
|
||||||
},
|
},
|
||||||
closeDevTools () {
|
closeDevTools () {
|
||||||
return this.webContents.closeDevTools()
|
return this.webContents.closeDevTools();
|
||||||
},
|
},
|
||||||
isDevToolsOpened () {
|
isDevToolsOpened () {
|
||||||
return this.webContents.isDevToolsOpened()
|
return this.webContents.isDevToolsOpened();
|
||||||
},
|
},
|
||||||
isDevToolsFocused () {
|
isDevToolsFocused () {
|
||||||
return this.webContents.isDevToolsFocused()
|
return this.webContents.isDevToolsFocused();
|
||||||
},
|
},
|
||||||
toggleDevTools () {
|
toggleDevTools () {
|
||||||
return this.webContents.toggleDevTools()
|
return this.webContents.toggleDevTools();
|
||||||
},
|
},
|
||||||
inspectElement (...args) {
|
inspectElement (...args) {
|
||||||
return this.webContents.inspectElement(...args)
|
return this.webContents.inspectElement(...args);
|
||||||
},
|
},
|
||||||
inspectSharedWorker () {
|
inspectSharedWorker () {
|
||||||
return this.webContents.inspectSharedWorker()
|
return this.webContents.inspectSharedWorker();
|
||||||
},
|
},
|
||||||
inspectServiceWorker () {
|
inspectServiceWorker () {
|
||||||
return this.webContents.inspectServiceWorker()
|
return this.webContents.inspectServiceWorker();
|
||||||
},
|
},
|
||||||
showDefinitionForSelection () {
|
showDefinitionForSelection () {
|
||||||
return this.webContents.showDefinitionForSelection()
|
return this.webContents.showDefinitionForSelection();
|
||||||
},
|
},
|
||||||
capturePage (...args) {
|
capturePage (...args) {
|
||||||
return this.webContents.capturePage(...args)
|
return this.webContents.capturePage(...args);
|
||||||
},
|
},
|
||||||
setTouchBar (touchBar) {
|
setTouchBar (touchBar) {
|
||||||
electron.TouchBar._setOnWindow(touchBar, this)
|
electron.TouchBar._setOnWindow(touchBar, this);
|
||||||
},
|
},
|
||||||
setBackgroundThrottling (allowed) {
|
setBackgroundThrottling (allowed) {
|
||||||
this.webContents.setBackgroundThrottling(allowed)
|
this.webContents.setBackgroundThrottling(allowed);
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
|
|
||||||
// Deprecations
|
// Deprecations
|
||||||
deprecate.fnToProperty(BrowserWindow.prototype, 'autoHideMenuBar', '_isMenuBarAutoHide', '_setAutoHideMenuBar')
|
deprecate.fnToProperty(BrowserWindow.prototype, 'autoHideMenuBar', '_isMenuBarAutoHide', '_setAutoHideMenuBar');
|
||||||
deprecate.fnToProperty(BrowserWindow.prototype, 'minimizable', '_isMinimizable', '_setMinimizable')
|
deprecate.fnToProperty(BrowserWindow.prototype, 'minimizable', '_isMinimizable', '_setMinimizable');
|
||||||
deprecate.fnToProperty(BrowserWindow.prototype, 'maximizable', '_isMaximizable', '_setMaximizable')
|
deprecate.fnToProperty(BrowserWindow.prototype, 'maximizable', '_isMaximizable', '_setMaximizable');
|
||||||
deprecate.fnToProperty(BrowserWindow.prototype, 'resizable', '_isResizable', '_setResizable')
|
deprecate.fnToProperty(BrowserWindow.prototype, 'resizable', '_isResizable', '_setResizable');
|
||||||
deprecate.fnToProperty(BrowserWindow.prototype, 'fullScreenable', '_isFullScreenable', '_setFullScreenable')
|
deprecate.fnToProperty(BrowserWindow.prototype, 'fullScreenable', '_isFullScreenable', '_setFullScreenable');
|
||||||
deprecate.fnToProperty(BrowserWindow.prototype, 'closable', '_isClosable', '_setClosable')
|
deprecate.fnToProperty(BrowserWindow.prototype, 'closable', '_isClosable', '_setClosable');
|
||||||
deprecate.fnToProperty(BrowserWindow.prototype, 'movable', '_isMovable', '_setMovable')
|
deprecate.fnToProperty(BrowserWindow.prototype, 'movable', '_isMovable', '_setMovable');
|
||||||
|
|
||||||
module.exports = BrowserWindow
|
module.exports = BrowserWindow;
|
||||||
|
|||||||
@@ -1,2 +1,2 @@
|
|||||||
'use strict'
|
'use strict';
|
||||||
module.exports = process.electronBinding('content_tracing')
|
module.exports = process.electronBinding('content_tracing');
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
'use strict'
|
'use strict';
|
||||||
|
|
||||||
const CrashReporter = require('@electron/internal/common/crash-reporter')
|
const CrashReporter = require('@electron/internal/common/crash-reporter');
|
||||||
const { crashReporterInit } = require('@electron/internal/browser/crash-reporter-init')
|
const { crashReporterInit } = require('@electron/internal/browser/crash-reporter-init');
|
||||||
|
|
||||||
class CrashReporterMain extends CrashReporter {
|
class CrashReporterMain extends CrashReporter {
|
||||||
init (options) {
|
init (options) {
|
||||||
return crashReporterInit(options)
|
return crashReporterInit(options);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = new CrashReporterMain()
|
module.exports = new CrashReporterMain();
|
||||||
|
|||||||
@@ -1,13 +1,13 @@
|
|||||||
'use strict'
|
'use strict';
|
||||||
|
|
||||||
const { app, BrowserWindow, deprecate } = require('electron')
|
const { app, BrowserWindow, deprecate } = require('electron');
|
||||||
const binding = process.electronBinding('dialog')
|
const binding = process.electronBinding('dialog');
|
||||||
const v8Util = process.electronBinding('v8_util')
|
const v8Util = process.electronBinding('v8_util');
|
||||||
|
|
||||||
const DialogType = {
|
const DialogType = {
|
||||||
OPEN: 'OPEN',
|
OPEN: 'OPEN',
|
||||||
SAVE: 'SAVE'
|
SAVE: 'SAVE'
|
||||||
}
|
};
|
||||||
|
|
||||||
const saveFileDialogProperties = {
|
const saveFileDialogProperties = {
|
||||||
createDirectory: 1 << 0,
|
createDirectory: 1 << 0,
|
||||||
@@ -15,7 +15,7 @@ const saveFileDialogProperties = {
|
|||||||
treatPackageAsDirectory: 1 << 2,
|
treatPackageAsDirectory: 1 << 2,
|
||||||
showOverwriteConfirmation: 1 << 3,
|
showOverwriteConfirmation: 1 << 3,
|
||||||
dontAddToRecent: 1 << 4
|
dontAddToRecent: 1 << 4
|
||||||
}
|
};
|
||||||
|
|
||||||
const openFileDialogProperties = {
|
const openFileDialogProperties = {
|
||||||
openFile: 1 << 0,
|
openFile: 1 << 0,
|
||||||
@@ -27,15 +27,15 @@ const openFileDialogProperties = {
|
|||||||
noResolveAliases: 1 << 6, // macOS
|
noResolveAliases: 1 << 6, // macOS
|
||||||
treatPackageAsDirectory: 1 << 7, // macOS
|
treatPackageAsDirectory: 1 << 7, // macOS
|
||||||
dontAddToRecent: 1 << 8 // Windows
|
dontAddToRecent: 1 << 8 // Windows
|
||||||
}
|
};
|
||||||
|
|
||||||
const normalizeAccessKey = (text) => {
|
const normalizeAccessKey = (text) => {
|
||||||
if (typeof text !== 'string') return text
|
if (typeof text !== 'string') return text;
|
||||||
|
|
||||||
// macOS does not have access keys so remove single ampersands
|
// macOS does not have access keys so remove single ampersands
|
||||||
// and replace double ampersands with a single ampersand
|
// and replace double ampersands with a single ampersand
|
||||||
if (process.platform === 'darwin') {
|
if (process.platform === 'darwin') {
|
||||||
return text.replace(/&(&?)/g, '$1')
|
return text.replace(/&(&?)/g, '$1');
|
||||||
}
|
}
|
||||||
|
|
||||||
// Linux uses a single underscore as an access key prefix so escape
|
// Linux uses a single underscore as an access key prefix so escape
|
||||||
@@ -44,41 +44,41 @@ const normalizeAccessKey = (text) => {
|
|||||||
// a single underscore
|
// a single underscore
|
||||||
if (process.platform === 'linux') {
|
if (process.platform === 'linux') {
|
||||||
return text.replace(/_/g, '__').replace(/&(.?)/g, (match, after) => {
|
return text.replace(/_/g, '__').replace(/&(.?)/g, (match, after) => {
|
||||||
if (after === '&') return after
|
if (after === '&') return after;
|
||||||
return `_${after}`
|
return `_${after}`;
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
return text
|
return text;
|
||||||
}
|
};
|
||||||
|
|
||||||
const checkAppInitialized = function () {
|
const checkAppInitialized = function () {
|
||||||
if (!app.isReady()) {
|
if (!app.isReady()) {
|
||||||
throw new Error('dialog module can only be used after app is ready')
|
throw new Error('dialog module can only be used after app is ready');
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
const setupDialogProperties = (type, properties) => {
|
const setupDialogProperties = (type, properties) => {
|
||||||
const dialogPropertiesTypes = (type === DialogType.OPEN) ? openFileDialogProperties : saveFileDialogProperties
|
const dialogPropertiesTypes = (type === DialogType.OPEN) ? openFileDialogProperties : saveFileDialogProperties;
|
||||||
let dialogProperties = 0
|
let dialogProperties = 0;
|
||||||
for (const prop in dialogPropertiesTypes) {
|
for (const prop in dialogPropertiesTypes) {
|
||||||
if (properties.includes(prop)) {
|
if (properties.includes(prop)) {
|
||||||
dialogProperties |= dialogPropertiesTypes[prop]
|
dialogProperties |= dialogPropertiesTypes[prop];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return dialogProperties
|
return dialogProperties;
|
||||||
}
|
};
|
||||||
|
|
||||||
const saveDialog = (sync, window, options) => {
|
const saveDialog = (sync, window, options) => {
|
||||||
checkAppInitialized()
|
checkAppInitialized();
|
||||||
|
|
||||||
if (window && window.constructor !== BrowserWindow) {
|
if (window && window.constructor !== BrowserWindow) {
|
||||||
options = window
|
options = window;
|
||||||
window = null
|
window = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (options == null) options = { title: 'Save' }
|
if (options == null) options = { title: 'Save' };
|
||||||
|
|
||||||
const {
|
const {
|
||||||
buttonLabel = '',
|
buttonLabel = '',
|
||||||
@@ -90,33 +90,33 @@ const saveDialog = (sync, window, options) => {
|
|||||||
securityScopedBookmarks = false,
|
securityScopedBookmarks = false,
|
||||||
nameFieldLabel = '',
|
nameFieldLabel = '',
|
||||||
showsTagField = true
|
showsTagField = true
|
||||||
} = options
|
} = options;
|
||||||
|
|
||||||
if (typeof title !== 'string') throw new TypeError('Title must be a string')
|
if (typeof title !== 'string') throw new TypeError('Title must be a string');
|
||||||
if (typeof buttonLabel !== 'string') throw new TypeError('Button label must be a string')
|
if (typeof buttonLabel !== 'string') throw new TypeError('Button label must be a string');
|
||||||
if (typeof defaultPath !== 'string') throw new TypeError('Default path must be a string')
|
if (typeof defaultPath !== 'string') throw new TypeError('Default path must be a string');
|
||||||
if (typeof message !== 'string') throw new TypeError('Message must be a string')
|
if (typeof message !== 'string') throw new TypeError('Message must be a string');
|
||||||
if (typeof nameFieldLabel !== 'string') throw new TypeError('Name field label must be a string')
|
if (typeof nameFieldLabel !== 'string') throw new TypeError('Name field label must be a string');
|
||||||
|
|
||||||
const settings = { buttonLabel, defaultPath, filters, title, message, securityScopedBookmarks, nameFieldLabel, showsTagField, window }
|
const settings = { buttonLabel, defaultPath, filters, title, message, securityScopedBookmarks, nameFieldLabel, showsTagField, window };
|
||||||
settings.properties = setupDialogProperties(DialogType.SAVE, properties)
|
settings.properties = setupDialogProperties(DialogType.SAVE, properties);
|
||||||
|
|
||||||
return (sync) ? binding.showSaveDialogSync(settings) : binding.showSaveDialog(settings)
|
return (sync) ? binding.showSaveDialogSync(settings) : binding.showSaveDialog(settings);
|
||||||
}
|
};
|
||||||
|
|
||||||
const openDialog = (sync, window, options) => {
|
const openDialog = (sync, window, options) => {
|
||||||
checkAppInitialized()
|
checkAppInitialized();
|
||||||
|
|
||||||
if (window && window.constructor !== BrowserWindow) {
|
if (window && window.constructor !== BrowserWindow) {
|
||||||
options = window
|
options = window;
|
||||||
window = null
|
window = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (options == null) {
|
if (options == null) {
|
||||||
options = {
|
options = {
|
||||||
title: 'Open',
|
title: 'Open',
|
||||||
properties: ['openFile']
|
properties: ['openFile']
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
const {
|
const {
|
||||||
@@ -127,33 +127,33 @@ const openDialog = (sync, window, options) => {
|
|||||||
title = '',
|
title = '',
|
||||||
message = '',
|
message = '',
|
||||||
securityScopedBookmarks = false
|
securityScopedBookmarks = false
|
||||||
} = options
|
} = options;
|
||||||
|
|
||||||
if (!Array.isArray(properties)) throw new TypeError('Properties must be an array')
|
if (!Array.isArray(properties)) throw new TypeError('Properties must be an array');
|
||||||
|
|
||||||
if (typeof title !== 'string') throw new TypeError('Title must be a string')
|
if (typeof title !== 'string') throw new TypeError('Title must be a string');
|
||||||
if (typeof buttonLabel !== 'string') throw new TypeError('Button label must be a string')
|
if (typeof buttonLabel !== 'string') throw new TypeError('Button label must be a string');
|
||||||
if (typeof defaultPath !== 'string') throw new TypeError('Default path must be a string')
|
if (typeof defaultPath !== 'string') throw new TypeError('Default path must be a string');
|
||||||
if (typeof message !== 'string') throw new TypeError('Message must be a string')
|
if (typeof message !== 'string') throw new TypeError('Message must be a string');
|
||||||
|
|
||||||
const settings = { title, buttonLabel, defaultPath, filters, message, securityScopedBookmarks, window }
|
const settings = { title, buttonLabel, defaultPath, filters, message, securityScopedBookmarks, window };
|
||||||
settings.properties = setupDialogProperties(DialogType.OPEN, properties)
|
settings.properties = setupDialogProperties(DialogType.OPEN, properties);
|
||||||
|
|
||||||
return (sync) ? binding.showOpenDialogSync(settings) : binding.showOpenDialog(settings)
|
return (sync) ? binding.showOpenDialogSync(settings) : binding.showOpenDialog(settings);
|
||||||
}
|
};
|
||||||
|
|
||||||
const messageBox = (sync, window, options) => {
|
const messageBox = (sync, window, options) => {
|
||||||
checkAppInitialized()
|
checkAppInitialized();
|
||||||
|
|
||||||
if (window && window.constructor !== BrowserWindow) {
|
if (window && window.constructor !== BrowserWindow) {
|
||||||
options = window
|
options = window;
|
||||||
window = null
|
window = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (options == null) options = { type: 'none' }
|
if (options == null) options = { type: 'none' };
|
||||||
|
|
||||||
const messageBoxTypes = ['none', 'info', 'warning', 'error', 'question']
|
const messageBoxTypes = ['none', 'info', 'warning', 'error', 'question'];
|
||||||
const messageBoxOptions = { noLink: 1 << 0 }
|
const messageBoxOptions = { noLink: 1 << 0 };
|
||||||
|
|
||||||
let {
|
let {
|
||||||
buttons = [],
|
buttons = [],
|
||||||
@@ -163,101 +163,104 @@ const messageBox = (sync, window, options) => {
|
|||||||
defaultId = -1,
|
defaultId = -1,
|
||||||
detail = '',
|
detail = '',
|
||||||
icon = null,
|
icon = null,
|
||||||
|
noLink = false,
|
||||||
message = '',
|
message = '',
|
||||||
title = '',
|
title = '',
|
||||||
type = 'none'
|
type = 'none'
|
||||||
} = options
|
} = options;
|
||||||
|
|
||||||
const messageBoxType = messageBoxTypes.indexOf(type)
|
const messageBoxType = messageBoxTypes.indexOf(type);
|
||||||
if (messageBoxType === -1) throw new TypeError('Invalid message box type')
|
if (messageBoxType === -1) throw new TypeError('Invalid message box type');
|
||||||
if (!Array.isArray(buttons)) throw new TypeError('Buttons must be an array')
|
if (!Array.isArray(buttons)) throw new TypeError('Buttons must be an array');
|
||||||
if (options.normalizeAccessKeys) buttons = buttons.map(normalizeAccessKey)
|
if (options.normalizeAccessKeys) buttons = buttons.map(normalizeAccessKey);
|
||||||
if (typeof title !== 'string') throw new TypeError('Title must be a string')
|
if (typeof title !== 'string') throw new TypeError('Title must be a string');
|
||||||
if (typeof message !== 'string') throw new TypeError('Message must be a string')
|
if (typeof noLink !== 'boolean') throw new TypeError('noLink must be a boolean');
|
||||||
if (typeof detail !== 'string') throw new TypeError('Detail must be a string')
|
if (typeof message !== 'string') throw new TypeError('Message must be a string');
|
||||||
if (typeof checkboxLabel !== 'string') throw new TypeError('checkboxLabel must be a string')
|
if (typeof detail !== 'string') throw new TypeError('Detail must be a string');
|
||||||
|
if (typeof checkboxLabel !== 'string') throw new TypeError('checkboxLabel must be a string');
|
||||||
|
|
||||||
checkboxChecked = !!checkboxChecked
|
checkboxChecked = !!checkboxChecked;
|
||||||
|
if (checkboxChecked && !checkboxLabel) {
|
||||||
|
throw new Error('checkboxChecked requires that checkboxLabel also be passed');
|
||||||
|
}
|
||||||
|
|
||||||
// Choose a default button to get selected when dialog is cancelled.
|
// Choose a default button to get selected when dialog is cancelled.
|
||||||
if (cancelId == null) {
|
if (cancelId == null) {
|
||||||
// If the defaultId is set to 0, ensure the cancel button is a different index (1)
|
// If the defaultId is set to 0, ensure the cancel button is a different index (1)
|
||||||
cancelId = (defaultId === 0 && buttons.length > 1) ? 1 : 0
|
cancelId = (defaultId === 0 && buttons.length > 1) ? 1 : 0;
|
||||||
for (let i = 0; i < buttons.length; i++) {
|
for (let i = 0; i < buttons.length; i++) {
|
||||||
const text = buttons[i].toLowerCase()
|
const text = buttons[i].toLowerCase();
|
||||||
if (text === 'cancel' || text === 'no') {
|
if (text === 'cancel' || text === 'no') {
|
||||||
cancelId = i
|
cancelId = i;
|
||||||
break
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const flags = options.noLink ? messageBoxOptions.noLink : 0
|
|
||||||
|
|
||||||
const settings = {
|
const settings = {
|
||||||
window,
|
window,
|
||||||
messageBoxType,
|
messageBoxType,
|
||||||
buttons,
|
buttons,
|
||||||
defaultId,
|
defaultId,
|
||||||
cancelId,
|
cancelId,
|
||||||
flags,
|
noLink,
|
||||||
title,
|
title,
|
||||||
message,
|
message,
|
||||||
detail,
|
detail,
|
||||||
checkboxLabel,
|
checkboxLabel,
|
||||||
checkboxChecked,
|
checkboxChecked,
|
||||||
icon
|
icon
|
||||||
}
|
};
|
||||||
|
|
||||||
if (sync) {
|
if (sync) {
|
||||||
return binding.showMessageBoxSync(settings)
|
return binding.showMessageBoxSync(settings);
|
||||||
} else {
|
} else {
|
||||||
return binding.showMessageBox(settings)
|
return binding.showMessageBox(settings);
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
showOpenDialog: function (window, options) {
|
showOpenDialog: function (window, options) {
|
||||||
return openDialog(false, window, options)
|
return openDialog(false, window, options);
|
||||||
},
|
},
|
||||||
|
|
||||||
showOpenDialogSync: function (window, options) {
|
showOpenDialogSync: function (window, options) {
|
||||||
return openDialog(true, window, options)
|
return openDialog(true, window, options);
|
||||||
},
|
},
|
||||||
|
|
||||||
showSaveDialog: function (window, options) {
|
showSaveDialog: function (window, options) {
|
||||||
return saveDialog(false, window, options)
|
return saveDialog(false, window, options);
|
||||||
},
|
},
|
||||||
|
|
||||||
showSaveDialogSync: function (window, options) {
|
showSaveDialogSync: function (window, options) {
|
||||||
return saveDialog(true, window, options)
|
return saveDialog(true, window, options);
|
||||||
},
|
},
|
||||||
|
|
||||||
showMessageBox: function (window, options) {
|
showMessageBox: function (window, options) {
|
||||||
return messageBox(false, window, options)
|
return messageBox(false, window, options);
|
||||||
},
|
},
|
||||||
|
|
||||||
showMessageBoxSync: function (window, options) {
|
showMessageBoxSync: function (window, options) {
|
||||||
return messageBox(true, window, options)
|
return messageBox(true, window, options);
|
||||||
},
|
},
|
||||||
|
|
||||||
showErrorBox: function (...args) {
|
showErrorBox: function (...args) {
|
||||||
return binding.showErrorBox(...args)
|
return binding.showErrorBox(...args);
|
||||||
},
|
},
|
||||||
|
|
||||||
showCertificateTrustDialog: function (window, options) {
|
showCertificateTrustDialog: function (window, options) {
|
||||||
if (window && window.constructor !== BrowserWindow) options = window
|
if (window && window.constructor !== BrowserWindow) options = window;
|
||||||
if (options == null || typeof options !== 'object') {
|
if (options == null || typeof options !== 'object') {
|
||||||
throw new TypeError('options must be an object')
|
throw new TypeError('options must be an object');
|
||||||
}
|
}
|
||||||
|
|
||||||
const { certificate, message = '' } = options
|
const { certificate, message = '' } = options;
|
||||||
if (certificate == null || typeof certificate !== 'object') {
|
if (certificate == null || typeof certificate !== 'object') {
|
||||||
throw new TypeError('certificate must be an object')
|
throw new TypeError('certificate must be an object');
|
||||||
}
|
}
|
||||||
|
|
||||||
if (typeof message !== 'string') throw new TypeError('message must be a string')
|
if (typeof message !== 'string') throw new TypeError('message must be a string');
|
||||||
|
|
||||||
return binding.showCertificateTrustDialog(window, certificate, message)
|
return binding.showCertificateTrustDialog(window, certificate, message);
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
import { defineProperties } from '@electron/internal/common/define-properties'
|
import { defineProperties } from '@electron/internal/common/define-properties';
|
||||||
import { commonModuleList } from '@electron/internal/common/api/module-list'
|
import { commonModuleList } from '@electron/internal/common/api/module-list';
|
||||||
import { browserModuleList } from '@electron/internal/browser/api/module-list'
|
import { browserModuleList } from '@electron/internal/browser/api/module-list';
|
||||||
|
|
||||||
defineProperties(exports, commonModuleList)
|
module.exports = {};
|
||||||
defineProperties(exports, browserModuleList)
|
|
||||||
|
defineProperties(module.exports, commonModuleList);
|
||||||
|
defineProperties(module.exports, browserModuleList);
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
'use strict'
|
'use strict';
|
||||||
|
|
||||||
module.exports = process.electronBinding('global_shortcut').globalShortcut
|
module.exports = process.electronBinding('global_shortcut').globalShortcut;
|
||||||
|
|||||||
@@ -1,22 +1,22 @@
|
|||||||
'use strict'
|
'use strict';
|
||||||
|
|
||||||
const { deprecate } = require('electron')
|
const { deprecate } = require('electron');
|
||||||
|
|
||||||
if (process.platform === 'darwin') {
|
if (process.platform === 'darwin') {
|
||||||
const { EventEmitter } = require('events')
|
const { EventEmitter } = require('events');
|
||||||
const { inAppPurchase, InAppPurchase } = process.electronBinding('in_app_purchase')
|
const { inAppPurchase, InAppPurchase } = process.electronBinding('in_app_purchase');
|
||||||
|
|
||||||
// inAppPurchase is an EventEmitter.
|
// inAppPurchase is an EventEmitter.
|
||||||
Object.setPrototypeOf(InAppPurchase.prototype, EventEmitter.prototype)
|
Object.setPrototypeOf(InAppPurchase.prototype, EventEmitter.prototype);
|
||||||
EventEmitter.call(inAppPurchase)
|
EventEmitter.call(inAppPurchase);
|
||||||
|
|
||||||
module.exports = inAppPurchase
|
module.exports = inAppPurchase;
|
||||||
} else {
|
} else {
|
||||||
module.exports = {
|
module.exports = {
|
||||||
purchaseProduct: (productID, quantity, callback) => {
|
purchaseProduct: (productID, quantity, callback) => {
|
||||||
throw new Error('The inAppPurchase module can only be used on macOS')
|
throw new Error('The inAppPurchase module can only be used on macOS');
|
||||||
},
|
},
|
||||||
canMakePayments: () => false,
|
canMakePayments: () => false,
|
||||||
getReceiptURL: () => ''
|
getReceiptURL: () => ''
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
import { IpcMainImpl } from '@electron/internal/browser/ipc-main-impl'
|
import { IpcMainImpl } from '@electron/internal/browser/ipc-main-impl';
|
||||||
|
|
||||||
const ipcMain = new IpcMainImpl()
|
const ipcMain = new IpcMainImpl();
|
||||||
|
|
||||||
// Do not throw exception when channel name is "error".
|
// Do not throw exception when channel name is "error".
|
||||||
ipcMain.on('error', () => {})
|
ipcMain.on('error', () => {});
|
||||||
|
|
||||||
export default ipcMain
|
export default ipcMain;
|
||||||
|
|||||||
@@ -1,15 +1,15 @@
|
|||||||
'use strict'
|
'use strict';
|
||||||
|
|
||||||
const { app } = require('electron')
|
const { app } = require('electron');
|
||||||
|
|
||||||
const isMac = process.platform === 'darwin'
|
const isMac = process.platform === 'darwin';
|
||||||
const isWindows = process.platform === 'win32'
|
const isWindows = process.platform === 'win32';
|
||||||
const isLinux = process.platform === 'linux'
|
const isLinux = process.platform === 'linux';
|
||||||
|
|
||||||
const roles = {
|
const roles = {
|
||||||
about: {
|
about: {
|
||||||
get label () {
|
get label () {
|
||||||
return isLinux ? 'About' : `About ${app.name}`
|
return isLinux ? 'About' : `About ${app.name}`;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
close: {
|
close: {
|
||||||
@@ -38,7 +38,7 @@ const roles = {
|
|||||||
accelerator: 'Shift+CmdOrCtrl+R',
|
accelerator: 'Shift+CmdOrCtrl+R',
|
||||||
nonNativeMacOSRole: true,
|
nonNativeMacOSRole: true,
|
||||||
windowMethod: (window) => {
|
windowMethod: (window) => {
|
||||||
window.webContents.reloadIgnoringCache()
|
window.webContents.reloadIgnoringCache();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
front: {
|
front: {
|
||||||
@@ -49,7 +49,7 @@ const roles = {
|
|||||||
},
|
},
|
||||||
hide: {
|
hide: {
|
||||||
get label () {
|
get label () {
|
||||||
return `Hide ${app.name}`
|
return `Hide ${app.name}`;
|
||||||
},
|
},
|
||||||
accelerator: 'Command+H'
|
accelerator: 'Command+H'
|
||||||
},
|
},
|
||||||
@@ -77,9 +77,9 @@ const roles = {
|
|||||||
quit: {
|
quit: {
|
||||||
get label () {
|
get label () {
|
||||||
switch (process.platform) {
|
switch (process.platform) {
|
||||||
case 'darwin': return `Quit ${app.name}`
|
case 'darwin': return `Quit ${app.name}`;
|
||||||
case 'win32': return 'Exit'
|
case 'win32': return 'Exit';
|
||||||
default: return 'Quit'
|
default: return 'Quit';
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
accelerator: isWindows ? undefined : 'CommandOrControl+Q',
|
accelerator: isWindows ? undefined : 'CommandOrControl+Q',
|
||||||
@@ -101,7 +101,7 @@ const roles = {
|
|||||||
accelerator: 'CommandOrControl+0',
|
accelerator: 'CommandOrControl+0',
|
||||||
nonNativeMacOSRole: true,
|
nonNativeMacOSRole: true,
|
||||||
webContentsMethod: (webContents) => {
|
webContentsMethod: (webContents) => {
|
||||||
webContents.zoomLevel = 0
|
webContents.zoomLevel = 0;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
selectall: {
|
selectall: {
|
||||||
@@ -134,7 +134,7 @@ const roles = {
|
|||||||
label: 'Toggle Full Screen',
|
label: 'Toggle Full Screen',
|
||||||
accelerator: isMac ? 'Control+Command+F' : 'F11',
|
accelerator: isMac ? 'Control+Command+F' : 'F11',
|
||||||
windowMethod: (window) => {
|
windowMethod: (window) => {
|
||||||
window.setFullScreen(!window.isFullScreen())
|
window.setFullScreen(!window.isFullScreen());
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
undo: {
|
undo: {
|
||||||
@@ -156,7 +156,7 @@ const roles = {
|
|||||||
accelerator: 'CommandOrControl+Plus',
|
accelerator: 'CommandOrControl+Plus',
|
||||||
nonNativeMacOSRole: true,
|
nonNativeMacOSRole: true,
|
||||||
webContentsMethod: (webContents) => {
|
webContentsMethod: (webContents) => {
|
||||||
webContents.zoomLevel += 0.5
|
webContents.zoomLevel += 0.5;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
zoomout: {
|
zoomout: {
|
||||||
@@ -164,13 +164,13 @@ const roles = {
|
|||||||
accelerator: 'CommandOrControl+-',
|
accelerator: 'CommandOrControl+-',
|
||||||
nonNativeMacOSRole: true,
|
nonNativeMacOSRole: true,
|
||||||
webContentsMethod: (webContents) => {
|
webContentsMethod: (webContents) => {
|
||||||
webContents.zoomLevel -= 0.5
|
webContents.zoomLevel -= 0.5;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
// App submenu should be used for Mac only
|
// App submenu should be used for Mac only
|
||||||
appmenu: {
|
appmenu: {
|
||||||
get label () {
|
get label () {
|
||||||
return app.name
|
return app.name;
|
||||||
},
|
},
|
||||||
submenu: [
|
submenu: [
|
||||||
{ role: 'about' },
|
{ role: 'about' },
|
||||||
@@ -249,71 +249,71 @@ const roles = {
|
|||||||
])
|
])
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
exports.roleList = roles
|
exports.roleList = roles;
|
||||||
|
|
||||||
const canExecuteRole = (role) => {
|
const canExecuteRole = (role) => {
|
||||||
if (!roles.hasOwnProperty(role)) return false
|
if (!roles.hasOwnProperty(role)) return false;
|
||||||
if (!isMac) return true
|
if (!isMac) return true;
|
||||||
|
|
||||||
// macOS handles all roles natively except for a few
|
// macOS handles all roles natively except for a few
|
||||||
return roles[role].nonNativeMacOSRole
|
return roles[role].nonNativeMacOSRole;
|
||||||
}
|
};
|
||||||
|
|
||||||
exports.getDefaultLabel = (role) => {
|
exports.getDefaultLabel = (role) => {
|
||||||
return roles.hasOwnProperty(role) ? roles[role].label : ''
|
return roles.hasOwnProperty(role) ? roles[role].label : '';
|
||||||
}
|
};
|
||||||
|
|
||||||
exports.getDefaultAccelerator = (role) => {
|
exports.getDefaultAccelerator = (role) => {
|
||||||
if (roles.hasOwnProperty(role)) return roles[role].accelerator
|
if (roles.hasOwnProperty(role)) return roles[role].accelerator;
|
||||||
}
|
};
|
||||||
|
|
||||||
exports.shouldRegisterAccelerator = (role) => {
|
exports.shouldRegisterAccelerator = (role) => {
|
||||||
const hasRoleRegister = roles.hasOwnProperty(role) && roles[role].registerAccelerator !== undefined
|
const hasRoleRegister = roles.hasOwnProperty(role) && roles[role].registerAccelerator !== undefined;
|
||||||
return hasRoleRegister ? roles[role].registerAccelerator : true
|
return hasRoleRegister ? roles[role].registerAccelerator : true;
|
||||||
}
|
};
|
||||||
|
|
||||||
exports.getDefaultSubmenu = (role) => {
|
exports.getDefaultSubmenu = (role) => {
|
||||||
if (!roles.hasOwnProperty(role)) return
|
if (!roles.hasOwnProperty(role)) return;
|
||||||
|
|
||||||
let { submenu } = roles[role]
|
let { submenu } = roles[role];
|
||||||
|
|
||||||
// remove null items from within the submenu
|
// remove null items from within the submenu
|
||||||
if (Array.isArray(submenu)) {
|
if (Array.isArray(submenu)) {
|
||||||
submenu = submenu.filter((item) => item != null)
|
submenu = submenu.filter((item) => item != null);
|
||||||
}
|
}
|
||||||
|
|
||||||
return submenu
|
return submenu;
|
||||||
}
|
};
|
||||||
|
|
||||||
exports.execute = (role, focusedWindow, focusedWebContents) => {
|
exports.execute = (role, focusedWindow, focusedWebContents) => {
|
||||||
if (!canExecuteRole(role)) return false
|
if (!canExecuteRole(role)) return false;
|
||||||
|
|
||||||
const { appMethod, webContentsMethod, windowMethod } = roles[role]
|
const { appMethod, webContentsMethod, windowMethod } = roles[role];
|
||||||
|
|
||||||
if (appMethod) {
|
if (appMethod) {
|
||||||
app[appMethod]()
|
app[appMethod]();
|
||||||
return true
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (windowMethod && focusedWindow != null) {
|
if (windowMethod && focusedWindow != null) {
|
||||||
if (typeof windowMethod === 'function') {
|
if (typeof windowMethod === 'function') {
|
||||||
windowMethod(focusedWindow)
|
windowMethod(focusedWindow);
|
||||||
} else {
|
} else {
|
||||||
focusedWindow[windowMethod]()
|
focusedWindow[windowMethod]();
|
||||||
}
|
}
|
||||||
return true
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (webContentsMethod && focusedWebContents != null) {
|
if (webContentsMethod && focusedWebContents != null) {
|
||||||
if (typeof webContentsMethod === 'function') {
|
if (typeof webContentsMethod === 'function') {
|
||||||
webContentsMethod(focusedWebContents)
|
webContentsMethod(focusedWebContents);
|
||||||
} else {
|
} else {
|
||||||
focusedWebContents[webContentsMethod]()
|
focusedWebContents[webContentsMethod]();
|
||||||
}
|
}
|
||||||
return true
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return false
|
return false;
|
||||||
}
|
};
|
||||||
|
|||||||
@@ -1,87 +1,87 @@
|
|||||||
'use strict'
|
'use strict';
|
||||||
|
|
||||||
const roles = require('@electron/internal/browser/api/menu-item-roles')
|
const roles = require('@electron/internal/browser/api/menu-item-roles');
|
||||||
|
|
||||||
let nextCommandId = 0
|
let nextCommandId = 0;
|
||||||
|
|
||||||
const MenuItem = function (options) {
|
const MenuItem = function (options) {
|
||||||
const { Menu } = require('electron')
|
const { Menu } = require('electron');
|
||||||
|
|
||||||
// Preserve extra fields specified by user
|
// Preserve extra fields specified by user
|
||||||
for (const key in options) {
|
for (const key in options) {
|
||||||
if (!(key in this)) this[key] = options[key]
|
if (!(key in this)) this[key] = options[key];
|
||||||
}
|
}
|
||||||
if (typeof this.role === 'string' || this.role instanceof String) {
|
if (typeof this.role === 'string' || this.role instanceof String) {
|
||||||
this.role = this.role.toLowerCase()
|
this.role = this.role.toLowerCase();
|
||||||
}
|
}
|
||||||
this.submenu = this.submenu || roles.getDefaultSubmenu(this.role)
|
this.submenu = this.submenu || roles.getDefaultSubmenu(this.role);
|
||||||
if (this.submenu != null && this.submenu.constructor !== Menu) {
|
if (this.submenu != null && this.submenu.constructor !== Menu) {
|
||||||
this.submenu = Menu.buildFromTemplate(this.submenu)
|
this.submenu = Menu.buildFromTemplate(this.submenu);
|
||||||
}
|
}
|
||||||
if (this.type == null && this.submenu != null) {
|
if (this.type == null && this.submenu != null) {
|
||||||
this.type = 'submenu'
|
this.type = 'submenu';
|
||||||
}
|
}
|
||||||
if (this.type === 'submenu' && (this.submenu == null || this.submenu.constructor !== Menu)) {
|
if (this.type === 'submenu' && (this.submenu == null || this.submenu.constructor !== Menu)) {
|
||||||
throw new Error('Invalid submenu')
|
throw new Error('Invalid submenu');
|
||||||
}
|
}
|
||||||
|
|
||||||
this.overrideReadOnlyProperty('type', 'normal')
|
this.overrideReadOnlyProperty('type', 'normal');
|
||||||
this.overrideReadOnlyProperty('role')
|
this.overrideReadOnlyProperty('role');
|
||||||
this.overrideReadOnlyProperty('accelerator')
|
this.overrideReadOnlyProperty('accelerator');
|
||||||
this.overrideReadOnlyProperty('icon')
|
this.overrideReadOnlyProperty('icon');
|
||||||
this.overrideReadOnlyProperty('submenu')
|
this.overrideReadOnlyProperty('submenu');
|
||||||
|
|
||||||
this.overrideProperty('label', roles.getDefaultLabel(this.role))
|
this.overrideProperty('label', roles.getDefaultLabel(this.role));
|
||||||
this.overrideProperty('sublabel', '')
|
this.overrideProperty('sublabel', '');
|
||||||
this.overrideProperty('toolTip', '')
|
this.overrideProperty('toolTip', '');
|
||||||
this.overrideProperty('enabled', true)
|
this.overrideProperty('enabled', true);
|
||||||
this.overrideProperty('visible', true)
|
this.overrideProperty('visible', true);
|
||||||
this.overrideProperty('checked', false)
|
this.overrideProperty('checked', false);
|
||||||
this.overrideProperty('acceleratorWorksWhenHidden', true)
|
this.overrideProperty('acceleratorWorksWhenHidden', true);
|
||||||
this.overrideProperty('registerAccelerator', roles.shouldRegisterAccelerator(this.role))
|
this.overrideProperty('registerAccelerator', roles.shouldRegisterAccelerator(this.role));
|
||||||
|
|
||||||
if (!MenuItem.types.includes(this.type)) {
|
if (!MenuItem.types.includes(this.type)) {
|
||||||
throw new Error(`Unknown menu item type: ${this.type}`)
|
throw new Error(`Unknown menu item type: ${this.type}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.overrideReadOnlyProperty('commandId', ++nextCommandId)
|
this.overrideReadOnlyProperty('commandId', ++nextCommandId);
|
||||||
|
|
||||||
const click = options.click
|
const click = options.click;
|
||||||
this.click = (event, focusedWindow, focusedWebContents) => {
|
this.click = (event, focusedWindow, focusedWebContents) => {
|
||||||
// Manually flip the checked flags when clicked.
|
// Manually flip the checked flags when clicked.
|
||||||
if (this.type === 'checkbox' || this.type === 'radio') {
|
if (this.type === 'checkbox' || this.type === 'radio') {
|
||||||
this.checked = !this.checked
|
this.checked = !this.checked;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!roles.execute(this.role, focusedWindow, focusedWebContents)) {
|
if (!roles.execute(this.role, focusedWindow, focusedWebContents)) {
|
||||||
if (typeof click === 'function') {
|
if (typeof click === 'function') {
|
||||||
click(this, focusedWindow, event)
|
click(this, focusedWindow, event);
|
||||||
} else if (typeof this.selector === 'string' && process.platform === 'darwin') {
|
} else if (typeof this.selector === 'string' && process.platform === 'darwin') {
|
||||||
Menu.sendActionToFirstResponder(this.selector)
|
Menu.sendActionToFirstResponder(this.selector);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
}
|
};
|
||||||
|
|
||||||
MenuItem.types = ['normal', 'separator', 'submenu', 'checkbox', 'radio']
|
MenuItem.types = ['normal', 'separator', 'submenu', 'checkbox', 'radio'];
|
||||||
|
|
||||||
MenuItem.prototype.getDefaultRoleAccelerator = function () {
|
MenuItem.prototype.getDefaultRoleAccelerator = function () {
|
||||||
return roles.getDefaultAccelerator(this.role)
|
return roles.getDefaultAccelerator(this.role);
|
||||||
}
|
};
|
||||||
|
|
||||||
MenuItem.prototype.overrideProperty = function (name, defaultValue = null) {
|
MenuItem.prototype.overrideProperty = function (name, defaultValue = null) {
|
||||||
if (this[name] == null) {
|
if (this[name] == null) {
|
||||||
this[name] = defaultValue
|
this[name] = defaultValue;
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
MenuItem.prototype.overrideReadOnlyProperty = function (name, defaultValue) {
|
MenuItem.prototype.overrideReadOnlyProperty = function (name, defaultValue) {
|
||||||
this.overrideProperty(name, defaultValue)
|
this.overrideProperty(name, defaultValue);
|
||||||
Object.defineProperty(this, name, {
|
Object.defineProperty(this, name, {
|
||||||
enumerable: true,
|
enumerable: true,
|
||||||
writable: false,
|
writable: false,
|
||||||
value: this[name]
|
value: this[name]
|
||||||
})
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
module.exports = MenuItem
|
module.exports = MenuItem;
|
||||||
|
|||||||
@@ -1,41 +1,41 @@
|
|||||||
'use strict'
|
'use strict';
|
||||||
|
|
||||||
function splitArray (arr, predicate) {
|
function splitArray (arr, predicate) {
|
||||||
const result = arr.reduce((multi, item) => {
|
const result = arr.reduce((multi, item) => {
|
||||||
const current = multi[multi.length - 1]
|
const current = multi[multi.length - 1];
|
||||||
if (predicate(item)) {
|
if (predicate(item)) {
|
||||||
if (current.length > 0) multi.push([])
|
if (current.length > 0) multi.push([]);
|
||||||
} else {
|
} else {
|
||||||
current.push(item)
|
current.push(item);
|
||||||
}
|
}
|
||||||
return multi
|
return multi;
|
||||||
}, [[]])
|
}, [[]]);
|
||||||
|
|
||||||
if (result[result.length - 1].length === 0) {
|
if (result[result.length - 1].length === 0) {
|
||||||
return result.slice(0, result.length - 1)
|
return result.slice(0, result.length - 1);
|
||||||
}
|
}
|
||||||
return result
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
function joinArrays (arrays, joinIDs) {
|
function joinArrays (arrays, joinIDs) {
|
||||||
return arrays.reduce((joined, arr, i) => {
|
return arrays.reduce((joined, arr, i) => {
|
||||||
if (i > 0 && arr.length) {
|
if (i > 0 && arr.length) {
|
||||||
if (joinIDs.length > 0) {
|
if (joinIDs.length > 0) {
|
||||||
joined.push(joinIDs[0])
|
joined.push(joinIDs[0]);
|
||||||
joinIDs.splice(0, 1)
|
joinIDs.splice(0, 1);
|
||||||
} else {
|
} else {
|
||||||
joined.push({ type: 'separator' })
|
joined.push({ type: 'separator' });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return joined.concat(arr)
|
return joined.concat(arr);
|
||||||
}, [])
|
}, []);
|
||||||
}
|
}
|
||||||
|
|
||||||
function pushOntoMultiMap (map, key, value) {
|
function pushOntoMultiMap (map, key, value) {
|
||||||
if (!map.has(key)) {
|
if (!map.has(key)) {
|
||||||
map.set(key, [])
|
map.set(key, []);
|
||||||
}
|
}
|
||||||
map.get(key).push(value)
|
map.get(key).push(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
function indexOfGroupContainingID (groups, id, ignoreGroup) {
|
function indexOfGroupContainingID (groups, id, ignoreGroup) {
|
||||||
@@ -45,102 +45,102 @@ function indexOfGroupContainingID (groups, id, ignoreGroup) {
|
|||||||
candidateGroup.some(
|
candidateGroup.some(
|
||||||
candidateItem => candidateItem.id === id
|
candidateItem => candidateItem.id === id
|
||||||
)
|
)
|
||||||
)
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sort nodes topologically using a depth-first approach. Encountered cycles
|
// Sort nodes topologically using a depth-first approach. Encountered cycles
|
||||||
// are broken.
|
// are broken.
|
||||||
function sortTopologically (originalOrder, edgesById) {
|
function sortTopologically (originalOrder, edgesById) {
|
||||||
const sorted = []
|
const sorted = [];
|
||||||
const marked = new Set()
|
const marked = new Set();
|
||||||
|
|
||||||
const visit = (mark) => {
|
const visit = (mark) => {
|
||||||
if (marked.has(mark)) return
|
if (marked.has(mark)) return;
|
||||||
marked.add(mark)
|
marked.add(mark);
|
||||||
const edges = edgesById.get(mark)
|
const edges = edgesById.get(mark);
|
||||||
if (edges != null) {
|
if (edges != null) {
|
||||||
edges.forEach(visit)
|
edges.forEach(visit);
|
||||||
}
|
}
|
||||||
sorted.push(mark)
|
sorted.push(mark);
|
||||||
}
|
};
|
||||||
|
|
||||||
originalOrder.forEach(visit)
|
originalOrder.forEach(visit);
|
||||||
return sorted
|
return sorted;
|
||||||
}
|
}
|
||||||
|
|
||||||
function attemptToMergeAGroup (groups) {
|
function attemptToMergeAGroup (groups) {
|
||||||
for (let i = 0; i < groups.length; i++) {
|
for (let i = 0; i < groups.length; i++) {
|
||||||
const group = groups[i]
|
const group = groups[i];
|
||||||
for (const item of group) {
|
for (const item of group) {
|
||||||
const toIDs = [...(item.before || []), ...(item.after || [])]
|
const toIDs = [...(item.before || []), ...(item.after || [])];
|
||||||
for (const id of toIDs) {
|
for (const id of toIDs) {
|
||||||
const index = indexOfGroupContainingID(groups, id, group)
|
const index = indexOfGroupContainingID(groups, id, group);
|
||||||
if (index === -1) continue
|
if (index === -1) continue;
|
||||||
const mergeTarget = groups[index]
|
const mergeTarget = groups[index];
|
||||||
|
|
||||||
mergeTarget.push(...group)
|
mergeTarget.push(...group);
|
||||||
groups.splice(i, 1)
|
groups.splice(i, 1);
|
||||||
return true
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
function mergeGroups (groups) {
|
function mergeGroups (groups) {
|
||||||
let merged = true
|
let merged = true;
|
||||||
while (merged) {
|
while (merged) {
|
||||||
merged = attemptToMergeAGroup(groups)
|
merged = attemptToMergeAGroup(groups);
|
||||||
}
|
}
|
||||||
return groups
|
return groups;
|
||||||
}
|
}
|
||||||
|
|
||||||
function sortItemsInGroup (group) {
|
function sortItemsInGroup (group) {
|
||||||
const originalOrder = group.map((node, i) => i)
|
const originalOrder = group.map((node, i) => i);
|
||||||
const edges = new Map()
|
const edges = new Map();
|
||||||
const idToIndex = new Map(group.map((item, i) => [item.id, i]))
|
const idToIndex = new Map(group.map((item, i) => [item.id, i]));
|
||||||
|
|
||||||
group.forEach((item, i) => {
|
group.forEach((item, i) => {
|
||||||
if (item.before) {
|
if (item.before) {
|
||||||
item.before.forEach(toID => {
|
item.before.forEach(toID => {
|
||||||
const to = idToIndex.get(toID)
|
const to = idToIndex.get(toID);
|
||||||
if (to != null) {
|
if (to != null) {
|
||||||
pushOntoMultiMap(edges, to, i)
|
pushOntoMultiMap(edges, to, i);
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
if (item.after) {
|
if (item.after) {
|
||||||
item.after.forEach(toID => {
|
item.after.forEach(toID => {
|
||||||
const to = idToIndex.get(toID)
|
const to = idToIndex.get(toID);
|
||||||
if (to != null) {
|
if (to != null) {
|
||||||
pushOntoMultiMap(edges, i, to)
|
pushOntoMultiMap(edges, i, to);
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
|
|
||||||
const sortedNodes = sortTopologically(originalOrder, edges)
|
const sortedNodes = sortTopologically(originalOrder, edges);
|
||||||
return sortedNodes.map(i => group[i])
|
return sortedNodes.map(i => group[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
function findEdgesInGroup (groups, i, edges) {
|
function findEdgesInGroup (groups, i, edges) {
|
||||||
const group = groups[i]
|
const group = groups[i];
|
||||||
for (const item of group) {
|
for (const item of group) {
|
||||||
if (item.beforeGroupContaining) {
|
if (item.beforeGroupContaining) {
|
||||||
for (const id of item.beforeGroupContaining) {
|
for (const id of item.beforeGroupContaining) {
|
||||||
const to = indexOfGroupContainingID(groups, id, group)
|
const to = indexOfGroupContainingID(groups, id, group);
|
||||||
if (to !== -1) {
|
if (to !== -1) {
|
||||||
pushOntoMultiMap(edges, to, i)
|
pushOntoMultiMap(edges, to, i);
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (item.afterGroupContaining) {
|
if (item.afterGroupContaining) {
|
||||||
for (const id of item.afterGroupContaining) {
|
for (const id of item.afterGroupContaining) {
|
||||||
const to = indexOfGroupContainingID(groups, id, group)
|
const to = indexOfGroupContainingID(groups, id, group);
|
||||||
if (to !== -1) {
|
if (to !== -1) {
|
||||||
pushOntoMultiMap(edges, i, to)
|
pushOntoMultiMap(edges, i, to);
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -148,29 +148,29 @@ function findEdgesInGroup (groups, i, edges) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function sortGroups (groups) {
|
function sortGroups (groups) {
|
||||||
const originalOrder = groups.map((item, i) => i)
|
const originalOrder = groups.map((item, i) => i);
|
||||||
const edges = new Map()
|
const edges = new Map();
|
||||||
|
|
||||||
for (let i = 0; i < groups.length; i++) {
|
for (let i = 0; i < groups.length; i++) {
|
||||||
findEdgesInGroup(groups, i, edges)
|
findEdgesInGroup(groups, i, edges);
|
||||||
}
|
}
|
||||||
|
|
||||||
const sortedGroupIndexes = sortTopologically(originalOrder, edges)
|
const sortedGroupIndexes = sortTopologically(originalOrder, edges);
|
||||||
return sortedGroupIndexes.map(i => groups[i])
|
return sortedGroupIndexes.map(i => groups[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
function sortMenuItems (menuItems) {
|
function sortMenuItems (menuItems) {
|
||||||
const isSeparator = (item) => item.type === 'separator'
|
const isSeparator = (item) => item.type === 'separator';
|
||||||
const separators = menuItems.filter(i => i.type === 'separator')
|
const separators = menuItems.filter(i => i.type === 'separator');
|
||||||
|
|
||||||
// Split the items into their implicit groups based upon separators.
|
// Split the items into their implicit groups based upon separators.
|
||||||
const groups = splitArray(menuItems, isSeparator)
|
const groups = splitArray(menuItems, isSeparator);
|
||||||
const mergedGroups = mergeGroups(groups)
|
const mergedGroups = mergeGroups(groups);
|
||||||
const mergedGroupsWithSortedItems = mergedGroups.map(sortItemsInGroup)
|
const mergedGroupsWithSortedItems = mergedGroups.map(sortItemsInGroup);
|
||||||
const sortedGroups = sortGroups(mergedGroupsWithSortedItems)
|
const sortedGroups = sortGroups(mergedGroupsWithSortedItems);
|
||||||
|
|
||||||
const joined = joinArrays(sortedGroups, separators)
|
const joined = joinArrays(sortedGroups, separators);
|
||||||
return joined
|
return joined;
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = { sortMenuItems }
|
module.exports = { sortMenuItems };
|
||||||
|
|||||||
@@ -1,16 +1,16 @@
|
|||||||
'use strict'
|
'use strict';
|
||||||
|
|
||||||
const { TopLevelWindow, MenuItem, webContents } = require('electron')
|
const { TopLevelWindow, MenuItem, webContents } = require('electron');
|
||||||
const { sortMenuItems } = require('@electron/internal/browser/api/menu-utils')
|
const { sortMenuItems } = require('@electron/internal/browser/api/menu-utils');
|
||||||
const EventEmitter = require('events').EventEmitter
|
const EventEmitter = require('events').EventEmitter;
|
||||||
const v8Util = process.electronBinding('v8_util')
|
const v8Util = process.electronBinding('v8_util');
|
||||||
const bindings = process.electronBinding('menu')
|
const bindings = process.electronBinding('menu');
|
||||||
|
|
||||||
const { Menu } = bindings
|
const { Menu } = bindings;
|
||||||
let applicationMenu = null
|
let applicationMenu = null;
|
||||||
let groupIdIndex = 0
|
let groupIdIndex = 0;
|
||||||
|
|
||||||
Object.setPrototypeOf(Menu.prototype, EventEmitter.prototype)
|
Object.setPrototypeOf(Menu.prototype, EventEmitter.prototype);
|
||||||
|
|
||||||
// Menu Delegate.
|
// Menu Delegate.
|
||||||
// This object should hold no reference to |Menu| to avoid cyclic reference.
|
// This object should hold no reference to |Menu| to avoid cyclic reference.
|
||||||
@@ -20,172 +20,172 @@ const delegate = {
|
|||||||
shouldCommandIdWorkWhenHidden: (menu, id) => menu.commandsMap[id] ? menu.commandsMap[id].acceleratorWorksWhenHidden : undefined,
|
shouldCommandIdWorkWhenHidden: (menu, id) => menu.commandsMap[id] ? menu.commandsMap[id].acceleratorWorksWhenHidden : undefined,
|
||||||
isCommandIdVisible: (menu, id) => menu.commandsMap[id] ? menu.commandsMap[id].visible : undefined,
|
isCommandIdVisible: (menu, id) => menu.commandsMap[id] ? menu.commandsMap[id].visible : undefined,
|
||||||
getAcceleratorForCommandId: (menu, id, useDefaultAccelerator) => {
|
getAcceleratorForCommandId: (menu, id, useDefaultAccelerator) => {
|
||||||
const command = menu.commandsMap[id]
|
const command = menu.commandsMap[id];
|
||||||
if (!command) return
|
if (!command) return;
|
||||||
if (command.accelerator != null) return command.accelerator
|
if (command.accelerator != null) return command.accelerator;
|
||||||
if (useDefaultAccelerator) return command.getDefaultRoleAccelerator()
|
if (useDefaultAccelerator) return command.getDefaultRoleAccelerator();
|
||||||
},
|
},
|
||||||
shouldRegisterAcceleratorForCommandId: (menu, id) => menu.commandsMap[id] ? menu.commandsMap[id].registerAccelerator : undefined,
|
shouldRegisterAcceleratorForCommandId: (menu, id) => menu.commandsMap[id] ? menu.commandsMap[id].registerAccelerator : undefined,
|
||||||
executeCommand: (menu, event, id) => {
|
executeCommand: (menu, event, id) => {
|
||||||
const command = menu.commandsMap[id]
|
const command = menu.commandsMap[id];
|
||||||
if (!command) return
|
if (!command) return;
|
||||||
command.click(event, TopLevelWindow.getFocusedWindow(), webContents.getFocusedWebContents())
|
command.click(event, TopLevelWindow.getFocusedWindow(), webContents.getFocusedWebContents());
|
||||||
},
|
},
|
||||||
menuWillShow: (menu) => {
|
menuWillShow: (menu) => {
|
||||||
// Ensure radio groups have at least one menu item selected
|
// Ensure radio groups have at least one menu item selected
|
||||||
for (const id in menu.groupsMap) {
|
for (const id of Object.keys(menu.groupsMap)) {
|
||||||
const found = menu.groupsMap[id].find(item => item.checked) || null
|
const found = menu.groupsMap[id].find(item => item.checked) || null;
|
||||||
if (!found) v8Util.setHiddenValue(menu.groupsMap[id][0], 'checked', true)
|
if (!found) v8Util.setHiddenValue(menu.groupsMap[id][0], 'checked', true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
/* Instance Methods */
|
/* Instance Methods */
|
||||||
|
|
||||||
Menu.prototype._init = function () {
|
Menu.prototype._init = function () {
|
||||||
this.commandsMap = {}
|
this.commandsMap = {};
|
||||||
this.groupsMap = {}
|
this.groupsMap = {};
|
||||||
this.items = []
|
this.items = [];
|
||||||
this.delegate = delegate
|
this.delegate = delegate;
|
||||||
}
|
};
|
||||||
|
|
||||||
Menu.prototype.popup = function (options = {}) {
|
Menu.prototype.popup = function (options = {}) {
|
||||||
if (options == null || typeof options !== 'object') {
|
if (options == null || typeof options !== 'object') {
|
||||||
throw new TypeError('Options must be an object')
|
throw new TypeError('Options must be an object');
|
||||||
}
|
}
|
||||||
let { window, x, y, positioningItem, callback } = options
|
let { window, x, y, positioningItem, callback } = options;
|
||||||
|
|
||||||
// no callback passed
|
// no callback passed
|
||||||
if (!callback || typeof callback !== 'function') callback = () => {}
|
if (!callback || typeof callback !== 'function') callback = () => {};
|
||||||
|
|
||||||
// set defaults
|
// set defaults
|
||||||
if (typeof x !== 'number') x = -1
|
if (typeof x !== 'number') x = -1;
|
||||||
if (typeof y !== 'number') y = -1
|
if (typeof y !== 'number') y = -1;
|
||||||
if (typeof positioningItem !== 'number') positioningItem = -1
|
if (typeof positioningItem !== 'number') positioningItem = -1;
|
||||||
|
|
||||||
// find which window to use
|
// find which window to use
|
||||||
const wins = TopLevelWindow.getAllWindows()
|
const wins = TopLevelWindow.getAllWindows();
|
||||||
if (!wins || wins.indexOf(window) === -1) {
|
if (!wins || wins.indexOf(window) === -1) {
|
||||||
window = TopLevelWindow.getFocusedWindow()
|
window = TopLevelWindow.getFocusedWindow();
|
||||||
if (!window && wins && wins.length > 0) {
|
if (!window && wins && wins.length > 0) {
|
||||||
window = wins[0]
|
window = wins[0];
|
||||||
}
|
}
|
||||||
if (!window) {
|
if (!window) {
|
||||||
throw new Error(`Cannot open Menu without a TopLevelWindow present`)
|
throw new Error(`Cannot open Menu without a TopLevelWindow present`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this.popupAt(window, x, y, positioningItem, callback)
|
this.popupAt(window, x, y, positioningItem, callback);
|
||||||
return { browserWindow: window, x, y, position: positioningItem }
|
return { browserWindow: window, x, y, position: positioningItem };
|
||||||
}
|
};
|
||||||
|
|
||||||
Menu.prototype.closePopup = function (window) {
|
Menu.prototype.closePopup = function (window) {
|
||||||
if (window instanceof TopLevelWindow) {
|
if (window instanceof TopLevelWindow) {
|
||||||
this.closePopupAt(window.id)
|
this.closePopupAt(window.id);
|
||||||
} else {
|
} else {
|
||||||
// Passing -1 (invalid) would make closePopupAt close the all menu runners
|
// Passing -1 (invalid) would make closePopupAt close the all menu runners
|
||||||
// belong to this menu.
|
// belong to this menu.
|
||||||
this.closePopupAt(-1)
|
this.closePopupAt(-1);
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
Menu.prototype.getMenuItemById = function (id) {
|
Menu.prototype.getMenuItemById = function (id) {
|
||||||
const items = this.items
|
const items = this.items;
|
||||||
|
|
||||||
let found = items.find(item => item.id === id) || null
|
let found = items.find(item => item.id === id) || null;
|
||||||
for (let i = 0; !found && i < items.length; i++) {
|
for (let i = 0; !found && i < items.length; i++) {
|
||||||
if (items[i].submenu) {
|
if (items[i].submenu) {
|
||||||
found = items[i].submenu.getMenuItemById(id)
|
found = items[i].submenu.getMenuItemById(id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return found
|
return found;
|
||||||
}
|
};
|
||||||
|
|
||||||
Menu.prototype.append = function (item) {
|
Menu.prototype.append = function (item) {
|
||||||
return this.insert(this.getItemCount(), item)
|
return this.insert(this.getItemCount(), item);
|
||||||
}
|
};
|
||||||
|
|
||||||
Menu.prototype.insert = function (pos, item) {
|
Menu.prototype.insert = function (pos, item) {
|
||||||
if ((item ? item.constructor : void 0) !== MenuItem) {
|
if ((item ? item.constructor : void 0) !== MenuItem) {
|
||||||
throw new TypeError('Invalid item')
|
throw new TypeError('Invalid item');
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pos < 0) {
|
if (pos < 0) {
|
||||||
throw new RangeError(`Position ${pos} cannot be less than 0`)
|
throw new RangeError(`Position ${pos} cannot be less than 0`);
|
||||||
} else if (pos > this.getItemCount()) {
|
} else if (pos > this.getItemCount()) {
|
||||||
throw new RangeError(`Position ${pos} cannot be greater than the total MenuItem count`)
|
throw new RangeError(`Position ${pos} cannot be greater than the total MenuItem count`);
|
||||||
}
|
}
|
||||||
|
|
||||||
// insert item depending on its type
|
// insert item depending on its type
|
||||||
insertItemByType.call(this, item, pos)
|
insertItemByType.call(this, item, pos);
|
||||||
|
|
||||||
// set item properties
|
// set item properties
|
||||||
if (item.sublabel) this.setSublabel(pos, item.sublabel)
|
if (item.sublabel) this.setSublabel(pos, item.sublabel);
|
||||||
if (item.toolTip) this.setToolTip(pos, item.toolTip)
|
if (item.toolTip) this.setToolTip(pos, item.toolTip);
|
||||||
if (item.icon) this.setIcon(pos, item.icon)
|
if (item.icon) this.setIcon(pos, item.icon);
|
||||||
if (item.role) this.setRole(pos, item.role)
|
if (item.role) this.setRole(pos, item.role);
|
||||||
|
|
||||||
// Make menu accessable to items.
|
// Make menu accessable to items.
|
||||||
item.overrideReadOnlyProperty('menu', this)
|
item.overrideReadOnlyProperty('menu', this);
|
||||||
|
|
||||||
// Remember the items.
|
// Remember the items.
|
||||||
this.items.splice(pos, 0, item)
|
this.items.splice(pos, 0, item);
|
||||||
this.commandsMap[item.commandId] = item
|
this.commandsMap[item.commandId] = item;
|
||||||
}
|
};
|
||||||
|
|
||||||
Menu.prototype._callMenuWillShow = function () {
|
Menu.prototype._callMenuWillShow = function () {
|
||||||
if (this.delegate) this.delegate.menuWillShow(this)
|
if (this.delegate) this.delegate.menuWillShow(this);
|
||||||
this.items.forEach(item => {
|
this.items.forEach(item => {
|
||||||
if (item.submenu) item.submenu._callMenuWillShow()
|
if (item.submenu) item.submenu._callMenuWillShow();
|
||||||
})
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
/* Static Methods */
|
/* Static Methods */
|
||||||
|
|
||||||
Menu.getApplicationMenu = () => applicationMenu
|
Menu.getApplicationMenu = () => applicationMenu;
|
||||||
|
|
||||||
Menu.sendActionToFirstResponder = bindings.sendActionToFirstResponder
|
Menu.sendActionToFirstResponder = bindings.sendActionToFirstResponder;
|
||||||
|
|
||||||
// set application menu with a preexisting menu
|
// set application menu with a preexisting menu
|
||||||
Menu.setApplicationMenu = function (menu) {
|
Menu.setApplicationMenu = function (menu) {
|
||||||
if (menu && menu.constructor !== Menu) {
|
if (menu && menu.constructor !== Menu) {
|
||||||
throw new TypeError('Invalid menu')
|
throw new TypeError('Invalid menu');
|
||||||
}
|
}
|
||||||
|
|
||||||
applicationMenu = menu
|
applicationMenu = menu;
|
||||||
v8Util.setHiddenValue(global, 'applicationMenuSet', true)
|
v8Util.setHiddenValue(global, 'applicationMenuSet', true);
|
||||||
|
|
||||||
if (process.platform === 'darwin') {
|
if (process.platform === 'darwin') {
|
||||||
if (!menu) return
|
if (!menu) return;
|
||||||
menu._callMenuWillShow()
|
menu._callMenuWillShow();
|
||||||
bindings.setApplicationMenu(menu)
|
bindings.setApplicationMenu(menu);
|
||||||
} else {
|
} else {
|
||||||
const windows = TopLevelWindow.getAllWindows()
|
const windows = TopLevelWindow.getAllWindows();
|
||||||
return windows.map(w => w.setMenu(menu))
|
return windows.map(w => w.setMenu(menu));
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
Menu.buildFromTemplate = function (template) {
|
Menu.buildFromTemplate = function (template) {
|
||||||
if (!Array.isArray(template)) {
|
if (!Array.isArray(template)) {
|
||||||
throw new TypeError('Invalid template for Menu: Menu template must be an array')
|
throw new TypeError('Invalid template for Menu: Menu template must be an array');
|
||||||
}
|
}
|
||||||
if (!areValidTemplateItems(template)) {
|
if (!areValidTemplateItems(template)) {
|
||||||
throw new TypeError('Invalid template for MenuItem: must have at least one of label, role or type')
|
throw new TypeError('Invalid template for MenuItem: must have at least one of label, role or type');
|
||||||
}
|
}
|
||||||
const filtered = removeExtraSeparators(template)
|
const filtered = removeExtraSeparators(template);
|
||||||
const sorted = sortTemplate(filtered)
|
const sorted = sortTemplate(filtered);
|
||||||
|
|
||||||
const menu = new Menu()
|
const menu = new Menu();
|
||||||
sorted.forEach(item => {
|
sorted.forEach(item => {
|
||||||
if (item instanceof MenuItem) {
|
if (item instanceof MenuItem) {
|
||||||
menu.append(item)
|
menu.append(item);
|
||||||
} else {
|
} else {
|
||||||
menu.append(new MenuItem(item))
|
menu.append(new MenuItem(item));
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
|
|
||||||
return menu
|
return menu;
|
||||||
}
|
};
|
||||||
|
|
||||||
/* Helper Functions */
|
/* Helper Functions */
|
||||||
|
|
||||||
@@ -196,51 +196,50 @@ function areValidTemplateItems (template) {
|
|||||||
typeof item === 'object' &&
|
typeof item === 'object' &&
|
||||||
(item.hasOwnProperty('label') ||
|
(item.hasOwnProperty('label') ||
|
||||||
item.hasOwnProperty('role') ||
|
item.hasOwnProperty('role') ||
|
||||||
item.type === 'separator'))
|
item.type === 'separator'));
|
||||||
}
|
}
|
||||||
|
|
||||||
function sortTemplate (template) {
|
function sortTemplate (template) {
|
||||||
const sorted = sortMenuItems(template)
|
const sorted = sortMenuItems(template);
|
||||||
for (const id in sorted) {
|
for (const item of sorted) {
|
||||||
const item = sorted[id]
|
|
||||||
if (Array.isArray(item.submenu)) {
|
if (Array.isArray(item.submenu)) {
|
||||||
item.submenu = sortTemplate(item.submenu)
|
item.submenu = sortTemplate(item.submenu);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return sorted
|
return sorted;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Search between separators to find a radio menu item and return its group id
|
// Search between separators to find a radio menu item and return its group id
|
||||||
function generateGroupId (items, pos) {
|
function generateGroupId (items, pos) {
|
||||||
if (pos > 0) {
|
if (pos > 0) {
|
||||||
for (let idx = pos - 1; idx >= 0; idx--) {
|
for (let idx = pos - 1; idx >= 0; idx--) {
|
||||||
if (items[idx].type === 'radio') return items[idx].groupId
|
if (items[idx].type === 'radio') return items[idx].groupId;
|
||||||
if (items[idx].type === 'separator') break
|
if (items[idx].type === 'separator') break;
|
||||||
}
|
}
|
||||||
} else if (pos < items.length) {
|
} else if (pos < items.length) {
|
||||||
for (let idx = pos; idx <= items.length - 1; idx++) {
|
for (let idx = pos; idx <= items.length - 1; idx++) {
|
||||||
if (items[idx].type === 'radio') return items[idx].groupId
|
if (items[idx].type === 'radio') return items[idx].groupId;
|
||||||
if (items[idx].type === 'separator') break
|
if (items[idx].type === 'separator') break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
groupIdIndex += 1
|
groupIdIndex += 1;
|
||||||
return groupIdIndex
|
return groupIdIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
function removeExtraSeparators (items) {
|
function removeExtraSeparators (items) {
|
||||||
// fold adjacent separators together
|
// fold adjacent separators together
|
||||||
let ret = items.filter((e, idx, arr) => {
|
let ret = items.filter((e, idx, arr) => {
|
||||||
if (e.visible === false) return true
|
if (e.visible === false) return true;
|
||||||
return e.type !== 'separator' || idx === 0 || arr[idx - 1].type !== 'separator'
|
return e.type !== 'separator' || idx === 0 || arr[idx - 1].type !== 'separator';
|
||||||
})
|
});
|
||||||
|
|
||||||
// remove edge separators
|
// remove edge separators
|
||||||
ret = ret.filter((e, idx, arr) => {
|
ret = ret.filter((e, idx, arr) => {
|
||||||
if (e.visible === false) return true
|
if (e.visible === false) return true;
|
||||||
return e.type !== 'separator' || (idx !== 0 && idx !== arr.length - 1)
|
return e.type !== 'separator' || (idx !== 0 && idx !== arr.length - 1);
|
||||||
})
|
});
|
||||||
|
|
||||||
return ret
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
function insertItemByType (item, pos) {
|
function insertItemByType (item, pos) {
|
||||||
@@ -251,28 +250,28 @@ function insertItemByType (item, pos) {
|
|||||||
submenu: () => this.insertSubMenu(pos, item.commandId, item.label, item.submenu),
|
submenu: () => this.insertSubMenu(pos, item.commandId, item.label, item.submenu),
|
||||||
radio: () => {
|
radio: () => {
|
||||||
// Grouping radio menu items
|
// Grouping radio menu items
|
||||||
item.overrideReadOnlyProperty('groupId', generateGroupId(this.items, pos))
|
item.overrideReadOnlyProperty('groupId', generateGroupId(this.items, pos));
|
||||||
if (this.groupsMap[item.groupId] == null) {
|
if (this.groupsMap[item.groupId] == null) {
|
||||||
this.groupsMap[item.groupId] = []
|
this.groupsMap[item.groupId] = [];
|
||||||
}
|
}
|
||||||
this.groupsMap[item.groupId].push(item)
|
this.groupsMap[item.groupId].push(item);
|
||||||
|
|
||||||
// Setting a radio menu item should flip other items in the group.
|
// Setting a radio menu item should flip other items in the group.
|
||||||
v8Util.setHiddenValue(item, 'checked', item.checked)
|
v8Util.setHiddenValue(item, 'checked', item.checked);
|
||||||
Object.defineProperty(item, 'checked', {
|
Object.defineProperty(item, 'checked', {
|
||||||
enumerable: true,
|
enumerable: true,
|
||||||
get: () => v8Util.getHiddenValue(item, 'checked'),
|
get: () => v8Util.getHiddenValue(item, 'checked'),
|
||||||
set: () => {
|
set: () => {
|
||||||
this.groupsMap[item.groupId].forEach(other => {
|
this.groupsMap[item.groupId].forEach(other => {
|
||||||
if (other !== item) v8Util.setHiddenValue(other, 'checked', false)
|
if (other !== item) v8Util.setHiddenValue(other, 'checked', false);
|
||||||
})
|
});
|
||||||
v8Util.setHiddenValue(item, 'checked', true)
|
v8Util.setHiddenValue(item, 'checked', true);
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
this.insertRadioItem(pos, item.commandId, item.label, item.groupId)
|
this.insertRadioItem(pos, item.commandId, item.label, item.groupId);
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
types[item.type]()
|
types[item.type]();
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = Menu
|
module.exports = Menu;
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
'use strict'
|
'use strict';
|
||||||
|
|
||||||
// TODO: Figure out a way to not duplicate this information between here and module-list
|
// TODO: Figure out a way to not duplicate this information between here and module-list
|
||||||
// It is currently duplicated as module-list "require"s all the browser API file and the
|
// It is currently duplicated as module-list "require"s all the browser API file and the
|
||||||
// remote module in the renderer process depends on that file. As a result webpack
|
// remote module in the renderer process depends on that file. As a result webpack
|
||||||
// includes all the browser API files in the renderer process as well and we want to avoid that
|
// includes all the browser API files in the renderer process as well and we want to avoid that
|
||||||
|
|
||||||
const features = process.electronBinding('features')
|
const features = process.electronBinding('features');
|
||||||
|
|
||||||
// Browser side modules, please sort alphabetically.
|
// Browser side modules, please sort alphabetically.
|
||||||
module.exports = [
|
module.exports = [
|
||||||
@@ -21,6 +21,7 @@ module.exports = [
|
|||||||
{ name: 'inAppPurchase' },
|
{ name: 'inAppPurchase' },
|
||||||
{ name: 'Menu' },
|
{ name: 'Menu' },
|
||||||
{ name: 'MenuItem' },
|
{ name: 'MenuItem' },
|
||||||
|
{ name: 'nativeTheme' },
|
||||||
{ name: 'net' },
|
{ name: 'net' },
|
||||||
{ name: 'netLog' },
|
{ name: 'netLog' },
|
||||||
{ name: 'Notification' },
|
{ name: 'Notification' },
|
||||||
@@ -36,7 +37,7 @@ module.exports = [
|
|||||||
{ name: 'View' },
|
{ name: 'View' },
|
||||||
{ name: 'webContents' },
|
{ name: 'webContents' },
|
||||||
{ name: 'WebContentsView' }
|
{ name: 'WebContentsView' }
|
||||||
]
|
];
|
||||||
|
|
||||||
if (features.isViewApiEnabled()) {
|
if (features.isViewApiEnabled()) {
|
||||||
module.exports.push(
|
module.exports.push(
|
||||||
@@ -47,5 +48,5 @@ if (features.isViewApiEnabled()) {
|
|||||||
{ name: 'MdTextButton' },
|
{ name: 'MdTextButton' },
|
||||||
{ name: 'ResizeArea' },
|
{ name: 'ResizeArea' },
|
||||||
{ name: 'TextField' }
|
{ name: 'TextField' }
|
||||||
)
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
// TODO: Updating this file also required updating the module-keys file
|
// TODO: Updating this file also required updating the module-keys file
|
||||||
|
|
||||||
const features = process.electronBinding('features')
|
const features = process.electronBinding('features');
|
||||||
|
|
||||||
// Browser side modules, please sort alphabetically.
|
// Browser side modules, please sort alphabetically.
|
||||||
export const browserModuleList: ElectronInternal.ModuleEntry[] = [
|
export const browserModuleList: ElectronInternal.ModuleEntry[] = [
|
||||||
@@ -32,7 +32,7 @@ export const browserModuleList: ElectronInternal.ModuleEntry[] = [
|
|||||||
{ name: 'View', loader: () => require('./view') },
|
{ name: 'View', loader: () => require('./view') },
|
||||||
{ name: 'webContents', loader: () => require('./web-contents') },
|
{ name: 'webContents', loader: () => require('./web-contents') },
|
||||||
{ name: 'WebContentsView', loader: () => require('./web-contents-view') }
|
{ name: 'WebContentsView', loader: () => require('./web-contents-view') }
|
||||||
]
|
];
|
||||||
|
|
||||||
if (features.isViewApiEnabled()) {
|
if (features.isViewApiEnabled()) {
|
||||||
browserModuleList.push(
|
browserModuleList.push(
|
||||||
@@ -43,5 +43,5 @@ if (features.isViewApiEnabled()) {
|
|||||||
{ name: 'MdTextButton', loader: () => require('./views/md-text-button') },
|
{ name: 'MdTextButton', loader: () => require('./views/md-text-button') },
|
||||||
{ name: 'ResizeArea', loader: () => require('./views/resize-area') },
|
{ name: 'ResizeArea', loader: () => require('./views/resize-area') },
|
||||||
{ name: 'TextField', loader: () => require('./views/text-field') }
|
{ name: 'TextField', loader: () => require('./views/text-field') }
|
||||||
)
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
import { EventEmitter } from 'events'
|
import { EventEmitter } from 'events';
|
||||||
|
|
||||||
const { NativeTheme, nativeTheme } = process.electronBinding('native_theme')
|
const { NativeTheme, nativeTheme } = process.electronBinding('native_theme');
|
||||||
|
|
||||||
Object.setPrototypeOf(NativeTheme.prototype, EventEmitter.prototype)
|
Object.setPrototypeOf(NativeTheme.prototype, EventEmitter.prototype);
|
||||||
EventEmitter.call(nativeTheme as any)
|
EventEmitter.call(nativeTheme as any);
|
||||||
|
|
||||||
module.exports = nativeTheme
|
module.exports = nativeTheme;
|
||||||
|
|||||||
@@ -1,32 +1,32 @@
|
|||||||
'use strict'
|
'use strict';
|
||||||
|
|
||||||
// TODO(deepak1556): Deprecate and remove standalone netLog module,
|
// TODO(deepak1556): Deprecate and remove standalone netLog module,
|
||||||
// it is now a property of session module.
|
// it is now a property of session module.
|
||||||
const { app, session } = require('electron')
|
const { app, session } = require('electron');
|
||||||
|
|
||||||
// Fallback to default session.
|
// Fallback to default session.
|
||||||
Object.setPrototypeOf(module.exports, new Proxy({}, {
|
Object.setPrototypeOf(module.exports, new Proxy({}, {
|
||||||
get (target, property) {
|
get (target, property) {
|
||||||
if (!app.isReady()) return
|
if (!app.isReady()) return;
|
||||||
|
|
||||||
const netLog = session.defaultSession.netLog
|
const netLog = session.defaultSession.netLog;
|
||||||
|
|
||||||
if (!Object.getPrototypeOf(netLog).hasOwnProperty(property)) return
|
if (!Object.getPrototypeOf(netLog).hasOwnProperty(property)) return;
|
||||||
|
|
||||||
// check for properties on the prototype chain that aren't functions
|
// check for properties on the prototype chain that aren't functions
|
||||||
if (typeof netLog[property] !== 'function') return netLog[property]
|
if (typeof netLog[property] !== 'function') return netLog[property];
|
||||||
|
|
||||||
// Returning a native function directly would throw error.
|
// Returning a native function directly would throw error.
|
||||||
return (...args) => netLog[property](...args)
|
return (...args) => netLog[property](...args);
|
||||||
},
|
},
|
||||||
|
|
||||||
ownKeys () {
|
ownKeys () {
|
||||||
if (!app.isReady()) return []
|
if (!app.isReady()) return [];
|
||||||
|
|
||||||
return Object.getOwnPropertyNames(Object.getPrototypeOf(session.defaultSession.netLog))
|
return Object.getOwnPropertyNames(Object.getPrototypeOf(session.defaultSession.netLog));
|
||||||
},
|
},
|
||||||
|
|
||||||
getOwnPropertyDescriptor (target) {
|
getOwnPropertyDescriptor (target) {
|
||||||
return { configurable: true, enumerable: true }
|
return { configurable: true, enumerable: true };
|
||||||
}
|
}
|
||||||
}))
|
}));
|
||||||
|
|||||||
@@ -1,20 +1,16 @@
|
|||||||
'use strict'
|
'use strict';
|
||||||
|
|
||||||
const url = require('url')
|
const url = require('url');
|
||||||
const { EventEmitter } = require('events')
|
const { EventEmitter } = require('events');
|
||||||
const { Readable } = require('stream')
|
const { Readable, Writable } = require('stream');
|
||||||
const { app } = require('electron')
|
const { app } = require('electron');
|
||||||
const { Session } = process.electronBinding('session')
|
const { Session } = process.electronBinding('session');
|
||||||
const { net, Net } = process.electronBinding('net')
|
const { net, Net, _isValidHeaderName, _isValidHeaderValue } = process.electronBinding('net');
|
||||||
const { URLRequest } = net
|
const { URLLoader } = net;
|
||||||
|
|
||||||
// Net is an EventEmitter.
|
Object.setPrototypeOf(URLLoader.prototype, EventEmitter.prototype);
|
||||||
Object.setPrototypeOf(Net.prototype, EventEmitter.prototype)
|
|
||||||
EventEmitter.call(net)
|
|
||||||
|
|
||||||
Object.setPrototypeOf(URLRequest.prototype, EventEmitter.prototype)
|
const kSupportedProtocols = new Set(['http:', 'https:']);
|
||||||
|
|
||||||
const kSupportedProtocols = new Set(['http:', 'https:'])
|
|
||||||
|
|
||||||
// set of headers that Node.js discards duplicates for
|
// set of headers that Node.js discards duplicates for
|
||||||
// see https://nodejs.org/api/http.html#http_message_headers
|
// see https://nodejs.org/api/http.html#http_message_headers
|
||||||
@@ -37,375 +33,445 @@ const discardableDuplicateHeaders = new Set([
|
|||||||
'server',
|
'server',
|
||||||
'age',
|
'age',
|
||||||
'expires'
|
'expires'
|
||||||
])
|
]);
|
||||||
|
|
||||||
class IncomingMessage extends Readable {
|
class IncomingMessage extends Readable {
|
||||||
constructor (urlRequest) {
|
constructor (responseHead) {
|
||||||
super()
|
super();
|
||||||
this.urlRequest = urlRequest
|
this._shouldPush = false;
|
||||||
this.shouldPush = false
|
this._data = [];
|
||||||
this.data = []
|
this._responseHead = responseHead;
|
||||||
this.urlRequest.on('data', (event, chunk) => {
|
|
||||||
this._storeInternalData(chunk)
|
|
||||||
this._pushInternalData()
|
|
||||||
})
|
|
||||||
this.urlRequest.on('end', () => {
|
|
||||||
this._storeInternalData(null)
|
|
||||||
this._pushInternalData()
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
get statusCode () {
|
get statusCode () {
|
||||||
return this.urlRequest.statusCode
|
return this._responseHead.statusCode;
|
||||||
}
|
}
|
||||||
|
|
||||||
get statusMessage () {
|
get statusMessage () {
|
||||||
return this.urlRequest.statusMessage
|
return this._responseHead.statusMessage;
|
||||||
}
|
}
|
||||||
|
|
||||||
get headers () {
|
get headers () {
|
||||||
const filteredHeaders = {}
|
const filteredHeaders = {};
|
||||||
const rawHeaders = this.urlRequest.rawResponseHeaders
|
const { rawHeaders } = this._responseHead;
|
||||||
Object.keys(rawHeaders).forEach(header => {
|
rawHeaders.forEach(header => {
|
||||||
if (header in filteredHeaders && discardableDuplicateHeaders.has(header)) {
|
if (Object.prototype.hasOwnProperty.call(filteredHeaders, header.key) &&
|
||||||
|
discardableDuplicateHeaders.has(header.key)) {
|
||||||
// do nothing with discardable duplicate headers
|
// do nothing with discardable duplicate headers
|
||||||
} else {
|
} else {
|
||||||
if (header === 'set-cookie') {
|
if (header.key === 'set-cookie') {
|
||||||
// keep set-cookie as an array per Node.js rules
|
// keep set-cookie as an array per Node.js rules
|
||||||
// see https://nodejs.org/api/http.html#http_message_headers
|
// see https://nodejs.org/api/http.html#http_message_headers
|
||||||
filteredHeaders[header] = rawHeaders[header]
|
if (Object.prototype.hasOwnProperty.call(filteredHeaders, header.key)) {
|
||||||
|
filteredHeaders[header.key].push(header.value);
|
||||||
|
} else {
|
||||||
|
filteredHeaders[header.key] = [header.value];
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
// for non-cookie headers, the values are joined together with ', '
|
// for non-cookie headers, the values are joined together with ', '
|
||||||
filteredHeaders[header] = rawHeaders[header].join(', ')
|
if (Object.prototype.hasOwnProperty.call(filteredHeaders, header.key)) {
|
||||||
|
filteredHeaders[header.key] += `, ${header.value}`;
|
||||||
|
} else {
|
||||||
|
filteredHeaders[header.key] = header.value;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
return filteredHeaders
|
return filteredHeaders;
|
||||||
}
|
}
|
||||||
|
|
||||||
get httpVersion () {
|
get httpVersion () {
|
||||||
return `${this.httpVersionMajor}.${this.httpVersionMinor}`
|
return `${this.httpVersionMajor}.${this.httpVersionMinor}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
get httpVersionMajor () {
|
get httpVersionMajor () {
|
||||||
return this.urlRequest.httpVersionMajor
|
return this._responseHead.httpVersion.major;
|
||||||
}
|
}
|
||||||
|
|
||||||
get httpVersionMinor () {
|
get httpVersionMinor () {
|
||||||
return this.urlRequest.httpVersionMinor
|
return this._responseHead.httpVersion.minor;
|
||||||
}
|
}
|
||||||
|
|
||||||
get rawTrailers () {
|
get rawTrailers () {
|
||||||
throw new Error('HTTP trailers are not supported')
|
throw new Error('HTTP trailers are not supported');
|
||||||
}
|
}
|
||||||
|
|
||||||
get trailers () {
|
get trailers () {
|
||||||
throw new Error('HTTP trailers are not supported')
|
throw new Error('HTTP trailers are not supported');
|
||||||
}
|
}
|
||||||
|
|
||||||
_storeInternalData (chunk) {
|
_storeInternalData (chunk) {
|
||||||
this.data.push(chunk)
|
this._data.push(chunk);
|
||||||
|
this._pushInternalData();
|
||||||
}
|
}
|
||||||
|
|
||||||
_pushInternalData () {
|
_pushInternalData () {
|
||||||
while (this.shouldPush && this.data.length > 0) {
|
while (this._shouldPush && this._data.length > 0) {
|
||||||
const chunk = this.data.shift()
|
const chunk = this._data.shift();
|
||||||
this.shouldPush = this.push(chunk)
|
this._shouldPush = this.push(chunk);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_read () {
|
_read () {
|
||||||
this.shouldPush = true
|
this._shouldPush = true;
|
||||||
this._pushInternalData()
|
this._pushInternalData();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
URLRequest.prototype._emitRequestEvent = function (isAsync, ...rest) {
|
/** Writable stream that buffers up everything written to it. */
|
||||||
if (isAsync) {
|
class SlurpStream extends Writable {
|
||||||
process.nextTick(() => {
|
constructor () {
|
||||||
this.clientRequest.emit(...rest)
|
super();
|
||||||
})
|
this._data = Buffer.alloc(0);
|
||||||
|
}
|
||||||
|
_write (chunk, encoding, callback) {
|
||||||
|
this._data = Buffer.concat([this._data, chunk]);
|
||||||
|
callback();
|
||||||
|
}
|
||||||
|
data () { return this._data; }
|
||||||
|
}
|
||||||
|
|
||||||
|
class ChunkedBodyStream extends Writable {
|
||||||
|
constructor (clientRequest) {
|
||||||
|
super();
|
||||||
|
this._clientRequest = clientRequest;
|
||||||
|
}
|
||||||
|
|
||||||
|
_write (chunk, encoding, callback) {
|
||||||
|
if (this._downstream) {
|
||||||
|
this._downstream.write(chunk).then(callback, callback);
|
||||||
|
} else {
|
||||||
|
// the contract of _write is that we won't be called again until we call
|
||||||
|
// the callback, so we're good to just save a single chunk.
|
||||||
|
this._pendingChunk = chunk;
|
||||||
|
this._pendingCallback = callback;
|
||||||
|
|
||||||
|
// The first write to a chunked body stream begins the request.
|
||||||
|
this._clientRequest._startRequest();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_final (callback) {
|
||||||
|
this._downstream.done();
|
||||||
|
callback();
|
||||||
|
}
|
||||||
|
|
||||||
|
startReading (pipe) {
|
||||||
|
if (this._downstream) {
|
||||||
|
throw new Error('two startReading calls???');
|
||||||
|
}
|
||||||
|
this._downstream = pipe;
|
||||||
|
if (this._pendingChunk) {
|
||||||
|
const doneWriting = (maybeError) => {
|
||||||
|
const cb = this._pendingCallback;
|
||||||
|
delete this._pendingCallback;
|
||||||
|
delete this._pendingChunk;
|
||||||
|
cb(maybeError);
|
||||||
|
};
|
||||||
|
this._downstream.write(this._pendingChunk).then(doneWriting, doneWriting);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function parseOptions (options) {
|
||||||
|
if (typeof options === 'string') {
|
||||||
|
options = url.parse(options);
|
||||||
} else {
|
} else {
|
||||||
this.clientRequest.emit(...rest)
|
options = { ...options };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const method = (options.method || 'GET').toUpperCase();
|
||||||
|
let urlStr = options.url;
|
||||||
|
|
||||||
|
if (!urlStr) {
|
||||||
|
const urlObj = {};
|
||||||
|
const protocol = options.protocol || 'http:';
|
||||||
|
if (!kSupportedProtocols.has(protocol)) {
|
||||||
|
throw new Error('Protocol "' + protocol + '" not supported');
|
||||||
|
}
|
||||||
|
urlObj.protocol = protocol;
|
||||||
|
|
||||||
|
if (options.host) {
|
||||||
|
urlObj.host = options.host;
|
||||||
|
} else {
|
||||||
|
if (options.hostname) {
|
||||||
|
urlObj.hostname = options.hostname;
|
||||||
|
} else {
|
||||||
|
urlObj.hostname = 'localhost';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (options.port) {
|
||||||
|
urlObj.port = options.port;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (options.path && / /.test(options.path)) {
|
||||||
|
// The actual regex is more like /[^A-Za-z0-9\-._~!$&'()*+,;=/:@]/
|
||||||
|
// with an additional rule for ignoring percentage-escaped characters
|
||||||
|
// but that's a) hard to capture in a regular expression that performs
|
||||||
|
// well, and b) possibly too restrictive for real-world usage. That's
|
||||||
|
// why it only scans for spaces because those are guaranteed to create
|
||||||
|
// an invalid request.
|
||||||
|
throw new TypeError('Request path contains unescaped characters');
|
||||||
|
}
|
||||||
|
const pathObj = url.parse(options.path || '/');
|
||||||
|
urlObj.pathname = pathObj.pathname;
|
||||||
|
urlObj.search = pathObj.search;
|
||||||
|
urlObj.hash = pathObj.hash;
|
||||||
|
urlStr = url.format(urlObj);
|
||||||
|
}
|
||||||
|
|
||||||
|
const redirectPolicy = options.redirect || 'follow';
|
||||||
|
if (!['follow', 'error', 'manual'].includes(redirectPolicy)) {
|
||||||
|
throw new Error('redirect mode should be one of follow, error or manual');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (options.headers != null && typeof options.headers !== 'object') {
|
||||||
|
throw new TypeError('headers must be an object');
|
||||||
|
}
|
||||||
|
|
||||||
|
const urlLoaderOptions = {
|
||||||
|
method: method,
|
||||||
|
url: urlStr,
|
||||||
|
redirectPolicy,
|
||||||
|
extraHeaders: options.headers || {},
|
||||||
|
useSessionCookies: options.useSessionCookies || false
|
||||||
|
};
|
||||||
|
for (const [name, value] of Object.entries(urlLoaderOptions.extraHeaders)) {
|
||||||
|
if (!_isValidHeaderName(name)) {
|
||||||
|
throw new Error(`Invalid header name: '${name}'`);
|
||||||
|
}
|
||||||
|
if (!_isValidHeaderValue(value.toString())) {
|
||||||
|
throw new Error(`Invalid value for header '${name}': '${value}'`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (options.session) {
|
||||||
|
if (options.session instanceof Session) {
|
||||||
|
urlLoaderOptions.session = options.session;
|
||||||
|
} else {
|
||||||
|
throw new TypeError('`session` should be an instance of the Session class');
|
||||||
|
}
|
||||||
|
} else if (options.partition) {
|
||||||
|
if (typeof options.partition === 'string') {
|
||||||
|
urlLoaderOptions.partition = options.partition;
|
||||||
|
} else {
|
||||||
|
throw new TypeError('`partition` should be a string');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return urlLoaderOptions;
|
||||||
}
|
}
|
||||||
|
|
||||||
URLRequest.prototype._emitResponseEvent = function (isAsync, ...rest) {
|
class ClientRequest extends Writable {
|
||||||
if (isAsync) {
|
|
||||||
process.nextTick(() => {
|
|
||||||
this._response.emit(...rest)
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
this._response.emit(...rest)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class ClientRequest extends EventEmitter {
|
|
||||||
constructor (options, callback) {
|
constructor (options, callback) {
|
||||||
super()
|
super({ autoDestroy: true });
|
||||||
|
|
||||||
if (!app.isReady()) {
|
if (!app.isReady()) {
|
||||||
throw new Error('net module can only be used after app is ready')
|
throw new Error('net module can only be used after app is ready');
|
||||||
}
|
}
|
||||||
|
|
||||||
if (typeof options === 'string') {
|
|
||||||
options = url.parse(options)
|
|
||||||
} else {
|
|
||||||
options = Object.assign({}, options)
|
|
||||||
}
|
|
||||||
|
|
||||||
const method = (options.method || 'GET').toUpperCase()
|
|
||||||
let urlStr = options.url
|
|
||||||
|
|
||||||
if (!urlStr) {
|
|
||||||
const urlObj = {}
|
|
||||||
const protocol = options.protocol || 'http:'
|
|
||||||
if (!kSupportedProtocols.has(protocol)) {
|
|
||||||
throw new Error('Protocol "' + protocol + '" not supported')
|
|
||||||
}
|
|
||||||
urlObj.protocol = protocol
|
|
||||||
|
|
||||||
if (options.host) {
|
|
||||||
urlObj.host = options.host
|
|
||||||
} else {
|
|
||||||
if (options.hostname) {
|
|
||||||
urlObj.hostname = options.hostname
|
|
||||||
} else {
|
|
||||||
urlObj.hostname = 'localhost'
|
|
||||||
}
|
|
||||||
|
|
||||||
if (options.port) {
|
|
||||||
urlObj.port = options.port
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (options.path && / /.test(options.path)) {
|
|
||||||
// The actual regex is more like /[^A-Za-z0-9\-._~!$&'()*+,;=/:@]/
|
|
||||||
// with an additional rule for ignoring percentage-escaped characters
|
|
||||||
// but that's a) hard to capture in a regular expression that performs
|
|
||||||
// well, and b) possibly too restrictive for real-world usage. That's
|
|
||||||
// why it only scans for spaces because those are guaranteed to create
|
|
||||||
// an invalid request.
|
|
||||||
throw new TypeError('Request path contains unescaped characters')
|
|
||||||
}
|
|
||||||
const pathObj = url.parse(options.path || '/')
|
|
||||||
urlObj.pathname = pathObj.pathname
|
|
||||||
urlObj.search = pathObj.search
|
|
||||||
urlObj.hash = pathObj.hash
|
|
||||||
urlStr = url.format(urlObj)
|
|
||||||
}
|
|
||||||
|
|
||||||
const redirectPolicy = options.redirect || 'follow'
|
|
||||||
if (!['follow', 'error', 'manual'].includes(redirectPolicy)) {
|
|
||||||
throw new Error('redirect mode should be one of follow, error or manual')
|
|
||||||
}
|
|
||||||
|
|
||||||
const urlRequestOptions = {
|
|
||||||
method: method,
|
|
||||||
url: urlStr,
|
|
||||||
redirect: redirectPolicy
|
|
||||||
}
|
|
||||||
if (options.session) {
|
|
||||||
if (options.session instanceof Session) {
|
|
||||||
urlRequestOptions.session = options.session
|
|
||||||
} else {
|
|
||||||
throw new TypeError('`session` should be an instance of the Session class')
|
|
||||||
}
|
|
||||||
} else if (options.partition) {
|
|
||||||
if (typeof options.partition === 'string') {
|
|
||||||
urlRequestOptions.partition = options.partition
|
|
||||||
} else {
|
|
||||||
throw new TypeError('`partition` should be a string')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const urlRequest = new URLRequest(urlRequestOptions)
|
|
||||||
|
|
||||||
// Set back and forward links.
|
|
||||||
this.urlRequest = urlRequest
|
|
||||||
urlRequest.clientRequest = this
|
|
||||||
|
|
||||||
// This is a copy of the extra headers structure held by the native
|
|
||||||
// net::URLRequest. The main reason is to keep the getHeader API synchronous
|
|
||||||
// after the request starts.
|
|
||||||
this.extraHeaders = {}
|
|
||||||
|
|
||||||
if (options.headers) {
|
|
||||||
for (const key in options.headers) {
|
|
||||||
this.setHeader(key, options.headers[key])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set when the request uses chunked encoding. Can be switched
|
|
||||||
// to true only once and never set back to false.
|
|
||||||
this.chunkedEncodingEnabled = false
|
|
||||||
|
|
||||||
urlRequest.on('response', () => {
|
|
||||||
const response = new IncomingMessage(urlRequest)
|
|
||||||
urlRequest._response = response
|
|
||||||
this.emit('response', response)
|
|
||||||
})
|
|
||||||
|
|
||||||
urlRequest.on('login', (event, authInfo, callback) => {
|
|
||||||
this.emit('login', authInfo, (username, password) => {
|
|
||||||
// If null or undefined username/password, force to empty string.
|
|
||||||
if (username === null || username === undefined) {
|
|
||||||
username = ''
|
|
||||||
}
|
|
||||||
if (typeof username !== 'string') {
|
|
||||||
throw new Error('username must be a string')
|
|
||||||
}
|
|
||||||
if (password === null || password === undefined) {
|
|
||||||
password = ''
|
|
||||||
}
|
|
||||||
if (typeof password !== 'string') {
|
|
||||||
throw new Error('password must be a string')
|
|
||||||
}
|
|
||||||
callback(username, password)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
if (callback) {
|
if (callback) {
|
||||||
this.once('response', callback)
|
this.once('response', callback);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
get chunkedEncoding () {
|
const { redirectPolicy, ...urlLoaderOptions } = parseOptions(options);
|
||||||
return this.chunkedEncodingEnabled
|
this._urlLoaderOptions = urlLoaderOptions;
|
||||||
|
this._redirectPolicy = redirectPolicy;
|
||||||
|
this._started = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
set chunkedEncoding (value) {
|
set chunkedEncoding (value) {
|
||||||
if (!this.urlRequest.notStarted) {
|
if (this._started) {
|
||||||
throw new Error('Can\'t set the transfer encoding, headers have been sent')
|
throw new Error('chunkedEncoding can only be set before the request is started');
|
||||||
|
}
|
||||||
|
if (typeof this._chunkedEncoding !== 'undefined') {
|
||||||
|
throw new Error('chunkedEncoding can only be set once');
|
||||||
|
}
|
||||||
|
this._chunkedEncoding = !!value;
|
||||||
|
if (this._chunkedEncoding) {
|
||||||
|
this._body = new ChunkedBodyStream(this);
|
||||||
|
this._urlLoaderOptions.body = (pipe) => {
|
||||||
|
this._body.startReading(pipe);
|
||||||
|
};
|
||||||
}
|
}
|
||||||
this.chunkedEncodingEnabled = value
|
|
||||||
}
|
}
|
||||||
|
|
||||||
setHeader (name, value) {
|
setHeader (name, value) {
|
||||||
if (typeof name !== 'string') {
|
if (typeof name !== 'string') {
|
||||||
throw new TypeError('`name` should be a string in setHeader(name, value)')
|
throw new TypeError('`name` should be a string in setHeader(name, value)');
|
||||||
}
|
}
|
||||||
if (value == null) {
|
if (value == null) {
|
||||||
throw new Error('`value` required in setHeader("' + name + '", value)')
|
throw new Error('`value` required in setHeader("' + name + '", value)');
|
||||||
}
|
}
|
||||||
if (!this.urlRequest.notStarted) {
|
if (this._started || this._firstWrite) {
|
||||||
throw new Error('Can\'t set headers after they are sent')
|
throw new Error('Can\'t set headers after they are sent');
|
||||||
|
}
|
||||||
|
if (!_isValidHeaderName(name)) {
|
||||||
|
throw new Error(`Invalid header name: '${name}'`);
|
||||||
|
}
|
||||||
|
if (!_isValidHeaderValue(value.toString())) {
|
||||||
|
throw new Error(`Invalid value for header '${name}': '${value}'`);
|
||||||
}
|
}
|
||||||
|
|
||||||
const key = name.toLowerCase()
|
const key = name.toLowerCase();
|
||||||
this.extraHeaders[key] = value
|
this._urlLoaderOptions.extraHeaders[key] = value;
|
||||||
this.urlRequest.setExtraHeader(name, value.toString())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
getHeader (name) {
|
getHeader (name) {
|
||||||
if (name == null) {
|
if (name == null) {
|
||||||
throw new Error('`name` is required for getHeader(name)')
|
throw new Error('`name` is required for getHeader(name)');
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!this.extraHeaders) {
|
const key = name.toLowerCase();
|
||||||
return
|
return this._urlLoaderOptions.extraHeaders[key];
|
||||||
}
|
|
||||||
|
|
||||||
const key = name.toLowerCase()
|
|
||||||
return this.extraHeaders[key]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
removeHeader (name) {
|
removeHeader (name) {
|
||||||
if (name == null) {
|
if (name == null) {
|
||||||
throw new Error('`name` is required for removeHeader(name)')
|
throw new Error('`name` is required for removeHeader(name)');
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!this.urlRequest.notStarted) {
|
if (this._started || this._firstWrite) {
|
||||||
throw new Error('Can\'t remove headers after they are sent')
|
throw new Error('Can\'t remove headers after they are sent');
|
||||||
}
|
}
|
||||||
|
|
||||||
const key = name.toLowerCase()
|
const key = name.toLowerCase();
|
||||||
delete this.extraHeaders[key]
|
delete this._urlLoaderOptions.extraHeaders[key];
|
||||||
this.urlRequest.removeExtraHeader(name)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_write (chunk, encoding, callback, isLast) {
|
_write (chunk, encoding, callback) {
|
||||||
const chunkIsString = typeof chunk === 'string'
|
this._firstWrite = true;
|
||||||
const chunkIsBuffer = chunk instanceof Buffer
|
if (!this._body) {
|
||||||
if (!chunkIsString && !chunkIsBuffer) {
|
this._body = new SlurpStream();
|
||||||
throw new TypeError('First argument must be a string or Buffer')
|
this._body.on('finish', () => {
|
||||||
|
this._urlLoaderOptions.body = this._body.data();
|
||||||
|
this._startRequest();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
// TODO: is this the right way to forward to another stream?
|
||||||
if (chunkIsString) {
|
this._body.write(chunk, encoding, callback);
|
||||||
// We convert all strings into binary buffers.
|
|
||||||
chunk = Buffer.from(chunk, encoding)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Since writing to the network is asynchronous, we conservatively
|
|
||||||
// assume that request headers are written after delivering the first
|
|
||||||
// buffer to the network IO thread.
|
|
||||||
if (this.urlRequest.notStarted) {
|
|
||||||
this.urlRequest.setChunkedUpload(this.chunkedEncoding)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Headers are assumed to be sent on first call to _writeBuffer,
|
|
||||||
// i.e. after the first call to write or end.
|
|
||||||
const result = this.urlRequest.write(chunk, isLast)
|
|
||||||
|
|
||||||
// The write callback is fired asynchronously to mimic Node.js.
|
|
||||||
if (callback) {
|
|
||||||
process.nextTick(callback)
|
|
||||||
}
|
|
||||||
|
|
||||||
return result
|
|
||||||
}
|
}
|
||||||
|
|
||||||
write (data, encoding, callback) {
|
_final (callback) {
|
||||||
if (this.urlRequest.finished) {
|
if (this._body) {
|
||||||
const error = new Error('Write after end')
|
// TODO: is this the right way to forward to another stream?
|
||||||
process.nextTick(writeAfterEndNT, this, error, callback)
|
this._body.end(callback);
|
||||||
return true
|
} else {
|
||||||
|
// end() called without a body, go ahead and start the request
|
||||||
|
this._startRequest();
|
||||||
|
callback();
|
||||||
}
|
}
|
||||||
|
|
||||||
return this._write(data, encoding, callback, false)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
end (data, encoding, callback) {
|
_startRequest () {
|
||||||
if (this.urlRequest.finished) {
|
this._started = true;
|
||||||
return false
|
const stringifyValues = (obj) => {
|
||||||
}
|
const ret = {};
|
||||||
|
for (const k of Object.keys(obj)) {
|
||||||
|
ret[k] = obj[k].toString();
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
};
|
||||||
|
const opts = { ...this._urlLoaderOptions, extraHeaders: stringifyValues(this._urlLoaderOptions.extraHeaders) };
|
||||||
|
this._urlLoader = new URLLoader(opts);
|
||||||
|
this._urlLoader.on('response-started', (event, finalUrl, responseHead) => {
|
||||||
|
const response = this._response = new IncomingMessage(responseHead);
|
||||||
|
this.emit('response', response);
|
||||||
|
});
|
||||||
|
this._urlLoader.on('data', (event, data) => {
|
||||||
|
this._response._storeInternalData(Buffer.from(data));
|
||||||
|
});
|
||||||
|
this._urlLoader.on('complete', () => {
|
||||||
|
if (this._response) { this._response._storeInternalData(null); }
|
||||||
|
});
|
||||||
|
this._urlLoader.on('error', (event, netErrorString) => {
|
||||||
|
const error = new Error(netErrorString);
|
||||||
|
if (this._response) this._response.destroy(error);
|
||||||
|
this._die(error);
|
||||||
|
});
|
||||||
|
|
||||||
if (typeof data === 'function') {
|
this._urlLoader.on('login', (event, authInfo, callback) => {
|
||||||
callback = data
|
const handled = this.emit('login', authInfo, callback);
|
||||||
encoding = null
|
if (!handled) {
|
||||||
data = null
|
// If there were no listeners, cancel the authentication request.
|
||||||
} else if (typeof encoding === 'function') {
|
callback();
|
||||||
callback = encoding
|
}
|
||||||
encoding = null
|
});
|
||||||
}
|
|
||||||
|
|
||||||
data = data || ''
|
this._urlLoader.on('redirect', (event, redirectInfo, headers) => {
|
||||||
|
const { statusCode, newMethod, newUrl } = redirectInfo;
|
||||||
|
if (this._redirectPolicy === 'error') {
|
||||||
|
this._die(new Error(`Attempted to redirect, but redirect policy was 'error'`));
|
||||||
|
} else if (this._redirectPolicy === 'manual') {
|
||||||
|
let _followRedirect = false;
|
||||||
|
this._followRedirectCb = () => { _followRedirect = true; };
|
||||||
|
try {
|
||||||
|
this.emit('redirect', statusCode, newMethod, newUrl, headers);
|
||||||
|
} finally {
|
||||||
|
this._followRedirectCb = null;
|
||||||
|
if (!_followRedirect && !this._aborted) {
|
||||||
|
this._die(new Error('Redirect was cancelled'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (this._redirectPolicy === 'follow') {
|
||||||
|
// Calling followRedirect() when the redirect policy is 'follow' is
|
||||||
|
// allowed but does nothing. (Perhaps it should throw an error
|
||||||
|
// though...? Since the redirect will happen regardless.)
|
||||||
|
try {
|
||||||
|
this._followRedirectCb = () => {};
|
||||||
|
this.emit('redirect', statusCode, newMethod, newUrl, headers);
|
||||||
|
} finally {
|
||||||
|
this._followRedirectCb = null;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this._die(new Error(`Unexpected redirect policy '${this._redirectPolicy}'`));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
return this._write(data, encoding, callback, true)
|
this._urlLoader.on('upload-progress', (event, position, total) => {
|
||||||
|
this._uploadProgress = { active: true, started: true, current: position, total };
|
||||||
|
this.emit('upload-progress', position, total); // Undocumented, for now
|
||||||
|
});
|
||||||
|
|
||||||
|
this._urlLoader.on('download-progress', (event, current) => {
|
||||||
|
if (this._response) {
|
||||||
|
this._response.emit('download-progress', current); // Undocumented, for now
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
followRedirect () {
|
followRedirect () {
|
||||||
this.urlRequest.followRedirect()
|
if (this._followRedirectCb) {
|
||||||
|
this._followRedirectCb();
|
||||||
|
} else {
|
||||||
|
throw new Error('followRedirect() called, but was not waiting for a redirect');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
abort () {
|
abort () {
|
||||||
this.urlRequest.cancel()
|
if (!this._aborted) {
|
||||||
|
process.nextTick(() => { this.emit('abort'); });
|
||||||
|
}
|
||||||
|
this._aborted = true;
|
||||||
|
this._die();
|
||||||
|
}
|
||||||
|
|
||||||
|
_die (err) {
|
||||||
|
this.destroy(err);
|
||||||
|
if (this._urlLoader) {
|
||||||
|
this._urlLoader.cancel();
|
||||||
|
if (this._response) this._response.destroy(err);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
getUploadProgress () {
|
getUploadProgress () {
|
||||||
return this.urlRequest.getUploadProgress()
|
return this._uploadProgress ? { ...this._uploadProgress } : { active: false };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function writeAfterEndNT (self, error, callback) {
|
|
||||||
self.emit('error', error)
|
|
||||||
if (callback) callback(error)
|
|
||||||
}
|
|
||||||
|
|
||||||
Net.prototype.request = function (options, callback) {
|
Net.prototype.request = function (options, callback) {
|
||||||
return new ClientRequest(options, callback)
|
return new ClientRequest(options, callback);
|
||||||
}
|
};
|
||||||
|
|
||||||
net.ClientRequest = ClientRequest
|
net.ClientRequest = ClientRequest;
|
||||||
|
|
||||||
module.exports = net
|
module.exports = net;
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
'use strict'
|
'use strict';
|
||||||
|
|
||||||
const { EventEmitter } = require('events')
|
const { EventEmitter } = require('events');
|
||||||
const { Notification, isSupported } = process.electronBinding('notification')
|
const { Notification, isSupported } = process.electronBinding('notification');
|
||||||
|
|
||||||
Object.setPrototypeOf(Notification.prototype, EventEmitter.prototype)
|
Object.setPrototypeOf(Notification.prototype, EventEmitter.prototype);
|
||||||
|
|
||||||
Notification.isSupported = isSupported
|
Notification.isSupported = isSupported;
|
||||||
|
|
||||||
module.exports = Notification
|
module.exports = Notification;
|
||||||
|
|||||||
@@ -1,28 +1,38 @@
|
|||||||
'use strict'
|
'use strict';
|
||||||
|
|
||||||
import { createLazyInstance } from '../utils'
|
import { createLazyInstance } from '../utils';
|
||||||
|
|
||||||
const { EventEmitter } = require('events')
|
const { EventEmitter } = require('events');
|
||||||
const { createPowerMonitor, PowerMonitor } = process.electronBinding('power_monitor')
|
const { createPowerMonitor, PowerMonitor } = process.electronBinding('power_monitor');
|
||||||
|
|
||||||
// PowerMonitor is an EventEmitter.
|
// PowerMonitor is an EventEmitter.
|
||||||
Object.setPrototypeOf(PowerMonitor.prototype, EventEmitter.prototype)
|
Object.setPrototypeOf(PowerMonitor.prototype, EventEmitter.prototype);
|
||||||
|
|
||||||
const powerMonitor = createLazyInstance(createPowerMonitor, PowerMonitor, true)
|
const powerMonitor = createLazyInstance(createPowerMonitor, PowerMonitor, true);
|
||||||
|
|
||||||
// On Linux we need to call blockShutdown() to subscribe to shutdown event.
|
|
||||||
if (process.platform === 'linux') {
|
if (process.platform === 'linux') {
|
||||||
powerMonitor.on('newListener', (event:string) => {
|
// In order to delay system shutdown when e.preventDefault() is invoked
|
||||||
if (event === 'shutdown' && powerMonitor.listenerCount('shutdown') === 0) {
|
// on a powerMonitor 'shutdown' event, we need an org.freedesktop.login1
|
||||||
powerMonitor.blockShutdown()
|
// shutdown delay lock. For more details see the "Taking Delay Locks"
|
||||||
}
|
// section of https://www.freedesktop.org/wiki/Software/systemd/inhibit/
|
||||||
})
|
//
|
||||||
|
// So here we watch for 'shutdown' listeners to be added or removed and
|
||||||
powerMonitor.on('removeListener', (event: string) => {
|
// set or unset our shutdown delay lock accordingly.
|
||||||
if (event === 'shutdown' && powerMonitor.listenerCount('shutdown') === 0) {
|
const { app } = require('electron');
|
||||||
powerMonitor.unblockShutdown()
|
app.whenReady().then(() => {
|
||||||
}
|
powerMonitor.on('newListener', (event: string) => {
|
||||||
})
|
// whenever the listener count is incremented to one...
|
||||||
|
if (event === 'shutdown' && powerMonitor.listenerCount('shutdown') === 0) {
|
||||||
|
powerMonitor.blockShutdown();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
powerMonitor.on('removeListener', (event: string) => {
|
||||||
|
// whenever the listener count is decremented to zero...
|
||||||
|
if (event === 'shutdown' && powerMonitor.listenerCount('shutdown') === 0) {
|
||||||
|
powerMonitor.unblockShutdown();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = powerMonitor
|
module.exports = powerMonitor;
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
'use strict'
|
'use strict';
|
||||||
|
|
||||||
module.exports = process.electronBinding('power_save_blocker').powerSaveBlocker
|
module.exports = process.electronBinding('power_save_blocker').powerSaveBlocker;
|
||||||
|
|||||||
@@ -1,29 +1,29 @@
|
|||||||
import { app, session } from 'electron'
|
import { app, session } from 'electron';
|
||||||
|
|
||||||
// Global protocol APIs.
|
// Global protocol APIs.
|
||||||
const protocol = process.electronBinding('protocol')
|
const protocol = process.electronBinding('protocol');
|
||||||
|
|
||||||
// Fallback protocol APIs of default session.
|
// Fallback protocol APIs of default session.
|
||||||
Object.setPrototypeOf(protocol, new Proxy({}, {
|
Object.setPrototypeOf(protocol, new Proxy({}, {
|
||||||
get (_target, property) {
|
get (_target, property) {
|
||||||
if (!app.isReady()) return
|
if (!app.isReady()) return;
|
||||||
|
|
||||||
const protocol = session.defaultSession!.protocol
|
const protocol = session.defaultSession!.protocol;
|
||||||
if (!Object.getPrototypeOf(protocol).hasOwnProperty(property)) return
|
if (!Object.getPrototypeOf(protocol).hasOwnProperty(property)) return;
|
||||||
|
|
||||||
// Returning a native function directly would throw error.
|
// Returning a native function directly would throw error.
|
||||||
return (...args: any[]) => (protocol[property as keyof Electron.Protocol] as Function)(...args)
|
return (...args: any[]) => (protocol[property as keyof Electron.Protocol] as Function)(...args);
|
||||||
},
|
},
|
||||||
|
|
||||||
ownKeys () {
|
ownKeys () {
|
||||||
if (!app.isReady()) return []
|
if (!app.isReady()) return [];
|
||||||
|
|
||||||
return Object.getOwnPropertyNames(Object.getPrototypeOf(session.defaultSession!.protocol))
|
return Object.getOwnPropertyNames(Object.getPrototypeOf(session.defaultSession!.protocol));
|
||||||
},
|
},
|
||||||
|
|
||||||
getOwnPropertyDescriptor () {
|
getOwnPropertyDescriptor () {
|
||||||
return { configurable: true, enumerable: true }
|
return { configurable: true, enumerable: true };
|
||||||
}
|
}
|
||||||
}))
|
}));
|
||||||
|
|
||||||
export default protocol
|
export default protocol;
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
'use strict'
|
'use strict';
|
||||||
|
|
||||||
import { createLazyInstance } from '../utils'
|
import { createLazyInstance } from '../utils';
|
||||||
const { EventEmitter } = require('events')
|
const { EventEmitter } = require('events');
|
||||||
const { Screen, createScreen } = process.electronBinding('screen')
|
const { Screen, createScreen } = process.electronBinding('screen');
|
||||||
|
|
||||||
// Screen is an EventEmitter.
|
// Screen is an EventEmitter.
|
||||||
Object.setPrototypeOf(Screen.prototype, EventEmitter.prototype)
|
Object.setPrototypeOf(Screen.prototype, EventEmitter.prototype);
|
||||||
|
|
||||||
module.exports = createLazyInstance(createScreen, Screen, true)
|
module.exports = createLazyInstance(createScreen, Screen, true);
|
||||||
|
|||||||
@@ -1,52 +1,53 @@
|
|||||||
'use strict'
|
'use strict';
|
||||||
|
|
||||||
const { EventEmitter } = require('events')
|
const { EventEmitter } = require('events');
|
||||||
const { app, deprecate } = require('electron')
|
const { app, deprecate } = require('electron');
|
||||||
const { fromPartition, Session, Cookies, NetLog, Protocol } = process.electronBinding('session')
|
const { fromPartition, Session, Cookies, NetLog, Protocol } = process.electronBinding('session');
|
||||||
|
|
||||||
// Public API.
|
// Public API.
|
||||||
Object.defineProperties(exports, {
|
Object.defineProperties(exports, {
|
||||||
defaultSession: {
|
defaultSession: {
|
||||||
enumerable: true,
|
enumerable: true,
|
||||||
get () { return fromPartition('') }
|
get () { return fromPartition(''); }
|
||||||
},
|
},
|
||||||
fromPartition: {
|
fromPartition: {
|
||||||
enumerable: true,
|
enumerable: true,
|
||||||
value: fromPartition
|
value: fromPartition
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
|
|
||||||
Object.setPrototypeOf(Session.prototype, EventEmitter.prototype)
|
Object.setPrototypeOf(Session.prototype, EventEmitter.prototype);
|
||||||
Object.setPrototypeOf(Cookies.prototype, EventEmitter.prototype)
|
Object.setPrototypeOf(Cookies.prototype, EventEmitter.prototype);
|
||||||
|
|
||||||
Session.prototype._init = function () {
|
Session.prototype._init = function () {
|
||||||
app.emit('session-created', this)
|
app.emit('session-created', this);
|
||||||
}
|
};
|
||||||
|
|
||||||
const _originalStartLogging = NetLog.prototype.startLogging
|
const _originalStartLogging = NetLog.prototype.startLogging;
|
||||||
NetLog.prototype.startLogging = function (path, ...args) {
|
NetLog.prototype.startLogging = function (path, ...args) {
|
||||||
this._currentlyLoggingPath = path
|
this._currentlyLoggingPath = path;
|
||||||
try {
|
try {
|
||||||
return _originalStartLogging.call(this, path, ...args)
|
return _originalStartLogging.call(this, path, ...args);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
this._currentlyLoggingPath = null
|
this._currentlyLoggingPath = null;
|
||||||
throw e
|
throw e;
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
const _originalStopLogging = NetLog.prototype.stopLogging
|
const _originalStopLogging = NetLog.prototype.stopLogging;
|
||||||
NetLog.prototype.stopLogging = function () {
|
NetLog.prototype.stopLogging = function () {
|
||||||
this._currentlyLoggingPath = null
|
const logPath = this._currentlyLoggingPath;
|
||||||
return _originalStopLogging.call(this)
|
this._currentlyLoggingPath = null;
|
||||||
}
|
return _originalStopLogging.call(this).then(() => logPath);
|
||||||
|
};
|
||||||
|
|
||||||
const currentlyLoggingPathDeprecated = deprecate.warnOnce('currentlyLoggingPath')
|
const currentlyLoggingPathDeprecated = deprecate.warnOnce('currentlyLoggingPath');
|
||||||
Object.defineProperties(NetLog.prototype, {
|
Object.defineProperties(NetLog.prototype, {
|
||||||
currentlyLoggingPath: {
|
currentlyLoggingPath: {
|
||||||
enumerable: true,
|
enumerable: true,
|
||||||
get () {
|
get () {
|
||||||
currentlyLoggingPathDeprecated()
|
currentlyLoggingPathDeprecated();
|
||||||
return this._currentlyLoggingPath == null ? '' : this._currentlyLoggingPath
|
return this._currentlyLoggingPath == null ? '' : this._currentlyLoggingPath;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
import { EventEmitter } from 'events'
|
import { EventEmitter } from 'events';
|
||||||
import { deprecate } from 'electron'
|
import { deprecate } from 'electron';
|
||||||
const { systemPreferences, SystemPreferences } = process.electronBinding('system_preferences')
|
const { systemPreferences, SystemPreferences } = process.electronBinding('system_preferences');
|
||||||
|
|
||||||
// SystemPreferences is an EventEmitter.
|
// SystemPreferences is an EventEmitter.
|
||||||
Object.setPrototypeOf(SystemPreferences.prototype, EventEmitter.prototype)
|
Object.setPrototypeOf(SystemPreferences.prototype, EventEmitter.prototype);
|
||||||
EventEmitter.call(systemPreferences)
|
EventEmitter.call(systemPreferences);
|
||||||
|
|
||||||
if ('appLevelAppearance' in systemPreferences) {
|
if ('appLevelAppearance' in systemPreferences) {
|
||||||
deprecate.fnToProperty(
|
deprecate.fnToProperty(
|
||||||
@@ -12,7 +12,7 @@ if ('appLevelAppearance' in systemPreferences) {
|
|||||||
'appLevelAppearance',
|
'appLevelAppearance',
|
||||||
'_getAppLevelAppearance',
|
'_getAppLevelAppearance',
|
||||||
'_setAppLevelAppearance'
|
'_setAppLevelAppearance'
|
||||||
)
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ('effectiveAppearance' in systemPreferences) {
|
if ('effectiveAppearance' in systemPreferences) {
|
||||||
@@ -20,23 +20,23 @@ if ('effectiveAppearance' in systemPreferences) {
|
|||||||
SystemPreferences.prototype,
|
SystemPreferences.prototype,
|
||||||
'effectiveAppearance',
|
'effectiveAppearance',
|
||||||
'_getEffectiveAppearance'
|
'_getEffectiveAppearance'
|
||||||
)
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
SystemPreferences.prototype.isDarkMode = deprecate.moveAPI(
|
SystemPreferences.prototype.isDarkMode = deprecate.moveAPI(
|
||||||
SystemPreferences.prototype.isDarkMode,
|
SystemPreferences.prototype.isDarkMode,
|
||||||
'systemPreferences.isDarkMode()',
|
'systemPreferences.isDarkMode()',
|
||||||
'nativeTheme.shouldUseDarkColors'
|
'nativeTheme.shouldUseDarkColors'
|
||||||
)
|
);
|
||||||
SystemPreferences.prototype.isInvertedColorScheme = deprecate.moveAPI(
|
SystemPreferences.prototype.isInvertedColorScheme = deprecate.moveAPI(
|
||||||
SystemPreferences.prototype.isInvertedColorScheme,
|
SystemPreferences.prototype.isInvertedColorScheme,
|
||||||
'systemPreferences.isInvertedColorScheme()',
|
'systemPreferences.isInvertedColorScheme()',
|
||||||
'nativeTheme.shouldUseInvertedColorScheme'
|
'nativeTheme.shouldUseInvertedColorScheme'
|
||||||
)
|
);
|
||||||
SystemPreferences.prototype.isHighContrastColorScheme = deprecate.moveAPI(
|
SystemPreferences.prototype.isHighContrastColorScheme = deprecate.moveAPI(
|
||||||
SystemPreferences.prototype.isHighContrastColorScheme,
|
SystemPreferences.prototype.isHighContrastColorScheme,
|
||||||
'systemPreferences.isHighContrastColorScheme()',
|
'systemPreferences.isHighContrastColorScheme()',
|
||||||
'nativeTheme.shouldUseHighContrastColors'
|
'nativeTheme.shouldUseHighContrastColors'
|
||||||
)
|
);
|
||||||
|
|
||||||
module.exports = systemPreferences
|
module.exports = systemPreferences;
|
||||||
|
|||||||
@@ -1,24 +1,24 @@
|
|||||||
'use strict'
|
'use strict';
|
||||||
|
|
||||||
const electron = require('electron')
|
const electron = require('electron');
|
||||||
const { EventEmitter } = require('events')
|
const { EventEmitter } = require('events');
|
||||||
const { TopLevelWindow } = process.electronBinding('top_level_window')
|
const { TopLevelWindow } = process.electronBinding('top_level_window');
|
||||||
|
|
||||||
Object.setPrototypeOf(TopLevelWindow.prototype, EventEmitter.prototype)
|
Object.setPrototypeOf(TopLevelWindow.prototype, EventEmitter.prototype);
|
||||||
|
|
||||||
TopLevelWindow.prototype._init = function () {
|
TopLevelWindow.prototype._init = function () {
|
||||||
// Avoid recursive require.
|
// Avoid recursive require.
|
||||||
const { app } = electron
|
const { app } = electron;
|
||||||
|
|
||||||
// Simulate the application menu on platforms other than macOS.
|
// Simulate the application menu on platforms other than macOS.
|
||||||
if (process.platform !== 'darwin') {
|
if (process.platform !== 'darwin') {
|
||||||
const menu = app.applicationMenu
|
const menu = app.applicationMenu;
|
||||||
if (menu) this.setMenu(menu)
|
if (menu) this.setMenu(menu);
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
TopLevelWindow.getFocusedWindow = () => {
|
TopLevelWindow.getFocusedWindow = () => {
|
||||||
return TopLevelWindow.getAllWindows().find((win) => win.isFocused())
|
return TopLevelWindow.getAllWindows().find((win) => win.isFocused());
|
||||||
}
|
};
|
||||||
|
|
||||||
module.exports = TopLevelWindow
|
module.exports = TopLevelWindow;
|
||||||
|
|||||||
@@ -1,336 +1,348 @@
|
|||||||
'use strict'
|
'use strict';
|
||||||
|
|
||||||
const { EventEmitter } = require('events')
|
const { EventEmitter } = require('events');
|
||||||
|
|
||||||
let nextItemID = 1
|
let nextItemID = 1;
|
||||||
|
|
||||||
class TouchBar extends EventEmitter {
|
class TouchBar extends EventEmitter {
|
||||||
// Bind a touch bar to a window
|
// Bind a touch bar to a window
|
||||||
static _setOnWindow (touchBar, window) {
|
static _setOnWindow (touchBar, window) {
|
||||||
if (window._touchBar != null) {
|
if (window._touchBar != null) {
|
||||||
window._touchBar._removeFromWindow(window)
|
window._touchBar._removeFromWindow(window);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (touchBar == null) {
|
if (touchBar == null) {
|
||||||
window._setTouchBarItems([])
|
window._setTouchBarItems([]);
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Array.isArray(touchBar)) {
|
if (Array.isArray(touchBar)) {
|
||||||
touchBar = new TouchBar(touchBar)
|
touchBar = new TouchBar(touchBar);
|
||||||
}
|
}
|
||||||
touchBar._addToWindow(window)
|
touchBar._addToWindow(window);
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor (options) {
|
constructor (options) {
|
||||||
super()
|
super();
|
||||||
|
|
||||||
if (options == null) {
|
if (options == null) {
|
||||||
throw new Error('Must specify options object as first argument')
|
throw new Error('Must specify options object as first argument');
|
||||||
}
|
}
|
||||||
|
|
||||||
let { items, escapeItem } = options
|
let { items, escapeItem } = options;
|
||||||
|
|
||||||
if (!Array.isArray(items)) {
|
if (!Array.isArray(items)) {
|
||||||
items = []
|
items = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
this.changeListener = (item) => {
|
this.changeListener = (item) => {
|
||||||
this.emit('change', item.id, item.type)
|
this.emit('change', item.id, item.type);
|
||||||
}
|
};
|
||||||
|
|
||||||
this.windowListeners = {}
|
this.windowListeners = {};
|
||||||
this.items = {}
|
this.items = {};
|
||||||
this.ordereredItems = []
|
this.ordereredItems = [];
|
||||||
this.escapeItem = escapeItem
|
this.escapeItem = escapeItem;
|
||||||
|
|
||||||
const registerItem = (item) => {
|
const registerItem = (item) => {
|
||||||
this.items[item.id] = item
|
this.items[item.id] = item;
|
||||||
item.on('change', this.changeListener)
|
item.on('change', this.changeListener);
|
||||||
if (item.child instanceof TouchBar) {
|
if (item.child instanceof TouchBar) {
|
||||||
item.child.ordereredItems.forEach(registerItem)
|
item.child.ordereredItems.forEach(registerItem);
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
|
const idSet = new Set();
|
||||||
items.forEach((item) => {
|
items.forEach((item) => {
|
||||||
if (!(item instanceof TouchBarItem)) {
|
if (!(item instanceof TouchBarItem)) {
|
||||||
throw new Error('Each item must be an instance of TouchBarItem')
|
throw new Error('Each item must be an instance of TouchBarItem');
|
||||||
}
|
}
|
||||||
this.ordereredItems.push(item)
|
|
||||||
registerItem(item)
|
if (!idSet.has(item.id)) {
|
||||||
})
|
idSet.add(item.id);
|
||||||
|
} else {
|
||||||
|
throw new Error('Cannot add a single instance of TouchBarItem multiple times in a TouchBar');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// register in separate loop after all items are validated
|
||||||
|
for (const item of items) {
|
||||||
|
this.ordereredItems.push(item);
|
||||||
|
registerItem(item);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
set escapeItem (item) {
|
set escapeItem (item) {
|
||||||
if (item != null && !(item instanceof TouchBarItem)) {
|
if (item != null && !(item instanceof TouchBarItem)) {
|
||||||
throw new Error('Escape item must be an instance of TouchBarItem')
|
throw new Error('Escape item must be an instance of TouchBarItem');
|
||||||
}
|
}
|
||||||
if (this.escapeItem != null) {
|
if (this.escapeItem != null) {
|
||||||
this.escapeItem.removeListener('change', this.changeListener)
|
this.escapeItem.removeListener('change', this.changeListener);
|
||||||
}
|
}
|
||||||
this._escapeItem = item
|
this._escapeItem = item;
|
||||||
if (this.escapeItem != null) {
|
if (this.escapeItem != null) {
|
||||||
this.escapeItem.on('change', this.changeListener)
|
this.escapeItem.on('change', this.changeListener);
|
||||||
}
|
}
|
||||||
this.emit('escape-item-change', item)
|
this.emit('escape-item-change', item);
|
||||||
}
|
}
|
||||||
|
|
||||||
get escapeItem () {
|
get escapeItem () {
|
||||||
return this._escapeItem
|
return this._escapeItem;
|
||||||
}
|
}
|
||||||
|
|
||||||
_addToWindow (window) {
|
_addToWindow (window) {
|
||||||
const { id } = window
|
const { id } = window;
|
||||||
|
|
||||||
// Already added to window
|
// Already added to window
|
||||||
if (this.windowListeners.hasOwnProperty(id)) return
|
if (this.windowListeners.hasOwnProperty(id)) return;
|
||||||
|
|
||||||
window._touchBar = this
|
window._touchBar = this;
|
||||||
|
|
||||||
const changeListener = (itemID) => {
|
const changeListener = (itemID) => {
|
||||||
window._refreshTouchBarItem(itemID)
|
window._refreshTouchBarItem(itemID);
|
||||||
}
|
};
|
||||||
this.on('change', changeListener)
|
this.on('change', changeListener);
|
||||||
|
|
||||||
const escapeItemListener = (item) => {
|
const escapeItemListener = (item) => {
|
||||||
window._setEscapeTouchBarItem(item != null ? item : {})
|
window._setEscapeTouchBarItem(item != null ? item : {});
|
||||||
}
|
};
|
||||||
this.on('escape-item-change', escapeItemListener)
|
this.on('escape-item-change', escapeItemListener);
|
||||||
|
|
||||||
const interactionListener = (event, itemID, details) => {
|
const interactionListener = (event, itemID, details) => {
|
||||||
let item = this.items[itemID]
|
let item = this.items[itemID];
|
||||||
if (item == null && this.escapeItem != null && this.escapeItem.id === itemID) {
|
if (item == null && this.escapeItem != null && this.escapeItem.id === itemID) {
|
||||||
item = this.escapeItem
|
item = this.escapeItem;
|
||||||
}
|
}
|
||||||
if (item != null && item.onInteraction != null) {
|
if (item != null && item.onInteraction != null) {
|
||||||
item.onInteraction(details)
|
item.onInteraction(details);
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
window.on('-touch-bar-interaction', interactionListener)
|
window.on('-touch-bar-interaction', interactionListener);
|
||||||
|
|
||||||
const removeListeners = () => {
|
const removeListeners = () => {
|
||||||
this.removeListener('change', changeListener)
|
this.removeListener('change', changeListener);
|
||||||
this.removeListener('escape-item-change', escapeItemListener)
|
this.removeListener('escape-item-change', escapeItemListener);
|
||||||
window.removeListener('-touch-bar-interaction', interactionListener)
|
window.removeListener('-touch-bar-interaction', interactionListener);
|
||||||
window.removeListener('closed', removeListeners)
|
window.removeListener('closed', removeListeners);
|
||||||
window._touchBar = null
|
window._touchBar = null;
|
||||||
delete this.windowListeners[id]
|
delete this.windowListeners[id];
|
||||||
const unregisterItems = (items) => {
|
const unregisterItems = (items) => {
|
||||||
for (const item of items) {
|
for (const item of items) {
|
||||||
item.removeListener('change', this.changeListener)
|
item.removeListener('change', this.changeListener);
|
||||||
if (item.child instanceof TouchBar) {
|
if (item.child instanceof TouchBar) {
|
||||||
unregisterItems(item.child.ordereredItems)
|
unregisterItems(item.child.ordereredItems);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
unregisterItems(this.ordereredItems)
|
unregisterItems(this.ordereredItems);
|
||||||
if (this.escapeItem) {
|
if (this.escapeItem) {
|
||||||
this.escapeItem.removeListener('change', this.changeListener)
|
this.escapeItem.removeListener('change', this.changeListener);
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
window.once('closed', removeListeners)
|
window.once('closed', removeListeners);
|
||||||
this.windowListeners[id] = removeListeners
|
this.windowListeners[id] = removeListeners;
|
||||||
|
|
||||||
window._setTouchBarItems(this.ordereredItems)
|
window._setTouchBarItems(this.ordereredItems);
|
||||||
escapeItemListener(this.escapeItem)
|
escapeItemListener(this.escapeItem);
|
||||||
}
|
}
|
||||||
|
|
||||||
_removeFromWindow (window) {
|
_removeFromWindow (window) {
|
||||||
const removeListeners = this.windowListeners[window.id]
|
const removeListeners = this.windowListeners[window.id];
|
||||||
if (removeListeners != null) removeListeners()
|
if (removeListeners != null) removeListeners();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class TouchBarItem extends EventEmitter {
|
class TouchBarItem extends EventEmitter {
|
||||||
constructor () {
|
constructor () {
|
||||||
super()
|
super();
|
||||||
this._addImmutableProperty('id', `${nextItemID++}`)
|
this._addImmutableProperty('id', `${nextItemID++}`);
|
||||||
this._parents = []
|
this._parents = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
_addImmutableProperty (name, value) {
|
_addImmutableProperty (name, value) {
|
||||||
Object.defineProperty(this, name, {
|
Object.defineProperty(this, name, {
|
||||||
get: function () {
|
get: function () {
|
||||||
return value
|
return value;
|
||||||
},
|
},
|
||||||
set: function () {
|
set: function () {
|
||||||
throw new Error(`Cannot override property ${name}`)
|
throw new Error(`Cannot override property ${name}`);
|
||||||
},
|
},
|
||||||
enumerable: true,
|
enumerable: true,
|
||||||
configurable: false
|
configurable: false
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
_addLiveProperty (name, initialValue) {
|
_addLiveProperty (name, initialValue) {
|
||||||
const privateName = `_${name}`
|
const privateName = `_${name}`;
|
||||||
this[privateName] = initialValue
|
this[privateName] = initialValue;
|
||||||
Object.defineProperty(this, name, {
|
Object.defineProperty(this, name, {
|
||||||
get: function () {
|
get: function () {
|
||||||
return this[privateName]
|
return this[privateName];
|
||||||
},
|
},
|
||||||
set: function (value) {
|
set: function (value) {
|
||||||
this[privateName] = value
|
this[privateName] = value;
|
||||||
this.emit('change', this)
|
this.emit('change', this);
|
||||||
},
|
},
|
||||||
enumerable: true
|
enumerable: true
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
_addParent (item) {
|
_addParent (item) {
|
||||||
const existing = this._parents.some(test => test.id === item.id)
|
const existing = this._parents.some(test => test.id === item.id);
|
||||||
if (!existing) {
|
if (!existing) {
|
||||||
this._parents.push({
|
this._parents.push({
|
||||||
id: item.id,
|
id: item.id,
|
||||||
type: item.type
|
type: item.type
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
TouchBar.TouchBarButton = class TouchBarButton extends TouchBarItem {
|
TouchBar.TouchBarButton = class TouchBarButton extends TouchBarItem {
|
||||||
constructor (config) {
|
constructor (config) {
|
||||||
super()
|
super();
|
||||||
if (config == null) config = {}
|
if (config == null) config = {};
|
||||||
this._addImmutableProperty('type', 'button')
|
this._addImmutableProperty('type', 'button');
|
||||||
this._addLiveProperty('label', config.label)
|
this._addLiveProperty('label', config.label);
|
||||||
this._addLiveProperty('accessibilityLabel', config.accessibilityLabel)
|
this._addLiveProperty('accessibilityLabel', config.accessibilityLabel);
|
||||||
this._addLiveProperty('backgroundColor', config.backgroundColor)
|
this._addLiveProperty('backgroundColor', config.backgroundColor);
|
||||||
this._addLiveProperty('icon', config.icon)
|
this._addLiveProperty('icon', config.icon);
|
||||||
this._addLiveProperty('iconPosition', config.iconPosition)
|
this._addLiveProperty('iconPosition', config.iconPosition);
|
||||||
if (typeof config.click === 'function') {
|
if (typeof config.click === 'function') {
|
||||||
this._addImmutableProperty('onInteraction', () => {
|
this._addImmutableProperty('onInteraction', () => {
|
||||||
config.click()
|
config.click();
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
TouchBar.TouchBarColorPicker = class TouchBarColorPicker extends TouchBarItem {
|
TouchBar.TouchBarColorPicker = class TouchBarColorPicker extends TouchBarItem {
|
||||||
constructor (config) {
|
constructor (config) {
|
||||||
super()
|
super();
|
||||||
if (config == null) config = {}
|
if (config == null) config = {};
|
||||||
this._addImmutableProperty('type', 'colorpicker')
|
this._addImmutableProperty('type', 'colorpicker');
|
||||||
this._addLiveProperty('availableColors', config.availableColors)
|
this._addLiveProperty('availableColors', config.availableColors);
|
||||||
this._addLiveProperty('selectedColor', config.selectedColor)
|
this._addLiveProperty('selectedColor', config.selectedColor);
|
||||||
|
|
||||||
if (typeof config.change === 'function') {
|
if (typeof config.change === 'function') {
|
||||||
this._addImmutableProperty('onInteraction', (details) => {
|
this._addImmutableProperty('onInteraction', (details) => {
|
||||||
this._selectedColor = details.color
|
this._selectedColor = details.color;
|
||||||
config.change(details.color)
|
config.change(details.color);
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
TouchBar.TouchBarGroup = class TouchBarGroup extends TouchBarItem {
|
TouchBar.TouchBarGroup = class TouchBarGroup extends TouchBarItem {
|
||||||
constructor (config) {
|
constructor (config) {
|
||||||
super()
|
super();
|
||||||
if (config == null) config = {}
|
if (config == null) config = {};
|
||||||
this._addImmutableProperty('type', 'group')
|
this._addImmutableProperty('type', 'group');
|
||||||
const defaultChild = (config.items instanceof TouchBar) ? config.items : new TouchBar(config.items)
|
const defaultChild = (config.items instanceof TouchBar) ? config.items : new TouchBar(config.items);
|
||||||
this._addLiveProperty('child', defaultChild)
|
this._addLiveProperty('child', defaultChild);
|
||||||
this.child.ordereredItems.forEach((item) => item._addParent(this))
|
this.child.ordereredItems.forEach((item) => item._addParent(this));
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
TouchBar.TouchBarLabel = class TouchBarLabel extends TouchBarItem {
|
TouchBar.TouchBarLabel = class TouchBarLabel extends TouchBarItem {
|
||||||
constructor (config) {
|
constructor (config) {
|
||||||
super()
|
super();
|
||||||
if (config == null) config = {}
|
if (config == null) config = {};
|
||||||
this._addImmutableProperty('type', 'label')
|
this._addImmutableProperty('type', 'label');
|
||||||
this._addLiveProperty('label', config.label)
|
this._addLiveProperty('label', config.label);
|
||||||
this._addLiveProperty('accessibilityLabel', config.accessibilityLabel)
|
this._addLiveProperty('accessibilityLabel', config.accessibilityLabel);
|
||||||
this._addLiveProperty('textColor', config.textColor)
|
this._addLiveProperty('textColor', config.textColor);
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
TouchBar.TouchBarPopover = class TouchBarPopover extends TouchBarItem {
|
TouchBar.TouchBarPopover = class TouchBarPopover extends TouchBarItem {
|
||||||
constructor (config) {
|
constructor (config) {
|
||||||
super()
|
super();
|
||||||
if (config == null) config = {}
|
if (config == null) config = {};
|
||||||
this._addImmutableProperty('type', 'popover')
|
this._addImmutableProperty('type', 'popover');
|
||||||
this._addLiveProperty('label', config.label)
|
this._addLiveProperty('label', config.label);
|
||||||
this._addLiveProperty('icon', config.icon)
|
this._addLiveProperty('icon', config.icon);
|
||||||
this._addLiveProperty('showCloseButton', config.showCloseButton)
|
this._addLiveProperty('showCloseButton', config.showCloseButton);
|
||||||
const defaultChild = (config.items instanceof TouchBar) ? config.items : new TouchBar(config.items)
|
const defaultChild = (config.items instanceof TouchBar) ? config.items : new TouchBar(config.items);
|
||||||
this._addLiveProperty('child', defaultChild)
|
this._addLiveProperty('child', defaultChild);
|
||||||
this.child.ordereredItems.forEach((item) => item._addParent(this))
|
this.child.ordereredItems.forEach((item) => item._addParent(this));
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
TouchBar.TouchBarSlider = class TouchBarSlider extends TouchBarItem {
|
TouchBar.TouchBarSlider = class TouchBarSlider extends TouchBarItem {
|
||||||
constructor (config) {
|
constructor (config) {
|
||||||
super()
|
super();
|
||||||
if (config == null) config = {}
|
if (config == null) config = {};
|
||||||
this._addImmutableProperty('type', 'slider')
|
this._addImmutableProperty('type', 'slider');
|
||||||
this._addLiveProperty('label', config.label)
|
this._addLiveProperty('label', config.label);
|
||||||
this._addLiveProperty('minValue', config.minValue)
|
this._addLiveProperty('minValue', config.minValue);
|
||||||
this._addLiveProperty('maxValue', config.maxValue)
|
this._addLiveProperty('maxValue', config.maxValue);
|
||||||
this._addLiveProperty('value', config.value)
|
this._addLiveProperty('value', config.value);
|
||||||
|
|
||||||
if (typeof config.change === 'function') {
|
if (typeof config.change === 'function') {
|
||||||
this._addImmutableProperty('onInteraction', (details) => {
|
this._addImmutableProperty('onInteraction', (details) => {
|
||||||
this._value = details.value
|
this._value = details.value;
|
||||||
config.change(details.value)
|
config.change(details.value);
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
TouchBar.TouchBarSpacer = class TouchBarSpacer extends TouchBarItem {
|
TouchBar.TouchBarSpacer = class TouchBarSpacer extends TouchBarItem {
|
||||||
constructor (config) {
|
constructor (config) {
|
||||||
super()
|
super();
|
||||||
if (config == null) config = {}
|
if (config == null) config = {};
|
||||||
this._addImmutableProperty('type', 'spacer')
|
this._addImmutableProperty('type', 'spacer');
|
||||||
this._addImmutableProperty('size', config.size)
|
this._addImmutableProperty('size', config.size);
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
TouchBar.TouchBarSegmentedControl = class TouchBarSegmentedControl extends TouchBarItem {
|
TouchBar.TouchBarSegmentedControl = class TouchBarSegmentedControl extends TouchBarItem {
|
||||||
constructor (config) {
|
constructor (config) {
|
||||||
super()
|
super();
|
||||||
if (config == null) config = {}
|
if (config == null) config = {};
|
||||||
this._addImmutableProperty('type', 'segmented_control')
|
this._addImmutableProperty('type', 'segmented_control');
|
||||||
this._addLiveProperty('segmentStyle', config.segmentStyle)
|
this._addLiveProperty('segmentStyle', config.segmentStyle);
|
||||||
this._addLiveProperty('segments', config.segments || [])
|
this._addLiveProperty('segments', config.segments || []);
|
||||||
this._addLiveProperty('selectedIndex', config.selectedIndex)
|
this._addLiveProperty('selectedIndex', config.selectedIndex);
|
||||||
this._addLiveProperty('mode', config.mode)
|
this._addLiveProperty('mode', config.mode);
|
||||||
|
|
||||||
if (typeof config.change === 'function') {
|
if (typeof config.change === 'function') {
|
||||||
this._addImmutableProperty('onInteraction', (details) => {
|
this._addImmutableProperty('onInteraction', (details) => {
|
||||||
this._selectedIndex = details.selectedIndex
|
this._selectedIndex = details.selectedIndex;
|
||||||
config.change(details.selectedIndex, details.isSelected)
|
config.change(details.selectedIndex, details.isSelected);
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
TouchBar.TouchBarScrubber = class TouchBarScrubber extends TouchBarItem {
|
TouchBar.TouchBarScrubber = class TouchBarScrubber extends TouchBarItem {
|
||||||
constructor (config) {
|
constructor (config) {
|
||||||
super()
|
super();
|
||||||
if (config == null) config = {}
|
if (config == null) config = {};
|
||||||
let { select, highlight } = config
|
let { select, highlight } = config;
|
||||||
this._addImmutableProperty('type', 'scrubber')
|
this._addImmutableProperty('type', 'scrubber');
|
||||||
this._addLiveProperty('items', config.items)
|
this._addLiveProperty('items', config.items);
|
||||||
this._addLiveProperty('selectedStyle', config.selectedStyle || null)
|
this._addLiveProperty('selectedStyle', config.selectedStyle || null);
|
||||||
this._addLiveProperty('overlayStyle', config.overlayStyle || null)
|
this._addLiveProperty('overlayStyle', config.overlayStyle || null);
|
||||||
this._addLiveProperty('showArrowButtons', config.showArrowButtons || false)
|
this._addLiveProperty('showArrowButtons', config.showArrowButtons || false);
|
||||||
this._addLiveProperty('mode', config.mode || 'free')
|
this._addLiveProperty('mode', config.mode || 'free');
|
||||||
|
|
||||||
const cont = typeof config.continuous === 'undefined' ? true : config.continuous
|
const cont = typeof config.continuous === 'undefined' ? true : config.continuous;
|
||||||
this._addLiveProperty('continuous', cont)
|
this._addLiveProperty('continuous', cont);
|
||||||
|
|
||||||
if (typeof select === 'function' || typeof highlight === 'function') {
|
if (typeof select === 'function' || typeof highlight === 'function') {
|
||||||
if (select == null) select = () => {}
|
if (select == null) select = () => {};
|
||||||
if (highlight == null) highlight = () => {}
|
if (highlight == null) highlight = () => {};
|
||||||
this._addImmutableProperty('onInteraction', (details) => {
|
this._addImmutableProperty('onInteraction', (details) => {
|
||||||
if (details.type === 'select' && typeof select === 'function') {
|
if (details.type === 'select' && typeof select === 'function') {
|
||||||
select(details.selectedIndex)
|
select(details.selectedIndex);
|
||||||
} else if (details.type === 'highlight' && typeof highlight === 'function') {
|
} else if (details.type === 'highlight' && typeof highlight === 'function') {
|
||||||
highlight(details.highlightedIndex)
|
highlight(details.highlightedIndex);
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
module.exports = TouchBar
|
module.exports = TouchBar;
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
'use strict'
|
'use strict';
|
||||||
|
|
||||||
const { EventEmitter } = require('events')
|
const { EventEmitter } = require('events');
|
||||||
const { deprecate } = require('electron')
|
const { deprecate } = require('electron');
|
||||||
const { Tray } = process.electronBinding('tray')
|
const { Tray } = process.electronBinding('tray');
|
||||||
|
|
||||||
Object.setPrototypeOf(Tray.prototype, EventEmitter.prototype)
|
Object.setPrototypeOf(Tray.prototype, EventEmitter.prototype);
|
||||||
|
|
||||||
module.exports = Tray
|
module.exports = Tray;
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
'use strict'
|
'use strict';
|
||||||
|
|
||||||
const { EventEmitter } = require('events')
|
const { EventEmitter } = require('events');
|
||||||
const { View } = process.electronBinding('view')
|
const { View } = process.electronBinding('view');
|
||||||
|
|
||||||
Object.setPrototypeOf(View.prototype, EventEmitter.prototype)
|
Object.setPrototypeOf(View.prototype, EventEmitter.prototype);
|
||||||
|
|
||||||
View.prototype._init = function () {
|
View.prototype._init = function () {
|
||||||
}
|
};
|
||||||
|
|
||||||
module.exports = View
|
module.exports = View;
|
||||||
|
|||||||
@@ -1,15 +1,15 @@
|
|||||||
'use strict'
|
'use strict';
|
||||||
|
|
||||||
const electron = require('electron')
|
const electron = require('electron');
|
||||||
|
|
||||||
const { LayoutManager } = electron
|
const { LayoutManager } = electron;
|
||||||
const { BoxLayout } = process.electronBinding('box_layout')
|
const { BoxLayout } = process.electronBinding('box_layout');
|
||||||
|
|
||||||
Object.setPrototypeOf(BoxLayout.prototype, LayoutManager.prototype)
|
Object.setPrototypeOf(BoxLayout.prototype, LayoutManager.prototype);
|
||||||
|
|
||||||
BoxLayout.prototype._init = function () {
|
BoxLayout.prototype._init = function () {
|
||||||
// Call parent class's _init.
|
// Call parent class's _init.
|
||||||
LayoutManager.prototype._init.call(this)
|
LayoutManager.prototype._init.call(this);
|
||||||
}
|
};
|
||||||
|
|
||||||
module.exports = BoxLayout
|
module.exports = BoxLayout;
|
||||||
|
|||||||
@@ -1,15 +1,15 @@
|
|||||||
'use strict'
|
'use strict';
|
||||||
|
|
||||||
const electron = require('electron')
|
const electron = require('electron');
|
||||||
|
|
||||||
const { View } = electron
|
const { View } = electron;
|
||||||
const { Button } = process.electronBinding('button')
|
const { Button } = process.electronBinding('button');
|
||||||
|
|
||||||
Object.setPrototypeOf(Button.prototype, View.prototype)
|
Object.setPrototypeOf(Button.prototype, View.prototype);
|
||||||
|
|
||||||
Button.prototype._init = function () {
|
Button.prototype._init = function () {
|
||||||
// Call parent class's _init.
|
// Call parent class's _init.
|
||||||
View.prototype._init.call(this)
|
View.prototype._init.call(this);
|
||||||
}
|
};
|
||||||
|
|
||||||
module.exports = Button
|
module.exports = Button;
|
||||||
|
|||||||
@@ -1,15 +1,15 @@
|
|||||||
'use strict'
|
'use strict';
|
||||||
|
|
||||||
const electron = require('electron')
|
const electron = require('electron');
|
||||||
|
|
||||||
const { Button } = electron
|
const { Button } = electron;
|
||||||
const { LabelButton } = process.electronBinding('label_button')
|
const { LabelButton } = process.electronBinding('label_button');
|
||||||
|
|
||||||
Object.setPrototypeOf(LabelButton.prototype, Button.prototype)
|
Object.setPrototypeOf(LabelButton.prototype, Button.prototype);
|
||||||
|
|
||||||
LabelButton.prototype._init = function () {
|
LabelButton.prototype._init = function () {
|
||||||
// Call parent class's _init.
|
// Call parent class's _init.
|
||||||
Button.prototype._init.call(this)
|
Button.prototype._init.call(this);
|
||||||
}
|
};
|
||||||
|
|
||||||
module.exports = LabelButton
|
module.exports = LabelButton;
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
'use strict'
|
'use strict';
|
||||||
|
|
||||||
const { LayoutManager } = process.electronBinding('layout_manager')
|
const { LayoutManager } = process.electronBinding('layout_manager');
|
||||||
|
|
||||||
LayoutManager.prototype._init = function () {
|
LayoutManager.prototype._init = function () {
|
||||||
}
|
};
|
||||||
|
|
||||||
module.exports = LayoutManager
|
module.exports = LayoutManager;
|
||||||
|
|||||||
@@ -1,15 +1,15 @@
|
|||||||
'use strict'
|
'use strict';
|
||||||
|
|
||||||
const electron = require('electron')
|
const electron = require('electron');
|
||||||
|
|
||||||
const { LabelButton } = electron
|
const { LabelButton } = electron;
|
||||||
const { MdTextButton } = process.electronBinding('md_text_button')
|
const { MdTextButton } = process.electronBinding('md_text_button');
|
||||||
|
|
||||||
Object.setPrototypeOf(MdTextButton.prototype, LabelButton.prototype)
|
Object.setPrototypeOf(MdTextButton.prototype, LabelButton.prototype);
|
||||||
|
|
||||||
MdTextButton.prototype._init = function () {
|
MdTextButton.prototype._init = function () {
|
||||||
// Call parent class's _init.
|
// Call parent class's _init.
|
||||||
LabelButton.prototype._init.call(this)
|
LabelButton.prototype._init.call(this);
|
||||||
}
|
};
|
||||||
|
|
||||||
module.exports = MdTextButton
|
module.exports = MdTextButton;
|
||||||
|
|||||||
@@ -1,15 +1,15 @@
|
|||||||
'use strict'
|
'use strict';
|
||||||
|
|
||||||
const electron = require('electron')
|
const electron = require('electron');
|
||||||
|
|
||||||
const { View } = electron
|
const { View } = electron;
|
||||||
const { ResizeArea } = process.electronBinding('resize_area')
|
const { ResizeArea } = process.electronBinding('resize_area');
|
||||||
|
|
||||||
Object.setPrototypeOf(ResizeArea.prototype, View.prototype)
|
Object.setPrototypeOf(ResizeArea.prototype, View.prototype);
|
||||||
|
|
||||||
ResizeArea.prototype._init = function () {
|
ResizeArea.prototype._init = function () {
|
||||||
// Call parent class's _init.
|
// Call parent class's _init.
|
||||||
View.prototype._init.call(this)
|
View.prototype._init.call(this);
|
||||||
}
|
};
|
||||||
|
|
||||||
module.exports = ResizeArea
|
module.exports = ResizeArea;
|
||||||
|
|||||||
@@ -1,15 +1,15 @@
|
|||||||
'use strict'
|
'use strict';
|
||||||
|
|
||||||
const electron = require('electron')
|
const electron = require('electron');
|
||||||
|
|
||||||
const { View } = electron
|
const { View } = electron;
|
||||||
const { TextField } = process.electronBinding('text_field')
|
const { TextField } = process.electronBinding('text_field');
|
||||||
|
|
||||||
Object.setPrototypeOf(TextField.prototype, View.prototype)
|
Object.setPrototypeOf(TextField.prototype, View.prototype);
|
||||||
|
|
||||||
TextField.prototype._init = function () {
|
TextField.prototype._init = function () {
|
||||||
// Call parent class's _init.
|
// Call parent class's _init.
|
||||||
View.prototype._init.call(this)
|
View.prototype._init.call(this);
|
||||||
}
|
};
|
||||||
|
|
||||||
module.exports = TextField
|
module.exports = TextField;
|
||||||
|
|||||||
@@ -1,15 +1,15 @@
|
|||||||
'use strict'
|
'use strict';
|
||||||
|
|
||||||
const electron = require('electron')
|
const electron = require('electron');
|
||||||
|
|
||||||
const { View } = electron
|
const { View } = electron;
|
||||||
const { WebContentsView } = process.electronBinding('web_contents_view')
|
const { WebContentsView } = process.electronBinding('web_contents_view');
|
||||||
|
|
||||||
Object.setPrototypeOf(WebContentsView.prototype, View.prototype)
|
Object.setPrototypeOf(WebContentsView.prototype, View.prototype);
|
||||||
|
|
||||||
WebContentsView.prototype._init = function () {
|
WebContentsView.prototype._init = function () {
|
||||||
// Call parent class's _init.
|
// Call parent class's _init.
|
||||||
View.prototype._init.call(this)
|
View.prototype._init.call(this);
|
||||||
}
|
};
|
||||||
|
|
||||||
module.exports = WebContentsView
|
module.exports = WebContentsView;
|
||||||
|
|||||||
@@ -1,25 +1,26 @@
|
|||||||
'use strict'
|
'use strict';
|
||||||
|
|
||||||
const features = process.electronBinding('features')
|
const features = process.electronBinding('features');
|
||||||
const { EventEmitter } = require('events')
|
const { EventEmitter } = require('events');
|
||||||
const electron = require('electron')
|
const electron = require('electron');
|
||||||
const path = require('path')
|
const path = require('path');
|
||||||
const url = require('url')
|
const url = require('url');
|
||||||
const { app, ipcMain, session, deprecate } = electron
|
const { app, ipcMain, session, deprecate } = electron;
|
||||||
|
|
||||||
const NavigationController = require('@electron/internal/browser/navigation-controller')
|
const { internalWindowOpen } = require('@electron/internal/browser/guest-window-manager');
|
||||||
const { ipcMainInternal } = require('@electron/internal/browser/ipc-main-internal')
|
const NavigationController = require('@electron/internal/browser/navigation-controller');
|
||||||
const ipcMainUtils = require('@electron/internal/browser/ipc-main-internal-utils')
|
const { ipcMainInternal } = require('@electron/internal/browser/ipc-main-internal');
|
||||||
|
const ipcMainUtils = require('@electron/internal/browser/ipc-main-internal-utils');
|
||||||
|
|
||||||
// session is not used here, the purpose is to make sure session is initalized
|
// session is not used here, the purpose is to make sure session is initalized
|
||||||
// before the webContents module.
|
// before the webContents module.
|
||||||
// eslint-disable-next-line
|
// eslint-disable-next-line
|
||||||
session
|
session
|
||||||
|
|
||||||
let nextId = 0
|
let nextId = 0;
|
||||||
const getNextId = function () {
|
const getNextId = function () {
|
||||||
return ++nextId
|
return ++nextId;
|
||||||
}
|
};
|
||||||
|
|
||||||
// Stock page sizes
|
// Stock page sizes
|
||||||
const PDFPageSizes = {
|
const PDFPageSizes = {
|
||||||
@@ -60,7 +61,7 @@ const PDFPageSizes = {
|
|||||||
width_microns: 279400,
|
width_microns: 279400,
|
||||||
custom_display_name: 'Tabloid'
|
custom_display_name: 'Tabloid'
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
// Default printing setting
|
// Default printing setting
|
||||||
const defaultPrintingSetting = {
|
const defaultPrintingSetting = {
|
||||||
@@ -71,7 +72,6 @@ const defaultPrintingSetting = {
|
|||||||
headerFooterEnabled: false,
|
headerFooterEnabled: false,
|
||||||
marginsType: 0,
|
marginsType: 0,
|
||||||
isFirstRequest: false,
|
isFirstRequest: false,
|
||||||
requestID: getNextId(),
|
|
||||||
previewUIID: 0,
|
previewUIID: 0,
|
||||||
previewModifiable: true,
|
previewModifiable: true,
|
||||||
printToPDF: true,
|
printToPDF: true,
|
||||||
@@ -91,83 +91,83 @@ const defaultPrintingSetting = {
|
|||||||
collate: true,
|
collate: true,
|
||||||
shouldPrintBackgrounds: false,
|
shouldPrintBackgrounds: false,
|
||||||
shouldPrintSelectionOnly: false
|
shouldPrintSelectionOnly: false
|
||||||
}
|
};
|
||||||
|
|
||||||
// JavaScript implementations of WebContents.
|
// JavaScript implementations of WebContents.
|
||||||
const binding = process.electronBinding('web_contents')
|
const binding = process.electronBinding('web_contents');
|
||||||
const { WebContents } = binding
|
const { WebContents } = binding;
|
||||||
|
|
||||||
Object.setPrototypeOf(NavigationController.prototype, EventEmitter.prototype)
|
Object.setPrototypeOf(NavigationController.prototype, EventEmitter.prototype);
|
||||||
Object.setPrototypeOf(WebContents.prototype, NavigationController.prototype)
|
Object.setPrototypeOf(WebContents.prototype, NavigationController.prototype);
|
||||||
|
|
||||||
// WebContents::send(channel, args..)
|
// WebContents::send(channel, args..)
|
||||||
// WebContents::sendToAll(channel, args..)
|
// WebContents::sendToAll(channel, args..)
|
||||||
WebContents.prototype.send = function (channel, ...args) {
|
WebContents.prototype.send = function (channel, ...args) {
|
||||||
if (typeof channel !== 'string') {
|
if (typeof channel !== 'string') {
|
||||||
throw new Error('Missing required channel argument')
|
throw new Error('Missing required channel argument');
|
||||||
}
|
}
|
||||||
|
|
||||||
const internal = false
|
const internal = false;
|
||||||
const sendToAll = false
|
const sendToAll = false;
|
||||||
|
|
||||||
return this._send(internal, sendToAll, channel, args)
|
return this._send(internal, sendToAll, channel, args);
|
||||||
}
|
};
|
||||||
|
|
||||||
WebContents.prototype.sendToAll = function (channel, ...args) {
|
WebContents.prototype.sendToAll = function (channel, ...args) {
|
||||||
if (typeof channel !== 'string') {
|
if (typeof channel !== 'string') {
|
||||||
throw new Error('Missing required channel argument')
|
throw new Error('Missing required channel argument');
|
||||||
}
|
}
|
||||||
|
|
||||||
const internal = false
|
const internal = false;
|
||||||
const sendToAll = true
|
const sendToAll = true;
|
||||||
|
|
||||||
return this._send(internal, sendToAll, channel, args)
|
return this._send(internal, sendToAll, channel, args);
|
||||||
}
|
};
|
||||||
|
|
||||||
WebContents.prototype._sendInternal = function (channel, ...args) {
|
WebContents.prototype._sendInternal = function (channel, ...args) {
|
||||||
if (typeof channel !== 'string') {
|
if (typeof channel !== 'string') {
|
||||||
throw new Error('Missing required channel argument')
|
throw new Error('Missing required channel argument');
|
||||||
}
|
}
|
||||||
|
|
||||||
const internal = true
|
const internal = true;
|
||||||
const sendToAll = false
|
const sendToAll = false;
|
||||||
|
|
||||||
return this._send(internal, sendToAll, channel, args)
|
return this._send(internal, sendToAll, channel, args);
|
||||||
}
|
};
|
||||||
WebContents.prototype._sendInternalToAll = function (channel, ...args) {
|
WebContents.prototype._sendInternalToAll = function (channel, ...args) {
|
||||||
if (typeof channel !== 'string') {
|
if (typeof channel !== 'string') {
|
||||||
throw new Error('Missing required channel argument')
|
throw new Error('Missing required channel argument');
|
||||||
}
|
}
|
||||||
|
|
||||||
const internal = true
|
const internal = true;
|
||||||
const sendToAll = true
|
const sendToAll = true;
|
||||||
|
|
||||||
return this._send(internal, sendToAll, channel, args)
|
return this._send(internal, sendToAll, channel, args);
|
||||||
}
|
};
|
||||||
WebContents.prototype.sendToFrame = function (frameId, channel, ...args) {
|
WebContents.prototype.sendToFrame = function (frameId, channel, ...args) {
|
||||||
if (typeof channel !== 'string') {
|
if (typeof channel !== 'string') {
|
||||||
throw new Error('Missing required channel argument')
|
throw new Error('Missing required channel argument');
|
||||||
} else if (typeof frameId !== 'number') {
|
} else if (typeof frameId !== 'number') {
|
||||||
throw new Error('Missing required frameId argument')
|
throw new Error('Missing required frameId argument');
|
||||||
}
|
}
|
||||||
|
|
||||||
const internal = false
|
const internal = false;
|
||||||
const sendToAll = false
|
const sendToAll = false;
|
||||||
|
|
||||||
return this._sendToFrame(internal, sendToAll, frameId, channel, args)
|
return this._sendToFrame(internal, sendToAll, frameId, channel, args);
|
||||||
}
|
};
|
||||||
WebContents.prototype._sendToFrameInternal = function (frameId, channel, ...args) {
|
WebContents.prototype._sendToFrameInternal = function (frameId, channel, ...args) {
|
||||||
if (typeof channel !== 'string') {
|
if (typeof channel !== 'string') {
|
||||||
throw new Error('Missing required channel argument')
|
throw new Error('Missing required channel argument');
|
||||||
} else if (typeof frameId !== 'number') {
|
} else if (typeof frameId !== 'number') {
|
||||||
throw new Error('Missing required frameId argument')
|
throw new Error('Missing required frameId argument');
|
||||||
}
|
}
|
||||||
|
|
||||||
const internal = true
|
const internal = true;
|
||||||
const sendToAll = false
|
const sendToAll = false;
|
||||||
|
|
||||||
return this._sendToFrame(internal, sendToAll, frameId, channel, args)
|
return this._sendToFrame(internal, sendToAll, frameId, channel, args);
|
||||||
}
|
};
|
||||||
|
|
||||||
// Following methods are mapped to webFrame.
|
// Following methods are mapped to webFrame.
|
||||||
const webFrameMethods = [
|
const webFrameMethods = [
|
||||||
@@ -176,59 +176,65 @@ const webFrameMethods = [
|
|||||||
'removeInsertedCSS',
|
'removeInsertedCSS',
|
||||||
'setLayoutZoomLevelLimits',
|
'setLayoutZoomLevelLimits',
|
||||||
'setVisualZoomLevelLimits'
|
'setVisualZoomLevelLimits'
|
||||||
]
|
];
|
||||||
|
|
||||||
for (const method of webFrameMethods) {
|
for (const method of webFrameMethods) {
|
||||||
WebContents.prototype[method] = function (...args) {
|
WebContents.prototype[method] = function (...args) {
|
||||||
return ipcMainUtils.invokeInWebContents(this, false, 'ELECTRON_INTERNAL_RENDERER_WEB_FRAME_METHOD', method, ...args)
|
return ipcMainUtils.invokeInWebContents(this, false, 'ELECTRON_INTERNAL_RENDERER_WEB_FRAME_METHOD', method, ...args);
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
const executeJavaScript = (contents, code, hasUserGesture) => {
|
const waitTillCanExecuteJavaScript = async (webContents) => {
|
||||||
return ipcMainUtils.invokeInWebContents(contents, false, 'ELECTRON_INTERNAL_RENDERER_WEB_FRAME_METHOD', 'executeJavaScript', code, hasUserGesture)
|
if (webContents.getURL() && !webContents.isLoadingMainFrame()) return;
|
||||||
}
|
|
||||||
|
return new Promise((resolve) => {
|
||||||
|
webContents.once('did-stop-loading', () => {
|
||||||
|
resolve();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
// Make sure WebContents::executeJavaScript would run the code only when the
|
// Make sure WebContents::executeJavaScript would run the code only when the
|
||||||
// WebContents has been loaded.
|
// WebContents has been loaded.
|
||||||
WebContents.prototype.executeJavaScript = function (code, hasUserGesture) {
|
WebContents.prototype.executeJavaScript = async function (code, hasUserGesture) {
|
||||||
if (this.getURL() && !this.isLoadingMainFrame()) {
|
await waitTillCanExecuteJavaScript(this);
|
||||||
return executeJavaScript(this, code, hasUserGesture)
|
return ipcMainUtils.invokeInWebContents(this, false, 'ELECTRON_INTERNAL_RENDERER_WEB_FRAME_METHOD', 'executeJavaScript', code, hasUserGesture);
|
||||||
} else {
|
};
|
||||||
return new Promise((resolve, reject) => {
|
WebContents.prototype.executeJavaScriptInIsolatedWorld = async function (code, hasUserGesture) {
|
||||||
this.once('did-stop-loading', () => {
|
await waitTillCanExecuteJavaScript(this);
|
||||||
executeJavaScript(this, code, hasUserGesture).then(resolve, reject)
|
return ipcMainUtils.invokeInWebContents(this, false, 'ELECTRON_INTERNAL_RENDERER_WEB_FRAME_METHOD', 'executeJavaScriptInIsolatedWorld', code, hasUserGesture);
|
||||||
})
|
};
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Translate the options of printToPDF.
|
// Translate the options of printToPDF.
|
||||||
WebContents.prototype.printToPDF = function (options) {
|
WebContents.prototype.printToPDF = function (options) {
|
||||||
const printingSetting = Object.assign({}, defaultPrintingSetting)
|
const printingSetting = {
|
||||||
|
...defaultPrintingSetting,
|
||||||
|
requestID: getNextId()
|
||||||
|
};
|
||||||
if (options.landscape) {
|
if (options.landscape) {
|
||||||
printingSetting.landscape = options.landscape
|
printingSetting.landscape = options.landscape;
|
||||||
}
|
}
|
||||||
if (options.fitToPageEnabled) {
|
if (options.fitToPageEnabled) {
|
||||||
printingSetting.fitToPageEnabled = options.fitToPageEnabled
|
printingSetting.fitToPageEnabled = options.fitToPageEnabled;
|
||||||
}
|
}
|
||||||
if (options.scaleFactor) {
|
if (options.scaleFactor) {
|
||||||
printingSetting.scaleFactor = options.scaleFactor
|
printingSetting.scaleFactor = options.scaleFactor;
|
||||||
}
|
}
|
||||||
if (options.marginsType) {
|
if (options.marginsType) {
|
||||||
printingSetting.marginsType = options.marginsType
|
printingSetting.marginsType = options.marginsType;
|
||||||
}
|
}
|
||||||
if (options.printSelectionOnly) {
|
if (options.printSelectionOnly) {
|
||||||
printingSetting.shouldPrintSelectionOnly = options.printSelectionOnly
|
printingSetting.shouldPrintSelectionOnly = options.printSelectionOnly;
|
||||||
}
|
}
|
||||||
if (options.printBackground) {
|
if (options.printBackground) {
|
||||||
printingSetting.shouldPrintBackgrounds = options.printBackground
|
printingSetting.shouldPrintBackgrounds = options.printBackground;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (options.pageSize) {
|
if (options.pageSize) {
|
||||||
const pageSize = options.pageSize
|
const pageSize = options.pageSize;
|
||||||
if (typeof pageSize === 'object') {
|
if (typeof pageSize === 'object') {
|
||||||
if (!pageSize.height || !pageSize.width) {
|
if (!pageSize.height || !pageSize.width) {
|
||||||
return Promise.reject(new Error('Must define height and width for pageSize'))
|
return Promise.reject(new Error('Must define height and width for pageSize'));
|
||||||
}
|
}
|
||||||
// Dimensions in Microns
|
// Dimensions in Microns
|
||||||
// 1 meter = 10^6 microns
|
// 1 meter = 10^6 microns
|
||||||
@@ -237,46 +243,49 @@ WebContents.prototype.printToPDF = function (options) {
|
|||||||
custom_display_name: 'Custom',
|
custom_display_name: 'Custom',
|
||||||
height_microns: Math.ceil(pageSize.height),
|
height_microns: Math.ceil(pageSize.height),
|
||||||
width_microns: Math.ceil(pageSize.width)
|
width_microns: Math.ceil(pageSize.width)
|
||||||
}
|
};
|
||||||
} else if (PDFPageSizes[pageSize]) {
|
} else if (PDFPageSizes[pageSize]) {
|
||||||
printingSetting.mediaSize = PDFPageSizes[pageSize]
|
printingSetting.mediaSize = PDFPageSizes[pageSize];
|
||||||
} else {
|
} else {
|
||||||
return Promise.reject(new Error(`Does not support pageSize with ${pageSize}`))
|
return Promise.reject(new Error(`Does not support pageSize with ${pageSize}`));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
printingSetting.mediaSize = PDFPageSizes['A4']
|
printingSetting.mediaSize = PDFPageSizes['A4'];
|
||||||
}
|
}
|
||||||
|
|
||||||
// Chromium expects this in a 0-100 range number, not as float
|
// Chromium expects this in a 0-100 range number, not as float
|
||||||
printingSetting.scaleFactor = Math.ceil(printingSetting.scaleFactor) % 100
|
printingSetting.scaleFactor = Math.ceil(printingSetting.scaleFactor) % 100;
|
||||||
|
// PrinterType enum from //printing/print_job_constants.h
|
||||||
|
printingSetting.printerType = 2;
|
||||||
if (features.isPrintingEnabled()) {
|
if (features.isPrintingEnabled()) {
|
||||||
return this._printToPDF(printingSetting)
|
return this._printToPDF(printingSetting);
|
||||||
} else {
|
} else {
|
||||||
return Promise.reject(new Error('Printing feature is disabled'))
|
return Promise.reject(new Error('Printing feature is disabled'));
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
WebContents.prototype.print = function (...args) {
|
WebContents.prototype.print = function (...args) {
|
||||||
if (features.isPrintingEnabled()) {
|
if (features.isPrintingEnabled()) {
|
||||||
this._print(...args)
|
this._print(...args);
|
||||||
} else {
|
} else {
|
||||||
console.error('Error: Printing feature is disabled.')
|
console.error('Error: Printing feature is disabled.');
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
WebContents.prototype.getPrinters = function () {
|
WebContents.prototype.getPrinters = function () {
|
||||||
if (features.isPrintingEnabled()) {
|
if (features.isPrintingEnabled()) {
|
||||||
return this._getPrinters()
|
return this._getPrinters();
|
||||||
} else {
|
} else {
|
||||||
console.error('Error: Printing feature is disabled.')
|
console.error('Error: Printing feature is disabled.');
|
||||||
|
return [];
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
WebContents.prototype.loadFile = function (filePath, options = {}) {
|
WebContents.prototype.loadFile = function (filePath, options = {}) {
|
||||||
if (typeof filePath !== 'string') {
|
if (typeof filePath !== 'string') {
|
||||||
throw new Error('Must pass filePath as a string')
|
throw new Error('Must pass filePath as a string');
|
||||||
}
|
}
|
||||||
const { query, search, hash } = options
|
const { query, search, hash } = options;
|
||||||
|
|
||||||
return this.loadURL(url.format({
|
return this.loadURL(url.format({
|
||||||
protocol: 'file',
|
protocol: 'file',
|
||||||
@@ -285,99 +294,105 @@ WebContents.prototype.loadFile = function (filePath, options = {}) {
|
|||||||
query,
|
query,
|
||||||
search,
|
search,
|
||||||
hash
|
hash
|
||||||
}))
|
}));
|
||||||
}
|
};
|
||||||
|
|
||||||
const addReplyToEvent = (event) => {
|
const addReplyToEvent = (event) => {
|
||||||
event.reply = (...args) => {
|
event.reply = (...args) => {
|
||||||
event.sender.sendToFrame(event.frameId, ...args)
|
event.sender.sendToFrame(event.frameId, ...args);
|
||||||
}
|
};
|
||||||
}
|
};
|
||||||
|
|
||||||
const addReplyInternalToEvent = (event) => {
|
const addReplyInternalToEvent = (event) => {
|
||||||
Object.defineProperty(event, '_replyInternal', {
|
Object.defineProperty(event, '_replyInternal', {
|
||||||
configurable: false,
|
configurable: false,
|
||||||
enumerable: false,
|
enumerable: false,
|
||||||
value: (...args) => {
|
value: (...args) => {
|
||||||
event.sender._sendToFrameInternal(event.frameId, ...args)
|
event.sender._sendToFrameInternal(event.frameId, ...args);
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
const addReturnValueToEvent = (event) => {
|
const addReturnValueToEvent = (event) => {
|
||||||
Object.defineProperty(event, 'returnValue', {
|
Object.defineProperty(event, 'returnValue', {
|
||||||
set: (value) => event.sendReply([value]),
|
set: (value) => event.sendReply([value]),
|
||||||
get: () => {}
|
get: () => {}
|
||||||
})
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
|
let warnedAboutRendererProcessReuse = false;
|
||||||
|
|
||||||
// Add JavaScript wrappers for WebContents class.
|
// Add JavaScript wrappers for WebContents class.
|
||||||
WebContents.prototype._init = function () {
|
WebContents.prototype._init = function () {
|
||||||
|
if (!process.noDeprecation && !warnedAboutRendererProcessReuse && app._allowRendererProcessReuseIsDefaultValue) {
|
||||||
|
deprecate.log('The default value of app.allowRendererProcessReuse is deprecated, it is currently "false". It will change to be "true" in Electron 9. For more information please check https://github.com/electron/electron/issues/18397');
|
||||||
|
warnedAboutRendererProcessReuse = true;
|
||||||
|
}
|
||||||
// The navigation controller.
|
// The navigation controller.
|
||||||
NavigationController.call(this, this)
|
NavigationController.call(this, this);
|
||||||
|
|
||||||
// Every remote callback from renderer process would add a listener to the
|
// Every remote callback from renderer process would add a listener to the
|
||||||
// render-view-deleted event, so ignore the listeners warning.
|
// render-view-deleted event, so ignore the listeners warning.
|
||||||
this.setMaxListeners(0)
|
this.setMaxListeners(0);
|
||||||
|
|
||||||
// Dispatch IPC messages to the ipc module.
|
// Dispatch IPC messages to the ipc module.
|
||||||
this.on('-ipc-message', function (event, internal, channel, args) {
|
this.on('-ipc-message', function (event, internal, channel, args) {
|
||||||
if (internal) {
|
if (internal) {
|
||||||
addReplyInternalToEvent(event)
|
addReplyInternalToEvent(event);
|
||||||
ipcMainInternal.emit(channel, event, ...args)
|
ipcMainInternal.emit(channel, event, ...args);
|
||||||
} else {
|
} else {
|
||||||
addReplyToEvent(event)
|
addReplyToEvent(event);
|
||||||
this.emit('ipc-message', event, channel, ...args)
|
this.emit('ipc-message', event, channel, ...args);
|
||||||
ipcMain.emit(channel, event, ...args)
|
ipcMain.emit(channel, event, ...args);
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
|
|
||||||
this.on('-ipc-invoke', function (event, internal, channel, args) {
|
this.on('-ipc-invoke', function (event, internal, channel, args) {
|
||||||
event._reply = (result) => event.sendReply({ result })
|
event._reply = (result) => event.sendReply({ result });
|
||||||
event._throw = (error) => {
|
event._throw = (error) => {
|
||||||
console.error(`Error occurred in handler for '${channel}':`, error)
|
console.error(`Error occurred in handler for '${channel}':`, error);
|
||||||
event.sendReply({ error: error.toString() })
|
event.sendReply({ error: error.toString() });
|
||||||
}
|
};
|
||||||
const target = internal ? ipcMainInternal : ipcMain
|
const target = internal ? ipcMainInternal : ipcMain;
|
||||||
if (target._invokeHandlers.has(channel)) {
|
if (target._invokeHandlers.has(channel)) {
|
||||||
target._invokeHandlers.get(channel)(event, ...args)
|
target._invokeHandlers.get(channel)(event, ...args);
|
||||||
} else {
|
} else {
|
||||||
event._throw(`No handler registered for '${channel}'`)
|
event._throw(`No handler registered for '${channel}'`);
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
|
|
||||||
this.on('-ipc-message-sync', function (event, internal, channel, args) {
|
this.on('-ipc-message-sync', function (event, internal, channel, args) {
|
||||||
addReturnValueToEvent(event)
|
addReturnValueToEvent(event);
|
||||||
if (internal) {
|
if (internal) {
|
||||||
addReplyInternalToEvent(event)
|
addReplyInternalToEvent(event);
|
||||||
ipcMainInternal.emit(channel, event, ...args)
|
ipcMainInternal.emit(channel, event, ...args);
|
||||||
} else {
|
} else {
|
||||||
addReplyToEvent(event)
|
addReplyToEvent(event);
|
||||||
this.emit('ipc-message-sync', event, channel, ...args)
|
this.emit('ipc-message-sync', event, channel, ...args);
|
||||||
ipcMain.emit(channel, event, ...args)
|
ipcMain.emit(channel, event, ...args);
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
|
|
||||||
// Handle context menu action request from pepper plugin.
|
// Handle context menu action request from pepper plugin.
|
||||||
this.on('pepper-context-menu', function (event, params, callback) {
|
this.on('pepper-context-menu', function (event, params, callback) {
|
||||||
// Access Menu via electron.Menu to prevent circular require.
|
// Access Menu via electron.Menu to prevent circular require.
|
||||||
const menu = electron.Menu.buildFromTemplate(params.menu)
|
const menu = electron.Menu.buildFromTemplate(params.menu);
|
||||||
menu.popup({
|
menu.popup({
|
||||||
window: event.sender.getOwnerBrowserWindow(),
|
window: event.sender.getOwnerBrowserWindow(),
|
||||||
x: params.x,
|
x: params.x,
|
||||||
y: params.y,
|
y: params.y,
|
||||||
callback
|
callback
|
||||||
})
|
});
|
||||||
})
|
});
|
||||||
|
|
||||||
this.on('crashed', (event, ...args) => {
|
this.on('crashed', (event, ...args) => {
|
||||||
app.emit('renderer-process-crashed', event, this, ...args)
|
app.emit('renderer-process-crashed', event, this, ...args);
|
||||||
})
|
});
|
||||||
|
|
||||||
// The devtools requests the webContents to reload.
|
// The devtools requests the webContents to reload.
|
||||||
this.on('devtools-reload-page', function () {
|
this.on('devtools-reload-page', function () {
|
||||||
this.reload()
|
this.reload();
|
||||||
})
|
});
|
||||||
|
|
||||||
// Handle window.open for BrowserWindow and BrowserView.
|
// Handle window.open for BrowserWindow and BrowserView.
|
||||||
if (['browserView', 'window'].includes(this.getType())) {
|
if (['browserView', 'window'].includes(this.getType())) {
|
||||||
@@ -389,11 +404,9 @@ WebContents.prototype._init = function () {
|
|||||||
show: true,
|
show: true,
|
||||||
width: 800,
|
width: 800,
|
||||||
height: 600
|
height: 600
|
||||||
}
|
};
|
||||||
ipcMainInternal.emit('ELECTRON_GUEST_WINDOW_MANAGER_INTERNAL_WINDOW_OPEN',
|
internalWindowOpen(event, url, referrer, frameName, disposition, options, additionalFeatures, postData);
|
||||||
event, url, referrer, frameName, disposition,
|
});
|
||||||
options, additionalFeatures, postData)
|
|
||||||
})
|
|
||||||
|
|
||||||
// Create a new browser window for the native implementation of
|
// Create a new browser window for the native implementation of
|
||||||
// "window.open", used in sandbox and nativeWindowOpen mode.
|
// "window.open", used in sandbox and nativeWindowOpen mode.
|
||||||
@@ -401,8 +414,8 @@ WebContents.prototype._init = function () {
|
|||||||
userGesture, left, top, width, height, url, frameName) => {
|
userGesture, left, top, width, height, url, frameName) => {
|
||||||
if ((disposition !== 'foreground-tab' && disposition !== 'new-window' &&
|
if ((disposition !== 'foreground-tab' && disposition !== 'new-window' &&
|
||||||
disposition !== 'background-tab')) {
|
disposition !== 'background-tab')) {
|
||||||
event.preventDefault()
|
event.preventDefault();
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const options = {
|
const options = {
|
||||||
@@ -412,51 +425,54 @@ WebContents.prototype._init = function () {
|
|||||||
width: width || 800,
|
width: width || 800,
|
||||||
height: height || 600,
|
height: height || 600,
|
||||||
webContents
|
webContents
|
||||||
}
|
};
|
||||||
const referrer = { url: '', policy: 'default' }
|
const referrer = { url: '', policy: 'default' };
|
||||||
ipcMainInternal.emit('ELECTRON_GUEST_WINDOW_MANAGER_INTERNAL_WINDOW_OPEN',
|
internalWindowOpen(event, url, referrer, frameName, disposition, options);
|
||||||
event, url, referrer, frameName, disposition, options)
|
});
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const event = process.electronBinding('event').createEmpty()
|
this.on('login', (event, ...args) => {
|
||||||
app.emit('web-contents-created', event, this)
|
app.emit('login', event, this, ...args);
|
||||||
}
|
});
|
||||||
|
|
||||||
|
const event = process.electronBinding('event').createEmpty();
|
||||||
|
app.emit('web-contents-created', event, this);
|
||||||
|
};
|
||||||
|
|
||||||
// Deprecations
|
// Deprecations
|
||||||
deprecate.fnToProperty(WebContents.prototype, 'audioMuted', '_isAudioMuted', '_setAudioMuted')
|
deprecate.fnToProperty(WebContents.prototype, 'audioMuted', '_isAudioMuted', '_setAudioMuted');
|
||||||
deprecate.fnToProperty(WebContents.prototype, 'userAgent', '_getUserAgent', '_setUserAgent')
|
deprecate.fnToProperty(WebContents.prototype, 'userAgent', '_getUserAgent', '_setUserAgent');
|
||||||
deprecate.fnToProperty(WebContents.prototype, 'zoomLevel', '_getZoomLevel', '_setZoomLevel')
|
deprecate.fnToProperty(WebContents.prototype, 'zoomLevel', '_getZoomLevel', '_setZoomLevel');
|
||||||
deprecate.fnToProperty(WebContents.prototype, 'zoomFactor', '_getZoomFactor', '_setZoomFactor')
|
deprecate.fnToProperty(WebContents.prototype, 'zoomFactor', '_getZoomFactor', '_setZoomFactor');
|
||||||
deprecate.fnToProperty(WebContents.prototype, 'frameRate', '_getFrameRate', '_setFrameRate')
|
deprecate.fnToProperty(WebContents.prototype, 'frameRate', '_getFrameRate', '_setFrameRate');
|
||||||
|
|
||||||
// JavaScript wrapper of Debugger.
|
// JavaScript wrapper of Debugger.
|
||||||
const { Debugger } = process.electronBinding('debugger')
|
const { Debugger } = process.electronBinding('debugger');
|
||||||
Object.setPrototypeOf(Debugger.prototype, EventEmitter.prototype)
|
Object.setPrototypeOf(Debugger.prototype, EventEmitter.prototype);
|
||||||
|
|
||||||
// Public APIs.
|
// Public APIs.
|
||||||
module.exports = {
|
module.exports = {
|
||||||
create (options = {}) {
|
create (options = {}) {
|
||||||
return binding.create(options)
|
return binding.create(options);
|
||||||
},
|
},
|
||||||
|
|
||||||
fromId (id) {
|
fromId (id) {
|
||||||
return binding.fromId(id)
|
return binding.fromId(id);
|
||||||
},
|
},
|
||||||
|
|
||||||
getFocusedWebContents () {
|
getFocusedWebContents () {
|
||||||
let focused = null
|
let focused = null;
|
||||||
for (const contents of binding.getAllWebContents()) {
|
for (const contents of binding.getAllWebContents()) {
|
||||||
if (!contents.isFocused()) continue
|
if (!contents.isFocused()) continue;
|
||||||
if (focused == null) focused = contents
|
if (focused == null) focused = contents;
|
||||||
// Return webview web contents which may be embedded inside another
|
// Return webview web contents which may be embedded inside another
|
||||||
// web contents that is also reporting as focused
|
// web contents that is also reporting as focused
|
||||||
if (contents.getType() === 'webview') return contents
|
if (contents.getType() === 'webview') return contents;
|
||||||
}
|
}
|
||||||
return focused
|
return focused;
|
||||||
},
|
},
|
||||||
|
|
||||||
getAllWebContents () {
|
getAllWebContents () {
|
||||||
return binding.getAllWebContents()
|
return binding.getAllWebContents();
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|||||||
@@ -1,62 +1,62 @@
|
|||||||
'use strict'
|
'use strict';
|
||||||
|
|
||||||
if (process.electronBinding('features').isExtensionsEnabled()) {
|
if (process.electronBinding('features').isExtensionsEnabled()) {
|
||||||
throw new Error('Attempted to load JS chrome-extension polyfill with //extensions support enabled')
|
throw new Error('Attempted to load JS chrome-extension polyfill with //extensions support enabled');
|
||||||
}
|
}
|
||||||
|
|
||||||
const { app, webContents, BrowserWindow } = require('electron')
|
const { app, webContents, BrowserWindow } = require('electron');
|
||||||
const { getAllWebContents } = process.electronBinding('web_contents')
|
const { getAllWebContents } = process.electronBinding('web_contents');
|
||||||
const { ipcMainInternal } = require('@electron/internal/browser/ipc-main-internal')
|
const { ipcMainInternal } = require('@electron/internal/browser/ipc-main-internal');
|
||||||
const ipcMainUtils = require('@electron/internal/browser/ipc-main-internal-utils')
|
const ipcMainUtils = require('@electron/internal/browser/ipc-main-internal-utils');
|
||||||
|
|
||||||
const { Buffer } = require('buffer')
|
const { Buffer } = require('buffer');
|
||||||
const fs = require('fs')
|
const fs = require('fs');
|
||||||
const path = require('path')
|
const path = require('path');
|
||||||
const url = require('url')
|
const url = require('url');
|
||||||
const util = require('util')
|
const util = require('util');
|
||||||
|
|
||||||
// Mapping between extensionId(hostname) and manifest.
|
// Mapping between extensionId(hostname) and manifest.
|
||||||
const manifestMap = {} // extensionId => manifest
|
const manifestMap = {}; // extensionId => manifest
|
||||||
const manifestNameMap = {} // name => manifest
|
const manifestNameMap = {}; // name => manifest
|
||||||
const devToolsExtensionNames = new Set()
|
const devToolsExtensionNames = new Set();
|
||||||
|
|
||||||
const generateExtensionIdFromName = function (name) {
|
const generateExtensionIdFromName = function (name) {
|
||||||
return name.replace(/[\W_]+/g, '-').toLowerCase()
|
return name.replace(/[\W_]+/g, '-').toLowerCase();
|
||||||
}
|
};
|
||||||
|
|
||||||
const isWindowOrWebView = function (webContents) {
|
const isWindowOrWebView = function (webContents) {
|
||||||
const type = webContents.getType()
|
const type = webContents.getType();
|
||||||
return type === 'window' || type === 'webview'
|
return type === 'window' || type === 'webview';
|
||||||
}
|
};
|
||||||
|
|
||||||
const isBackgroundPage = function (webContents) {
|
const isBackgroundPage = function (webContents) {
|
||||||
return webContents.getType() === 'backgroundPage'
|
return webContents.getType() === 'backgroundPage';
|
||||||
}
|
};
|
||||||
|
|
||||||
// Create or get manifest object from |srcDirectory|.
|
// Create or get manifest object from |srcDirectory|.
|
||||||
const getManifestFromPath = function (srcDirectory) {
|
const getManifestFromPath = function (srcDirectory) {
|
||||||
let manifest
|
let manifest;
|
||||||
let manifestContent
|
let manifestContent;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
manifestContent = fs.readFileSync(path.join(srcDirectory, 'manifest.json'))
|
manifestContent = fs.readFileSync(path.join(srcDirectory, 'manifest.json'));
|
||||||
} catch (readError) {
|
} catch (readError) {
|
||||||
console.warn(`Reading ${path.join(srcDirectory, 'manifest.json')} failed.`)
|
console.warn(`Reading ${path.join(srcDirectory, 'manifest.json')} failed.`);
|
||||||
console.warn(readError.stack || readError)
|
console.warn(readError.stack || readError);
|
||||||
throw readError
|
throw readError;
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
manifest = JSON.parse(manifestContent)
|
manifest = JSON.parse(manifestContent);
|
||||||
} catch (parseError) {
|
} catch (parseError) {
|
||||||
console.warn(`Parsing ${path.join(srcDirectory, 'manifest.json')} failed.`)
|
console.warn(`Parsing ${path.join(srcDirectory, 'manifest.json')} failed.`);
|
||||||
console.warn(parseError.stack || parseError)
|
console.warn(parseError.stack || parseError);
|
||||||
throw parseError
|
throw parseError;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!manifestNameMap[manifest.name]) {
|
if (!manifestNameMap[manifest.name]) {
|
||||||
const extensionId = generateExtensionIdFromName(manifest.name)
|
const extensionId = generateExtensionIdFromName(manifest.name);
|
||||||
manifestMap[extensionId] = manifestNameMap[manifest.name] = manifest
|
manifestMap[extensionId] = manifestNameMap[manifest.name] = manifest;
|
||||||
Object.assign(manifest, {
|
Object.assign(manifest, {
|
||||||
srcDirectory: srcDirectory,
|
srcDirectory: srcDirectory,
|
||||||
extensionId: extensionId,
|
extensionId: extensionId,
|
||||||
@@ -68,31 +68,31 @@ const getManifestFromPath = function (srcDirectory) {
|
|||||||
hostname: extensionId,
|
hostname: extensionId,
|
||||||
pathname: manifest.devtools_page
|
pathname: manifest.devtools_page
|
||||||
})
|
})
|
||||||
})
|
});
|
||||||
return manifest
|
return manifest;
|
||||||
} else if (manifest && manifest.name) {
|
} else if (manifest && manifest.name) {
|
||||||
console.warn(`Attempted to load extension "${manifest.name}" that has already been loaded.`)
|
console.warn(`Attempted to load extension "${manifest.name}" that has already been loaded.`);
|
||||||
return manifest
|
return manifest;
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
// Manage the background pages.
|
// Manage the background pages.
|
||||||
const backgroundPages = {}
|
const backgroundPages = {};
|
||||||
|
|
||||||
const startBackgroundPages = function (manifest) {
|
const startBackgroundPages = function (manifest) {
|
||||||
if (backgroundPages[manifest.extensionId] || !manifest.background) return
|
if (backgroundPages[manifest.extensionId] || !manifest.background) return;
|
||||||
|
|
||||||
let html
|
let html;
|
||||||
let name
|
let name;
|
||||||
if (manifest.background.page) {
|
if (manifest.background.page) {
|
||||||
name = manifest.background.page
|
name = manifest.background.page;
|
||||||
html = fs.readFileSync(path.join(manifest.srcDirectory, manifest.background.page))
|
html = fs.readFileSync(path.join(manifest.srcDirectory, manifest.background.page));
|
||||||
} else {
|
} else {
|
||||||
name = '_generated_background_page.html'
|
name = '_generated_background_page.html';
|
||||||
const scripts = manifest.background.scripts.map((name) => {
|
const scripts = manifest.background.scripts.map((name) => {
|
||||||
return `<script src="${name}"></script>`
|
return `<script src="${name}"></script>`;
|
||||||
}).join('')
|
}).join('');
|
||||||
html = Buffer.from(`<html><body>${scripts}</body></html>`)
|
html = Buffer.from(`<html><body>${scripts}</body></html>`);
|
||||||
}
|
}
|
||||||
|
|
||||||
const contents = webContents.create({
|
const contents = webContents.create({
|
||||||
@@ -100,36 +100,36 @@ const startBackgroundPages = function (manifest) {
|
|||||||
type: 'backgroundPage',
|
type: 'backgroundPage',
|
||||||
sandbox: true,
|
sandbox: true,
|
||||||
enableRemoteModule: false
|
enableRemoteModule: false
|
||||||
})
|
});
|
||||||
backgroundPages[manifest.extensionId] = { html: html, webContents: contents, name: name }
|
backgroundPages[manifest.extensionId] = { html: html, webContents: contents, name: name };
|
||||||
contents.loadURL(url.format({
|
contents.loadURL(url.format({
|
||||||
protocol: 'chrome-extension',
|
protocol: 'chrome-extension',
|
||||||
slashes: true,
|
slashes: true,
|
||||||
hostname: manifest.extensionId,
|
hostname: manifest.extensionId,
|
||||||
pathname: name
|
pathname: name
|
||||||
}))
|
}));
|
||||||
}
|
};
|
||||||
|
|
||||||
const removeBackgroundPages = function (manifest) {
|
const removeBackgroundPages = function (manifest) {
|
||||||
if (!backgroundPages[manifest.extensionId]) return
|
if (!backgroundPages[manifest.extensionId]) return;
|
||||||
|
|
||||||
backgroundPages[manifest.extensionId].webContents.destroy()
|
backgroundPages[manifest.extensionId].webContents.destroy();
|
||||||
delete backgroundPages[manifest.extensionId]
|
delete backgroundPages[manifest.extensionId];
|
||||||
}
|
};
|
||||||
|
|
||||||
const sendToBackgroundPages = function (...args) {
|
const sendToBackgroundPages = function (...args) {
|
||||||
for (const page of Object.values(backgroundPages)) {
|
for (const page of Object.values(backgroundPages)) {
|
||||||
if (!page.webContents.isDestroyed()) {
|
if (!page.webContents.isDestroyed()) {
|
||||||
page.webContents._sendInternalToAll(...args)
|
page.webContents._sendInternalToAll(...args);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
// Dispatch web contents events to Chrome APIs
|
// Dispatch web contents events to Chrome APIs
|
||||||
const hookWebContentsEvents = function (webContents) {
|
const hookWebContentsEvents = function (webContents) {
|
||||||
const tabId = webContents.id
|
const tabId = webContents.id;
|
||||||
|
|
||||||
sendToBackgroundPages('CHROME_TABS_ONCREATED')
|
sendToBackgroundPages('CHROME_TABS_ONCREATED');
|
||||||
|
|
||||||
webContents.on('will-navigate', (event, url) => {
|
webContents.on('will-navigate', (event, url) => {
|
||||||
sendToBackgroundPages('CHROME_WEBNAVIGATION_ONBEFORENAVIGATE', {
|
sendToBackgroundPages('CHROME_WEBNAVIGATION_ONBEFORENAVIGATE', {
|
||||||
@@ -139,8 +139,8 @@ const hookWebContentsEvents = function (webContents) {
|
|||||||
tabId: tabId,
|
tabId: tabId,
|
||||||
timeStamp: Date.now(),
|
timeStamp: Date.now(),
|
||||||
url: url
|
url: url
|
||||||
})
|
});
|
||||||
})
|
});
|
||||||
|
|
||||||
webContents.on('did-navigate', (event, url) => {
|
webContents.on('did-navigate', (event, url) => {
|
||||||
sendToBackgroundPages('CHROME_WEBNAVIGATION_ONCOMPLETED', {
|
sendToBackgroundPages('CHROME_WEBNAVIGATION_ONCOMPLETED', {
|
||||||
@@ -150,189 +150,189 @@ const hookWebContentsEvents = function (webContents) {
|
|||||||
tabId: tabId,
|
tabId: tabId,
|
||||||
timeStamp: Date.now(),
|
timeStamp: Date.now(),
|
||||||
url: url
|
url: url
|
||||||
})
|
});
|
||||||
})
|
});
|
||||||
|
|
||||||
webContents.once('destroyed', () => {
|
webContents.once('destroyed', () => {
|
||||||
sendToBackgroundPages('CHROME_TABS_ONREMOVED', tabId)
|
sendToBackgroundPages('CHROME_TABS_ONREMOVED', tabId);
|
||||||
})
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
// Handle the chrome.* API messages.
|
// Handle the chrome.* API messages.
|
||||||
let nextId = 0
|
let nextId = 0;
|
||||||
|
|
||||||
ipcMainUtils.handleSync('CHROME_RUNTIME_CONNECT', function (event, extensionId, connectInfo) {
|
ipcMainUtils.handleSync('CHROME_RUNTIME_CONNECT', function (event, extensionId, connectInfo) {
|
||||||
if (isBackgroundPage(event.sender)) {
|
if (isBackgroundPage(event.sender)) {
|
||||||
throw new Error('chrome.runtime.connect is not supported in background page')
|
throw new Error('chrome.runtime.connect is not supported in background page');
|
||||||
}
|
}
|
||||||
|
|
||||||
const page = backgroundPages[extensionId]
|
const page = backgroundPages[extensionId];
|
||||||
if (!page || page.webContents.isDestroyed()) {
|
if (!page || page.webContents.isDestroyed()) {
|
||||||
throw new Error(`Connect to unknown extension ${extensionId}`)
|
throw new Error(`Connect to unknown extension ${extensionId}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
const tabId = page.webContents.id
|
const tabId = page.webContents.id;
|
||||||
const portId = ++nextId
|
const portId = ++nextId;
|
||||||
|
|
||||||
event.sender.once('render-view-deleted', () => {
|
event.sender.once('render-view-deleted', () => {
|
||||||
if (page.webContents.isDestroyed()) return
|
if (page.webContents.isDestroyed()) return;
|
||||||
page.webContents._sendInternalToAll(`CHROME_PORT_DISCONNECT_${portId}`)
|
page.webContents._sendInternalToAll(`CHROME_PORT_DISCONNECT_${portId}`);
|
||||||
})
|
});
|
||||||
page.webContents._sendInternalToAll(`CHROME_RUNTIME_ONCONNECT_${extensionId}`, event.sender.id, portId, connectInfo)
|
page.webContents._sendInternalToAll(`CHROME_RUNTIME_ONCONNECT_${extensionId}`, event.sender.id, portId, connectInfo);
|
||||||
|
|
||||||
return { tabId, portId }
|
return { tabId, portId };
|
||||||
})
|
});
|
||||||
|
|
||||||
ipcMainUtils.handleSync('CHROME_EXTENSION_MANIFEST', function (event, extensionId) {
|
ipcMainUtils.handleSync('CHROME_EXTENSION_MANIFEST', function (event, extensionId) {
|
||||||
const manifest = manifestMap[extensionId]
|
const manifest = manifestMap[extensionId];
|
||||||
if (!manifest) {
|
if (!manifest) {
|
||||||
throw new Error(`Invalid extensionId: ${extensionId}`)
|
throw new Error(`Invalid extensionId: ${extensionId}`);
|
||||||
}
|
}
|
||||||
return manifest
|
return manifest;
|
||||||
})
|
});
|
||||||
|
|
||||||
ipcMainInternal.handle('CHROME_RUNTIME_SEND_MESSAGE', async function (event, extensionId, message) {
|
ipcMainInternal.handle('CHROME_RUNTIME_SEND_MESSAGE', async function (event, extensionId, message) {
|
||||||
if (isBackgroundPage(event.sender)) {
|
if (isBackgroundPage(event.sender)) {
|
||||||
throw new Error('chrome.runtime.sendMessage is not supported in background page')
|
throw new Error('chrome.runtime.sendMessage is not supported in background page');
|
||||||
}
|
}
|
||||||
|
|
||||||
const page = backgroundPages[extensionId]
|
const page = backgroundPages[extensionId];
|
||||||
if (!page || page.webContents.isDestroyed()) {
|
if (!page || page.webContents.isDestroyed()) {
|
||||||
throw new Error(`Connect to unknown extension ${extensionId}`)
|
throw new Error(`Connect to unknown extension ${extensionId}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
return ipcMainUtils.invokeInWebContents(page.webContents, true, `CHROME_RUNTIME_ONMESSAGE_${extensionId}`, event.sender.id, message)
|
return ipcMainUtils.invokeInWebContents(page.webContents, true, `CHROME_RUNTIME_ONMESSAGE_${extensionId}`, event.sender.id, message);
|
||||||
})
|
});
|
||||||
|
|
||||||
ipcMainInternal.handle('CHROME_TABS_SEND_MESSAGE', async function (event, tabId, extensionId, message) {
|
ipcMainInternal.handle('CHROME_TABS_SEND_MESSAGE', async function (event, tabId, extensionId, message) {
|
||||||
const contents = webContents.fromId(tabId)
|
const contents = webContents.fromId(tabId);
|
||||||
if (!contents) {
|
if (!contents) {
|
||||||
throw new Error(`Sending message to unknown tab ${tabId}`)
|
throw new Error(`Sending message to unknown tab ${tabId}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
const senderTabId = isBackgroundPage(event.sender) ? null : event.sender.id
|
const senderTabId = isBackgroundPage(event.sender) ? null : event.sender.id;
|
||||||
|
|
||||||
return ipcMainUtils.invokeInWebContents(contents, true, `CHROME_RUNTIME_ONMESSAGE_${extensionId}`, senderTabId, message)
|
return ipcMainUtils.invokeInWebContents(contents, true, `CHROME_RUNTIME_ONMESSAGE_${extensionId}`, senderTabId, message);
|
||||||
})
|
});
|
||||||
|
|
||||||
const getLanguage = () => {
|
const getLanguage = () => {
|
||||||
return app.getLocale().replace(/-.*$/, '').toLowerCase()
|
return app.getLocale().replace(/-.*$/, '').toLowerCase();
|
||||||
}
|
};
|
||||||
|
|
||||||
const getMessagesPath = (extensionId) => {
|
const getMessagesPath = (extensionId) => {
|
||||||
const metadata = manifestMap[extensionId]
|
const metadata = manifestMap[extensionId];
|
||||||
if (!metadata) {
|
if (!metadata) {
|
||||||
throw new Error(`Invalid extensionId: ${extensionId}`)
|
throw new Error(`Invalid extensionId: ${extensionId}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
const localesDirectory = path.join(metadata.srcDirectory, '_locales')
|
const localesDirectory = path.join(metadata.srcDirectory, '_locales');
|
||||||
const language = getLanguage()
|
const language = getLanguage();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const filename = path.join(localesDirectory, language, 'messages.json')
|
const filename = path.join(localesDirectory, language, 'messages.json');
|
||||||
fs.accessSync(filename, fs.constants.R_OK)
|
fs.accessSync(filename, fs.constants.R_OK);
|
||||||
return filename
|
return filename;
|
||||||
} catch {
|
} catch {
|
||||||
const defaultLocale = metadata.default_locale || 'en'
|
const defaultLocale = metadata.default_locale || 'en';
|
||||||
return path.join(localesDirectory, defaultLocale, 'messages.json')
|
return path.join(localesDirectory, defaultLocale, 'messages.json');
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
ipcMainUtils.handleSync('CHROME_GET_MESSAGES', async function (event, extensionId) {
|
ipcMainUtils.handleSync('CHROME_GET_MESSAGES', async function (event, extensionId) {
|
||||||
const messagesPath = getMessagesPath(extensionId)
|
const messagesPath = getMessagesPath(extensionId);
|
||||||
return fs.promises.readFile(messagesPath, 'utf8')
|
return fs.promises.readFile(messagesPath, 'utf8');
|
||||||
})
|
});
|
||||||
|
|
||||||
const validStorageTypes = new Set(['sync', 'local'])
|
const validStorageTypes = new Set(['sync', 'local']);
|
||||||
|
|
||||||
const getChromeStoragePath = (storageType, extensionId) => {
|
const getChromeStoragePath = (storageType, extensionId) => {
|
||||||
if (!validStorageTypes.has(storageType)) {
|
if (!validStorageTypes.has(storageType)) {
|
||||||
throw new Error(`Invalid storageType: ${storageType}`)
|
throw new Error(`Invalid storageType: ${storageType}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!manifestMap[extensionId]) {
|
if (!manifestMap[extensionId]) {
|
||||||
throw new Error(`Invalid extensionId: ${extensionId}`)
|
throw new Error(`Invalid extensionId: ${extensionId}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
return path.join(app.getPath('userData'), `/Chrome Storage/${extensionId}-${storageType}.json`)
|
return path.join(app.getPath('userData'), `/Chrome Storage/${extensionId}-${storageType}.json`);
|
||||||
}
|
};
|
||||||
|
|
||||||
ipcMainInternal.handle('CHROME_STORAGE_READ', async function (event, storageType, extensionId) {
|
ipcMainInternal.handle('CHROME_STORAGE_READ', async function (event, storageType, extensionId) {
|
||||||
const filePath = getChromeStoragePath(storageType, extensionId)
|
const filePath = getChromeStoragePath(storageType, extensionId);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
return await fs.promises.readFile(filePath, 'utf8')
|
return await fs.promises.readFile(filePath, 'utf8');
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
if (error.code === 'ENOENT') {
|
if (error.code === 'ENOENT') {
|
||||||
return null
|
return null;
|
||||||
} else {
|
} else {
|
||||||
throw error
|
throw error;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
|
|
||||||
ipcMainInternal.handle('CHROME_STORAGE_WRITE', async function (event, storageType, extensionId, data) {
|
ipcMainInternal.handle('CHROME_STORAGE_WRITE', async function (event, storageType, extensionId, data) {
|
||||||
const filePath = getChromeStoragePath(storageType, extensionId)
|
const filePath = getChromeStoragePath(storageType, extensionId);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await fs.promises.mkdir(path.dirname(filePath), { recursive: true })
|
await fs.promises.mkdir(path.dirname(filePath), { recursive: true });
|
||||||
} catch {
|
} catch {
|
||||||
// we just ignore the errors of mkdir
|
// we just ignore the errors of mkdir
|
||||||
}
|
}
|
||||||
|
|
||||||
return fs.promises.writeFile(filePath, data, 'utf8')
|
return fs.promises.writeFile(filePath, data, 'utf8');
|
||||||
})
|
});
|
||||||
|
|
||||||
const isChromeExtension = function (pageURL) {
|
const isChromeExtension = function (pageURL) {
|
||||||
const { protocol } = url.parse(pageURL)
|
const { protocol } = url.parse(pageURL);
|
||||||
return protocol === 'chrome-extension:'
|
return protocol === 'chrome-extension:';
|
||||||
}
|
};
|
||||||
|
|
||||||
const assertChromeExtension = function (contents, api) {
|
const assertChromeExtension = function (contents, api) {
|
||||||
const pageURL = contents._getURL()
|
const pageURL = contents._getURL();
|
||||||
if (!isChromeExtension(pageURL)) {
|
if (!isChromeExtension(pageURL)) {
|
||||||
console.error(`Blocked ${pageURL} from calling ${api}`)
|
console.error(`Blocked ${pageURL} from calling ${api}`);
|
||||||
throw new Error(`Blocked ${api}`)
|
throw new Error(`Blocked ${api}`);
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
ipcMainInternal.handle('CHROME_TABS_EXECUTE_SCRIPT', async function (event, tabId, extensionId, details) {
|
ipcMainInternal.handle('CHROME_TABS_EXECUTE_SCRIPT', async function (event, tabId, extensionId, details) {
|
||||||
assertChromeExtension(event.sender, 'chrome.tabs.executeScript()')
|
assertChromeExtension(event.sender, 'chrome.tabs.executeScript()');
|
||||||
|
|
||||||
const contents = webContents.fromId(tabId)
|
const contents = webContents.fromId(tabId);
|
||||||
if (!contents) {
|
if (!contents) {
|
||||||
throw new Error(`Sending message to unknown tab ${tabId}`)
|
throw new Error(`Sending message to unknown tab ${tabId}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
let code, url
|
let code, url;
|
||||||
if (details.file) {
|
if (details.file) {
|
||||||
const manifest = manifestMap[extensionId]
|
const manifest = manifestMap[extensionId];
|
||||||
code = String(fs.readFileSync(path.join(manifest.srcDirectory, details.file)))
|
code = String(fs.readFileSync(path.join(manifest.srcDirectory, details.file)));
|
||||||
url = `chrome-extension://${extensionId}${details.file}`
|
url = `chrome-extension://${extensionId}${details.file}`;
|
||||||
} else {
|
} else {
|
||||||
code = details.code
|
code = details.code;
|
||||||
url = `chrome-extension://${extensionId}/${String(Math.random()).substr(2, 8)}.js`
|
url = `chrome-extension://${extensionId}/${String(Math.random()).substr(2, 8)}.js`;
|
||||||
}
|
}
|
||||||
|
|
||||||
return ipcMainUtils.invokeInWebContents(contents, false, 'CHROME_TABS_EXECUTE_SCRIPT', extensionId, url, code)
|
return ipcMainUtils.invokeInWebContents(contents, false, 'CHROME_TABS_EXECUTE_SCRIPT', extensionId, url, code);
|
||||||
})
|
});
|
||||||
|
|
||||||
exports.getContentScripts = () => {
|
exports.getContentScripts = () => {
|
||||||
return Object.values(contentScripts)
|
return Object.values(contentScripts);
|
||||||
}
|
};
|
||||||
|
|
||||||
// Transfer the content scripts to renderer.
|
// Transfer the content scripts to renderer.
|
||||||
const contentScripts = {}
|
const contentScripts = {};
|
||||||
|
|
||||||
const injectContentScripts = function (manifest) {
|
const injectContentScripts = function (manifest) {
|
||||||
if (contentScripts[manifest.name] || !manifest.content_scripts) return
|
if (contentScripts[manifest.name] || !manifest.content_scripts) return;
|
||||||
|
|
||||||
const readArrayOfFiles = function (relativePath) {
|
const readArrayOfFiles = function (relativePath) {
|
||||||
return {
|
return {
|
||||||
url: `chrome-extension://${manifest.extensionId}/${relativePath}`,
|
url: `chrome-extension://${manifest.extensionId}/${relativePath}`,
|
||||||
code: String(fs.readFileSync(path.join(manifest.srcDirectory, relativePath)))
|
code: String(fs.readFileSync(path.join(manifest.srcDirectory, relativePath)))
|
||||||
}
|
};
|
||||||
}
|
};
|
||||||
|
|
||||||
const contentScriptToEntry = function (script) {
|
const contentScriptToEntry = function (script) {
|
||||||
return {
|
return {
|
||||||
@@ -341,25 +341,25 @@ const injectContentScripts = function (manifest) {
|
|||||||
css: script.css ? script.css.map(readArrayOfFiles) : [],
|
css: script.css ? script.css.map(readArrayOfFiles) : [],
|
||||||
runAt: script.run_at || 'document_idle',
|
runAt: script.run_at || 'document_idle',
|
||||||
allFrames: script.all_frames || false
|
allFrames: script.all_frames || false
|
||||||
}
|
};
|
||||||
}
|
};
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const entry = {
|
const entry = {
|
||||||
extensionId: manifest.extensionId,
|
extensionId: manifest.extensionId,
|
||||||
contentScripts: manifest.content_scripts.map(contentScriptToEntry)
|
contentScripts: manifest.content_scripts.map(contentScriptToEntry)
|
||||||
}
|
};
|
||||||
contentScripts[manifest.name] = entry
|
contentScripts[manifest.name] = entry;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error('Failed to read content scripts', e)
|
console.error('Failed to read content scripts', e);
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
const removeContentScripts = function (manifest) {
|
const removeContentScripts = function (manifest) {
|
||||||
if (!contentScripts[manifest.name]) return
|
if (!contentScripts[manifest.name]) return;
|
||||||
|
|
||||||
delete contentScripts[manifest.name]
|
delete contentScripts[manifest.name];
|
||||||
}
|
};
|
||||||
|
|
||||||
// Transfer the |manifest| to a format that can be recognized by the
|
// Transfer the |manifest| to a format that can be recognized by the
|
||||||
// |DevToolsAPI.addExtensions|.
|
// |DevToolsAPI.addExtensions|.
|
||||||
@@ -369,166 +369,166 @@ const manifestToExtensionInfo = function (manifest) {
|
|||||||
srcDirectory: manifest.srcDirectory,
|
srcDirectory: manifest.srcDirectory,
|
||||||
name: manifest.name,
|
name: manifest.name,
|
||||||
exposeExperimentalAPIs: true
|
exposeExperimentalAPIs: true
|
||||||
}
|
};
|
||||||
}
|
};
|
||||||
|
|
||||||
// Load the extensions for the window.
|
// Load the extensions for the window.
|
||||||
const loadExtension = function (manifest) {
|
const loadExtension = function (manifest) {
|
||||||
startBackgroundPages(manifest)
|
startBackgroundPages(manifest);
|
||||||
injectContentScripts(manifest)
|
injectContentScripts(manifest);
|
||||||
}
|
};
|
||||||
|
|
||||||
const loadDevToolsExtensions = function (win, manifests) {
|
const loadDevToolsExtensions = function (win, manifests) {
|
||||||
if (!win.devToolsWebContents) return
|
if (!win.devToolsWebContents) return;
|
||||||
|
|
||||||
manifests.forEach(loadExtension)
|
manifests.forEach(loadExtension);
|
||||||
|
|
||||||
const extensionInfoArray = manifests.map(manifestToExtensionInfo)
|
const extensionInfoArray = manifests.map(manifestToExtensionInfo);
|
||||||
extensionInfoArray.forEach((extension) => {
|
extensionInfoArray.forEach((extension) => {
|
||||||
win.devToolsWebContents._grantOriginAccess(extension.startPage)
|
win.devToolsWebContents._grantOriginAccess(extension.startPage);
|
||||||
})
|
});
|
||||||
|
|
||||||
extensionInfoArray.forEach((extensionInfo) => {
|
extensionInfoArray.forEach((extensionInfo) => {
|
||||||
win.devToolsWebContents.executeJavaScript(`Extensions.extensionServer._addExtension(${JSON.stringify(extensionInfo)})`)
|
win.devToolsWebContents.executeJavaScript(`Extensions.extensionServer._addExtension(${JSON.stringify(extensionInfo)})`);
|
||||||
})
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
app.on('web-contents-created', function (event, webContents) {
|
app.on('web-contents-created', function (event, webContents) {
|
||||||
if (!isWindowOrWebView(webContents)) return
|
if (!isWindowOrWebView(webContents)) return;
|
||||||
|
|
||||||
hookWebContentsEvents(webContents)
|
hookWebContentsEvents(webContents);
|
||||||
webContents.on('devtools-opened', function () {
|
webContents.on('devtools-opened', function () {
|
||||||
loadDevToolsExtensions(webContents, Object.values(manifestMap))
|
loadDevToolsExtensions(webContents, Object.values(manifestMap));
|
||||||
})
|
});
|
||||||
})
|
});
|
||||||
|
|
||||||
// The chrome-extension: can map a extension URL request to real file path.
|
// The chrome-extension: can map a extension URL request to real file path.
|
||||||
const chromeExtensionHandler = function (request, callback) {
|
const chromeExtensionHandler = function (request, callback) {
|
||||||
const parsed = url.parse(request.url)
|
const parsed = url.parse(request.url);
|
||||||
if (!parsed.hostname || !parsed.path) return callback()
|
if (!parsed.hostname || !parsed.path) return callback();
|
||||||
|
|
||||||
const manifest = manifestMap[parsed.hostname]
|
const manifest = manifestMap[parsed.hostname];
|
||||||
if (!manifest) return callback()
|
if (!manifest) return callback();
|
||||||
|
|
||||||
const page = backgroundPages[parsed.hostname]
|
const page = backgroundPages[parsed.hostname];
|
||||||
if (page && parsed.path === `/${page.name}`) {
|
if (page && parsed.path === `/${page.name}`) {
|
||||||
// Disabled due to false positive in StandardJS
|
// Disabled due to false positive in StandardJS
|
||||||
// eslint-disable-next-line standard/no-callback-literal
|
// eslint-disable-next-line standard/no-callback-literal
|
||||||
return callback({
|
return callback({
|
||||||
mimeType: 'text/html',
|
mimeType: 'text/html',
|
||||||
data: page.html
|
data: page.html
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
fs.readFile(path.join(manifest.srcDirectory, parsed.path), function (err, content) {
|
fs.readFile(path.join(manifest.srcDirectory, parsed.path), function (err, content) {
|
||||||
if (err) {
|
if (err) {
|
||||||
// Disabled due to false positive in StandardJS
|
// Disabled due to false positive in StandardJS
|
||||||
// eslint-disable-next-line standard/no-callback-literal
|
// eslint-disable-next-line standard/no-callback-literal
|
||||||
return callback(-6) // FILE_NOT_FOUND
|
return callback(-6); // FILE_NOT_FOUND
|
||||||
} else {
|
} else {
|
||||||
return callback(content)
|
return callback(content);
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
app.on('session-created', function (ses) {
|
app.on('session-created', function (ses) {
|
||||||
ses.protocol.registerBufferProtocol('chrome-extension', chromeExtensionHandler)
|
ses.protocol.registerBufferProtocol('chrome-extension', chromeExtensionHandler);
|
||||||
})
|
});
|
||||||
|
|
||||||
// The persistent path of "DevTools Extensions" preference file.
|
// The persistent path of "DevTools Extensions" preference file.
|
||||||
let loadedDevToolsExtensionsPath = null
|
let loadedDevToolsExtensionsPath = null;
|
||||||
|
|
||||||
app.on('will-quit', function () {
|
app.on('will-quit', function () {
|
||||||
try {
|
try {
|
||||||
const loadedDevToolsExtensions = Array.from(devToolsExtensionNames)
|
const loadedDevToolsExtensions = Array.from(devToolsExtensionNames)
|
||||||
.map(name => manifestNameMap[name].srcDirectory)
|
.map(name => manifestNameMap[name].srcDirectory);
|
||||||
if (loadedDevToolsExtensions.length > 0) {
|
if (loadedDevToolsExtensions.length > 0) {
|
||||||
try {
|
try {
|
||||||
fs.mkdirSync(path.dirname(loadedDevToolsExtensionsPath))
|
fs.mkdirSync(path.dirname(loadedDevToolsExtensionsPath));
|
||||||
} catch {
|
} catch {
|
||||||
// Ignore error
|
// Ignore error
|
||||||
}
|
}
|
||||||
fs.writeFileSync(loadedDevToolsExtensionsPath, JSON.stringify(loadedDevToolsExtensions))
|
fs.writeFileSync(loadedDevToolsExtensionsPath, JSON.stringify(loadedDevToolsExtensions));
|
||||||
} else {
|
} else {
|
||||||
fs.unlinkSync(loadedDevToolsExtensionsPath)
|
fs.unlinkSync(loadedDevToolsExtensionsPath);
|
||||||
}
|
}
|
||||||
} catch {
|
} catch {
|
||||||
// Ignore error
|
// Ignore error
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
|
|
||||||
// We can not use protocol or BrowserWindow until app is ready.
|
// We can not use protocol or BrowserWindow until app is ready.
|
||||||
app.once('ready', function () {
|
app.once('ready', function () {
|
||||||
// The public API to add/remove extensions.
|
// The public API to add/remove extensions.
|
||||||
BrowserWindow.addExtension = function (srcDirectory) {
|
BrowserWindow.addExtension = function (srcDirectory) {
|
||||||
const manifest = getManifestFromPath(srcDirectory)
|
const manifest = getManifestFromPath(srcDirectory);
|
||||||
if (manifest) {
|
if (manifest) {
|
||||||
loadExtension(manifest)
|
loadExtension(manifest);
|
||||||
for (const webContents of getAllWebContents()) {
|
for (const webContents of getAllWebContents()) {
|
||||||
if (isWindowOrWebView(webContents)) {
|
if (isWindowOrWebView(webContents)) {
|
||||||
loadDevToolsExtensions(webContents, [manifest])
|
loadDevToolsExtensions(webContents, [manifest]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return manifest.name
|
return manifest.name;
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
BrowserWindow.removeExtension = function (name) {
|
BrowserWindow.removeExtension = function (name) {
|
||||||
const manifest = manifestNameMap[name]
|
const manifest = manifestNameMap[name];
|
||||||
if (!manifest) return
|
if (!manifest) return;
|
||||||
|
|
||||||
removeBackgroundPages(manifest)
|
removeBackgroundPages(manifest);
|
||||||
removeContentScripts(manifest)
|
removeContentScripts(manifest);
|
||||||
delete manifestMap[manifest.extensionId]
|
delete manifestMap[manifest.extensionId];
|
||||||
delete manifestNameMap[name]
|
delete manifestNameMap[name];
|
||||||
}
|
};
|
||||||
|
|
||||||
BrowserWindow.getExtensions = function () {
|
BrowserWindow.getExtensions = function () {
|
||||||
const extensions = {}
|
const extensions = {};
|
||||||
Object.keys(manifestNameMap).forEach(function (name) {
|
Object.keys(manifestNameMap).forEach(function (name) {
|
||||||
const manifest = manifestNameMap[name]
|
const manifest = manifestNameMap[name];
|
||||||
extensions[name] = { name: manifest.name, version: manifest.version }
|
extensions[name] = { name: manifest.name, version: manifest.version };
|
||||||
})
|
});
|
||||||
return extensions
|
return extensions;
|
||||||
}
|
};
|
||||||
|
|
||||||
BrowserWindow.addDevToolsExtension = function (srcDirectory) {
|
BrowserWindow.addDevToolsExtension = function (srcDirectory) {
|
||||||
const manifestName = BrowserWindow.addExtension(srcDirectory)
|
const manifestName = BrowserWindow.addExtension(srcDirectory);
|
||||||
if (manifestName) {
|
if (manifestName) {
|
||||||
devToolsExtensionNames.add(manifestName)
|
devToolsExtensionNames.add(manifestName);
|
||||||
}
|
}
|
||||||
return manifestName
|
return manifestName;
|
||||||
}
|
};
|
||||||
|
|
||||||
BrowserWindow.removeDevToolsExtension = function (name) {
|
BrowserWindow.removeDevToolsExtension = function (name) {
|
||||||
BrowserWindow.removeExtension(name)
|
BrowserWindow.removeExtension(name);
|
||||||
devToolsExtensionNames.delete(name)
|
devToolsExtensionNames.delete(name);
|
||||||
}
|
};
|
||||||
|
|
||||||
BrowserWindow.getDevToolsExtensions = function () {
|
BrowserWindow.getDevToolsExtensions = function () {
|
||||||
const extensions = BrowserWindow.getExtensions()
|
const extensions = BrowserWindow.getExtensions();
|
||||||
const devExtensions = {}
|
const devExtensions = {};
|
||||||
Array.from(devToolsExtensionNames).forEach(function (name) {
|
Array.from(devToolsExtensionNames).forEach(function (name) {
|
||||||
if (!extensions[name]) return
|
if (!extensions[name]) return;
|
||||||
devExtensions[name] = extensions[name]
|
devExtensions[name] = extensions[name];
|
||||||
})
|
});
|
||||||
return devExtensions
|
return devExtensions;
|
||||||
}
|
};
|
||||||
|
|
||||||
// Load persisted extensions.
|
// Load persisted extensions.
|
||||||
loadedDevToolsExtensionsPath = path.join(app.getPath('userData'), 'DevTools Extensions')
|
loadedDevToolsExtensionsPath = path.join(app.getPath('userData'), 'DevTools Extensions');
|
||||||
try {
|
try {
|
||||||
const loadedDevToolsExtensions = JSON.parse(fs.readFileSync(loadedDevToolsExtensionsPath))
|
const loadedDevToolsExtensions = JSON.parse(fs.readFileSync(loadedDevToolsExtensionsPath));
|
||||||
if (Array.isArray(loadedDevToolsExtensions)) {
|
if (Array.isArray(loadedDevToolsExtensions)) {
|
||||||
for (const srcDirectory of loadedDevToolsExtensions) {
|
for (const srcDirectory of loadedDevToolsExtensions) {
|
||||||
// Start background pages and set content scripts.
|
// Start background pages and set content scripts.
|
||||||
BrowserWindow.addDevToolsExtension(srcDirectory)
|
BrowserWindow.addDevToolsExtension(srcDirectory);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
if (process.env.ELECTRON_ENABLE_LOGGING && error.code !== 'ENOENT') {
|
if (process.env.ELECTRON_ENABLE_LOGGING && error.code !== 'ENOENT') {
|
||||||
console.error('Failed to load browser extensions from directory:', loadedDevToolsExtensionsPath)
|
console.error('Failed to load browser extensions from directory:', loadedDevToolsExtensionsPath);
|
||||||
console.error(error)
|
console.error(error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
|
|||||||
@@ -1,25 +1,25 @@
|
|||||||
'use strict'
|
'use strict';
|
||||||
|
|
||||||
const { app } = require('electron')
|
const { app } = require('electron');
|
||||||
const path = require('path')
|
const path = require('path');
|
||||||
|
|
||||||
const getTempDirectory = function () {
|
const getTempDirectory = function () {
|
||||||
try {
|
try {
|
||||||
return app.getPath('temp')
|
return app.getPath('temp');
|
||||||
} catch {
|
} catch {
|
||||||
// Delibrately laze-load the os module, this file is on the hot
|
// Delibrately laze-load the os module, this file is on the hot
|
||||||
// path when booting Electron and os takes between 5 - 8ms to load and we do not need it yet
|
// path when booting Electron and os takes between 5 - 8ms to load and we do not need it yet
|
||||||
return require('os').tmpdir()
|
return require('os').tmpdir();
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
exports.crashReporterInit = function (options) {
|
exports.crashReporterInit = function (options) {
|
||||||
const productName = options.productName || app.name
|
const productName = options.productName || app.name;
|
||||||
const crashesDirectory = path.join(getTempDirectory(), `${productName} Crashes`)
|
const crashesDirectory = path.join(getTempDirectory(), `${productName} Crashes`);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
productName,
|
productName,
|
||||||
crashesDirectory,
|
crashesDirectory,
|
||||||
appVersion: app.getVersion()
|
appVersion: app.getVersion()
|
||||||
}
|
};
|
||||||
}
|
};
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
import { shell, Menu } from 'electron'
|
import { shell, Menu } from 'electron';
|
||||||
|
|
||||||
const v8Util = process.electronBinding('v8_util')
|
const v8Util = process.electronBinding('v8_util');
|
||||||
|
|
||||||
const isMac = process.platform === 'darwin'
|
const isMac = process.platform === 'darwin';
|
||||||
|
|
||||||
export const setDefaultApplicationMenu = () => {
|
export const setDefaultApplicationMenu = () => {
|
||||||
if (v8Util.getHiddenValue<boolean>(global, 'applicationMenuSet')) return
|
if (v8Util.getHiddenValue<boolean>(global, 'applicationMenuSet')) return;
|
||||||
|
|
||||||
const helpMenu: Electron.MenuItemConstructorOptions = {
|
const helpMenu: Electron.MenuItemConstructorOptions = {
|
||||||
role: 'help',
|
role: 'help',
|
||||||
@@ -13,32 +13,32 @@ export const setDefaultApplicationMenu = () => {
|
|||||||
{
|
{
|
||||||
label: 'Learn More',
|
label: 'Learn More',
|
||||||
click: async () => {
|
click: async () => {
|
||||||
await shell.openExternal('https://electronjs.org')
|
await shell.openExternal('https://electronjs.org');
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: 'Documentation',
|
label: 'Documentation',
|
||||||
click: async () => {
|
click: async () => {
|
||||||
const version = process.versions.electron
|
const version = process.versions.electron;
|
||||||
await shell.openExternal(`https://github.com/electron/electron/tree/v${version}/docs#readme`)
|
await shell.openExternal(`https://github.com/electron/electron/tree/v${version}/docs#readme`);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: 'Community Discussions',
|
label: 'Community Discussions',
|
||||||
click: async () => {
|
click: async () => {
|
||||||
await shell.openExternal('https://discuss.atom.io/c/electron')
|
await shell.openExternal('https://discuss.atom.io/c/electron');
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: 'Search Issues',
|
label: 'Search Issues',
|
||||||
click: async () => {
|
click: async () => {
|
||||||
await shell.openExternal('https://github.com/electron/electron/issues')
|
await shell.openExternal('https://github.com/electron/electron/issues');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
};
|
||||||
|
|
||||||
const macAppMenu: Electron.MenuItemConstructorOptions = { role: 'appMenu' }
|
const macAppMenu: Electron.MenuItemConstructorOptions = { role: 'appMenu' };
|
||||||
const template: Electron.MenuItemConstructorOptions[] = [
|
const template: Electron.MenuItemConstructorOptions[] = [
|
||||||
...(isMac ? [macAppMenu] : []),
|
...(isMac ? [macAppMenu] : []),
|
||||||
{ role: 'fileMenu' },
|
{ role: 'fileMenu' },
|
||||||
@@ -46,8 +46,8 @@ export const setDefaultApplicationMenu = () => {
|
|||||||
{ role: 'viewMenu' },
|
{ role: 'viewMenu' },
|
||||||
{ role: 'windowMenu' },
|
{ role: 'windowMenu' },
|
||||||
helpMenu
|
helpMenu
|
||||||
]
|
];
|
||||||
|
|
||||||
const menu = Menu.buildFromTemplate(template)
|
const menu = Menu.buildFromTemplate(template);
|
||||||
Menu.setApplicationMenu(menu)
|
Menu.setApplicationMenu(menu);
|
||||||
}
|
};
|
||||||
|
|||||||
@@ -1,66 +1,66 @@
|
|||||||
import { EventEmitter } from 'events'
|
import { EventEmitter } from 'events';
|
||||||
|
|
||||||
const { createDesktopCapturer } = process.electronBinding('desktop_capturer')
|
const { createDesktopCapturer } = process.electronBinding('desktop_capturer');
|
||||||
|
|
||||||
const deepEqual = (a: ElectronInternal.GetSourcesOptions, b: ElectronInternal.GetSourcesOptions) => JSON.stringify(a) === JSON.stringify(b)
|
const deepEqual = (a: ElectronInternal.GetSourcesOptions, b: ElectronInternal.GetSourcesOptions) => JSON.stringify(a) === JSON.stringify(b);
|
||||||
|
|
||||||
let currentlyRunning: {
|
let currentlyRunning: {
|
||||||
options: ElectronInternal.GetSourcesOptions;
|
options: ElectronInternal.GetSourcesOptions;
|
||||||
getSources: Promise<ElectronInternal.GetSourcesResult[]>;
|
getSources: Promise<ElectronInternal.GetSourcesResult[]>;
|
||||||
}[] = []
|
}[] = [];
|
||||||
|
|
||||||
export const getSources = (event: Electron.IpcMainEvent, options: ElectronInternal.GetSourcesOptions) => {
|
export const getSources = (event: Electron.IpcMainEvent, options: ElectronInternal.GetSourcesOptions) => {
|
||||||
for (const running of currentlyRunning) {
|
for (const running of currentlyRunning) {
|
||||||
if (deepEqual(running.options, options)) {
|
if (deepEqual(running.options, options)) {
|
||||||
// If a request is currently running for the same options
|
// If a request is currently running for the same options
|
||||||
// return that promise
|
// return that promise
|
||||||
return running.getSources
|
return running.getSources;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const getSources = new Promise<ElectronInternal.GetSourcesResult[]>((resolve, reject) => {
|
const getSources = new Promise<ElectronInternal.GetSourcesResult[]>((resolve, reject) => {
|
||||||
let capturer: ElectronInternal.DesktopCapturer | null = createDesktopCapturer()
|
let capturer: ElectronInternal.DesktopCapturer | null = createDesktopCapturer();
|
||||||
|
|
||||||
const stopRunning = () => {
|
const stopRunning = () => {
|
||||||
if (capturer) {
|
if (capturer) {
|
||||||
capturer.emit = null
|
capturer.emit = null;
|
||||||
capturer = null
|
capturer = null;
|
||||||
}
|
}
|
||||||
// Remove from currentlyRunning once we resolve or reject
|
// Remove from currentlyRunning once we resolve or reject
|
||||||
currentlyRunning = currentlyRunning.filter(running => running.options !== options)
|
currentlyRunning = currentlyRunning.filter(running => running.options !== options);
|
||||||
}
|
};
|
||||||
|
|
||||||
const emitter = new EventEmitter()
|
const emitter = new EventEmitter();
|
||||||
|
|
||||||
emitter.once('error', (event, error: string) => {
|
emitter.once('error', (event, error: string) => {
|
||||||
stopRunning()
|
stopRunning();
|
||||||
reject(error)
|
reject(error);
|
||||||
})
|
});
|
||||||
|
|
||||||
emitter.once('finished', (event, sources: Electron.DesktopCapturerSource[], fetchWindowIcons: boolean) => {
|
emitter.once('finished', (event, sources: Electron.DesktopCapturerSource[], fetchWindowIcons: boolean) => {
|
||||||
stopRunning()
|
stopRunning();
|
||||||
resolve(sources.map(source => ({
|
resolve(sources.map(source => ({
|
||||||
id: source.id,
|
id: source.id,
|
||||||
name: source.name,
|
name: source.name,
|
||||||
thumbnail: source.thumbnail.toDataURL(),
|
thumbnail: source.thumbnail.toDataURL(),
|
||||||
display_id: source.display_id,
|
display_id: source.display_id,
|
||||||
appIcon: (fetchWindowIcons && source.appIcon) ? source.appIcon.toDataURL() : null
|
appIcon: (fetchWindowIcons && source.appIcon) ? source.appIcon.toDataURL() : null
|
||||||
})))
|
})));
|
||||||
})
|
});
|
||||||
|
|
||||||
capturer.emit = emitter.emit.bind(emitter)
|
capturer.emit = emitter.emit.bind(emitter);
|
||||||
capturer.startHandling(options.captureWindow, options.captureScreen, options.thumbnailSize, options.fetchWindowIcons)
|
capturer.startHandling(options.captureWindow, options.captureScreen, options.thumbnailSize, options.fetchWindowIcons);
|
||||||
|
|
||||||
// If the WebContents is destroyed before receiving result, just remove the
|
// If the WebContents is destroyed before receiving result, just remove the
|
||||||
// reference to emit and the capturer itself so that it never dispatches
|
// reference to emit and the capturer itself so that it never dispatches
|
||||||
// back to the renderer
|
// back to the renderer
|
||||||
event.sender.once('destroyed', () => stopRunning())
|
event.sender.once('destroyed', () => stopRunning());
|
||||||
})
|
});
|
||||||
|
|
||||||
currentlyRunning.push({
|
currentlyRunning.push({
|
||||||
options,
|
options,
|
||||||
getSources
|
getSources
|
||||||
})
|
});
|
||||||
|
|
||||||
return getSources
|
return getSources;
|
||||||
}
|
};
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
import { dialog, Menu } from 'electron'
|
import { dialog, Menu } from 'electron';
|
||||||
import * as fs from 'fs'
|
import * as fs from 'fs';
|
||||||
import * as url from 'url'
|
import * as url from 'url';
|
||||||
|
|
||||||
import { ipcMainInternal } from '@electron/internal/browser/ipc-main-internal'
|
import { ipcMainInternal } from '@electron/internal/browser/ipc-main-internal';
|
||||||
import * as ipcMainUtils from '@electron/internal/browser/ipc-main-internal-utils'
|
import * as ipcMainUtils from '@electron/internal/browser/ipc-main-internal-utils';
|
||||||
|
|
||||||
const convertToMenuTemplate = function (items: ContextMenuItem[], handler: (id: number) => void) {
|
const convertToMenuTemplate = function (items: ContextMenuItem[], handler: (id: number) => void) {
|
||||||
return items.map(function (item) {
|
return items.map(function (item) {
|
||||||
@@ -23,15 +23,15 @@ const convertToMenuTemplate = function (items: ContextMenuItem[], handler: (id:
|
|||||||
type: 'normal',
|
type: 'normal',
|
||||||
label: item.label,
|
label: item.label,
|
||||||
enabled: item.enabled
|
enabled: item.enabled
|
||||||
}
|
};
|
||||||
|
|
||||||
if (item.id != null) {
|
if (item.id != null) {
|
||||||
transformed.click = () => handler(item.id)
|
transformed.click = () => handler(item.id);
|
||||||
}
|
}
|
||||||
|
|
||||||
return transformed
|
return transformed;
|
||||||
})
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
const getEditMenuItems = function (): Electron.MenuItemConstructorOptions[] {
|
const getEditMenuItems = function (): Electron.MenuItemConstructorOptions[] {
|
||||||
return [
|
return [
|
||||||
@@ -44,56 +44,56 @@ const getEditMenuItems = function (): Electron.MenuItemConstructorOptions[] {
|
|||||||
{ role: 'pasteAndMatchStyle' },
|
{ role: 'pasteAndMatchStyle' },
|
||||||
{ role: 'delete' },
|
{ role: 'delete' },
|
||||||
{ role: 'selectAll' }
|
{ role: 'selectAll' }
|
||||||
]
|
];
|
||||||
}
|
};
|
||||||
|
|
||||||
const isChromeDevTools = function (pageURL: string) {
|
const isChromeDevTools = function (pageURL: string) {
|
||||||
const { protocol } = url.parse(pageURL)
|
const { protocol } = url.parse(pageURL);
|
||||||
return protocol === 'devtools:'
|
return protocol === 'devtools:';
|
||||||
}
|
};
|
||||||
|
|
||||||
const assertChromeDevTools = function (contents: Electron.WebContents, api: string) {
|
const assertChromeDevTools = function (contents: Electron.WebContents, api: string) {
|
||||||
const pageURL = contents._getURL()
|
const pageURL = contents._getURL();
|
||||||
if (!isChromeDevTools(pageURL)) {
|
if (!isChromeDevTools(pageURL)) {
|
||||||
console.error(`Blocked ${pageURL} from calling ${api}`)
|
console.error(`Blocked ${pageURL} from calling ${api}`);
|
||||||
throw new Error(`Blocked ${api}`)
|
throw new Error(`Blocked ${api}`);
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
ipcMainInternal.handle('ELECTRON_INSPECTOR_CONTEXT_MENU', function (event: Electron.IpcMainInvokeEvent, items: ContextMenuItem[], isEditMenu: boolean) {
|
ipcMainInternal.handle('ELECTRON_INSPECTOR_CONTEXT_MENU', function (event: Electron.IpcMainInvokeEvent, items: ContextMenuItem[], isEditMenu: boolean) {
|
||||||
return new Promise(resolve => {
|
return new Promise(resolve => {
|
||||||
assertChromeDevTools(event.sender, 'window.InspectorFrontendHost.showContextMenuAtPoint()')
|
assertChromeDevTools(event.sender, 'window.InspectorFrontendHost.showContextMenuAtPoint()');
|
||||||
|
|
||||||
const template = isEditMenu ? getEditMenuItems() : convertToMenuTemplate(items, resolve)
|
const template = isEditMenu ? getEditMenuItems() : convertToMenuTemplate(items, resolve);
|
||||||
const menu = Menu.buildFromTemplate(template)
|
const menu = Menu.buildFromTemplate(template);
|
||||||
const window = event.sender.getOwnerBrowserWindow()
|
const window = event.sender.getOwnerBrowserWindow();
|
||||||
|
|
||||||
menu.popup({ window, callback: () => resolve() })
|
menu.popup({ window, callback: () => resolve() });
|
||||||
})
|
});
|
||||||
})
|
});
|
||||||
|
|
||||||
ipcMainInternal.handle('ELECTRON_INSPECTOR_SELECT_FILE', async function (event: Electron.IpcMainInvokeEvent) {
|
ipcMainInternal.handle('ELECTRON_INSPECTOR_SELECT_FILE', async function (event: Electron.IpcMainInvokeEvent) {
|
||||||
assertChromeDevTools(event.sender, 'window.UI.createFileSelectorElement()')
|
assertChromeDevTools(event.sender, 'window.UI.createFileSelectorElement()');
|
||||||
|
|
||||||
const result = await dialog.showOpenDialog({})
|
const result = await dialog.showOpenDialog({});
|
||||||
if (result.canceled) return []
|
if (result.canceled) return [];
|
||||||
|
|
||||||
const path = result.filePaths[0]
|
const path = result.filePaths[0];
|
||||||
const data = await fs.promises.readFile(path)
|
const data = await fs.promises.readFile(path);
|
||||||
|
|
||||||
return [path, data]
|
return [path, data];
|
||||||
})
|
});
|
||||||
|
|
||||||
ipcMainUtils.handleSync('ELECTRON_INSPECTOR_CONFIRM', async function (event: Electron.IpcMainInvokeEvent, message: string = '', title: string = '') {
|
ipcMainUtils.handleSync('ELECTRON_INSPECTOR_CONFIRM', async function (event: Electron.IpcMainInvokeEvent, message: string = '', title: string = '') {
|
||||||
assertChromeDevTools(event.sender, 'window.confirm()')
|
assertChromeDevTools(event.sender, 'window.confirm()');
|
||||||
|
|
||||||
const options = {
|
const options = {
|
||||||
message: String(message),
|
message: String(message),
|
||||||
title: String(title),
|
title: String(title),
|
||||||
buttons: ['OK', 'Cancel'],
|
buttons: ['OK', 'Cancel'],
|
||||||
cancelId: 1
|
cancelId: 1
|
||||||
}
|
};
|
||||||
const window = event.sender.getOwnerBrowserWindow()
|
const window = event.sender.getOwnerBrowserWindow();
|
||||||
const { response } = await dialog.showMessageBox(window, options)
|
const { response } = await dialog.showMessageBox(window, options);
|
||||||
return response === 0
|
return response === 0;
|
||||||
})
|
});
|
||||||
|
|||||||
@@ -1,13 +1,14 @@
|
|||||||
'use strict'
|
'use strict';
|
||||||
|
|
||||||
const { webContents } = require('electron')
|
const { webContents } = require('electron');
|
||||||
const { ipcMainInternal } = require('@electron/internal/browser/ipc-main-internal')
|
const { ipcMainInternal } = require('@electron/internal/browser/ipc-main-internal');
|
||||||
const ipcMainUtils = require('@electron/internal/browser/ipc-main-internal-utils')
|
const ipcMainUtils = require('@electron/internal/browser/ipc-main-internal-utils');
|
||||||
const parseFeaturesString = require('@electron/internal/common/parse-features-string')
|
const parseFeaturesString = require('@electron/internal/common/parse-features-string');
|
||||||
const { syncMethods, asyncMethods } = require('@electron/internal/common/web-view-methods')
|
const { syncMethods, asyncMethods, properties } = require('@electron/internal/common/web-view-methods');
|
||||||
|
const { serialize } = require('@electron/internal/common/type-utils');
|
||||||
|
|
||||||
// Doesn't exist in early initialization.
|
// Doesn't exist in early initialization.
|
||||||
let webViewManager = null
|
let webViewManager = null;
|
||||||
|
|
||||||
const supportedWebViewEvents = [
|
const supportedWebViewEvents = [
|
||||||
'load-commit',
|
'load-commit',
|
||||||
@@ -42,155 +43,155 @@ const supportedWebViewEvents = [
|
|||||||
'found-in-page',
|
'found-in-page',
|
||||||
'did-change-theme-color',
|
'did-change-theme-color',
|
||||||
'update-target-url'
|
'update-target-url'
|
||||||
]
|
];
|
||||||
|
|
||||||
const guestInstances = {}
|
const guestInstances = {};
|
||||||
const embedderElementsMap = {}
|
const embedderElementsMap = {};
|
||||||
|
|
||||||
function sanitizeOptionsForGuest (options) {
|
function sanitizeOptionsForGuest (options) {
|
||||||
const ret = { ...options }
|
const ret = { ...options };
|
||||||
// WebContents values can't be sent over IPC.
|
// WebContents values can't be sent over IPC.
|
||||||
delete ret.webContents
|
delete ret.webContents;
|
||||||
return ret
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create a new guest instance.
|
// Create a new guest instance.
|
||||||
const createGuest = function (embedder, params) {
|
const createGuest = function (embedder, params) {
|
||||||
if (webViewManager == null) {
|
if (webViewManager == null) {
|
||||||
webViewManager = process.electronBinding('web_view_manager')
|
webViewManager = process.electronBinding('web_view_manager');
|
||||||
}
|
}
|
||||||
|
|
||||||
const guest = webContents.create({
|
const guest = webContents.create({
|
||||||
type: 'webview',
|
type: 'webview',
|
||||||
partition: params.partition,
|
partition: params.partition,
|
||||||
embedder: embedder
|
embedder: embedder
|
||||||
})
|
});
|
||||||
const guestInstanceId = guest.id
|
const guestInstanceId = guest.id;
|
||||||
guestInstances[guestInstanceId] = {
|
guestInstances[guestInstanceId] = {
|
||||||
guest: guest,
|
guest: guest,
|
||||||
embedder: embedder
|
embedder: embedder
|
||||||
}
|
};
|
||||||
|
|
||||||
// Clear the guest from map when it is destroyed.
|
// Clear the guest from map when it is destroyed.
|
||||||
guest.once('destroyed', () => {
|
guest.once('destroyed', () => {
|
||||||
if (guestInstanceId in guestInstances) {
|
if (Object.prototype.hasOwnProperty.call(guestInstances, guestInstanceId)) {
|
||||||
detachGuest(embedder, guestInstanceId)
|
detachGuest(embedder, guestInstanceId);
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
|
|
||||||
// Init guest web view after attached.
|
// Init guest web view after attached.
|
||||||
guest.once('did-attach', function (event) {
|
guest.once('did-attach', function (event) {
|
||||||
params = this.attachParams
|
params = this.attachParams;
|
||||||
delete this.attachParams
|
delete this.attachParams;
|
||||||
|
|
||||||
const previouslyAttached = this.viewInstanceId != null
|
const previouslyAttached = this.viewInstanceId != null;
|
||||||
this.viewInstanceId = params.instanceId
|
this.viewInstanceId = params.instanceId;
|
||||||
|
|
||||||
// Only load URL and set size on first attach
|
// Only load URL and set size on first attach
|
||||||
if (previouslyAttached) {
|
if (previouslyAttached) {
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (params.src) {
|
if (params.src) {
|
||||||
const opts = {}
|
const opts = {};
|
||||||
if (params.httpreferrer) {
|
if (params.httpreferrer) {
|
||||||
opts.httpReferrer = params.httpreferrer
|
opts.httpReferrer = params.httpreferrer;
|
||||||
}
|
}
|
||||||
if (params.useragent) {
|
if (params.useragent) {
|
||||||
opts.userAgent = params.useragent
|
opts.userAgent = params.useragent;
|
||||||
}
|
}
|
||||||
this.loadURL(params.src, opts)
|
this.loadURL(params.src, opts);
|
||||||
}
|
}
|
||||||
embedder.emit('did-attach-webview', event, guest)
|
embedder.emit('did-attach-webview', event, guest);
|
||||||
})
|
});
|
||||||
|
|
||||||
const sendToEmbedder = (channel, ...args) => {
|
const sendToEmbedder = (channel, ...args) => {
|
||||||
if (!embedder.isDestroyed()) {
|
if (!embedder.isDestroyed()) {
|
||||||
embedder._sendInternal(`${channel}-${guest.viewInstanceId}`, ...args)
|
embedder._sendInternal(`${channel}-${guest.viewInstanceId}`, ...args);
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
// Dispatch events to embedder.
|
// Dispatch events to embedder.
|
||||||
const fn = function (event) {
|
const fn = function (event) {
|
||||||
guest.on(event, function (_, ...args) {
|
guest.on(event, function (_, ...args) {
|
||||||
sendToEmbedder('ELECTRON_GUEST_VIEW_INTERNAL_DISPATCH_EVENT', event, ...args)
|
sendToEmbedder('ELECTRON_GUEST_VIEW_INTERNAL_DISPATCH_EVENT', event, ...args);
|
||||||
})
|
});
|
||||||
}
|
};
|
||||||
for (const event of supportedWebViewEvents) {
|
for (const event of supportedWebViewEvents) {
|
||||||
fn(event)
|
fn(event);
|
||||||
}
|
}
|
||||||
|
|
||||||
guest.on('new-window', function (event, url, frameName, disposition, options, additionalFeatures, referrer) {
|
guest.on('new-window', function (event, url, frameName, disposition, options, additionalFeatures, referrer) {
|
||||||
sendToEmbedder('ELECTRON_GUEST_VIEW_INTERNAL_DISPATCH_EVENT', 'new-window', url,
|
sendToEmbedder('ELECTRON_GUEST_VIEW_INTERNAL_DISPATCH_EVENT', 'new-window', url,
|
||||||
frameName, disposition, sanitizeOptionsForGuest(options),
|
frameName, disposition, sanitizeOptionsForGuest(options),
|
||||||
additionalFeatures, referrer)
|
additionalFeatures, referrer);
|
||||||
})
|
});
|
||||||
|
|
||||||
// Dispatch guest's IPC messages to embedder.
|
// Dispatch guest's IPC messages to embedder.
|
||||||
guest.on('ipc-message-host', function (_, channel, args) {
|
guest.on('ipc-message-host', function (_, channel, args) {
|
||||||
sendToEmbedder('ELECTRON_GUEST_VIEW_INTERNAL_IPC_MESSAGE', channel, ...args)
|
sendToEmbedder('ELECTRON_GUEST_VIEW_INTERNAL_IPC_MESSAGE', channel, ...args);
|
||||||
})
|
});
|
||||||
|
|
||||||
// Notify guest of embedder window visibility when it is ready
|
// Notify guest of embedder window visibility when it is ready
|
||||||
// FIXME Remove once https://github.com/electron/electron/issues/6828 is fixed
|
// FIXME Remove once https://github.com/electron/electron/issues/6828 is fixed
|
||||||
guest.on('dom-ready', function () {
|
guest.on('dom-ready', function () {
|
||||||
const guestInstance = guestInstances[guestInstanceId]
|
const guestInstance = guestInstances[guestInstanceId];
|
||||||
if (guestInstance != null && guestInstance.visibilityState != null) {
|
if (guestInstance != null && guestInstance.visibilityState != null) {
|
||||||
guest._sendInternal('ELECTRON_GUEST_INSTANCE_VISIBILITY_CHANGE', guestInstance.visibilityState)
|
guest._sendInternal('ELECTRON_GUEST_INSTANCE_VISIBILITY_CHANGE', guestInstance.visibilityState);
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
|
|
||||||
// Forward internal web contents event to embedder to handle
|
// Forward internal web contents event to embedder to handle
|
||||||
// native window.open setup
|
// native window.open setup
|
||||||
guest.on('-add-new-contents', (...args) => {
|
guest.on('-add-new-contents', (...args) => {
|
||||||
if (guest.getLastWebPreferences().nativeWindowOpen === true) {
|
if (guest.getLastWebPreferences().nativeWindowOpen === true) {
|
||||||
const embedder = getEmbedder(guestInstanceId)
|
const embedder = getEmbedder(guestInstanceId);
|
||||||
if (embedder != null) {
|
if (embedder != null) {
|
||||||
embedder.emit('-add-new-contents', ...args)
|
embedder.emit('-add-new-contents', ...args);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
|
|
||||||
return guestInstanceId
|
return guestInstanceId;
|
||||||
}
|
};
|
||||||
|
|
||||||
// Attach the guest to an element of embedder.
|
// Attach the guest to an element of embedder.
|
||||||
const attachGuest = function (event, embedderFrameId, elementInstanceId, guestInstanceId, params) {
|
const attachGuest = function (event, embedderFrameId, elementInstanceId, guestInstanceId, params) {
|
||||||
const embedder = event.sender
|
const embedder = event.sender;
|
||||||
// Destroy the old guest when attaching.
|
// Destroy the old guest when attaching.
|
||||||
const key = `${embedder.id}-${elementInstanceId}`
|
const key = `${embedder.id}-${elementInstanceId}`;
|
||||||
const oldGuestInstanceId = embedderElementsMap[key]
|
const oldGuestInstanceId = embedderElementsMap[key];
|
||||||
if (oldGuestInstanceId != null) {
|
if (oldGuestInstanceId != null) {
|
||||||
// Reattachment to the same guest is just a no-op.
|
// Reattachment to the same guest is just a no-op.
|
||||||
if (oldGuestInstanceId === guestInstanceId) {
|
if (oldGuestInstanceId === guestInstanceId) {
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const oldGuestInstance = guestInstances[oldGuestInstanceId]
|
const oldGuestInstance = guestInstances[oldGuestInstanceId];
|
||||||
if (oldGuestInstance) {
|
if (oldGuestInstance) {
|
||||||
oldGuestInstance.guest.detachFromOuterFrame()
|
oldGuestInstance.guest.detachFromOuterFrame();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const guestInstance = guestInstances[guestInstanceId]
|
const guestInstance = guestInstances[guestInstanceId];
|
||||||
// If this isn't a valid guest instance then do nothing.
|
// If this isn't a valid guest instance then do nothing.
|
||||||
if (!guestInstance) {
|
if (!guestInstance) {
|
||||||
throw new Error(`Invalid guestInstanceId: ${guestInstanceId}`)
|
throw new Error(`Invalid guestInstanceId: ${guestInstanceId}`);
|
||||||
}
|
}
|
||||||
const { guest } = guestInstance
|
const { guest } = guestInstance;
|
||||||
if (guest.hostWebContents !== event.sender) {
|
if (guest.hostWebContents !== event.sender) {
|
||||||
throw new Error(`Access denied to guestInstanceId: ${guestInstanceId}`)
|
throw new Error(`Access denied to guestInstanceId: ${guestInstanceId}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
// If this guest is already attached to an element then remove it
|
// If this guest is already attached to an element then remove it
|
||||||
if (guestInstance.elementInstanceId) {
|
if (guestInstance.elementInstanceId) {
|
||||||
const oldKey = `${guestInstance.embedder.id}-${guestInstance.elementInstanceId}`
|
const oldKey = `${guestInstance.embedder.id}-${guestInstance.elementInstanceId}`;
|
||||||
delete embedderElementsMap[oldKey]
|
delete embedderElementsMap[oldKey];
|
||||||
|
|
||||||
// Remove guest from embedder if moving across web views
|
// Remove guest from embedder if moving across web views
|
||||||
if (guest.viewInstanceId !== params.instanceId) {
|
if (guest.viewInstanceId !== params.instanceId) {
|
||||||
webViewManager.removeGuest(guestInstance.embedder, guestInstanceId)
|
webViewManager.removeGuest(guestInstance.embedder, guestInstanceId);
|
||||||
guestInstance.embedder._sendInternal(`ELECTRON_GUEST_VIEW_INTERNAL_DESTROY_GUEST-${guest.viewInstanceId}`)
|
guestInstance.embedder._sendInternal(`ELECTRON_GUEST_VIEW_INTERNAL_DESTROY_GUEST-${guest.viewInstanceId}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -200,12 +201,12 @@ const attachGuest = function (event, embedderFrameId, elementInstanceId, guestIn
|
|||||||
nodeIntegrationInSubFrames: params.nodeintegrationinsubframes != null ? params.nodeintegrationinsubframes : false,
|
nodeIntegrationInSubFrames: params.nodeintegrationinsubframes != null ? params.nodeintegrationinsubframes : false,
|
||||||
enableRemoteModule: params.enableremotemodule,
|
enableRemoteModule: params.enableremotemodule,
|
||||||
plugins: params.plugins,
|
plugins: params.plugins,
|
||||||
zoomFactor: embedder.getZoomFactor(),
|
zoomFactor: embedder.zoomFactor,
|
||||||
disablePopups: !params.allowpopups,
|
disablePopups: !params.allowpopups,
|
||||||
webSecurity: !params.disablewebsecurity,
|
webSecurity: !params.disablewebsecurity,
|
||||||
enableBlinkFeatures: params.blinkfeatures,
|
enableBlinkFeatures: params.blinkfeatures,
|
||||||
disableBlinkFeatures: params.disableblinkfeatures
|
disableBlinkFeatures: params.disableblinkfeatures
|
||||||
}
|
};
|
||||||
|
|
||||||
// parse the 'webpreferences' attribute string, if set
|
// parse the 'webpreferences' attribute string, if set
|
||||||
// this uses the same parsing rules as window.open uses for its features
|
// this uses the same parsing rules as window.open uses for its features
|
||||||
@@ -213,14 +214,14 @@ const attachGuest = function (event, embedderFrameId, elementInstanceId, guestIn
|
|||||||
parseFeaturesString(params.webpreferences, function (key, value) {
|
parseFeaturesString(params.webpreferences, function (key, value) {
|
||||||
if (value === undefined) {
|
if (value === undefined) {
|
||||||
// no value was specified, default it to true
|
// no value was specified, default it to true
|
||||||
value = true
|
value = true;
|
||||||
}
|
}
|
||||||
webPreferences[key] = value
|
webPreferences[key] = value;
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (params.preload) {
|
if (params.preload) {
|
||||||
webPreferences.preloadURL = params.preload
|
webPreferences.preloadURL = params.preload;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Security options that guest will always inherit from embedder
|
// Security options that guest will always inherit from embedder
|
||||||
@@ -232,184 +233,208 @@ const attachGuest = function (event, embedderFrameId, elementInstanceId, guestIn
|
|||||||
['enableRemoteModule', false],
|
['enableRemoteModule', false],
|
||||||
['sandbox', true],
|
['sandbox', true],
|
||||||
['nodeIntegrationInSubFrames', false]
|
['nodeIntegrationInSubFrames', false]
|
||||||
])
|
]);
|
||||||
|
|
||||||
// Inherit certain option values from embedder
|
// Inherit certain option values from embedder
|
||||||
const lastWebPreferences = embedder.getLastWebPreferences()
|
const lastWebPreferences = embedder.getLastWebPreferences();
|
||||||
for (const [name, value] of inheritedWebPreferences) {
|
for (const [name, value] of inheritedWebPreferences) {
|
||||||
if (lastWebPreferences[name] === value) {
|
if (lastWebPreferences[name] === value) {
|
||||||
webPreferences[name] = value
|
webPreferences[name] = value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
embedder.emit('will-attach-webview', event, webPreferences, params)
|
embedder.emit('will-attach-webview', event, webPreferences, params);
|
||||||
if (event.defaultPrevented) {
|
if (event.defaultPrevented) {
|
||||||
if (guest.viewInstanceId == null) guest.viewInstanceId = params.instanceId
|
if (guest.viewInstanceId == null) guest.viewInstanceId = params.instanceId;
|
||||||
guest.destroy()
|
guest.destroy();
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
guest.attachParams = params
|
guest.attachParams = params;
|
||||||
embedderElementsMap[key] = guestInstanceId
|
embedderElementsMap[key] = guestInstanceId;
|
||||||
|
|
||||||
guest.setEmbedder(embedder)
|
guest.setEmbedder(embedder);
|
||||||
guestInstance.embedder = embedder
|
guestInstance.embedder = embedder;
|
||||||
guestInstance.elementInstanceId = elementInstanceId
|
guestInstance.elementInstanceId = elementInstanceId;
|
||||||
|
|
||||||
watchEmbedder(embedder)
|
watchEmbedder(embedder);
|
||||||
|
|
||||||
webViewManager.addGuest(guestInstanceId, elementInstanceId, embedder, guest, webPreferences)
|
webViewManager.addGuest(guestInstanceId, elementInstanceId, embedder, guest, webPreferences);
|
||||||
guest.attachToIframe(embedder, embedderFrameId)
|
guest.attachToIframe(embedder, embedderFrameId);
|
||||||
}
|
};
|
||||||
|
|
||||||
// Remove an guest-embedder relationship.
|
// Remove an guest-embedder relationship.
|
||||||
const detachGuest = function (embedder, guestInstanceId) {
|
const detachGuest = function (embedder, guestInstanceId) {
|
||||||
const guestInstance = guestInstances[guestInstanceId]
|
const guestInstance = guestInstances[guestInstanceId];
|
||||||
if (embedder !== guestInstance.embedder) {
|
if (embedder !== guestInstance.embedder) {
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
webViewManager.removeGuest(embedder, guestInstanceId)
|
webViewManager.removeGuest(embedder, guestInstanceId);
|
||||||
delete guestInstances[guestInstanceId]
|
delete guestInstances[guestInstanceId];
|
||||||
|
|
||||||
const key = `${embedder.id}-${guestInstance.elementInstanceId}`
|
const key = `${embedder.id}-${guestInstance.elementInstanceId}`;
|
||||||
delete embedderElementsMap[key]
|
delete embedderElementsMap[key];
|
||||||
}
|
};
|
||||||
|
|
||||||
// Once an embedder has had a guest attached we watch it for destruction to
|
// Once an embedder has had a guest attached we watch it for destruction to
|
||||||
// destroy any remaining guests.
|
// destroy any remaining guests.
|
||||||
const watchedEmbedders = new Set()
|
const watchedEmbedders = new Set();
|
||||||
const watchEmbedder = function (embedder) {
|
const watchEmbedder = function (embedder) {
|
||||||
if (watchedEmbedders.has(embedder)) {
|
if (watchedEmbedders.has(embedder)) {
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
watchedEmbedders.add(embedder)
|
watchedEmbedders.add(embedder);
|
||||||
|
|
||||||
// Forward embedder window visiblity change events to guest
|
// Forward embedder window visiblity change events to guest
|
||||||
const onVisibilityChange = function (visibilityState) {
|
const onVisibilityChange = function (visibilityState) {
|
||||||
for (const guestInstanceId in guestInstances) {
|
for (const guestInstanceId of Object.keys(guestInstances)) {
|
||||||
const guestInstance = guestInstances[guestInstanceId]
|
const guestInstance = guestInstances[guestInstanceId];
|
||||||
guestInstance.visibilityState = visibilityState
|
guestInstance.visibilityState = visibilityState;
|
||||||
if (guestInstance.embedder === embedder) {
|
if (guestInstance.embedder === embedder) {
|
||||||
guestInstance.guest._sendInternal('ELECTRON_GUEST_INSTANCE_VISIBILITY_CHANGE', visibilityState)
|
guestInstance.guest._sendInternal('ELECTRON_GUEST_INSTANCE_VISIBILITY_CHANGE', visibilityState);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
embedder.on('-window-visibility-change', onVisibilityChange)
|
embedder.on('-window-visibility-change', onVisibilityChange);
|
||||||
|
|
||||||
embedder.once('will-destroy', () => {
|
embedder.once('will-destroy', () => {
|
||||||
// Usually the guestInstances is cleared when guest is destroyed, but it
|
// Usually the guestInstances is cleared when guest is destroyed, but it
|
||||||
// may happen that the embedder gets manually destroyed earlier than guest,
|
// may happen that the embedder gets manually destroyed earlier than guest,
|
||||||
// and the embedder will be invalid in the usual code path.
|
// and the embedder will be invalid in the usual code path.
|
||||||
for (const guestInstanceId in guestInstances) {
|
for (const guestInstanceId of Object.keys(guestInstances)) {
|
||||||
const guestInstance = guestInstances[guestInstanceId]
|
const guestInstance = guestInstances[guestInstanceId];
|
||||||
if (guestInstance.embedder === embedder) {
|
if (guestInstance.embedder === embedder) {
|
||||||
detachGuest(embedder, parseInt(guestInstanceId))
|
detachGuest(embedder, parseInt(guestInstanceId));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Clear the listeners.
|
// Clear the listeners.
|
||||||
embedder.removeListener('-window-visibility-change', onVisibilityChange)
|
embedder.removeListener('-window-visibility-change', onVisibilityChange);
|
||||||
watchedEmbedders.delete(embedder)
|
watchedEmbedders.delete(embedder);
|
||||||
})
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
const isWebViewTagEnabledCache = new WeakMap()
|
const isWebViewTagEnabledCache = new WeakMap();
|
||||||
|
|
||||||
const isWebViewTagEnabled = function (contents) {
|
const isWebViewTagEnabled = function (contents) {
|
||||||
if (!isWebViewTagEnabledCache.has(contents)) {
|
if (!isWebViewTagEnabledCache.has(contents)) {
|
||||||
const webPreferences = contents.getLastWebPreferences() || {}
|
const webPreferences = contents.getLastWebPreferences() || {};
|
||||||
isWebViewTagEnabledCache.set(contents, !!webPreferences.webviewTag)
|
isWebViewTagEnabledCache.set(contents, !!webPreferences.webviewTag);
|
||||||
}
|
}
|
||||||
|
|
||||||
return isWebViewTagEnabledCache.get(contents)
|
return isWebViewTagEnabledCache.get(contents);
|
||||||
}
|
};
|
||||||
|
|
||||||
const makeSafeHandler = function (channel, handler) {
|
const makeSafeHandler = function (channel, handler) {
|
||||||
return (event, ...args) => {
|
return (event, ...args) => {
|
||||||
if (isWebViewTagEnabled(event.sender)) {
|
if (isWebViewTagEnabled(event.sender)) {
|
||||||
return handler(event, ...args)
|
return handler(event, ...args);
|
||||||
} else {
|
} else {
|
||||||
console.error(`<webview> IPC message ${channel} sent by WebContents with <webview> disabled (${event.sender.id})`)
|
console.error(`<webview> IPC message ${channel} sent by WebContents with <webview> disabled (${event.sender.id})`);
|
||||||
throw new Error('<webview> disabled')
|
throw new Error('<webview> disabled');
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
}
|
};
|
||||||
|
|
||||||
const handleMessage = function (channel, handler) {
|
const handleMessage = function (channel, handler) {
|
||||||
ipcMainInternal.handle(channel, makeSafeHandler(channel, handler))
|
ipcMainInternal.handle(channel, makeSafeHandler(channel, handler));
|
||||||
}
|
};
|
||||||
|
|
||||||
const handleMessageSync = function (channel, handler) {
|
const handleMessageSync = function (channel, handler) {
|
||||||
ipcMainUtils.handleSync(channel, makeSafeHandler(channel, handler))
|
ipcMainUtils.handleSync(channel, makeSafeHandler(channel, handler));
|
||||||
}
|
};
|
||||||
|
|
||||||
handleMessage('ELECTRON_GUEST_VIEW_MANAGER_CREATE_GUEST', function (event, params) {
|
handleMessage('ELECTRON_GUEST_VIEW_MANAGER_CREATE_GUEST', function (event, params) {
|
||||||
return createGuest(event.sender, params)
|
return createGuest(event.sender, params);
|
||||||
})
|
});
|
||||||
|
|
||||||
handleMessageSync('ELECTRON_GUEST_VIEW_MANAGER_CREATE_GUEST', function (event, params) {
|
handleMessageSync('ELECTRON_GUEST_VIEW_MANAGER_CREATE_GUEST', function (event, params) {
|
||||||
return createGuest(event.sender, params)
|
return createGuest(event.sender, params);
|
||||||
})
|
});
|
||||||
|
|
||||||
handleMessage('ELECTRON_GUEST_VIEW_MANAGER_ATTACH_GUEST', function (event, embedderFrameId, elementInstanceId, guestInstanceId, params) {
|
handleMessage('ELECTRON_GUEST_VIEW_MANAGER_ATTACH_GUEST', function (event, embedderFrameId, elementInstanceId, guestInstanceId, params) {
|
||||||
try {
|
try {
|
||||||
attachGuest(event, embedderFrameId, elementInstanceId, guestInstanceId, params)
|
attachGuest(event, embedderFrameId, elementInstanceId, guestInstanceId, params);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(`Guest attach failed: ${error}`)
|
console.error(`Guest attach failed: ${error}`);
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
|
|
||||||
// this message is sent by the actual <webview>
|
// this message is sent by the actual <webview>
|
||||||
ipcMainInternal.on('ELECTRON_GUEST_VIEW_MANAGER_FOCUS_CHANGE', function (event, focus, guestInstanceId) {
|
ipcMainInternal.on('ELECTRON_GUEST_VIEW_MANAGER_FOCUS_CHANGE', function (event, focus, guestInstanceId) {
|
||||||
const guest = getGuest(guestInstanceId)
|
const guest = getGuest(guestInstanceId);
|
||||||
if (guest === event.sender) {
|
if (guest === event.sender) {
|
||||||
event.sender.emit('focus-change', {}, focus, guestInstanceId)
|
event.sender.emit('focus-change', {}, focus, guestInstanceId);
|
||||||
} else {
|
} else {
|
||||||
console.error(`focus-change for guestInstanceId: ${guestInstanceId}`)
|
console.error(`focus-change for guestInstanceId: ${guestInstanceId}`);
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
|
|
||||||
handleMessage('ELECTRON_GUEST_VIEW_MANAGER_CALL', function (event, guestInstanceId, method, args) {
|
handleMessage('ELECTRON_GUEST_VIEW_MANAGER_CALL', function (event, guestInstanceId, method, args) {
|
||||||
const guest = getGuestForWebContents(guestInstanceId, event.sender)
|
const guest = getGuestForWebContents(guestInstanceId, event.sender);
|
||||||
if (!asyncMethods.has(method)) {
|
if (!asyncMethods.has(method)) {
|
||||||
throw new Error(`Invalid method: ${method}`)
|
throw new Error(`Invalid method: ${method}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
return guest[method](...args)
|
return guest[method](...args);
|
||||||
})
|
});
|
||||||
|
|
||||||
handleMessageSync('ELECTRON_GUEST_VIEW_MANAGER_CALL', function (event, guestInstanceId, method, args) {
|
handleMessageSync('ELECTRON_GUEST_VIEW_MANAGER_CALL', function (event, guestInstanceId, method, args) {
|
||||||
const guest = getGuestForWebContents(guestInstanceId, event.sender)
|
const guest = getGuestForWebContents(guestInstanceId, event.sender);
|
||||||
if (!syncMethods.has(method)) {
|
if (!syncMethods.has(method)) {
|
||||||
throw new Error(`Invalid method: ${method}`)
|
throw new Error(`Invalid method: ${method}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
return guest[method](...args)
|
return guest[method](...args);
|
||||||
})
|
});
|
||||||
|
|
||||||
|
handleMessageSync('ELECTRON_GUEST_VIEW_MANAGER_PROPERTY_GET', function (event, guestInstanceId, property) {
|
||||||
|
const guest = getGuestForWebContents(guestInstanceId, event.sender);
|
||||||
|
if (!properties.has(property)) {
|
||||||
|
throw new Error(`Invalid property: ${property}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
return guest[property];
|
||||||
|
});
|
||||||
|
|
||||||
|
handleMessageSync('ELECTRON_GUEST_VIEW_MANAGER_PROPERTY_SET', function (event, guestInstanceId, property, val) {
|
||||||
|
const guest = getGuestForWebContents(guestInstanceId, event.sender);
|
||||||
|
if (!properties.has(property)) {
|
||||||
|
throw new Error(`Invalid property: ${property}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
guest[property] = val;
|
||||||
|
});
|
||||||
|
|
||||||
|
handleMessage('ELECTRON_GUEST_VIEW_MANAGER_CAPTURE_PAGE', async function (event, guestInstanceId, args) {
|
||||||
|
const guest = getGuestForWebContents(guestInstanceId, event.sender);
|
||||||
|
|
||||||
|
return serialize(await guest.capturePage(...args));
|
||||||
|
});
|
||||||
|
|
||||||
// Returns WebContents from its guest id hosted in given webContents.
|
// Returns WebContents from its guest id hosted in given webContents.
|
||||||
const getGuestForWebContents = function (guestInstanceId, contents) {
|
const getGuestForWebContents = function (guestInstanceId, contents) {
|
||||||
const guest = getGuest(guestInstanceId)
|
const guest = getGuest(guestInstanceId);
|
||||||
if (!guest) {
|
if (!guest) {
|
||||||
throw new Error(`Invalid guestInstanceId: ${guestInstanceId}`)
|
throw new Error(`Invalid guestInstanceId: ${guestInstanceId}`);
|
||||||
}
|
}
|
||||||
if (guest.hostWebContents !== contents) {
|
if (guest.hostWebContents !== contents) {
|
||||||
throw new Error(`Access denied to guestInstanceId: ${guestInstanceId}`)
|
throw new Error(`Access denied to guestInstanceId: ${guestInstanceId}`);
|
||||||
}
|
}
|
||||||
return guest
|
return guest;
|
||||||
}
|
};
|
||||||
|
|
||||||
// Returns WebContents from its guest id.
|
// Returns WebContents from its guest id.
|
||||||
const getGuest = function (guestInstanceId) {
|
const getGuest = function (guestInstanceId) {
|
||||||
const guestInstance = guestInstances[guestInstanceId]
|
const guestInstance = guestInstances[guestInstanceId];
|
||||||
if (guestInstance != null) return guestInstance.guest
|
if (guestInstance != null) return guestInstance.guest;
|
||||||
}
|
};
|
||||||
|
|
||||||
// Returns the embedder of the guest.
|
// Returns the embedder of the guest.
|
||||||
const getEmbedder = function (guestInstanceId) {
|
const getEmbedder = function (guestInstanceId) {
|
||||||
const guestInstance = guestInstances[guestInstanceId]
|
const guestInstance = guestInstances[guestInstanceId];
|
||||||
if (guestInstance != null) return guestInstance.embedder
|
if (guestInstance != null) return guestInstance.embedder;
|
||||||
}
|
};
|
||||||
|
|
||||||
exports.getGuestForWebContents = getGuestForWebContents
|
exports.getGuestForWebContents = getGuestForWebContents;
|
||||||
exports.isWebViewTagEnabled = isWebViewTagEnabled
|
exports.isWebViewTagEnabled = isWebViewTagEnabled;
|
||||||
|
|||||||
@@ -1,13 +1,14 @@
|
|||||||
'use strict'
|
'use strict';
|
||||||
|
|
||||||
const { BrowserWindow, webContents } = require('electron')
|
const electron = require('electron');
|
||||||
const { isSameOrigin } = process.electronBinding('v8_util')
|
const { BrowserWindow } = electron;
|
||||||
const { ipcMainInternal } = require('@electron/internal/browser/ipc-main-internal')
|
const { isSameOrigin } = process.electronBinding('v8_util');
|
||||||
const ipcMainUtils = require('@electron/internal/browser/ipc-main-internal-utils')
|
const { ipcMainInternal } = require('@electron/internal/browser/ipc-main-internal');
|
||||||
const parseFeaturesString = require('@electron/internal/common/parse-features-string')
|
const ipcMainUtils = require('@electron/internal/browser/ipc-main-internal-utils');
|
||||||
|
const parseFeaturesString = require('@electron/internal/common/parse-features-string');
|
||||||
|
|
||||||
const hasProp = {}.hasOwnProperty
|
const hasProp = {}.hasOwnProperty;
|
||||||
const frameToGuest = new Map()
|
const frameToGuest = new Map();
|
||||||
|
|
||||||
// Security options that child windows will always inherit from parent windows
|
// Security options that child windows will always inherit from parent windows
|
||||||
const inheritedWebPreferences = new Map([
|
const inheritedWebPreferences = new Map([
|
||||||
@@ -19,107 +20,109 @@ const inheritedWebPreferences = new Map([
|
|||||||
['sandbox', true],
|
['sandbox', true],
|
||||||
['webviewTag', false],
|
['webviewTag', false],
|
||||||
['nodeIntegrationInSubFrames', false]
|
['nodeIntegrationInSubFrames', false]
|
||||||
])
|
]);
|
||||||
|
|
||||||
// Copy attribute of |parent| to |child| if it is not defined in |child|.
|
// Copy attribute of |parent| to |child| if it is not defined in |child|.
|
||||||
const mergeOptions = function (child, parent, visited) {
|
const mergeOptions = function (child, parent, visited) {
|
||||||
// Check for circular reference.
|
// Check for circular reference.
|
||||||
if (visited == null) visited = new Set()
|
if (visited == null) visited = new Set();
|
||||||
if (visited.has(parent)) return
|
if (visited.has(parent)) return;
|
||||||
|
|
||||||
visited.add(parent)
|
visited.add(parent);
|
||||||
for (const key in parent) {
|
for (const key in parent) {
|
||||||
if (key === 'type') continue
|
if (key === 'type') continue;
|
||||||
if (!hasProp.call(parent, key)) continue
|
if (!hasProp.call(parent, key)) continue;
|
||||||
if (key in child && key !== 'webPreferences') continue
|
if (key in child && key !== 'webPreferences') continue;
|
||||||
|
|
||||||
const value = parent[key]
|
const value = parent[key];
|
||||||
if (typeof value === 'object' && !Array.isArray(value)) {
|
if (typeof value === 'object' && !Array.isArray(value)) {
|
||||||
child[key] = mergeOptions(child[key] || {}, value, visited)
|
child[key] = mergeOptions(child[key] || {}, value, visited);
|
||||||
} else {
|
} else {
|
||||||
child[key] = value
|
child[key] = value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
visited.delete(parent)
|
visited.delete(parent);
|
||||||
|
|
||||||
return child
|
return child;
|
||||||
}
|
};
|
||||||
|
|
||||||
// Merge |options| with the |embedder|'s window's options.
|
// Merge |options| with the |embedder|'s window's options.
|
||||||
const mergeBrowserWindowOptions = function (embedder, options) {
|
const mergeBrowserWindowOptions = function (embedder, options) {
|
||||||
if (options.webPreferences == null) {
|
if (options.webPreferences == null) {
|
||||||
options.webPreferences = {}
|
options.webPreferences = {};
|
||||||
}
|
}
|
||||||
if (embedder.browserWindowOptions != null) {
|
if (embedder.browserWindowOptions != null) {
|
||||||
let parentOptions = embedder.browserWindowOptions
|
let parentOptions = embedder.browserWindowOptions;
|
||||||
|
|
||||||
// if parent's visibility is available, that overrides 'show' flag (#12125)
|
// if parent's visibility is available, that overrides 'show' flag (#12125)
|
||||||
const win = BrowserWindow.fromWebContents(embedder.webContents)
|
const win = BrowserWindow.fromWebContents(embedder.webContents);
|
||||||
if (win != null) {
|
if (win != null) {
|
||||||
parentOptions = { ...embedder.browserWindowOptions, show: win.isVisible() }
|
parentOptions = { ...embedder.browserWindowOptions, show: win.isVisible() };
|
||||||
}
|
}
|
||||||
|
|
||||||
// Inherit the original options if it is a BrowserWindow.
|
// Inherit the original options if it is a BrowserWindow.
|
||||||
mergeOptions(options, parentOptions)
|
mergeOptions(options, parentOptions);
|
||||||
} else {
|
} else {
|
||||||
// Or only inherit webPreferences if it is a webview.
|
// Or only inherit webPreferences if it is a webview.
|
||||||
mergeOptions(options.webPreferences, embedder.getLastWebPreferences())
|
mergeOptions(options.webPreferences, embedder.getLastWebPreferences());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Inherit certain option values from parent window
|
// Inherit certain option values from parent window
|
||||||
const webPreferences = embedder.getLastWebPreferences()
|
const webPreferences = embedder.getLastWebPreferences();
|
||||||
for (const [name, value] of inheritedWebPreferences) {
|
for (const [name, value] of inheritedWebPreferences) {
|
||||||
if (webPreferences[name] === value) {
|
if (webPreferences[name] === value) {
|
||||||
options.webPreferences[name] = value
|
options.webPreferences[name] = value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sets correct openerId here to give correct options to 'new-window' event handler
|
if (!webPreferences.nativeWindowOpen) {
|
||||||
options.webPreferences.openerId = embedder.id
|
// Sets correct openerId here to give correct options to 'new-window' event handler
|
||||||
|
options.webPreferences.openerId = embedder.id;
|
||||||
|
}
|
||||||
|
|
||||||
return options
|
return options;
|
||||||
}
|
};
|
||||||
|
|
||||||
// Setup a new guest with |embedder|
|
// Setup a new guest with |embedder|
|
||||||
const setupGuest = function (embedder, frameName, guest, options) {
|
const setupGuest = function (embedder, frameName, guest, options) {
|
||||||
// When |embedder| is destroyed we should also destroy attached guest, and if
|
// When |embedder| is destroyed we should also destroy attached guest, and if
|
||||||
// guest is closed by user then we should prevent |embedder| from double
|
// guest is closed by user then we should prevent |embedder| from double
|
||||||
// closing guest.
|
// closing guest.
|
||||||
const guestId = guest.webContents.id
|
const guestId = guest.webContents.id;
|
||||||
const closedByEmbedder = function () {
|
const closedByEmbedder = function () {
|
||||||
guest.removeListener('closed', closedByUser)
|
guest.removeListener('closed', closedByUser);
|
||||||
guest.destroy()
|
guest.destroy();
|
||||||
}
|
};
|
||||||
const closedByUser = function () {
|
const closedByUser = function () {
|
||||||
embedder._sendInternal('ELECTRON_GUEST_WINDOW_MANAGER_WINDOW_CLOSED_' + guestId)
|
embedder._sendInternal('ELECTRON_GUEST_WINDOW_MANAGER_WINDOW_CLOSED_' + guestId);
|
||||||
embedder.removeListener('current-render-view-deleted', closedByEmbedder)
|
embedder.removeListener('current-render-view-deleted', closedByEmbedder);
|
||||||
}
|
};
|
||||||
embedder.once('current-render-view-deleted', closedByEmbedder)
|
embedder.once('current-render-view-deleted', closedByEmbedder);
|
||||||
guest.once('closed', closedByUser)
|
guest.once('closed', closedByUser);
|
||||||
if (frameName) {
|
if (frameName) {
|
||||||
frameToGuest.set(frameName, guest)
|
frameToGuest.set(frameName, guest);
|
||||||
guest.frameName = frameName
|
guest.frameName = frameName;
|
||||||
guest.once('closed', function () {
|
guest.once('closed', function () {
|
||||||
frameToGuest.delete(frameName)
|
frameToGuest.delete(frameName);
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
return guestId
|
return guestId;
|
||||||
}
|
};
|
||||||
|
|
||||||
// Create a new guest created by |embedder| with |options|.
|
// Create a new guest created by |embedder| with |options|.
|
||||||
const createGuest = function (embedder, url, referrer, frameName, options, postData) {
|
const createGuest = function (embedder, url, referrer, frameName, options, postData) {
|
||||||
let guest = frameToGuest.get(frameName)
|
let guest = frameToGuest.get(frameName);
|
||||||
if (frameName && (guest != null)) {
|
if (frameName && (guest != null)) {
|
||||||
guest.loadURL(url)
|
guest.loadURL(url);
|
||||||
return guest.webContents.id
|
return guest.webContents.id;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remember the embedder window's id.
|
// Remember the embedder window's id.
|
||||||
if (options.webPreferences == null) {
|
if (options.webPreferences == null) {
|
||||||
options.webPreferences = {}
|
options.webPreferences = {};
|
||||||
}
|
}
|
||||||
|
|
||||||
guest = new BrowserWindow(options)
|
guest = new BrowserWindow(options);
|
||||||
if (!options.webContents) {
|
if (!options.webContents) {
|
||||||
// We should not call `loadURL` if the window was constructed from an
|
// We should not call `loadURL` if the window was constructed from an
|
||||||
// existing webContents (window.open in a sandboxed renderer).
|
// existing webContents (window.open in a sandboxed renderer).
|
||||||
@@ -128,233 +131,236 @@ const createGuest = function (embedder, url, referrer, frameName, options, postD
|
|||||||
// webContents is not necessary (it will navigate there anyway).
|
// webContents is not necessary (it will navigate there anyway).
|
||||||
const loadOptions = {
|
const loadOptions = {
|
||||||
httpReferrer: referrer
|
httpReferrer: referrer
|
||||||
}
|
};
|
||||||
if (postData != null) {
|
if (postData != null) {
|
||||||
loadOptions.postData = postData
|
loadOptions.postData = postData;
|
||||||
loadOptions.extraHeaders = 'content-type: application/x-www-form-urlencoded'
|
loadOptions.extraHeaders = 'content-type: application/x-www-form-urlencoded';
|
||||||
if (postData.length > 0) {
|
if (postData.length > 0) {
|
||||||
const postDataFront = postData[0].bytes.toString()
|
const postDataFront = postData[0].bytes.toString();
|
||||||
const boundary = /^--.*[^-\r\n]/.exec(postDataFront)
|
const boundary = /^--.*[^-\r\n]/.exec(postDataFront);
|
||||||
if (boundary != null) {
|
if (boundary != null) {
|
||||||
loadOptions.extraHeaders = `content-type: multipart/form-data; boundary=${boundary[0].substr(2)}`
|
loadOptions.extraHeaders = `content-type: multipart/form-data; boundary=${boundary[0].substr(2)}`;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
guest.loadURL(url, loadOptions)
|
guest.loadURL(url, loadOptions);
|
||||||
}
|
}
|
||||||
|
|
||||||
return setupGuest(embedder, frameName, guest, options)
|
return setupGuest(embedder, frameName, guest, options);
|
||||||
}
|
};
|
||||||
|
|
||||||
const getGuestWindow = function (guestContents) {
|
const getGuestWindow = function (guestContents) {
|
||||||
let guestWindow = BrowserWindow.fromWebContents(guestContents)
|
let guestWindow = BrowserWindow.fromWebContents(guestContents);
|
||||||
if (guestWindow == null) {
|
if (guestWindow == null) {
|
||||||
const hostContents = guestContents.hostWebContents
|
const hostContents = guestContents.hostWebContents;
|
||||||
if (hostContents != null) {
|
if (hostContents != null) {
|
||||||
guestWindow = BrowserWindow.fromWebContents(hostContents)
|
guestWindow = BrowserWindow.fromWebContents(hostContents);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!guestWindow) {
|
if (!guestWindow) {
|
||||||
throw new Error('getGuestWindow failed')
|
throw new Error('getGuestWindow failed');
|
||||||
}
|
}
|
||||||
return guestWindow
|
return guestWindow;
|
||||||
}
|
};
|
||||||
|
|
||||||
const isChildWindow = function (sender, target) {
|
const isChildWindow = function (sender, target) {
|
||||||
return target.getLastWebPreferences().openerId === sender.id
|
return target.getLastWebPreferences().openerId === sender.id;
|
||||||
}
|
};
|
||||||
|
|
||||||
const isRelatedWindow = function (sender, target) {
|
const isRelatedWindow = function (sender, target) {
|
||||||
return isChildWindow(sender, target) || isChildWindow(target, sender)
|
return isChildWindow(sender, target) || isChildWindow(target, sender);
|
||||||
}
|
};
|
||||||
|
|
||||||
const isScriptableWindow = function (sender, target) {
|
const isScriptableWindow = function (sender, target) {
|
||||||
return isRelatedWindow(sender, target) && isSameOrigin(sender.getURL(), target.getURL())
|
return isRelatedWindow(sender, target) && isSameOrigin(sender.getURL(), target.getURL());
|
||||||
}
|
};
|
||||||
|
|
||||||
const isNodeIntegrationEnabled = function (sender) {
|
const isNodeIntegrationEnabled = function (sender) {
|
||||||
return sender.getLastWebPreferences().nodeIntegration === true
|
return sender.getLastWebPreferences().nodeIntegration === true;
|
||||||
}
|
};
|
||||||
|
|
||||||
// Checks whether |sender| can access the |target|:
|
// Checks whether |sender| can access the |target|:
|
||||||
const canAccessWindow = function (sender, target) {
|
const canAccessWindow = function (sender, target) {
|
||||||
return isChildWindow(sender, target) ||
|
return isChildWindow(sender, target) ||
|
||||||
isScriptableWindow(sender, target) ||
|
isScriptableWindow(sender, target) ||
|
||||||
isNodeIntegrationEnabled(sender)
|
isNodeIntegrationEnabled(sender);
|
||||||
}
|
};
|
||||||
|
|
||||||
// Routed window.open messages with raw options
|
// Routed window.open messages with raw options
|
||||||
ipcMainInternal.on('ELECTRON_GUEST_WINDOW_MANAGER_WINDOW_OPEN', (event, url, frameName, features) => {
|
ipcMainInternal.on('ELECTRON_GUEST_WINDOW_MANAGER_WINDOW_OPEN', (event, url, frameName, features) => {
|
||||||
if (url == null || url === '') url = 'about:blank'
|
if (url == null || url === '') url = 'about:blank';
|
||||||
if (frameName == null) frameName = ''
|
if (frameName == null) frameName = '';
|
||||||
if (features == null) features = ''
|
if (features == null) features = '';
|
||||||
|
|
||||||
const options = {}
|
const options = {};
|
||||||
|
|
||||||
const ints = ['x', 'y', 'width', 'height', 'minWidth', 'maxWidth', 'minHeight', 'maxHeight', 'zoomFactor']
|
const ints = ['x', 'y', 'width', 'height', 'minWidth', 'maxWidth', 'minHeight', 'maxHeight', 'zoomFactor'];
|
||||||
const webPreferences = ['zoomFactor', 'nodeIntegration', 'enableRemoteModule', 'preload', 'javascript', 'contextIsolation', 'webviewTag']
|
const webPreferences = ['zoomFactor', 'nodeIntegration', 'enableRemoteModule', 'preload', 'javascript', 'contextIsolation', 'webviewTag'];
|
||||||
const disposition = 'new-window'
|
const disposition = 'new-window';
|
||||||
|
|
||||||
// Used to store additional features
|
// Used to store additional features
|
||||||
const additionalFeatures = []
|
const additionalFeatures = [];
|
||||||
|
|
||||||
// Parse the features
|
// Parse the features
|
||||||
parseFeaturesString(features, function (key, value) {
|
parseFeaturesString(features, function (key, value) {
|
||||||
if (value === undefined) {
|
if (value === undefined) {
|
||||||
additionalFeatures.push(key)
|
additionalFeatures.push(key);
|
||||||
} else {
|
} else {
|
||||||
// Don't allow webPreferences to be set since it must be an object
|
// Don't allow webPreferences to be set since it must be an object
|
||||||
// that cannot be directly overridden
|
// that cannot be directly overridden
|
||||||
if (key === 'webPreferences') return
|
if (key === 'webPreferences') return;
|
||||||
|
|
||||||
if (webPreferences.includes(key)) {
|
if (webPreferences.includes(key)) {
|
||||||
if (options.webPreferences == null) {
|
if (options.webPreferences == null) {
|
||||||
options.webPreferences = {}
|
options.webPreferences = {};
|
||||||
}
|
}
|
||||||
options.webPreferences[key] = value
|
options.webPreferences[key] = value;
|
||||||
} else {
|
} else {
|
||||||
options[key] = value
|
options[key] = value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
if (options.left) {
|
if (options.left) {
|
||||||
if (options.x == null) {
|
if (options.x == null) {
|
||||||
options.x = options.left
|
options.x = options.left;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (options.top) {
|
if (options.top) {
|
||||||
if (options.y == null) {
|
if (options.y == null) {
|
||||||
options.y = options.top
|
options.y = options.top;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (options.title == null) {
|
if (options.title == null) {
|
||||||
options.title = frameName
|
options.title = frameName;
|
||||||
}
|
}
|
||||||
if (options.width == null) {
|
if (options.width == null) {
|
||||||
options.width = 800
|
options.width = 800;
|
||||||
}
|
}
|
||||||
if (options.height == null) {
|
if (options.height == null) {
|
||||||
options.height = 600
|
options.height = 600;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const name of ints) {
|
for (const name of ints) {
|
||||||
if (options[name] != null) {
|
if (options[name] != null) {
|
||||||
options[name] = parseInt(options[name], 10)
|
options[name] = parseInt(options[name], 10);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const referrer = { url: '', policy: 'default' }
|
const referrer = { url: '', policy: 'default' };
|
||||||
ipcMainInternal.emit('ELECTRON_GUEST_WINDOW_MANAGER_INTERNAL_WINDOW_OPEN', event,
|
internalWindowOpen(event, url, referrer, frameName, disposition, options, additionalFeatures);
|
||||||
url, referrer, frameName, disposition, options, additionalFeatures)
|
});
|
||||||
})
|
|
||||||
|
|
||||||
// Routed window.open messages with fully parsed options
|
// Routed window.open messages with fully parsed options
|
||||||
ipcMainInternal.on('ELECTRON_GUEST_WINDOW_MANAGER_INTERNAL_WINDOW_OPEN', function (event, url, referrer,
|
function internalWindowOpen (event, url, referrer, frameName, disposition, options, additionalFeatures, postData) {
|
||||||
frameName, disposition, options, additionalFeatures, postData) {
|
options = mergeBrowserWindowOptions(event.sender, options);
|
||||||
options = mergeBrowserWindowOptions(event.sender, options)
|
event.sender.emit('new-window', event, url, frameName, disposition, options, additionalFeatures, referrer);
|
||||||
event.sender.emit('new-window', event, url, frameName, disposition, options, additionalFeatures, referrer)
|
const { newGuest } = event;
|
||||||
const { newGuest } = event
|
|
||||||
if ((event.sender.getType() === 'webview' && event.sender.getLastWebPreferences().disablePopups) || event.defaultPrevented) {
|
if ((event.sender.getType() === 'webview' && event.sender.getLastWebPreferences().disablePopups) || event.defaultPrevented) {
|
||||||
if (newGuest != null) {
|
if (newGuest != null) {
|
||||||
if (options.webContents === newGuest.webContents) {
|
if (options.webContents === newGuest.webContents) {
|
||||||
// the webContents is not changed, so set defaultPrevented to false to
|
// the webContents is not changed, so set defaultPrevented to false to
|
||||||
// stop the callers of this event from destroying the webContents.
|
// stop the callers of this event from destroying the webContents.
|
||||||
event.defaultPrevented = false
|
event.defaultPrevented = false;
|
||||||
}
|
}
|
||||||
event.returnValue = setupGuest(event.sender, frameName, newGuest, options)
|
event.returnValue = setupGuest(event.sender, frameName, newGuest, options);
|
||||||
} else {
|
} else {
|
||||||
event.returnValue = null
|
event.returnValue = null;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
event.returnValue = createGuest(event.sender, url, referrer, frameName, options, postData)
|
event.returnValue = createGuest(event.sender, url, referrer, frameName, options, postData);
|
||||||
}
|
}
|
||||||
})
|
}
|
||||||
|
|
||||||
const makeSafeHandler = function (handler) {
|
const makeSafeHandler = function (handler) {
|
||||||
return (event, guestId, ...args) => {
|
return (event, guestId, ...args) => {
|
||||||
const guestContents = webContents.fromId(guestId)
|
// Access webContents via electron to prevent circular require.
|
||||||
|
const guestContents = electron.webContents.fromId(guestId);
|
||||||
if (!guestContents) {
|
if (!guestContents) {
|
||||||
throw new Error(`Invalid guestId: ${guestId}`)
|
throw new Error(`Invalid guestId: ${guestId}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
return handler(event, guestContents, ...args)
|
return handler(event, guestContents, ...args);
|
||||||
}
|
};
|
||||||
}
|
};
|
||||||
|
|
||||||
const handleMessage = function (channel, handler) {
|
const handleMessage = function (channel, handler) {
|
||||||
ipcMainInternal.handle(channel, makeSafeHandler(handler))
|
ipcMainInternal.handle(channel, makeSafeHandler(handler));
|
||||||
}
|
};
|
||||||
|
|
||||||
const handleMessageSync = function (channel, handler) {
|
const handleMessageSync = function (channel, handler) {
|
||||||
ipcMainUtils.handleSync(channel, makeSafeHandler(handler))
|
ipcMainUtils.handleSync(channel, makeSafeHandler(handler));
|
||||||
}
|
};
|
||||||
|
|
||||||
const assertCanAccessWindow = function (contents, guestContents) {
|
const securityCheck = function (contents, guestContents, check) {
|
||||||
if (!canAccessWindow(contents, guestContents)) {
|
if (!check(contents, guestContents)) {
|
||||||
console.error(`Blocked ${contents.getURL()} from accessing guestId: ${guestContents.id}`)
|
console.error(`Blocked ${contents.getURL()} from accessing guestId: ${guestContents.id}`);
|
||||||
throw new Error(`Access denied to guestId: ${guestContents.id}`)
|
throw new Error(`Access denied to guestId: ${guestContents.id}`);
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
const windowMethods = new Set([
|
const windowMethods = new Set([
|
||||||
'destroy',
|
'destroy',
|
||||||
'focus',
|
'focus',
|
||||||
'blur'
|
'blur'
|
||||||
])
|
]);
|
||||||
|
|
||||||
handleMessage('ELECTRON_GUEST_WINDOW_MANAGER_WINDOW_METHOD', (event, guestContents, method, ...args) => {
|
handleMessage('ELECTRON_GUEST_WINDOW_MANAGER_WINDOW_METHOD', (event, guestContents, method, ...args) => {
|
||||||
assertCanAccessWindow(event.sender, guestContents)
|
securityCheck(event.sender, guestContents, canAccessWindow);
|
||||||
|
|
||||||
if (!windowMethods.has(method)) {
|
if (!windowMethods.has(method)) {
|
||||||
console.error(`Blocked ${event.sender.getURL()} from calling method: ${method}`)
|
console.error(`Blocked ${event.sender.getURL()} from calling method: ${method}`);
|
||||||
throw new Error(`Invalid method: ${method}`)
|
throw new Error(`Invalid method: ${method}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
return getGuestWindow(guestContents)[method](...args)
|
return getGuestWindow(guestContents)[method](...args);
|
||||||
})
|
});
|
||||||
|
|
||||||
handleMessage('ELECTRON_GUEST_WINDOW_MANAGER_WINDOW_POSTMESSAGE', (event, guestContents, message, targetOrigin, sourceOrigin) => {
|
handleMessage('ELECTRON_GUEST_WINDOW_MANAGER_WINDOW_POSTMESSAGE', (event, guestContents, message, targetOrigin, sourceOrigin) => {
|
||||||
if (targetOrigin == null) {
|
if (targetOrigin == null) {
|
||||||
targetOrigin = '*'
|
targetOrigin = '*';
|
||||||
}
|
}
|
||||||
|
|
||||||
// The W3C does not seem to have word on how postMessage should work when the
|
// The W3C does not seem to have word on how postMessage should work when the
|
||||||
// origins do not match, so we do not do |canAccessWindow| check here since
|
// origins do not match, so we do not do |canAccessWindow| check here since
|
||||||
// postMessage across origins is useful and not harmful.
|
// postMessage across origins is useful and not harmful.
|
||||||
|
securityCheck(event.sender, guestContents, isRelatedWindow);
|
||||||
|
|
||||||
if (targetOrigin === '*' || isSameOrigin(guestContents.getURL(), targetOrigin)) {
|
if (targetOrigin === '*' || isSameOrigin(guestContents.getURL(), targetOrigin)) {
|
||||||
const sourceId = event.sender.id
|
const sourceId = event.sender.id;
|
||||||
guestContents._sendInternal('ELECTRON_GUEST_WINDOW_POSTMESSAGE', sourceId, message, sourceOrigin)
|
guestContents._sendInternal('ELECTRON_GUEST_WINDOW_POSTMESSAGE', sourceId, message, sourceOrigin);
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
|
|
||||||
const webContentsMethodsAsync = new Set([
|
const webContentsMethodsAsync = new Set([
|
||||||
'loadURL',
|
'loadURL',
|
||||||
'executeJavaScript',
|
'executeJavaScript',
|
||||||
'print'
|
'print'
|
||||||
])
|
]);
|
||||||
|
|
||||||
handleMessage('ELECTRON_GUEST_WINDOW_MANAGER_WEB_CONTENTS_METHOD', (event, guestContents, method, ...args) => {
|
handleMessage('ELECTRON_GUEST_WINDOW_MANAGER_WEB_CONTENTS_METHOD', (event, guestContents, method, ...args) => {
|
||||||
assertCanAccessWindow(event.sender, guestContents)
|
securityCheck(event.sender, guestContents, canAccessWindow);
|
||||||
|
|
||||||
if (!webContentsMethodsAsync.has(method)) {
|
if (!webContentsMethodsAsync.has(method)) {
|
||||||
console.error(`Blocked ${event.sender.getURL()} from calling method: ${method}`)
|
console.error(`Blocked ${event.sender.getURL()} from calling method: ${method}`);
|
||||||
throw new Error(`Invalid method: ${method}`)
|
throw new Error(`Invalid method: ${method}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
return guestContents[method](...args)
|
return guestContents[method](...args);
|
||||||
})
|
});
|
||||||
|
|
||||||
const webContentsMethodsSync = new Set([
|
const webContentsMethodsSync = new Set([
|
||||||
'getURL'
|
'getURL'
|
||||||
])
|
]);
|
||||||
|
|
||||||
handleMessageSync('ELECTRON_GUEST_WINDOW_MANAGER_WEB_CONTENTS_METHOD', (event, guestContents, method, ...args) => {
|
handleMessageSync('ELECTRON_GUEST_WINDOW_MANAGER_WEB_CONTENTS_METHOD', (event, guestContents, method, ...args) => {
|
||||||
assertCanAccessWindow(event.sender, guestContents)
|
securityCheck(event.sender, guestContents, canAccessWindow);
|
||||||
|
|
||||||
if (!webContentsMethodsSync.has(method)) {
|
if (!webContentsMethodsSync.has(method)) {
|
||||||
console.error(`Blocked ${event.sender.getURL()} from calling method: ${method}`)
|
console.error(`Blocked ${event.sender.getURL()} from calling method: ${method}`);
|
||||||
throw new Error(`Invalid method: ${method}`)
|
throw new Error(`Invalid method: ${method}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
return guestContents[method](...args)
|
return guestContents[method](...args);
|
||||||
})
|
});
|
||||||
|
|
||||||
|
exports.internalWindowOpen = internalWindowOpen;
|
||||||
|
|||||||
@@ -1,45 +1,47 @@
|
|||||||
import { Buffer } from 'buffer'
|
import { Buffer } from 'buffer';
|
||||||
import * as fs from 'fs'
|
import * as fs from 'fs';
|
||||||
import * as path from 'path'
|
import * as path from 'path';
|
||||||
import * as util from 'util'
|
import * as util from 'util';
|
||||||
|
|
||||||
const Module = require('module')
|
const Module = require('module');
|
||||||
|
|
||||||
// We modified the original process.argv to let node.js load the init.js,
|
// We modified the original process.argv to let node.js load the init.js,
|
||||||
// we need to restore it here.
|
// we need to restore it here.
|
||||||
process.argv.splice(1, 1)
|
process.argv.splice(1, 1);
|
||||||
|
|
||||||
// Clear search paths.
|
// Clear search paths.
|
||||||
require('../common/reset-search-paths')
|
require('../common/reset-search-paths');
|
||||||
|
|
||||||
// Import common settings.
|
// Import common settings.
|
||||||
require('@electron/internal/common/init')
|
require('@electron/internal/common/init');
|
||||||
|
|
||||||
if (process.platform === 'win32') {
|
if (process.platform === 'win32') {
|
||||||
// Redirect node's console to use our own implementations, since node can not
|
// Redirect node's console to use our own implementations, since node can not
|
||||||
// handle console output when running as GUI program.
|
// handle console output when running as GUI program.
|
||||||
const consoleLog = (format: any, ...args: any[]) => {
|
const consoleLog = (...args: any[]) => {
|
||||||
return process.log(util.format(format, ...args) + '\n')
|
// @ts-ignore this typing is incorrect; 'format' is an optional parameter
|
||||||
}
|
// See https://nodejs.org/api/util.html#util_util_format_format_args
|
||||||
|
return process.log(util.format(...args) + '\n');
|
||||||
|
};
|
||||||
const streamWrite: NodeJS.WritableStream['write'] = function (chunk: Buffer | string, encoding?: any, callback?: Function) {
|
const streamWrite: NodeJS.WritableStream['write'] = function (chunk: Buffer | string, encoding?: any, callback?: Function) {
|
||||||
if (Buffer.isBuffer(chunk)) {
|
if (Buffer.isBuffer(chunk)) {
|
||||||
chunk = chunk.toString(encoding)
|
chunk = chunk.toString(encoding);
|
||||||
}
|
}
|
||||||
process.log(chunk)
|
process.log(chunk);
|
||||||
if (callback) {
|
if (callback) {
|
||||||
callback()
|
callback();
|
||||||
}
|
}
|
||||||
return true
|
return true;
|
||||||
}
|
};
|
||||||
console.log = console.error = console.warn = consoleLog
|
console.log = console.error = console.warn = consoleLog;
|
||||||
process.stdout.write = process.stderr.write = streamWrite
|
process.stdout.write = process.stderr.write = streamWrite;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Don't quit on fatal error.
|
// Don't quit on fatal error.
|
||||||
process.on('uncaughtException', function (error) {
|
process.on('uncaughtException', function (error) {
|
||||||
// Do nothing if the user has a custom uncaught exception handler.
|
// Do nothing if the user has a custom uncaught exception handler.
|
||||||
if (process.listenerCount('uncaughtException') > 1) {
|
if (process.listenerCount('uncaughtException') > 1) {
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Show error in GUI.
|
// Show error in GUI.
|
||||||
@@ -48,18 +50,18 @@ process.on('uncaughtException', function (error) {
|
|||||||
// so we import it inside the handler down here
|
// so we import it inside the handler down here
|
||||||
import('electron')
|
import('electron')
|
||||||
.then(({ dialog }) => {
|
.then(({ dialog }) => {
|
||||||
const stack = error.stack ? error.stack : `${error.name}: ${error.message}`
|
const stack = error.stack ? error.stack : `${error.name}: ${error.message}`;
|
||||||
const message = 'Uncaught Exception:\n' + stack
|
const message = 'Uncaught Exception:\n' + stack;
|
||||||
dialog.showErrorBox('A JavaScript error occurred in the main process', message)
|
dialog.showErrorBox('A JavaScript error occurred in the main process', message);
|
||||||
})
|
});
|
||||||
})
|
});
|
||||||
|
|
||||||
// Emit 'exit' event on quit.
|
// Emit 'exit' event on quit.
|
||||||
const { app } = require('electron')
|
const { app } = require('electron');
|
||||||
|
|
||||||
app.on('quit', function (event, exitCode) {
|
app.on('quit', function (event, exitCode) {
|
||||||
process.emit('exit', exitCode)
|
process.emit('exit', exitCode);
|
||||||
})
|
});
|
||||||
|
|
||||||
if (process.platform === 'win32') {
|
if (process.platform === 'win32') {
|
||||||
// If we are a Squirrel.Windows-installed app, set app user model ID
|
// If we are a Squirrel.Windows-installed app, set app user model ID
|
||||||
@@ -76,138 +78,139 @@ if (process.platform === 'win32') {
|
|||||||
// form `com.squirrel.PACKAGE-NAME.OUREXE`. We need to call
|
// form `com.squirrel.PACKAGE-NAME.OUREXE`. We need to call
|
||||||
// app.setAppUserModelId with a matching identifier so that renderer processes
|
// app.setAppUserModelId with a matching identifier so that renderer processes
|
||||||
// will inherit this value.
|
// will inherit this value.
|
||||||
const updateDotExe = path.join(path.dirname(process.execPath), '..', 'update.exe')
|
const updateDotExe = path.join(path.dirname(process.execPath), '..', 'update.exe');
|
||||||
|
|
||||||
if (fs.existsSync(updateDotExe)) {
|
if (fs.existsSync(updateDotExe)) {
|
||||||
const packageDir = path.dirname(path.resolve(updateDotExe))
|
const packageDir = path.dirname(path.resolve(updateDotExe));
|
||||||
const packageName = path.basename(packageDir).replace(/\s/g, '')
|
const packageName = path.basename(packageDir).replace(/\s/g, '');
|
||||||
const exeName = path.basename(process.execPath).replace(/\.exe$/i, '').replace(/\s/g, '')
|
const exeName = path.basename(process.execPath).replace(/\.exe$/i, '').replace(/\s/g, '');
|
||||||
|
|
||||||
app.setAppUserModelId(`com.squirrel.${packageName}.${exeName}`)
|
app.setAppUserModelId(`com.squirrel.${packageName}.${exeName}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Map process.exit to app.exit, which quits gracefully.
|
// Map process.exit to app.exit, which quits gracefully.
|
||||||
process.exit = app.exit as () => never
|
process.exit = app.exit as () => never;
|
||||||
|
|
||||||
// Load the RPC server.
|
// Load the RPC server.
|
||||||
require('@electron/internal/browser/rpc-server')
|
require('@electron/internal/browser/rpc-server');
|
||||||
|
|
||||||
// Load the guest view manager.
|
// Load the guest view manager.
|
||||||
require('@electron/internal/browser/guest-view-manager')
|
require('@electron/internal/browser/guest-view-manager');
|
||||||
require('@electron/internal/browser/guest-window-manager')
|
require('@electron/internal/browser/guest-window-manager');
|
||||||
|
|
||||||
// Now we try to load app's package.json.
|
// Now we try to load app's package.json.
|
||||||
let packagePath = null
|
let packagePath = null;
|
||||||
let packageJson = null
|
let packageJson = null;
|
||||||
const searchPaths = ['app', 'app.asar', 'default_app.asar']
|
const searchPaths = ['app', 'app.asar', 'default_app.asar'];
|
||||||
|
|
||||||
if (process.resourcesPath) {
|
if (process.resourcesPath) {
|
||||||
for (packagePath of searchPaths) {
|
for (packagePath of searchPaths) {
|
||||||
try {
|
try {
|
||||||
packagePath = path.join(process.resourcesPath, packagePath)
|
packagePath = path.join(process.resourcesPath, packagePath);
|
||||||
packageJson = Module._load(path.join(packagePath, 'package.json'))
|
packageJson = Module._load(path.join(packagePath, 'package.json'));
|
||||||
break
|
break;
|
||||||
} catch {
|
} catch {
|
||||||
continue
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (packageJson == null) {
|
if (packageJson == null) {
|
||||||
process.nextTick(function () {
|
process.nextTick(function () {
|
||||||
return process.exit(1)
|
return process.exit(1);
|
||||||
})
|
});
|
||||||
throw new Error('Unable to find a valid app')
|
throw new Error('Unable to find a valid app');
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set application's version.
|
// Set application's version.
|
||||||
if (packageJson.version != null) {
|
if (packageJson.version != null) {
|
||||||
app.setVersion(packageJson.version)
|
app.setVersion(packageJson.version);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set application's name.
|
// Set application's name.
|
||||||
if (packageJson.productName != null) {
|
if (packageJson.productName != null) {
|
||||||
app.name = `${packageJson.productName}`.trim()
|
app.name = `${packageJson.productName}`.trim();
|
||||||
} else if (packageJson.name != null) {
|
} else if (packageJson.name != null) {
|
||||||
app.name = `${packageJson.name}`.trim()
|
app.name = `${packageJson.name}`.trim();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set application's desktop name.
|
// Set application's desktop name.
|
||||||
if (packageJson.desktopName != null) {
|
if (packageJson.desktopName != null) {
|
||||||
app.setDesktopName(packageJson.desktopName)
|
app.setDesktopName(packageJson.desktopName);
|
||||||
} else {
|
} else {
|
||||||
app.setDesktopName(`${app.name}.desktop`)
|
app.setDesktopName(`${app.name}.desktop`);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set v8 flags, delibrately lazy load so that apps that do not use this
|
// Set v8 flags, delibrately lazy load so that apps that do not use this
|
||||||
// feature do not pay the price
|
// feature do not pay the price
|
||||||
if (packageJson.v8Flags != null) {
|
if (packageJson.v8Flags != null) {
|
||||||
require('v8').setFlagsFromString(packageJson.v8Flags)
|
require('v8').setFlagsFromString(packageJson.v8Flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
app._setDefaultAppPaths(packagePath)
|
app._setDefaultAppPaths(packagePath);
|
||||||
|
|
||||||
// Load the chrome devtools support.
|
// Load the chrome devtools support.
|
||||||
require('@electron/internal/browser/devtools')
|
require('@electron/internal/browser/devtools');
|
||||||
|
|
||||||
const features = process.electronBinding('features')
|
const features = process.electronBinding('features');
|
||||||
|
|
||||||
// Load the chrome extension support.
|
// Load the chrome extension support.
|
||||||
if (!features.isExtensionsEnabled()) {
|
if (!features.isExtensionsEnabled()) {
|
||||||
require('@electron/internal/browser/chrome-extension')
|
require('@electron/internal/browser/chrome-extension');
|
||||||
}
|
}
|
||||||
|
|
||||||
if (features.isRemoteModuleEnabled()) {
|
if (features.isRemoteModuleEnabled()) {
|
||||||
require('@electron/internal/browser/remote/server')
|
require('@electron/internal/browser/remote/server');
|
||||||
}
|
}
|
||||||
|
|
||||||
// Load protocol module to ensure it is populated on app ready
|
// Load protocol module to ensure it is populated on app ready
|
||||||
require('@electron/internal/browser/api/protocol')
|
require('@electron/internal/browser/api/protocol');
|
||||||
|
|
||||||
// Set main startup script of the app.
|
// Set main startup script of the app.
|
||||||
const mainStartupScript = packageJson.main || 'index.js'
|
const mainStartupScript = packageJson.main || 'index.js';
|
||||||
|
|
||||||
const KNOWN_XDG_DESKTOP_VALUES = ['Pantheon', 'Unity:Unity7', 'pop:GNOME']
|
const KNOWN_XDG_DESKTOP_VALUES = ['Pantheon', 'Unity:Unity7', 'pop:GNOME'];
|
||||||
|
|
||||||
function currentPlatformSupportsAppIndicator () {
|
function currentPlatformSupportsAppIndicator () {
|
||||||
if (process.platform !== 'linux') return false
|
if (process.platform !== 'linux') return false;
|
||||||
const currentDesktop = process.env.XDG_CURRENT_DESKTOP
|
const currentDesktop = process.env.XDG_CURRENT_DESKTOP;
|
||||||
|
|
||||||
if (!currentDesktop) return false
|
if (!currentDesktop) return false;
|
||||||
if (KNOWN_XDG_DESKTOP_VALUES.includes(currentDesktop)) return true
|
if (KNOWN_XDG_DESKTOP_VALUES.includes(currentDesktop)) return true;
|
||||||
// ubuntu based or derived session (default ubuntu one, communitheme…) supports
|
// ubuntu based or derived session (default ubuntu one, communitheme…) supports
|
||||||
// indicator too.
|
// indicator too.
|
||||||
if (/ubuntu/ig.test(currentDesktop)) return true
|
if (/ubuntu/ig.test(currentDesktop)) return true;
|
||||||
|
|
||||||
return false
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Workaround for electron/electron#5050 and electron/electron#9046
|
// Workaround for electron/electron#5050 and electron/electron#9046
|
||||||
if (currentPlatformSupportsAppIndicator()) {
|
if (currentPlatformSupportsAppIndicator()) {
|
||||||
process.env.XDG_CURRENT_DESKTOP = 'Unity'
|
process.env.XDG_CURRENT_DESKTOP = 'Unity';
|
||||||
}
|
}
|
||||||
|
|
||||||
// Quit when all windows are closed and no other one is listening to this.
|
// Quit when all windows are closed and no other one is listening to this.
|
||||||
app.on('window-all-closed', () => {
|
app.on('window-all-closed', () => {
|
||||||
if (app.listenerCount('window-all-closed') === 1) {
|
if (app.listenerCount('window-all-closed') === 1) {
|
||||||
app.quit()
|
app.quit();
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
|
|
||||||
Promise.all([
|
const { setDefaultApplicationMenu } = require('@electron/internal/browser/default-menu');
|
||||||
import('@electron/internal/browser/default-menu'),
|
|
||||||
app.whenReady()
|
// Create default menu.
|
||||||
]).then(([{ setDefaultApplicationMenu }]) => {
|
//
|
||||||
// Create default menu
|
// Note that the task must be added before loading any app, so we can make sure
|
||||||
setDefaultApplicationMenu()
|
// the call is maded before any user window is created, otherwise the default
|
||||||
})
|
// menu may show even when user explicitly hides the menu.
|
||||||
|
app.once('ready', setDefaultApplicationMenu);
|
||||||
|
|
||||||
if (packagePath) {
|
if (packagePath) {
|
||||||
// Finally load app's main.js and transfer control to C++.
|
// Finally load app's main.js and transfer control to C++.
|
||||||
process._firstFileName = Module._resolveFilename(path.join(packagePath, mainStartupScript), null, false)
|
process._firstFileName = Module._resolveFilename(path.join(packagePath, mainStartupScript), null, false);
|
||||||
Module._load(path.join(packagePath, mainStartupScript), Module, true)
|
Module._load(path.join(packagePath, mainStartupScript), Module, true);
|
||||||
} else {
|
} else {
|
||||||
console.error('Failed to locate a valid package to load (app, app.asar or default_app.asar)')
|
console.error('Failed to locate a valid package to load (app, app.asar or default_app.asar)');
|
||||||
console.error('This normally means you\'ve damaged the Electron package somehow')
|
console.error('This normally means you\'ve damaged the Electron package somehow');
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,33 +1,33 @@
|
|||||||
import { EventEmitter } from 'events'
|
import { EventEmitter } from 'events';
|
||||||
import { IpcMainInvokeEvent } from 'electron'
|
import { IpcMainInvokeEvent } from 'electron';
|
||||||
|
|
||||||
export class IpcMainImpl extends EventEmitter {
|
export class IpcMainImpl extends EventEmitter {
|
||||||
private _invokeHandlers: Map<string, (e: IpcMainInvokeEvent, ...args: any[]) => void> = new Map();
|
private _invokeHandlers: Map<string, (e: IpcMainInvokeEvent, ...args: any[]) => void> = new Map();
|
||||||
|
|
||||||
handle: Electron.IpcMain['handle'] = (method, fn) => {
|
handle: Electron.IpcMain['handle'] = (method, fn) => {
|
||||||
if (this._invokeHandlers.has(method)) {
|
if (this._invokeHandlers.has(method)) {
|
||||||
throw new Error(`Attempted to register a second handler for '${method}'`)
|
throw new Error(`Attempted to register a second handler for '${method}'`);
|
||||||
}
|
}
|
||||||
if (typeof fn !== 'function') {
|
if (typeof fn !== 'function') {
|
||||||
throw new Error(`Expected handler to be a function, but found type '${typeof fn}'`)
|
throw new Error(`Expected handler to be a function, but found type '${typeof fn}'`);
|
||||||
}
|
}
|
||||||
this._invokeHandlers.set(method, async (e, ...args) => {
|
this._invokeHandlers.set(method, async (e, ...args) => {
|
||||||
try {
|
try {
|
||||||
(e as any)._reply(await Promise.resolve(fn(e, ...args)))
|
(e as any)._reply(await Promise.resolve(fn(e, ...args)));
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
(e as any)._throw(err)
|
(e as any)._throw(err);
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
handleOnce: Electron.IpcMain['handleOnce'] = (method, fn) => {
|
handleOnce: Electron.IpcMain['handleOnce'] = (method, fn) => {
|
||||||
this.handle(method, (e, ...args) => {
|
this.handle(method, (e, ...args) => {
|
||||||
this.removeHandler(method)
|
this.removeHandler(method);
|
||||||
return fn(e, ...args)
|
return fn(e, ...args);
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
removeHandler (method: string) {
|
removeHandler (method: string) {
|
||||||
this._invokeHandlers.delete(method)
|
this._invokeHandlers.delete(method);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,44 +1,44 @@
|
|||||||
import { ipcMainInternal } from '@electron/internal/browser/ipc-main-internal'
|
import { ipcMainInternal } from '@electron/internal/browser/ipc-main-internal';
|
||||||
|
|
||||||
type IPCHandler = (event: Electron.IpcMainInvokeEvent, ...args: any[]) => any
|
type IPCHandler = (event: Electron.IpcMainInvokeEvent, ...args: any[]) => any
|
||||||
|
|
||||||
export const handleSync = function <T extends IPCHandler> (channel: string, handler: T) {
|
export const handleSync = function <T extends IPCHandler> (channel: string, handler: T) {
|
||||||
ipcMainInternal.on(channel, async (event, ...args) => {
|
ipcMainInternal.on(channel, async (event, ...args) => {
|
||||||
try {
|
try {
|
||||||
event.returnValue = [null, await handler(event, ...args)]
|
event.returnValue = [null, await handler(event, ...args)];
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
event.returnValue = [error]
|
event.returnValue = [error];
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
let nextId = 0
|
let nextId = 0;
|
||||||
|
|
||||||
export function invokeInWebContents<T> (sender: Electron.WebContentsInternal, sendToAll: boolean, command: string, ...args: any[]) {
|
export function invokeInWebContents<T> (sender: Electron.WebContentsInternal, sendToAll: boolean, command: string, ...args: any[]) {
|
||||||
return new Promise<T>((resolve, reject) => {
|
return new Promise<T>((resolve, reject) => {
|
||||||
const requestId = ++nextId
|
const requestId = ++nextId;
|
||||||
const channel = `${command}_RESPONSE_${requestId}`
|
const channel = `${command}_RESPONSE_${requestId}`;
|
||||||
ipcMainInternal.on(channel, function handler (
|
ipcMainInternal.on(channel, function handler (
|
||||||
event, error: Electron.SerializedError, result: any
|
event, error: Electron.SerializedError, result: any
|
||||||
) {
|
) {
|
||||||
if (event.sender !== sender) {
|
if (event.sender !== sender) {
|
||||||
console.error(`Reply to ${command} sent by unexpected WebContents (${event.sender.id})`)
|
console.error(`Reply to ${command} sent by unexpected WebContents (${event.sender.id})`);
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
ipcMainInternal.removeListener(channel, handler)
|
ipcMainInternal.removeListener(channel, handler);
|
||||||
|
|
||||||
if (error) {
|
if (error) {
|
||||||
reject(error)
|
reject(error);
|
||||||
} else {
|
} else {
|
||||||
resolve(result)
|
resolve(result);
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
|
|
||||||
if (sendToAll) {
|
if (sendToAll) {
|
||||||
sender._sendInternalToAll(command, requestId, ...args)
|
sender._sendInternalToAll(command, requestId, ...args);
|
||||||
} else {
|
} else {
|
||||||
sender._sendInternal(command, requestId, ...args)
|
sender._sendInternal(command, requestId, ...args);
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user