Merge pull request #3 from atom/master

update as upstream
This commit is contained in:
Heilig Benedek 2016-02-09 00:52:19 +01:00
commit d5bdb17144
79 changed files with 1547 additions and 268 deletions

View file

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

View file

@ -367,6 +367,10 @@ mate::ObjectTemplateBuilder App::GetObjectTemplateBuilder(
base::Bind(&Browser::ClearRecentDocuments, browser))
.SetMethod("setAppUserModelId",
base::Bind(&Browser::SetAppUserModelID, browser))
#if defined(OS_MACOSX)
.SetMethod("hide", base::Bind(&Browser::Hide, browser))
.SetMethod("show", base::Bind(&Browser::Show, browser))
#endif
#if defined(OS_WIN)
.SetMethod("setUserTasks",
base::Bind(&Browser::SetUserTasks, browser))

View file

@ -12,6 +12,7 @@
#include "atom/common/native_mate_converters/gurl_converter.h"
#include "atom/common/node_includes.h"
#include "base/memory/linked_ptr.h"
#include "base/message_loop/message_loop.h"
#include "base/strings/utf_string_conversions.h"
#include "native_mate/dictionary.h"
#include "net/base/filename_util.h"
@ -47,80 +48,49 @@ namespace atom {
namespace api {
namespace {
// The wrapDownloadItem funtion which is implemented in JavaScript
using WrapDownloadItemCallback = base::Callback<void(v8::Local<v8::Value>)>;
WrapDownloadItemCallback g_wrap_download_item;
char kDownloadItemSavePathKey[] = "DownloadItemSavePathKey";
std::map<uint32, linked_ptr<v8::Global<v8::Value>>> g_download_item_objects;
} // namespace
DownloadItem::SavePathData::SavePathData(const base::FilePath& path) :
path_(path) {
}
const base::FilePath& DownloadItem::SavePathData::path() {
return path_;
}
DownloadItem::DownloadItem(content::DownloadItem* download_item) :
download_item_(download_item) {
DownloadItem::DownloadItem(content::DownloadItem* download_item)
: download_item_(download_item) {
download_item_->AddObserver(this);
AttachAsUserData(download_item);
}
DownloadItem::~DownloadItem() {
if (download_item_)
OnDownloadDestroyed(download_item_);
if (download_item_) {
// Destroyed by either garbage collection or destroy().
download_item_->RemoveObserver(this);
download_item_->Remove();
}
// Remove from the global map.
auto iter = g_download_item_objects.find(weak_map_id());
if (iter != g_download_item_objects.end())
g_download_item_objects.erase(iter);
}
void DownloadItem::OnDownloadUpdated(content::DownloadItem* item) {
download_item_->IsDone() ? Emit("done", item->GetState()) : Emit("updated");
if (download_item_->IsDone()) {
Emit("done", item->GetState());
// Destroy the item once item is downloaded.
base::MessageLoop::current()->PostTask(FROM_HERE, GetDestroyClosure());
} else {
Emit("updated");
}
}
void DownloadItem::OnDownloadDestroyed(content::DownloadItem* download_item) {
download_item_->RemoveObserver(this);
auto iter = g_download_item_objects.find(download_item_->GetId());
if (iter != g_download_item_objects.end())
g_download_item_objects.erase(iter);
download_item_ = nullptr;
}
int64 DownloadItem::GetReceivedBytes() {
return download_item_->GetReceivedBytes();
}
int64 DownloadItem::GetTotalBytes() {
return download_item_->GetTotalBytes();
}
const GURL& DownloadItem::GetURL() {
return download_item_->GetURL();
}
std::string DownloadItem::GetMimeType() {
return download_item_->GetMimeType();
}
bool DownloadItem::HasUserGesture() {
return download_item_->HasUserGesture();
}
std::string DownloadItem::GetFilename() {
return base::UTF16ToUTF8(net::GenerateFileName(GetURL(),
GetContentDisposition(),
std::string(),
download_item_->GetSuggestedFilename(),
GetMimeType(),
std::string()).LossyDisplayName());
}
std::string DownloadItem::GetContentDisposition() {
return download_item_->GetContentDisposition();
}
void DownloadItem::SetSavePath(const base::FilePath& path) {
download_item_->SetUserData(UserDataKey(), new SavePathData(path));
// Destroy the native class immediately when downloadItem is destroyed.
delete this;
}
void DownloadItem::Pause() {
@ -133,6 +103,48 @@ void DownloadItem::Resume() {
void DownloadItem::Cancel() {
download_item_->Cancel(true);
download_item_->Remove();
}
int64 DownloadItem::GetReceivedBytes() const {
return download_item_->GetReceivedBytes();
}
int64 DownloadItem::GetTotalBytes() const {
return download_item_->GetTotalBytes();
}
std::string DownloadItem::GetMimeType() const {
return download_item_->GetMimeType();
}
bool DownloadItem::HasUserGesture() const {
return download_item_->HasUserGesture();
}
std::string DownloadItem::GetFilename() const {
return base::UTF16ToUTF8(net::GenerateFileName(GetURL(),
GetContentDisposition(),
std::string(),
download_item_->GetSuggestedFilename(),
GetMimeType(),
std::string()).LossyDisplayName());
}
std::string DownloadItem::GetContentDisposition() const {
return download_item_->GetContentDisposition();
}
const GURL& DownloadItem::GetURL() const {
return download_item_->GetURL();
}
void DownloadItem::SetSavePath(const base::FilePath& path) {
save_path_ = path;
}
base::FilePath DownloadItem::GetSavePath() const {
return save_path_;
}
// static
@ -145,29 +157,31 @@ void DownloadItem::BuildPrototype(v8::Isolate* isolate,
.SetMethod("cancel", &DownloadItem::Cancel)
.SetMethod("getReceivedBytes", &DownloadItem::GetReceivedBytes)
.SetMethod("getTotalBytes", &DownloadItem::GetTotalBytes)
.SetMethod("getURL", &DownloadItem::GetURL)
.SetMethod("getMimeType", &DownloadItem::GetMimeType)
.SetMethod("hasUserGesture", &DownloadItem::HasUserGesture)
.SetMethod("getFilename", &DownloadItem::GetFilename)
.SetMethod("getContentDisposition", &DownloadItem::GetContentDisposition)
.SetMethod("setSavePath", &DownloadItem::SetSavePath);
.SetMethod("getURL", &DownloadItem::GetURL)
.SetMethod("setSavePath", &DownloadItem::SetSavePath)
.SetMethod("getSavePath", &DownloadItem::GetSavePath);
}
// static
mate::Handle<DownloadItem> DownloadItem::Create(
v8::Isolate* isolate, content::DownloadItem* item) {
auto existing = TrackableObject::FromWrappedClass(isolate, item);
if (existing)
return mate::CreateHandle(isolate, static_cast<DownloadItem*>(existing));
auto handle = mate::CreateHandle(isolate, new DownloadItem(item));
g_wrap_download_item.Run(handle.ToV8());
g_download_item_objects[item->GetId()] = make_linked_ptr(
// Reference this object in case it got garbage collected.
g_download_item_objects[handle->weak_map_id()] = make_linked_ptr(
new v8::Global<v8::Value>(isolate, handle.ToV8()));
return handle;
}
// static
void* DownloadItem::UserDataKey() {
return &kDownloadItemSavePathKey;
}
void ClearWrapDownloadItem() {
g_wrap_download_item.Reset();
}

View file

@ -20,22 +20,26 @@ namespace api {
class DownloadItem : public mate::TrackableObject<DownloadItem>,
public content::DownloadItem::Observer {
public:
class SavePathData : public base::SupportsUserData::Data {
public:
explicit SavePathData(const base::FilePath& path);
const base::FilePath& path();
private:
base::FilePath path_;
};
static mate::Handle<DownloadItem> Create(v8::Isolate* isolate,
content::DownloadItem* item);
static void* UserDataKey();
// mate::TrackableObject:
static void BuildPrototype(v8::Isolate* isolate,
v8::Local<v8::ObjectTemplate> prototype);
void Pause();
void Resume();
void Cancel();
int64 GetReceivedBytes() const;
int64 GetTotalBytes() const;
std::string GetMimeType() const;
bool HasUserGesture() const;
std::string GetFilename() const;
std::string GetContentDisposition() const;
const GURL& GetURL() const;
void SetSavePath(const base::FilePath& path);
base::FilePath GetSavePath() const;
protected:
explicit DownloadItem(content::DownloadItem* download_item);
~DownloadItem();
@ -44,19 +48,8 @@ class DownloadItem : public mate::TrackableObject<DownloadItem>,
void OnDownloadUpdated(content::DownloadItem* download) override;
void OnDownloadDestroyed(content::DownloadItem* download) override;
void Pause();
void Resume();
void Cancel();
int64 GetReceivedBytes();
int64 GetTotalBytes();
std::string GetMimeType();
bool HasUserGesture();
std::string GetFilename();
std::string GetContentDisposition();
const GURL& GetURL();
void SetSavePath(const base::FilePath& path);
private:
base::FilePath save_path_;
content::DownloadItem* download_item_;
DISALLOW_COPY_AND_ASSIGN(DownloadItem);

View file

@ -14,8 +14,10 @@
#include "atom/browser/api/save_page_handler.h"
#include "atom/browser/atom_browser_context.h"
#include "atom/browser/atom_browser_main_parts.h"
#include "atom/browser/atom_permission_manager.h"
#include "atom/browser/net/atom_cert_verifier.h"
#include "atom/common/native_mate_converters/callback.h"
#include "atom/common/native_mate_converters/content_converter.h"
#include "atom/common/native_mate_converters/gurl_converter.h"
#include "atom/common/native_mate_converters/file_path_converter.h"
#include "atom/common/native_mate_converters/net_converter.h"
@ -34,6 +36,7 @@
#include "native_mate/object_template_builder.h"
#include "net/base/load_flags.h"
#include "net/disk_cache/disk_cache.h"
#include "net/dns/host_cache.h"
#include "net/proxy/proxy_service.h"
#include "net/proxy/proxy_config_service_fixed.h"
#include "net/url_request/url_request_context.h"
@ -269,6 +272,19 @@ void SetProxyInIO(net::URLRequestContextGetter* getter,
RunCallbackInUI(callback);
}
void ClearHostResolverCacheInIO(
const scoped_refptr<net::URLRequestContextGetter>& context_getter,
const base::Closure& callback) {
auto request_context = context_getter->GetURLRequestContext();
auto cache = request_context->host_resolver()->GetHostCache();
if (cache) {
cache->clear();
DCHECK_EQ(0u, cache->size());
if (!callback.is_null())
RunCallbackInUI(callback);
}
}
} // namespace
Session::Session(AtomBrowserContext* browser_context)
@ -397,6 +413,28 @@ void Session::SetCertVerifyProc(v8::Local<v8::Value> val,
browser_context_->cert_verifier()->SetVerifyProc(proc);
}
void Session::SetPermissionRequestHandler(v8::Local<v8::Value> val,
mate::Arguments* args) {
AtomPermissionManager::RequestHandler handler;
if (!(val->IsNull() || mate::ConvertFromV8(args->isolate(), val, &handler))) {
args->ThrowError("Must pass null or function");
return;
}
auto permission_manager = static_cast<AtomPermissionManager*>(
browser_context()->GetPermissionManager());
permission_manager->SetPermissionRequestHandler(handler);
}
void Session::ClearHostResolverCache(mate::Arguments* args) {
base::Closure callback;
args->GetNext(&callback);
BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
base::Bind(&ClearHostResolverCacheInIO,
make_scoped_refptr(browser_context_->GetRequestContext()),
callback));
}
v8::Local<v8::Value> Session::Cookies(v8::Isolate* isolate) {
if (cookies_.IsEmpty()) {
auto handle = atom::api::Cookies::Create(isolate, browser_context());
@ -448,6 +486,9 @@ void Session::BuildPrototype(v8::Isolate* isolate,
.SetMethod("enableNetworkEmulation", &Session::EnableNetworkEmulation)
.SetMethod("disableNetworkEmulation", &Session::DisableNetworkEmulation)
.SetMethod("setCertificateVerifyProc", &Session::SetCertVerifyProc)
.SetMethod("setPermissionRequestHandler",
&Session::SetPermissionRequestHandler)
.SetMethod("clearHostResolverCache", &Session::ClearHostResolverCache)
.SetProperty("cookies", &Session::Cookies)
.SetProperty("webRequest", &Session::WebRequest);
}

View file

@ -76,6 +76,9 @@ class Session: public mate::TrackableObject<Session>,
void EnableNetworkEmulation(const mate::Dictionary& options);
void DisableNetworkEmulation();
void SetCertVerifyProc(v8::Local<v8::Value> proc, mate::Arguments* args);
void SetPermissionRequestHandler(v8::Local<v8::Value> val,
mate::Arguments* args);
void ClearHostResolverCache(mate::Arguments* args);
v8::Local<v8::Value> Cookies(v8::Isolate* isolate);
v8::Local<v8::Value> WebRequest(v8::Isolate* isolate);

View file

@ -14,6 +14,7 @@
#include "atom/browser/atom_browser_context.h"
#include "atom/browser/atom_browser_main_parts.h"
#include "atom/browser/native_window.h"
#include "atom/browser/web_contents_permission_helper.h"
#include "atom/browser/web_contents_preferences.h"
#include "atom/browser/web_view_guest_delegate.h"
#include "atom/common/api/api_messages.h"
@ -263,6 +264,9 @@ WebContents::WebContents(v8::Isolate* isolate,
// Save the preferences in C++.
new WebContentsPreferences(web_contents, options);
// Intialize permission helper.
WebContentsPermissionHelper::CreateForWebContents(web_contents);
web_contents->SetUserAgentOverride(GetBrowserContext()->GetUserAgent());
if (is_guest) {
@ -387,6 +391,18 @@ void WebContents::HandleKeyboardEvent(
void WebContents::EnterFullscreenModeForTab(content::WebContents* source,
const GURL& origin) {
auto permission_helper =
WebContentsPermissionHelper::FromWebContents(source);
auto callback = base::Bind(&WebContents::OnEnterFullscreenModeForTab,
base::Unretained(this), source, origin);
permission_helper->RequestFullscreenPermission(callback);
}
void WebContents::OnEnterFullscreenModeForTab(content::WebContents* source,
const GURL& origin,
bool allowed) {
if (!allowed)
return;
CommonWebContentsDelegate::EnterFullscreenModeForTab(source, origin);
Emit("enter-html-full-screen");
}
@ -445,6 +461,24 @@ void WebContents::FindReply(content::WebContents* web_contents,
}
}
void WebContents::RequestMediaAccessPermission(
content::WebContents* web_contents,
const content::MediaStreamRequest& request,
const content::MediaResponseCallback& callback) {
auto permission_helper =
WebContentsPermissionHelper::FromWebContents(web_contents);
permission_helper->RequestMediaAccessPermission(request, callback);
}
void WebContents::RequestToLockMouse(
content::WebContents* web_contents,
bool user_gesture,
bool last_unlocked_by_target) {
auto permission_helper =
WebContentsPermissionHelper::FromWebContents(web_contents);
permission_helper->RequestPointerLockPermission(user_gesture);
}
void WebContents::BeforeUnloadFired(const base::TimeTicks& proceed_time) {
// Do nothing, we override this method just to avoid compilation error since
// there are two virtual functions named BeforeUnloadFired.

View file

@ -134,6 +134,11 @@ class WebContents : public mate::TrackableObject<WebContents>,
void SetAllowTransparency(bool allow);
bool IsGuest() const;
// Callback triggered on permission response.
void OnEnterFullscreenModeForTab(content::WebContents* source,
const GURL& origin,
bool allowed);
// Returns the web preferences of current WebContents.
v8::Local<v8::Value> GetWebPreferences(v8::Isolate* isolate);
@ -196,6 +201,14 @@ class WebContents : public mate::TrackableObject<WebContents>,
const gfx::Rect& selection_rect,
int active_match_ordinal,
bool final_update) override;
void RequestMediaAccessPermission(
content::WebContents* web_contents,
const content::MediaStreamRequest& request,
const content::MediaResponseCallback& callback) override;
void RequestToLockMouse(
content::WebContents* web_contents,
bool user_gesture,
bool last_unlocked_by_target) override;
// content::WebContentsObserver:
void BeforeUnloadFired(const base::TimeTicks& proceed_time) override;

View file

@ -55,14 +55,16 @@ BrowserWindow.prototype._init = function() {
})(this));
// Change window title to page title.
this.webContents.on('page-title-updated', (function(_this) {
return function(event, title) {
_this.emit('page-title-updated', event, title);
if (!event.defaultPrevented) {
return _this.setTitle(title);
}
};
})(this));
this.webContents.on('page-title-updated', (event, title) => {
// The page-title-updated event is not emitted immediately (see #3645), so
// when the callback is called the BrowserWindow might have been closed.
if (this.isDestroyed())
return;
// Route the event to BrowserWindow.
this.emit('page-title-updated', event, title);
if (!event.defaultPrevented)
this.setTitle(title);
});
// Sometimes the webContents doesn't get focus when window is shown, so we have
// to force focusing on webContents in this case. The safest way is to focus it

View file

@ -15,6 +15,7 @@
#include "atom/browser/atom_resource_dispatcher_host_delegate.h"
#include "atom/browser/atom_speech_recognition_manager_delegate.h"
#include "atom/browser/native_window.h"
#include "atom/browser/web_contents_permission_helper.h"
#include "atom/browser/web_contents_preferences.h"
#include "atom/browser/window_list.h"
#include "atom/common/options_switches.h"
@ -281,6 +282,24 @@ brightray::BrowserMainParts* AtomBrowserClient::OverrideCreateBrowserMainParts(
return new AtomBrowserMainParts;
}
void AtomBrowserClient::WebNotificationAllowed(
int render_process_id,
const base::Callback<void(bool)>& callback) {
content::WebContents* web_contents = content::WebContents::FromRenderViewHost(
content::RenderViewHost::FromID(render_process_id, kDefaultRoutingID));
if (!web_contents) {
callback.Run(false);
return;
}
auto permission_helper =
WebContentsPermissionHelper::FromWebContents(web_contents);
if (!permission_helper) {
callback.Run(false);
return;
}
permission_helper->RequestWebNotificationPermission(callback);
}
void AtomBrowserClient::RenderProcessHostDestroyed(
content::RenderProcessHost* host) {
int process_id = host->GetID();

View file

@ -81,6 +81,9 @@ class AtomBrowserClient : public brightray::BrowserClient,
// brightray::BrowserClient:
brightray::BrowserMainParts* OverrideCreateBrowserMainParts(
const content::MainFunctionParams&) override;
void WebNotificationAllowed(
int render_process_id,
const base::Callback<void(bool)>& callback) override;
// content::RenderProcessHostObserver:
void RenderProcessHostDestroyed(content::RenderProcessHost* host) override;

View file

@ -13,6 +13,7 @@
#include "atom/browser/net/atom_url_request_job_factory.h"
#include "atom/browser/net/asar/asar_protocol_handler.h"
#include "atom/browser/net/http_protocol_handler.h"
#include "atom/browser/atom_permission_manager.h"
#include "atom/browser/web_view_manager.h"
#include "atom/common/atom_version.h"
#include "atom/common/chrome_version.h"
@ -169,6 +170,12 @@ content::BrowserPluginGuestManager* AtomBrowserContext::GetGuestManager() {
return guest_manager_.get();
}
content::PermissionManager* AtomBrowserContext::GetPermissionManager() {
if (!permission_manager_.get())
permission_manager_.reset(new AtomPermissionManager);
return permission_manager_.get();
}
scoped_ptr<net::CertVerifier> AtomBrowserContext::CreateCertVerifier() {
DCHECK(!cert_verifier_);
cert_verifier_ = new AtomCertVerifier;

View file

@ -14,6 +14,7 @@ namespace atom {
class AtomDownloadManagerDelegate;
class AtomCertVerifier;
class AtomNetworkDelegate;
class AtomPermissionManager;
class AtomURLRequestJobFactory;
class WebViewManager;
@ -37,6 +38,7 @@ class AtomBrowserContext : public brightray::BrowserContext {
// content::BrowserContext:
content::DownloadManagerDelegate* GetDownloadManagerDelegate() override;
content::BrowserPluginGuestManager* GetGuestManager() override;
content::PermissionManager* GetPermissionManager() override;
// brightray::BrowserContext:
void RegisterPrefs(PrefRegistrySimple* pref_registry) override;
@ -52,6 +54,7 @@ class AtomBrowserContext : public brightray::BrowserContext {
private:
scoped_ptr<AtomDownloadManagerDelegate> download_manager_delegate_;
scoped_ptr<WebViewManager> guest_manager_;
scoped_ptr<AtomPermissionManager> permission_manager_;
// Managed by brightray::BrowserContext.
AtomCertVerifier* cert_verifier_;

View file

@ -109,16 +109,24 @@ bool AtomDownloadManagerDelegate::DetermineDownloadTarget(
download->GetForcedFilePath());
return true;
}
base::SupportsUserData::Data* save_path = download->GetUserData(
atom::api::DownloadItem::UserDataKey());
if (save_path) {
const base::FilePath& default_download_path =
static_cast<api::DownloadItem::SavePathData*>(save_path)->path();
callback.Run(default_download_path,
content::DownloadItem::TARGET_DISPOSITION_OVERWRITE,
content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS,
default_download_path);
return true;
// Try to get the save path from JS wrapper.
{
v8::Isolate* isolate = v8::Isolate::GetCurrent();
v8::Locker locker(isolate);
v8::HandleScope handle_scope(isolate);
api::DownloadItem* download_item = api::DownloadItem::FromWrappedClass(
isolate, download);
if (download_item) {
base::FilePath save_path = download_item->GetSavePath();
if (!save_path.empty()) {
callback.Run(save_path,
content::DownloadItem::TARGET_DISPOSITION_OVERWRITE,
content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS,
save_path);
return true;
}
}
}
AtomBrowserContext* browser_context = static_cast<AtomBrowserContext*>(

View file

@ -0,0 +1,136 @@
// Copyright (c) 2016 GitHub, Inc.
// Use of this source code is governed by the MIT license that can be
// found in the LICENSE file.
#include "atom/browser/atom_permission_manager.h"
#include "content/public/browser/child_process_security_policy.h"
#include "content/public/browser/permission_type.h"
#include "content/public/browser/render_frame_host.h"
#include "content/public/browser/render_process_host.h"
#include "content/public/browser/render_view_host.h"
#include "content/public/browser/web_contents.h"
namespace atom {
namespace {
// Must be kept in sync with atom_browser_client.cc
int kDefaultRoutingID = 2;
bool WebContentsDestroyed(int process_id) {
auto rvh = content::RenderViewHost::FromID(process_id, kDefaultRoutingID);
if (rvh) {
auto contents = content::WebContents::FromRenderViewHost(rvh);
return contents->IsBeingDestroyed();
}
return true;
}
} // namespace
AtomPermissionManager::AtomPermissionManager()
: request_id_(0) {
}
AtomPermissionManager::~AtomPermissionManager() {
}
void AtomPermissionManager::SetPermissionRequestHandler(
const RequestHandler& handler) {
if (handler.is_null() && !pending_requests_.empty()) {
for (const auto& request : pending_requests_) {
if (!WebContentsDestroyed(request.second.render_process_id))
request.second.callback.Run(content::PERMISSION_STATUS_DENIED);
}
pending_requests_.clear();
}
request_handler_ = handler;
}
int AtomPermissionManager::RequestPermission(
content::PermissionType permission,
content::RenderFrameHost* render_frame_host,
const GURL& requesting_origin,
bool user_gesture,
const ResponseCallback& response_callback) {
int process_id = render_frame_host->GetProcess()->GetID();
if (permission == content::PermissionType::MIDI_SYSEX) {
content::ChildProcessSecurityPolicy::GetInstance()->
GrantSendMidiSysExMessage(process_id);
}
if (!request_handler_.is_null()) {
auto web_contents =
content::WebContents::FromRenderFrameHost(render_frame_host);
++request_id_;
auto callback = base::Bind(&AtomPermissionManager::OnPermissionResponse,
base::Unretained(this),
request_id_,
requesting_origin,
response_callback);
pending_requests_[request_id_] = { process_id, callback };
request_handler_.Run(web_contents, permission, callback);
return request_id_;
}
response_callback.Run(content::PERMISSION_STATUS_GRANTED);
return kNoPendingOperation;
}
void AtomPermissionManager::OnPermissionResponse(
int request_id,
const GURL& origin,
const ResponseCallback& callback,
content::PermissionStatus status) {
auto request = pending_requests_.find(request_id);
if (request != pending_requests_.end()) {
if (!WebContentsDestroyed(request->second.render_process_id))
callback.Run(status);
pending_requests_.erase(request);
}
}
void AtomPermissionManager::CancelPermissionRequest(int request_id) {
auto request = pending_requests_.find(request_id);
if (request != pending_requests_.end()) {
if (!WebContentsDestroyed(request->second.render_process_id))
request->second.callback.Run(content::PERMISSION_STATUS_DENIED);
pending_requests_.erase(request);
}
}
void AtomPermissionManager::ResetPermission(
content::PermissionType permission,
const GURL& requesting_origin,
const GURL& embedding_origin) {
}
content::PermissionStatus AtomPermissionManager::GetPermissionStatus(
content::PermissionType permission,
const GURL& requesting_origin,
const GURL& embedding_origin) {
return content::PERMISSION_STATUS_GRANTED;
}
void AtomPermissionManager::RegisterPermissionUsage(
content::PermissionType permission,
const GURL& requesting_origin,
const GURL& embedding_origin) {
}
int AtomPermissionManager::SubscribePermissionStatusChange(
content::PermissionType permission,
const GURL& requesting_origin,
const GURL& embedding_origin,
const ResponseCallback& callback) {
return -1;
}
void AtomPermissionManager::UnsubscribePermissionStatusChange(
int subscription_id) {
}
} // namespace atom

View file

@ -0,0 +1,84 @@
// Copyright (c) 2016 GitHub, Inc.
// Use of this source code is governed by the MIT license that can be
// found in the LICENSE file.
#ifndef ATOM_BROWSER_ATOM_PERMISSION_MANAGER_H_
#define ATOM_BROWSER_ATOM_PERMISSION_MANAGER_H_
#include <map>
#include "base/callback.h"
#include "content/public/browser/permission_manager.h"
namespace content {
class WebContents;
}
namespace atom {
class AtomPermissionManager : public content::PermissionManager {
public:
AtomPermissionManager();
~AtomPermissionManager() override;
using ResponseCallback =
base::Callback<void(content::PermissionStatus)>;
using RequestHandler =
base::Callback<void(content::WebContents*,
content::PermissionType,
const ResponseCallback&)>;
// Handler to dispatch permission requests in JS.
void SetPermissionRequestHandler(const RequestHandler& handler);
// content::PermissionManager:
int RequestPermission(
content::PermissionType permission,
content::RenderFrameHost* render_frame_host,
const GURL& requesting_origin,
bool user_gesture,
const ResponseCallback& callback) override;
protected:
void OnPermissionResponse(int request_id,
const GURL& url,
const ResponseCallback& callback,
content::PermissionStatus status);
// content::PermissionManager:
void CancelPermissionRequest(int request_id) override;
void ResetPermission(content::PermissionType permission,
const GURL& requesting_origin,
const GURL& embedding_origin) override;
content::PermissionStatus GetPermissionStatus(
content::PermissionType permission,
const GURL& requesting_origin,
const GURL& embedding_origin) override;
void RegisterPermissionUsage(content::PermissionType permission,
const GURL& requesting_origin,
const GURL& embedding_origin) override;
int SubscribePermissionStatusChange(
content::PermissionType permission,
const GURL& requesting_origin,
const GURL& embedding_origin,
const base::Callback<void(content::PermissionStatus)>& callback) override;
void UnsubscribePermissionStatusChange(int subscription_id) override;
private:
struct RequestInfo {
int render_process_id;
ResponseCallback callback;
};
RequestHandler request_handler_;
std::map<int, RequestInfo> pending_requests_;
int request_id_;
DISALLOW_COPY_AND_ASSIGN(AtomPermissionManager);
};
} // namespace atom
#endif // ATOM_BROWSER_ATOM_PERMISSION_MANAGER_H_

View file

@ -77,6 +77,12 @@ class Browser : public WindowListObserver {
void SetAppUserModelID(const base::string16& name);
#if defined(OS_MACOSX)
// Hide the application.
void Hide();
// Show the application.
void Show();
// Bounce the dock icon.
enum BounceType {
BOUNCE_CRITICAL = 0,

View file

@ -18,6 +18,14 @@ void Browser::Focus() {
[[AtomApplication sharedApplication] activateIgnoringOtherApps:YES];
}
void Browser::Hide() {
[[AtomApplication sharedApplication] hide:nil];
}
void Browser::Show() {
[[AtomApplication sharedApplication] unhide:nil];
}
void Browser::AddRecentDocument(const base::FilePath& path) {
NSString* path_string = base::mac::FilePathToNSString(path);
if (!path_string)
@ -103,7 +111,7 @@ void Browser::DockSetMenu(ui::MenuModel* model) {
}
void Browser::DockSetIcon(const gfx::Image& image) {
[[NSApplication sharedApplication]
[[AtomApplication sharedApplication]
setApplicationIconImage:image.AsNSImage()];
}

View file

@ -181,13 +181,6 @@ content::WebContents* CommonWebContentsDelegate::OpenURLFromTab(
return source;
}
void CommonWebContentsDelegate::RequestToLockMouse(
content::WebContents* web_contents,
bool user_gesture,
bool last_unlocked_by_target) {
GetWebContents()->GotResponseToLockMouseRequest(true);
}
bool CommonWebContentsDelegate::CanOverscrollContent() const {
return false;
}

View file

@ -9,10 +9,10 @@
#include <string>
#include <vector>
#include "brightray/browser/default_web_contents_delegate.h"
#include "brightray/browser/inspectable_web_contents_impl.h"
#include "brightray/browser/inspectable_web_contents_delegate.h"
#include "brightray/browser/inspectable_web_contents_view_delegate.h"
#include "content/public/browser/web_contents_delegate.h"
namespace atom {
@ -21,7 +21,7 @@ class NativeWindow;
class WebDialogHelper;
class CommonWebContentsDelegate
: public brightray::DefaultWebContentsDelegate,
: public content::WebContentsDelegate,
public brightray::InspectableWebContentsDelegate,
public brightray::InspectableWebContentsViewDelegate {
public:
@ -59,9 +59,6 @@ class CommonWebContentsDelegate
content::WebContents* OpenURLFromTab(
content::WebContents* source,
const content::OpenURLParams& params) override;
void RequestToLockMouse(content::WebContents* web_contents,
bool user_gesture,
bool last_unlocked_by_target) override;
bool CanOverscrollContent() const override;
content::JavaScriptDialogManager* GetJavaScriptDialogManager(
content::WebContents* source) override;

View file

@ -6,7 +6,38 @@ var slice = [].slice;
// Doesn't exist in early initialization.
var webViewManager = null;
var supportedWebViewEvents = ['load-commit', 'did-finish-load', 'did-fail-load', 'did-frame-finish-load', 'did-start-loading', 'did-stop-loading', 'did-get-response-details', 'did-get-redirect-request', 'dom-ready', 'console-message', 'devtools-opened', 'devtools-closed', 'devtools-focused', 'new-window', 'will-navigate', 'did-navigate', 'did-navigate-in-page', 'close', 'crashed', 'gpu-crashed', 'plugin-crashed', 'destroyed', 'page-title-updated', 'page-favicon-updated', 'enter-html-full-screen', 'leave-html-full-screen', 'media-started-playing', 'media-paused', 'found-in-page', 'did-change-theme-color'];
var supportedWebViewEvents = [
'load-commit',
'did-finish-load',
'did-fail-load',
'did-frame-finish-load',
'did-start-loading',
'did-stop-loading',
'did-get-response-details',
'did-get-redirect-request',
'dom-ready',
'console-message',
'devtools-opened',
'devtools-closed',
'devtools-focused',
'new-window',
'will-navigate',
'did-navigate',
'did-navigate-in-page',
'close',
'crashed',
'gpu-crashed',
'plugin-crashed',
'destroyed',
'page-title-updated',
'page-favicon-updated',
'enter-html-full-screen',
'leave-html-full-screen',
'media-started-playing',
'media-paused',
'found-in-page',
'did-change-theme-color'
];
var nextInstanceId = 0;
var guestInstances = {};

View file

@ -162,12 +162,12 @@ var unwrapArgs = function(sender, args) {
});
let callIntoRenderer = function(...args) {
if (rendererReleased)
if (rendererReleased || sender.isDestroyed())
throw new Error(`Attempting to call a function in a renderer window that has been closed or released. Function provided here: ${meta.location}.`);
sender.send('ATOM_RENDERER_CALLBACK', meta.id, valueToMeta(sender, args));
};
v8Util.setDestructor(callIntoRenderer, function() {
if (!rendererReleased)
if (!rendererReleased && !sender.isDestroyed())
sender.send('ATOM_RENDERER_RELEASE_CALLBACK', meta.id);
});
sender.callbacks.set(meta.id, callIntoRenderer);

View file

@ -17,13 +17,13 @@
<key>CFBundleIconFile</key>
<string>atom.icns</string>
<key>CFBundleVersion</key>
<string>0.36.6</string>
<string>0.36.7</string>
<key>CFBundleShortVersionString</key>
<string>0.36.6</string>
<string>0.36.7</string>
<key>LSApplicationCategoryType</key>
<string>public.app-category.developer-tools</string>
<key>LSMinimumSystemVersion</key>
<string>10.8.0</string>
<string>10.9.0</string>
<key>NSMainNibFile</key>
<string>MainMenu</string>
<key>NSPrincipalClass</key>

View file

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

View file

@ -0,0 +1,94 @@
// Copyright (c) 2016 GitHub, Inc.
// Use of this source code is governed by the MIT license that can be
// found in the LICENSE file.
#include "atom/browser/web_contents_permission_helper.h"
#include <string>
#include "atom/browser/atom_permission_manager.h"
#include "brightray/browser/media/media_stream_devices_controller.h"
#include "content/public/browser/browser_context.h"
#include "content/public/browser/render_process_host.h"
DEFINE_WEB_CONTENTS_USER_DATA_KEY(atom::WebContentsPermissionHelper);
namespace atom {
namespace {
void MediaAccessAllowed(
const content::MediaStreamRequest& request,
const content::MediaResponseCallback& callback,
bool allowed) {
brightray::MediaStreamDevicesController controller(request, callback);
if (allowed)
controller.Accept();
else
controller.Deny(content::MEDIA_DEVICE_PERMISSION_DENIED);
}
void OnPointerLockResponse(content::WebContents* web_contents, bool allowed) {
if (web_contents)
web_contents->GotResponseToLockMouseRequest(allowed);
}
void OnPermissionResponse(const base::Callback<void(bool)>& callback,
content::PermissionStatus status) {
if (status == content::PERMISSION_STATUS_GRANTED)
callback.Run(true);
else
callback.Run(false);
}
} // namespace
WebContentsPermissionHelper::WebContentsPermissionHelper(
content::WebContents* web_contents)
: web_contents_(web_contents) {
}
WebContentsPermissionHelper::~WebContentsPermissionHelper() {
}
void WebContentsPermissionHelper::RequestPermission(
content::PermissionType permission,
const base::Callback<void(bool)>& callback,
bool user_gesture) {
auto rfh = web_contents_->GetMainFrame();
auto permission_manager = static_cast<AtomPermissionManager*>(
web_contents_->GetBrowserContext()->GetPermissionManager());
auto origin = web_contents_->GetLastCommittedURL();
permission_manager->RequestPermission(
permission, rfh, origin, user_gesture,
base::Bind(&OnPermissionResponse, callback));
}
void WebContentsPermissionHelper::RequestFullscreenPermission(
const base::Callback<void(bool)>& callback) {
RequestPermission((content::PermissionType)(PermissionType::FULLSCREEN),
callback);
}
void WebContentsPermissionHelper::RequestMediaAccessPermission(
const content::MediaStreamRequest& request,
const content::MediaResponseCallback& response_callback) {
auto callback = base::Bind(&MediaAccessAllowed, request, response_callback);
// The permission type doesn't matter here, AUDIO_CAPTURE/VIDEO_CAPTURE
// are presented as same type in content_converter.h.
RequestPermission(content::PermissionType::AUDIO_CAPTURE, callback);
}
void WebContentsPermissionHelper::RequestWebNotificationPermission(
const base::Callback<void(bool)>& callback) {
RequestPermission(content::PermissionType::NOTIFICATIONS, callback);
}
void WebContentsPermissionHelper::RequestPointerLockPermission(
bool user_gesture) {
RequestPermission((content::PermissionType)(PermissionType::POINTER_LOCK),
base::Bind(&OnPointerLockResponse, web_contents_),
user_gesture);
}
} // namespace atom

View file

@ -0,0 +1,50 @@
// Copyright (c) 2016 GitHub, Inc.
// Use of this source code is governed by the MIT license that can be
// found in the LICENSE file.
#ifndef ATOM_BROWSER_WEB_CONTENTS_PERMISSION_HELPER_H_
#define ATOM_BROWSER_WEB_CONTENTS_PERMISSION_HELPER_H_
#include "content/public/browser/permission_type.h"
#include "content/public/browser/web_contents_user_data.h"
#include "content/public/common/media_stream_request.h"
namespace atom {
// Applies the permission requested for WebContents.
class WebContentsPermissionHelper
: public content::WebContentsUserData<WebContentsPermissionHelper> {
public:
~WebContentsPermissionHelper() override;
enum class PermissionType {
POINTER_LOCK = static_cast<int>(content::PermissionType::NUM) + 1,
FULLSCREEN
};
void RequestFullscreenPermission(
const base::Callback<void(bool)>& callback);
void RequestMediaAccessPermission(
const content::MediaStreamRequest& request,
const content::MediaResponseCallback& callback);
void RequestWebNotificationPermission(
const base::Callback<void(bool)>& callback);
void RequestPointerLockPermission(bool user_gesture);
private:
explicit WebContentsPermissionHelper(content::WebContents* web_contents);
friend class content::WebContentsUserData<WebContentsPermissionHelper>;
void RequestPermission(
content::PermissionType permission,
const base::Callback<void(bool)>& callback,
bool user_gesture = false);
content::WebContents* web_contents_;
DISALLOW_COPY_AND_ASSIGN(WebContentsPermissionHelper);
};
} // namespace atom
#endif // ATOM_BROWSER_WEB_CONTENTS_PERMISSION_HELPER_H_

View file

@ -130,14 +130,20 @@ Archive::Archive(const base::FilePath& path)
Archive::~Archive() {
#if defined(OS_WIN)
if (fd_ != -1)
if (fd_ != -1) {
_close(fd_);
// Don't close the handle since we already closed the fd.
file_.TakePlatformFile();
}
#endif
}
bool Archive::Init() {
if (!file_.IsValid()) {
LOG(ERROR) << base::File::ErrorToString(file_.error_details());
if (file_.error_details() != base::File::FILE_ERROR_NOT_FOUND) {
LOG(WARNING) << "Opening " << path_.value()
<< ": " << base::File::ErrorToString(file_.error_details());
}
return false;
}

View file

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

View file

@ -7,6 +7,8 @@
#include <string>
#include <vector>
#include "atom/browser/api/atom_api_web_contents.h"
#include "atom/browser/web_contents_permission_helper.h"
#include "atom/common/native_mate_converters/callback.h"
#include "atom/common/native_mate_converters/string16_converter.h"
#include "content/public/browser/web_contents.h"
@ -98,6 +100,55 @@ v8::Local<v8::Value> Converter<ContextMenuParamsWithWebContents>::ToV8(
return mate::ConvertToV8(isolate, dict);
}
// static
bool Converter<content::PermissionStatus>::FromV8(
v8::Isolate* isolate,
v8::Local<v8::Value> val,
content::PermissionStatus* out) {
bool result;
if (!ConvertFromV8(isolate, val, &result))
return false;
if (result)
*out = content::PERMISSION_STATUS_GRANTED;
else
*out = content::PERMISSION_STATUS_DENIED;
return true;
}
// static
v8::Local<v8::Value> Converter<content::PermissionType>::ToV8(
v8::Isolate* isolate, const content::PermissionType& val) {
using PermissionType = atom::WebContentsPermissionHelper::PermissionType;
switch (val) {
case content::PermissionType::MIDI_SYSEX:
return StringToV8(isolate, "midiSysex");
case content::PermissionType::PUSH_MESSAGING:
return StringToV8(isolate, "pushMessaging");
case content::PermissionType::NOTIFICATIONS:
return StringToV8(isolate, "notifications");
case content::PermissionType::GEOLOCATION:
return StringToV8(isolate, "geolocation");
case content::PermissionType::AUDIO_CAPTURE:
case content::PermissionType::VIDEO_CAPTURE:
return StringToV8(isolate, "media");
case content::PermissionType::PROTECTED_MEDIA_IDENTIFIER:
return StringToV8(isolate, "mediaKeySystem");
case content::PermissionType::MIDI:
return StringToV8(isolate, "midi");
default:
break;
}
if (val == (content::PermissionType)(PermissionType::POINTER_LOCK))
return StringToV8(isolate, "pointerLock");
else if (val == (content::PermissionType)(PermissionType::FULLSCREEN))
return StringToV8(isolate, "fullscreen");
return StringToV8(isolate, "unknown");
}
// static
bool Converter<content::StopFindAction>::FromV8(
v8::Isolate* isolate,
@ -119,4 +170,10 @@ bool Converter<content::StopFindAction>::FromV8(
return true;
}
// static
v8::Local<v8::Value> Converter<content::WebContents*>::ToV8(
v8::Isolate* isolate, content::WebContents* val) {
return atom::api::WebContents::CreateFrom(isolate, val).ToV8();
}
} // namespace mate

View file

@ -7,7 +7,9 @@
#include <utility>
#include "content/public/browser/permission_type.h"
#include "content/public/common/menu_item.h"
#include "content/public/common/permission_status.mojom.h"
#include "content/public/common/stop_find_action.h"
#include "native_mate/converter.h"
@ -33,12 +35,30 @@ struct Converter<ContextMenuParamsWithWebContents> {
const ContextMenuParamsWithWebContents& val);
};
template<>
struct Converter<content::PermissionStatus> {
static bool FromV8(v8::Isolate* isolate, v8::Local<v8::Value> val,
content::PermissionStatus* out);
};
template<>
struct Converter<content::PermissionType> {
static v8::Local<v8::Value> ToV8(v8::Isolate* isolate,
const content::PermissionType& val);
};
template<>
struct Converter<content::StopFindAction> {
static bool FromV8(v8::Isolate* isolate, v8::Local<v8::Value> val,
content::StopFindAction* out);
};
template<>
struct Converter<content::WebContents*> {
static v8::Local<v8::Value> ToV8(v8::Isolate* isolate,
content::WebContents* val);
};
} // namespace mate
#endif // ATOM_COMMON_NATIVE_MATE_CONVERTERS_CONTENT_CONVERTER_H_

View file

@ -9,6 +9,7 @@
#include "atom/common/api/api_messages.h"
#include "atom/common/api/atom_bindings.h"
#include "atom/common/api/event_emitter_caller.h"
#include "atom/common/node_bindings.h"
#include "atom/common/node_includes.h"
#include "atom/common/options_switches.h"
@ -47,17 +48,27 @@ class AtomRenderFrameObserver : public content::RenderFrameObserver {
AtomRenderFrameObserver(content::RenderFrame* frame,
AtomRendererClient* renderer_client)
: content::RenderFrameObserver(frame),
world_id_(-1),
renderer_client_(renderer_client) {}
// content::RenderFrameObserver:
void DidCreateScriptContext(v8::Handle<v8::Context> context,
int extension_group,
int world_id) {
renderer_client_->DidCreateScriptContext(
render_frame()->GetWebFrame(), context);
int world_id) override {
if (world_id_ != -1 && world_id_ != world_id)
return;
world_id_ = world_id;
renderer_client_->DidCreateScriptContext(context);
}
void WillReleaseScriptContext(v8::Local<v8::Context> context,
int world_id) override {
if (world_id_ != world_id)
return;
renderer_client_->WillReleaseScriptContext(context);
}
private:
int world_id_;
AtomRendererClient* renderer_client_;
DISALLOW_COPY_AND_ASSIGN(AtomRenderFrameObserver);
@ -108,10 +119,15 @@ void AtomRendererClient::RenderThreadStarted() {
void AtomRendererClient::RenderFrameCreated(
content::RenderFrame* render_frame) {
new PepperHelper(render_frame);
new AtomRenderFrameObserver(render_frame, this);
// Allow file scheme to handle service worker by default.
blink::WebSecurityPolicy::registerURLSchemeAsAllowingServiceWorkers("file");
// Only insert node integration for the main frame.
if (!render_frame->IsMainFrame())
return;
new AtomRenderFrameObserver(render_frame, this);
}
void AtomRendererClient::RenderViewCreated(content::RenderView* render_view) {
@ -139,12 +155,7 @@ bool AtomRendererClient::OverrideCreatePlugin(
}
void AtomRendererClient::DidCreateScriptContext(
blink::WebFrame* frame,
v8::Handle<v8::Context> context) {
// Only insert node integration for the main frame.
if (frame->parent())
return;
// Give the node loop a run to make sure everything is ready.
node_bindings_->RunMessageLoop();
@ -162,6 +173,12 @@ void AtomRendererClient::DidCreateScriptContext(
node_bindings_->LoadEnvironment(env);
}
void AtomRendererClient::WillReleaseScriptContext(
v8::Handle<v8::Context> context) {
node::Environment* env = node::Environment::GetCurrent(context);
mate::EmitEvent(env->isolate(), env->process_object(), "exit");
}
bool AtomRendererClient::ShouldFork(blink::WebLocalFrame* frame,
const GURL& url,
const std::string& http_method,

View file

@ -22,8 +22,8 @@ class AtomRendererClient : public content::ContentRendererClient,
AtomRendererClient();
virtual ~AtomRendererClient();
void DidCreateScriptContext(blink::WebFrame* frame,
v8::Handle<v8::Context> context);
void DidCreateScriptContext(v8::Handle<v8::Context> context);
void WillReleaseScriptContext(v8::Handle<v8::Context> context);
private:
enum NodeIntegration {

View file

@ -1,4 +1,4 @@
'user strict';
'use strict';
const events = require('events');
const path = require('path');
@ -106,11 +106,6 @@ if (nodeIntegration === 'true' || nodeIntegration === 'all' || nodeIntegration =
return false;
}
};
// Emit the 'exit' event when page is unloading.
window.addEventListener('unload', function() {
return process.emit('exit');
});
} else {
// Delete Node's symbols after the Environment has been loaded.
process.once('loaded', function() {

View file

@ -1,4 +1,4 @@
'user strict';
'use strict';
const deprecate = require('electron').deprecate;
const webFrame = require('electron').webFrame;

View file

@ -61,8 +61,7 @@ de distribuirlo a los usuarios.
### Windows
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)
o [ResEdit](http://www.resedit.net).
y otra información con herramientas como [rcedit](https://github.com/atom/rcedit).
### OSX

View file

@ -431,6 +431,12 @@ dock アイコンを表示します。
アプリケーションの[dock menu][dock-menu]を設定します。
### `app.dock.setIcon(image)` _OS X_
* `image` [NativeImage](native-image.md)
dock アイコンに紐づいた`image`を設定します。
[dock-menu]:https://developer.apple.com/library/mac/documentation/Carbon/Conceptual/customizing_docktile/concepts/dockconcepts.html#//apple_ref/doc/uid/TP30000986-CH2-TPXREF103
[tasks]:http://msdn.microsoft.com/en-us/library/windows/desktop/dd378460(v=vs.85).aspx#tasks
[app-user-model-id]: https://msdn.microsoft.com/en-us/library/windows/desktop/dd378459(v=vs.85).aspx

View file

@ -24,6 +24,11 @@ Windows コンソール上:
Chromeのインターナルログをコンソールに出力します。
## `ELECTRON_LOG_ASAR_READS`
ASARファイルからElectronが読み込んだとき、システム`tmpdir`へ読み込みオフセットとファイルのパスを記録します。ファイルの順序を最適化するために、得られたファイルはASARモジュールに提供されます。
## `ELECTRON_ENABLE_STACK_DUMPING`
Electronがクラッシュしたとき、コンソールにスタックとレースを出力します。

View file

@ -45,9 +45,22 @@ app.on('ready', function() {
レスポンスとしてファイルを送信する`scheme`のプロトコルを登録します。`scheme`で`request`が生成された時、`handler`は`handler(request, callback)`で呼び出されます。`scheme` 登録が成功したり、`completion(error)`が失敗したときに、`completion` は`completion(null)`で呼び出されます。
* `request` Object
* `url` String
* `referrer` String
* `method` String
* `uploadData` Array (オプション)
* `callback` Function
`uploadData``data` オブジェクトの配列です:
* `data` Object
* `bytes` Buffer - 送信するコンテンツ
* `file` String - アップロードするファイルパス
`request`をハンドルするために、`callback`はファイルパスまたは`path`プロパティを持つオブジェクトで呼び出すべきです。例えば、`callback(filePath)` または`callback({path: filePath})`です。
何もなし、数字、`error`プロパティを持つオブジェクトで、`callback`が呼び出された時、 `request`は指定した`error`番号で失敗します。使用できる提供されているエラー番号は、[net error list](https://code.google.com/p/chromium/codesearch#chromium/src/net/base/net_error_list.h)を参照してください。
何もなし、数字、`error`プロパティを持つオブジェクトで、`callback`が呼び出された時、 `request`は指定した`error`番号で失敗します。使用できる提供されているエラー番号は、[net error list][net-error]を参照してください。
既定では、`scheme`は、`file:`のような一般的なURIの構文に続くプロトコルと違う解析がされ、`http:`のように扱われます。なので、恐らく標準的なスキーマーのように扱われるスキーマーを持つために、`protocol.registerStandardSchemes` を呼び出したくなります。
@ -57,7 +70,9 @@ app.on('ready', function() {
* `handler` Function
* `completion` Function (optional)
レスポンスとして`Buffer`を送信する`scheme`プロトコルを登録します。`callback`は、`Buffer`オブジェクトまたは`data`と `mimeType`、`chart`プロパティを持つオブジェクトを呼び出す必要があります。
レスポンスとして`Buffer`を送信する`scheme`プロトコルを登録します。
`callback`は、`Buffer`オブジェクトまたは、`data`と`mimeType`、 `charset`プロパティを持つオブジェクトのどちらかで呼ばれる必要があることを除いて、この使用方法は、`registerFileProtocol`と同じです。
例:
@ -76,7 +91,9 @@ protocol.registerBufferProtocol('atom', function(request, callback) {
* `handler` Function
* `completion` Function (optional)
レスポンスとして`String`を送信する`scheme`プロトコルを登録します。`callback`は、`String`または`data`と `mimeType`、`chart`プロパティを持つオブジェクトを呼び出す必要があります。
レスポンスとして`String`を送信する`scheme`プロトコルを登録します。
`callback`は、`String`または`data`と `mimeType`、`chart`プロパティを持つオブジェクトを呼び出す必要があることを除いて、使用方法は`registerFileProtocol`と同じです。
### `protocol.registerHttpProtocol(scheme, handler[, completion])`
@ -84,14 +101,22 @@ protocol.registerBufferProtocol('atom', function(request, callback) {
* `handler` Function
* `completion` Function (optional)
レスポンスとしてHTTPリクエストを送信する`scheme`プロトコルを登録します。`callback`は、`url`と`method`、`referrer`、`uploadData`、`session`プロパティを持つオブジェクトを呼び出す必要があります。
レスポンスとしてHTTPリクエストを送信する`scheme`プロトコルを登録します。
`callback`は、`url`と`method`、`referrer`、`uploadData`、`session`プロパティを持つオブジェクトを呼び出す必要があることを除いて、使用方法は`registerFileProtocol`と同じです。
* `redirectRequest` Object
* `url` String
* `method` String
* `session` Object (オプション)
* `uploadData` Object (オプション)
既定では、HTTPリクエストは現在のセッションを再利用します。別のセッションでリクエストをしたい場合、`session` に `null`を設定する必要があります。
POSTリクエストは`uploadData`オブジェクトを提供する必要があります。
* `uploadData` object
* `contentType` String - コンテンツのMIMEタイプ
* `data` String - 送信されるコンテンツ
* `data` String - 送信されるコンテンツ
### `protocol.unregisterProtocol(scheme[, completion])`
@ -139,12 +164,12 @@ POSTリクエストは`uploadData`オブジェクトを提供する必要があ
`scheme`プロトコルをインターセプタ―し、レスポンスとして新しいHTTPリクエストを送信するプロトコルの新しいハンドラーとして`handler`を使います。
Intercepts `scheme` protocol and uses `handler` as the protocol's new handler
which sends a new HTTP request as a response.
### `protocol.uninterceptProtocol(scheme[, completion])`
* `scheme` String
* `completion` Function
インターセプタ―したインストールされた`scheme`を削除し、オリジナルハンドラーをリストアします。
[net-error]: https://code.google.com/p/chromium/codesearch#chromium/src/net/base/net_error_list.h

View file

@ -197,6 +197,7 @@ proxyURL = [<proxyScheme>"://"]<proxyHost>[":"<proxyPort>]
```
具体例:
* `http=foopy:80;ftp=foopy2` - `http://`URLは`foopy:80`HTTPプロキシを使用し、`ftp://`URLは`foopy2:80` HTTPプロキシを使用します。
* `foopy:80` - 全てのURLで`foopy:80`を使用します。
* `foopy:80,bar,direct://` - 全てのURLで`foopy:80`HTTPプロキシを使用し、`foopy:80`が提供されていなければ`bar`を使用し、さらに使えない場合はプロキシを使いません。
@ -296,6 +297,14 @@ session.defaultSession.webRequest.onBeforeSendHeaders(filter, function(details,
* `method` String
* `resourceType` String
* `timestamp` Double
* `uploadData` Array (オプション)
* `callback` Function
`uploadData``data`オブジェクトの配列です。
* `data` Object
* `bytes` Buffer - 送信されるコンテンツ
* `file` String - アップロードされるファイルパス
`callback`は`response`オブジェクトでコールされる必要があります:
@ -317,6 +326,7 @@ session.defaultSession.webRequest.onBeforeSendHeaders(filter, function(details,
* `resourceType` String
* `timestamp` Double
* `requestHeaders` Object
* `callback` Function
The `callback` has to be called with an `response` object:
@ -355,6 +365,7 @@ The `callback` has to be called with an `response` object:
* `statusLine` String
* `statusCode` Integer
* `responseHeaders` Object
* `callback` Function
`callback`は`response`オブジェクトでコールされる必要があります:

View file

@ -4,7 +4,7 @@ Electron では全ての [Node.js のビルトインモジュール](http://node
Electron はネイティブのデスクトップアプリケーション開発のための幾つかの追加のビルトインモジュールも提供しています。メインプロセスでだけ使えるモジュールもあれば、レンダラプロセス(ウェブページ)でだけ使えるモジュール、あるいはメインプロセス、レンダラプロセスどちらでも使えるモジュールもあります。
基本的なルールは:[GUI][gui]、または低レベルのシステムに関連するモジュールはメインモジュールでだけ利用できるべきです。これらのモジュールを使用できるようにするためには [メインプロセス対レンダラプロセス][main-process] スクリプトの概念を理解する必要があります。
基本的なルールは:[GUI][gui]、または低レベルのシステムに関連するモジュールはメインモジュールでだけ利用できるべきです。これらのモジュールを使用できるようにするためには [メインプロセス対レンダラプロセス](../tutorial/quick-start.md#メインプロセス)スクリプトの概念を理解する必要があります。
メインプロセススクリプトは普通の Node.js スクリプトのようなものです:
@ -64,6 +64,5 @@ require('electron').hideInternalModules()
```
[gui]: https://en.wikipedia.org/wiki/Graphical_user_interface
[main-process]: ../tutorial/quick-start.md#メインプロセス
[desctructuring-assignment]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment
[issue-387]: https://github.com/atom/electron/issues/387

View file

@ -69,5 +69,38 @@ delete window.module;
</head>
```
## `require('electron').xxx` は定義されていません。
Electronの組み込みモジュールを使うとに、次のようなエラーに遭遇するかもしれません。
```
> require('electron').webFrame.setZoomFactor(1.0);
Uncaught TypeError: Cannot read property 'setZoomLevel' of undefined
```
これは、ローカルまたはグローバルのどちらかで [npm `electron` module][electron-module] をインストールしたことが原因で、Electronの組み込みモジュールを上書きしてしまいます。
正しい組み込みモジュールを使用しているかを確認するために、`electron`モジュールのパスを出力します。
```javascript
console.log(require.resolve('electron'));
```
そして、次の形式かどうかを確認します。
```
"/path/to/Electron.app/Contents/Resources/atom.asar/renderer/api/lib/exports/electron.js"
```
If it is something like もし、`node_modules/electron/index.js` のような形式の場合は、npm `electron` モジュールを削除するか、それをリネームします。
```bash
npm uninstall electron
npm uninstall -g electron
```
しかし、組み込みモジュールを使用しているのに、まだこのエラーが出る場合、不適切なプロセスでモジュールを使用しようとしている可能性が高いです。例えば、`electron.app`はメインプロセスのみで使え、一方で`electron.webFrame`はレンダラープロセスのみに提供されています。
[memory-management]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Memory_Management
[variable-scope]: https://msdn.microsoft.com/library/bzt2dkta(v=vs.94).aspx
[electron-module]: https://www.npmjs.com/package/electron

View file

@ -51,8 +51,8 @@ Electronにバンドルした後、ユーザーに配布する前に、 Electron
### Windows
`electron.exe`を任意の名前に変更でき、[rcedit](https://github.com/atom/rcedit) または
[ResEdit](http://www.resedit.net)のようなツールでアイコンやその他の情報を編集できます。
`electron.exe`を任意の名前に変更でき、[rcedit](https://github.com/atom/rcedit)
のようなツールでアイコンやその他の情報を編集できます。
### OS X

View file

@ -55,13 +55,13 @@ $ electron --debug=5858 your/app
$ electron --debug-brk=5858 your/app
```
### 5. Electronを使用して、[node-inspector][node-inspector] サーバーを開始する
### 6. Electronを使用して、[node-inspector][node-inspector] サーバーを開始する
```bash
$ ELECTRON_RUN_AS_NODE=true path/to/electron.exe node_modules/node-inspector/bin/inspector.js
```
### 6. デバッグUIを読み込みます
### 7. デバッグUIを読み込みます
Chromeブラウザで、 http://127.0.0.1:8080/debug?ws=127.0.0.1:8080&port=5858 を開きます。エントリーラインを見るために、debug-brkを始めるには、ポーズをクリックします。

View file

@ -25,16 +25,7 @@ myNotification.onclick = function () {
* Windows 10では、通知はすぐに動作します。
* Windows 8.1 と Windows 8では、[Application User
Model ID][app-user-model-id]で、アプリへのショートカットはスタートメニューにインストールされます。しかし、スタートメニューにピン止めをする必要がありません。
* Windows 7以前は、通知はサポートされていません。 しかし、[Tray API](tray-balloon)を使用してバルーンヒントを送信することができます。
通知にイメージを使うために、通知オプションの `icon` プロパティにローカルのイメージファイル(`png`が望ましい)を設定します。 正しくない、または`http/https`の URLを設定した場合でも、通知は表示されますが、イメージは表示されません。
```javascript
new Notification('Title', {
body: 'Notification with icon',
icon: 'file:///C:/Users/feriese/Desktop/icon.png'
});
```
* Windows 7以前は、通知はサポートされていません。 しかし、[Tray API][tray-balloon]を使用してバルーンヒントを送信することができます。
その上で、bodyの最大サイズは250文字であることに留意してください。Windowsチームは、通知は200文字にすることを推奨しています。

View file

@ -2,6 +2,8 @@
v0.34.0から、ElectronはMac App Store (MAS)にパッケージ化したアプリを登録することができます。このガイドでは、MASビルド用の制限とアプリを登録する方法についての情報を提供します。
__Note:__ v0.36.0から、アプリがサンドボックス化された後GPUプロセスを妨害するバグがあるので、このバグが修正されるまでは、v0.35.xを使用することを推奨します。[issue #3871][issue-3871]で、このことに関する追加情報を確認できます。
__Note:__ Mac App Storeにアプリを登録するには、費用が発生する[Apple Developer Program][developer-program]に登録する必要があります。
## アプリを登録する方法
@ -63,13 +65,18 @@ INSTALLER_KEY="3rd Party Mac Developer Installer: Company Name (APPIDENTITY)"
FRAMEWORKS_PATH="$APP_PATH/Contents/Frameworks"
codesign --deep -fs "$APP_KEY" --entitlements child.plist "$FRAMEWORKS_PATH/Electron Framework.framework/Libraries/libnode.dylib"
codesign --deep -fs "$APP_KEY" --entitlements child.plist "$FRAMEWORKS_PATH/Electron Framework.framework/Electron Framework"
codesign --deep -fs "$APP_KEY" --entitlements child.plist "$FRAMEWORKS_PATH/Electron Framework.framework/"
codesign --deep -fs "$APP_KEY" --entitlements child.plist "$FRAMEWORKS_PATH/Electron Framework.framework/Versions/A"
codesign --deep -fs "$APP_KEY" --entitlements child.plist "$FRAMEWORKS_PATH/$APP Helper.app/"
codesign --deep -fs "$APP_KEY" --entitlements child.plist "$FRAMEWORKS_PATH/$APP Helper EH.app/"
codesign --deep -fs "$APP_KEY" --entitlements child.plist "$FRAMEWORKS_PATH/$APP Helper NP.app/"
codesign -fs "$APP_KEY" --entitlements parent.plist "$APP_PATH"
if [ -d "$FRAMEWORKS_PATH/Squirrel.framework/Versions/A" ]; then
# Signing a non-MAS build.
codesign --deep -fs "$APP_KEY" --entitlements child.plist "$FRAMEWORKS_PATH/Mantle.framework/Versions/A"
codesign --deep -fs "$APP_KEY" --entitlements child.plist "$FRAMEWORKS_PATH/ReactiveCocoa.framework/Versions/A"
codesign --deep -fs "$APP_KEY" --entitlements child.plist "$FRAMEWORKS_PATH/Squirrel.framework/Versions/A"
fi
codesign -fs "$APP_KEY" --entitlements parent.plist "$APP_PATH"
productbuild --component "$APP_PATH" /Applications --sign "$INSTALLER_KEY" "$RESULT_PATH"
```
@ -83,8 +90,8 @@ OS Xで、サンドボックスにアプリを新しく追加した場合、基
アプリのサンドボックスですべての要件を満たすために、MASビルドで次のモジュールを無効にしてください。
* `crash-reporter`
* `auto-updater`
* `crashReporter`
* `autoUpdater`
次の挙動を変更してください。
@ -92,7 +99,39 @@ OS Xで、サンドボックスにアプリを新しく追加した場合、基
* 一部のアクセシビリティ機能が動作しないことがあります。
* アプリはDNSの変更を認識しません。
アプリのサンドボックスでの使用が原因で、アプリがアクセスできるリソースは厳密に制限されています。詳細は、 [App Sandboxing][app-sandboxing] を参照してください。
アプリのサンドボックスでの使用では、アプリがアクセスできるリソースは厳密に制限されています。詳細は、 [App Sandboxing][app-sandboxing] を参照してください。
## Electronが使用する暗号化アルゴリズム
あなたが住んでいる国や地域に依存して、Mac App Store がアプリで使用する暗号化アルゴリズムを文章化することを要求することがあり、暗号登録番号U.S. Encryption Registration (ERN))の同意のコピーの提出を求められます。
Electron は次の暗号アルゴリズムを使用しています:
* AES - [NIST SP 800-38A](http://csrc.nist.gov/publications/nistpubs/800-38a/sp800-38a.pdf), [NIST SP 800-38D](http://csrc.nist.gov/publications/nistpubs/800-38D/SP-800-38D.pdf), [RFC 3394](http://www.ietf.org/rfc/rfc3394.txt)
* HMAC - [FIPS 198-1](http://csrc.nist.gov/publications/fips/fips198-1/FIPS-198-1_final.pdf)
* ECDSA - ANS X9.622005
* ECDH - ANS X9.632001
* HKDF - [NIST SP 800-56C](http://csrc.nist.gov/publications/nistpubs/800-56C/SP-800-56C.pdf)
* PBKDF2 - [RFC 2898](https://tools.ietf.org/html/rfc2898)
* RSA - [RFC 3447](http://www.ietf.org/rfc/rfc3447)
* SHA - [FIPS 180-4](http://csrc.nist.gov/publications/fips/fips180-4/fips-180-4.pdf)
* Blowfish - https://www.schneier.com/cryptography/blowfish/
* CAST - [RFC 2144](https://tools.ietf.org/html/rfc2144), [RFC 2612](https://tools.ietf.org/html/rfc2612)
* DES - [FIPS 46-3](http://csrc.nist.gov/publications/fips/fips46-3/fips46-3.pdf)
* DH - [RFC 2631](https://tools.ietf.org/html/rfc2631)
* DSA - [ANSI X9.30](http://webstore.ansi.org/RecordDetail.aspx?sku=ANSI+X9.30-1%3A1997)
* EC - [SEC 1](http://www.secg.org/sec1-v2.pdf)
* IDEA - "On the Design and Security of Block Ciphers" book by X. Lai
* MD2 - [RFC 1319](http://tools.ietf.org/html/rfc1319)
* MD4 - [RFC 6150](https://tools.ietf.org/html/rfc6150)
* MD5 - [RFC 1321](https://tools.ietf.org/html/rfc1321)
* MDC2 - [ISO/IEC 10118-2](https://www.openssl.org/docs/manmaster/crypto/mdc2.html)
* RC2 - [RFC 2268](https://tools.ietf.org/html/rfc2268)
* RC4 - [RFC 4345](https://tools.ietf.org/html/rfc4345)
* RC5 - http://people.csail.mit.edu/rivest/Rivest-rc5rev.pdf
* RIPEMD - [ISO/IEC 10118-3](http://webstore.ansi.org/RecordDetail.aspx?sku=ISO%2FIEC%2010118-3:2004)
ERNの同意を取得するには、 [How to legally submit an app to Apples App Store when it uses encryption (or how to obtain an ERN)][ern-tutorial]を参照してくだsだい。
[developer-program]: https://developer.apple.com/support/compare-memberships/
[submitting-your-app]: https://developer.apple.com/library/mac/documentation/IDEs/Conceptual/AppDistributionGuide/SubmittingYourApp/SubmittingYourApp.html
@ -101,3 +140,5 @@ OS Xで、サンドボックスにアプリを新しく追加した場合、基
[create-record]: https://developer.apple.com/library/ios/documentation/LanguagesUtilities/Conceptual/iTunesConnect_Guide/Chapters/CreatingiTunesConnectRecord.html
[submit-for-review]: https://developer.apple.com/library/ios/documentation/LanguagesUtilities/Conceptual/iTunesConnect_Guide/Chapters/SubmittingTheApp.html
[app-sandboxing]: https://developer.apple.com/app-sandboxing/
[issue-3871]: https://github.com/atom/electron/issues/3871
[ern-tutorial]: https://carouselapps.com/2015/12/15/legally-submit-app-apples-app-store-uses-encryption-obtain-ern/

View file

@ -4,7 +4,7 @@ Electronでは次のプラットフォームをサポートします。
### OS X
OS X用に提供しているバイナリは64bitのみで、サポートするOS Xのバージョンは、OS X 10.8 以降です。
OS X用に提供しているバイナリは64bitのみで、サポートするOS Xのバージョンは、OS X 10.9 以降です。
### Windows

View file

@ -252,6 +252,14 @@ GPU가 작동하던 중 크래시가 일어났을 때 발생하는 이벤트입
`beforeunload` 이벤트 핸들러에서 `false`를 반환했을 때 윈도우 종료가 취소 될 수
있습니다.
### `app.hide()` _OS X_
최소화를 하지 않고 어플리케이션의 모든 윈도우들을 숨깁니다.
### `app.show()` _OS X_
숨긴 어플리케이션 윈도우들을 다시 보이게 만듭니다. 자동으로 포커스되지 않습니다.
### `app.exit(exitCode)`
* `exitCode` Integer

View file

@ -293,6 +293,11 @@ OS X에선 지정한 어플리케이션 메뉴에 상관없이 메뉴의 첫번
이름이 됩니다. 어플리케이션 이름을 변경하려면 앱 번들내의 `Info.plist` 파일을 수정해야
합니다. 자세한 내용은 [About Information Property List Files][AboutInformationPropertyListFiles] 문서를 참고하세요.
## 지정한 브라우저 윈도우에 메뉴 설정 (*Linux* *Windows*)
브라우저 윈도우의 [`setMenu` 메서드][setMenu]는 어떤 브라우저 윈도우의 메뉴를 설정할
수 있습니다.
## 메뉴 아이템 위치
`Menu.buildFromTemplate`로 메뉴를 만들 때 `position``id`를 사용해서 아이템의
@ -367,3 +372,4 @@ OS X에선 지정한 어플리케이션 메뉴에 상관없이 메뉴의 첫번
```
[AboutInformationPropertyListFiles]: https://developer.apple.com/library/ios/documentation/general/Reference/InfoPlistKeyReference/Articles/AboutInformationPropertyListFiles.html
[setMenu]: https://github.com/atom/electron/blob/master/docs/api/browser-window.md#winsetmenumenu-linux-windows

View file

@ -212,6 +212,7 @@ proxyURL = [<proxyScheme>"://"]<proxyHost>[":"<proxyPort>]
```
예시:
* `http=foopy:80;ftp=foopy2` - http:// URL에 `foopy:80` HTTP 프록시를 사용합니다.
`foopy2:80` 는 ftp:// URL에 사용됩니다.
* `foopy:80` - 모든 URL에 `foopy:80` 프록시를 사용합니다.
@ -287,6 +288,30 @@ myWindow.webContents.session.setCertificateVerifyProc(function(hostname, cert, c
callback(false);
});
```
#### `ses.setPermissionRequestHandler(handler)`
* `handler` Function
* `webContents` Object - [WebContents](web-contents.md) 권한을 요청.
* `permission` String - 'media', 'geolocation', 'notifications',
'midiSysex'의 나열.
* `callback` Function - 권한 허용 및 거부.
`session`의 권한 요청에 응답을 하는데 사용하는 핸들러를 설정합니다.
`callback('granted')`를 호출하면 권한 제공을 허용하고 `callback('denied')`
호출하면 권한 제공을 거부합니다.
```javascript
session.fromPartition(partition).setPermissionRequestHandler(function(webContents, permission, callback) {
if (webContents.getURL() === host) {
if (permission == "notifications") {
callback(); // 거부됨.
return;
}
}
callback('granted');
});
```
#### `ses.webRequest`

View file

@ -278,6 +278,28 @@ Returns:
<meta name='theme-color' content='#ff0000'>
```
### Event: 'cursor-changed'
Returns:
* `event` Event
* `type` String
* `image` NativeImage (optional)
* `scale` Float (optional)
커서 타입이 변경될 때 발생하는 이벤트입니다. `type` 매개변수는 다음 값이 될 수 있습니다:
`default`, `crosshair`, `pointer`, `text`, `wait`, `help`, `e-resize`, `n-resize`,
`ne-resize`, `nw-resize`, `s-resize`, `se-resize`, `sw-resize`, `w-resize`,
`ns-resize`, `ew-resize`, `nesw-resize`, `nwse-resize`, `col-resize`,
`row-resize`, `m-panning`, `e-panning`, `n-panning`, `ne-panning`, `nw-panning`,
`s-panning`, `se-panning`, `sw-panning`, `w-panning`, `move`, `vertical-text`,
`cell`, `context-menu`, `alias`, `progress`, `nodrop`, `copy`, `none`,
`not-allowed`, `zoom-in`, `zoom-out`, `grab`, `grabbing`, `custom`.
만약 `type` 매개변수가 `custom` 이고 `image` 매개변수가 `NativeImage`를 통한 커스텀
커서를 지정했을 때, 해당 이미지로 커서가 변경됩니다. 또한 `scale` 매개변수는 이미지의
크기를 조정합니다.
## Instance Methods
`webContents`객체는 다음과 같은 인스턴스 메서드들을 가지고 있습니다.

View file

@ -60,8 +60,8 @@ electron/resources/
### Windows
`electron.exe`을 원하는 이름으로 변경할 수 있습니다.
그리고 [rcedit](https://github.com/atom/rcedit) 또는
[ResEdit](http://www.resedit.net)를 사용하여 아이콘을 변경할 수 있습니다.
그리고 [rcedit](https://github.com/atom/rcedit)
를 사용하여 아이콘을 변경할 수 있습니다.
### OS X

View file

@ -4,6 +4,10 @@ Electron은 v0.34.0 버전부터 앱 패키지를 Mac App Store(MAS)에 제출
되었습니다. 이 가이드는 어플리케이션을 앱 스토어에 등록하는 방법과 빌드의 한계에 대한
설명을 제공합니다.
__참고:__ v0.36.0 버전부터 어플리케이션이 샌드박스화 된 상태로 실행되면 GPU 작동을
방지하는 버그가 있었습니다. 따라서 이 버그가 고쳐지기 전까진 v0.35.x 버전을 사용하는
것을 권장합니다. 이 버그에 관한 자세한 사항은 [issue #3871][issue-3871]를 참고하세요.
__참고:__ Mac App Store에 어플리케이션을 등록하려면
[Apple Developer Program][developer-program]에 등록되어 있어야 하며 비용이 발생할
수 있습니다.
@ -73,13 +77,18 @@ INSTALLER_KEY="3rd Party Mac Developer Installer: Company Name (APPIDENTITY)"
FRAMEWORKS_PATH="$APP_PATH/Contents/Frameworks"
codesign --deep -fs "$APP_KEY" --entitlements child.plist "$FRAMEWORKS_PATH/Electron Framework.framework/Libraries/libnode.dylib"
codesign --deep -fs "$APP_KEY" --entitlements child.plist "$FRAMEWORKS_PATH/Electron Framework.framework/Electron Framework"
codesign --deep -fs "$APP_KEY" --entitlements child.plist "$FRAMEWORKS_PATH/Electron Framework.framework/"
codesign --deep -fs "$APP_KEY" --entitlements child.plist "$FRAMEWORKS_PATH/Electron Framework.framework/Versions/A"
codesign --deep -fs "$APP_KEY" --entitlements child.plist "$FRAMEWORKS_PATH/$APP Helper.app/"
codesign --deep -fs "$APP_KEY" --entitlements child.plist "$FRAMEWORKS_PATH/$APP Helper EH.app/"
codesign --deep -fs "$APP_KEY" --entitlements child.plist "$FRAMEWORKS_PATH/$APP Helper NP.app/"
codesign -fs "$APP_KEY" --entitlements parent.plist "$APP_PATH"
if [ -d "$FRAMEWORKS_PATH/Squirrel.framework/Versions/A" ]; then
# non-MAS 빌드 서명
codesign --deep -fs "$APP_KEY" --entitlements child.plist "$FRAMEWORKS_PATH/Mantle.framework/Versions/A"
codesign --deep -fs "$APP_KEY" --entitlements child.plist "$FRAMEWORKS_PATH/ReactiveCocoa.framework/Versions/A"
codesign --deep -fs "$APP_KEY" --entitlements child.plist "$FRAMEWORKS_PATH/Squirrel.framework/Versions/A"
fi
codesign -fs "$APP_KEY" --entitlements parent.plist "$APP_PATH"
productbuild --component "$APP_PATH" /Applications --sign "$INSTALLER_KEY" "$RESULT_PATH"
```
@ -98,8 +107,8 @@ productbuild --component "$APP_PATH" /Applications --sign "$INSTALLER_KEY" "$RES
모든 어플리케이션 샌드박스에 대한 요구 사항을 충족시키기 위해, 다음 모듈들은 MAS
빌드에서 비활성화됩니다:
* `crash-reporter`
* `auto-updater`
* `crashReporter`
* `autoUpdater`
그리고 다음 동작으로 대체됩니다:
@ -111,7 +120,42 @@ productbuild --component "$APP_PATH" /Applications --sign "$INSTALLER_KEY" "$RES
엄격하게 제한되어 있습니다. 자세한 내용은 [App Sandboxing][app-sandboxing] 문서를
참고하세요.
**역주:** [Mac 앱 배포 가이드 공식 문서](https://developer.apple.com/osx/distribution/kr/)
## Electron에서 사용하는 암호화 알고리즘
국가와 살고 있는 지역에 따라, 맥 앱스토어는 제출한 어플리케이션에서 사용하는 암호화
알고리즘의 문서를 요구할 수 있습니다. 심지어 U.S. Encryption Registration (ERN)의
승인 사본을 제출하라고 할 수도 있습니다.
Electron은 다음과 같은 암호화 알고리즘을 사용합니다:
* AES - [NIST SP 800-38A](http://csrc.nist.gov/publications/nistpubs/800-38a/sp800-38a.pdf), [NIST SP 800-38D](http://csrc.nist.gov/publications/nistpubs/800-38D/SP-800-38D.pdf), [RFC 3394](http://www.ietf.org/rfc/rfc3394.txt)
* HMAC - [FIPS 198-1](http://csrc.nist.gov/publications/fips/fips198-1/FIPS-198-1_final.pdf)
* ECDSA - ANS X9.622005
* ECDH - ANS X9.632001
* HKDF - [NIST SP 800-56C](http://csrc.nist.gov/publications/nistpubs/800-56C/SP-800-56C.pdf)
* PBKDF2 - [RFC 2898](https://tools.ietf.org/html/rfc2898)
* RSA - [RFC 3447](http://www.ietf.org/rfc/rfc3447)
* SHA - [FIPS 180-4](http://csrc.nist.gov/publications/fips/fips180-4/fips-180-4.pdf)
* Blowfish - https://www.schneier.com/cryptography/blowfish/
* CAST - [RFC 2144](https://tools.ietf.org/html/rfc2144), [RFC 2612](https://tools.ietf.org/html/rfc2612)
* DES - [FIPS 46-3](http://csrc.nist.gov/publications/fips/fips46-3/fips46-3.pdf)
* DH - [RFC 2631](https://tools.ietf.org/html/rfc2631)
* DSA - [ANSI X9.30](http://webstore.ansi.org/RecordDetail.aspx?sku=ANSI+X9.30-1%3A1997)
* EC - [SEC 1](http://www.secg.org/sec1-v2.pdf)
* IDEA - "On the Design and Security of Block Ciphers" book by X. Lai
* MD2 - [RFC 1319](http://tools.ietf.org/html/rfc1319)
* MD4 - [RFC 6150](https://tools.ietf.org/html/rfc6150)
* MD5 - [RFC 1321](https://tools.ietf.org/html/rfc1321)
* MDC2 - [ISO/IEC 10118-2](https://www.openssl.org/docs/manmaster/crypto/mdc2.html)
* RC2 - [RFC 2268](https://tools.ietf.org/html/rfc2268)
* RC4 - [RFC 4345](https://tools.ietf.org/html/rfc4345)
* RC5 - http://people.csail.mit.edu/rivest/Rivest-rc5rev.pdf
* RIPEMD - [ISO/IEC 10118-3](http://webstore.ansi.org/RecordDetail.aspx?sku=ISO%2FIEC%2010118-3:2004)
ERN의 승인을 얻는 방법은, 다음 글을 참고하는 것이 좋습니다:
[어플리케이션이 암호화를 사용할 때, 합법적으로 Apple의 앱 스토어에 제출하는 방법 (또는 ERN의 승인을 얻는 방법)][ern-tutorial].
**역주:** [Mac 앱 배포 가이드 공식 한국어 문서](https://developer.apple.com/osx/distribution/kr/)
[developer-program]: https://developer.apple.com/support/compare-memberships/
[submitting-your-app]: https://developer.apple.com/library/mac/documentation/IDEs/Conceptual/AppDistributionGuide/SubmittingYourApp/SubmittingYourApp.html
@ -120,3 +164,5 @@ productbuild --component "$APP_PATH" /Applications --sign "$INSTALLER_KEY" "$RES
[create-record]: https://developer.apple.com/library/ios/documentation/LanguagesUtilities/Conceptual/iTunesConnect_Guide/Chapters/CreatingiTunesConnectRecord.html
[submit-for-review]: https://developer.apple.com/library/ios/documentation/LanguagesUtilities/Conceptual/iTunesConnect_Guide/Chapters/SubmittingTheApp.html
[app-sandboxing]: https://developer.apple.com/app-sandboxing/
[issue-3871]: https://github.com/atom/electron/issues/3871
[ern-tutorial]: https://carouselapps.com/2015/12/15/legally-submit-app-apples-app-store-uses-encryption-obtain-ern/

View file

@ -4,7 +4,7 @@ Electron에선 다음과 같은 플랫폼을 지원합니다:
### OS X
OS X는 64비트 바이너리만 제공됩니다. 그리고 최소 OS X 지원 버전은 10.8입니다.
OS X는 64비트 바이너리만 제공됩니다. 그리고 최소 OS X 지원 버전은 10.9입니다.
### Windows

View file

@ -6,9 +6,14 @@ documentação na lista de [versões disponíveis](http://electron.atom.io/docs/
ou se você estiver usando a interface do GitHub, abra o *dropdown* "Switch branches/tags" e
selecione a *tag* que corresponde à sua versão.
## FAQ
Existem muitas perguntas comuns que são feitas, verifique antes de criar uma issue.
* [Electron FAQ](../../docs/faq/electron-faq.md)
## Guias
* [Platformas Suportadas](../../tutorial/supported-platforms.md)
* [Plataformas Suportadas](tutorial/supported-platforms.md)
* [Distribuição de Aplicações](tutorial/application-distribution.md)
* [Guia de Submissão da Mac App Store](../../tutorial/mac-app-store-submission-guide.md)
* [Empacotamento da Aplicação](tutorial/application-packaging.md)
@ -17,6 +22,7 @@ selecione a *tag* que corresponde à sua versão.
* [Usando Selenium e WebDriver](../../docs/tutorial/using-selenium-and-webdriver.md)
* [Extensão DevTools](../../docs/tutorial/devtools-extension.md)
* [Usando o Plugin Pepper Flash](tutorial/using-pepper-flash-plugin.md)
* [Usando o Plugin Widevine CDM](../../tutorial/using-widevine-cdm-plugin.md)
## Tutoriais
@ -58,6 +64,7 @@ selecione a *tag* que corresponde à sua versão.
### Módulos para o Processo Renderizador:
* [DesktopCapturer](../../docs/api/desktop-capturer)
* [ipcRenderer](../../docs/api/ipc-renderer.md)
* [remote](../../docs/api/remote.md)
* [webFrame](../../docs/api/web-frame.md)

View file

@ -0,0 +1,53 @@
# Estrutura de Diretórios do Código-Fonte
O código-fonte do Electron é separado em algumas partes, seguindo principalmente as convenções de separação do chromium.
Você pode se familiarizar com a [arquitetura de multiprocessamento ](http://dev.chromium.org/developers/design-documents/multi-process-architecture) do Chromium para entender melhor o código-fonte.
## Estrutura do Código-Fonte
```
Electron
├──atom - Código fonte do Electron.
| ├── app - Código de inicialização.
| ├── browser - A interface incluíndo a janela principal, UI, e todas as coisas do processo principal. Ele se comunica com o renderizador para gerenciar as páginas web.
| |   ├── lib - Código Javascript para inicializar o processo principal.
| | ├── ui - Implementação da UI para plataformas distintas.
| | | ├── cocoa - Código-fonte específico do cocoa .
| | | ├── gtk - Código-font específico do GTK+.
| | | └── win - Código-fonte específico do Windows GUI.
| | ├── default_app - A página padrão é mostrada quando
| | | Electron inicializa sem fornecer um app.
| | ├── api - Implementação do processo principal das APIs
| | | └── lib - Código Javascript, parte da implementação da API.
| | ├── net - Código relacionado a rede.
| | ├── mac - Código fonte em Object-c, específico para Mac.
| | └── resources - Icones, arquivos dependentes da plataforma, etc.
| ├── renderer - Código que é executado no processo de renderização.
| | ├── lib - Parte do código Javascript de inicialização do renderizador.
| | └── api - Implementação das APIs para o processo de renderizaçãp.
| | └── lib - Código Javascript, parte da implementação da API.
| └── common - Código que utiliza ambos os processos, o principal e o de rendezição,
| ele inclui algumas funções utilitárias e códigos para integrar com ciclo de mensagens do node no ciclo de mensagens do Chromium.
| ├── lib - Código Javascript comum para a inicialização.
| └── api - A implementação de APIs comuns e fundamentação dos
| módulos integrados com Electron's.
| └── lib - Código Javascript, parte da implementação da API.
├── chromium_src - Código-fonte copiado do Chromium.
├── docs - Documentação.
├── spec - Testes Automáticos.
├── atom.gyp - Regras de compilação do Electron.
└── common.gypi - Configuração específica do compilador e regras de construção para outros componentes
como `node` e `breakpad`.
```
## Estrutura de Outros Diretórios.
* **script** - Scripts utilizado para fins de desenvolvimento como building, packaging, testes, etc.
* **tools** - Scripts auxiliares, utilizados pelos arquivos gyp, ao contrário do`script`, os scripts colocados aqui nunca devem ser invocados diretamente pelos usuários.
* **vendor** - Dependências de código-fonte de terceiros, nós não utilizamos `third_party` como nome porque ele poderia ser confundido com o diretório homônimo existente no código-fonte do Chromium.
* **node_modules** - Módulos de terceiros em node usados para compilação
* **out** - Diretório temporário saída do `ninja`.
* **dist** - Diretório temporário do `script/create-dist.py` ao criar uma distribuição
* **external_binaries** - Binários baixados de Frameworks de terceiros que não suportam a compilação com `gyp`.

View file

@ -1,7 +1,7 @@
# 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
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
`Electron.app/Contents/Resources/`,
no Linux e no Windows é em `resources/`):
@ -24,7 +24,7 @@ electron/resources/app
```
Logo após execute `Electron.app` (ou `electron` no Linux e `electron.exe` no Windows),
e o Electron iniciaria a aplicação. O diretório `electron` será utilizado para criar a distribuição para
e o Electron iniciaria a aplicação. O diretório `electron` será utilizado para criar a distribuição para
usuários finais.
## Empacotando sua aplicação em um arquivo.
@ -58,11 +58,10 @@ Mais detalhes podem ser encontrados em [Empacotamento da aplicação](../../../d
Depois de empacotar seu aplicativo Electron, você vai querer renomear a marca Electron
antes de distribuí-lo aos usuários.
### Janelas
### Windows
Você pode renomear `electron.exe` para o nome que desejar e editar o seu ícone e outras
informações com ferramentas como [rcedit](https://github.com/atom/rcedit) ou
[ResEdit](http://www.resedit.net).
informações com ferramentas como [rcedit](https://github.com/atom/rcedit).
### OS X
@ -115,4 +114,4 @@ uma tarefa para o Grunt foi criado e irá cuidar desta tarefa automaticamente pa
[grunt-build-atom-shell](https://github.com/paulcbetts/grunt-build-atom-shell).
Esta tarefa irá automaticamente editar o arquivo `.gyp`, compilar o código
e reconstruir os módulos nativos da aplicação para utilizar o novo nome.
e reconstruir os módulos nativos da aplicação para utilizar o novo nome.

View file

@ -0,0 +1,22 @@
# Plataformas Suportadas
As plataformas suportadas por Electron são:
### OS X
Somente binarios em 64bit são construidos para OS X e a versão mínima suportada é OS X 10.9.
### Windows
Suporte para Windows 7 ou superior, versões anteriores não são suportados (e não ira funcionar)
Binarios em `x86` e `amd64` (x64) são construidos para Windows. Atencão: Versão `ARM` do Windows não é suportada agora.
### Linux
Binario pré-construido `ia32`(`i686`) e binario `x64`(`amd64`) são construidas no Ubuntu 12.04, binario `arm` está construido contra ARM v7 com hard-float ABI e NEION para Debian Wheezy.
Se o pré-compilador poderá ser executado por uma distribuição, depende se a distruibuicão inclui as blibliotecas que o Eletron está vinculando na plataforma de construcão, por este motivo apenas Ubuntu 12.04 é garantido para funcionar corretamente, mas as seguintes distribuições foram verificados com o pre-compilador:
* Ubuntu 12.04 ou superior
* Fedora 21
* Debian 8

View file

@ -58,10 +58,14 @@ app.on('window-all-closed', function() {
`window-all-closed` 事件的区别。
### 事件: 'quit'
返回:
* `event` 事件
* `exitCode` 整数
当应用程序正在退出时触发。
### 事件: 'open-file'
### 事件: 'open-file' _OS X_
返回:
@ -73,8 +77,8 @@ app.on('window-all-closed', function() {
请确认在应用启动的时候(甚至在 `ready` 事件被触发前)就对 `open-file` 事件进行监听,以处理这种情况。
如果你想处理这个事件,你应该调用 `event.preventDefault()`
### 事件: 'open-url'
在 Windows系统中, 你需要通过解析 process.argv 来获取文件路径。
### 事件: 'open-url' _OS X_
返回:
@ -121,32 +125,89 @@ app.on('window-all-closed', function() {
当一个 [浏览器窗口](browser-window.md) 被创建的时候触发。
### 事件: 'select-certificate'
当一个客户端认证被请求的时候被触发。
### 事件: 'certificate-error'
返回:
* `event` 事件
* `webContents` [web组件](browser-window.md#class-webcontents)
* `webContents` [web组件](web-contents.md)
* `url` 字符串
* `certificateList` 对象
* `data` PEM 编码数据
* `issuerName` 发行者的公有名称
* `callback` 函数
Emitted when failed to verify the `certificate` for `url`, to trust the
certificate you should prevent the default behavior with
`event.preventDefault()` and call `callback(true)`.
```javascript
session.on('certificate-error', function(event, webContents, url, error, certificate, callback) {
if (url == "https://github.com") {
// Verification logic.
event.preventDefault();
callback(true);
} else {
callback(false);
}
});
```
### 事件: 'select-client-certificate'
返回:
* `event` 事件
* `webContents` [web组件](web-contents.md)
* `url` 字符串
* `certificateList` 对象
* `data` PEM 编码数据
* `issuerName` 发行者的公有名称
* `callback` 函数
当一个客户端认证被请求的时候被触发。
The `url` corresponds to the navigation entry requesting the client certificate
and `callback` needs to be called with an entry filtered from the list.
Using `event.preventDefault()` prevents the application from using the first
certificate from the store.
```javascript
app.on('select-certificate', function(event, host, url, list, callback) {
event.preventDefault();
callback(list[0]);
})
```
### Event: 'login'
The `url` corresponds to the navigation entry requesting the client certificate
and `callback` needs to be called with an entry filtered from the list.
Using `event.preventDefault()` prevents the application from using the first
certificate from the store.
Returns:
* `event` Event
* `webContents` [Web组件](web-contents.md)
* `request` Object
* `method` String
* `url` URL
* `referrer` URL
* `authInfo` Object
* `isProxy` Boolean
* `scheme` String
* `host` String
* `port` Integer
* `realm` String
* `callback` Function
`webContents` 要做验证时被触发。
The default behavior is to cancel all authentications, to override this you
should prevent the default behavior with `event.preventDefault()` and call
`callback(username, password)` with the credentials.
```javascript
app.on('login', function(event, webContents, request, authInfo, callback) {
event.preventDefault();
callback('username', 'secret');
})
```
### 事件: 'gpu-process-crashed'
当GPU进程崩溃时触发。
@ -164,6 +225,23 @@ certificate from the store.
这个方法保证了所有的 `beforeunload``unload` 事件处理器被正确执行。会存在一个窗口被 `beforeunload` 事件处理器返回 `false` 取消退出的可能性。
### `app.hide()` _OS X_
隐藏所有的应用窗口,不是最小化.
### `app.show()` _OS X_
隐藏后重新显示所有的窗口,不会自动选中他们。
### `app.exit(exitCode)`
* `exitCode` 整数
带着`exitCode`退出应用.
所有的窗口会被立刻关闭,不会询问用户。`before-quit` 和 `will-quit` 这2个事件不会被触发
### `app.getAppPath()`
返回当前应用所在的文件路径。
@ -182,15 +260,15 @@ certificate from the store.
* `$XDG_CONFIG_HOME` or `~/.config` Linux 中
* `~/Library/Application Support` OS X 中
* `userData` 储存你应用程序设置文件的文件夹,默认是 `appData` 文件夹附加应用的名称。
* `cache` 所有用户应用程序缓存的文件夹,默认对应:
* `%APPDATA%` Windows 中 (没有一个通用的缓存位置)
* `$XDG_CACHE_HOME``~/.cache` Linux 中
* `~/Library/Caches` OS X 中
* `userCache` 用于存放应用程序缓存的文件夹,默认是 `cache` 文件夹附加应用的名称。
* `temp` 临时文件夹。
* `userDesktop` 当前用户的桌面文件夹。
* `exe` 当前的可执行文件。
* `module` `libchromiumcontent` 库。
* `exe` 当前的可执行文件
* `module` `libchromiumcontent` 库.
* `desktop` 当前用户的桌面文件夹。
* `documents` "我的文件夹"的路径.
* `downloads` 用户下载目录的路径.
* `music` 用户音乐目录的路径.
* `pictures` 用户图片目录的路径.
* `videos` 用户视频目录的路径.
### `app.setPath(name, path)`
@ -201,7 +279,7 @@ certificate from the store.
如果这个路径指向的文件夹不存在,这个文件夹将会被这个方法创建。
如果错误则抛出 `Error`
你只可以指向 `app.getPath` 中定义过 `name` 的路径。You can only override paths of a `name` defined in `app.getPath`.
你只可以指向 `app.getPath` 中定义过 `name` 的路径。
默认情况下,网页的 cookie 和缓存都会储存在 `userData` 文件夹。
如果你想要改变这个位置,你需要在 `app` 模块中的 `ready` 事件被触发之前重写 `userData` 的路径。
@ -220,16 +298,11 @@ certificate from the store.
### `app.getLocale()`
返回当前应用程序的位置
返回当前应用程序的语言种类
### `app.resolveProxy(url, callback)`
* `url` URL
* `callback` 函数
`url` 解析代理信息。 `callback` 在请求被执行之后将会被 `callback(proxy)` 调用。
### `app.addRecentDocument(path)`
### `app.addRecentDocument(path)` _OS X_ _Windows_
* `path` 字符串
@ -237,7 +310,7 @@ certificate from the store.
这个列表由操作系统进行管理。在 Windows 中您可以通过任务条进行访问,在 OS X 中你可以通过dock 菜单进行访问。
### `app.clearRecentDocuments()`
### `app.clearRecentDocuments()` _OS X_ _Windows_
清除最近访问的文档列表。
@ -257,6 +330,103 @@ certificate from the store.
* `iconPath` 字符串 - JumpList 中显示的 icon 的绝对路径可以是一个任意包含一个icon的资源文件。你通常可以通过指明 `process.execPath` 来显示程序中的icon。
* `iconIndex` 整数 - icon文件中的icon目录。如果一个icon文件包括了两个或多个icon就需要设置这个值以确定icon。如果一个文件仅包含一个icon那么这个值为0。
### `app.allowNTLMCredentialsForAllDomains(allow)`
* `allow` Boolean
Dynamically sets whether to always send credentials for HTTP NTLM or Negotiate
authentication - normally, Electron will only send NTLM/Kerberos credentials for
URLs that fall under "Local Intranet" sites (i.e. are in the same domain as you).
However, this detection often fails when corporate networks are badly configured,
so this lets you co-opt this behavior and enable it for all URLs.
### `app.makeSingleInstance(callback)`
* `callback` Function
This method makes your application a Single Instance Application - instead of
allowing multiple instances of your app to run, this will ensure that only a
single instance of your app is running, and other instances signal this
instance and exit.
`callback` will be called with `callback(argv, workingDirectory)` when a second
instance has been executed. `argv` is an Array of the second instance's command
line arguments, and `workingDirectory` is its current working directory. Usually
applications respond to this by making their primary window focused and
non-minimized.
The `callback` is guaranteed to be executed after the `ready` event of `app`
gets emitted.
This method returns `false` if your process is the primary instance of the
application and your app should continue loading. And returns `true` if your
process has sent its parameters to another instance, and you should immediately
quit.
On OS X the system enforces single instance automatically when users try to open
a second instance of your app in Finder, and the `open-file` and `open-url`
events will be emitted for that. However when users start your app in command
line the system's single instance machanism will be bypassed and you have to
use this method to ensure single instance.
An example of activating the window of primary instance when a second instance
starts:
```js
var myWindow = null;
var shouldQuit = app.makeSingleInstance(function(commandLine, workingDirectory) {
// Someone tried to run a second instance, we should focus our window.
if (myWindow) {
if (myWindow.isMinimized()) myWindow.restore();
myWindow.focus();
}
return true;
});
if (shouldQuit) {
app.quit();
return;
}
// Create myWindow, load the rest of the app, etc...
app.on('ready', function() {
});
```
### `app.setAppUserModelId(id)` _Windows_
* `id` String
改变 [Application User Model ID][app-user-model-id] 的 `id`.
### `app.isAeroGlassEnabled()` _Windows_
This method returns `true` if [DWM composition](https://msdn.microsoft.com/en-us/library/windows/desktop/aa969540.aspx)
(Aero Glass) is enabled, and `false` otherwise. You can use it to determine if
you should create a transparent window or not (transparent windows won't work
correctly when DWM composition is disabled).
Usage example:
```js
let browserOptions = {width: 1000, height: 800};
// Make the window transparent only if the platform supports it.
if (process.platform !== 'win32' || app.isAeroGlassEnabled()) {
browserOptions.transparent = true;
browserOptions.frame = false;
}
// Create the window.
win = new BrowserWindow(browserOptions);
// Navigate.
if (browserOptions.transparent) {
win.loadURL('file://' + __dirname + '/index.html');
} else {
// No transparency, so we load a fallback that uses basic styles.
win.loadURL('file://' + __dirname + '/fallback.html');
}
```
### `app.commandLine.appendSwitch(switch[, value])`
通过可选的参数 `value` 给 Chromium 命令行中添加一个开关。
@ -312,4 +482,5 @@ Append a switch (with optional `value`) to Chromium's command line.
设置应用的 [dock 菜单][dock-menu].
[dock-menu]:https://developer.apple.com/library/mac/documentation/Carbon/Conceptual/customizing_docktile/concepts/dockconcepts.html#//apple_ref/doc/uid/TP30000986-CH2-TPXREF103
[tasks]:http://msdn.microsoft.com/en-us/library/windows/desktop/dd378460(v=vs.85).aspx#tasks
[tasks]:http://msdn.microsoft.com/en-us/library/windows/desktop/dd378460(v=vs.85).aspx#tasks
[app-user-model-id]: https://msdn.microsoft.com/en-us/library/windows/desktop/dd378459(v=vs.85).aspx

View file

@ -55,12 +55,12 @@ electron/resources/
### Windows
你可以将 `electron.exe` 改成任意你喜欢的名字,然后可以使用像
[rcedit](https://github.com/atom/rcedit) 或者[ResEdit](http://www.resedit.net)
[rcedit](https://github.com/atom/rcedit)
编辑它的icon和其他信息。
### OS X
你可以将 `Electron.app` 改成任意你喜欢的名字,然后你也需要修改这些文件中的
你可以将 `Electron.app` 改成任意你喜欢的名字,然后你也需要修改这些文件中的
`CFBundleDisplayName` `CFBundleIdentifier` 以及 `CFBundleName` 字段。
这些文件如下:

View file

@ -14,7 +14,7 @@ Electron 可以让你使用纯 JavaScript 调用丰富的原生 APIs 来创造
在一般浏览器中网页通常会在沙盒环境下运行并且不允许访问原生资源。然而Electron 用户拥有在网页中调用 io.js 的 APIs 的能力,可以与底层操作系统直接交互。
## 主进程与渲染进程的区别
主进程使用 BroswerWindow 实例创建网页。每个 BroswerWindow 实例都在自己的渲染进程里运行着一个网页。当一个 BroswerWindow 实例被销毁后,相应的渲染进程也会被终止。
主进程使用 BrowserWindow 实例创建网页。每个 BrowserWindow 实例都在自己的渲染进程里运行着一个网页。当一个 BrowserWindow 实例被销毁后,相应的渲染进程也会被终止。
主进程管理所有页面和与之对应的渲染进程。每个渲染进程都是相互独立的,并且只关心他们自己的网页。

View file

@ -50,8 +50,8 @@ electron/resources/
### Windows
你可以重新命名 `electron.exe` 為任何你喜歡的名稱,然後透過像是 [rcedit](https://github.com/atom/rcedit)
[ResEdit](http://www.resedit.net) 的工具來編輯它的圖示(icon)和其他資訊。
你可以重新命名 `electron.exe` 為任何你喜歡的名稱,然後透過像是 [rcedit](https://github.com/atom/rcedit)
的工具來編輯它的圖示(icon)和其他資訊。
### OS X
@ -60,7 +60,7 @@ electron/resources/
* `Electron.app/Contents/Info.plist`
* `Electron.app/Contents/Frameworks/Electron Helper.app/Contents/Info.plist`
你也可以重新命名 helper 應用程式來避免在活動監視器中秀出 `Electron Helper`
你也可以重新命名 helper 應用程式來避免在活動監視器中秀出 `Electron Helper`
,但請確認你有重新命名 helper 應用程式的可執行檔名稱。
重新命名後的應用程式檔案結構可能長得相這樣:

View file

@ -87,7 +87,7 @@ handle this case (even before the `ready` event is emitted).
You should call `event.preventDefault()` if you want to handle this event.
On Windows, you have to parse `process.argv` to get the filepath.
On Windows, you have to parse `process.argv` (in the main process) to get the filepath.
### Event: 'open-url' _OS X_
@ -244,6 +244,14 @@ This method guarantees that all `beforeunload` and `unload` event handlers are
correctly executed. It is possible that a window cancels the quitting by
returning `false` in the `beforeunload` event handler.
### `app.hide()` _OS X_
Hides all application windows without minimising them.
### `app.show()` _OS X_
Shows application windows after they were hidden. Does not automatically focus them.
### `app.exit(exitCode)`
* `exitCode` Integer

View file

@ -785,7 +785,7 @@ cleared
* `description` String - a description that will be provided to Accessibility
screen readers
Sets a 16px overlay onto the current taskbar icon, usually used to convey some
Sets a 16 x 16 pixel overlay onto the current taskbar icon, usually used to convey some
sort of application status or to passively notify the user.
### `win.setHasShadow(hasShadow)` _OS X_

View file

@ -37,9 +37,9 @@ channel.
This removes *all* handlers to this ipc channel.
### `ipcMain.once(channel, callback)`
### `ipcRenderer.once(channel, callback)`
Use this in place of `ipcMain.on()` to fire handlers meant to occur only once,
Use this in place of `ipcRenderer.on()` to fire handlers meant to occur only once,
as in, they won't be activated after one call of `callback`
## Sending Messages

View file

@ -296,6 +296,11 @@ no matter what label you set. To change it you have to change your app's name
by modifying your app bundle's `Info.plist` file. See [About Information
Property List Files][AboutInformationPropertyListFiles] for more information.
## Setting Menu for Specific Browser Window (*Linux* *Windows*)
The [`setMenu` method][setMenu] of browser windows can set the menu of certain
browser window.
## Menu Item Position
You can make use of `position` and `id` to control how the item will be placed
@ -371,3 +376,5 @@ Menu:
```
[AboutInformationPropertyListFiles]: https://developer.apple.com/library/ios/documentation/general/Reference/InfoPlistKeyReference/Articles/AboutInformationPropertyListFiles.html
[setMenu]:
https://github.com/atom/electron/blob/master/docs/api/browser-window.md#winsetmenumenu-linux-windows

View file

@ -60,7 +60,8 @@ The following events are available on instances of `Session`:
Emitted when Electron is about to download `item` in `webContents`.
Calling `event.preventDefault()` will cancel the download.
Calling `event.preventDefault()` will cancel the download and `item` will not be
available from next tick of the process.
```javascript
session.defaultSession.on('will-download', function(event, item, webContents) {
@ -290,6 +291,35 @@ myWindow.webContents.session.setCertificateVerifyProc(function(hostname, cert, c
});
```
#### `ses.setPermissionRequestHandler(handler)`
* `handler` Function
* `webContents` Object - [WebContents](web-contents.md) requesting the permission.
* `permission` String - Enum of 'media', 'geolocation', 'notifications', 'midiSysex', 'pointerLock', 'fullscreen'.
* `callback` Function - Allow or deny the permission.
Sets the handler which can be used to respond to permission requests for the `session`.
Calling `callback(true)` will allow the permission and `callback(false)` will reject it.
```javascript
session.fromPartition(partition).setPermissionRequestHandler(function(webContents, permission, callback) {
if (webContents.getURL() === host) {
if (permission == "notifications") {
callback(false); // denied.
return;
}
}
callback(true);
});
```
#### `ses.clearHostResolverCache([callback])`
* `callback` Function (optional) - Called when operation is done.
Clears the host resolver cache.
#### `ses.webRequest`
The `webRequest` API set allows to intercept and modify contents of a request at

View file

@ -58,6 +58,6 @@ Electron
* **node_modules** - Third party node modules used for building.
* **out** - Temporary output directory of `ninja`.
* **dist** - Temporary directory created by `script/create-dist.py` script
when creating an distribution.
when creating a distribution.
* **external_binaries** - Downloaded binaries of third-party frameworks which
do not support building with `gyp`.

View file

@ -61,8 +61,7 @@ before distributing it to users.
### Windows
You can rename `electron.exe` to any name you like, and edit its icon and other
information with tools like [rcedit](https://github.com/atom/rcedit) or
[ResEdit](http://www.resedit.net).
information with tools like [rcedit](https://github.com/atom/rcedit).
### OS X

View file

@ -5,7 +5,7 @@ Following platforms are supported by Electron:
### OS X
Only 64bit binaries are provided for OS X, and the minimum OS X version
supported is OS X 10.8.
supported is OS X 10.9.
### Windows

View file

@ -144,6 +144,8 @@
'atom/browser/atom_browser_main_parts_posix.cc',
'atom/browser/atom_javascript_dialog_manager.cc',
'atom/browser/atom_javascript_dialog_manager.h',
'atom/browser/atom_permission_manager.cc',
'atom/browser/atom_permission_manager.h',
'atom/browser/atom_quota_permission_context.cc',
'atom/browser/atom_quota_permission_context.h',
'atom/browser/atom_resource_dispatcher_host_delegate.cc',
@ -256,6 +258,8 @@
'atom/browser/ui/x/window_state_watcher.h',
'atom/browser/ui/x/x_window_utils.cc',
'atom/browser/ui/x/x_window_utils.h',
'atom/browser/web_contents_permission_helper.cc',
'atom/browser/web_contents_permission_helper.h',
'atom/browser/web_contents_preferences.cc',
'atom/browser/web_contents_preferences.h',
'atom/browser/web_dialog_helper.cc',

View file

@ -1,6 +1,6 @@
{
"name": "electron",
"version": "0.36.6",
"version": "0.36.7",
"devDependencies": {
"asar": "^0.9.0",
"eslint": "^1.10.3",

View file

@ -144,6 +144,50 @@ describe('session module', function() {
});
});
});
describe('session will-download event', function() {
var w = null;
beforeEach(function() {
w = new BrowserWindow({
show: false,
width: 400,
height: 400
});
});
afterEach(function() {
return w.destroy();
});
it('can cancel default download behavior', function(done) {
const mockFile = new Buffer(1024);
const contentDisposition = 'inline; filename="mockFile.txt"';
const downloadServer = http.createServer(function(req, res) {
res.writeHead(200, {
'Content-Length': mockFile.length,
'Content-Type': 'application/plain',
'Content-Disposition': contentDisposition
});
res.end(mockFile);
downloadServer.close();
});
downloadServer.listen(0, '127.0.0.1', function() {
const port = downloadServer.address().port;
const url = "http://127.0.0.1:" + port + '/';
ipcRenderer.sendSync('set-download-option', false, true);
w.loadURL(url);
ipcRenderer.once('download-error', function(event, downloadUrl, filename, error) {
assert.equal(downloadUrl, url);
assert.equal(filename, 'mockFile.txt');
assert.equal(error, 'Object has been destroyed');
done();
});
});
});
});
return describe('DownloadItem', function() {
var assertDownload, contentDisposition, downloadFilePath, downloadServer, mockPDF;
mockPDF = new Buffer(1024 * 1024 * 5);
@ -173,7 +217,7 @@ describe('session module', function() {
return downloadServer.listen(0, '127.0.0.1', function() {
var port;
port = downloadServer.address().port;
ipcRenderer.sendSync('set-download-option', false);
ipcRenderer.sendSync('set-download-option', false, false);
w.loadURL(url + ":" + port);
return ipcRenderer.once('download-done', function(event, state, url, mimeType, receivedBytes, totalBytes, disposition, filename) {
assertDownload(event, state, url, mimeType, receivedBytes, totalBytes, disposition, filename, port);
@ -185,7 +229,7 @@ describe('session module', function() {
return downloadServer.listen(0, '127.0.0.1', function() {
var port, webview;
port = downloadServer.address().port;
ipcRenderer.sendSync('set-download-option', false);
ipcRenderer.sendSync('set-download-option', false, false);
webview = new WebView;
webview.src = "file://" + fixtures + "/api/blank.html";
webview.addEventListener('did-finish-load', function() {
@ -199,11 +243,11 @@ describe('session module', function() {
return document.body.appendChild(webview);
});
});
return it('can cancel download', function(done) {
it('can cancel download', function(done) {
return downloadServer.listen(0, '127.0.0.1', function() {
var port;
port = downloadServer.address().port;
ipcRenderer.sendSync('set-download-option', true);
ipcRenderer.sendSync('set-download-option', true, false);
w.loadURL(url + ":" + port + "/");
return ipcRenderer.once('download-done', function(event, state, url, mimeType, receivedBytes, totalBytes, disposition, filename) {
assert.equal(state, 'cancelled');

View file

@ -0,0 +1,5 @@
<script>
navigator.geolocation.getCurrentPosition(() => {}, (err) => {
require('electron').ipcRenderer.sendToHost('message', err.message);
});
</script>

View file

@ -0,0 +1,7 @@
<script>
navigator.webkitGetUserMedia({ audio: true, video: true }, function(mediaStream) {
}, function(err) {
require('electron').ipcRenderer.sendToHost('message', err.name);
});
</script>

View file

@ -0,0 +1,5 @@
<script>
navigator.requestMIDIAccess({sysex: true}).then(() => {}, (err) => {
require('electron').ipcRenderer.sendToHost('message', err.name);
});
</script>

View file

@ -102,23 +102,35 @@ app.on('ready', function() {
// For session's download test, listen 'will-download' event in browser, and
// reply the result to renderer for verifying
var downloadFilePath = path.join(__dirname, '..', 'fixtures', 'mock.pdf');
ipcMain.on('set-download-option', function(event, need_cancel) {
window.webContents.session.once('will-download',
function(e, item, webContents) {
item.setSavePath(downloadFilePath);
item.on('done', function(e, state) {
window.webContents.send('download-done',
state,
item.getURL(),
item.getMimeType(),
item.getReceivedBytes(),
item.getTotalBytes(),
item.getContentDisposition(),
item.getFilename());
});
if (need_cancel)
item.cancel();
ipcMain.on('set-download-option', function(event, need_cancel, prevent_default) {
window.webContents.session.once('will-download', function(e, item, webContents) {
if (prevent_default) {
e.preventDefault();
const url = item.getURL();
const filename = item.getFilename();
setImmediate(function() {
try {
item.getURL();
} catch(err) {
window.webContents.send('download-error', url, filename, err.message);
}
});
} else {
item.setSavePath(downloadFilePath);
item.on('done', function(e, state) {
window.webContents.send('download-done',
state,
item.getURL(),
item.getMimeType(),
item.getReceivedBytes(),
item.getTotalBytes(),
item.getContentDisposition(),
item.getFilename());
});
if (need_cancel)
item.cancel();
}
});
event.returnValue = "done";
});
});

View file

@ -624,7 +624,7 @@ describe('<webview> tag', function() {
return document.body.appendChild(webview);
});
});
return xdescribe('did-change-theme-color event', function() {
xdescribe('did-change-theme-color event', function() {
return it('emits when theme color changes', function(done) {
webview.addEventListener('did-change-theme-color', function() {
return done();
@ -633,4 +633,55 @@ describe('<webview> tag', function() {
return document.body.appendChild(webview);
});
});
describe('permission-request event', function() {
function setUpRequestHandler(webview, requested_permission) {
const session = require('electron').remote.session;
var listener = function(webContents, permission, callback) {
if (webContents.getId() === webview.getId() ) {
assert.equal(permission, requested_permission);
callback(false);
}
};
session.fromPartition(webview.partition).setPermissionRequestHandler(listener);
}
it ('emits when using navigator.getUserMedia api', function(done) {
webview.addEventListener('ipc-message', function(e) {
assert(e.channel, 'message');
assert(e.args, ['PermissionDeniedError']);
done();
});
webview.src = "file://" + fixtures + "/pages/permissions/media.html";
webview.partition = "permissionTest";
webview.setAttribute('nodeintegration', 'on');
setUpRequestHandler(webview, "media");
document.body.appendChild(webview);
});
it ('emits when using navigator.geolocation api', function(done) {
webview.addEventListener('ipc-message', function(e) {
assert(e.channel, 'message');
assert(e.args, ['ERROR(1): User denied Geolocation']);
done();
});
webview.src = "file://" + fixtures + "/pages/permissions/geolocation.html";
webview.partition = "permissionTest";
webview.setAttribute('nodeintegration', 'on');
setUpRequestHandler(webview, "geolocation");
document.body.appendChild(webview);
});
it ('emits when using navigator.requestMIDIAccess api', function(done) {
webview.addEventListener('ipc-message', function(e) {
assert(e.channel, 'message');
assert(e.args, ['SecurityError']);
done();
});
webview.src = "file://" + fixtures + "/pages/permissions/midi.html";
webview.partition = "permissionTest";
webview.setAttribute('nodeintegration', 'on');
setUpRequestHandler(webview, "midiSysex");
document.body.appendChild(webview);
});
});
});

2
vendor/brightray vendored

@ -1 +1 @@
Subproject commit ea6011bc9607f321258bf93e510f56f031973230
Subproject commit 2a5cd7178b641de91ca6eb0bca826fea588f923a

2
vendor/native_mate vendored

@ -1 +1 @@
Subproject commit a3dcf8ced663e974ac94ad5e50a1d25a43995a9d
Subproject commit e719eab878c264bb03188d0cd6eb9ad6882bc13a