Compare commits

..

81 Commits

Author SHA1 Message Date
Cheng Zhao
367f94aa76 Bump v1.3.1 2016-07-27 13:21:17 +09:00
Cheng Zhao
1e61743242 Merge pull request #6602 from electron/appusermodelid-remove-spaces
Remove all spaces from potential appUserModelID as it isn't allowed by the spec
2016-07-27 10:53:52 +09:00
Cheng Zhao
b8bafbc5a3 Merge pull request #6620 from electron/tray-highlight-toggle
Add option to always highlight the tray icon
2016-07-27 10:49:38 +09:00
Cheng Zhao
99b523176b Merge pull request #6619 from electron/web-contents-copy-image-at
Add webContents.copyImageAt(x, y)
2016-07-27 10:15:38 +09:00
Cheng Zhao
7994f087fb Merge pull request #6618 from electron/code-range-registration
Only register code range in Windows crash reporter once
2016-07-27 09:52:18 +09:00
Cheng Zhao
4dc8e90586 Merge pull request #6603 from electron/standard-markdown
Standardize JavaScript code snippets in the documentation
2016-07-27 09:36:44 +09:00
Cheng Zhao
0bfd31e7cb Update brightray for #6613 2016-07-27 08:53:55 +09:00
Cheng Zhao
b3530a55a9 Merge pull request #6613 from deepak1556/pref_init_patch
browser: initialize pref registry in brightray
2016-07-27 08:53:33 +09:00
Samuel Attard
9f0299cc31 Use better regex to match spaces 2016-07-27 09:38:49 +10:00
Kevin Sawicki
c4e743d207 Add TODO to deprecate boolean param 2016-07-26 14:18:15 -07:00
Kevin Sawicki
8e1de88512 Correct typo in variable name 2016-07-26 14:17:41 -07:00
Kevin Sawicki
0ff6b87f8c Update tray.setHighlightMode docs 2016-07-26 13:59:19 -07:00
Kevin Sawicki
b2f9cce297 Add option to always highlight the tray icon 2016-07-26 13:51:43 -07:00
Kevin Sawicki
31564f079f Document webContents.copyImageAt(x,y) 2016-07-26 12:08:05 -07:00
Kevin Sawicki
bde432b64d Add webContents.copyImageAt 2016-07-26 12:06:11 -07:00
Kevin Sawicki
7a1b796dd0 Change registered flag from InitBreakpad 2016-07-26 10:54:30 -07:00
Kevin Sawicki
3279f5c80a Add spec for starting crash reporter twice 2016-07-26 10:43:57 -07:00
Kevin Sawicki
8956388804 Only register code range once 2016-07-26 10:40:11 -07:00
Zeke Sikelianos
c3f26df577 standardize electron-capturer doc snippets 2016-07-26 09:49:02 -07:00
Zeke Sikelianos
c38f505001 update standard-markdown to use linux-friendly local require statements 2016-07-26 09:48:19 -07:00
Zeke Sikelianos
3a16a9b0bf update to standard-markdown with node 0.10 support 2016-07-26 09:48:19 -07:00
Zeke Sikelianos
784bee8faa update npm run lint to include docs 2016-07-26 09:48:19 -07:00
Zeke Sikelianos
06a354a2eb standardize all javascript blocks in English docs 2016-07-26 09:48:19 -07:00
Zeke Sikelianos
dd9935a9d7 add npm script to lint all javascript blocks in the docs using standard 2016-07-26 09:47:16 -07:00
deepak1556
e65bc481a8 browser: initialize pref registry in brightray 2016-07-26 16:34:04 +05:30
Cheng Zhao
7c1f48808b Merge pull request #6612 from electron/cc-cxx
Do not overwrite CC and CXX in bootstrap
2016-07-26 19:55:25 +09:00
Cheng Zhao
7d11912a03 No more need to overwrite env when running update.py 2016-07-26 19:24:58 +09:00
Cheng Zhao
49181403ef Ignore CC and CXX in env 2016-07-26 19:24:28 +09:00
Cheng Zhao
0cdd764161 Merge pull request #6609 from electron/msvs
Add --msvs parameter to bootstrap.py
2016-07-26 19:03:25 +09:00
Cheng Zhao
89de791e9d docs: Mention the --msvs 2016-07-26 17:42:12 +09:00
Cheng Zhao
b34deb1d2f docs: x64 is the default build 2016-07-26 17:40:58 +09:00
Cheng Zhao
9bf3150237 Add --msvs parameter to bootstrap.py 2016-07-26 17:38:31 +09:00
Cheng Zhao
a4d983c236 Merge pull request #6607 from enlight/patch-4
Normalize string quotes in desktopCapturer docs
2016-07-26 16:29:01 +09:00
Cheng Zhao
61d16d5caa Merge pull request #6606 from electron/font-settings
Set page's font settings with system settings
2016-07-26 14:11:20 +09:00
Vadim Macagon
6cc68638e7 Normalize string quotes in desktopCapturer docs
Missed one string in my previous PR :(
2016-07-26 11:57:39 +07:00
Cheng Zhao
2b0cd97bb8 Merge pull request #6593 from enlight/improved-desktop-capturer-docs
Improve readability, and add a link to the navigator.getUserMedia API
2016-07-26 13:35:54 +09:00
Cheng Zhao
d2ce50e3dd c++11 styling 2016-07-26 13:32:17 +09:00
Cheng Zhao
0da1a772be Set page's font settings with system settings 2016-07-26 13:29:27 +09:00
Vadim Macagon
89309244b5 Improve the desktopCapturer docs
Made minor improvements to readability, and added a link to the
`navigator.getUserMedia` docs on MDN for convenience.
2016-07-26 10:48:38 +07:00
Cheng Zhao
8d941a6559 Merge pull request #6566 from electron/win-autoupdater-es6
Move autoUpdater to ES6
2016-07-26 12:46:00 +09:00
Cheng Zhao
b139d5ad1c Merge pull request #6598 from electron/fs-access-asar
Add asar implementation of fs.access/accessSync
2016-07-26 12:42:59 +09:00
Cheng Zhao
7b6d74fdc2 Merge pull request #6596 from liusy182/restore-issue
Window position doesn't restore correctly minimize and restore window
2016-07-26 11:21:59 +09:00
Cheng Zhao
c70ec47138 Merge pull request #6595 from lukeapage/patch-8
Clarify the default arguments for Menu popup
2016-07-26 11:16:57 +09:00
Samuel Attard
12dba2cb67 Remove all spaces from potential appUserModelID as it isn't allowed by the spec 2016-07-26 11:44:01 +10:00
Samuel Attard
20e26a9639 Move auto-updater-win to ES6 2016-07-26 11:40:55 +10:00
Kevin Sawicki
c730800f0c Merge pull request #6601 from feross/master
Fix test for PR #6600
2016-07-25 17:45:50 -07:00
Feross Aboukhadijeh
9bc144c880 Fix test for PR #6600
Just realized that the tests don't pass after my PR. This fixes that :)
2016-07-25 17:27:45 -07:00
Kevin Sawicki
8c7d28de27 Merge pull request #6600 from feross/master
MenuItem: Use 'Close Window' for 'close' role label
2016-07-25 15:21:05 -07:00
Feross Aboukhadijeh
d6a7ced32c MenuItem: Use 'Close Window' for 'close' role label
On OS X, the standard label that's used for the 'close' role is 'Close
Window'. You can see this in the default macOS apps from Apple.
2016-07-25 15:13:17 -07:00
Kevin Sawicki
b627b8711a Add spec for accessing normal files 2016-07-25 11:17:40 -07:00
Kevin Sawicki
8eca019157 Support paths as Buffers 2016-07-25 11:10:36 -07:00
Kevin Sawicki
30fbe92970 Add asar-supported fs.accessSync implementation 2016-07-25 11:05:18 -07:00
Kevin Sawicki
3ad5504194 Add asar-supported fs.access implementation 2016-07-25 10:50:30 -07:00
Kevin Sawicki
a518c47f4c Use let/const instead of var 2016-07-25 10:43:38 -07:00
liusi
8129c27a4a Merge branch 'master' of https://github.com/electron/electron into restore-issue 2016-07-25 22:53:18 +08:00
liusi
2cc01eea30 issue 6574 - Window position doesn't restore correctly 2016-07-25 22:51:27 +08:00
Luke Page
c365aa85c2 Clarify the default arguments for popup
The null / -1 defaults weren't very helpful, so changed to follow other documentation and write the behaviour if that param is missing.
2016-07-25 13:57:38 +02:00
Cheng Zhao
729b84f2ca Merge pull request #6576 from electron/browser-window-proxy-docs
Fix BrowserWindowProxy documentation
2016-07-25 16:55:49 +09:00
Cheng Zhao
66086880e2 Merge pull request #6575 from electron/asar-doc-fixes
fix wording in asar doc
2016-07-25 16:55:20 +09:00
Cheng Zhao
a30997867f Merge pull request #6573 from electron/native-image-doc
Fix documentation for NativeImage
2016-07-25 16:55:09 +09:00
Cheng Zhao
72c4952907 Merge pull request #6590 from electron/reliable-typed-array
Use ArrayBuffer.isView to detect Buffer and ArrayBuffer
2016-07-25 16:54:54 +09:00
Cheng Zhao
7a61966423 Use deepEqual for comparing type arrays 2016-07-25 16:41:20 +09:00
Cheng Zhao
9ddb62c42a Use Buffer.from instead of deprecated new Buffer 2016-07-25 16:40:22 +09:00
Cheng Zhao
1c9421bc89 Use ArrayBuffer.isView to detect Buffer and ArrayBuffer 2016-07-25 16:39:09 +09:00
Cheng Zhao
eb51e080e5 spec: TypeArray should work in remote 2016-07-25 16:30:40 +09:00
Cheng Zhao
200d09cc70 Merge pull request #6572 from haadcode/master
Add support for TypedArrays in IPC.
2016-07-25 16:22:29 +09:00
Cheng Zhao
fb251ac09b Update brightray for #6156 2016-07-25 16:08:38 +09:00
Cheng Zhao
e95da6ad1b Merge pull request #6565 from TiagoDanin/Update-Doc
Update docs-translations
2016-07-25 16:05:04 +09:00
Cheng Zhao
fd8cc63ca9 Merge pull request #6558 from deepak1556/session_proxy_patch
session: add proxyBypassRules option to setProxy api
2016-07-25 16:03:50 +09:00
Cheng Zhao
c497765dea Merge pull request #6524 from liusy182/painted-event-6426
add "view-painted" event to WebContent.
2016-07-25 16:02:50 +09:00
haad
fac330fb50 Fix TypedArray check, add check when instanceof doesn't work for TypedArrays. 2016-07-23 12:43:49 +01:00
haad
2757046e71 Add isTypedArray to Electron exports 2016-07-23 11:30:14 +01:00
Zeke Sikelianos
a2ffab40f9 use an instance-variable-style name for BrowserWindowProxy 2016-07-22 15:00:10 -07:00
Zeke Sikelianos
3a9c57231e fix wording in asar doc 2016-07-22 14:52:43 -07:00
Zeke Sikelianos
9432cb9170 use standard-style javascript in nativeImage doc 2016-07-22 13:47:05 -07:00
Zeke Sikelianos
9ca0fbaeb7 fix capitalization and headings for NativeImage class 2016-07-22 13:42:27 -07:00
haad
e6c8900a18 Fix linting 2016-07-22 20:20:24 +01:00
haad
c717cd9192 🐛 Add support for TypedArrays in IPC.
Fixes https://github.com/electron/electron/issues/2104.
2016-07-22 19:44:19 +01:00
TiagoDanin
c7c6dda122 Replace OSX to macOS and Update references 2016-07-21 16:07:03 -05:00
deepak1556
aa6d79a3d8 session: add proxyBypassRules option to setProxy api 2016-07-21 10:14:54 +05:30
liusi
d335d7d706 add "view-painted" event to WebContent. 2016-07-18 14:54:52 +08:00
84 changed files with 1299 additions and 796 deletions

View File

@@ -133,7 +133,7 @@ struct Converter<net::ProxyConfig> {
static bool FromV8(v8::Isolate* isolate,
v8::Local<v8::Value> val,
net::ProxyConfig* out) {
std::string proxy_rules;
std::string proxy_rules, proxy_bypass_rules;
GURL pac_url;
mate::Dictionary options;
// Fallback to previous API when passed String.
@@ -143,6 +143,7 @@ struct Converter<net::ProxyConfig> {
} else if (ConvertFromV8(isolate, val, &options)) {
options.Get("pacScript", &pac_url);
options.Get("proxyRules", &proxy_rules);
options.Get("proxyBypassRules", &proxy_bypass_rules);
} else {
return false;
}
@@ -152,6 +153,7 @@ struct Converter<net::ProxyConfig> {
out->set_pac_url(pac_url);
} else {
out->proxy_rules().ParseFromString(proxy_rules);
out->proxy_rules().bypass_rules.ParseFromString(proxy_bypass_rules);
}
return true;
}

View File

@@ -8,7 +8,6 @@
#include "atom/browser/api/atom_api_menu.h"
#include "atom/browser/browser.h"
#include "atom/browser/ui/tray_icon.h"
#include "atom/common/api/atom_api_native_image.h"
#include "atom/common/native_mate_converters/gfx_converter.h"
#include "atom/common/native_mate_converters/image_converter.h"
@@ -18,6 +17,45 @@
#include "native_mate/dictionary.h"
#include "ui/gfx/image/image.h"
namespace mate {
template<>
struct Converter<atom::TrayIcon::HighlightMode> {
static bool FromV8(v8::Isolate* isolate, v8::Local<v8::Value> val,
atom::TrayIcon::HighlightMode* out) {
std::string mode;
if (ConvertFromV8(isolate, val, &mode)) {
if (mode == "always") {
*out = atom::TrayIcon::HighlightMode::ALWAYS;
return true;
}
if (mode == "selection") {
*out = atom::TrayIcon::HighlightMode::SELECTION;
return true;
}
if (mode == "never") {
*out = atom::TrayIcon::HighlightMode::NEVER;
return true;
}
}
// Support old boolean parameter
// TODO(kevinsawicki): Remove in 2.0, deprecate before then with warnings
bool highlight;
if (ConvertFromV8(isolate, val, &highlight)) {
if (highlight)
*out = atom::TrayIcon::HighlightMode::SELECTION;
else
*out = atom::TrayIcon::HighlightMode::NEVER;
return true;
}
return false;
}
};
} // namespace mate
namespace atom {
namespace api {
@@ -117,8 +155,8 @@ void Tray::SetTitle(const std::string& title) {
tray_icon_->SetTitle(title);
}
void Tray::SetHighlightMode(bool highlight) {
tray_icon_->SetHighlightMode(highlight);
void Tray::SetHighlightMode(TrayIcon::HighlightMode mode) {
tray_icon_->SetHighlightMode(mode);
}
void Tray::DisplayBalloon(mate::Arguments* args,

View File

@@ -10,6 +10,7 @@
#include <vector>
#include "atom/browser/api/trackable_object.h"
#include "atom/browser/ui/tray_icon.h"
#include "atom/browser/ui/tray_icon_observer.h"
#include "native_mate/handle.h"
@@ -62,7 +63,7 @@ class Tray : public mate::TrackableObject<Tray>,
void SetPressedImage(v8::Isolate* isolate, mate::Handle<NativeImage> image);
void SetToolTip(const std::string& tool_tip);
void SetTitle(const std::string& title);
void SetHighlightMode(bool highlight);
void SetHighlightMode(TrayIcon::HighlightMode mode);
void DisplayBalloon(mate::Arguments* args, const mate::Dictionary& options);
void PopUpContextMenu(mate::Arguments* args);
void SetContextMenu(v8::Isolate* isolate, mate::Handle<Menu> menu);

View File

@@ -733,6 +733,7 @@ bool WebContents::OnMessageReceived(const IPC::Message& message) {
IPC_MESSAGE_HANDLER(AtomViewHostMsg_Message, OnRendererMessage)
IPC_MESSAGE_HANDLER_DELAY_REPLY(AtomViewHostMsg_Message_Sync,
OnRendererMessageSync)
IPC_MESSAGE_HANDLER(AtomViewHostMsg_DidCommitCompositorFrame, OnViewPainted)
IPC_MESSAGE_HANDLER_CODE(ViewHostMsg_SetCursor, OnCursorChange,
handled = false)
IPC_MESSAGE_UNHANDLED(handled = false)
@@ -1145,6 +1146,12 @@ void WebContents::ShowDefinitionForSelection() {
#endif
}
void WebContents::CopyImageAt(int x, int y) {
const auto host = web_contents()->GetRenderViewHost();
if (host)
host->CopyImageAt(x, y);
}
void WebContents::Focus() {
web_contents()->Focus();
}
@@ -1298,6 +1305,10 @@ void WebContents::OnCursorChange(const content::WebCursor& cursor) {
}
}
void WebContents::OnViewPainted() {
Emit("view-painted");
}
void WebContents::SetSize(const SetSizeParams& params) {
if (guest_delegate_)
guest_delegate_->SetSize(params);
@@ -1420,6 +1431,7 @@ void WebContents::BuildPrototype(v8::Isolate* isolate,
.SetMethod("removeWorkSpace", &WebContents::RemoveWorkSpace)
.SetMethod("showDefinitionForSelection",
&WebContents::ShowDefinitionForSelection)
.SetMethod("copyImageAt", &WebContents::CopyImageAt)
.SetMethod("capturePage", &WebContents::CapturePage)
.SetMethod("isFocused", &WebContents::IsFocused)
.SetProperty("id", &WebContents::ID)

View File

@@ -126,6 +126,7 @@ class WebContents : public mate::TrackableObject<WebContents>,
uint32_t FindInPage(mate::Arguments* args);
void StopFindInPage(content::StopFindAction action);
void ShowDefinitionForSelection();
void CopyImageAt(int x, int y);
// Focus.
void Focus();
@@ -294,6 +295,9 @@ class WebContents : public mate::TrackableObject<WebContents>,
const base::ListValue& args,
IPC::Message* message);
// Called when the hosted view gets graphical updates.
void OnViewPainted();
v8::Global<v8::Value> session_;
v8::Global<v8::Value> devtools_web_contents_;
v8::Global<v8::Value> debugger_;

View File

@@ -87,6 +87,9 @@ AtomBrowserContext::AtomBrowserContext(
// Read options.
use_cache_ = true;
options.GetBoolean("cache", &use_cache_);
// Initialize Pref Registry in brightray.
InitPrefs();
}
AtomBrowserContext::~AtomBrowserContext() {

View File

@@ -40,6 +40,11 @@
#include "ui/gfx/geometry/size_conversions.h"
#include "ui/gl/gpu_switching_manager.h"
#if defined(OS_LINUX) || defined(OS_WIN)
#include "content/public/common/renderer_preferences.h"
#include "ui/gfx/font_render_params.h"
#endif
DEFINE_WEB_CONTENTS_USER_DATA_KEY(atom::NativeWindowRelay);
namespace atom {
@@ -67,6 +72,20 @@ NativeWindow::NativeWindow(
if (parent)
options.Get("modal", &is_modal_);
#if defined(OS_LINUX) || defined(OS_WIN)
auto* prefs = web_contents()->GetMutableRendererPrefs();
// Update font settings.
CR_DEFINE_STATIC_LOCAL(const gfx::FontRenderParams, params,
(gfx::GetFontRenderParams(gfx::FontRenderParamsQuery(), nullptr)));
prefs->should_antialias_text = params.antialiasing;
prefs->use_subpixel_positioning = params.subpixel_positioning;
prefs->hinting = params.hinting;
prefs->use_autohinter = params.autohinter;
prefs->use_bitmaps = params.use_bitmaps;
prefs->subpixel_rendering = params.subpixel_rendering;
#endif
// Tell the content module to initialize renderer widget with transparent
// mode.
ui::GpuSwitchingManager::SetTransparent(transparent_);

View File

@@ -121,7 +121,10 @@ bool NativeWindowViews::PreHandleMSG(
::GetWindowRect(GetAcceleratedWidget(), (LPRECT)l_param);
return false;
}
case WM_MOVE: {
last_normal_bounds_ = GetBounds();
return false;
}
default:
return false;
}

View File

@@ -17,9 +17,9 @@
<key>CFBundleIconFile</key>
<string>electron.icns</string>
<key>CFBundleVersion</key>
<string>1.3.0</string>
<string>1.3.1</string>
<key>CFBundleShortVersionString</key>
<string>1.3.0</string>
<string>1.3.1</string>
<key>LSApplicationCategoryType</key>
<string>public.app-category.developer-tools</string>
<key>LSMinimumSystemVersion</key>

View File

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

View File

@@ -18,7 +18,7 @@ void TrayIcon::SetPressedImage(ImageType image) {
void TrayIcon::SetTitle(const std::string& title) {
}
void TrayIcon::SetHighlightMode(bool highlight) {
void TrayIcon::SetHighlightMode(TrayIcon::HighlightMode mode) {
}
void TrayIcon::DisplayBalloon(ImageType icon,

View File

@@ -43,9 +43,13 @@ class TrayIcon {
// only works on macOS.
virtual void SetTitle(const std::string& title);
// Sets whether the status icon is highlighted when it is clicked. This only
// works on macOS.
virtual void SetHighlightMode(bool highlight);
// Sets the status icon highlight mode. This only works on macOS.
enum HighlightMode {
ALWAYS, // Always highlight the tray icon
NEVER, // Never highlight the tray icon
SELECTION // Highlight the tray icon when clicked or the menu is opened
};
virtual void SetHighlightMode(HighlightMode mode);
// Displays a notification balloon with the specified contents.
// Depending on the platform it might not appear by the icon tray.

View File

@@ -27,7 +27,7 @@ class TrayIconCocoa : public TrayIcon,
void SetPressedImage(const gfx::Image& image) override;
void SetToolTip(const std::string& tool_tip) override;
void SetTitle(const std::string& title) override;
void SetHighlightMode(bool highlight) override;
void SetHighlightMode(TrayIcon::HighlightMode mode) override;
void PopUpContextMenu(const gfx::Point& pos,
AtomMenuModel* menu_model) override;
void SetContextMenu(AtomMenuModel* menu_model) override;

View File

@@ -23,7 +23,7 @@ const CGFloat kVerticalTitleMargin = 2;
@interface StatusItemView : NSView {
atom::TrayIconCocoa* trayIcon_; // weak
AtomMenuController* menuController_; // weak
BOOL isHighlightEnable_;
atom::TrayIcon::HighlightMode highlight_mode_;
BOOL forceHighlight_;
BOOL inMouseEventSequence_;
base::scoped_nsobject<NSImage> image_;
@@ -39,7 +39,7 @@ const CGFloat kVerticalTitleMargin = 2;
- (id)initWithImage:(NSImage*)image icon:(atom::TrayIconCocoa*)icon {
image_.reset([image copy]);
trayIcon_ = icon;
isHighlightEnable_ = YES;
highlight_mode_ = atom::TrayIcon::HighlightMode::SELECTION;
forceHighlight_ = NO;
inMouseEventSequence_ = NO;
@@ -192,8 +192,9 @@ const CGFloat kVerticalTitleMargin = 2;
alternateImage_.reset([image copy]);
}
- (void)setHighlight:(BOOL)highlight {
isHighlightEnable_ = highlight;
- (void)setHighlight:(atom::TrayIcon::HighlightMode)mode {
highlight_mode_ = mode;
[self setNeedsDisplay:YES];
}
- (void)setTitle:(NSString*)title {
@@ -328,10 +329,15 @@ const CGFloat kVerticalTitleMargin = 2;
}
- (BOOL)shouldHighlight {
if (isHighlightEnable_ && forceHighlight_)
return true;
BOOL isMenuOpen = menuController_ && [menuController_ isMenuOpen];
return isHighlightEnable_ && (inMouseEventSequence_ || isMenuOpen);
switch (highlight_mode_) {
case atom::TrayIcon::HighlightMode::ALWAYS:
return true;
case atom::TrayIcon::HighlightMode::NEVER:
return false;
case atom::TrayIcon::HighlightMode::SELECTION:
BOOL isMenuOpen = menuController_ && [menuController_ isMenuOpen];
return forceHighlight_ || inMouseEventSequence_ || isMenuOpen;
}
}
@end
@@ -369,8 +375,8 @@ void TrayIconCocoa::SetTitle(const std::string& title) {
[status_item_view_ setTitle:base::SysUTF8ToNSString(title)];
}
void TrayIconCocoa::SetHighlightMode(bool highlight) {
[status_item_view_ setHighlight:highlight];
void TrayIconCocoa::SetHighlightMode(TrayIcon::HighlightMode mode) {
[status_item_view_ setHighlight:mode];
}
void TrayIconCocoa::PopUpContextMenu(const gfx::Point& pos,

View File

@@ -39,5 +39,7 @@ IPC_MESSAGE_ROUTED3(AtomViewMsg_Message,
IPC_MESSAGE_ROUTED1(AtomViewHostMsg_UpdateDraggableRegions,
std::vector<atom::DraggableRegion> /* regions */)
IPC_MESSAGE_ROUTED0(AtomViewHostMsg_DidCommitCompositorFrame)
// Update renderer process preferences.
IPC_MESSAGE_CONTROL1(AtomMsg_UpdatePreferences, base::ListValue)

View File

@@ -7,7 +7,7 @@
#define ATOM_MAJOR_VERSION 1
#define ATOM_MINOR_VERSION 3
#define ATOM_PATCH_VERSION 0
#define ATOM_PATCH_VERSION 1
#define ATOM_VERSION_IS_RELEASE 1

View File

@@ -138,7 +138,8 @@ void UnregisterNonABICompliantCodeRange(void* start) {
} // namespace
CrashReporterWin::CrashReporterWin()
: skip_system_crash_handler_(false) {
: skip_system_crash_handler_(false),
code_range_registered_(false) {
}
CrashReporterWin::~CrashReporterWin() {
@@ -189,19 +190,20 @@ void CrashReporterWin::InitBreakpad(const std::string& product_name,
LOG(ERROR) << "Cannot initialize out-of-process crash handler";
#ifdef _WIN64
bool registered = false;
// Hook up V8 to breakpad.
{
if (!code_range_registered_) {
code_range_registered_ = true;
// gin::Debug::SetCodeRangeCreatedCallback only runs the callback when
// Isolate is just created, so we have to manually run following code here.
void* code_range = nullptr;
size_t size = 0;
v8::Isolate::GetCurrent()->GetCodeRange(&code_range, &size);
if (code_range && size)
registered = RegisterNonABICompliantCodeRange(code_range, size);
if (code_range && size &&
RegisterNonABICompliantCodeRange(code_range, size)) {
gin::Debug::SetCodeRangeDeletedCallback(
UnregisterNonABICompliantCodeRange);
}
}
if (registered)
gin::Debug::SetCodeRangeDeletedCallback(UnregisterNonABICompliantCodeRange);
#endif
}

View File

@@ -62,6 +62,7 @@ class CrashReporterWin : public CrashReporter {
google_breakpad::CustomClientInfo custom_info_;
bool skip_system_crash_handler_;
bool code_range_registered_;
std::unique_ptr<google_breakpad::ExceptionHandler> breakpad_;
DISALLOW_COPY_AND_ASSIGN(CrashReporterWin);

View File

@@ -141,6 +141,10 @@ void AtomRenderViewObserver::DraggableRegionsChanged(blink::WebFrame* frame) {
Send(new AtomViewHostMsg_UpdateDraggableRegions(routing_id(), regions));
}
void AtomRenderViewObserver::DidCommitCompositorFrame() {
Send(new AtomViewHostMsg_DidCommitCompositorFrame(routing_id()));
}
bool AtomRenderViewObserver::OnMessageReceived(const IPC::Message& message) {
bool handled = true;
IPC_BEGIN_MESSAGE_MAP(AtomRenderViewObserver, message)

View File

@@ -28,6 +28,7 @@ class AtomRenderViewObserver : public content::RenderViewObserver {
// content::RenderViewObserver implementation.
void DidCreateDocumentElement(blink::WebLocalFrame* frame) override;
void DraggableRegionsChanged(blink::WebFrame* frame) override;
void DidCommitCompositorFrame() override;
bool OnMessageReceived(const IPC::Message& message) override;
void OnBrowserMessage(bool send_to_all,

View File

@@ -65,7 +65,7 @@
* [Estructura de los directorios del Código Fuente](development/source-code-directory-structure.md)
* [Diferencias Técnicas con NW.js (anteriormente conocido como node-webkit)](development/atom-shell-vs-node-webkit.md)
* [Repaso del Sistema de Compilación](development/build-system-overview.md)
* [Instrucciones de Compilación (Mac)](development/build-instructions-osx.md)
* [Instrucciones de Compilación (macOS)](development/build-instructions-osx.md)
* [Instrucciones de Compilación (Windows)](development/build-instructions-windows.md)
* [Instrucciones de Compilación (Linux)](development/build-instructions-linux.md)
* [Configurando un Servidor de Símbolos en el depurador](development/setting-up-symbol-server.md)

View File

@@ -2,7 +2,7 @@
Para distribuir tu aplicación con Electron, el directorio que contiene la
aplicación deberá llamarse `app`, y ser colocado debajo del directorio de
recursos de Electron (en OSX es `Electron.app/Contents/Resources/`, en Linux y
recursos de Electron (en macOS es `Electron.app/Contents/Resources/`, en Linux y
Windows es `resources/`), de esta forma:
En macOS:
@@ -63,7 +63,7 @@ de distribuirlo a los usuarios.
Puedes renombrar `electron.exe` a cualquier nombre que desees, y editar su ícono
y otra información con herramientas como [rcedit](https://github.com/atom/rcedit).
### OSX
### macOS
Puedes renombrar `Electron.app` a cualquier nombre que desees, y tendrás que
renombrar los campos `CFBundleDisplayName`, `CFBundleIdentifier` y `CFBundleName`

View File

@@ -57,7 +57,7 @@ __Menú dock de Terminal.app:__
<img src="https://cloud.githubusercontent.com/assets/639601/5069962/6032658a-6e9c-11e4-9953-aa84006bdfff.png" height="354" width="341" >
Para establecer tu menú dock, puedes utilizar la API `app.dock.setMenu`, la cual sólo está disponible para OSX:
Para establecer tu menú dock, puedes utilizar la API `app.dock.setMenu`, la cual sólo está disponible para macOS:
```javascript
var app = require('app');

View File

@@ -35,8 +35,8 @@ porque la gestión de los recursos GUI nativos es peligrosa, y tiende a que ocur
Si deseas realizar operaciones GUI en una página web, el proceso renderer de la página web debe comunicarse
con el proceso principal, y solicitar a este que realice esas operaciones.
En Electron, hemos proveído el módulo [ipc](../api/ipc-renderer.md) para la comunicación
entre el proceso principal y el proceso renderer. Y también hay un módulo [remote](../api/remote.md)
En Electron, hemos proveído el módulo [ipc](../../../docs/api/ipc-renderer.md) para la comunicación
entre el proceso principal y el proceso renderer. Y también hay un módulo [remote](../../../docs/api/remote.md)
para comunicación al estilo RPC.
## Escribe tu primera aplicación Electron

View File

@@ -4,7 +4,7 @@ El plugin Pepper Flash es soportado ahora. Para utilizar pepper flash en Electro
## Preparar una copia del plugin Flash
En OSX y Linux, el detalle del plugin puede encontrarse accediendo a `chrome://plugins` en el navegador. Su ubicación y versión son útiles para el soporte. También puedes copiarlo a otro lugar.
En macOS y Linux, el detalle del plugin puede encontrarse accediendo a `chrome://plugins` en el navegador. Su ubicación y versión son útiles para el soporte. También puedes copiarlo a otro lugar.
## Agrega la opción a Electron

View File

@@ -1,11 +1,11 @@
# Distribuição de aplicações
Para distribuir sua aplicação com o Electron, você deve nomear o diretório que contém sua aplicação como
`app` e dentro deste diretório colocar os recursos que você está utilizando (no OSX
`app` e dentro deste diretório colocar os recursos que você está utilizando (no macOS
`Electron.app/Contents/Resources/`,
no Linux e no Windows é em `resources/`):
No OSX:
No macOS:
```text
electron/Electron.app/Contents/Resources/app/
@@ -37,7 +37,7 @@ Para usar um arquivo `asar` ao invés da pasta `app` você precisa mudar o nome
arquivo para `app.asar` e colocá-lo sob o diretório de recursos do Electron como
mostrado abaixo, então o Electron vai ler o arquivo e iniciar a aplicação a partir dele.
No OSX:
No macOS:
```text
electron/Electron.app/Contents/Resources/

View File

@@ -8,12 +8,12 @@ módulos nativos.
## Compatibilidade de Módulos Nativos do Node
Módulos nativos podem quebrar quando utilizar a nova versão do Node, V8.
Para ter certeza que o módulo que você está interessado em trabalhar com o
Para ter certeza que o módulo que você está interessado em trabalhar com o
Electron, você deve checar se a versão do Node utilizada é compatível com a
usada pelo Electron.
Você pode verificar qual versão do Node foi utilizada no Electron olhando na
página [releases](https://github.com/electron/electron/releases) ou usando
`process.version` (veja [Quick Start](https://github.com/electron/electron/blob/master/docs/tutorial/quick-start.md)
`process.version` (veja em [Introdução](quick-start.md)
por exemplo).
Considere usar [NAN](https://github.com/nodejs/nan/) para seus próprios

View File

@@ -6,10 +6,10 @@ The following example shows how to quit the application when the last window is
closed:
```javascript
const {app} = require('electron');
const {app} = require('electron')
app.on('window-all-closed', () => {
app.quit();
});
app.quit()
})
```
## Events
@@ -192,15 +192,17 @@ certificate you should prevent the default behavior with
`event.preventDefault()` and call `callback(true)`.
```javascript
const {app} = require('electron')
app.on('certificate-error', (event, webContents, url, error, certificate, callback) => {
if (url === 'https://github.com') {
// Verification logic.
event.preventDefault();
callback(true);
event.preventDefault()
callback(true)
} else {
callback(false);
callback(false)
}
});
})
```
### Event: 'select-client-certificate'
@@ -228,10 +230,12 @@ and `callback` needs to be called with an entry filtered from the list. Using
certificate from the store.
```javascript
const {app} = require('electron')
app.on('select-client-certificate', (event, webContents, url, list, callback) => {
event.preventDefault();
callback(list[0]);
});
event.preventDefault()
callback(list[0])
})
```
### Event: 'login'
@@ -259,10 +263,12 @@ should prevent the default behavior with `event.preventDefault()` and call
`callback(username, password)` with the credentials.
```javascript
const {app} = require('electron')
app.on('login', (event, webContents, request, authInfo, callback) => {
event.preventDefault();
callback('username', 'secret');
});
event.preventDefault()
callback('username', 'secret')
})
```
### Event: 'gpu-process-crashed'
@@ -331,6 +337,8 @@ An example of restarting current instance immediately and adding a new command
line argument to the new instance:
```javascript
const {app} = require('electron')
app.relaunch({args: process.argv.slice(1) + ['--relaunch']})
app.exit(0)
```
@@ -537,24 +545,24 @@ An example of activating the window of primary instance when a second instance
starts:
```javascript
let myWindow = null;
const {app} = require('electron')
let myWindow = null
const shouldQuit = app.makeSingleInstance((commandLine, workingDirectory) => {
// Someone tried to run a second instance, we should focus our window.
if (myWindow) {
if (myWindow.isMinimized()) myWindow.restore();
myWindow.focus();
if (myWindow.isMinimized()) myWindow.restore()
myWindow.focus()
}
});
})
if (shouldQuit) {
app.quit();
return;
app.quit()
}
// Create myWindow, load the rest of the app, etc...
app.on('ready', () => {
});
})
```
### `app.releaseSingleInstance()`

View File

@@ -6,8 +6,8 @@
// In the main process.
const {BrowserWindow} = require('electron')
// Or in the renderer process.
const {BrowserWindow} = require('electron').remote
// Or use `remote` from the renderer process.
// const {BrowserWindow} = require('electron').remote
let win = new BrowserWindow({width: 800, height: 600})
win.on('closed', () => {
@@ -35,6 +35,7 @@ process has done drawing for the first time, showing window after this event
will have no visual flash:
```javascript
const {BrowserWindow} = require('electron')
let win = new BrowserWindow({show: false})
win.once('ready-to-show', () => {
win.show()
@@ -52,6 +53,8 @@ the app feel slow. In this case, it is recommended to show the window
immediately, and use a `backgroundColor` close to your app's background:
```javascript
const {BrowserWindow} = require('electron')
let win = new BrowserWindow({backgroundColor: '#2e2c29'})
win.loadURL('https://github.com')
```
@@ -64,8 +67,12 @@ to set `backgroundColor` to make app feel more native.
By using `parent` option, you can create child windows:
```javascript
const {BrowserWindow} = require('electron')
let top = new BrowserWindow()
let child = new BrowserWindow({parent: top})
child.show()
top.show()
```
The `child` window will always show on top of the `top` window.
@@ -76,6 +83,8 @@ A modal window is a child window that disables parent window, to create a modal
window, you have to set both `parent` and `modal` options:
```javascript
const {BrowserWindow} = require('electron')
let child = new BrowserWindow({parent: top, modal: true, show: false})
child.loadURL('https://github.com')
child.once('ready-to-show', () => {
@@ -308,14 +317,14 @@ close. For example:
```javascript
window.onbeforeunload = (e) => {
console.log('I do not want to be closed');
console.log('I do not want to be closed')
// Unlike usual browsers that a message box will be prompted to users, returning
// a non-void value will silently cancel the close.
// It is recommended to use the dialog API to let the user confirm closing the
// application.
e.returnValue = false;
};
e.returnValue = false
}
```
#### Event: 'closed'
@@ -414,12 +423,14 @@ Commands are lowercased, underscores are replaced with hyphens, and the
e.g. `APPCOMMAND_BROWSER_BACKWARD` is emitted as `browser-backward`.
```javascript
someWindow.on('app-command', (e, cmd) => {
const {BrowserWindow} = require('electron')
let win = new BrowserWindow()
win.on('app-command', (e, cmd) => {
// Navigate the window back when the user hits their mouse back button
if (cmd === 'browser-backward' && someWindow.webContents.canGoBack()) {
someWindow.webContents.goBack();
if (cmd === 'browser-backward' && win.webContents.canGoBack()) {
win.webContents.goBack()
}
});
})
```
#### Event: 'scroll-touch-begin' _macOS_
@@ -496,7 +507,10 @@ an Object containing `name` and `version` properties.
To check if a DevTools extension is installed you can run the following:
```javascript
const {BrowserWindow} = require('electron')
let installed = BrowserWindow.getDevToolsExtensions().hasOwnProperty('devtron')
console.log(installed)
```
**Note:** This API cannot be called before the `ready` event of the `app` module
@@ -507,8 +521,10 @@ is emitted.
Objects created with `new BrowserWindow` have the following properties:
```javascript
const {BrowserWindow} = require('electron')
// In this example `win` is our instance
let win = new BrowserWindow({width: 800, height: 600});
let win = new BrowserWindow({width: 800, height: 600})
win.loadURL('https://github.com')
```
#### `win.webContents`
@@ -809,8 +825,11 @@ attached just below the window frame, but you may want to display them beneath
a HTML-rendered toolbar. For example:
```javascript
let toolbarRect = document.getElementById('toolbar').getBoundingClientRect();
win.setSheetOffset(toolbarRect.height);
const {BrowserWindow} = require('electron')
let win = new BrowserWindow()
let toolbarRect = document.getElementById('toolbar').getBoundingClientRect()
win.setSheetOffset(toolbarRect.height)
```
#### `win.flashFrame(flag)`

View File

@@ -7,13 +7,13 @@ your app's main script before the [ready][ready] event of the [app][app] module
is emitted:
```javascript
const {app} = require('electron');
app.commandLine.appendSwitch('remote-debugging-port', '8315');
app.commandLine.appendSwitch('host-rules', 'MAP * 127.0.0.1');
const {app} = require('electron')
app.commandLine.appendSwitch('remote-debugging-port', '8315')
app.commandLine.appendSwitch('host-rules', 'MAP * 127.0.0.1')
app.on('ready', () => {
// Your code here
});
})
```
## --ignore-connections-limit=`domains`
@@ -57,6 +57,7 @@ list of hosts. This flag has an effect only if used in tandem with
For example:
```javascript
const {app} = require('electron')
app.commandLine.appendSwitch('proxy-bypass-list', '<local>;*.google.com;*foo.com;1.2.3.4:5678')
```

View File

@@ -5,16 +5,17 @@
The following example shows how to write a string to the clipboard:
```javascript
const {clipboard} = require('electron');
clipboard.writeText('Example String');
const {clipboard} = require('electron')
clipboard.writeText('Example String')
```
On X Window systems, there is also a selection clipboard. To manipulate it
you need to pass `selection` to each method:
```javascript
clipboard.writeText('Example String', 'selection');
console.log(clipboard.readText('selection'));
const {clipboard} = require('electron')
clipboard.writeText('Example String', 'selection')
console.log(clipboard.readText('selection'))
```
## Methods
@@ -109,7 +110,8 @@ Returns an array of supported formats for the clipboard `type`.
Returns whether the clipboard supports the format of specified `data`.
```javascript
console.log(clipboard.has('<p>selection</p>'));
const {clipboard} = require('electron')
console.log(clipboard.has('<p>selection</p>'))
```
### `clipboard.read(data[, type])` _Experimental_
@@ -130,6 +132,7 @@ Reads `data` from the clipboard.
* `type` String (optional)
```javascript
clipboard.write({text: 'test', html: "<b>test</b>"});
const {clipboard} = require('electron')
clipboard.write({text: 'test', html: '<b>test</b>'})
```
Writes `data` to the clipboard.

View File

@@ -8,22 +8,22 @@ This module does not include a web interface so you need to open
result.
```javascript
const {contentTracing} = require('electron');
const {contentTracing} = require('electron')
const options = {
categoryFilter: '*',
traceOptions: 'record-until-full,enable-sampling'
};
}
contentTracing.startRecording(options, () => {
console.log('Tracing started');
console.log('Tracing started')
setTimeout(() => {
contentTracing.stopRecording('', (path) => {
console.log('Tracing data recorded to ' + path);
});
}, 5000);
});
console.log('Tracing data recorded to ' + path)
})
}, 5000)
})
```
## Methods

View File

@@ -6,14 +6,14 @@ The following is an example of automatically submitting a crash report to a
remote server:
```javascript
const {crashReporter} = require('electron');
const {crashReporter} = require('electron')
crashReporter.start({
productName: 'YourName',
companyName: 'YourCompany',
submitURL: 'https://your-domain.com/url-to-submit',
autoSubmit: true
});
})
```
For setting up a server to accept and process crash reports, you can use

View File

@@ -1,14 +1,17 @@
# desktopCapturer
> List `getUserMedia` sources for capturing audio, video, and images from a
microphone, camera, or screen.
> Access information about media sources that can be used to capture audio and
> video from the desktop using the [`navigator.webkitGetUserMedia`] API.
The following example shows how to capture video from a desktop window whose
title is `Electron`:
```javascript
// In the renderer process.
const {desktopCapturer} = require('electron');
const {desktopCapturer} = require('electron')
desktopCapturer.getSources({types: ['window', 'screen']}, (error, sources) => {
if (error) throw error;
if (error) throw error
for (let i = 0; i < sources.length; ++i) {
if (sources[i].name === 'Electron') {
navigator.webkitGetUserMedia({
@@ -23,29 +26,28 @@ desktopCapturer.getSources({types: ['window', 'screen']}, (error, sources) => {
maxHeight: 720
}
}
}, gotStream, getUserMediaError);
return;
}, handleStream, handleError)
return
}
}
});
})
function gotStream(stream) {
document.querySelector('video').src = URL.createObjectURL(stream);
function handleStream (stream) {
document.querySelector('video').src = URL.createObjectURL(stream)
}
function getUserMediaError(e) {
console.log('getUserMediaError');
function handleError (e) {
console.log(e)
}
```
When creating a constraints object for the `navigator.webkitGetUserMedia` call,
if you are using a source from `desktopCapturer` your `chromeMediaSource` must
be set to `"desktop"` and your `audio` must be set to `false`.
To capture video from a source provided by `desktopCapturer` the constraints
passed to [`navigator.webkitGetUserMedia`] must include
`chromeMediaSource: 'desktop'`, and `audio: false`.
If you wish to
capture the audio and video from the entire desktop you can set
`chromeMediaSource` to `"screen"` and `audio` to `true`. When using this method
you cannot specify a `chromeMediaSourceId`.
To capture both audio and video from the entire desktop the constraints passed
to [`navigator.webkitGetUserMedia`] must include `chromeMediaSource: 'screen'`,
and `audio: true`, but should not include a `chromeMediaSourceId` constraint.
## Methods
@@ -56,24 +58,28 @@ The `desktopCapturer` module has the following methods:
* `options` Object
* `types` Array - An array of String that lists the types of desktop sources
to be captured, available types are `screen` and `window`.
* `thumbnailSize` Object (optional) - The suggested size that thumbnail should
be scaled, it is `{width: 150, height: 150}` by default.
* `thumbnailSize` Object (optional) - The suggested size that the media source
thumbnail should be scaled to, defaults to `{width: 150, height: 150}`.
* `callback` Function
Starts a request to get all desktop sources, `callback` will be called with
`callback(error, sources)` when the request is completed.
Starts gathering information about all available desktop media sources,
and calls `callback(error, sources)` when finished.
The `sources` is an array of `Source` objects, each `Source` represents a
captured screen or individual window, and has following properties:
`sources` is an array of `Source` objects, each `Source` represents a
screen or an individual window that can be captured, and has the following
properties:
* `id` String - The id of the captured window or screen used in
`navigator.webkitGetUserMedia`. The format looks like `window:XX` or
`screen:XX` where `XX` is a random generated number.
* `name` String - The described name of the capturing screen or window. If the
source is a screen, the name will be `Entire Screen` or `Screen <index>`; if
it is a window, the name will be the window's title.
* `thumbnail` [NativeImage](native-image.md) - A thumbnail native image.
* `id` String - The identifier of a window or screen that can be used as a
`chromeMediaSourceId` constraint when calling
[`navigator.webkitGetUserMedia`]. The format of the identifier will be
`window:XX` or `screen:XX`, where `XX` is a random generated number.
* `name` String - A screen source will be named either `Entire Screen` or
`Screen <index>`, while the name of a window source will match the window
title.
* `thumbnail` [NativeImage](native-image.md) - A thumbnail image. **Note:**
There is no guarantee that the size of the thumbnail is the same as the
`thumnbailSize` specified in the `options` passed to
`desktopCapturer.getSources`. The actual size depends on the scale of the
screen or window.
**Note:** There is no guarantee that the size of `source.thumbnail` is always
the same as the `thumnbailSize` in `options`. It also depends on the scale of
the screen or window.
[`navigator.webkitGetUserMedia`]: https://developer.mozilla.org/en/docs/Web/API/Navigator/getUserMedia

View File

@@ -5,17 +5,16 @@
An example of showing a dialog to select multiple files and directories:
```javascript
let win = ...; // BrowserWindow in which to show the dialog
const {dialog} = require('electron');
console.log(dialog.showOpenDialog({properties: ['openFile', 'openDirectory', 'multiSelections']}));
const {dialog} = require('electron')
console.log(dialog.showOpenDialog({properties: ['openFile', 'openDirectory', 'multiSelections']}))
```
The Dialog is opened from Electron's main thread. If you want to use the dialog
object from a renderer process, remember to access it using the remote:
```javascript
const {dialog} = require('electron').remote;
const {dialog} = require('electron').remote
console.log(dialog)
```
## Methods
@@ -42,7 +41,7 @@ otherwise it returns `undefined`.
The `filters` specifies an array of file types that can be displayed or
selected when you want to limit the user to a specific type. For example:
```javascript
```
{
filters: [
{name: 'Images', extensions: ['jpg', 'png', 'gif']},

View File

@@ -8,6 +8,8 @@ control the download item.
```javascript
// In the main process.
const {BrowserWindow} = require('electron')
let win = new BrowserWindow()
win.webContents.session.on('will-download', (event, item, webContents) => {
// Set the save path, making Electron not to prompt a save dialog.
item.setSavePath('/tmp/save.pdf')

View File

@@ -15,19 +15,19 @@ Example on getting a real path from a dragged-onto-the-app file:
</div>
<script>
const holder = document.getElementById('holder');
const holder = document.getElementById('holder')
holder.ondragover = () => {
return false;
};
}
holder.ondragleave = holder.ondragend = () => {
return false;
};
}
holder.ondrop = (e) => {
e.preventDefault();
e.preventDefault()
for (let f of e.dataTransfer.files) {
console.log('File(s) you dragged here: ', f.path);
console.log('File(s) you dragged here: ', f.path)
}
return false;
};
}
</script>
```

View File

@@ -16,6 +16,7 @@ To create a frameless window, you need to set `frame` to `false` in
```javascript
const {BrowserWindow} = require('electron')
let win = new BrowserWindow({width: 800, height: 600, frame: false})
win.show()
```
### Alternatives on macOS
@@ -28,7 +29,9 @@ the window controls ("traffic lights") for standard window actions.
You can do so by specifying the new `titleBarStyle` option:
```javascript
const {BrowserWindow} = require('electron')
let win = new BrowserWindow({titleBarStyle: 'hidden'})
win.show()
```
## Transparent window
@@ -37,7 +40,9 @@ By setting the `transparent` option to `true`, you can also make the frameless
window transparent:
```javascript
const {BrowserWindow} = require('electron')
let win = new BrowserWindow({transparent: true, frame: false})
win.show()
```
### Limitations
@@ -66,6 +71,8 @@ events, you can call the [win.setIgnoreMouseEvents(ignore)][ignore-mouse-events]
API:
```javascript
const {BrowserWindow} = require('electron')
let win = new BrowserWindow()
win.setIgnoreMouseEvents(true)
```

View File

@@ -11,29 +11,29 @@ not have the keyboard focus. You should not use this module until the `ready`
event of the app module is emitted.
```javascript
const {app, globalShortcut} = require('electron');
const {app, globalShortcut} = require('electron')
app.on('ready', () => {
// Register a 'CommandOrControl+X' shortcut listener.
const ret = globalShortcut.register('CommandOrControl+X', () => {
console.log('CommandOrControl+X is pressed');
});
console.log('CommandOrControl+X is pressed')
})
if (!ret) {
console.log('registration failed');
console.log('registration failed')
}
// Check whether a shortcut is registered.
console.log(globalShortcut.isRegistered('CommandOrControl+X'));
});
console.log(globalShortcut.isRegistered('CommandOrControl+X'))
})
app.on('will-quit', () => {
// Unregister a shortcut.
globalShortcut.unregister('CommandOrControl+X');
globalShortcut.unregister('CommandOrControl+X')
// Unregister all shortcuts.
globalShortcut.unregisterAll();
});
globalShortcut.unregisterAll()
})
```
## Methods

View File

@@ -23,27 +23,27 @@ processes:
```javascript
// In main process.
const {ipcMain} = require('electron');
const {ipcMain} = require('electron')
ipcMain.on('asynchronous-message', (event, arg) => {
console.log(arg); // prints "ping"
event.sender.send('asynchronous-reply', 'pong');
});
console.log(arg) // prints "ping"
event.sender.send('asynchronous-reply', 'pong')
})
ipcMain.on('synchronous-message', (event, arg) => {
console.log(arg); // prints "ping"
event.returnValue = 'pong';
});
console.log(arg) // prints "ping"
event.returnValue = 'pong'
})
```
```javascript
// In renderer process (web page).
const {ipcRenderer} = require('electron');
console.log(ipcRenderer.sendSync('synchronous-message', 'ping')); // prints "pong"
const {ipcRenderer} = require('electron')
console.log(ipcRenderer.sendSync('synchronous-message', 'ping')) // prints "pong"
ipcRenderer.on('asynchronous-reply', (event, arg) => {
console.log(arg); // prints "pong"
});
ipcRenderer.send('asynchronous-message', 'ping');
console.log(arg) // prints "pong"
})
ipcRenderer.send('asynchronous-message', 'ping')
```
## Listening for Messages

View File

@@ -15,18 +15,18 @@ the user right clicks the page:
```html
<!-- index.html -->
<script>
const {remote} = require('electron');
const {remote} = require('electron')
const {Menu, MenuItem} = remote;
const menu = new Menu();
menu.append(new MenuItem({label: 'MenuItem1', click() { console.log('item 1 clicked'); }}));
menu.append(new MenuItem({type: 'separator'}));
menu.append(new MenuItem({label: 'MenuItem2', type: 'checkbox', checked: true}));
const menu = new Menu()
menu.append(new MenuItem({label: 'MenuItem1', click() { console.log('item 1 clicked') }}))
menu.append(new MenuItem({type: 'separator'}))
menu.append(new MenuItem({label: 'MenuItem2', type: 'checkbox', checked: true}))
window.addEventListener('contextmenu', (e) => {
e.preventDefault();
menu.popup(remote.getCurrentWindow());
}, false);
e.preventDefault()
menu.popup(remote.getCurrentWindow())
}, false)
</script>
```
@@ -34,6 +34,8 @@ An example of creating the application menu in the render process with the
simple template API:
```javascript
const {Menu} = require('electron')
const template = [
{
label: 'Edit',
@@ -64,7 +66,7 @@ const template = [
},
{
role: 'selectall'
},
}
]
},
{
@@ -73,8 +75,8 @@ const template = [
{
label: 'Reload',
accelerator: 'CmdOrCtrl+R',
click(item, focusedWindow) {
if (focusedWindow) focusedWindow.reload();
click (item, focusedWindow) {
if (focusedWindow) focusedWindow.reload()
}
},
{
@@ -83,11 +85,10 @@ const template = [
{
label: 'Toggle Developer Tools',
accelerator: process.platform === 'darwin' ? 'Alt+Command+I' : 'Ctrl+Shift+I',
click(item, focusedWindow) {
if (focusedWindow)
focusedWindow.webContents.toggleDevTools();
click (item, focusedWindow) {
if (focusedWindow) focusedWindow.webContents.toggleDevTools()
}
},
}
]
},
{
@@ -98,7 +99,7 @@ const template = [
},
{
role: 'close'
},
}
]
},
{
@@ -106,14 +107,14 @@ const template = [
submenu: [
{
label: 'Learn More',
click() { require('electron').shell.openExternal('http://electron.atom.io'); }
},
click () { require('electron').shell.openExternal('http://electron.atom.io') }
}
]
},
];
}
]
if (process.platform === 'darwin') {
const name = require('electron').remote.app.getName();
const name = require('electron').remote.app.getName()
template.unshift({
label: name,
submenu: [
@@ -144,9 +145,9 @@ if (process.platform === 'darwin') {
},
{
role: 'quit'
},
}
]
});
})
// Window menu.
template[3].submenu = [
{
@@ -170,11 +171,11 @@ if (process.platform === 'darwin') {
label: 'Bring All to Front',
role: 'front'
}
];
]
}
const menu = Menu.buildFromTemplate(template);
Menu.setApplicationMenu(menu);
const menu = Menu.buildFromTemplate(template)
Menu.setApplicationMenu(menu)
```
## Class: Menu
@@ -227,16 +228,14 @@ The `menu` object has the following instance methods:
#### `menu.popup([browserWindow, x, y, positioningItem])`
* `browserWindow` BrowserWindow (optional) - Default is `null`.
* `x` Number (optional) - Default is -1.
* `y` Number (**required** if `x` is used) - Default is -1.
* `browserWindow` BrowserWindow (optional) - Default is `BrowserWindow.getFocusedWindow()`.
* `x` Number (optional) - Default is the current mouse cursor position.
* `y` Number (**required** if `x` is used) - Default is the current mouse cursor position.
* `positioningItem` Number (optional) _macOS_ - The index of the menu item to
be positioned under the mouse cursor at the specified coordinates. Default is
-1.
Pops up this menu as a context menu in the `browserWindow`. You can optionally
provide a `x, y` coordinate to place the menu at, otherwise it will be placed
at the current mouse cursor position.
Pops up this menu as a context menu in the `browserWindow`.
#### `menu.append(menuItem)`
@@ -322,7 +321,7 @@ the first item.
Template:
```javascript
```
[
{label: '4', id: '4'},
{label: '5', id: '5'},
@@ -344,7 +343,7 @@ Menu:
Template:
```javascript
```
[
{label: 'a', position: 'endof=letters'},
{label: '1', position: 'endof=numbers'},

View File

@@ -3,21 +3,26 @@
> Create tray, dock, and application icons using PNG or JPG files.
In Electron, for the APIs that take images, you can pass either file paths or
`nativeImage` instances. An empty image will be used when `null` is passed.
`NativeImage` instances. An empty image will be used when `null` is passed.
For example, when creating a tray or setting a window's icon, you can pass an
image file path as a `String`:
```javascript
const appIcon = new Tray('/Users/somebody/images/icon.png');
let win = new BrowserWindow({icon: '/Users/somebody/images/window.png'});
const {BrowserWindow, Tray} = require('electron')
const appIcon = new Tray('/Users/somebody/images/icon.png')
let win = new BrowserWindow({icon: '/Users/somebody/images/window.png'})
console.log(appIcon, win)
```
Or read the image from the clipboard which returns a `nativeImage`:
```javascript
const image = clipboard.readImage();
const appIcon = new Tray(image);
const {clipboard, Tray} = require('electron')
const image = clipboard.readImage()
const appIcon = new Tray(image)
console.log(appIcon)
```
## Supported Formats
@@ -25,8 +30,8 @@ const appIcon = new Tray(image);
Currently `PNG` and `JPEG` image formats are supported. `PNG` is recommended
because of its support for transparency and lossless compression.
On Windows, you can also load `ICO` icons from file paths, to get best visual
effects it is recommended to include at least followings sizes in the icon:
On Windows, you can also load `ICO` icons from file paths. For best visual
quality it is recommended to include at least the following sizes in the icon:
* 16x16
* 32x32
@@ -35,8 +40,8 @@ effects it is recommended to include at least followings sizes in the icon:
## High Resolution Image
On platforms that have high-DPI support, you can append `@2x` after image's
base filename to mark it as a high resolution image.
On platforms that have high-DPI support such as Apple Retina displays, you can
append `@2x` after image's base filename to mark it as a high resolution image.
For example if `icon.png` is a normal image that has standard resolution, then
`icon@2x.png` will be treated as a high resolution image that has double DPI
@@ -55,7 +60,9 @@ images/
```javascript
let appIcon = new Tray('/Users/somebody/images/icon.png');
const {Tray} = require('electron')
let appIcon = new Tray('/Users/somebody/images/icon.png')
console.log(appIcon)
```
Following suffixes for DPI are also supported:
@@ -91,22 +98,24 @@ To mark an image as a template image, its filename should end with the word
## Methods
The `nativeImage` class has the following methods:
The `nativeImage` module has the following methods, all of which return
an instance of the `NativeImage` class:
### `nativeImage.createEmpty()`
Creates an empty `nativeImage` instance.
Creates an empty `NativeImage` instance.
### `nativeImage.createFromPath(path)`
* `path` String
Creates a new `nativeImage` instance from a file located at `path`.
Creates a new `NativeImage` instance from a file located at `path`.
```javascript
const nativeImage = require('electron').nativeImage;
const nativeImage = require('electron').nativeImage
let image = nativeImage.createFromPath('/Users/somebody/images/icon.png');
let image = nativeImage.createFromPath('/Users/somebody/images/icon.png')
console.log(image)
```
### `nativeImage.createFromBuffer(buffer[, scaleFactor])`
@@ -114,34 +123,38 @@ let image = nativeImage.createFromPath('/Users/somebody/images/icon.png');
* `buffer` [Buffer][buffer]
* `scaleFactor` Double (optional)
Creates a new `nativeImage` instance from `buffer`. The default `scaleFactor` is
Creates a new `NativeImage` instance from `buffer`. The default `scaleFactor` is
1.0.
### `nativeImage.createFromDataURL(dataURL)`
* `dataURL` String
Creates a new `nativeImage` instance from `dataURL`.
Creates a new `NativeImage` instance from `dataURL`.
## Instance Methods
## Class: NativeImage
The following methods are available on instances of `nativeImage`:
A native wrapper for images such as tray, dock, and application icons.
### `image.toPNG()`
### Instance Methods
The following methods are available on instances of the `NativeImage` class:
#### `image.toPNG()`
Returns a [Buffer][buffer] that contains the image's `PNG` encoded data.
### `image.toJPEG(quality)`
#### `image.toJPEG(quality)`
* `quality` Integer (**required**) - Between 0 - 100.
Returns a [Buffer][buffer] that contains the image's `JPEG` encoded data.
### `image.toDataURL()`
#### `image.toDataURL()`
Returns the data URL of the image.
### `image.getNativeHandle()` _macOS_
#### `image.getNativeHandle()` _macOS_
Returns a [Buffer][buffer] that stores C pointer to underlying native handle of
the image. On macOS, a pointer to `NSImage` instance would be returned.
@@ -150,22 +163,22 @@ Notice that the returned pointer is a weak pointer to the underlying native
image instead of a copy, so you _must_ ensure that the associated
`nativeImage` instance is kept around.
### `image.isEmpty()`
#### `image.isEmpty()`
Returns a boolean whether the image is empty.
### `image.getSize()`
#### `image.getSize()`
Returns the size of the image.
[buffer]: https://nodejs.org/api/buffer.html#buffer_class_buffer
### `image.setTemplateImage(option)`
#### `image.setTemplateImage(option)`
* `option` Boolean
Marks the image as template image.
Marks the image as a template image.
### `image.isTemplateImage()`
#### `image.isTemplateImage()`
Returns a boolean whether the image is a template image.

View File

@@ -8,11 +8,13 @@ event of the `app` module is emitted.
For example:
```javascript
const {app} = require('electron')
app.on('ready', () => {
require('electron').powerMonitor.on('suspend', () => {
console.log('The system is going to sleep');
});
});
console.log('The system is going to sleep')
})
})
```
## Events

View File

@@ -5,12 +5,12 @@
For example:
```javascript
const {powerSaveBlocker} = require('electron');
const {powerSaveBlocker} = require('electron')
const id = powerSaveBlocker.start('prevent-display-sleep');
console.log(powerSaveBlocker.isStarted(id));
const id = powerSaveBlocker.start('prevent-display-sleep')
console.log(powerSaveBlocker.isStarted(id))
powerSaveBlocker.stop(id);
powerSaveBlocker.stop(id)
```
## Methods

View File

@@ -16,12 +16,12 @@ the global scope when node integration is turned off:
```javascript
// preload.js
const _setImmediate = setImmediate;
const _clearImmediate = clearImmediate;
const _setImmediate = setImmediate
const _clearImmediate = clearImmediate
process.once('loaded', () => {
global.setImmediate = _setImmediate;
global.clearImmediate = _clearImmediate;
});
global.setImmediate = _setImmediate
global.clearImmediate = _clearImmediate
})
```
## Properties

View File

@@ -6,19 +6,19 @@ An example of implementing a protocol that has the same effect as the
`file://` protocol:
```javascript
const {app, protocol} = require('electron');
const path = require('path');
const {app, protocol} = require('electron')
const path = require('path')
app.on('ready', () => {
protocol.registerFileProtocol('atom', (request, callback) => {
const url = request.url.substr(7);
callback({path: path.normalize(__dirname + '/' + url)});
const url = request.url.substr(7)
callback({path: path.normalize(`${__dirname}/${url}`)})
}, (error) => {
if (error)
console.error('Failed to register protocol');
});
});
if (error) console.error('Failed to register protocol')
})
})
```
**Note:** All methods unless specified can only be used after the `ready` event
of the `app` module gets emitted.
@@ -52,10 +52,12 @@ So if you want to register a custom protocol to replace the `http` protocol, you
have to register it as standard scheme:
```javascript
protocol.registerStandardSchemes(['atom']);
const {app, protocol} = require('electron')
protocol.registerStandardSchemes(['atom'])
app.on('ready', () => {
protocol.registerHttpProtocol('atom', ...);
});
protocol.registerHttpProtocol('atom', '...')
})
```
**Note:** This method can only be used before the `ready` event of the `app`
@@ -119,12 +121,13 @@ should be called with either a `Buffer` object or an object that has the `data`,
Example:
```javascript
const {protocol} = require('electron')
protocol.registerBufferProtocol('atom', (request, callback) => {
callback({mimeType: 'text/html', data: new Buffer('<h5>Response</h5>')});
callback({mimeType: 'text/html', data: new Buffer('<h5>Response</h5>')})
}, (error) => {
if (error)
console.error('Failed to register protocol');
});
if (error) console.error('Failed to register protocol')
})
```
### `protocol.registerStringProtocol(scheme, handler[, completion])`

View File

@@ -14,10 +14,9 @@ similar to Java's [RMI][rmi]. An example of creating a browser window from a
renderer process:
```javascript
const {BrowserWindow} = require('electron').remote;
let win = new BrowserWindow({width: 800, height: 600});
win.loadURL('https://github.com');
const {BrowserWindow} = require('electron').remote
let win = new BrowserWindow({width: 800, height: 600})
win.loadURL('https://github.com')
```
**Note:** for the reverse (access the renderer process from the main process),
@@ -70,23 +69,22 @@ For instance you can't use a function from the renderer process in an
```javascript
// main process mapNumbers.js
exports.withRendererCallback = (mapper) => {
return [1,2,3].map(mapper);
};
return [1, 2, 3].map(mapper)
}
exports.withLocalCallback = () => {
return [1,2,3].map(x => x + 1);
};
return [1, 2, 3].map(x => x + 1)
}
```
```javascript
// renderer process
const mapNumbers = require('electron').remote.require('./mapNumbers');
const mapNumbers = require('electron').remote.require('./mapNumbers')
const withRendererCb = mapNumbers.withRendererCallback(x => x + 1)
const withLocalCb = mapNumbers.withLocalCallback()
const withRendererCb = mapNumbers.withRendererCallback(x => x + 1);
const withLocalCb = mapNumbers.withLocalCallback();
console.log(withRendererCb, withLocalCb); // [undefined, undefined, undefined], [2, 3, 4]
console.log(withRendererCb, withLocalCb)
// [undefined, undefined, undefined], [2, 3, 4]
```
As you can see, the renderer callback's synchronous return value was not as
@@ -100,9 +98,9 @@ For example, the following code seems innocent at first glance. It installs a
callback for the `close` event on a remote object:
```javascript
remote.getCurrentWindow().on('close', () => {
// blabla...
});
require('electron').remote.getCurrentWindow().on('close', () => {
// window was closed...
})
```
But remember the callback is referenced by the main process until you
@@ -124,7 +122,8 @@ The built-in modules in the main process are added as getters in the `remote`
module, so you can use them directly like the `electron` module.
```javascript
const app = remote.app;
const app = require('electron').remote.app
console.log(app)
```
## Methods

View File

@@ -21,7 +21,8 @@ let win
app.on('ready', () => {
const {width, height} = electron.screen.getPrimaryDisplay().workAreaSize
win = new BrowserWindow({width, height})
});
win.loadURL('https://github.com')
})
```
Another example of creating a window in the external display:
@@ -43,6 +44,7 @@ app.on('ready', () => {
x: externalDisplay.bounds.x + 50,
y: externalDisplay.bounds.y + 50
})
win.loadURL('https://github.com')
}
})
```

View File

@@ -1,4 +1,4 @@
# session
# session
> Manage browser sessions, cookies, cache, proxy settings, etc.
@@ -8,12 +8,13 @@ You can also access the `session` of existing pages by using the `session`
property of [`WebContents`](web-contents.md), or from the `session` module.
```javascript
const {session, BrowserWindow} = require('electron')
const {BrowserWindow} = require('electron')
let win = new BrowserWindow({width: 800, height: 600})
win.loadURL('http://github.com')
const ses = win.webContents.session
console.log(ses.getUserAgent())
```
## Methods
@@ -52,9 +53,9 @@ Returns the default session object of the app.
You can create a `Session` object in the `session` module:
```javascript
const session = require('electron').session;
const ses = session.fromPartition('persist:name');
const {session} = require('electron')
const ses = session.fromPartition('persist:name')
console.log(ses.getUserAgent())
```
### Instance Events
@@ -73,12 +74,13 @@ Calling `event.preventDefault()` will cancel the download and `item` will not be
available from next tick of the process.
```javascript
const {session} = require('electron')
session.defaultSession.on('will-download', (event, item, webContents) => {
event.preventDefault();
event.preventDefault()
require('request')(item.getURL(), (data) => {
require('fs').writeFileSync('/somewhere', data);
});
});
require('fs').writeFileSync('/somewhere', data)
})
})
```
### Instance Methods
@@ -121,6 +123,8 @@ Writes any unwritten DOMStorage data to disk.
* `config` Object
* `pacScript` String - The URL associated with the PAC file.
* `proxyRules` String - Rules indicating which proxies to use.
* `proxyBypassRules` String - Rules indicating which URLs should
bypass the proxy settings.
* `callback` Function - Called when operation is done.
Sets the proxy settings.
@@ -153,6 +157,43 @@ For example:
* `http=foopy;socks=foopy2` - Use HTTP proxy `foopy` for http URLs, and use
`socks4://foopy2` for all other URLs.
The `proxyBypassRules` is a comma separated list of rules described below:
* `[ URL_SCHEME "://" ] HOSTNAME_PATTERN [ ":" <port> ]`
Match all hostnames that match the pattern HOSTNAME_PATTERN.
Examples:
"foobar.com", "*foobar.com", "*.foobar.com", "*foobar.com:99",
"https://x.*.y.com:99"
* `"." HOSTNAME_SUFFIX_PATTERN [ ":" PORT ]`
Match a particular domain suffix.
Examples:
".google.com", ".com", "http://.google.com"
* `[ SCHEME "://" ] IP_LITERAL [ ":" PORT ]`
Match URLs which are IP address literals.
Examples:
"127.0.1", "[0:0::1]", "[::1]", "http://[::1]:99"
* `IP_LITERAL "/" PREFIX_LENGHT_IN_BITS`
Match any URL that is to an IP literal that falls between the
given range. IP range is specified using CIDR notation.
Examples:
"192.168.1.1/16", "fefe:13::abc/33".
* `<local>`
Match local addresses. The meaning of `<local>` is whether the
host matches one of: "127.0.0.1", "::1", "localhost".
### `ses.resolveProxy(url, callback)`
* `url` URL
@@ -181,13 +222,13 @@ Emulates network with the given configuration for the `session`.
```javascript
// To emulate a GPRS connection with 50kbps throughput and 500 ms latency.
window.webContents.session.enableNetworkEmulation({
latency: 500,
downloadThroughput: 6400,
uploadThroughput: 6400
});
latency: 500,
downloadThroughput: 6400,
uploadThroughput: 6400
})
// To emulate a network outage.
window.webContents.session.enableNetworkEmulation({offline: true});
window.webContents.session.enableNetworkEmulation({offline: true})
```
#### `ses.disableNetworkEmulation()`
@@ -208,12 +249,12 @@ Calling `setCertificateVerifyProc(null)` will revert back to default certificate
verify proc.
```javascript
myWindow.webContents.session.setCertificateVerifyProc((hostname, cert, callback) => {
if (hostname === 'github.com')
callback(true);
else
callback(false);
});
const {BrowserWindow} = require('electron')
let win = new BrowserWindow()
win.webContents.session.setCertificateVerifyProc((hostname, cert, callback) => {
callback(hostname === 'github.com')
})
```
#### `ses.setPermissionRequestHandler(handler)`
@@ -228,16 +269,14 @@ Sets the handler which can be used to respond to permission requests for the `se
Calling `callback(true)` will allow the permission and `callback(false)` will reject it.
```javascript
session.fromPartition(partition).setPermissionRequestHandler((webContents, permission, callback) => {
if (webContents.getURL() === host) {
if (permission === 'notifications') {
callback(false); // denied.
return;
}
const {session} = require('electron')
session.fromPartition('some-partition').setPermissionRequestHandler((webContents, permission, callback) => {
if (webContents.getURL() === 'some-host' && permission === 'notifications') {
return callback(false) // denied.
}
callback(true);
});
callback(true)
})
```
#### `ses.clearHostResolverCache([callback])`
@@ -255,6 +294,7 @@ Dynamically sets whether to always send credentials for HTTP NTLM or Negotiate
authentication.
```javascript
const {session} = require('electron')
// consider any url ending with `example.com`, `foobar.com`, `baz`
// for integrated authentication.
session.defaultSession.allowNTLMCredentialsForDomains('*example.com, *foobar.com, *baz')
@@ -301,13 +341,12 @@ const {app, session} = require('electron')
const path = require('path')
app.on('ready', function () {
const protocol = session.fromPartition(partitionName).protocol
const protocol = session.fromPartition('some-partition').protocol
protocol.registerFileProtocol('atom', function (request, callback) {
var url = request.url.substr(7)
callback({path: path.normalize(__dirname + '/' + url)})
callback({path: path.normalize(`${__dirname}/${url}`)})
}, function (error) {
if (error)
console.error('Failed to register protocol')
if (error) console.error('Failed to register protocol')
})
})
```
@@ -320,22 +359,23 @@ The `Cookies` class gives you ability to query and modify cookies. Instances of
For example:
```javascript
const {session} = require('electron')
// Query all cookies.
session.defaultSession.cookies.get({}, (error, cookies) => {
console.log(cookies)
console.log(error, cookies)
})
// Query all cookies associated with a specific url.
session.defaultSession.cookies.get({url: 'http://www.github.com'}, (error, cookies) => {
console.log(cookies)
console.log(error, cookies)
})
// Set a cookie with the given cookie data;
// may overwrite equivalent cookies if they exist.
const cookie = {url: 'http://www.github.com', name: 'dummy_name', value: 'dummy'}
session.defaultSession.cookies.set(cookie, (error) => {
if (error)
console.error(error)
if (error) console.error(error)
})
```
@@ -425,13 +465,15 @@ called with an `response` object when `listener` has done its work.
An example of adding `User-Agent` header for requests:
```javascript
const {session} = require('electron')
// Modify the user agent for all requests to the following urls.
const filter = {
urls: ['https://*.github.com/*', '*://electron.github.io']
}
session.defaultSession.webRequest.onBeforeSendHeaders(filter, (details, callback) => {
details.requestHeaders['User-Agent'] = "MyAgent"
details.requestHeaders['User-Agent'] = 'MyAgent'
callback({cancel: false, requestHeaders: details.requestHeaders})
})
```

View File

@@ -7,9 +7,9 @@ The `shell` module provides functions related to desktop integration.
An example of opening a URL in the user's default browser:
```javascript
const {shell} = require('electron');
const {shell} = require('electron')
shell.openExternal('https://github.com');
shell.openExternal('https://github.com')
```
## Methods

View File

@@ -19,14 +19,13 @@ scripts to be able to use those modules.
The main process script is just like a normal Node.js script:
```javascript
const {app, BrowserWindow} = require('electron');
let win = null;
const {app, BrowserWindow} = require('electron')
let win = null
app.on('ready', () => {
win = new BrowserWindow({width: 800, height: 600});
win.loadURL('https://github.com');
});
win = new BrowserWindow({width: 800, height: 600})
win.loadURL('https://github.com')
})
```
The renderer process is no different than a normal web page, except for the
@@ -37,8 +36,8 @@ extra ability to use node modules:
<html>
<body>
<script>
const {app} = require('electron').remote;
console.log(app.getVersion());
const {app} = require('electron').remote
console.log(app.getVersion())
</script>
</body>
</html>
@@ -53,23 +52,43 @@ As of 0.37, you can use
built-in modules.
```javascript
const {app, BrowserWindow} = require('electron');
const {app, BrowserWindow} = require('electron')
let win
app.on('ready', () => {
win = new BrowserWindow()
win.loadURL('https://github.com')
})
```
If you need the entire `electron` module, you can require it and then using
destructuring to access the individual modules from `electron`.
```javascript
const electron = require('electron');
const {app, BrowserWindow} = electron;
const electron = require('electron')
const {app, BrowserWindow} = electron
let win
app.on('ready', () => {
win = new BrowserWindow()
win.loadURL('https://github.com')
})
```
This is equivalent to the following code:
```javascript
const electron = require('electron');
const app = electron.app;
const BrowserWindow = electron.BrowserWindow;
const electron = require('electron')
const app = electron.app
const BrowserWindow = electron.BrowserWindow
let win
app.on('ready', () => {
win = new BrowserWindow()
win.loadURL('https://github.com')
})
```
[gui]: https://en.wikipedia.org/wiki/Graphical_user_interface

View File

@@ -3,8 +3,8 @@
> Get system preferences.
```javascript
const {systemPreferences} = require('electron');
console.log(systemPreferences.isDarkMode());
const {systemPreferences} = require('electron')
console.log(systemPreferences.isDarkMode())
```
## Methods
@@ -79,23 +79,24 @@ An example of using it to determine if you should create a transparent window or
not (transparent windows won't work correctly when DWM composition is disabled):
```javascript
let browserOptions = {width: 1000, height: 800};
const {BrowserWindow, systemPreferences} = require('electron')
let browserOptions = {width: 1000, height: 800}
// Make the window transparent only if the platform supports it.
if (process.platform !== 'win32' || systemPreferences.isAeroGlassEnabled()) {
browserOptions.transparent = true;
browserOptions.frame = false;
browserOptions.transparent = true
browserOptions.frame = false
}
// Create the window.
let win = new BrowserWindow(browserOptions);
let win = new BrowserWindow(browserOptions)
// Navigate.
if (browserOptions.transparent) {
win.loadURL('file://' + __dirname + '/index.html');
win.loadURL(`file://${__dirname}/index.html`)
} else {
// No transparency, so we load a fallback that uses basic styles.
win.loadURL('file://' + __dirname + '/fallback.html');
win.loadURL(`file://${__dirname}/fallback.html`)
}
```

View File

@@ -13,7 +13,7 @@ app.on('ready', () => {
{label: 'Item2', type: 'radio'},
{label: 'Item3', type: 'radio', checked: true},
{label: 'Item4', type: 'radio'}
]);
])
tray.setToolTip('This is my application.')
tray.setContextMenu(contextMenu)
})
@@ -31,8 +31,18 @@ __Platform limitations:__
you have to call `setContextMenu` again. For example:
```javascript
contextMenu.items[2].checked = false;
appIcon.setContextMenu(contextMenu);
const {Menu, Tray} = require('electron')
const appIcon = new Tray('/path/to/my/icon')
const contextMenu = Menu.buildFromTemplate([
{label: 'Item1', type: 'radio'},
{label: 'Item2', type: 'radio'}
])
// Make a change to the context menu
contextMenu.items[2].checked = false
// Call this again for Linux because we modified the context menu
appIcon.setContextMenu(contextMenu)
```
* On Windows it is recommended to use `ICO` icons to get best visual effects.
@@ -173,12 +183,15 @@ Sets the hover text for this tray icon.
Sets the title displayed aside of the tray icon in the status bar.
#### `tray.setHighlightMode(highlight)` _macOS_
#### `tray.setHighlightMode(mode)` _macOS_
* `highlight` Boolean
* `mode` String highlight mode with one of the following values:
* `'selection'` - Highlight the tray icon when it is clicked and also when
its context menu is open. This is the default.
* `'always'` - Always highlight the tray icon.
* `'never'` - Never highlight the tray icon.
Sets whether the tray icon's background becomes highlighted (in blue)
when the tray icon is clicked. Defaults to true.
Sets when the tray's icon background becomes highlighted (in blue).
#### `tray.displayBalloon(options)` _Windows_

View File

@@ -9,12 +9,13 @@ the [`BrowserWindow`](browser-window.md) object. An example of accessing the
`webContents` object:
```javascript
const {BrowserWindow} = require('electron');
const {BrowserWindow} = require('electron')
let win = new BrowserWindow({width: 800, height: 1500});
win.loadURL('http://github.com');
let win = new BrowserWindow({width: 800, height: 1500})
win.loadURL('http://github.com')
let contents = win.webContents;
let contents = win.webContents
console.log(contents)
```
## Methods
@@ -22,7 +23,8 @@ let contents = win.webContents;
These methods can be accessed from the `webContents` module:
```js
const {webContents} = require('electron');
const {webContents} = require('electron')
console.log(webContents)
```
### `webContents.getAllWebContents()`
@@ -431,6 +433,7 @@ first available device will be selected. `callback` should be called with
cancel the request.
```javascript
const {app, webContents} = require('electron')
app.commandLine.appendSwitch('enable-web-bluetooth')
app.on('ready', () => {
@@ -448,6 +451,10 @@ app.on('ready', () => {
})
```
#### Event: 'view-painted'
Emitted when a page's view is repainted.
### Instance Methods
#### `contents.loadURL(url[, options])`
@@ -463,8 +470,9 @@ e.g. the `http://` or `file://`. If the load should bypass http cache then
use the `pragma` header to achieve it.
```javascript
const options = {extraHeaders: 'pragma: no-cache\n'};
webContents.loadURL(url, options);
const {webContents} = require('electron')
const options = {extraHeaders: 'pragma: no-cache\n'}
webContents.loadURL('https://github.com', options)
```
#### `contents.downloadURL(url)`
@@ -479,10 +487,12 @@ Initiates a download of the resource at `url` without navigating. The
Returns URL of the current web page.
```javascript
let win = new BrowserWindow({width: 800, height: 600});
win.loadURL('http://github.com');
const {BrowserWindow} = require('electron')
let win = new BrowserWindow({width: 800, height: 600})
win.loadURL('http://github.com')
let currentURL = win.webContents.getURL();
let currentURL = win.webContents.getURL()
console.log(currentURL)
```
#### `contents.getTitle()`
@@ -616,6 +626,13 @@ Executes the editing command `cut` in web page.
Executes the editing command `copy` in web page.
### `contents.copyImageAt(x, y)`
* `x` Integer
* `y` Integer
Copy the image at the given position to the clipboard.
#### `contents.paste()`
Executes the editing command `paste` in web page.
@@ -686,12 +703,13 @@ the request can be obtained by subscribing to
Stops any `findInPage` request for the `webContents` with the provided `action`.
```javascript
const {webContents} = require('electron')
webContents.on('found-in-page', (event, result) => {
if (result.finalUpdate)
webContents.stopFindInPage('clearSelection');
});
if (result.finalUpdate) webContents.stopFindInPage('clearSelection')
})
const requestId = webContents.findInPage('api');
const requestId = webContents.findInPage('api')
console.log(requestId)
```
#### `contents.capturePage([rect, ]callback)`
@@ -757,7 +775,7 @@ The `callback` will be called with `callback(error, data)` on completion. The
By default, an empty `options` will be regarded as:
```javascript
```
{
marginsType: 0,
printBackground: false,
@@ -769,23 +787,22 @@ By default, an empty `options` will be regarded as:
An example of `webContents.printToPDF`:
```javascript
const {BrowserWindow} = require('electron');
const fs = require('fs');
const {BrowserWindow} = require('electron')
const fs = require('fs')
let win = new BrowserWindow({width: 800, height: 600});
win.loadURL('http://github.com');
let win = new BrowserWindow({width: 800, height: 600})
win.loadURL('http://github.com')
win.webContents.on('did-finish-load', () => {
// Use default printing options
win.webContents.printToPDF({}, (error, data) => {
if (error) throw error;
if (error) throw error
fs.writeFile('/tmp/print.pdf', data, (error) => {
if (error)
throw error;
console.log('Write PDF successfully.');
});
});
});
if (error) throw error
console.log('Write PDF successfully.')
})
})
})
```
#### `contents.addWorkSpace(path)`
@@ -796,9 +813,11 @@ Adds the specified path to DevTools workspace. Must be used after DevTools
creation:
```javascript
const {BrowserWindow} = require('electron')
let win = new BrowserWindow()
win.webContents.on('devtools-opened', () => {
win.webContents.addWorkSpace(__dirname);
});
win.webContents.addWorkSpace(__dirname)
})
```
#### `contents.removeWorkSpace(path)`
@@ -859,15 +878,16 @@ An example of sending messages from the main process to the renderer process:
```javascript
// In the main process.
let win = null;
const {app, BrowserWindow} = require('electron')
let win = null
app.on('ready', () => {
win = new BrowserWindow({width: 800, height: 600});
win.loadURL(`file://${__dirname}/index.html`);
win = new BrowserWindow({width: 800, height: 600})
win.loadURL(`file://${__dirname}/index.html`)
win.webContents.on('did-finish-load', () => {
win.webContents.send('ping', 'whoooooooh!');
});
});
win.webContents.send('ping', 'whoooooooh!')
})
})
```
```html
@@ -876,8 +896,8 @@ app.on('ready', () => {
<body>
<script>
require('electron').ipcRenderer.on('ping', (event, message) => {
console.log(message); // Prints "whoooooooh!"
});
console.log(message) // Prints 'whoooooooh!'
})
</script>
</body>
</html>
@@ -1006,14 +1026,16 @@ the cursor when dragging.
Returns true if the process of saving page has been initiated successfully.
```javascript
win.loadURL('https://github.com');
const {BrowserWindow} = require('electron')
let win = new BrowserWindow()
win.loadURL('https://github.com')
win.webContents.on('did-finish-load', () => {
win.webContents.savePage('/tmp/test.html', 'HTMLComplete', (error) => {
if (!error)
console.log('Save page successfully');
});
});
if (!error) console.log('Save page successfully')
})
})
```
#### `contents.showDefinitionForSelection()` _macOS_
@@ -1050,24 +1072,28 @@ Get the debugger instance for this webContents.
Debugger API serves as an alternate transport for [remote debugging protocol][rdp].
```javascript
const {BrowserWindow} = require('electron')
let win = new BrowserWindow()
try {
win.webContents.debugger.attach('1.1');
} catch(err) {
console.log('Debugger attach failed : ', err);
};
win.webContents.debugger.attach('1.1')
} catch (err) {
console.log('Debugger attach failed : ', err)
}
win.webContents.debugger.on('detach', (event, reason) => {
console.log('Debugger detached due to : ', reason);
});
console.log('Debugger detached due to : ', reason)
})
win.webContents.debugger.on('message', (event, method, params) => {
if (method === 'Network.requestWillBeSent') {
if (params.request.url === 'https://www.github.com')
win.webContents.debugger.detach();
if (params.request.url === 'https://www.github.com') {
win.webContents.debugger.detach()
}
}
});
})
win.webContents.debugger.sendCommand('Network.enable');
win.webContents.debugger.sendCommand('Network.enable')
```
### Instance Methods

View File

@@ -5,9 +5,9 @@
An example of zooming current page to 200%.
```javascript
const {webFrame} = require('electron');
const {webFrame} = require('electron')
webFrame.setZoomFactor(2);
webFrame.setZoomFactor(2)
```
## Methods
@@ -58,11 +58,12 @@ whether the word passed is correctly spelled.
An example of using [node-spellchecker][spellchecker] as provider:
```javascript
const {webFrame} = require('electron')
webFrame.setSpellCheckProvider('en-US', true, {
spellCheck(text) {
return !(require('spellchecker').isMisspelled(text));
spellCheck (text) {
return !(require('spellchecker').isMisspelled(text))
}
});
})
```
### `webFrame.registerURLSchemeAsSecure(scheme)`
@@ -112,12 +113,13 @@ Returns an object describing usage information of Blink's internal memory
caches.
```javascript
const {webFrame} = require('electron')
console.log(webFrame.getResourceUsage())
```
This will generate:
```javascript
```
{
images: {
count: 22,
@@ -130,8 +132,8 @@ This will generate:
cssStyleSheets: { /* same with "images" */ },
xslStyleSheets: { /* same with "images" */ },
fonts: { /* same with "images" */ },
other: { /* same with "images" */ },
}
other: { /* same with "images" */ }
})
```
### `webFrame.clearCache()`

View File

@@ -12,7 +12,7 @@ app. It doesn't have the same permissions as your web page and all interactions
between your app and embedded content will be asynchronous. This keeps your app
safe from the embedded content.
For security purpose, `webview` can only be used in `BrowserWindow`s that have
For security purposes, `webview` can only be used in `BrowserWindow`s that have
`nodeIntegration` enabled.
## Example
@@ -35,20 +35,20 @@ and displays a "loading..." message during the load time:
```html
<script>
onload = () => {
const webview = document.getElementById('foo');
const indicator = document.querySelector('.indicator');
const webview = document.getElementById('foo')
const indicator = document.querySelector('.indicator')
const loadstart = () => {
indicator.innerText = 'loading...';
};
indicator.innerText = 'loading...'
}
const loadstop = () => {
indicator.innerText = '';
};
indicator.innerText = ''
}
webview.addEventListener('did-start-loading', loadstart);
webview.addEventListener('did-stop-loading', loadstop);
};
webview.addEventListener('did-start-loading', loadstart)
webview.addEventListener('did-stop-loading', loadstop)
}
</script>
```
@@ -223,9 +223,10 @@ The `webview` tag has the following methods:
**Example**
```javascript
const webview = document.getElementById('foo')
webview.addEventListener('dom-ready', () => {
webview.openDevTools();
});
webview.openDevTools()
})
```
### `<webview>.loadURL(url[, options])`
@@ -618,9 +619,10 @@ The following example code forwards all log messages to the embedder's console
without regard for log level or other properties.
```javascript
const webview = document.getElementById('foo')
webview.addEventListener('console-message', (e) => {
console.log('Guest page logged a message:', e.message);
});
console.log('Guest page logged a message:', e.message)
})
```
### Event: 'found-in-page'
@@ -638,12 +640,13 @@ Fired when a result is available for
[`webview.findInPage`](web-view-tag.md#webviewtagfindinpage) request.
```javascript
const webview = document.getElementById('foo')
webview.addEventListener('found-in-page', (e) => {
if (e.result.finalUpdate)
webview.stopFindInPage('keepSelection');
});
if (e.result.finalUpdate) webview.stopFindInPage('keepSelection')
})
const requestId = webview.findInPage('test');
const requestId = webview.findInPage('test')
console.log(requestId)
```
### Event: 'new-window'
@@ -662,14 +665,15 @@ Fired when the guest page attempts to open a new browser window.
The following example code opens the new url in system's default browser.
```javascript
const {shell} = require('electron');
const {shell} = require('electron')
const webview = document.getElementById('foo')
webview.addEventListener('new-window', (e) => {
const protocol = require('url').parse(e.url).protocol;
const protocol = require('url').parse(e.url).protocol
if (protocol === 'http:' || protocol === 'https:') {
shell.openExternal(e.url);
shell.openExternal(e.url)
}
});
})
```
### Event: 'will-navigate'
@@ -722,9 +726,10 @@ The following example code navigates the `webview` to `about:blank` when the
guest attempts to close itself.
```javascript
const webview = document.getElementById('foo')
webview.addEventListener('close', () => {
webview.src = 'about:blank';
});
webview.src = 'about:blank'
})
```
### Event: 'ipc-message'
@@ -741,19 +746,20 @@ between guest page and embedder page:
```javascript
// In embedder page.
const webview = document.getElementById('foo')
webview.addEventListener('ipc-message', (event) => {
console.log(event.channel);
console.log(event.channel)
// Prints "pong"
});
webview.send('ping');
})
webview.send('ping')
```
```javascript
// In guest page.
const {ipcRenderer} = require('electron');
const {ipcRenderer} = require('electron')
ipcRenderer.on('ping', () => {
ipcRenderer.sendToHost('pong');
});
ipcRenderer.sendToHost('pong')
})
```
### Event: 'crashed'

View File

@@ -10,8 +10,8 @@ The proxy has limited standard functionality implemented to be
compatible with traditional web pages. For full control of the new window
you should create a `BrowserWindow` directly.
The newly created `BrowserWindow` will inherit parent window's options by
default, to override inherited options you can set them in the `features`
The newly created `BrowserWindow` will inherit the parent window's options by
default. To override inherited options you can set them in the `features`
string.
### `window.open(url[, frameName][, features])`
@@ -45,33 +45,33 @@ limited functionality with the child window.
The `BrowserWindowProxy` object has the following instance methods:
#### `BrowserWindowProxy.blur()`
#### `win.blur()`
Removes focus from the child window.
#### `BrowserWindowProxy.close()`
#### `win.close()`
Forcefully closes the child window without calling its unload event.
#### `BrowserWindowProxy.closed`
#### `win.closed`
Set to true after the child window gets closed.
#### `BrowserWindowProxy.eval(code)`
#### `win.eval(code)`
* `code` String
Evaluates the code in the child window.
#### `BrowserWindowProxy.focus()`
#### `win.focus()`
Focuses the child window (brings the window to front).
#### `BrowserWindowProxy.print()`
#### `win.print()`
Invokes the print dialog on the child window.
#### `BrowserWindowProxy.postMessage(message, targetOrigin)`
#### `win.postMessage(message, targetOrigin)`
* `message` String
* `targetOrigin` String

View File

@@ -58,17 +58,25 @@ $ python script\build.py -c D
After building is done, you can find `electron.exe` under `out\D` (debug
target) or under `out\R` (release target).
## 64bit Build
## 32bit Build
To build for the 64bit target, you need to pass `--target_arch=x64` when running
the bootstrap script:
To build for the 32bit target, you need to pass `--target_arch=ia32` when
running the bootstrap script:
```powershell
$ python script\bootstrap.py -v --target_arch=x64
$ python script\bootstrap.py -v --target_arch=ia32
```
The other building steps are exactly the same.
## Visual Studio project
To generate a Visual Studio project, you can pass the `--msvs` parameter:
```powershell
$ python script\bootstrap.py --msvs
```
## Tests
Test your changes conform to the project coding style using:

View File

@@ -36,17 +36,17 @@ renderers through the `remote` property of `electron` module:
// In the main process.
global.sharedObject = {
someProperty: 'default value'
};
}
```
```javascript
// In page 1.
require('electron').remote.getGlobal('sharedObject').someProperty = 'new value';
require('electron').remote.getGlobal('sharedObject').someProperty = 'new value'
```
```javascript
// In page 2.
console.log(require('electron').remote.getGlobal('sharedObject').someProperty);
console.log(require('electron').remote.getGlobal('sharedObject').someProperty)
```
## My app's window/tray disappeared after a few minutes.
@@ -63,18 +63,22 @@ If you want a quick fix, you can make the variables global by changing your
code from this:
```javascript
const {app, Tray} = require('electron')
app.on('ready', () => {
const tray = new Tray('/path/to/icon.png');
});
const tray = new Tray('/path/to/icon.png')
tray.setTitle('hello world')
})
```
to this:
```javascript
let tray = null;
const {app, Tray} = require('electron')
let tray = null
app.on('ready', () => {
tray = new Tray('/path/to/icon.png');
});
tray = new Tray('/path/to/icon.png')
tray.setTitle('hello world')
})
```
## I can not use jQuery/RequireJS/Meteor/AngularJS in Electron.
@@ -87,11 +91,13 @@ To solve this, you can turn off node integration in Electron:
```javascript
// In the main process.
const {BrowserWindow} = require('electron')
let win = new BrowserWindow({
webPreferences: {
nodeIntegration: false
}
});
})
win.show()
```
But if you want to keep the abilities of using Node.js and Electron APIs, you
@@ -114,7 +120,7 @@ delete window.module;
When using Electron's built-in module you might encounter an error like this:
```
> require('electron').webFrame.setZoomFactor(1.0);
> require('electron').webFrame.setZoomFactor(1.0)
Uncaught TypeError: Cannot read property 'setZoomLevel' of undefined
```
@@ -125,7 +131,7 @@ To verify whether you are using the correct built-in module, you can print the
path of the `electron` module:
```javascript
console.log(require.resolve('electron'));
console.log(require.resolve('electron'))
```
and then check if it is in the following form:

View File

@@ -51,29 +51,29 @@ $ asar list /path/to/example.asar
Read a file in the `asar` archive:
```javascript
const fs = require('fs');
fs.readFileSync('/path/to/example.asar/file.txt');
const fs = require('fs')
fs.readFileSync('/path/to/example.asar/file.txt')
```
List all files under the root of the archive:
```javascript
const fs = require('fs');
fs.readdirSync('/path/to/example.asar');
const fs = require('fs')
fs.readdirSync('/path/to/example.asar')
```
Use a module from the archive:
```javascript
require('/path/to/example.asar/dir/module.js');
require('/path/to/example.asar/dir/module.js')
```
You can also display a web page in an `asar` archive with `BrowserWindow`:
```javascript
const {BrowserWindow} = require('electron');
let win = new BrowserWindow({width: 800, height: 600});
win.loadURL('file:///path/to/example.asar/static/index.html');
const {BrowserWindow} = require('electron')
let win = new BrowserWindow({width: 800, height: 600})
win.loadURL('file:///path/to/example.asar/static/index.html')
```
### Web API
@@ -85,33 +85,34 @@ For example, to get a file with `$.get`:
```html
<script>
let $ = require('./jquery.min.js');
let $ = require('./jquery.min.js')
$.get('file:///path/to/example.asar/file.txt', (data) => {
console.log(data);
});
console.log(data)
})
</script>
```
### Treating an `asar` Archive as a Normal File
For some cases like verifying the `asar` archive's checksum, we need to read the
content of `asar` archive as file. For this purpose you can use the built-in
content of an `asar` archive as a file. For this purpose you can use the built-in
`original-fs` module which provides original `fs` APIs without `asar` support:
```javascript
const originalFs = require('original-fs');
originalFs.readFileSync('/path/to/example.asar');
const originalFs = require('original-fs')
originalFs.readFileSync('/path/to/example.asar')
```
You can also set `process.noAsar` to `true` to disable the support for `asar` in
the `fs` module:
```javascript
process.noAsar = true;
fs.readFileSync('/path/to/example.asar');
const fs = require('fs')
process.noAsar = true
fs.readFileSync('/path/to/example.asar')
```
## Limitations on Node API
## Limitations of the Node API
Even though we tried hard to make `asar` archives in the Node API work like
directories as much as possible, there are still limitations due to the

View File

@@ -20,11 +20,11 @@ the currently running operating system's native notification APIs to display it.
```javascript
let myNotification = new Notification('Title', {
body: 'Lorem Ipsum Dolor Sit Amet'
});
})
myNotification.onclick = () => {
console.log('Notification clicked');
};
console.log('Notification clicked')
}
```
While code and user experience across operating systems are similar, there
@@ -75,14 +75,16 @@ To add a file to recent documents, you can use the
[app.addRecentDocument][addrecentdocument] API:
```javascript
app.addRecentDocument('/Users/USERNAME/Desktop/work.type');
const {app} = require('electron')
app.addRecentDocument('/Users/USERNAME/Desktop/work.type')
```
And you can use [app.clearRecentDocuments][clearrecentdocuments] API to empty
the recent documents list:
```javascript
app.clearRecentDocuments();
const {app} = require('electron')
app.clearRecentDocuments()
```
### Windows Notes
@@ -113,19 +115,17 @@ To set your custom dock menu, you can use the `app.dock.setMenu` API, which is
only available on macOS:
```javascript
const electron = require('electron');
const app = electron.app;
const Menu = electron.Menu;
const {app, Menu} = require('electron')
const dockMenu = Menu.buildFromTemplate([
{ label: 'New Window', click() { console.log('New Window'); } },
{ label: 'New Window with Settings', submenu: [
{ label: 'Basic' },
{ label: 'Pro'}
{label: 'New Window', click () { console.log('New Window') }},
{label: 'New Window with Settings', submenu: [
{label: 'Basic'},
{label: 'Pro'}
]},
{ label: 'New Command...'}
]);
app.dock.setMenu(dockMenu);
{label: 'New Command...'}
])
app.dock.setMenu(dockMenu)
```
## User Tasks (Windows)
@@ -162,6 +162,7 @@ To set user tasks for your application, you can use
[app.setUserTasks][setusertaskstasks] API:
```javascript
const {app} = require('electron')
app.setUserTasks([
{
program: process.execPath,
@@ -171,13 +172,14 @@ app.setUserTasks([
title: 'New Window',
description: 'Create a new window'
}
]);
])
```
To clean your tasks list, just call `app.setUserTasks` with an empty array:
```javascript
app.setUserTasks([]);
const {app} = require('electron')
app.setUserTasks([])
```
The user tasks will still show even after your application closes, so the icon
@@ -209,34 +211,36 @@ You can use [BrowserWindow.setThumbarButtons][setthumbarbuttons] to set
thumbnail toolbar in your application:
```javascript
const {BrowserWindow} = require('electron');
const path = require('path');
const {BrowserWindow} = require('electron')
const path = require('path')
let win = new BrowserWindow({
width: 800,
height: 600
});
})
win.setThumbarButtons([
{
tooltip: 'button1',
icon: path.join(__dirname, 'button1.png'),
click() { console.log('button1 clicked'); }
click () { console.log('button1 clicked') }
},
{
tooltip: 'button2',
icon: path.join(__dirname, 'button2.png'),
flags: ['enabled', 'dismissonclick'],
click() { console.log('button2 clicked.'); }
click () { console.log('button2 clicked.') }
}
]);
])
```
To clean thumbnail toolbar buttons, just call `BrowserWindow.setThumbarButtons`
with an empty array:
```javascript
win.setThumbarButtons([]);
const {BrowserWindow} = require('electron')
let win = new BrowserWindow()
win.setThumbarButtons([])
```
## Unity Launcher Shortcuts (Linux)
@@ -267,8 +271,9 @@ To set the progress bar for a Window, you can use the
[BrowserWindow.setProgressBar][setprogressbar] API:
```javascript
let win = new BrowserWindow({...});
win.setProgressBar(0.5);
const {BrowserWindow} = require('electron')
let win = new BrowserWindow()
win.setProgressBar(0.5)
```
## Icon Overlays in Taskbar (Windows)
@@ -294,8 +299,9 @@ To set the overlay icon for a window, you can use the
[BrowserWindow.setOverlayIcon][setoverlayicon] API:
```javascript
let win = new BrowserWindow({...});
win.setOverlayIcon('path/to/overlay.png', 'Description for overlay');
const {BrowserWindow} = require('electron')
let win = new BrowserWindow()
win.setOverlayIcon('path/to/overlay.png', 'Description for overlay')
```
## Represented File of Window (macOS)
@@ -316,9 +322,10 @@ To set the represented file of window, you can use the
[BrowserWindow.setDocumentEdited][setdocumentedited] APIs:
```javascript
let win = new BrowserWindow({...});
win.setRepresentedFilename('/etc/passwd');
win.setDocumentEdited(true);
const {BrowserWindow} = require('electron')
let win = new BrowserWindow()
win.setRepresentedFilename('/etc/passwd')
win.setDocumentEdited(true)
```
## Dragging files out of the window
@@ -342,6 +349,7 @@ In web page:
In the main process:
```javascript
const {ipcMain} = require('electron')
ipcMain.on('ondragstart', (event, filePath) => {
event.sender.startDrag({
file: filePath,

View File

@@ -6,16 +6,14 @@ using standard HTML5 APIs, as shown in the following example.
_main.js_
```javascript
const electron = require('electron');
const app = electron.app;
const BrowserWindow = electron.BrowserWindow;
const {app, BrowserWindow} = require('electron')
let onlineStatusWindow;
let onlineStatusWindow
app.on('ready', () => {
onlineStatusWindow = new BrowserWindow({ width: 0, height: 0, show: false });
onlineStatusWindow.loadURL(`file://${__dirname}/online-status.html`);
});
onlineStatusWindow = new BrowserWindow({ width: 0, height: 0, show: false })
onlineStatusWindow.loadURL(`file://${__dirname}/online-status.html`)
})
```
_online-status.html_
@@ -26,13 +24,13 @@ _online-status.html_
<body>
<script>
const alertOnlineStatus = () => {
window.alert(navigator.onLine ? 'online' : 'offline');
};
window.alert(navigator.onLine ? 'online' : 'offline')
}
window.addEventListener('online', alertOnlineStatus);
window.addEventListener('offline', alertOnlineStatus);
window.addEventListener('online', alertOnlineStatus)
window.addEventListener('offline', alertOnlineStatus)
alertOnlineStatus();
alertOnlineStatus()
</script>
</body>
</html>
@@ -47,21 +45,17 @@ to the main process and handled as needed, as shown in the following example.
_main.js_
```javascript
const electron = require('electron');
const app = electron.app;
const ipcMain = electron.ipcMain;
const BrowserWindow = electron.BrowserWindow;
let onlineStatusWindow;
const {app, BrowserWindow, ipcMain} = require('electron')
let onlineStatusWindow
app.on('ready', () => {
onlineStatusWindow = new BrowserWindow({ width: 0, height: 0, show: false });
onlineStatusWindow.loadURL(`file://${__dirname}/online-status.html`);
});
onlineStatusWindow = new BrowserWindow({ width: 0, height: 0, show: false })
onlineStatusWindow.loadURL(`file://${__dirname}/online-status.html`)
})
ipcMain.on('online-status-changed', (event, status) => {
console.log(status);
});
console.log(status)
})
```
_online-status.html_
@@ -71,15 +65,15 @@ _online-status.html_
<html>
<body>
<script>
const {ipcRenderer} = require('electron');
const {ipcRenderer} = require('electron')
const updateOnlineStatus = () => {
ipcRenderer.send('online-status-changed', navigator.onLine ? 'online' : 'offline');
};
ipcRenderer.send('online-status-changed', navigator.onLine ? 'online' : 'offline')
}
window.addEventListener('online', updateOnlineStatus);
window.addEventListener('offline', updateOnlineStatus);
window.addEventListener('online', updateOnlineStatus)
window.addEventListener('offline', updateOnlineStatus)
updateOnlineStatus();
updateOnlineStatus()
</script>
</body>
</html>

View File

@@ -80,56 +80,52 @@ The `main.js` should create windows and handle system events, a typical
example being:
```javascript
const electron = require('electron');
// Module to control application life.
const {app} = electron;
// Module to create native browser window.
const {BrowserWindow} = electron;
const {app, BrowserWindow} = require('electron')
// Keep a global reference of the window object, if you don't, the window will
// be closed automatically when the JavaScript object is garbage collected.
let win;
let win
function createWindow() {
function createWindow () {
// Create the browser window.
win = new BrowserWindow({width: 800, height: 600});
win = new BrowserWindow({width: 800, height: 600})
// and load the index.html of the app.
win.loadURL(`file://${__dirname}/index.html`);
win.loadURL(`file://${__dirname}/index.html`)
// Open the DevTools.
win.webContents.openDevTools();
win.webContents.openDevTools()
// Emitted when the window is closed.
win.on('closed', () => {
// Dereference the window object, usually you would store windows
// in an array if your app supports multi windows, this is the time
// when you should delete the corresponding element.
win = null;
});
win = null
})
}
// This method will be called when Electron has finished
// initialization and is ready to create browser windows.
// Some APIs can only be used after this event occurs.
app.on('ready', createWindow);
app.on('ready', createWindow)
// Quit when all windows are closed.
app.on('window-all-closed', () => {
// On macOS it is common for applications and their menu bar
// to stay active until the user quits explicitly with Cmd + Q
if (process.platform !== 'darwin') {
app.quit();
app.quit()
}
});
})
app.on('activate', () => {
// On macOS it's common to re-create a window in the app when the
// dock icon is clicked and there are no other windows open.
if (win === null) {
createWindow();
createWindow()
}
});
})
// In this file you can include the rest of your app's specific main process
// code. You can also put them in separate files and require them here.

View File

@@ -20,6 +20,9 @@ before the app ready event. Also, turn on `plugins` option of `BrowserWindow`.
For example:
```javascript
const {app, BrowserWindow} = require('electron')
const path = require('path')
// Specify flash path, supposing it is placed in the same directory with main.js.
let pluginName
switch (process.platform) {
@@ -39,7 +42,7 @@ app.commandLine.appendSwitch('ppapi-flash-path', path.join(__dirname, pluginName
app.commandLine.appendSwitch('ppapi-flash-version', '17.0.0.169')
app.on('ready', () => {
win = new BrowserWindow({
let win = new BrowserWindow({
width: 800,
height: 600,
webPreferences: {
@@ -48,7 +51,7 @@ app.on('ready', () => {
})
win.loadURL(`file://${__dirname}/index.html`)
// Something else
});
})
```
You can also try loading the system wide Pepper Flash plugin instead of shipping

View File

@@ -79,7 +79,7 @@ upstream, except that you have to manually specify how to connect chrome driver
and where to find Electron's binary:
```javascript
const webdriver = require('selenium-webdriver');
const webdriver = require('selenium-webdriver')
const driver = new webdriver.Builder()
// The "9515" is the port opened by chrome driver.
@@ -87,22 +87,22 @@ const driver = new webdriver.Builder()
.withCapabilities({
chromeOptions: {
// Here is the path to your Electron binary.
binary: '/Path-to-Your-App.app/Contents/MacOS/Electron',
binary: '/Path-to-Your-App.app/Contents/MacOS/Electron'
}
})
.forBrowser('electron')
.build();
.build()
driver.get('http://www.google.com');
driver.findElement(webdriver.By.name('q')).sendKeys('webdriver');
driver.findElement(webdriver.By.name('btnG')).click();
driver.get('http://www.google.com')
driver.findElement(webdriver.By.name('q')).sendKeys('webdriver')
driver.findElement(webdriver.By.name('btnG')).click()
driver.wait(() => {
return driver.getTitle().then((title) => {
return title === 'webdriver - Google Search';
});
}, 1000);
return driver.getTitle().then((title) => {
return title === 'webdriver - Google Search'
})
}, 1000)
driver.quit();
driver.quit()
```
## Setting up with WebdriverIO
@@ -132,7 +132,7 @@ $ npm install webdriverio
### 3. Connect to chrome driver
```javascript
const webdriverio = require('webdriverio');
const webdriverio = require('webdriverio')
const options = {
host: 'localhost', // Use localhost as chrome driver server
port: 9515, // "9515" is the port opened by chrome driver.
@@ -143,9 +143,9 @@ const options = {
args: [/* cli arguments */] // Optional, perhaps 'app=' + /path/to/your/app/
}
}
};
}
let client = webdriverio.remote(options);
let client = webdriverio.remote(options)
client
.init()
@@ -153,9 +153,9 @@ client
.setValue('#q', 'webdriverio')
.click('#btnG')
.getTitle().then((title) => {
console.log('Title was: ' + title);
console.log('Title was: ' + title)
})
.end();
.end()
```
## Workflow

View File

@@ -51,23 +51,26 @@ enabled.
Example code:
```javascript
const {app, BrowserWindow} = require('electron')
// You have to pass the filename of `widevinecdmadapter` here, it is
// * `widevinecdmadapter.plugin` on macOS,
// * `libwidevinecdmadapter.so` on Linux,
// * `widevinecdmadapter.dll` on Windows.
app.commandLine.appendSwitch('widevine-cdm-path', '/path/to/widevinecdmadapter.plugin');
app.commandLine.appendSwitch('widevine-cdm-path', '/path/to/widevinecdmadapter.plugin')
// The version of plugin can be got from `chrome://plugins` page in Chrome.
app.commandLine.appendSwitch('widevine-cdm-version', '1.4.8.866');
app.commandLine.appendSwitch('widevine-cdm-version', '1.4.8.866')
let win = null;
let win = null
app.on('ready', () => {
win = new BrowserWindow({
webPreferences: {
// The `plugins` have to be enabled.
plugins: true
}
});
});
})
win.show()
})
```
## Verifying the plugin

View File

@@ -4,7 +4,7 @@
'product_name%': 'Electron',
'company_name%': 'GitHub, Inc',
'company_abbr%': 'github',
'version%': '1.3.0',
'version%': '1.3.1',
},
'includes': [
'filenames.gypi',

View File

@@ -1,71 +1,66 @@
'use strict'
const app = require('electron').app
const EventEmitter = require('events').EventEmitter
const {app} = require('electron')
const {EventEmitter} = require('events')
const squirrelUpdate = require('./squirrel-update-win')
const util = require('util')
function AutoUpdater () {
EventEmitter.call(this)
}
util.inherits(AutoUpdater, EventEmitter)
AutoUpdater.prototype.quitAndInstall = function () {
if (!this.updateAvailable) {
return this.emitError('No update available, can\'t quit and install')
}
squirrelUpdate.processStart()
return app.quit()
}
AutoUpdater.prototype.getFeedURL = function () {
return this.updateURL
}
AutoUpdater.prototype.setFeedURL = function (updateURL, headers) {
this.updateURL = updateURL
}
AutoUpdater.prototype.checkForUpdates = function () {
if (!this.updateURL) {
return this.emitError('Update URL is not set')
}
if (!squirrelUpdate.supported()) {
return this.emitError('Can not find Squirrel')
}
this.emit('checking-for-update')
squirrelUpdate.download(this.updateURL, (error, update) => {
if (error != null) {
return this.emitError(error)
class AutoUpdater extends EventEmitter {
quitAndInstall () {
if (!this.updateAvailable) {
return this.emitError('No update available, can\'t quit and install')
}
if (update == null) {
this.updateAvailable = false
return this.emit('update-not-available')
squirrelUpdate.processStart()
return app.quit()
}
getFeedURL () {
return this.updateURL
}
setFeedURL (updateURL, headers) {
this.updateURL = updateURL
}
checkForUpdates () {
if (!this.updateURL) {
return this.emitError('Update URL is not set')
}
this.updateAvailable = true
this.emit('update-available')
squirrelUpdate.update(this.updateURL, (error) => {
var date, releaseNotes, version
if (!squirrelUpdate.supported()) {
return this.emitError('Can not find Squirrel')
}
this.emit('checking-for-update')
squirrelUpdate.download(this.updateURL, (error, update) => {
if (error != null) {
return this.emitError(error)
}
releaseNotes = update.releaseNotes
version = update.version
if (update == null) {
this.updateAvailable = false
return this.emit('update-not-available')
}
this.updateAvailable = true
this.emit('update-available')
squirrelUpdate.update(this.updateURL, (error) => {
var date, releaseNotes, version
if (error != null) {
return this.emitError(error)
}
releaseNotes = update.releaseNotes
version = update.version
// Following information is not available on Windows, so fake them.
date = new Date()
this.emit('update-downloaded', {}, releaseNotes, version, date, this.updateURL, () => {
this.quitAndInstall()
// Following information is not available on Windows, so fake them.
date = new Date()
this.emit('update-downloaded', {}, releaseNotes, version, date, this.updateURL, () => {
this.quitAndInstall()
})
})
})
})
}
}
// Private: Emit both error object and message, this is to keep compatibility
// with Old APIs.
AutoUpdater.prototype.emitError = function (message) {
return this.emit('error', new Error(message), message)
// Private: Emit both error object and message, this is to keep compatibility
// with Old APIs.
emitError (message) {
return this.emit('error', new Error(message), message)
}
}
module.exports = new AutoUpdater()

View File

@@ -7,7 +7,7 @@ const roles = {
}
},
close: {
label: 'Close',
label: process.platform === 'darwin' ? 'Close Window' : 'Close',
accelerator: 'CommandOrControl+W',
windowMethod: 'close'
},

View File

@@ -93,8 +93,8 @@ if (process.platform === 'win32') {
if (fs.statSyncNoException(updateDotExe)) {
var packageDir = path.dirname(path.resolve(updateDotExe))
var packageName = path.basename(packageDir)
var exeName = path.basename(process.execPath).replace(/\.exe$/i, '')
var packageName = path.basename(packageDir).replace(/\s/g, '')
var exeName = path.basename(process.execPath).replace(/\.exe$/i, '').replace(/\s/g, '')
app.setAppUserModelId(`com.squirrel.${packageName}.${exeName}`)
}

View File

@@ -59,7 +59,7 @@ let valueToMeta = function (sender, value, optimizeSimpleObject = false) {
// Recognize certain types of objects.
if (value === null) {
meta.type = 'value'
} else if (Buffer.isBuffer(value)) {
} else if (ArrayBuffer.isView(value)) {
meta.type = 'buffer'
} else if (Array.isArray(value)) {
meta.type = 'array'
@@ -148,7 +148,7 @@ const unwrapArgs = function (sender, args) {
case 'array':
return unwrapArgs(sender, meta.value)
case 'buffer':
return new Buffer(meta.value)
return Buffer.from(meta.value)
case 'date':
return new Date(meta.value)
case 'promise':

View File

@@ -4,14 +4,13 @@
const path = require('path')
const util = require('util')
var hasProp = {}.hasOwnProperty
const hasProp = {}.hasOwnProperty
// Cache asar archive objects.
var cachedArchives = {}
const cachedArchives = {}
var getOrCreateArchive = function (p) {
var archive
archive = cachedArchives[p]
const getOrCreateArchive = function (p) {
let archive = cachedArchives[p]
if (archive != null) {
return archive
}
@@ -25,31 +24,33 @@
// Clean cache on quit.
process.on('exit', function () {
var archive, p
for (p in cachedArchives) {
for (let p in cachedArchives) {
if (!hasProp.call(cachedArchives, p)) continue
archive = cachedArchives[p]
archive.destroy()
cachedArchives[p].destroy()
}
})
// Separate asar package's path from full path.
var splitPath = function (p) {
var index
const splitPath = function (p) {
// shortcut to disable asar.
if (process.noAsar) {
return [false]
}
if (Buffer.isBuffer(p)) {
p = p.toString()
}
if (typeof p !== 'string') {
return [false]
}
if (p.substr(-5) === '.asar') {
return [true, p, '']
}
p = path.normalize(p)
index = p.lastIndexOf('.asar' + path.sep)
const index = p.lastIndexOf('.asar' + path.sep)
if (index === -1) {
return [false]
}
@@ -57,15 +58,15 @@
}
// Convert asar archive's Stats object to fs's Stats object.
var nextInode = 0
let nextInode = 0
var uid = process.getuid != null ? process.getuid() : 0
const uid = process.getuid != null ? process.getuid() : 0
var gid = process.getgid != null ? process.getgid() : 0
const gid = process.getgid != null ? process.getgid() : 0
var fakeTime = new Date()
const fakeTime = new Date()
var asarStatsToFsStats = function (stats) {
const asarStatsToFsStats = function (stats) {
return {
dev: 1,
ino: ++nextInode,
@@ -104,97 +105,110 @@
}
// Create a ENOENT error.
var notFoundError = function (asarPath, filePath, callback) {
var error
error = new Error(`ENOENT, ${filePath} not found in ${asarPath}`)
const notFoundError = function (asarPath, filePath, callback) {
const error = new Error(`ENOENT, ${filePath} not found in ${asarPath}`)
error.code = 'ENOENT'
error.errno = -2
if (typeof callback !== 'function') {
throw error
}
return process.nextTick(function () {
return callback(error)
process.nextTick(function () {
callback(error)
})
}
// Create a ENOTDIR error.
var notDirError = function (callback) {
var error
error = new Error('ENOTDIR, not a directory')
const notDirError = function (callback) {
const error = new Error('ENOTDIR, not a directory')
error.code = 'ENOTDIR'
error.errno = -20
if (typeof callback !== 'function') {
throw error
}
return process.nextTick(function () {
return callback(error)
process.nextTick(function () {
callback(error)
})
}
// Create a EACCES error.
const accessError = function (asarPath, filePath, callback) {
const error = new Error(`EACCES: permission denied, access '${filePath}'`)
error.code = 'EACCES'
error.errno = -13
if (typeof callback !== 'function') {
throw error
}
process.nextTick(function () {
callback(error)
})
}
// Create invalid archive error.
var invalidArchiveError = function (asarPath, callback) {
var error
error = new Error(`Invalid package ${asarPath}`)
const invalidArchiveError = function (asarPath, callback) {
const error = new Error(`Invalid package ${asarPath}`)
if (typeof callback !== 'function') {
throw error
}
return process.nextTick(function () {
return callback(error)
process.nextTick(function () {
callback(error)
})
}
// Override APIs that rely on passing file path instead of content to C++.
var overrideAPISync = function (module, name, arg) {
var old
const overrideAPISync = function (module, name, arg) {
if (arg == null) {
arg = 0
}
old = module[name]
const old = module[name]
module[name] = function () {
var archive, newPath, p
p = arguments[arg]
const p = arguments[arg]
const [isAsar, asarPath, filePath] = splitPath(p)
if (!isAsar) {
return old.apply(this, arguments)
}
archive = getOrCreateArchive(asarPath)
const archive = getOrCreateArchive(asarPath)
if (!archive) {
invalidArchiveError(asarPath)
}
newPath = archive.copyFileOut(filePath)
const newPath = archive.copyFileOut(filePath)
if (!newPath) {
notFoundError(asarPath, filePath)
}
arguments[arg] = newPath
return old.apply(this, arguments)
}
}
var overrideAPI = function (module, name, arg) {
var old
const overrideAPI = function (module, name, arg) {
if (arg == null) {
arg = 0
}
old = module[name]
const old = module[name]
module[name] = function () {
var archive, callback, newPath, p
p = arguments[arg]
const p = arguments[arg]
const [isAsar, asarPath, filePath] = splitPath(p)
if (!isAsar) {
return old.apply(this, arguments)
}
callback = arguments[arguments.length - 1]
const callback = arguments[arguments.length - 1]
if (typeof callback !== 'function') {
return overrideAPISync(module, name, arg)
}
archive = getOrCreateArchive(asarPath)
const archive = getOrCreateArchive(asarPath)
if (!archive) {
return invalidArchiveError(asarPath, callback)
}
newPath = archive.copyFileOut(filePath)
const newPath = archive.copyFileOut(filePath)
if (!newPath) {
return notFoundError(asarPath, filePath, callback)
}
arguments[arg] = newPath
return old.apply(this, arguments)
}
@@ -202,61 +216,58 @@
// Override fs APIs.
exports.wrapFsWithAsar = function (fs) {
var exists, existsSync, internalModuleReadFile, internalModuleStat, lstat, lstatSync, mkdir, mkdirSync, readFile, readFileSync, readdir, readdirSync, realpath, realpathSync, stat, statSync, statSyncNoException, logFDs, logASARAccess
logFDs = {}
logASARAccess = function (asarPath, filePath, offset) {
const logFDs = {}
const logASARAccess = function (asarPath, filePath, offset) {
if (!process.env.ELECTRON_LOG_ASAR_READS) {
return
}
if (!logFDs[asarPath]) {
var logFilename, logPath
const path = require('path')
logFilename = path.basename(asarPath, '.asar') + '-access-log.txt'
logPath = path.join(require('os').tmpdir(), logFilename)
const logFilename = path.basename(asarPath, '.asar') + '-access-log.txt'
const logPath = path.join(require('os').tmpdir(), logFilename)
logFDs[asarPath] = fs.openSync(logPath, 'a')
console.log('Logging ' + asarPath + ' access to ' + logPath)
}
fs.writeSync(logFDs[asarPath], offset + ': ' + filePath + '\n')
}
lstatSync = fs.lstatSync
const {lstatSync} = fs
fs.lstatSync = function (p) {
var archive, stats
const [isAsar, asarPath, filePath] = splitPath(p)
if (!isAsar) {
return lstatSync(p)
}
archive = getOrCreateArchive(asarPath)
const archive = getOrCreateArchive(asarPath)
if (!archive) {
invalidArchiveError(asarPath)
}
stats = archive.stat(filePath)
const stats = archive.stat(filePath)
if (!stats) {
notFoundError(asarPath, filePath)
}
return asarStatsToFsStats(stats)
}
lstat = fs.lstat
const {lstat} = fs
fs.lstat = function (p, callback) {
var archive, stats
const [isAsar, asarPath, filePath] = splitPath(p)
if (!isAsar) {
return lstat(p, callback)
}
archive = getOrCreateArchive(asarPath)
const archive = getOrCreateArchive(asarPath)
if (!archive) {
return invalidArchiveError(asarPath, callback)
}
stats = getOrCreateArchive(asarPath).stat(filePath)
const stats = getOrCreateArchive(asarPath).stat(filePath)
if (!stats) {
return notFoundError(asarPath, filePath, callback)
}
return process.nextTick(function () {
return callback(null, asarStatsToFsStats(stats))
process.nextTick(function () {
callback(null, asarStatsToFsStats(stats))
})
}
statSync = fs.statSync
const {statSync} = fs
fs.statSync = function (p) {
const [isAsar] = splitPath(p)
if (!isAsar) {
@@ -266,7 +277,8 @@
// Do not distinguish links for now.
return fs.lstatSync(p)
}
stat = fs.stat
const {stat} = fs
fs.stat = function (p, callback) {
const [isAsar] = splitPath(p)
if (!isAsar) {
@@ -274,47 +286,47 @@
}
// Do not distinguish links for now.
return process.nextTick(function () {
return fs.lstat(p, callback)
process.nextTick(function () {
fs.lstat(p, callback)
})
}
statSyncNoException = fs.statSyncNoException
const {statSyncNoException} = fs
fs.statSyncNoException = function (p) {
var archive, stats
const [isAsar, asarPath, filePath] = splitPath(p)
if (!isAsar) {
return statSyncNoException(p)
}
archive = getOrCreateArchive(asarPath)
const archive = getOrCreateArchive(asarPath)
if (!archive) {
return false
}
stats = archive.stat(filePath)
const stats = archive.stat(filePath)
if (!stats) {
return false
}
return asarStatsToFsStats(stats)
}
realpathSync = fs.realpathSync
const {realpathSync} = fs
fs.realpathSync = function (p) {
var archive, real
const [isAsar, asarPath, filePath] = splitPath(p)
if (!isAsar) {
return realpathSync.apply(this, arguments)
}
archive = getOrCreateArchive(asarPath)
const archive = getOrCreateArchive(asarPath)
if (!archive) {
invalidArchiveError(asarPath)
}
real = archive.realpath(filePath)
const real = archive.realpath(filePath)
if (real === false) {
notFoundError(asarPath, filePath)
}
return path.join(realpathSync(asarPath), real)
}
realpath = fs.realpath
const {realpath} = fs
fs.realpath = function (p, cache, callback) {
var archive, real
const [isAsar, asarPath, filePath] = splitPath(p)
if (!isAsar) {
return realpath.apply(this, arguments)
@@ -323,11 +335,11 @@
callback = cache
cache = void 0
}
archive = getOrCreateArchive(asarPath)
const archive = getOrCreateArchive(asarPath)
if (!archive) {
return invalidArchiveError(asarPath, callback)
}
real = archive.realpath(filePath)
const real = archive.realpath(filePath)
if (real === false) {
return notFoundError(asarPath, filePath, callback)
}
@@ -338,37 +350,101 @@
return callback(null, path.join(p, real))
})
}
exists = fs.exists
const {exists} = fs
fs.exists = function (p, callback) {
var archive
const [isAsar, asarPath, filePath] = splitPath(p)
if (!isAsar) {
return exists(p, callback)
}
archive = getOrCreateArchive(asarPath)
const archive = getOrCreateArchive(asarPath)
if (!archive) {
return invalidArchiveError(asarPath, callback)
}
return process.nextTick(function () {
return callback(archive.stat(filePath) !== false)
process.nextTick(function () {
callback(archive.stat(filePath) !== false)
})
}
existsSync = fs.existsSync
const {existsSync} = fs
fs.existsSync = function (p) {
var archive
const [isAsar, asarPath, filePath] = splitPath(p)
if (!isAsar) {
return existsSync(p)
}
archive = getOrCreateArchive(asarPath)
const archive = getOrCreateArchive(asarPath)
if (!archive) {
return false
}
return archive.stat(filePath) !== false
}
readFile = fs.readFile
const {access} = fs
fs.access = function (p, mode, callback) {
const [isAsar, asarPath, filePath] = splitPath(p)
if (!isAsar) {
return access.apply(this, arguments)
}
if (typeof mode === 'function') {
callback = mode
mode = fs.constants.F_OK
}
const archive = getOrCreateArchive(asarPath)
if (!archive) {
return invalidArchiveError(asarPath, callback)
}
const info = archive.getFileInfo(filePath)
if (!info) {
return notFoundError(asarPath, filePath, callback)
}
if (info.unpacked) {
const realPath = archive.copyFileOut(filePath)
return fs.access(realPath, mode, callback)
}
const stats = getOrCreateArchive(asarPath).stat(filePath)
if (!stats) {
return notFoundError(asarPath, filePath, callback)
}
if (mode & fs.constants.W_OK) {
return accessError(asarPath, filePath, callback)
}
process.nextTick(function () {
callback()
})
}
const {accessSync} = fs
fs.accessSync = function (p, mode) {
const [isAsar, asarPath, filePath] = splitPath(p)
if (!isAsar) {
return accessSync.apply(this, arguments)
}
if (mode == null) {
mode = fs.constants.F_OK
}
const archive = getOrCreateArchive(asarPath)
if (!archive) {
invalidArchiveError(asarPath)
}
const info = archive.getFileInfo(filePath)
if (!info) {
notFoundError(asarPath, filePath)
}
if (info.unpacked) {
const realPath = archive.copyFileOut(filePath)
return fs.accessSync(realPath, mode)
}
const stats = getOrCreateArchive(asarPath).stat(filePath)
if (!stats) {
notFoundError(asarPath, filePath)
}
if (mode & fs.constants.W_OK) {
accessError(asarPath, filePath)
}
}
const {readFile} = fs
fs.readFile = function (p, options, callback) {
var archive, buffer, encoding, fd, info, realPath
const [isAsar, asarPath, filePath] = splitPath(p)
if (!isAsar) {
return readFile.apply(this, arguments)
@@ -377,21 +453,21 @@
callback = options
options = void 0
}
archive = getOrCreateArchive(asarPath)
const archive = getOrCreateArchive(asarPath)
if (!archive) {
return invalidArchiveError(asarPath, callback)
}
info = archive.getFileInfo(filePath)
const info = archive.getFileInfo(filePath)
if (!info) {
return notFoundError(asarPath, filePath, callback)
}
if (info.size === 0) {
return process.nextTick(function () {
return callback(null, new Buffer(0))
callback(null, new Buffer(0))
})
}
if (info.unpacked) {
realPath = archive.copyFileOut(filePath)
const realPath = archive.copyFileOut(filePath)
return fs.readFile(realPath, options, callback)
}
if (!options) {
@@ -405,31 +481,29 @@
} else if (!util.isObject(options)) {
throw new TypeError('Bad arguments')
}
encoding = options.encoding
buffer = new Buffer(info.size)
fd = archive.getFd()
const {encoding} = options
const buffer = new Buffer(info.size)
const fd = archive.getFd()
if (!(fd >= 0)) {
return notFoundError(asarPath, filePath, callback)
}
logASARAccess(asarPath, filePath, info.offset)
return fs.read(fd, buffer, 0, info.size, info.offset, function (error) {
return callback(error, encoding ? buffer.toString(encoding) : buffer)
fs.read(fd, buffer, 0, info.size, info.offset, function (error) {
callback(error, encoding ? buffer.toString(encoding) : buffer)
})
}
readFileSync = fs.readFileSync
fs.readFileSync = function (p, opts) {
// this allows v8 to optimize this function
var archive, buffer, encoding, fd, info, options, realPath
options = opts
const {readFileSync} = fs
fs.readFileSync = function (p, options) {
const [isAsar, asarPath, filePath] = splitPath(p)
if (!isAsar) {
return readFileSync.apply(this, arguments)
}
archive = getOrCreateArchive(asarPath)
const archive = getOrCreateArchive(asarPath)
if (!archive) {
invalidArchiveError(asarPath)
}
info = archive.getFileInfo(filePath)
const info = archive.getFileInfo(filePath)
if (!info) {
notFoundError(asarPath, filePath)
}
@@ -441,7 +515,7 @@
}
}
if (info.unpacked) {
realPath = archive.copyFileOut(filePath)
const realPath = archive.copyFileOut(filePath)
return fs.readFileSync(realPath, options)
}
if (!options) {
@@ -455,9 +529,9 @@
} else if (!util.isObject(options)) {
throw new TypeError('Bad arguments')
}
encoding = options.encoding
buffer = new Buffer(info.size)
fd = archive.getFd()
const {encoding} = options
const buffer = new Buffer(info.size)
const fd = archive.getFd()
if (!(fd >= 0)) {
notFoundError(asarPath, filePath)
}
@@ -469,89 +543,89 @@
return buffer
}
}
readdir = fs.readdir
const {readdir} = fs
fs.readdir = function (p, callback) {
var archive, files
const [isAsar, asarPath, filePath] = splitPath(p)
if (!isAsar) {
return readdir.apply(this, arguments)
}
archive = getOrCreateArchive(asarPath)
const archive = getOrCreateArchive(asarPath)
if (!archive) {
return invalidArchiveError(asarPath, callback)
}
files = archive.readdir(filePath)
const files = archive.readdir(filePath)
if (!files) {
return notFoundError(asarPath, filePath, callback)
}
return process.nextTick(function () {
return callback(null, files)
process.nextTick(function () {
callback(null, files)
})
}
readdirSync = fs.readdirSync
const {readdirSync} = fs
fs.readdirSync = function (p) {
var archive, files
const [isAsar, asarPath, filePath] = splitPath(p)
if (!isAsar) {
return readdirSync.apply(this, arguments)
}
archive = getOrCreateArchive(asarPath)
const archive = getOrCreateArchive(asarPath)
if (!archive) {
invalidArchiveError(asarPath)
}
files = archive.readdir(filePath)
const files = archive.readdir(filePath)
if (!files) {
notFoundError(asarPath, filePath)
}
return files
}
internalModuleReadFile = process.binding('fs').internalModuleReadFile
const {internalModuleReadFile} = process.binding('fs')
process.binding('fs').internalModuleReadFile = function (p) {
var archive, buffer, fd, info, realPath
const [isAsar, asarPath, filePath] = splitPath(p)
if (!isAsar) {
return internalModuleReadFile(p)
}
archive = getOrCreateArchive(asarPath)
const archive = getOrCreateArchive(asarPath)
if (!archive) {
return void 0
return
}
info = archive.getFileInfo(filePath)
const info = archive.getFileInfo(filePath)
if (!info) {
return void 0
return
}
if (info.size === 0) {
return ''
}
if (info.unpacked) {
realPath = archive.copyFileOut(filePath)
const realPath = archive.copyFileOut(filePath)
return fs.readFileSync(realPath, {
encoding: 'utf8'
})
}
buffer = new Buffer(info.size)
fd = archive.getFd()
const buffer = new Buffer(info.size)
const fd = archive.getFd()
if (!(fd >= 0)) {
return void 0
return
}
logASARAccess(asarPath, filePath, info.offset)
fs.readSync(fd, buffer, 0, info.size, info.offset)
return buffer.toString('utf8')
}
internalModuleStat = process.binding('fs').internalModuleStat
const {internalModuleStat} = process.binding('fs')
process.binding('fs').internalModuleStat = function (p) {
var archive, stats
const [isAsar, asarPath, filePath] = splitPath(p)
if (!isAsar) {
return internalModuleStat(p)
}
archive = getOrCreateArchive(asarPath)
const archive = getOrCreateArchive(asarPath)
// -ENOENT
if (!archive) {
return -34
}
stats = archive.stat(filePath)
const stats = archive.stat(filePath)
// -ENOENT
if (!stats) {
@@ -569,7 +643,7 @@
// This is to work around the recursive looping bug of mkdirp since it is
// widely used.
if (process.platform === 'win32') {
mkdir = fs.mkdir
const {mkdir} = fs
fs.mkdir = function (p, mode, callback) {
if (typeof mode === 'function') {
callback = mode
@@ -578,9 +652,10 @@
if (isAsar && filePath.length) {
return notDirError(callback)
}
return mkdir(p, mode, callback)
mkdir(p, mode, callback)
}
mkdirSync = fs.mkdirSync
const {mkdirSync} = fs
fs.mkdirSync = function (p, mode) {
const [isAsar, , filePath] = splitPath(p)
if (isAsar && filePath.length) {
@@ -595,12 +670,12 @@
// called by `childProcess.{exec,execSync}`, causing
// Electron to consider the full command as a single path
// to an archive.
[ 'exec', 'execSync' ].forEach(function (functionName) {
var old = childProcess[functionName]
['exec', 'execSync'].forEach(function (functionName) {
const old = childProcess[functionName]
childProcess[functionName] = function () {
var processNoAsarOriginalValue = process.noAsar
const processNoAsarOriginalValue = process.noAsar
process.noAsar = true
var result = old.apply(this, arguments)
const result = old.apply(this, arguments)
process.noAsar = processNoAsarOriginalValue
return result
}
@@ -611,6 +686,6 @@
overrideAPISync(process, 'dlopen', 1)
overrideAPISync(require('module')._extensions, '.node', 1)
overrideAPISync(fs, 'openSync')
return overrideAPISync(childProcess, 'execFileSync')
overrideAPISync(childProcess, 'execFileSync')
}
})()

View File

@@ -30,7 +30,7 @@ const wrapArgs = function (args, visited) {
}
visited.delete(value)
return meta
} else if (Buffer.isBuffer(value)) {
} else if (ArrayBuffer.isView(value)) {
return {
type: 'buffer',
value: Array.prototype.slice.call(value, 0)
@@ -163,7 +163,7 @@ const metaToValue = function (meta) {
}
return results
case 'buffer':
return new Buffer(meta.value)
return Buffer.from(meta.value)
case 'promise':
return Promise.resolve({
then: metaToValue(meta.then)

View File

@@ -1,10 +1,11 @@
{
"name": "electron",
"version": "1.3.0",
"version": "1.3.1",
"devDependencies": {
"asar": "^0.11.0",
"request": "*",
"standard": "^7.1.2"
"standard": "^7.1.2",
"standard-markdown": "^1.1.1"
},
"optionalDependencies": {
"runas": "^3.0.0"
@@ -23,9 +24,10 @@
"scripts": {
"bootstrap": "python ./script/bootstrap.py",
"build": "python ./script/build.py -c D",
"lint": "npm run lint-js && npm run lint-cpp",
"lint": "npm run lint-js && npm run lint-cpp && npm run lint-docs",
"lint-js": "standard && cd spec && standard",
"lint-cpp": "python ./script/cpplint.py",
"lint-docs": "standard-markdown docs",
"preinstall": "node -e 'process.exit(0)'",
"repl": "python ./script/start.py --interactive",
"start": "python ./script/start.py",

View File

@@ -65,7 +65,7 @@ def main():
create_chrome_version_h()
touch_config_gypi()
run_update(defines, args.disable_clang, args.clang_dir)
run_update(defines, args.msvs)
update_electron_modules('spec', args.target_arch)
@@ -86,6 +86,8 @@ def parse_args():
action='store_true',
help='Run non-interactively by assuming "yes" to all ' \
'prompts.')
parser.add_argument('--msvs', action='store_true',
help='Generate Visual Studio project')
parser.add_argument('--target_arch', default=get_target_arch(),
help='Manually specify the arch to build for')
parser.add_argument('--clang_dir', default='', help='Path to clang binaries')
@@ -249,14 +251,14 @@ def touch_config_gypi():
f.write(content)
def run_update(defines, disable_clang, clang_dir):
env = os.environ.copy()
if not disable_clang and clang_dir == '':
# Build with prebuilt clang.
set_clang_env(env)
def run_update(defines, msvs):
args = [sys.executable, os.path.join(SOURCE_ROOT, 'script', 'update.py')]
if defines:
args += ['--defines', defines]
if msvs:
args += ['--msvs']
update = os.path.join(SOURCE_ROOT, 'script', 'update.py')
execute_stdout([sys.executable, update, '--defines', defines], env)
execute_stdout(args)
if __name__ == '__main__':

View File

@@ -35,6 +35,13 @@ def main():
if os.environ.has_key('JANKY_SHA1'):
setup_nodenv()
# Ignore the CXX and CC env in CI.
try:
del os.environ['CC']
del os.environ['CXX']
except KeyError:
pass
target_arch = 'x64'
if os.environ.has_key('TARGET_ARCH'):
target_arch = os.environ['TARGET_ARCH']

View File

@@ -28,6 +28,8 @@ def parse_args():
parser = argparse.ArgumentParser(description='Update build configurations')
parser.add_argument('--defines', default='',
help='The definetions passed to gyp')
parser.add_argument('--msvs', action='store_true',
help='Generate Visual Studio project')
return parser.parse_args()
@@ -86,7 +88,11 @@ def run_gyp(target_arch, component):
if define:
defines += ['-D' + define]
return subprocess.call([python, gyp, '-f', 'ninja', '--depth', '.',
generator = 'ninja'
if args.msvs:
generator = 'msvs-ninja'
return subprocess.call([python, gyp, '-f', generator, '--depth', '.',
'electron.gyp', '-Icommon.gypi'] + defines, env=env)

View File

@@ -88,5 +88,19 @@ describe('crash-reporter module', function () {
})
}, /companyName is a required option to crashReporter\.start/)
})
it('can be called multiple times', function () {
assert.doesNotThrow(function () {
crashReporter.start({
companyName: 'Umbrella Corporation',
submitURL: 'http://127.0.0.1/crashes'
})
crashReporter.start({
companyName: 'Umbrella Corporation 2',
submitURL: 'http://127.0.0.1/more-crashes'
})
})
})
})
})

View File

@@ -142,20 +142,25 @@ describe('ipc module', function () {
})
describe('remote value in browser', function () {
var print = path.join(fixtures, 'module', 'print_name.js')
const print = path.join(fixtures, 'module', 'print_name.js')
const printName = remote.require(print)
it('keeps its constructor name for objects', function () {
var buf = new Buffer('test')
var printName = remote.require(print)
const buf = new Buffer('test')
assert.equal(printName.print(buf), 'Buffer')
})
it('supports instanceof Date', function () {
var now = new Date()
var printName = remote.require(print)
const now = new Date()
assert.equal(printName.print(now), 'Date')
assert.deepEqual(printName.echo(now), now)
})
it('supports TypedArray', function () {
const values = [1, 2, 3, 4]
const typedArray = printName.typedArray(values)
assert.deepEqual(values, typedArray)
})
})
describe('remote promise', function () {

View File

@@ -399,7 +399,7 @@ describe('menu module', function () {
describe('MenuItem role', function () {
it('includes a default label and accelerator', function () {
var item = new MenuItem({role: 'close'})
assert.equal(item.label, 'Close')
assert.equal(item.label, process.platform === 'darwin' ? 'Close Window' : 'Close')
assert.equal(item.accelerator, undefined)
assert.equal(item.getDefaultRoleAccelerator(), 'CommandOrControl+W')

View File

@@ -342,4 +342,31 @@ describe('session module', function () {
w.loadURL(`${protocolName}://fake-host`)
})
})
describe('ses.setProxy(options, callback)', function () {
it('allows configuring proxy settings', function (done) {
const config = {
proxyRules: 'http=myproxy:80'
}
session.defaultSession.setProxy(config, function () {
session.defaultSession.resolveProxy('http://localhost', function (proxy) {
assert.equal(proxy, 'PROXY myproxy:80')
done()
})
})
})
it('allows bypassing proxy settings', function (done) {
const config = {
proxyRules: 'http=myproxy:80',
proxyBypassRules: '<local>'
}
session.defaultSession.setProxy(config, function () {
session.defaultSession.resolveProxy('http://localhost', function (proxy) {
assert.equal(proxy, 'DIRECT')
done()
})
})
})
})
})

