Merge remote-tracking branch 'refs/remotes/atom/master'

This commit is contained in:
Plusb Preco 2015-12-04 13:38:21 +09:00
commit 4a2bfa0b06
42 changed files with 388 additions and 340 deletions

24
CODE_OF_CONDUCT.md Normal file
View file

@ -0,0 +1,24 @@
# Contributor Code of Conduct
As contributors and maintainers of this project, and in the interest of fostering an open and welcoming community, we pledge to respect all people who contribute through reporting issues, posting feature requests, updating documentation, submitting pull requests or patches, and other activities.
We are committed to making participation in this project a harassment-free experience for everyone, regardless of level of experience, gender, gender identity and expression, sexual orientation, disability, personal appearance, body size, race, ethnicity, age, religion, or nationality.
Examples of unacceptable behavior by participants include:
- The use of sexualized language or imagery
- Personal attacks
- Trolling or insulting/derogatory comments
- Public or private harassment
- Publishing other's private information, such as physical or electronic addresses, without explicit permission
- Other unethical or unprofessional conduct
Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful.
By adopting this Code of Conduct, project maintainers commit themselves to fairly and consistently applying these principles to every aspect of managing this project. Project maintainers who do not follow or enforce the Code of Conduct may be permanently removed from the project team.
This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community.
Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting a project maintainer at [atom@github.com](mailto:atom@github.com). All complaints will be reviewed and investigated and will result in a response that is deemed necessary and appropriate to the circumstances. Maintainers are obligated to maintain confidentiality with regard to the reporter of an incident.
This Code of Conduct is adapted from the Contributor Covenant, version 1.3.0, available from http://contributor-covenant.org/version/1/3/0/

View file

