Merge remote-tracking branch 'atom/master'
This commit is contained in:
commit
7923e19553
69 changed files with 908 additions and 213 deletions
2
atom.gyp
2
atom.gyp
|
@ -4,7 +4,7 @@
|
|||
'product_name%': 'Electron',
|
||||
'company_name%': 'GitHub, Inc',
|
||||
'company_abbr%': 'github',
|
||||
'version%': '0.33.0',
|
||||
'version%': '0.33.3',
|
||||
},
|
||||
'includes': [
|
||||
'filenames.gypi',
|
||||
|
|
201
atom/browser/api/atom_api_download_item.cc
Normal file
201
atom/browser/api/atom_api_download_item.cc
Normal file
|
@ -0,0 +1,201 @@
|
|||
// Copyright (c) 2015 GitHub, Inc.
|
||||
// Use of this source code is governed by the MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "atom/browser/api/atom_api_download_item.h"
|
||||
|
||||
#include <map>
|
||||
|
||||
#include "atom/common/native_mate_converters/callback.h"
|
||||
#include "atom/common/native_mate_converters/file_path_converter.h"
|
||||
#include "atom/common/native_mate_converters/gurl_converter.h"
|
||||
#include "atom/common/node_includes.h"
|
||||
#include "base/memory/linked_ptr.h"
|
||||
#include "base/strings/utf_string_conversions.h"
|
||||
#include "native_mate/dictionary.h"
|
||||
#include "net/base/filename_util.h"
|
||||
|
||||
namespace mate {
|
||||
|
||||
template<>
|
||||
struct Converter<content::DownloadItem::DownloadState> {
|
||||
static v8::Local<v8::Value> ToV8(v8::Isolate* isolate,
|
||||
content::DownloadItem::DownloadState state) {
|
||||
std::string download_state;
|
||||
switch (state) {
|
||||
case content::DownloadItem::COMPLETE:
|
||||
download_state = "completed";
|
||||
break;
|
||||
case content::DownloadItem::CANCELLED:
|
||||
download_state = "cancelled";
|
||||
break;
|
||||
case content::DownloadItem::INTERRUPTED:
|
||||
download_state = "interrupted";
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return ConvertToV8(isolate, download_state);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace mate
|
||||
|
||||
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) {
|
||||
download_item_->AddObserver(this);
|
||||
}
|
||||
|
||||
DownloadItem::~DownloadItem() {
|
||||
Destroy();
|
||||
}
|
||||
|
||||
void DownloadItem::Destroy() {
|
||||
if (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;
|
||||
}
|
||||
}
|
||||
|
||||
bool DownloadItem::IsDestroyed() const {
|
||||
return download_item_ == nullptr;
|
||||
}
|
||||
|
||||
void DownloadItem::OnDownloadUpdated(content::DownloadItem* item) {
|
||||
download_item_->IsDone() ? Emit("done", item->GetState()) : Emit("updated");
|
||||
}
|
||||
|
||||
void DownloadItem::OnDownloadDestroyed(content::DownloadItem* download) {
|
||||
Destroy();
|
||||
}
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
void DownloadItem::Pause() {
|
||||
download_item_->Pause();
|
||||
}
|
||||
|
||||
void DownloadItem::Resume() {
|
||||
download_item_->Resume();
|
||||
}
|
||||
|
||||
void DownloadItem::Cancel() {
|
||||
download_item_->Cancel(true);
|
||||
}
|
||||
|
||||
mate::ObjectTemplateBuilder DownloadItem::GetObjectTemplateBuilder(
|
||||
v8::Isolate* isolate) {
|
||||
return mate::ObjectTemplateBuilder(isolate)
|
||||
.SetMethod("pause", &DownloadItem::Pause)
|
||||
.SetMethod("resume", &DownloadItem::Resume)
|
||||
.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);
|
||||
}
|
||||
|
||||
void SetWrapDownloadItem(const WrapDownloadItemCallback& callback) {
|
||||
g_wrap_download_item = callback;
|
||||
}
|
||||
|
||||
void ClearWrapDownloadItem() {
|
||||
g_wrap_download_item.Reset();
|
||||
}
|
||||
|
||||
// static
|
||||
mate::Handle<DownloadItem> DownloadItem::Create(
|
||||
v8::Isolate* isolate, content::DownloadItem* item) {
|
||||
auto handle = mate::CreateHandle(isolate, new DownloadItem(item));
|
||||
g_wrap_download_item.Run(handle.ToV8());
|
||||
g_download_item_objects[item->GetId()] = make_linked_ptr(
|
||||
new v8::Global<v8::Value>(isolate, handle.ToV8()));
|
||||
return handle;
|
||||
}
|
||||
|
||||
// static
|
||||
void* DownloadItem::UserDataKey() {
|
||||
return &kDownloadItemSavePathKey;
|
||||
}
|
||||
|
||||
} // namespace api
|
||||
|
||||
} // namespace atom
|
||||
|
||||
namespace {
|
||||
|
||||
void Initialize(v8::Local<v8::Object> exports, v8::Local<v8::Value> unused,
|
||||
v8::Local<v8::Context> context, void* priv) {
|
||||
v8::Isolate* isolate = context->GetIsolate();
|
||||
mate::Dictionary dict(isolate, exports);
|
||||
dict.SetMethod("_setWrapDownloadItem", &atom::api::SetWrapDownloadItem);
|
||||
dict.SetMethod("_clearWrapDownloadItem", &atom::api::ClearWrapDownloadItem);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
NODE_MODULE_CONTEXT_AWARE_BUILTIN(atom_browser_download_item, Initialize);
|
72
atom/browser/api/atom_api_download_item.h
Normal file
72
atom/browser/api/atom_api_download_item.h
Normal file
|
@ -0,0 +1,72 @@
|
|||
// Copyright (c) 2015 GitHub, Inc.
|
||||
// Use of this source code is governed by the MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef ATOM_BROWSER_API_ATOM_API_DOWNLOAD_ITEM_H_
|
||||
#define ATOM_BROWSER_API_ATOM_API_DOWNLOAD_ITEM_H_
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "atom/browser/api/trackable_object.h"
|
||||
#include "base/files/file_path.h"
|
||||
#include "content/public/browser/download_item.h"
|
||||
#include "native_mate/handle.h"
|
||||
#include "url/gurl.h"
|
||||
|
||||
namespace atom {
|
||||
|
||||
namespace api {
|
||||
|
||||
class DownloadItem : public mate::EventEmitter,
|
||||
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();
|
||||
|
||||
protected:
|
||||
explicit DownloadItem(content::DownloadItem* download_item);
|
||||
~DownloadItem();
|
||||
|
||||
// Override content::DownloadItem::Observer methods
|
||||
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:
|
||||
// mate::Wrappable:
|
||||
mate::ObjectTemplateBuilder GetObjectTemplateBuilder(
|
||||
v8::Isolate* isolate) override;
|
||||
bool IsDestroyed() const override;
|
||||
|
||||
void Destroy();
|
||||
|
||||
content::DownloadItem* download_item_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(DownloadItem);
|
||||
};
|
||||
|
||||
} // namespace api
|
||||
|
||||
} // namespace atom
|
||||
|
||||
#endif // ATOM_BROWSER_API_ATOM_API_DOWNLOAD_ITEM_H_
|
|
@ -8,6 +8,7 @@
|
|||
#include <vector>
|
||||
|
||||
#include "atom/browser/api/atom_api_cookies.h"
|
||||
#include "atom/browser/api/atom_api_download_item.h"
|
||||
#include "atom/browser/atom_browser_context.h"
|
||||
#include "atom/browser/api/atom_api_web_contents.h"
|
||||
#include "atom/common/native_mate_converters/callback.h"
|
||||
|
@ -101,19 +102,6 @@ struct Converter<ClearStorageDataOptions> {
|
|||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct Converter<content::DownloadItem*> {
|
||||
static v8::Local<v8::Value> ToV8(v8::Isolate* isolate,
|
||||
content::DownloadItem* val) {
|
||||
mate::Dictionary dict(isolate, v8::Object::New(isolate));
|
||||
dict.Set("url", val->GetURL());
|
||||
dict.Set("filename", val->GetSuggestedFilename());
|
||||
dict.Set("mimeType", val->GetMimeType());
|
||||
dict.Set("hasUserGesture", val->HasUserGesture());
|
||||
return dict.GetHandle();
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace mate
|
||||
|
||||
namespace atom {
|
||||
|
@ -245,11 +233,12 @@ Session::~Session() {
|
|||
}
|
||||
|
||||
void Session::OnDownloadCreated(content::DownloadManager* manager,
|
||||
content::DownloadItem* item) {
|
||||
content::DownloadItem* item) {
|
||||
auto web_contents = item->GetWebContents();
|
||||
bool prevent_default = Emit("will-download", item,
|
||||
api::WebContents::CreateFrom(isolate(),
|
||||
web_contents));
|
||||
bool prevent_default = Emit(
|
||||
"will-download",
|
||||
DownloadItem::Create(isolate(), item),
|
||||
api::WebContents::CreateFrom(isolate(), web_contents));
|
||||
if (prevent_default) {
|
||||
item->Cancel(true);
|
||||
item->Remove();
|
||||
|
|
|
@ -120,6 +120,33 @@ struct Converter<WindowOpenDisposition> {
|
|||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct Converter<net::HttpResponseHeaders*> {
|
||||
static v8::Local<v8::Value> ToV8(v8::Isolate* isolate,
|
||||
net::HttpResponseHeaders* headers) {
|
||||
base::DictionaryValue response_headers;
|
||||
if (headers) {
|
||||
void* iter = nullptr;
|
||||
std::string key;
|
||||
std::string value;
|
||||
while (headers->EnumerateHeaderLines(&iter, &key, &value)) {
|
||||
key = base::StringToLowerASCII(key);
|
||||
value = base::StringToLowerASCII(value);
|
||||
if (response_headers.HasKey(key)) {
|
||||
base::ListValue* values = nullptr;
|
||||
if (response_headers.GetList(key, &values))
|
||||
values->AppendString(value);
|
||||
} else {
|
||||
scoped_ptr<base::ListValue> values(new base::ListValue());
|
||||
values->AppendString(value);
|
||||
response_headers.Set(key, values.Pass());
|
||||
}
|
||||
}
|
||||
}
|
||||
return ConvertToV8(isolate, response_headers);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace mate
|
||||
|
||||
|
||||
|
@ -131,7 +158,7 @@ namespace {
|
|||
|
||||
v8::Persistent<v8::ObjectTemplate> template_;
|
||||
|
||||
// The wrapWebContents funtion which is implemented in JavaScript
|
||||
// The wrapWebContents function which is implemented in JavaScript
|
||||
using WrapWebContentsCallback = base::Callback<void(v8::Local<v8::Value>)>;
|
||||
WrapWebContentsCallback g_wrap_web_contents;
|
||||
|
||||
|
@ -201,7 +228,7 @@ WebContents::WebContents(v8::Isolate* isolate,
|
|||
AttachAsUserData(web_contents);
|
||||
InitWithWebContents(web_contents);
|
||||
|
||||
// Save the preferences.
|
||||
// Save the preferences in C++.
|
||||
base::DictionaryValue web_preferences;
|
||||
mate::ConvertFromV8(isolate, options.GetHandle(), &web_preferences);
|
||||
new WebContentsPreferences(web_contents, &web_preferences);
|
||||
|
@ -414,30 +441,6 @@ void WebContents::DidStopLoading() {
|
|||
|
||||
void WebContents::DidGetResourceResponseStart(
|
||||
const content::ResourceRequestDetails& details) {
|
||||
v8::Locker locker(isolate());
|
||||
v8::HandleScope handle_scope(isolate());
|
||||
base::DictionaryValue response_headers;
|
||||
|
||||
net::HttpResponseHeaders* headers = details.headers.get();
|
||||
if (!headers)
|
||||
return;
|
||||
void* iter = nullptr;
|
||||
std::string key;
|
||||
std::string value;
|
||||
while (headers->EnumerateHeaderLines(&iter, &key, &value)) {
|
||||
key = base::StringToLowerASCII(key);
|
||||
value = base::StringToLowerASCII(value);
|
||||
if (response_headers.HasKey(key)) {
|
||||
base::ListValue* values = nullptr;
|
||||
if (response_headers.GetList(key, &values))
|
||||
values->AppendString(value);
|
||||
} else {
|
||||
scoped_ptr<base::ListValue> values(new base::ListValue());
|
||||
values->AppendString(value);
|
||||
response_headers.Set(key, values.Pass());
|
||||
}
|
||||
}
|
||||
|
||||
Emit("did-get-response-details",
|
||||
details.socket_address.IsEmpty(),
|
||||
details.url,
|
||||
|
@ -445,7 +448,7 @@ void WebContents::DidGetResourceResponseStart(
|
|||
details.http_response_code,
|
||||
details.method,
|
||||
details.referrer,
|
||||
response_headers);
|
||||
details.headers.get());
|
||||
}
|
||||
|
||||
void WebContents::DidGetRedirectForResourceRequest(
|
||||
|
@ -454,7 +457,11 @@ void WebContents::DidGetRedirectForResourceRequest(
|
|||
Emit("did-get-redirect-request",
|
||||
details.url,
|
||||
details.new_url,
|
||||
(details.resource_type == content::RESOURCE_TYPE_MAIN_FRAME));
|
||||
(details.resource_type == content::RESOURCE_TYPE_MAIN_FRAME),
|
||||
details.http_response_code,
|
||||
details.method,
|
||||
details.referrer,
|
||||
details.headers.get());
|
||||
}
|
||||
|
||||
void WebContents::DidNavigateMainFrame(
|
||||
|
@ -880,6 +887,12 @@ bool WebContents::IsGuest() const {
|
|||
return type_ == WEB_VIEW;
|
||||
}
|
||||
|
||||
v8::Local<v8::Value> WebContents::GetWebPreferences(v8::Isolate* isolate) {
|
||||
WebContentsPreferences* web_preferences =
|
||||
WebContentsPreferences::FromWebContents(web_contents());
|
||||
return mate::ConvertToV8(isolate, *web_preferences->web_preferences());
|
||||
}
|
||||
|
||||
mate::ObjectTemplateBuilder WebContents::GetObjectTemplateBuilder(
|
||||
v8::Isolate* isolate) {
|
||||
if (template_.IsEmpty())
|
||||
|
@ -935,6 +948,7 @@ mate::ObjectTemplateBuilder WebContents::GetObjectTemplateBuilder(
|
|||
.SetMethod("setSize", &WebContents::SetSize)
|
||||
.SetMethod("setAllowTransparency", &WebContents::SetAllowTransparency)
|
||||
.SetMethod("isGuest", &WebContents::IsGuest)
|
||||
.SetMethod("getWebPreferences", &WebContents::GetWebPreferences)
|
||||
.SetMethod("hasServiceWorker", &WebContents::HasServiceWorker)
|
||||
.SetMethod("unregisterServiceWorker",
|
||||
&WebContents::UnregisterServiceWorker)
|
||||
|
@ -988,7 +1002,7 @@ mate::Handle<WebContents> WebContents::CreateFrom(
|
|||
// static
|
||||
mate::Handle<WebContents> WebContents::Create(
|
||||
v8::Isolate* isolate, const mate::Dictionary& options) {
|
||||
auto handle = mate::CreateHandle(isolate, new WebContents(isolate, options));
|
||||
auto handle = mate::CreateHandle(isolate, new WebContents(isolate, options));
|
||||
g_wrap_web_contents.Run(handle.ToV8());
|
||||
return handle;
|
||||
}
|
||||
|
|
|
@ -132,6 +132,9 @@ class WebContents : public mate::TrackableObject<WebContents>,
|
|||
void SetAllowTransparency(bool allow);
|
||||
bool IsGuest() const;
|
||||
|
||||
// Returns the web preferences of current WebContents.
|
||||
v8::Local<v8::Value> GetWebPreferences(v8::Isolate* isolate);
|
||||
|
||||
protected:
|
||||
explicit WebContents(content::WebContents* web_contents);
|
||||
WebContents(v8::Isolate* isolate, const mate::Dictionary& options);
|
||||
|
|
|
@ -82,6 +82,10 @@ Window::Window(v8::Isolate* isolate, const mate::Dictionary& options) {
|
|||
web_contents_.Reset(isolate, web_contents.ToV8());
|
||||
api_web_contents_ = web_contents.get();
|
||||
|
||||
// Keep a copy of the options for later use.
|
||||
mate::Dictionary(isolate, web_contents->GetWrapper(isolate)).Set(
|
||||
"browserWindowOptions", options);
|
||||
|
||||
// Creates BrowserWindow.
|
||||
window_.reset(NativeWindow::Create(web_contents->managed_web_contents(),
|
||||
options));
|
||||
|
|
|
@ -2,6 +2,7 @@ EventEmitter = require('events').EventEmitter
|
|||
|
||||
bindings = process.atomBinding 'app'
|
||||
sessionBindings = process.atomBinding 'session'
|
||||
downloadItemBindings = process.atomBinding 'download_item'
|
||||
|
||||
app = bindings.app
|
||||
app.__proto__ = EventEmitter.prototype
|
||||
|
@ -10,6 +11,15 @@ wrapSession = (session) ->
|
|||
# session is an Event Emitter.
|
||||
session.__proto__ = EventEmitter.prototype
|
||||
|
||||
wrapDownloadItem = (download_item) ->
|
||||
# download_item is an Event Emitter.
|
||||
download_item.__proto__ = EventEmitter.prototype
|
||||
# Be compatible with old APIs.
|
||||
download_item.url = download_item.getUrl()
|
||||
download_item.filename = download_item.getFilename()
|
||||
download_item.mimeType = download_item.getMimeType()
|
||||
download_item.hasUserGesture = download_item.hasUserGesture()
|
||||
|
||||
app.setApplicationMenu = (menu) ->
|
||||
require('menu').setApplicationMenu menu
|
||||
|
||||
|
@ -51,5 +61,8 @@ app.on 'activate', (event, hasVisibleWindows) -> @emit 'activate-with-no-open-wi
|
|||
sessionBindings._setWrapSession wrapSession
|
||||
process.once 'exit', sessionBindings._clearWrapSession
|
||||
|
||||
downloadItemBindings._setWrapDownloadItem wrapDownloadItem
|
||||
process.once 'exit', downloadItemBindings._clearWrapDownloadItem
|
||||
|
||||
# Only one App object pemitted.
|
||||
module.exports = app
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
|
||||
#include "atom/browser/atom_browser_main_parts.h"
|
||||
#include "atom/browser/atom_download_manager_delegate.h"
|
||||
#include "atom/browser/atom_ssl_config_service.h"
|
||||
#include "atom/browser/browser.h"
|
||||
#include "atom/browser/net/atom_url_request_job_factory.h"
|
||||
#include "atom/browser/net/asar/asar_protocol_handler.h"
|
||||
|
@ -156,6 +157,10 @@ content::BrowserPluginGuestManager* AtomBrowserContext::GetGuestManager() {
|
|||
return guest_manager_.get();
|
||||
}
|
||||
|
||||
net::SSLConfigService* AtomBrowserContext::CreateSSLConfigService() {
|
||||
return new AtomSSLConfigService;
|
||||
}
|
||||
|
||||
void AtomBrowserContext::RegisterPrefs(PrefRegistrySimple* pref_registry) {
|
||||
pref_registry->RegisterFilePathPref(prefs::kSelectFileLastDirectory,
|
||||
base::FilePath());
|
||||
|
|
|
@ -27,6 +27,7 @@ class AtomBrowserContext : public brightray::BrowserContext {
|
|||
content::URLRequestInterceptorScopedVector* interceptors) override;
|
||||
net::HttpCache::BackendFactory* CreateHttpCacheBackendFactory(
|
||||
const base::FilePath& base_path) override;
|
||||
net::SSLConfigService* CreateSSLConfigService() override;
|
||||
|
||||
// content::BrowserContext:
|
||||
content::DownloadManagerDelegate* GetDownloadManagerDelegate() override;
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
|
||||
#include <string>
|
||||
|
||||
#include "atom/browser/api/atom_api_download_item.h"
|
||||
#include "atom/browser/atom_browser_context.h"
|
||||
#include "atom/browser/native_window.h"
|
||||
#include "atom/browser/ui/file_dialog.h"
|
||||
|
@ -73,18 +74,19 @@ void AtomDownloadManagerDelegate::OnDownloadPathGenerated(
|
|||
if (relay)
|
||||
window = relay->window.get();
|
||||
|
||||
file_dialog::Filters filters;
|
||||
base::FilePath path;
|
||||
if (!file_dialog::ShowSaveDialog(window, item->GetURL().spec(), default_path,
|
||||
filters, &path)) {
|
||||
return;
|
||||
if (file_dialog::ShowSaveDialog(window, item->GetURL().spec(), default_path,
|
||||
file_dialog::Filters(), &path)) {
|
||||
// Remember the last selected download directory.
|
||||
AtomBrowserContext* browser_context = static_cast<AtomBrowserContext*>(
|
||||
download_manager_->GetBrowserContext());
|
||||
browser_context->prefs()->SetFilePath(prefs::kDownloadDefaultDirectory,
|
||||
path.DirName());
|
||||
}
|
||||
|
||||
// Remeber the last selected download directory.
|
||||
AtomBrowserContext* browser_context = static_cast<AtomBrowserContext*>(
|
||||
download_manager_->GetBrowserContext());
|
||||
browser_context->prefs()->SetFilePath(prefs::kDownloadDefaultDirectory,
|
||||
path.DirName());
|
||||
// Running the DownloadTargetCallback with an empty FilePath signals that the
|
||||
// download should be cancelled.
|
||||
// If user cancels the file save dialog, run the callback with empty FilePath.
|
||||
callback.Run(path,
|
||||
content::DownloadItem::TARGET_DISPOSITION_PROMPT,
|
||||
content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS, path);
|
||||
|
@ -100,6 +102,25 @@ bool AtomDownloadManagerDelegate::DetermineDownloadTarget(
|
|||
const content::DownloadTargetCallback& callback) {
|
||||
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
|
||||
|
||||
if (!download->GetForcedFilePath().empty()) {
|
||||
callback.Run(download->GetForcedFilePath(),
|
||||
content::DownloadItem::TARGET_DISPOSITION_OVERWRITE,
|
||||
content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS,
|
||||
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;
|
||||
}
|
||||
|
||||
AtomBrowserContext* browser_context = static_cast<AtomBrowserContext*>(
|
||||
download_manager_->GetBrowserContext());
|
||||
base::FilePath default_download_path = browser_context->prefs()->GetFilePath(
|
||||
|
@ -110,14 +131,6 @@ bool AtomDownloadManagerDelegate::DetermineDownloadTarget(
|
|||
default_download_path = path.Append(FILE_PATH_LITERAL("Downloads"));
|
||||
}
|
||||
|
||||
if (!download->GetForcedFilePath().empty()) {
|
||||
callback.Run(download->GetForcedFilePath(),
|
||||
content::DownloadItem::TARGET_DISPOSITION_OVERWRITE,
|
||||
content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS,
|
||||
download->GetForcedFilePath());
|
||||
return true;
|
||||
}
|
||||
|
||||
CreateDownloadPathCallback download_path_callback =
|
||||
base::Bind(&AtomDownloadManagerDelegate::OnDownloadPathGenerated,
|
||||
weak_ptr_factory_.GetWeakPtr(),
|
||||
|
|
47
atom/browser/atom_ssl_config_service.cc
Normal file
47
atom/browser/atom_ssl_config_service.cc
Normal file
|
@ -0,0 +1,47 @@
|
|||
// Copyright (c) 2015 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_ssl_config_service.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "base/command_line.h"
|
||||
#include "atom/common/options_switches.h"
|
||||
#include "content/public/browser/browser_thread.h"
|
||||
#include "net/socket/ssl_client_socket.h"
|
||||
|
||||
namespace atom {
|
||||
|
||||
namespace {
|
||||
|
||||
uint16 GetSSLProtocolVersion(const std::string& version_string) {
|
||||
uint16 version = 0; // Invalid
|
||||
if (version_string == "tls1")
|
||||
version = net::SSL_PROTOCOL_VERSION_TLS1;
|
||||
else if (version_string == "tls1.1")
|
||||
version = net::SSL_PROTOCOL_VERSION_TLS1_1;
|
||||
else if (version_string == "tls1.2")
|
||||
version = net::SSL_PROTOCOL_VERSION_TLS1_2;
|
||||
return version;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
AtomSSLConfigService::AtomSSLConfigService() {
|
||||
auto cmd_line = base::CommandLine::ForCurrentProcess();
|
||||
if (cmd_line->HasSwitch(switches::kSSLVersionFallbackMin)) {
|
||||
auto version_string =
|
||||
cmd_line->GetSwitchValueASCII(switches::kSSLVersionFallbackMin);
|
||||
config_.version_fallback_min = GetSSLProtocolVersion(version_string);
|
||||
}
|
||||
}
|
||||
|
||||
AtomSSLConfigService::~AtomSSLConfigService() {
|
||||
}
|
||||
|
||||
void AtomSSLConfigService::GetSSLConfig(net::SSLConfig* config) {
|
||||
*config = config_;
|
||||
}
|
||||
|
||||
} // namespace atom
|
28
atom/browser/atom_ssl_config_service.h
Normal file
28
atom/browser/atom_ssl_config_service.h
Normal file
|
@ -0,0 +1,28 @@
|
|||
// Copyright (c) 2015 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_SSL_CONFIG_SERVICE_H_
|
||||
#define ATOM_BROWSER_ATOM_SSL_CONFIG_SERVICE_H_
|
||||
|
||||
#include "net/ssl/ssl_config_service.h"
|
||||
|
||||
namespace atom {
|
||||
|
||||
class AtomSSLConfigService : public net::SSLConfigService {
|
||||
public:
|
||||
AtomSSLConfigService();
|
||||
~AtomSSLConfigService() override;
|
||||
|
||||
// net::SSLConfigService:
|
||||
void GetSSLConfig(net::SSLConfig* config) override;
|
||||
|
||||
private:
|
||||
net::SSLConfig config_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(AtomSSLConfigService);
|
||||
};
|
||||
|
||||
} // namespace atom
|
||||
|
||||
#endif // ATOM_BROWSER_ATOM_SSL_CONFIG_SERVICE_H_
|
|
@ -84,6 +84,8 @@ createGuest = (embedder, params) ->
|
|||
if params.allowtransparency?
|
||||
@setAllowTransparency params.allowtransparency
|
||||
|
||||
guest.allowPopups = params.allowpopups
|
||||
|
||||
# Dispatch events to embedder.
|
||||
for event in supportedWebViewEvents
|
||||
do (event) ->
|
||||
|
|
|
@ -4,6 +4,17 @@ BrowserWindow = require 'browser-window'
|
|||
|
||||
frameToGuest = {}
|
||||
|
||||
# Merge |options| with the |embedder|'s window's options.
|
||||
mergeBrowserWindowOptions = (embedder, options) ->
|
||||
if embedder.browserWindowOptions?
|
||||
# Inherit the original options if it is a BrowserWindow.
|
||||
options.__proto__ = embedder.browserWindowOptions
|
||||
else
|
||||
# Or only inherit web-preferences if it is a webview.
|
||||
options['web-preferences'] ?= {}
|
||||
options['web-preferences'].__proto__ = embedder.getWebPreferences()
|
||||
options
|
||||
|
||||
# Create a new guest created by |embedder| with |options|.
|
||||
createGuest = (embedder, url, frameName, options) ->
|
||||
guest = frameToGuest[frameName]
|
||||
|
@ -40,11 +51,12 @@ createGuest = (embedder, url, frameName, options) ->
|
|||
# Routed window.open messages.
|
||||
ipc.on 'ATOM_SHELL_GUEST_WINDOW_MANAGER_WINDOW_OPEN', (event, args...) ->
|
||||
[url, frameName, options] = args
|
||||
event.sender.emit 'new-window', event, url, frameName, 'new-window'
|
||||
if event.sender.isGuest() or event.defaultPrevented
|
||||
options = mergeBrowserWindowOptions event.sender, options
|
||||
event.sender.emit 'new-window', event, url, frameName, 'new-window', options
|
||||
if (event.sender.isGuest() and not event.sender.allowPopups) or event.defaultPrevented
|
||||
event.returnValue = null
|
||||
else
|
||||
event.returnValue = createGuest event.sender, args...
|
||||
event.returnValue = createGuest event.sender, url, frameName, options
|
||||
|
||||
ipc.on 'ATOM_SHELL_GUEST_WINDOW_MANAGER_WINDOW_CLOSE', (event, guestId) ->
|
||||
BrowserWindow.fromId(guestId)?.destroy()
|
||||
|
|
|
@ -68,6 +68,7 @@ NativeWindow::NativeWindow(
|
|||
const mate::Dictionary& options)
|
||||
: content::WebContentsObserver(inspectable_web_contents->GetWebContents()),
|
||||
has_frame_(true),
|
||||
force_using_draggable_region_(false),
|
||||
transparent_(false),
|
||||
enable_larger_than_screen_(false),
|
||||
is_closed_(false),
|
||||
|
@ -159,8 +160,13 @@ void NativeWindow::InitFromOptions(const mate::Dictionary& options) {
|
|||
// Then show it.
|
||||
bool show = true;
|
||||
options.Get(switches::kShow, &show);
|
||||
if (show)
|
||||
if (show) {
|
||||
Show();
|
||||
} else {
|
||||
// When RenderView is created it sets to visible, this is to prevent
|
||||
// breaking the visibility API.
|
||||
web_contents()->WasHidden();
|
||||
}
|
||||
}
|
||||
|
||||
void NativeWindow::SetSize(const gfx::Size& size) {
|
||||
|
@ -468,7 +474,7 @@ bool NativeWindow::OnMessageReceived(const IPC::Message& message) {
|
|||
void NativeWindow::UpdateDraggableRegions(
|
||||
const std::vector<DraggableRegion>& regions) {
|
||||
// Draggable region is not supported for non-frameless window.
|
||||
if (has_frame_)
|
||||
if (has_frame_ && !force_using_draggable_region_)
|
||||
return;
|
||||
draggable_region_ = DraggableRegionsToSkRegion(regions);
|
||||
}
|
||||
|
|
|
@ -219,6 +219,13 @@ class NativeWindow : public content::WebContentsObserver,
|
|||
bool enable_larger_than_screen() const { return enable_larger_than_screen_; }
|
||||
gfx::ImageSkia icon() const { return icon_; }
|
||||
|
||||
bool force_using_draggable_region() const {
|
||||
return force_using_draggable_region_;
|
||||
}
|
||||
void set_force_using_draggable_region(bool force) {
|
||||
force_using_draggable_region_ = true;
|
||||
}
|
||||
|
||||
void set_has_dialog_attached(bool has_dialog_attached) {
|
||||
has_dialog_attached_ = has_dialog_attached;
|
||||
}
|
||||
|
@ -257,6 +264,9 @@ class NativeWindow : public content::WebContentsObserver,
|
|||
// Whether window has standard frame.
|
||||
bool has_frame_;
|
||||
|
||||
// Force the window to be aware of draggable regions.
|
||||
bool force_using_draggable_region_;
|
||||
|
||||
// Whether window is transparent.
|
||||
bool transparent_;
|
||||
|
||||
|
|
|
@ -351,21 +351,19 @@ NativeWindowMac::NativeWindowMac(
|
|||
bool useStandardWindow = true;
|
||||
options.Get(switches::kStandardWindow, &useStandardWindow);
|
||||
|
||||
// New title bar styles are available in Yosemite or newer
|
||||
std::string titleBarStyle;
|
||||
if (base::mac::IsOSYosemiteOrLater())
|
||||
options.Get(switches::kTitleBarStyle, &titleBarStyle);
|
||||
|
||||
NSUInteger styleMask = NSTitledWindowMask | NSClosableWindowMask |
|
||||
NSMiniaturizableWindowMask | NSResizableWindowMask;
|
||||
if (!useStandardWindow || transparent() || !has_frame()) {
|
||||
styleMask |= NSTexturedBackgroundWindowMask;
|
||||
}
|
||||
|
||||
std::string titleBarStyle = "default";
|
||||
options.Get(switches::kTitleBarStyle, &titleBarStyle);
|
||||
|
||||
if (base::mac::IsOSYosemiteOrLater()) {
|
||||
// New title bar styles are available in Yosemite or newer
|
||||
if ((titleBarStyle == "hidden") || (titleBarStyle == "hidden-inset")) {
|
||||
styleMask |= NSFullSizeContentViewWindowMask;
|
||||
styleMask |= NSUnifiedTitleAndToolbarWindowMask;
|
||||
}
|
||||
if ((titleBarStyle == "hidden") || (titleBarStyle == "hidden-inset")) {
|
||||
styleMask |= NSFullSizeContentViewWindowMask;
|
||||
styleMask |= NSUnifiedTitleAndToolbarWindowMask;
|
||||
}
|
||||
|
||||
window_.reset([[AtomNSWindow alloc]
|
||||
|
@ -393,18 +391,18 @@ NativeWindowMac::NativeWindowMac(
|
|||
// We will manage window's lifetime ourselves.
|
||||
[window_ setReleasedWhenClosed:NO];
|
||||
|
||||
// Configure title bar look on Yosemite or newer
|
||||
if (base::mac::IsOSYosemiteOrLater()) {
|
||||
if ((titleBarStyle == "hidden") || (titleBarStyle == "hidden-inset")) {
|
||||
[window_ setTitlebarAppearsTransparent:YES];
|
||||
[window_ setTitleVisibility:NSWindowTitleHidden];
|
||||
if (titleBarStyle == "hidden-inset") {
|
||||
NSToolbar *toolbar = [[NSToolbar alloc] initWithIdentifier:@"titlebarStylingToolbar"];
|
||||
toolbar.showsBaselineSeparator = NO;
|
||||
[window_ setToolbar:toolbar];
|
||||
[toolbar release];
|
||||
}
|
||||
// Hide the title bar.
|
||||
if ((titleBarStyle == "hidden") || (titleBarStyle == "hidden-inset")) {
|
||||
[window_ setTitlebarAppearsTransparent:YES];
|
||||
[window_ setTitleVisibility:NSWindowTitleHidden];
|
||||
if (titleBarStyle == "hidden-inset") {
|
||||
base::scoped_nsobject<NSToolbar> toolbar(
|
||||
[[NSToolbar alloc] initWithIdentifier:@"titlebarStylingToolbar"]);
|
||||
[toolbar setShowsBaselineSeparator:NO];
|
||||
[window_ setToolbar:toolbar];
|
||||
}
|
||||
// We should be aware of draggable regions when using hidden titlebar.
|
||||
set_force_using_draggable_region(true);
|
||||
}
|
||||
|
||||
// On OS X the initial window size doesn't include window frame.
|
||||
|
@ -436,6 +434,11 @@ NativeWindowMac::NativeWindowMac(
|
|||
[view setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable];
|
||||
|
||||
InstallView();
|
||||
|
||||
// Install the DraggableRegionView if it is forced to use draggable regions
|
||||
// for normal window.
|
||||
if (has_frame() && force_using_draggable_region())
|
||||
InstallDraggableRegionView();
|
||||
}
|
||||
|
||||
NativeWindowMac::~NativeWindowMac() {
|
||||
|
@ -467,6 +470,8 @@ bool NativeWindowMac::IsFocused() {
|
|||
}
|
||||
|
||||
void NativeWindowMac::Show() {
|
||||
web_contents()->WasShown();
|
||||
|
||||
// This method is supposed to put focus on window, however if the app does not
|
||||
// have focus then "makeKeyAndOrderFront" will only show the window.
|
||||
[NSApp activateIgnoringOtherApps:YES];
|
||||
|
@ -475,11 +480,13 @@ void NativeWindowMac::Show() {
|
|||
}
|
||||
|
||||
void NativeWindowMac::ShowInactive() {
|
||||
web_contents()->WasShown();
|
||||
[window_ orderFrontRegardless];
|
||||
}
|
||||
|
||||
void NativeWindowMac::Hide() {
|
||||
[window_ orderOut:nil];
|
||||
web_contents()->WasHidden();
|
||||
}
|
||||
|
||||
bool NativeWindowMac::IsVisible() {
|
||||
|
|
|
@ -338,15 +338,18 @@ bool NativeWindowViews::IsFocused() {
|
|||
}
|
||||
|
||||
void NativeWindowViews::Show() {
|
||||
web_contents()->WasShown();
|
||||
window_->native_widget_private()->ShowWithWindowState(GetRestoredState());
|
||||
}
|
||||
|
||||
void NativeWindowViews::ShowInactive() {
|
||||
web_contents()->WasShown();
|
||||
window_->ShowInactive();
|
||||
}
|
||||
|
||||
void NativeWindowViews::Hide() {
|
||||
window_->Hide();
|
||||
web_contents()->WasHidden();
|
||||
}
|
||||
|
||||
bool NativeWindowViews::IsVisible() {
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
<key>CFBundleIconFile</key>
|
||||
<string>atom.icns</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>0.33.0</string>
|
||||
<string>0.33.3</string>
|
||||
<key>LSMinimumSystemVersion</key>
|
||||
<string>10.8.0</string>
|
||||
<key>NSMainNibFile</key>
|
||||
|
|
|
@ -56,8 +56,8 @@ END
|
|||
//
|
||||
|
||||
VS_VERSION_INFO VERSIONINFO
|
||||
FILEVERSION 0,33,0,0
|
||||
PRODUCTVERSION 0,33,0,0
|
||||
FILEVERSION 0,33,3,0
|
||||
PRODUCTVERSION 0,33,3,0
|
||||
FILEFLAGSMASK 0x3fL
|
||||
#ifdef _DEBUG
|
||||
FILEFLAGS 0x1L
|
||||
|
@ -74,12 +74,12 @@ BEGIN
|
|||
BEGIN
|
||||
VALUE "CompanyName", "GitHub, Inc."
|
||||
VALUE "FileDescription", "Electron"
|
||||
VALUE "FileVersion", "0.33.0"
|
||||
VALUE "FileVersion", "0.33.3"
|
||||
VALUE "InternalName", "electron.exe"
|
||||
VALUE "LegalCopyright", "Copyright (C) 2015 GitHub, Inc. All rights reserved."
|
||||
VALUE "OriginalFilename", "electron.exe"
|
||||
VALUE "ProductName", "Electron"
|
||||
VALUE "ProductVersion", "0.33.0"
|
||||
VALUE "ProductVersion", "0.33.3"
|
||||
VALUE "SquirrelAwareVersion", "1"
|
||||
END
|
||||
END
|
||||
|
|
|
@ -4,10 +4,7 @@
|
|||
|
||||
#include "atom/browser/ui/win/notify_icon.h"
|
||||
|
||||
#include <shobjidl.h>
|
||||
|
||||
#include "atom/browser/ui/win/notify_icon_host.h"
|
||||
#include "base/md5.h"
|
||||
#include "base/strings/string_number_conversions.h"
|
||||
#include "base/strings/utf_string_conversions.h"
|
||||
#include "base/win/windows_version.h"
|
||||
|
@ -28,31 +25,7 @@ NotifyIcon::NotifyIcon(NotifyIconHost* host,
|
|||
icon_id_(id),
|
||||
window_(window),
|
||||
message_id_(message),
|
||||
menu_model_(NULL),
|
||||
has_tray_app_id_hash_(false) {
|
||||
// NB: If we have an App Model ID, we should propagate that to the tray.
|
||||
// Doing this prevents duplicate items from showing up in the notification
|
||||
// preferences (i.e. "Always Show / Show notifications only / etc")
|
||||
PWSTR explicit_app_id;
|
||||
if (SUCCEEDED(GetCurrentProcessExplicitAppUserModelID(&explicit_app_id))) {
|
||||
// GUIDs and MD5 hashes are the same length. So convenient!
|
||||
base::MD5Sum(explicit_app_id,
|
||||
sizeof(wchar_t) * wcslen(explicit_app_id),
|
||||
reinterpret_cast<base::MD5Digest*>(&tray_app_id_hash_));
|
||||
|
||||
// Set the GUID to version 4 as described in RFC 4122, section 4.4.
|
||||
// The format of GUID version 4 must be like
|
||||
// xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx, where y is one of [8, 9, A, B].
|
||||
tray_app_id_hash_.Data3 &= 0x0fff;
|
||||
tray_app_id_hash_.Data3 |= 0x4000;
|
||||
|
||||
// Set y to one of [8, 9, A, B].
|
||||
tray_app_id_hash_.Data4[0] = 1;
|
||||
|
||||
has_tray_app_id_hash_ = true;
|
||||
CoTaskMemFree(explicit_app_id);
|
||||
}
|
||||
|
||||
menu_model_(NULL) {
|
||||
NOTIFYICONDATA icon_data;
|
||||
InitIconData(&icon_data);
|
||||
icon_data.uFlags |= NIF_MESSAGE;
|
||||
|
@ -81,10 +54,6 @@ void NotifyIcon::HandleClickEvent(const gfx::Point& cursor_pos,
|
|||
icon_id.uID = icon_id_;
|
||||
icon_id.hWnd = window_;
|
||||
icon_id.cbSize = sizeof(NOTIFYICONIDENTIFIER);
|
||||
if (has_tray_app_id_hash_)
|
||||
memcpy(reinterpret_cast<void*>(&icon_id.guidItem),
|
||||
&tray_app_id_hash_,
|
||||
sizeof(GUID));
|
||||
|
||||
RECT rect = { 0 };
|
||||
Shell_NotifyIconGetRect(&icon_id, &rect);
|
||||
|
@ -202,13 +171,6 @@ void NotifyIcon::InitIconData(NOTIFYICONDATA* icon_data) {
|
|||
icon_data->cbSize = sizeof(NOTIFYICONDATA);
|
||||
icon_data->hWnd = window_;
|
||||
icon_data->uID = icon_id_;
|
||||
|
||||
if (has_tray_app_id_hash_) {
|
||||
icon_data->uFlags |= NIF_GUID;
|
||||
memcpy(reinterpret_cast<void*>(&icon_data->guidItem),
|
||||
&tray_app_id_hash_,
|
||||
sizeof(GUID));
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace atom
|
||||
|
|
|
@ -79,10 +79,6 @@ class NotifyIcon : public TrayIcon {
|
|||
// The context menu.
|
||||
ui::SimpleMenuModel* menu_model_;
|
||||
|
||||
// A hash of the app model ID
|
||||
GUID tray_app_id_hash_;
|
||||
bool has_tray_app_id_hash_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(NotifyIcon);
|
||||
};
|
||||
|
||||
|
|
|
@ -40,6 +40,9 @@ WebContentsPreferences::WebContentsPreferences(
|
|||
base::DictionaryValue* web_preferences) {
|
||||
web_preferences_.Swap(web_preferences);
|
||||
web_contents->SetUserData(UserDataKey(), this);
|
||||
|
||||
// The "isGuest" is not a preferences field.
|
||||
web_preferences_.Remove("isGuest", nullptr);
|
||||
}
|
||||
|
||||
WebContentsPreferences::~WebContentsPreferences() {
|
||||
|
@ -94,7 +97,7 @@ void WebContentsPreferences::AppendExtraCommandLineSwitches(
|
|||
if (base::FilePath(preload).IsAbsolute())
|
||||
command_line->AppendSwitchNative(switches::kPreloadScript, preload);
|
||||
else
|
||||
LOG(ERROR) << "preload script must have abosulute path.";
|
||||
LOG(ERROR) << "preload script must have absolute path.";
|
||||
} else if (web_preferences.GetString(switches::kPreloadUrl, &preload)) {
|
||||
// Translate to file path if there is "preload-url" option.
|
||||
base::FilePath preload_path;
|
||||
|
|
|
@ -37,6 +37,9 @@ class WebContentsPreferences
|
|||
// $.extend(|web_preferences_|, |new_web_preferences|).
|
||||
void Merge(const base::DictionaryValue& new_web_preferences);
|
||||
|
||||
// Returns the web preferences.
|
||||
base::DictionaryValue* web_preferences() { return &web_preferences_; }
|
||||
|
||||
private:
|
||||
friend class content::WebContentsUserData<WebContentsPreferences>;
|
||||
|
||||
|
|
|
@ -115,6 +115,14 @@ bool FillFileInfoWithNode(Archive::FileInfo* info,
|
|||
Archive::Archive(const base::FilePath& path)
|
||||
: path_(path),
|
||||
file_(path_, base::File::FLAG_OPEN | base::File::FLAG_READ),
|
||||
#if defined(OS_WIN)
|
||||
fd_(_open_osfhandle(
|
||||
reinterpret_cast<intptr_t>(file_.GetPlatformFile()), 0)),
|
||||
#elif defined(OS_POSIX)
|
||||
fd_(file_.GetPlatformFile()),
|
||||
#else
|
||||
fd_(-1),
|
||||
#endif
|
||||
header_size_(0) {
|
||||
}
|
||||
|
||||
|
@ -271,17 +279,7 @@ bool Archive::CopyFileOut(const base::FilePath& path, base::FilePath* out) {
|
|||
}
|
||||
|
||||
int Archive::GetFD() const {
|
||||
if (!file_.IsValid())
|
||||
return -1;
|
||||
|
||||
#if defined(OS_WIN)
|
||||
return
|
||||
_open_osfhandle(reinterpret_cast<intptr_t>(file_.GetPlatformFile()), 0);
|
||||
#elif defined(OS_POSIX)
|
||||
return file_.GetPlatformFile();
|
||||
#else
|
||||
return -1;
|
||||
#endif
|
||||
return fd_;
|
||||
}
|
||||
|
||||
} // namespace asar
|
||||
|
|
|
@ -69,6 +69,7 @@ class Archive {
|
|||
private:
|
||||
base::FilePath path_;
|
||||
base::File file_;
|
||||
int fd_;
|
||||
uint32 header_size_;
|
||||
scoped_ptr<base::DictionaryValue> header_;
|
||||
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
|
||||
#define ATOM_MAJOR_VERSION 0
|
||||
#define ATOM_MINOR_VERSION 33
|
||||
#define ATOM_PATCH_VERSION 0
|
||||
#define ATOM_PATCH_VERSION 3
|
||||
|
||||
#define ATOM_VERSION_IS_RELEASE 1
|
||||
|
||||
|
|
|
@ -329,7 +329,7 @@ exports.wrapFsWithAsar = (fs) ->
|
|||
|
||||
buffer = new Buffer(info.size)
|
||||
fd = archive.getFd()
|
||||
retrun undefined unless fd >= 0
|
||||
return undefined unless fd >= 0
|
||||
|
||||
fs.readSync fd, buffer, 0, info.size, info.offset
|
||||
buffer.toString 'utf8'
|
||||
|
|
|
@ -1,8 +1,7 @@
|
|||
process = global.process
|
||||
fs = require 'fs'
|
||||
path = require 'path'
|
||||
timers = require 'timers'
|
||||
Module = require 'module'
|
||||
fs = require 'fs'
|
||||
path = require 'path'
|
||||
timers = require 'timers'
|
||||
Module = require 'module'
|
||||
|
||||
process.atomBinding = (name) ->
|
||||
try
|
||||
|
@ -37,6 +36,8 @@ wrapWithActivateUvLoop = (func) ->
|
|||
process.activateUvLoop()
|
||||
func.apply this, arguments
|
||||
process.nextTick = wrapWithActivateUvLoop process.nextTick
|
||||
global.setImmediate = wrapWithActivateUvLoop timers.setImmediate
|
||||
global.clearImmediate = timers.clearImmediate
|
||||
|
||||
if process.type is 'browser'
|
||||
# setTimeout needs to update the polling timeout of the event loop, when
|
||||
|
@ -45,10 +46,3 @@ if process.type is 'browser'
|
|||
# recalculate the timeout in browser process.
|
||||
global.setTimeout = wrapWithActivateUvLoop timers.setTimeout
|
||||
global.setInterval = wrapWithActivateUvLoop timers.setInterval
|
||||
global.setImmediate = wrapWithActivateUvLoop timers.setImmediate
|
||||
global.clearImmediate = wrapWithActivateUvLoop timers.clearImmediate
|
||||
else
|
||||
# There are no setImmediate under renderer process by default, so we need to
|
||||
# manually setup them here.
|
||||
global.setImmediate = setImmediate
|
||||
global.clearImmediate = clearImmediate
|
||||
|
|
|
@ -34,6 +34,7 @@ REFERENCE_MODULE(atom_browser_app);
|
|||
REFERENCE_MODULE(atom_browser_auto_updater);
|
||||
REFERENCE_MODULE(atom_browser_content_tracing);
|
||||
REFERENCE_MODULE(atom_browser_dialog);
|
||||
REFERENCE_MODULE(atom_browser_download_item);
|
||||
REFERENCE_MODULE(atom_browser_menu);
|
||||
REFERENCE_MODULE(atom_browser_power_monitor);
|
||||
REFERENCE_MODULE(atom_browser_power_save_blocker);
|
||||
|
|
|
@ -113,6 +113,10 @@ const char kDisableHttpCache[] = "disable-http-cache";
|
|||
// Register schemes to standard.
|
||||
const char kRegisterStandardSchemes[] = "register-standard-schemes";
|
||||
|
||||
// The minimum SSL/TLS version ("tls1", "tls1.1", or "tls1.2") that
|
||||
// TLS fallback will accept.
|
||||
const char kSSLVersionFallbackMin[] = "ssl-version-fallback-min";
|
||||
|
||||
// The browser process app model ID
|
||||
const char kAppUserModelId[] = "app-user-model-id";
|
||||
|
||||
|
|
|
@ -59,6 +59,7 @@ extern const char kPageVisibility[];
|
|||
|
||||
extern const char kDisableHttpCache[];
|
||||
extern const char kRegisterStandardSchemes[];
|
||||
extern const char kSSLVersionFallbackMin[];
|
||||
|
||||
extern const char kAppUserModelId[];
|
||||
|
||||
|
|
|
@ -98,6 +98,16 @@ void WebFrame::RegisterURLSchemeAsBypassingCsp(const std::string& scheme) {
|
|||
blink::WebString::fromUTF8(scheme));
|
||||
}
|
||||
|
||||
void WebFrame::RegisterURLSchemeAsPrivileged(const std::string& scheme) {
|
||||
// Register scheme to privileged list (https, wss, data, chrome-extension)
|
||||
blink::WebString privileged_scheme(blink::WebString::fromUTF8(scheme));
|
||||
blink::WebSecurityPolicy::registerURLSchemeAsSecure(privileged_scheme);
|
||||
blink::WebSecurityPolicy::registerURLSchemeAsBypassingContentSecurityPolicy(
|
||||
privileged_scheme);
|
||||
blink::WebSecurityPolicy::registerURLSchemeAsAllowingServiceWorkers(
|
||||
privileged_scheme);
|
||||
}
|
||||
|
||||
mate::ObjectTemplateBuilder WebFrame::GetObjectTemplateBuilder(
|
||||
v8::Isolate* isolate) {
|
||||
return mate::ObjectTemplateBuilder(isolate)
|
||||
|
@ -116,7 +126,9 @@ mate::ObjectTemplateBuilder WebFrame::GetObjectTemplateBuilder(
|
|||
.SetMethod("registerUrlSchemeAsSecure",
|
||||
&WebFrame::RegisterURLSchemeAsSecure)
|
||||
.SetMethod("registerUrlSchemeAsBypassingCsp",
|
||||
&WebFrame::RegisterURLSchemeAsBypassingCsp);
|
||||
&WebFrame::RegisterURLSchemeAsBypassingCsp)
|
||||
.SetMethod("registerUrlSchemeAsPrivileged",
|
||||
&WebFrame::RegisterURLSchemeAsPrivileged);
|
||||
}
|
||||
|
||||
// static
|
||||
|
|
|
@ -58,6 +58,7 @@ class WebFrame : public mate::Wrappable {
|
|||
|
||||
void RegisterURLSchemeAsSecure(const std::string& scheme);
|
||||
void RegisterURLSchemeAsBypassingCsp(const std::string& scheme);
|
||||
void RegisterURLSchemeAsPrivileged(const std::string& scheme);
|
||||
|
||||
// mate::Wrappable:
|
||||
virtual mate::ObjectTemplateBuilder GetObjectTemplateBuilder(
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
process = global.process
|
||||
ipc = require 'ipc'
|
||||
v8Util = process.atomBinding 'v8_util'
|
||||
CallbacksRegistry = require 'callbacks-registry'
|
||||
|
|
|
@ -1,8 +1,7 @@
|
|||
process = global.process
|
||||
events = require 'events'
|
||||
path = require 'path'
|
||||
url = require 'url'
|
||||
Module = require 'module'
|
||||
events = require 'events'
|
||||
path = require 'path'
|
||||
url = require 'url'
|
||||
Module = require 'module'
|
||||
|
||||
# We modified the original process.argv to let node.js load the
|
||||
# atom-renderer.js, we need to restore it here.
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
process = global.process
|
||||
ipc = require 'ipc'
|
||||
remote = require 'remote'
|
||||
|
||||
|
@ -71,7 +70,6 @@ window.open = (url, frameName='', features='') ->
|
|||
if guestId
|
||||
new BrowserWindowProxy(guestId)
|
||||
else
|
||||
console.error 'It is not allowed to open new window from this WebContents'
|
||||
null
|
||||
|
||||
# Use the dialog API to implement alert().
|
||||
|
|
|
@ -16,7 +16,7 @@ WEB_VIEW_EVENTS =
|
|||
'did-get-redirect-request': ['oldUrl', 'newUrl', 'isMainFrame']
|
||||
'dom-ready': []
|
||||
'console-message': ['level', 'message', 'line', 'sourceId']
|
||||
'new-window': ['url', 'frameName', 'disposition']
|
||||
'new-window': ['url', 'frameName', 'disposition', 'options']
|
||||
'close': []
|
||||
'crashed': []
|
||||
'gpu-crashed': []
|
||||
|
|
|
@ -216,6 +216,7 @@ WebViewImpl::setupWebViewAttributes = ->
|
|||
@attributes[webViewConstants.ATTRIBUTE_NODEINTEGRATION] = new BooleanAttribute(webViewConstants.ATTRIBUTE_NODEINTEGRATION, this)
|
||||
@attributes[webViewConstants.ATTRIBUTE_PLUGINS] = new BooleanAttribute(webViewConstants.ATTRIBUTE_PLUGINS, this)
|
||||
@attributes[webViewConstants.ATTRIBUTE_DISABLEWEBSECURITY] = new BooleanAttribute(webViewConstants.ATTRIBUTE_DISABLEWEBSECURITY, this)
|
||||
@attributes[webViewConstants.ATTRIBUTE_ALLOWPOPUPS] = new BooleanAttribute(webViewConstants.ATTRIBUTE_ALLOWPOPUPS, this)
|
||||
@attributes[webViewConstants.ATTRIBUTE_PRELOAD] = new PreloadAttribute(this)
|
||||
|
||||
autosizeAttributes = [
|
||||
|
|
|
@ -13,6 +13,7 @@ module.exports =
|
|||
ATTRIBUTE_NODEINTEGRATION: 'nodeintegration'
|
||||
ATTRIBUTE_PLUGINS: 'plugins'
|
||||
ATTRIBUTE_DISABLEWEBSECURITY: 'disablewebsecurity'
|
||||
ATTRIBUTE_ALLOWPOPUPS: 'allowpopups'
|
||||
ATTRIBUTE_PRELOAD: 'preload'
|
||||
ATTRIBUTE_USERAGENT: 'useragent'
|
||||
|
||||
|
|
|
@ -665,7 +665,7 @@ Same as `webContents.loadUrl(url[, options])`.
|
|||
|
||||
Same as `webContents.reload`.
|
||||
|
||||
### `win.setMenu(menu)` _OS X_
|
||||
### `win.setMenu(menu)` _Linux_ _Windows_
|
||||
|
||||
* `menu` Menu
|
||||
|
||||
|
|
|
@ -87,6 +87,11 @@ Sets the `version` of the pepper flash plugin.
|
|||
|
||||
Enables net log events to be saved and writes them to `path`.
|
||||
|
||||
## --ssl-version-fallback-min=`version`
|
||||
|
||||
Set the minimum SSL/TLS version ("tls1", "tls1.1" or "tls1.2") that TLS
|
||||
fallback will accept.
|
||||
|
||||
## --v=`log_level`
|
||||
|
||||
Gives the default maximal active V-logging level; 0 is the default. Normally
|
||||
|
|
101
docs/api/download-item.md
Normal file
101
docs/api/download-item.md
Normal file
|
@ -0,0 +1,101 @@
|
|||
# DownloadItem
|
||||
|
||||
`DownloadItem` is an EventEmitter represents a download item in Electron. It
|
||||
is used in `will-download` event of `Session` module, and allows users to
|
||||
control the download item.
|
||||
|
||||
```javascript
|
||||
// In the main process.
|
||||
win.webContents.session.on('will-download', function(event, item, webContents) {
|
||||
// Set the save path, making Electron not to prompt a save dialog.
|
||||
item.setSavePath('/tmp/save.pdf');
|
||||
console.log(item.getMimeType());
|
||||
console.log(item.getFilename());
|
||||
console.log(item.getTotalBytes());
|
||||
item.on('updated', function() {
|
||||
console.log('Received bytes: ' + item.getReceivedBytes());
|
||||
});
|
||||
item.on('done', function(e, state) {
|
||||
if (state == "completed") {
|
||||
console.log("Download successfully");
|
||||
} else {
|
||||
console.log("Download is cancelled or interrupted that can't be resumed");
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
## Events
|
||||
|
||||
### Event: 'updated'
|
||||
|
||||
Emits when the `downloadItem` gets updated.
|
||||
|
||||
### Event: 'done'
|
||||
|
||||
* `event` Event
|
||||
* `state` String
|
||||
* `completed` - The download completed successfully.
|
||||
* `cancelled` - The download has been cancelled.
|
||||
* `interrupted` - An error broke the connection with the file server.
|
||||
|
||||
Emits when the download is in a terminal state. This includes a completed
|
||||
download, a cancelled download(via `downloadItem.cancel()`), and interrupted
|
||||
download that can't be resumed.
|
||||
|
||||
## Methods
|
||||
|
||||
The `downloadItem` object has the following methods:
|
||||
|
||||
### `downloadItem.setSavePath(path)`
|
||||
|
||||
* `path` String - Set the save file path of the download item.
|
||||
|
||||
The API is only available in session's `will-download` callback function.
|
||||
If user doesn't set the save path via the API, Electron will use the original
|
||||
routine to determine the save path(Usually prompts a save dialog).
|
||||
|
||||
### `downloadItem.pause()`
|
||||
|
||||
Pauses the download.
|
||||
|
||||
### `downloadItem.resume()`
|
||||
|
||||
Resumes the download that has been paused.
|
||||
|
||||
### `downloadItem.cancel()`
|
||||
|
||||
Cancels the download operation.
|
||||
|
||||
### `downloadItem.getUrl()`
|
||||
|
||||
Returns a `String` represents the origin url where the item is downloaded from.
|
||||
|
||||
### `downloadItem.getMimeType()`
|
||||
|
||||
Returns a `String` represents the mime type.
|
||||
|
||||
### `downloadItem.hasUserGesture()`
|
||||
|
||||
Returns a `Boolean` indicates whether the download has user gesture.
|
||||
|
||||
### `downloadItem.getFilename()`
|
||||
|
||||
Returns a `String` represents the file name of the download item.
|
||||
|
||||
**Note:** The file name is not always the same as the actual one saved in local
|
||||
disk. If user changes the file name in a prompted download saving dialog, the
|
||||
actual name of saved file will be different.
|
||||
|
||||
### `downloadItem.getTotalBytes()`
|
||||
|
||||
Returns a `Integer` represents the total size in bytes of the download item.
|
||||
If the size is unknown, it returns 0.
|
||||
|
||||
### `downloadItem.getReceivedBytes()`
|
||||
|
||||
Returns a `Integer` represents the received bytes of the download item.
|
||||
|
||||
### `downloadItem.getContentDisposition()`
|
||||
|
||||
Returns a `String` represents the Content-Disposition field from the response
|
||||
header.
|
|
@ -18,11 +18,7 @@ var session = win.webContents.session
|
|||
### Event: 'will-download'
|
||||
|
||||
* `event` Event
|
||||
* `item` Object
|
||||
* `url` String
|
||||
* `filename` String
|
||||
* `mimeType` String
|
||||
* `hasUserGesture` Boolean
|
||||
* `item` [DownloadItem](download-item.md)
|
||||
* `webContents` [WebContents](web-contents.md)
|
||||
|
||||
Fired when Electron is about to download `item` in `webContents`.
|
||||
|
@ -32,7 +28,7 @@ Calling `event.preventDefault()` will cancel the download.
|
|||
```javascript
|
||||
session.on('will-download', function(event, item, webContents) {
|
||||
event.preventDefault();
|
||||
require('request')(item.url, function(data) {
|
||||
require('request')(item.getUrl(), function(data) {
|
||||
require('fs').writeFileSync('/somewhere', data);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -78,6 +78,10 @@ Returns:
|
|||
* `oldUrl` String
|
||||
* `newUrl` String
|
||||
* `isMainFrame` Boolean
|
||||
* `httpResponseCode` Integer
|
||||
* `requestMethod` String
|
||||
* `referrer` String
|
||||
* `headers` Object
|
||||
|
||||
Emitted when a redirect is received while requesting a resource.
|
||||
|
||||
|
@ -107,6 +111,8 @@ Returns:
|
|||
* `frameName` String
|
||||
* `disposition` String - Can be `default`, `foreground-tab`, `background-tab`,
|
||||
`new-window` and `other`.
|
||||
* `options` Object - The options which will be used for creating the new
|
||||
`BrowserWindow`.
|
||||
|
||||
Emitted when the page requests to open a new window for a `url`. It could be
|
||||
requested by `window.open` or an external link like `<a target='_blank'>`.
|
||||
|
@ -415,7 +421,7 @@ win.webContents.on("did-finish-load", function() {
|
|||
win.webContents.printToPDF({}, function(error, data) {
|
||||
if (error) throw error;
|
||||
fs.writeFile("/tmp/print.pdf", data, function(error) {
|
||||
if (err)
|
||||
if (error)
|
||||
throw error;
|
||||
console.log("Write PDF successfully.");
|
||||
})
|
||||
|
|
|
@ -83,4 +83,11 @@ attackers.
|
|||
Resources will be loaded from this `scheme` regardless of the current page's
|
||||
Content Security Policy.
|
||||
|
||||
### `webFrame.registerUrlSchemeAsPrivileged(scheme)`
|
||||
|
||||
* `scheme` String
|
||||
|
||||
Registers the `scheme` as secure, bypasses content security policy for resources and
|
||||
allows registering ServiceWorker.
|
||||
|
||||
[spellchecker]: https://github.com/atom/node-spellchecker
|
||||
|
|
|
@ -149,6 +149,14 @@ This value can only be modified before the first navigation, since the session
|
|||
of an active renderer process cannot change. Subsequent attempts to modify the
|
||||
value will fail with a DOM exception.
|
||||
|
||||
### `allowpopups`
|
||||
|
||||
```html
|
||||
<webview src="https://www.github.com/" allowpopups></webview>
|
||||
```
|
||||
|
||||
If "on", the guest page will be allowed to open new windows.
|
||||
|
||||
## Methods
|
||||
|
||||
The `webview` tag has the following methods:
|
||||
|
@ -496,7 +504,9 @@ Returns:
|
|||
* `url` String
|
||||
* `frameName` String
|
||||
* `disposition` String - Can be `default`, `foreground-tab`, `background-tab`,
|
||||
`new-window` and `other`
|
||||
`new-window` and `other`.
|
||||
* `options` Object - The options which should be used for creating the new
|
||||
`BrowserWindow`.
|
||||
|
||||
Fired when the guest page attempts to open a new browser window.
|
||||
|
||||
|
|
|
@ -8,6 +8,10 @@ The proxy has limited standard functionality implemented to be
|
|||
compatible with traditional web pages. For full control of the new window
|
||||
you should create a `BrowserWindow` directly.
|
||||
|
||||
The newly created `BrowserWindow` will inherit parent window's options by
|
||||
default, to override inherited options you can set them in the `features`
|
||||
string.
|
||||
|
||||
### `window.open(url[, frameName][, features])`
|
||||
|
||||
* `url` String
|
||||
|
@ -16,6 +20,9 @@ you should create a `BrowserWindow` directly.
|
|||
|
||||
Creates a new window and returns an instance of `BrowserWindowProxy` class.
|
||||
|
||||
The `features` string follows the format of standard browser, but each feature
|
||||
has to be a field of `BrowserWindow`'s options.
|
||||
|
||||
### `window.opener.postMessage(message, targetOrigin)`
|
||||
|
||||
* `message` String
|
||||
|
|
|
@ -124,6 +124,7 @@ Finally the `index.html` is the web page you want to show:
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Hello World!</title>
|
||||
</head>
|
||||
<body>
|
||||
|
|
|
@ -34,6 +34,19 @@ npm install --save-dev electron-rebuild
|
|||
node ./node_modules/.bin/electron-rebuild
|
||||
```
|
||||
|
||||
### The npm Way
|
||||
|
||||
You can also use `npm` to install modules. The steps are exactly the same with
|
||||
Node modules, except that you need to setup some environment variables:
|
||||
|
||||
```bash
|
||||
export npm_config_disturl=https://atom.io/download/atom-shell
|
||||
export npm_config_target=0.33.1
|
||||
export npm_config_arch=x64
|
||||
export npm_config_runtime=electron
|
||||
HOME=~/.electron-gyp npm install module-name
|
||||
```
|
||||
|
||||
### The node-gyp Way
|
||||
|
||||
To build Node modules with headers of Electron, you need to tell `node-gyp`
|
||||
|
@ -48,15 +61,3 @@ The `HOME=~/.electron-gyp` changes where to find development headers. The
|
|||
`--target=0.29.1` is version of Electron. The `--dist-url=...` specifies
|
||||
where to download the headers. The `--arch=x64` says the module is built for
|
||||
64bit system.
|
||||
|
||||
### The npm Way
|
||||
|
||||
You can also use `npm` to install modules. The steps are exactly the same with
|
||||
Node modules, except that you need to setup some environment variables:
|
||||
|
||||
```bash
|
||||
export npm_config_disturl=https://atom.io/download/atom-shell
|
||||
export npm_config_target=0.29.1
|
||||
export npm_config_arch=x64
|
||||
HOME=~/.electron-gyp npm install module-name
|
||||
```
|
||||
|
|
|
@ -71,6 +71,8 @@
|
|||
'atom/browser/api/atom_api_content_tracing.cc',
|
||||
'atom/browser/api/atom_api_cookies.cc',
|
||||
'atom/browser/api/atom_api_cookies.h',
|
||||
'atom/browser/api/atom_api_download_item.cc',
|
||||
'atom/browser/api/atom_api_download_item.h',
|
||||
'atom/browser/api/atom_api_dialog.cc',
|
||||
'atom/browser/api/atom_api_global_shortcut.cc',
|
||||
'atom/browser/api/atom_api_global_shortcut.h',
|
||||
|
@ -129,6 +131,8 @@
|
|||
'atom/browser/atom_quota_permission_context.h',
|
||||
'atom/browser/atom_speech_recognition_manager_delegate.cc',
|
||||
'atom/browser/atom_speech_recognition_manager_delegate.h',
|
||||
'atom/browser/atom_ssl_config_service.cc',
|
||||
'atom/browser/atom_ssl_config_service.h',
|
||||
'atom/browser/bridge_task_runner.cc',
|
||||
'atom/browser/bridge_task_runner.h',
|
||||
'atom/browser/browser.cc',
|
||||
|
|
|
@ -126,6 +126,8 @@ def copy_chrome_binary(binary):
|
|||
|
||||
|
||||
def copy_license():
|
||||
shutil.copy2(os.path.join(CHROMIUM_DIR, '..', 'LICENSES.chromium.html'),
|
||||
DIST_DIR)
|
||||
shutil.copy2(os.path.join(SOURCE_ROOT, 'LICENSE'), DIST_DIR)
|
||||
|
||||
|
||||
|
|
|
@ -8,7 +8,7 @@ import sys
|
|||
|
||||
BASE_URL = os.getenv('LIBCHROMIUMCONTENT_MIRROR') or \
|
||||
'http://github-janky-artifacts.s3.amazonaws.com/libchromiumcontent'
|
||||
LIBCHROMIUMCONTENT_COMMIT = '8482fe555913dea3bde8a74f754524e2cfb02bc5'
|
||||
LIBCHROMIUMCONTENT_COMMIT = '04523758cda2a96d2454f9056fb1fb9a1c1f95f1'
|
||||
|
||||
PLATFORM = {
|
||||
'cygwin': 'win32',
|
||||
|
|
|
@ -8,7 +8,7 @@ from lib.config import get_target_arch
|
|||
from lib.util import safe_mkdir, rm_rf, extract_zip, tempdir, download
|
||||
|
||||
|
||||
VERSION = 'v0.7.0'
|
||||
VERSION = 'v0.8.0'
|
||||
SOURCE_ROOT = os.path.abspath(os.path.dirname(os.path.dirname(__file__)))
|
||||
FRAMEWORKS_URL = 'http://github.com/atom/atom-shell-frameworks/releases' \
|
||||
'/download/' + VERSION
|
||||
|
|
|
@ -294,17 +294,7 @@ describe 'browser-window module', ->
|
|||
w.show()
|
||||
w.minimize()
|
||||
|
||||
describe 'will-navigate event', ->
|
||||
@timeout 10000
|
||||
it 'emits when user starts a navigation', (done) ->
|
||||
url = "file://#{fixtures}/pages/will-navigate.html"
|
||||
w.webContents.on 'will-navigate', (event, u) ->
|
||||
event.preventDefault()
|
||||
assert.equal u, url
|
||||
done()
|
||||
w.loadUrl url
|
||||
|
||||
describe 'beginFrameSubscription method', ->
|
||||
xdescribe 'beginFrameSubscription method', ->
|
||||
it 'subscribes frame updates', (done) ->
|
||||
w.loadUrl "file://#{fixtures}/api/blank.html"
|
||||
w.webContents.beginFrameSubscription (data) ->
|
||||
|
|
|
@ -2,6 +2,7 @@ assert = require 'assert'
|
|||
remote = require 'remote'
|
||||
http = require 'http'
|
||||
path = require 'path'
|
||||
fs = require 'fs'
|
||||
app = remote.require 'app'
|
||||
BrowserWindow = remote.require 'browser-window'
|
||||
|
||||
|
@ -72,3 +73,51 @@ describe 'session module', ->
|
|||
quotas: ['persistent'],
|
||||
w.webContents.session.clearStorageData options, ->
|
||||
w.webContents.send 'getcount'
|
||||
|
||||
describe 'DownloadItem', ->
|
||||
# A 5 MB mock pdf.
|
||||
mockPDF = new Buffer 1024 * 1024 * 5
|
||||
contentDisposition = 'inline; filename="mock.pdf"'
|
||||
ipc = require 'ipc'
|
||||
downloadFilePath = path.join fixtures, 'mock.pdf'
|
||||
downloadServer = http.createServer (req, res) ->
|
||||
res.writeHead 200, {
|
||||
'Content-Length': mockPDF.length,
|
||||
'Content-Type': 'application/pdf',
|
||||
'Content-Disposition': contentDisposition
|
||||
}
|
||||
res.end mockPDF
|
||||
downloadServer.close()
|
||||
|
||||
it 'can download successfully', (done) ->
|
||||
downloadServer.listen 0, '127.0.0.1', ->
|
||||
{port} = downloadServer.address()
|
||||
ipc.sendSync 'set-download-option', false
|
||||
w.loadUrl "#{url}:#{port}"
|
||||
ipc.once 'download-done', (state, url, mimeType, receivedBytes,
|
||||
totalBytes, disposition, filename) ->
|
||||
assert.equal state, 'completed'
|
||||
assert.equal filename, 'mock.pdf'
|
||||
assert.equal url, "http://127.0.0.1:#{port}/"
|
||||
assert.equal mimeType, 'application/pdf'
|
||||
assert.equal receivedBytes, mockPDF.length
|
||||
assert.equal totalBytes, mockPDF.length
|
||||
assert.equal disposition, contentDisposition
|
||||
assert fs.existsSync downloadFilePath
|
||||
fs.unlinkSync downloadFilePath
|
||||
done()
|
||||
|
||||
it 'can cancel download', (done) ->
|
||||
downloadServer.listen 0, '127.0.0.1', ->
|
||||
{port} = downloadServer.address()
|
||||
ipc.sendSync 'set-download-option', true
|
||||
w.loadUrl "#{url}:#{port}/"
|
||||
ipc.once 'download-done', (state, url, mimeType, receivedBytes,
|
||||
totalBytes, disposition, filename) ->
|
||||
assert.equal state, 'cancelled'
|
||||
assert.equal filename, 'mock.pdf'
|
||||
assert.equal mimeType, 'application/pdf'
|
||||
assert.equal receivedBytes, 0
|
||||
assert.equal totalBytes, mockPDF.length
|
||||
assert.equal disposition, contentDisposition
|
||||
done()
|
||||
|
|
|
@ -8,6 +8,10 @@ describe 'asar package', ->
|
|||
|
||||
describe 'node api', ->
|
||||
describe 'fs.readFileSync', ->
|
||||
it 'does not leak fd', ->
|
||||
for i in [1..10000]
|
||||
fs.readFileSync(path.join(process.resourcesPath, 'atom.asar', 'renderer', 'api', 'lib', 'ipc.js'))
|
||||
|
||||
it 'reads a normal file', ->
|
||||
file1 = path.join fixtures, 'asar', 'a.asar', 'file1'
|
||||
assert.equal fs.readFileSync(file1).toString().trim(), 'file1'
|
||||
|
|
|
@ -23,6 +23,23 @@ describe 'chromium feature', ->
|
|||
{port} = server.address()
|
||||
$.get "http://127.0.0.1:#{port}"
|
||||
|
||||
describe 'document.hidden', ->
|
||||
BrowserWindow = remote.require 'browser-window'
|
||||
ipc = remote.require 'ipc'
|
||||
url = "file://#{fixtures}/pages/document-hidden.html"
|
||||
w = null
|
||||
|
||||
afterEach ->
|
||||
w?.destroy()
|
||||
ipc.removeAllListeners 'hidden'
|
||||
|
||||
it 'is set correctly when window is not shown', (done) ->
|
||||
ipc.once 'hidden', (event, hidden) ->
|
||||
assert hidden
|
||||
done()
|
||||
w = new BrowserWindow(show:false)
|
||||
w.loadUrl url
|
||||
|
||||
describe 'navigator.webkitGetUserMedia', ->
|
||||
it 'calls its callbacks', (done) ->
|
||||
@timeout 5000
|
||||
|
@ -35,6 +52,8 @@ describe 'chromium feature', ->
|
|||
assert.notEqual navigator.language, ''
|
||||
|
||||
describe 'window.open', ->
|
||||
@timeout 10000
|
||||
|
||||
it 'returns a BrowserWindowProxy object', ->
|
||||
b = window.open 'about:blank', '', 'show=no'
|
||||
assert.equal b.closed, false
|
||||
|
@ -50,6 +69,16 @@ describe 'chromium feature', ->
|
|||
window.addEventListener 'message', listener
|
||||
b = window.open "file://#{fixtures}/pages/window-opener-node.html", '', 'node-integration=no,show=no'
|
||||
|
||||
it 'inherit options of parent window', (done) ->
|
||||
listener = (event) ->
|
||||
window.removeEventListener 'message', listener
|
||||
b.close()
|
||||
size = remote.getCurrentWindow().getSize()
|
||||
assert.equal event.data, "size: #{size.width} #{size.height}"
|
||||
done()
|
||||
window.addEventListener 'message', listener
|
||||
b = window.open "file://#{fixtures}/pages/window-open-size.html", '', 'show=no'
|
||||
|
||||
describe 'window.opener', ->
|
||||
@timeout 10000
|
||||
|
||||
|
@ -62,7 +91,7 @@ describe 'chromium feature', ->
|
|||
ipc.removeAllListeners 'opener'
|
||||
|
||||
it 'is null for main window', (done) ->
|
||||
ipc.on 'opener', (event, opener) ->
|
||||
ipc.once 'opener', (event, opener) ->
|
||||
assert.equal opener, null
|
||||
done()
|
||||
BrowserWindow = remote.require 'browser-window'
|
||||
|
@ -70,7 +99,7 @@ describe 'chromium feature', ->
|
|||
w.loadUrl url
|
||||
|
||||
it 'is not null for window opened by window.open', (done) ->
|
||||
ipc.on 'opener', (event, opener) ->
|
||||
ipc.once 'opener', (event, opener) ->
|
||||
b.close()
|
||||
done(if opener isnt null then undefined else opener)
|
||||
b = window.open url, '', 'show=no'
|
||||
|
|
7
spec/fixtures/pages/document-hidden.html
vendored
Normal file
7
spec/fixtures/pages/document-hidden.html
vendored
Normal file
|
@ -0,0 +1,7 @@
|
|||
<html>
|
||||
<body>
|
||||
<script type="text/javascript" charset="utf-8">
|
||||
require('ipc').send('hidden', document.hidden);
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
12
spec/fixtures/pages/window-open-hide.html
vendored
Normal file
12
spec/fixtures/pages/window-open-hide.html
vendored
Normal file
|
@ -0,0 +1,12 @@
|
|||
<html>
|
||||
<body>
|
||||
<script type="text/javascript" charset="utf-8">
|
||||
var w = window.open('http://host', '', 'show=no');
|
||||
if (w == null)
|
||||
console.log('null');
|
||||
else
|
||||
console.log('window');
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
8
spec/fixtures/pages/window-open-size.html
vendored
Normal file
8
spec/fixtures/pages/window-open-size.html
vendored
Normal file
|
@ -0,0 +1,8 @@
|
|||
<html>
|
||||
<body>
|
||||
<script type="text/javascript" charset="utf-8">
|
||||
var size = require('remote').getCurrentWindow().getSize();
|
||||
window.opener.postMessage('size: ' + size.width + ' ' + size.height, '*')
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -22,6 +22,12 @@ describe 'third-party module', ->
|
|||
assert.equal msg, 'ok'
|
||||
done()
|
||||
|
||||
describe 'ffi', ->
|
||||
it 'does not crash', ->
|
||||
ffi = require 'ffi'
|
||||
libm = ffi.Library('libm', ceil: [ 'double', [ 'double' ] ])
|
||||
assert.equal libm.ceil(1.5), 2
|
||||
|
||||
describe 'q', ->
|
||||
Q = require 'q'
|
||||
|
||||
|
|
|
@ -65,6 +65,7 @@ describe 'node feature', ->
|
|||
|
||||
describe 'contexts', ->
|
||||
describe 'setTimeout in fs callback', ->
|
||||
return if process.env.TRAVIS is 'true'
|
||||
it 'does not crash', (done) ->
|
||||
fs.readFile __filename, ->
|
||||
setTimeout done, 0
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
"version": "0.1.0",
|
||||
"devDependencies": {
|
||||
"basic-auth": "^1.0.0",
|
||||
"ffi": "2.0.0",
|
||||
"formidable": "1.0.16",
|
||||
"graceful-fs": "3.0.5",
|
||||
"mocha": "2.1.0",
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
var app = require('app');
|
||||
var ipc = require('ipc');
|
||||
var dialog = require('dialog');
|
||||
var path = require('path');
|
||||
var BrowserWindow = require('browser-window');
|
||||
|
||||
var window = null;
|
||||
|
@ -73,4 +74,27 @@ app.on('ready', function() {
|
|||
});
|
||||
if (chosen == 0) window.destroy();
|
||||
});
|
||||
|
||||
// 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');
|
||||
require('ipc').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();
|
||||
});
|
||||
event.returnValue = "done";
|
||||
});
|
||||
});
|
||||
|
|
|
@ -86,7 +86,7 @@ describe '<webview> tag', ->
|
|||
|
||||
it 'preload script can still use "process" in required modules when nodeintegration is off', (done) ->
|
||||
webview.addEventListener 'console-message', (e) ->
|
||||
assert.equal e.message, 'object function object'
|
||||
assert.equal e.message, 'object undefined object'
|
||||
done()
|
||||
webview.setAttribute 'preload', "#{fixtures}/module/preload-node-off.js"
|
||||
webview.src = "file://#{fixtures}/api/blank.html"
|
||||
|
@ -201,6 +201,26 @@ describe '<webview> tag', ->
|
|||
webview.src = "file://#{fixtures}/pages/partition/one.html"
|
||||
document.body.appendChild webview
|
||||
|
||||
describe 'allowpopups attribute', ->
|
||||
it 'can not open new window when not set', (done) ->
|
||||
listener = (e) ->
|
||||
assert.equal e.message, 'null'
|
||||
webview.removeEventListener 'console-message', listener
|
||||
done()
|
||||
webview.addEventListener 'console-message', listener
|
||||
webview.src = "file://#{fixtures}/pages/window-open-hide.html"
|
||||
document.body.appendChild webview
|
||||
|
||||
it 'can open new window when set', (done) ->
|
||||
listener = (e) ->
|
||||
assert.equal e.message, 'window'
|
||||
webview.removeEventListener 'console-message', listener
|
||||
done()
|
||||
webview.addEventListener 'console-message', listener
|
||||
webview.setAttribute 'allowpopups', 'on'
|
||||
webview.src = "file://#{fixtures}/pages/window-open-hide.html"
|
||||
document.body.appendChild webview
|
||||
|
||||
describe 'new-window event', ->
|
||||
it 'emits when window.open is called', (done) ->
|
||||
webview.addEventListener 'new-window', (e) ->
|
||||
|
|
2
vendor/brightray
vendored
2
vendor/brightray
vendored
|
@ -1 +1 @@
|
|||
Subproject commit 25f3a9d0a5b73ec170a65f4e2e4c9ad91e23fc8c
|
||||
Subproject commit 8e443520e695674fd26585cfa24a0ec0b6140c27
|
2
vendor/node
vendored
2
vendor/node
vendored
|
@ -1 +1 @@
|
|||
Subproject commit aa9c7a2316ba7762f1d04d091585695be3e6be22
|
||||
Subproject commit ac25693ad1d4c248e69a89147fd3995c3bf6c946
|
Loading…
Reference in a new issue