View File

@@ -13,6 +13,11 @@ describe('asar package', function () {
var fixtures = path.join(__dirname, 'fixtures')
describe('node api', function () {
it('supports paths specified as a Buffer', function () {
var file = new Buffer(path.join(fixtures, 'asar', 'a.asar', 'file1'))
assert.equal(fs.existsSync(file), true)
})
describe('fs.readFileSync', function () {
it('does not leak fd', function () {
var readCalls = 1
@@ -534,6 +539,70 @@ describe('asar package', function () {
})
})
describe('fs.access', function () {
it('accesses a normal file', function (done) {
var p = path.join(fixtures, 'asar', 'a.asar', 'file1')
fs.access(p, function (err) {
assert(err == null)
done()
})
})
it('throws an error when called with write mode', function (done) {
var p = path.join(fixtures, 'asar', 'a.asar', 'file1')
fs.access(p, fs.constants.R_OK | fs.constants.W_OK, function (err) {
assert.equal(err.code, 'EACCES')
done()
})
})
it('throws an error when called on non-existent file', function (done) {
var p = path.join(fixtures, 'asar', 'a.asar', 'not-exist')
fs.access(p, function (err) {
assert.equal(err.code, 'ENOENT')
done()
})
})
it('allows write mode for unpacked files', function (done) {
var p = path.join(fixtures, 'asar', 'unpack.asar', 'a.txt')
fs.access(p, fs.constants.R_OK | fs.constants.W_OK, function (err) {
assert(err == null)
done()
})
})
})
describe('fs.accessSync', function () {
it('accesses a normal file', function () {
var p = path.join(fixtures, 'asar', 'a.asar', 'file1')
assert.doesNotThrow(function () {
fs.accessSync(p)
})
})
it('throws an error when called with write mode', function () {
var p = path.join(fixtures, 'asar', 'a.asar', 'file1')
assert.throws(function () {
fs.accessSync(p, fs.constants.R_OK | fs.constants.W_OK)
}, /EACCES/)
})
it('throws an error when called on non-existent file', function () {
var p = path.join(fixtures, 'asar', 'a.asar', 'not-exist')
assert.throws(function () {
fs.accessSync(p)
}, /ENOENT/)
})
it('allows write mode for unpacked files', function () {
var p = path.join(fixtures, 'asar', 'unpack.asar', 'a.txt')
assert.doesNotThrow(function () {
fs.accessSync(p, fs.constants.R_OK | fs.constants.W_OK)
})
})
})
describe('child_process.fork', function () {
it('opens a normal js file', function (done) {
var child = ChildProcess.fork(path.join(fixtures, 'asar', 'a.asar', 'ping.js'))

View File

@@ -5,3 +5,11 @@ exports.print = function (obj) {
exports.echo = function (obj) {
return obj
}
exports.typedArray = function (name) {
const int16 = new Int16Array(name.length)
for (let i = 0; i < name.length; ++i) {
int16[i] = name[i]
}
return int16
}