@ -2,8 +2,9 @@
:+1::tada: First off, thanks for taking the time to contribute! :tada::+1:
This project adheres to the [Contributor Covenant 1.2](http://contributor-covenant.org/version/1/2/0).
By participating, you are expected to uphold this code. Please report unacceptable behavior to atom@github.com.
This project adheres to the Contributor Covenant [code of conduct](CODE_OF_CONDUCT.md).
By participating, you are expected to uphold this code. Please report unacceptable
behavior to atom@github.com.
The following is a set of guidelines for contributing to Electron.
These are just guidelines, not rules, use your best judgment and feel free to

View file

@ -16,9 +16,7 @@ Cross-Platform 데스크톱 어플리케이션을 개발할 수 있도록 해주
Electron에 대한 중요한 알림을 받고 싶다면 Twitter에서
[@ElectronJS](https://twitter.com/electronjs)를 팔로우 하세요.
이 프로젝트는 [기여자 규약 1.2](http://contributor-covenant.org/version/1/2/0/)을
준수합니다. 따라서 이 프로젝트의 개발에 참여하려면 이 계약을 지켜야 합니다. 받아들일 수
없는 행위를 발견했을 경우 atom@github.com로 보고 하십시오.
[CODE_OF_CONDUCT.md](CODE_OF_CONDUCT.md)
## 다운로드

View file

@ -14,9 +14,9 @@ editor](https://github.com/atom/atom).
Follow [@ElectronJS](https://twitter.com/electronjs) on Twitter for important
announcements.
This project adheres to the [Contributor Covenant 1.2](http://contributor-covenant.org/version/1/2/0/).
By participating, you are expected to uphold this code. Please report
unacceptable behavior to atom@github.com.
This project adheres to the Contributor Covenant [code of conduct](CODE_OF_CONDUCT.md).
By participating, you are expected to uphold this code. Please report unacceptable
behavior to atom@github.com.
## Downloads
@ -67,6 +67,7 @@ locations:
forums
- `#atom-shell` channel on Freenode
- [`Atom`](http://atom-slack.herokuapp.com/) channel on Slack
- [`electron-br`](https://electron-br.slack.com) *(Brazilian Portuguese)*
Check out [awesome-electron](https://github.com/sindresorhus/awesome-electron)
for a community maintained list of useful example apps, tools and resources.

View file

@ -322,14 +322,6 @@ void Cookies::OnSetCookies(const CookiesCallback& callback,
callback));
}
mate::ObjectTemplateBuilder Cookies::GetObjectTemplateBuilder(
v8::Isolate* isolate) {
return mate::ObjectTemplateBuilder(isolate)
.SetMethod("get", &Cookies::Get)
.SetMethod("remove", &Cookies::Remove)
.SetMethod("set", &Cookies::Set);
}
net::CookieStore* Cookies::GetCookieStore() {
return request_context_getter_->GetURLRequestContext()->cookie_store();
}
@ -341,6 +333,15 @@ mate::Handle<Cookies> Cookies::Create(
return mate::CreateHandle(isolate, new Cookies(browser_context));
}
// static
void Cookies::BuildPrototype(v8::Isolate* isolate,
v8::Local<v8::ObjectTemplate> prototype) {
mate::ObjectTemplateBuilder(isolate, prototype)
.SetMethod("get", &Cookies::Get)
.SetMethod("remove", &Cookies::Remove)
.SetMethod("set", &Cookies::Set);
}
} // namespace api
} // namespace atom

View file

@ -7,8 +7,8 @@
#include <string>
#include "atom/browser/api/trackable_object.h"
#include "base/callback.h"
#include "native_mate/wrappable.h"
#include "native_mate/handle.h"
#include "net/cookies/canonical_cookie.h"
@ -33,7 +33,7 @@ namespace atom {
namespace api {
class Cookies : public mate::Wrappable {
class Cookies : public mate::TrackableObject<Cookies> {
public:
// node.js style callback function(error, result)
typedef base::Callback<void(v8::Local<v8::Value>, v8::Local<v8::Value>)>
@ -42,6 +42,10 @@ class Cookies : public mate::Wrappable {
static mate::Handle<Cookies> Create(v8::Isolate* isolate,
content::BrowserContext* browser_context);
// mate::TrackableObject:
static void BuildPrototype(v8::Isolate* isolate,
v8::Local<v8::ObjectTemplate> prototype);
protected:
explicit Cookies(content::BrowserContext* browser_context);
~Cookies();
@ -70,10 +74,6 @@ class Cookies : public mate::Wrappable {
void OnSetCookies(const CookiesCallback& callback,
bool set_success);
// mate::Wrappable:
mate::ObjectTemplateBuilder GetObjectTemplateBuilder(
v8::Isolate* isolate) override;
private:
// Must be called on IO thread.
net::CookieStore* GetCookieStore();

View file

@ -70,29 +70,20 @@ DownloadItem::DownloadItem(content::DownloadItem* download_item) :
}
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;
if (download_item_)
OnDownloadDestroyed(download_item_);
}
void DownloadItem::OnDownloadUpdated(content::DownloadItem* item) {
download_item_->IsDone() ? Emit("done", item->GetState()) : Emit("updated");
}
void DownloadItem::OnDownloadDestroyed(content::DownloadItem* download) {
Destroy();
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() {
@ -144,9 +135,11 @@ void DownloadItem::Cancel() {
download_item_->Cancel(true);
}
mate::ObjectTemplateBuilder DownloadItem::GetObjectTemplateBuilder(
v8::Isolate* isolate) {
return mate::ObjectTemplateBuilder(isolate)
// static
void DownloadItem::BuildPrototype(v8::Isolate* isolate,
v8::Local<v8::ObjectTemplate> prototype) {
mate::ObjectTemplateBuilder(isolate, prototype)
.MakeDestroyable()
.SetMethod("pause", &DownloadItem::Pause)
.SetMethod("resume", &DownloadItem::Resume)
.SetMethod("cancel", &DownloadItem::Cancel)

View file

@ -17,7 +17,7 @@ namespace atom {
namespace api {
class DownloadItem : public mate::EventEmitter,
class DownloadItem : public mate::TrackableObject<DownloadItem>,
public content::DownloadItem::Observer {
public:
class SavePathData : public base::SupportsUserData::Data {
@ -32,6 +32,10 @@ class DownloadItem : public mate::EventEmitter,
content::DownloadItem* item);
static void* UserDataKey();
// mate::TrackableObject:
static void BuildPrototype(v8::Isolate* isolate,
v8::Local<v8::ObjectTemplate> prototype);
protected:
explicit DownloadItem(content::DownloadItem* download_item);
~DownloadItem();
@ -53,13 +57,6 @@ class DownloadItem : public mate::EventEmitter,
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);

View file

@ -23,9 +23,6 @@ GlobalShortcut::GlobalShortcut() {
}
GlobalShortcut::~GlobalShortcut() {
}
void GlobalShortcut::Destroy() {
UnregisterAll();
}

View file

@ -27,9 +27,6 @@ class GlobalShortcut : public extensions::GlobalShortcutListener::Observer,
GlobalShortcut();
~GlobalShortcut() override;
// mate::TrackableObject:
void Destroy() override;
// mate::Wrappable implementations:
mate::ObjectTemplateBuilder GetObjectTemplateBuilder(
v8::Isolate* isolate) override;

View file

@ -27,14 +27,6 @@ Menu::Menu()
Menu::~Menu() {
}
void Menu::Destroy() {
model_.reset();
}
bool Menu::IsDestroyed() const {
return !model_;
}
void Menu::AfterInit(v8::Isolate* isolate) {
mate::Dictionary wrappable(isolate, GetWrapper(isolate));
mate::Dictionary delegate;
@ -159,6 +151,7 @@ bool Menu::IsVisibleAt(int index) const {
void Menu::BuildPrototype(v8::Isolate* isolate,
v8::Local<v8::ObjectTemplate> prototype) {
mate::ObjectTemplateBuilder(isolate, prototype)
.MakeDestroyable()
.SetMethod("insertItem", &Menu::InsertItemAt)
.SetMethod("insertCheckItem", &Menu::InsertCheckItemAt)
.SetMethod("insertRadioItem", &Menu::InsertRadioItemAt)

View file

@ -39,11 +39,7 @@ class Menu : public mate::TrackableObject<Menu>,
Menu();
~Menu() override;
// mate::TrackableObject:
void Destroy() override;
// mate::Wrappable:
bool IsDestroyed() const override;
void AfterInit(v8::Isolate* isolate) override;
// ui::SimpleMenuModel::Delegate:

View file

@ -19,7 +19,6 @@ class MenuMac : public Menu {
protected:
MenuMac();
void Destroy() override;
void Popup(Window* window) override;
void PopupAt(Window* window, int x, int y) override;

View file

@ -18,11 +18,6 @@ namespace api {
MenuMac::MenuMac() {
}
void MenuMac::Destroy() {
menu_controller_.reset();
Menu::Destroy();
}
void MenuMac::Popup(Window* window) {
NativeWindow* native_window = window->window();
if (!native_window)

View file

@ -19,9 +19,6 @@ PowerMonitor::PowerMonitor() {
}
PowerMonitor::~PowerMonitor() {
}
void PowerMonitor::Destroy() {
base::PowerMonitor::Get()->RemoveObserver(this);
}

View file

@ -23,9 +23,6 @@ class PowerMonitor : public mate::TrackableObject<PowerMonitor>,
PowerMonitor();
~PowerMonitor() override;
// mate::TrackableObject:
void Destroy() override;
// base::PowerObserver implementations:
void OnPowerStateChange(bool on_battery_power) override;
void OnSuspend() override;

View file

@ -45,11 +45,6 @@ PowerSaveBlocker::PowerSaveBlocker()
PowerSaveBlocker::~PowerSaveBlocker() {
}
void PowerSaveBlocker::Destroy() {
power_save_blocker_types_.clear();
power_save_blocker_.reset();
}
void PowerSaveBlocker::UpdatePowerSaveBlocker() {
if (power_save_blocker_types_.empty()) {
power_save_blocker_.reset();

View file

@ -28,9 +28,6 @@ class PowerSaveBlocker : public mate::TrackableObject<PowerSaveBlocker> {
PowerSaveBlocker();
~PowerSaveBlocker() override;
// mate::TrackableObject:
void Destroy() override;
// mate::Wrappable implementations:
mate::ObjectTemplateBuilder GetObjectTemplateBuilder(
v8::Isolate* isolate) override;

View file

@ -253,7 +253,6 @@ Session::Session(AtomBrowserContext* browser_context)
Session::~Session() {
content::BrowserContext::GetDownloadManager(browser_context())->
RemoveObserver(this);
Destroy();
}
void Session::OnDownloadCreated(content::DownloadManager* manager,
@ -271,14 +270,6 @@ void Session::OnDownloadCreated(content::DownloadManager* manager,
}
}
bool Session::IsDestroyed() const {
return !browser_context_;
}
void Session::Destroy() {
browser_context_ = nullptr;
}
void Session::ResolveProxy(const GURL& url, ResolveProxyCallback callback) {
new ResolveProxyHelper(browser_context(), url, callback);
}
@ -376,20 +367,6 @@ v8::Local<v8::Value> Session::Cookies(v8::Isolate* isolate) {
return v8::Local<v8::Value>::New(isolate, cookies_);
}
mate::ObjectTemplateBuilder Session::GetObjectTemplateBuilder(
v8::Isolate* isolate) {
return mate::ObjectTemplateBuilder(isolate)
.SetMethod("resolveProxy", &Session::ResolveProxy)
.SetMethod("clearCache", &Session::ClearCache)
.SetMethod("clearStorageData", &Session::ClearStorageData)
.SetMethod("setProxy", &Session::SetProxy)
.SetMethod("setDownloadPath", &Session::SetDownloadPath)
.SetMethod("enableNetworkEmulation", &Session::EnableNetworkEmulation)
.SetMethod("disableNetworkEmulation", &Session::DisableNetworkEmulation)
.SetMethod("setCertificateVerifyProc", &Session::SetCertVerifyProc)
.SetProperty("cookies", &Session::Cookies);
}
// static
mate::Handle<Session> Session::CreateFrom(
v8::Isolate* isolate, AtomBrowserContext* browser_context) {
@ -410,6 +387,22 @@ mate::Handle<Session> Session::FromPartition(
static_cast<AtomBrowserContext*>(browser_context.get()));
}
// static
void Session::BuildPrototype(v8::Isolate* isolate,
v8::Local<v8::ObjectTemplate> prototype) {
mate::ObjectTemplateBuilder(isolate, prototype)
.MakeDestroyable()
.SetMethod("resolveProxy", &Session::ResolveProxy)
.SetMethod("clearCache", &Session::ClearCache)
.SetMethod("clearStorageData", &Session::ClearStorageData)
.SetMethod("setProxy", &Session::SetProxy)
.SetMethod("setDownloadPath", &Session::SetDownloadPath)
.SetMethod("enableNetworkEmulation", &Session::EnableNetworkEmulation)
.SetMethod("disableNetworkEmulation", &Session::DisableNetworkEmulation)
.SetMethod("setCertificateVerifyProc", &Session::SetCertVerifyProc)
.SetProperty("cookies", &Session::Cookies);
}
void ClearWrapSession() {
g_wrap_session.Reset();
}

View file

@ -48,6 +48,10 @@ class Session: public mate::TrackableObject<Session>,
AtomBrowserContext* browser_context() const { return browser_context_.get(); }
// mate::TrackableObject:
static void BuildPrototype(v8::Isolate* isolate,
v8::Local<v8::ObjectTemplate> prototype);
protected:
explicit Session(AtomBrowserContext* browser_context);
~Session();
@ -56,15 +60,7 @@ class Session: public mate::TrackableObject<Session>,
void OnDownloadCreated(content::DownloadManager* manager,
content::DownloadItem* item) override;
// mate::Wrappable:
mate::ObjectTemplateBuilder GetObjectTemplateBuilder(
v8::Isolate* isolate) override;
bool IsDestroyed() const override;
private:
// mate::TrackableObject:
void Destroy() override;
void ResolveProxy(const GURL& url, ResolveProxyCallback callback);
void ClearCache(const net::CompletionCallback& callback);
void ClearStorageData(mate::Arguments* args);

View file

@ -94,14 +94,6 @@ void Tray::OnDragEnded() {
Emit("drag-end");
}
bool Tray::IsDestroyed() const {
return !tray_icon_;
}
void Tray::Destroy() {
tray_icon_.reset();
}
void Tray::SetImage(mate::Arguments* args, const gfx::Image& image) {
tray_icon_->SetImage(image);
}
@ -162,8 +154,7 @@ v8::Local<v8::Object> Tray::ModifiersToObject(v8::Isolate* isolate,
void Tray::BuildPrototype(v8::Isolate* isolate,
v8::Local<v8::ObjectTemplate> prototype) {
mate::ObjectTemplateBuilder(isolate, prototype)
.SetMethod("destroy", &Tray::Destroy, true)
.SetMethod("isDestroyed", &Tray::IsDestroyed, true)
.MakeDestroyable()
.SetMethod("setImage", &Tray::SetImage)
.SetMethod("setPressedImage", &Tray::SetPressedImage)
.SetMethod("setToolTip", &Tray::SetToolTip)

View file

@ -54,12 +54,6 @@ class Tray : public mate::TrackableObject<Tray>,
void OnDragExited() override;
void OnDragEnded() override;
// mate::Wrappable:
bool IsDestroyed() const override;
// mate::TrackableObject:
void Destroy() override;
void SetImage(mate::Arguments* args, const gfx::Image& image);
void SetPressedImage(mate::Arguments* args, const gfx::Image& image);
void SetToolTip(mate::Arguments* args, const std::string& tool_tip);

View file

@ -194,8 +194,6 @@ namespace api {
namespace {
v8::Persistent<v8::ObjectTemplate> template_;
// The wrapWebContents function which is implemented in JavaScript
using WrapWebContentsCallback = base::Callback<void(v8::Local<v8::Value>)>;
WrapWebContentsCallback g_wrap_web_contents;
@ -290,7 +288,15 @@ WebContents::WebContents(v8::Isolate* isolate,
}
WebContents::~WebContents() {
Destroy();
if (type_ == WEB_VIEW && managed_web_contents()) {
// When force destroying the "destroyed" event is not emitted.
WebContentsDestroyed();
guest_delegate_->Destroy();
Observe(nullptr);
DestroyWebContents();
}
}
bool WebContents::AddMessageToConsole(content::WebContents* source,
@ -591,19 +597,6 @@ void WebContents::NavigationEntryCommitted(
details.is_in_page, details.did_replace_entry);
}
void WebContents::Destroy() {
session_.Reset();
if (type_ == WEB_VIEW && managed_web_contents()) {
// When force destroying the "destroyed" event is not emitted.
WebContentsDestroyed();
guest_delegate_->Destroy();
Observe(nullptr);
DestroyWebContents();
}
}
int WebContents::GetID() const {
return web_contents()->GetRenderProcessHost()->GetID();
}
@ -634,6 +627,15 @@ void WebContents::LoadURL(const GURL& url, const mate::Dictionary& options) {
web_contents()->GetController().LoadURLWithParams(params);
}
void WebContents::DownloadURL(const GURL& url) {
auto browser_context = web_contents()->GetBrowserContext();
auto download_manager =
content::BrowserContext::GetDownloadManager(browser_context);
download_manager->DownloadUrl(
content::DownloadUrlParameters::FromWebContents(web_contents(), url));
}
GURL WebContents::GetURL() const {
return web_contents()->GetURL();
}
@ -987,82 +989,73 @@ v8::Local<v8::Value> WebContents::DevToolsWebContents(v8::Isolate* isolate) {
return v8::Local<v8::Value>::New(isolate, devtools_web_contents_);
}
mate::ObjectTemplateBuilder WebContents::GetObjectTemplateBuilder(
v8::Isolate* isolate) {
if (template_.IsEmpty())
template_.Reset(isolate, mate::ObjectTemplateBuilder(isolate)
.SetMethod("destroy", &WebContents::Destroy, true)
.SetMethod("isDestroyed", &WebContents::IsDestroyed, true)
.SetMethod("getId", &WebContents::GetID)
.SetMethod("equal", &WebContents::Equal)
.SetMethod("_loadURL", &WebContents::LoadURL)
.SetMethod("_getURL", &WebContents::GetURL)
.SetMethod("getTitle", &WebContents::GetTitle)
.SetMethod("isLoading", &WebContents::IsLoading)
.SetMethod("isWaitingForResponse", &WebContents::IsWaitingForResponse)
.SetMethod("_stop", &WebContents::Stop)
.SetMethod("_goBack", &WebContents::GoBack)
.SetMethod("_goForward", &WebContents::GoForward)
.SetMethod("_goToOffset", &WebContents::GoToOffset)
.SetMethod("isCrashed", &WebContents::IsCrashed)
.SetMethod("setUserAgent", &WebContents::SetUserAgent)
.SetMethod("getUserAgent", &WebContents::GetUserAgent)
.SetMethod("insertCSS", &WebContents::InsertCSS)
.SetMethod("savePage", &WebContents::SavePage)
.SetMethod("_executeJavaScript", &WebContents::ExecuteJavaScript)
.SetMethod("openDevTools", &WebContents::OpenDevTools)
.SetMethod("closeDevTools", &WebContents::CloseDevTools)
.SetMethod("isDevToolsOpened", &WebContents::IsDevToolsOpened)
.SetMethod("enableDeviceEmulation",
&WebContents::EnableDeviceEmulation)
.SetMethod("disableDeviceEmulation",
&WebContents::DisableDeviceEmulation)
.SetMethod("toggleDevTools", &WebContents::ToggleDevTools)
.SetMethod("inspectElement", &WebContents::InspectElement)
.SetMethod("setAudioMuted", &WebContents::SetAudioMuted)
.SetMethod("isAudioMuted", &WebContents::IsAudioMuted)
.SetMethod("undo", &WebContents::Undo)
.SetMethod("redo", &WebContents::Redo)
.SetMethod("cut", &WebContents::Cut)
.SetMethod("copy", &WebContents::Copy)
.SetMethod("paste", &WebContents::Paste)
.SetMethod("pasteAndMatchStyle", &WebContents::PasteAndMatchStyle)
.SetMethod("delete", &WebContents::Delete)
.SetMethod("selectAll", &WebContents::SelectAll)
.SetMethod("unselect", &WebContents::Unselect)
.SetMethod("replace", &WebContents::Replace)
.SetMethod("replaceMisspelling", &WebContents::ReplaceMisspelling)
.SetMethod("focus", &WebContents::Focus)
.SetMethod("tabTraverse", &WebContents::TabTraverse)
.SetMethod("_send", &WebContents::SendIPCMessage, true)
.SetMethod("sendInputEvent", &WebContents::SendInputEvent)
.SetMethod("beginFrameSubscription",
&WebContents::BeginFrameSubscription)
.SetMethod("endFrameSubscription", &WebContents::EndFrameSubscription)
.SetMethod("setSize", &WebContents::SetSize)
.SetMethod("setAllowTransparency", &WebContents::SetAllowTransparency)
.SetMethod("isGuest", &WebContents::IsGuest)
.SetMethod("getWebPreferences", &WebContents::GetWebPreferences)
.SetMethod("getOwnerBrowserWindow", &WebContents::GetOwnerBrowserWindow)
.SetMethod("hasServiceWorker", &WebContents::HasServiceWorker)
.SetMethod("unregisterServiceWorker",
&WebContents::UnregisterServiceWorker)
.SetMethod("inspectServiceWorker", &WebContents::InspectServiceWorker)
.SetMethod("print", &WebContents::Print)
.SetMethod("_printToPDF", &WebContents::PrintToPDF)
.SetMethod("addWorkSpace", &WebContents::AddWorkSpace)
.SetMethod("removeWorkSpace", &WebContents::RemoveWorkSpace)
.SetProperty("session", &WebContents::Session, true)
.SetProperty("devToolsWebContents",
&WebContents::DevToolsWebContents, true)
.Build());
return mate::ObjectTemplateBuilder(
isolate, v8::Local<v8::ObjectTemplate>::New(isolate, template_));
}
bool WebContents::IsDestroyed() const {
return !web_contents();
// static
void WebContents::BuildPrototype(v8::Isolate* isolate,
v8::Local<v8::ObjectTemplate> prototype) {
mate::ObjectTemplateBuilder(isolate, prototype)
.MakeDestroyable()
.SetMethod("getId", &WebContents::GetID)
.SetMethod("equal", &WebContents::Equal)
.SetMethod("_loadURL", &WebContents::LoadURL)
.SetMethod("downloadURL", &WebContents::DownloadURL)
.SetMethod("_getURL", &WebContents::GetURL)
.SetMethod("getTitle", &WebContents::GetTitle)
.SetMethod("isLoading", &WebContents::IsLoading)
.SetMethod("isWaitingForResponse", &WebContents::IsWaitingForResponse)
.SetMethod("_stop", &WebContents::Stop)
.SetMethod("_goBack", &WebContents::GoBack)
.SetMethod("_goForward", &WebContents::GoForward)
.SetMethod("_goToOffset", &WebContents::GoToOffset)
.SetMethod("isCrashed", &WebContents::IsCrashed)
.SetMethod("setUserAgent", &WebContents::SetUserAgent)
.SetMethod("getUserAgent", &WebContents::GetUserAgent)
.SetMethod("insertCSS", &WebContents::InsertCSS)
.SetMethod("savePage", &WebContents::SavePage)
.SetMethod("_executeJavaScript", &WebContents::ExecuteJavaScript)
.SetMethod("openDevTools", &WebContents::OpenDevTools)
.SetMethod("closeDevTools", &WebContents::CloseDevTools)
.SetMethod("isDevToolsOpened", &WebContents::IsDevToolsOpened)
.SetMethod("enableDeviceEmulation",
&WebContents::EnableDeviceEmulation)
.SetMethod("disableDeviceEmulation",
&WebContents::DisableDeviceEmulation)
.SetMethod("toggleDevTools", &WebContents::ToggleDevTools)
.SetMethod("inspectElement", &WebContents::InspectElement)
.SetMethod("setAudioMuted", &WebContents::SetAudioMuted)
.SetMethod("isAudioMuted", &WebContents::IsAudioMuted)
.SetMethod("undo", &WebContents::Undo)
.SetMethod("redo", &WebContents::Redo)
.SetMethod("cut", &WebContents::Cut)
.SetMethod("copy", &WebContents::Copy)
.SetMethod("paste", &WebContents::Paste)
.SetMethod("pasteAndMatchStyle", &WebContents::PasteAndMatchStyle)
.SetMethod("delete", &WebContents::Delete)
.SetMethod("selectAll", &WebContents::SelectAll)
.SetMethod("unselect", &WebContents::Unselect)
.SetMethod("replace", &WebContents::Replace)
.SetMethod("replaceMisspelling", &WebContents::ReplaceMisspelling)
.SetMethod("focus", &WebContents::Focus)
.SetMethod("tabTraverse", &WebContents::TabTraverse)
.SetMethod("_send", &WebContents::SendIPCMessage)
.SetMethod("sendInputEvent", &WebContents::SendInputEvent)
.SetMethod("beginFrameSubscription",
&WebContents::BeginFrameSubscription)
.SetMethod("endFrameSubscription", &WebContents::EndFrameSubscription)
.SetMethod("setSize", &WebContents::SetSize)
.SetMethod("setAllowTransparency", &WebContents::SetAllowTransparency)
.SetMethod("isGuest", &WebContents::IsGuest)
.SetMethod("getWebPreferences", &WebContents::GetWebPreferences)
.SetMethod("getOwnerBrowserWindow", &WebContents::GetOwnerBrowserWindow)
.SetMethod("hasServiceWorker", &WebContents::HasServiceWorker)
.SetMethod("unregisterServiceWorker",
&WebContents::UnregisterServiceWorker)
.SetMethod("inspectServiceWorker", &WebContents::InspectServiceWorker)
.SetMethod("print", &WebContents::Print)
.SetMethod("_printToPDF", &WebContents::PrintToPDF)
.SetMethod("addWorkSpace", &WebContents::AddWorkSpace)
.SetMethod("removeWorkSpace", &WebContents::RemoveWorkSpace)
.SetProperty("session", &WebContents::Session)
.SetProperty("devToolsWebContents", &WebContents::DevToolsWebContents);
}
AtomBrowserContext* WebContents::GetBrowserContext() const {

View file

@ -54,12 +54,10 @@ class WebContents : public mate::TrackableObject<WebContents>,
static mate::Handle<WebContents> Create(
v8::Isolate* isolate, const mate::Dictionary& options);
// mate::TrackableObject:
void Destroy() override;
int GetID() const;
bool Equal(const WebContents* web_contents) const;
void LoadURL(const GURL& url, const mate::Dictionary& options);
void DownloadURL(const GURL& url);
GURL GetURL() const;
base::string16 GetTitle() const;
bool IsLoading() const;
@ -144,16 +142,15 @@ class WebContents : public mate::TrackableObject<WebContents>,
v8::Local<v8::Value> Session(v8::Isolate* isolate);
v8::Local<v8::Value> DevToolsWebContents(v8::Isolate* isolate);
// mate::TrackableObject:
static void BuildPrototype(v8::Isolate* isolate,
v8::Local<v8::ObjectTemplate> prototype);
protected:
explicit WebContents(content::WebContents* web_contents);
WebContents(v8::Isolate* isolate, const mate::Dictionary& options);
~WebContents();
// mate::Wrappable:
mate::ObjectTemplateBuilder GetObjectTemplateBuilder(
v8::Isolate* isolate) override;
bool IsDestroyed() const override;
// content::WebContentsDelegate:
bool AddMessageToConsole(content::WebContents* source,
int32 level,

View file

@ -157,8 +157,8 @@ Window::Window(v8::Isolate* isolate, const mate::Dictionary& options) {
}
Window::~Window() {
if (window_)
Destroy();
if (!window_->IsClosed())
window_->CloseContents(nullptr);
}
void Window::WillCloseWindow(bool* prevent_default) {
@ -166,19 +166,19 @@ void Window::WillCloseWindow(bool* prevent_default) {
}
void Window::OnWindowClosed() {
if (api_web_contents_) {
api_web_contents_->DestroyWebContents();
api_web_contents_ = nullptr;
web_contents_.Reset();
}
api_web_contents_->DestroyWebContents();
RemoveFromWeakMap();
window_->RemoveObserver(this);
// We can not call Destroy here because we need to call Emit first, but we
// also do not want any method to be used, so just mark as destroyed here.
MarkDestroyed();
Emit("closed");
// Clean up the resources after window has been closed.
base::MessageLoop::current()->DeleteSoon(FROM_HERE, window_.release());
// Destroy the native class when window is closed.
base::MessageLoop::current()->PostTask(FROM_HERE, GetDestroyClosure());
}
void Window::OnWindowBlur() {
@ -276,15 +276,6 @@ mate::Wrappable* Window::New(v8::Isolate* isolate, mate::Arguments* args) {
return new Window(isolate, options);
}
bool Window::IsDestroyed() const {
return !window_ || window_->IsClosed();
}
void Window::Destroy() {
if (window_)
window_->CloseContents(nullptr);
}
void Window::Close() {
window_->Close();
}
@ -622,8 +613,7 @@ v8::Local<v8::Value> Window::WebContents(v8::Isolate* isolate) {
void Window::BuildPrototype(v8::Isolate* isolate,
v8::Local<v8::ObjectTemplate> prototype) {
mate::ObjectTemplateBuilder(isolate, prototype)
.SetMethod("destroy", &Window::Destroy, true)
.SetMethod("isDestroyed", &Window::IsDestroyed, true)
.MakeDestroyable()
.SetMethod("close", &Window::Close)
.SetMethod("focus", &Window::Focus)
.SetMethod("isFocused", &Window::IsFocused)
@ -695,8 +685,8 @@ void Window::BuildPrototype(v8::Isolate* isolate,
.SetMethod("showDefinitionForSelection",
&Window::ShowDefinitionForSelection)
#endif
.SetProperty("id", &Window::ID, true)
.SetProperty("webContents", &Window::WebContents, true);
.SetProperty("id", &Window::ID)
.SetProperty("webContents", &Window::WebContents);
}
// static

View file

@ -77,13 +77,7 @@ class Window : public mate::TrackableObject<Window>,
void OnWindowMessage(UINT message, WPARAM w_param, LPARAM l_param) override;
#endif
// mate::Wrappable:
bool IsDestroyed() const override;
private:
// mate::TrackableObject:
void Destroy() override;
// APIs for NativeWindow.
void Close();
void Focus();

View file

@ -30,11 +30,11 @@ class IDUserData : public base::SupportsUserData::Data {
TrackableObjectBase::TrackableObjectBase()
: weak_map_id_(0), wrapped_(nullptr), weak_factory_(this) {
RegisterDestructionCallback(
base::Bind(&TrackableObjectBase::Destroy, weak_factory_.GetWeakPtr()));
cleanup_ = RegisterDestructionCallback(GetDestroyClosure());
}
TrackableObjectBase::~TrackableObjectBase() {
cleanup_.Run();
}
void TrackableObjectBase::AfterInit(v8::Isolate* isolate) {
@ -42,6 +42,18 @@ void TrackableObjectBase::AfterInit(v8::Isolate* isolate) {
AttachAsUserData(wrapped_);
}
void TrackableObjectBase::MarkDestroyed() {
GetWrapper(isolate())->SetAlignedPointerInInternalField(0, nullptr);
}
base::Closure TrackableObjectBase::GetDestroyClosure() {
return base::Bind(&TrackableObjectBase::Destroy, weak_factory_.GetWeakPtr());
}
void TrackableObjectBase::Destroy() {
delete this;
}
void TrackableObjectBase::AttachAsUserData(base::SupportsUserData* wrapped) {
if (weak_map_id_ != 0) {
wrapped->SetUserData(kTrackedObjectKey, new IDUserData(weak_map_id_));
@ -63,9 +75,9 @@ int32_t TrackableObjectBase::GetIDFromWrappedClass(base::SupportsUserData* w) {
}
// static
void TrackableObjectBase::RegisterDestructionCallback(
const base::Closure& closure) {
atom::AtomBrowserMainParts::Get()->RegisterDestructionCallback(closure);
base::Closure TrackableObjectBase::RegisterDestructionCallback(
const base::Closure& c) {
return atom::AtomBrowserMainParts::Get()->RegisterDestructionCallback(c);
}
} // namespace mate

View file

@ -12,6 +12,7 @@
#include "base/bind.h"
#include "base/memory/scoped_ptr.h"
#include "base/memory/weak_ptr.h"
#include "native_mate/object_template_builder.h"
namespace base {
class SupportsUserData;
@ -30,26 +31,32 @@ class TrackableObjectBase : public mate::EventEmitter {
// Wrap TrackableObject into a class that SupportsUserData.
void AttachAsUserData(base::SupportsUserData* wrapped);
// Subclasses should implement this to destroy their native types.
virtual void Destroy() = 0;
protected:
~TrackableObjectBase() override;
// mate::Wrappable:
void AfterInit(v8::Isolate* isolate) override;
// Mark the JS object as destroyed.
void MarkDestroyed();
// Returns a closure that can destroy the native class.
base::Closure GetDestroyClosure();
// Get the weak_map_id from SupportsUserData.
static int32_t GetIDFromWrappedClass(base::SupportsUserData* wrapped);
// Register a callback that should be destroyed before JavaScript environment
// gets destroyed.
static void RegisterDestructionCallback(const base::Closure& closure);
static base::Closure RegisterDestructionCallback(const base::Closure& c);
int32_t weak_map_id_;
base::SupportsUserData* wrapped_;
private:
void Destroy();
base::Closure cleanup_;
base::WeakPtrFactory<TrackableObjectBase> weak_factory_;
DISALLOW_COPY_AND_ASSIGN(TrackableObjectBase);
@ -91,11 +98,6 @@ class TrackableObject : public TrackableObjectBase {
return std::vector<v8::Local<v8::Object>>();
}
TrackableObject() {
RegisterDestructionCallback(
base::Bind(&TrackableObject<T>::ReleaseAllWeakReferences));
}
// Removes this instance from the weak map.
void RemoveFromWeakMap() {
if (weak_map_ && weak_map_->Has(weak_map_id()))
@ -103,28 +105,49 @@ class TrackableObject : public TrackableObjectBase {
}
protected:
TrackableObject() {}
~TrackableObject() override {
RemoveFromWeakMap();
}
void AfterInit(v8::Isolate* isolate) override {
if (!weak_map_)
if (!weak_map_) {
weak_map_.reset(new atom::IDWeakMap);
RegisterDestructionCallback(
base::Bind(&TrackableObject<T>::ReleaseAllWeakReferences));
}
weak_map_id_ = weak_map_->Add(isolate, GetWrapper(isolate));
TrackableObjectBase::AfterInit(isolate);
}
private:
// mate::Wrappable:
mate::ObjectTemplateBuilder GetObjectTemplateBuilder(
v8::Isolate* isolate) override {
if (template_.IsEmpty()) {
auto templ = v8::ObjectTemplate::New(isolate);
T::BuildPrototype(isolate, templ);
template_.Reset(isolate, templ);
}
return ObjectTemplateBuilder(
isolate, v8::Local<v8::ObjectTemplate>::New(isolate, template_));
}
// Releases all weak references in weak map, called when app is terminating.
static void ReleaseAllWeakReferences() {
weak_map_.reset();
}
static v8::Persistent<v8::ObjectTemplate> template_;
static scoped_ptr<atom::IDWeakMap> weak_map_;
DISALLOW_COPY_AND_ASSIGN(TrackableObject);
};
template<typename T>
v8::Persistent<v8::ObjectTemplate> TrackableObject<T>::template_;
template<typename T>
scoped_ptr<atom::IDWeakMap> TrackableObject<T>::weak_map_;

View file

@ -25,6 +25,11 @@
namespace atom {
template<typename T>
void Erase(T* container, typename T::iterator iter) {
container->erase(iter);
}
// static
AtomBrowserMainParts* AtomBrowserMainParts::self_ = NULL;
@ -56,9 +61,10 @@ bool AtomBrowserMainParts::SetExitCode(int code) {
return true;
}
void AtomBrowserMainParts::RegisterDestructionCallback(
base::Closure AtomBrowserMainParts::RegisterDestructionCallback(
const base::Closure& callback) {
destruction_callbacks_.push_back(callback);
auto iter = destructors_.insert(destructors_.end(), callback);
return base::Bind(&Erase<std::list<base::Closure>>, &destructors_, iter);
}
void AtomBrowserMainParts::PreEarlyInitialization() {
@ -150,8 +156,13 @@ void AtomBrowserMainParts::PostMainMessageLoopRun() {
// Make sure destruction callbacks are called before message loop is
// destroyed, otherwise some objects that need to be deleted on IO thread
// won't be freed.
for (const auto& callback : destruction_callbacks_)
// We don't use ranged for loop because iterators are getting invalided when
// the callback runs.
for (auto iter = destructors_.begin(); iter != destructors_.end();) {
base::Closure& callback = *iter;
++iter;
callback.Run();
}
// Destroy JavaScript environment immediately after running destruction
// callbacks.

View file

@ -36,7 +36,8 @@ class AtomBrowserMainParts : public brightray::BrowserMainParts {
// Register a callback that should be destroyed before JavaScript environment
// gets destroyed.
void RegisterDestructionCallback(const base::Closure& callback);
// Returns a closure that can be used to remove |callback| from the list.
base::Closure RegisterDestructionCallback(const base::Closure& callback);
Browser* browser() { return browser_.get(); }
@ -82,7 +83,7 @@ class AtomBrowserMainParts : public brightray::BrowserMainParts {
base::Timer gc_timer_;
// List of callbacks should be executed before destroying JS env.
std::list<base::Closure> destruction_callbacks_;
std::list<base::Closure> destructors_;
static AtomBrowserMainParts* self_;

View file

@ -5,7 +5,7 @@ frameToGuest = {}
# Copy attribute of |parent| to |child| if it is not defined in |child|.
mergeOptions = (child, parent) ->
for own key, value of parent when key not in child
for own key, value of parent when key not in Object.keys child
if typeof value is 'object'
child[key] = mergeOptions {}, value
else
@ -39,11 +39,12 @@ createGuest = (embedder, url, frameName, options) ->
# When |embedder| is destroyed we should also destroy attached guest, and if
# guest is closed by user then we should prevent |embedder| from double
# closing guest.
guestId = guest.id
closedByEmbedder = ->
guest.removeListener 'closed', closedByUser
guest.destroy()
closedByUser = ->
embedder.send 'ATOM_SHELL_GUEST_WINDOW_MANAGER_WINDOW_CLOSED', guest.id
embedder.send 'ATOM_SHELL_GUEST_WINDOW_MANAGER_WINDOW_CLOSED', guestId
embedder.removeListener 'render-view-deleted', closedByEmbedder
embedder.once 'render-view-deleted', closedByEmbedder
guest.once 'closed', closedByUser

View file

@ -18,6 +18,8 @@
namespace {
v8::Persistent<v8::ObjectTemplate> template_;
class Archive : public mate::Wrappable {
public:
static v8::Local<v8::Value> Create(v8::Isolate* isolate,
@ -101,15 +103,20 @@ class Archive : public mate::Wrappable {
// mate::Wrappable:
mate::ObjectTemplateBuilder GetObjectTemplateBuilder(v8::Isolate* isolate) {
return mate::ObjectTemplateBuilder(isolate)
.SetValue("path", archive_->path())
.SetMethod("getFileInfo", &Archive::GetFileInfo)
.SetMethod("stat", &Archive::Stat)
.SetMethod("readdir", &Archive::Readdir)
.SetMethod("realpath", &Archive::Realpath)
.SetMethod("copyFileOut", &Archive::CopyFileOut)
.SetMethod("getFd", &Archive::GetFD)
.SetMethod("destroy", &Archive::Destroy);
if (template_.IsEmpty())
template_.Reset(isolate, mate::ObjectTemplateBuilder(isolate)
.SetValue("path", archive_->path())
.SetMethod("getFileInfo", &Archive::GetFileInfo)
.SetMethod("stat", &Archive::Stat)
.SetMethod("readdir", &Archive::Readdir)
.SetMethod("realpath", &Archive::Realpath)
.SetMethod("copyFileOut", &Archive::CopyFileOut)
.SetMethod("getFd", &Archive::GetFD)
.SetMethod("destroy", &Archive::Destroy)
.Build());
return mate::ObjectTemplateBuilder(
isolate, v8::Local<v8::ObjectTemplate>::New(isolate, template_));
}
private:

View file

@ -4,7 +4,9 @@
#include "atom/common/native_mate_converters/callback.h"
#include "atom/browser/atom_browser_main_parts.h"
#include "content/public/browser/browser_thread.h"
using content::BrowserThread;
namespace mate {
@ -56,31 +58,59 @@ v8::Local<v8::Value> BindFunctionWith(v8::Isolate* isolate,
} // namespace
// Destroy the class on UI thread when possible.
struct DeleteOnUIThread {
template<typename T>
static void Destruct(const T* x) {
if (Locker::IsBrowserProcess() &&
!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
BrowserThread::DeleteSoon(BrowserThread::UI, FROM_HERE, x);
} else {
delete x;
}
}
};
// Like v8::Global, but ref-counted.
template<typename T>
class RefCountedGlobal : public base::RefCountedThreadSafe<RefCountedGlobal<T>,
DeleteOnUIThread> {
public:
RefCountedGlobal(v8::Isolate* isolate, v8::Local<v8::Value> value)
: handle_(isolate, v8::Local<T>::Cast(value)) {
}
bool IsAlive() const {
return !handle_.IsEmpty();
}
v8::Local<T> NewHandle(v8::Isolate* isolate) const {
return v8::Local<T>::New(isolate, handle_);
}
private:
v8::Global<T> handle_;
DISALLOW_COPY_AND_ASSIGN(RefCountedGlobal);
};
SafeV8Function::SafeV8Function(v8::Isolate* isolate, v8::Local<v8::Value> value)
: v8_function_(new RefCountedPersistent<v8::Function>(isolate, value)),
weak_factory_(this) {
Init();
: v8_function_(new RefCountedGlobal<v8::Function>(isolate, value)) {
}
SafeV8Function::SafeV8Function(const SafeV8Function& other)
: v8_function_(other.v8_function_),
weak_factory_(this) {
Init();
: v8_function_(other.v8_function_) {
}
v8::Local<v8::Function> SafeV8Function::NewHandle() const {
return v8_function_->NewHandle();
SafeV8Function::~SafeV8Function() {
}
void SafeV8Function::Init() {
if (Locker::IsBrowserProcess() && atom::AtomBrowserMainParts::Get())
atom::AtomBrowserMainParts::Get()->RegisterDestructionCallback(
base::Bind(&SafeV8Function::FreeHandle, weak_factory_.GetWeakPtr()));
bool SafeV8Function::IsAlive() const {
return v8_function_.get() && v8_function_->IsAlive();
}
void SafeV8Function::FreeHandle() {
Locker locker(v8_function_->isolate());
v8_function_ = nullptr;
v8::Local<v8::Function> SafeV8Function::NewHandle(v8::Isolate* isolate) const {
return v8_function_->NewHandle(isolate);
}
v8::Local<v8::Value> CreateFunctionFromTranslater(

View file

@ -19,23 +19,21 @@ namespace mate {
namespace internal {
// Manages the V8 function with RAII, and automatically cleans the handle when
// JavaScript context is destroyed, even when the class is not destroyed.
template<typename T>
class RefCountedGlobal;
// Manages the V8 function with RAII.
class SafeV8Function {
public:
SafeV8Function(v8::Isolate* isolate, v8::Local<v8::Value> value);
SafeV8Function(const SafeV8Function& other);
~SafeV8Function();
bool is_alive() const { return v8_function_.get(); }
v8::Local<v8::Function> NewHandle() const;
bool IsAlive() const;
v8::Local<v8::Function> NewHandle(v8::Isolate* isolate) const;
private:
void Init();
void FreeHandle();
scoped_refptr<RefCountedPersistent<v8::Function>> v8_function_;
base::WeakPtrFactory<SafeV8Function> weak_factory_;
scoped_refptr<RefCountedGlobal<v8::Function>> v8_function_;
};
// Helper to invoke a V8 function with C++ parameters.
@ -49,12 +47,12 @@ struct V8FunctionInvoker<v8::Local<v8::Value>(ArgTypes...)> {
ArgTypes... raw) {
Locker locker(isolate);
v8::EscapableHandleScope handle_scope(isolate);
if (!function.is_alive())
if (!function.IsAlive())
return v8::Null(isolate);
scoped_ptr<blink::WebScopedRunV8Script> script_scope(
Locker::IsBrowserProcess() ?
nullptr : new blink::WebScopedRunV8Script(isolate));
v8::Local<v8::Function> holder = function.NewHandle();
v8::Local<v8::Function> holder = function.NewHandle(isolate);
v8::Local<v8::Context> context = holder->CreationContext();
v8::Context::Scope context_scope(context);
std::vector<v8::Local<v8::Value>> args = { ConvertToV8(isolate, raw)... };
@ -70,12 +68,12 @@ struct V8FunctionInvoker<void(ArgTypes...)> {
ArgTypes... raw) {
Locker locker(isolate);
v8::HandleScope handle_scope(isolate);
if (!function.is_alive())
if (!function.IsAlive())
return;
scoped_ptr<blink::WebScopedRunV8Script> script_scope(
Locker::IsBrowserProcess() ?
nullptr : new blink::WebScopedRunV8Script(isolate));
v8::Local<v8::Function> holder = function.NewHandle();
v8::Local<v8::Function> holder = function.NewHandle(isolate);
v8::Local<v8::Context> context = holder->CreationContext();
v8::Context::Scope context_scope(context);
std::vector<v8::Local<v8::Value>> args = { ConvertToV8(isolate, raw)... };
@ -91,12 +89,12 @@ struct V8FunctionInvoker<ReturnType(ArgTypes...)> {
Locker locker(isolate);
v8::HandleScope handle_scope(isolate);
ReturnType ret = ReturnType();
if (!function.is_alive())
if (!function.IsAlive())
return ret;
scoped_ptr<blink::WebScopedRunV8Script> script_scope(
Locker::IsBrowserProcess() ?
nullptr : new blink::WebScopedRunV8Script(isolate));
v8::Local<v8::Function> holder = function.NewHandle();
v8::Local<v8::Function> holder = function.NewHandle(isolate);
v8::Local<v8::Context> context = holder->CreationContext();
v8::Context::Scope context_scope(context);
std::vector<v8::Local<v8::Value>> args = { ConvertToV8(isolate, raw)... };

View file

@ -288,6 +288,7 @@ registerWebViewElement = ->
'replace'
'replaceMisspelling'
'getId'
'downloadURL'
'inspectServiceWorker'
'print'
'printToPDF'

View file

@ -242,6 +242,13 @@ const options = {"extraHeaders" : "pragma: no-cache\n"}
webContents.loadURL(url, options)
```
### `webContents.downloadURL(url)`
* `url` URL
Initiates a download of the resource at `url` without navigating. The
`will-download` event of `session` will be triggered.
### `webContents.getURL()`
Returns URL of the current web page.

View file

@ -164,6 +164,7 @@ The `webview` tag has the following methods:
**Note:** The webview element must be loaded before using the methods.
**Example**
```javascript
webview.addEventListener("dom-ready", function() {
webview.openDevTools();

View file

@ -262,6 +262,7 @@ describe 'browser-window module', ->
w.loadURL "file://#{fixtures}/pages/window-open.html"
it 'emits when link with target is called', (done) ->
@timeout 10000
w.webContents.once 'new-window', (e, url, frameName) ->
e.preventDefault()
assert.equal url, 'http://host/'

View file

@ -87,23 +87,43 @@ describe 'session module', ->
res.end mockPDF
downloadServer.close()
it 'can download successfully', (done) ->
assertDownload = (event, state, url, mimeType, receivedBytes, totalBytes, disposition, filename, port) ->
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
it 'can download using BrowserWindow.loadURL', (done) ->
downloadServer.listen 0, '127.0.0.1', ->
{port} = downloadServer.address()
ipcRenderer.sendSync 'set-download-option', false
w.loadURL "#{url}:#{port}"
ipcRenderer.once 'download-done', (event, 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
assertDownload event, state, url, mimeType, receivedBytes, totalBytes, disposition, filename, port
done()
it 'can download using WebView.downloadURL', (done) ->
downloadServer.listen 0, '127.0.0.1', ->
{port} = downloadServer.address()
ipcRenderer.sendSync 'set-download-option', false
webview = new WebView
webview.src = "file://#{fixtures}/api/blank.html"
webview.addEventListener 'did-finish-load', ->
webview.downloadURL "#{url}:#{port}/"
ipcRenderer.once 'download-done', (event, state, url, mimeType, receivedBytes, totalBytes, disposition, filename) ->
assertDownload event, state, url, mimeType, receivedBytes, totalBytes, disposition, filename, port
document.body.removeChild(webview)
done()
document.body.appendChild webview
it 'can cancel download', (done) ->
downloadServer.listen 0, '127.0.0.1', ->
{port} = downloadServer.address()

View file

@ -75,13 +75,22 @@ describe 'chromium feature', ->
it 'inherit options of parent window', (done) ->
listener = (event) ->
size = remote.getCurrentWindow().getSize()
assert.equal event.data, "size: #{size.width} #{size.height}"
[width, height] = remote.getCurrentWindow().getSize()
assert.equal event.data, "size: #{width} #{height}"
b.close()
done()
window.addEventListener 'message', listener
b = window.open "file://#{fixtures}/pages/window-open-size.html", '', 'show=no'
it 'does not override child options', (done) ->
size = {width: 350, height: 450}
listener = (event) ->
assert.equal event.data, "size: #{size.width} #{size.height}"
b.close()
done()
window.addEventListener 'message', listener
b = window.open "file://#{fixtures}/pages/window-open-size.html", '', "show=no,width=#{size.width},height=#{size.height}"
describe 'window.opener', ->
@timeout 10000

View file

@ -2,7 +2,7 @@
<body>
<script type="text/javascript" charset="utf-8">
var size = require('electron').remote.getCurrentWindow().getSize();
window.opener.postMessage('size: ' + size.width + ' ' + size.height, '*')
window.opener.postMessage('size: ' + size[0] + ' ' + size[1], '*')
</script>
</body>
</html>

2
vendor/native_mate vendored

@ -1 +1 @@
Subproject commit 93984941005bab194a2d47aff655d525c064efcb
Subproject commit e859228db163c27410fb200c2df0715478fdf0d7