From 3f0c00757806d2bf50027c140a64d5aed96afb30 Mon Sep 17 00:00:00 2001 From: Omri Litov Date: Thu, 7 Jan 2016 22:38:35 +0200 Subject: [PATCH 01/95] Added getNativeWindowHandle --- atom/browser/api/atom_api_window.cc | 6 ++++++ atom/browser/api/atom_api_window.h | 1 + atom/browser/native_window.h | 1 + atom/browser/native_window_mac.h | 1 + atom/browser/native_window_mac.mm | 4 ++++ atom/browser/native_window_views.h | 2 +- 6 files changed, 14 insertions(+), 1 deletion(-) diff --git a/atom/browser/api/atom_api_window.cc b/atom/browser/api/atom_api_window.cc index 222f2cae03f1..c9410d11f886 100644 --- a/atom/browser/api/atom_api_window.cc +++ b/atom/browser/api/atom_api_window.cc @@ -594,6 +594,11 @@ void Window::SetAspectRatio(double aspect_ratio, mate::Arguments* args) { window_->SetAspectRatio(aspect_ratio, extra_size); } +v8::Local Window::GetNativeWindowHandle() { + gfx::AcceleratedWidget handle = window_->GetAcceleratedWidget(); + return ToBuffer(isolate(), static_cast(&handle), sizeof(gfx::AcceleratedWidget)); +} + void Window::SetVisibleOnAllWorkspaces(bool visible) { return window_->SetVisibleOnAllWorkspaces(visible); } @@ -634,6 +639,7 @@ void Window::BuildPrototype(v8::Isolate* isolate, .SetMethod("setFullScreen", &Window::SetFullScreen) .SetMethod("isFullScreen", &Window::IsFullscreen) .SetMethod("setAspectRatio", &Window::SetAspectRatio) + .SetMethod("getNativeWindowHandle", &Window::GetNativeWindowHandle) .SetMethod("getBounds", &Window::GetBounds) .SetMethod("setBounds", &Window::SetBounds) .SetMethod("getSize", &Window::GetSize) diff --git a/atom/browser/api/atom_api_window.h b/atom/browser/api/atom_api_window.h index 9297b2fe7562..fe9a7e828d39 100644 --- a/atom/browser/api/atom_api_window.h +++ b/atom/browser/api/atom_api_window.h @@ -137,6 +137,7 @@ class Window : public mate::TrackableObject, void SetMenuBarVisibility(bool visible); bool IsMenuBarVisible(); void SetAspectRatio(double aspect_ratio, mate::Arguments* args); + v8::Local GetNativeWindowHandle(); #if defined(OS_WIN) typedef base::Callback, diff --git a/atom/browser/native_window.h b/atom/browser/native_window.h index c60c0dd5f1d6..a11be26ff7d1 100644 --- a/atom/browser/native_window.h +++ b/atom/browser/native_window.h @@ -143,6 +143,7 @@ class NativeWindow : public base::SupportsUserData, virtual void SetMenu(ui::MenuModel* menu); virtual bool HasModalDialog(); virtual gfx::NativeWindow GetNativeWindow() = 0; + virtual gfx::AcceleratedWidget GetAcceleratedWidget() = 0; // Taskbar/Dock APIs. virtual void SetProgressBar(double progress) = 0; diff --git a/atom/browser/native_window_mac.h b/atom/browser/native_window_mac.h index 23f210d597f6..d1703ac944da 100644 --- a/atom/browser/native_window_mac.h +++ b/atom/browser/native_window_mac.h @@ -65,6 +65,7 @@ class NativeWindowMac : public NativeWindow { void SetIgnoreMouseEvents(bool ignore) override; bool HasModalDialog() override; gfx::NativeWindow GetNativeWindow() override; + gfx::AcceleratedWidget GetAcceleratedWidget() override; void SetProgressBar(double progress) override; void SetOverlayIcon(const gfx::Image& overlay, const std::string& description) override; diff --git a/atom/browser/native_window_mac.mm b/atom/browser/native_window_mac.mm index 3735772fe1df..434067712c34 100644 --- a/atom/browser/native_window_mac.mm +++ b/atom/browser/native_window_mac.mm @@ -731,6 +731,10 @@ gfx::NativeWindow NativeWindowMac::GetNativeWindow() { return window_; } +gfx::AcceleratedWidget NativeWindowMac::GetAcceleratedWidget() { + return window_; +} + void NativeWindowMac::SetProgressBar(double progress) { NSDockTile* dock_tile = [NSApp dockTile]; diff --git a/atom/browser/native_window_views.h b/atom/browser/native_window_views.h index 6c47c74331d0..125cd4740831 100644 --- a/atom/browser/native_window_views.h +++ b/atom/browser/native_window_views.h @@ -90,7 +90,7 @@ class NativeWindowViews : public NativeWindow, void SetVisibleOnAllWorkspaces(bool visible) override; bool IsVisibleOnAllWorkspaces() override; - gfx::AcceleratedWidget GetAcceleratedWidget(); + gfx::AcceleratedWidget GetAcceleratedWidget() override; views::Widget* widget() const { return window_.get(); } From 224955d6ac4ecd8a23141705f0606bf1abcd3d8b Mon Sep 17 00:00:00 2001 From: Omri Litov Date: Thu, 7 Jan 2016 23:17:23 +0200 Subject: [PATCH 02/95] Update browser-window.md --- docs/api/browser-window.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/api/browser-window.md b/docs/api/browser-window.md index 8fb64b561224..12c528a897d7 100644 --- a/docs/api/browser-window.md +++ b/docs/api/browser-window.md @@ -571,6 +571,10 @@ Enters or leaves the kiosk mode. Returns whether the window is in kiosk mode. +### `win.getNativeWindowHandle()` + +Returns the OS window handle in a buffer. + ### `win.hookWindowMessage(message, callback)` _Windows_ * `message` Integer From 943e46f3bd8eb4cfcf0df97218750bfc4856701c Mon Sep 17 00:00:00 2001 From: Omri Litov Date: Fri, 8 Jan 2016 00:27:53 +0200 Subject: [PATCH 03/95] Fix linux and mac build errors --- atom/browser/api/atom_api_window.cc | 6 +++--- atom/browser/native_window_mac.mm | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/atom/browser/api/atom_api_window.cc b/atom/browser/api/atom_api_window.cc index c9410d11f886..494d3fedd76b 100644 --- a/atom/browser/api/atom_api_window.cc +++ b/atom/browser/api/atom_api_window.cc @@ -107,7 +107,6 @@ void TranslateOldOptions(v8::Isolate* isolate, v8::Local options) { } } -#if defined(OS_WIN) // Converts binary data to Buffer. v8::Local ToBuffer(v8::Isolate* isolate, void* val, int size) { auto buffer = node::Buffer::New(isolate, static_cast(val), size); @@ -116,7 +115,6 @@ v8::Local ToBuffer(v8::Isolate* isolate, void* val, int size) { else return buffer.ToLocalChecked(); } -#endif } // namespace @@ -596,7 +594,9 @@ void Window::SetAspectRatio(double aspect_ratio, mate::Arguments* args) { v8::Local Window::GetNativeWindowHandle() { gfx::AcceleratedWidget handle = window_->GetAcceleratedWidget(); - return ToBuffer(isolate(), static_cast(&handle), sizeof(gfx::AcceleratedWidget)); + return ToBuffer(isolate(), + static_cast(&handle), + sizeof(gfx::AcceleratedWidget)); } void Window::SetVisibleOnAllWorkspaces(bool visible) { diff --git a/atom/browser/native_window_mac.mm b/atom/browser/native_window_mac.mm index 434067712c34..2d75a682c653 100644 --- a/atom/browser/native_window_mac.mm +++ b/atom/browser/native_window_mac.mm @@ -732,7 +732,7 @@ gfx::NativeWindow NativeWindowMac::GetNativeWindow() { } gfx::AcceleratedWidget NativeWindowMac::GetAcceleratedWidget() { - return window_; + return inspectable_web_contents()->GetView()->GetNativeView(); } void NativeWindowMac::SetProgressBar(double progress) { From df27cda36cb4fe04d122493897b69b9c8d6e1e51 Mon Sep 17 00:00:00 2001 From: Cheng Zhao Date: Fri, 8 Jan 2016 09:58:51 +0800 Subject: [PATCH 04/95] Bump v0.36.3 --- atom.gyp | 2 +- atom/browser/resources/mac/Info.plist | 4 ++-- atom/browser/resources/win/atom.rc | 8 ++++---- atom/common/atom_version.h | 2 +- package.json | 2 +- 5 files changed, 9 insertions(+), 9 deletions(-) diff --git a/atom.gyp b/atom.gyp index eb4302d74c27..ca2d6bf91a1f 100644 --- a/atom.gyp +++ b/atom.gyp @@ -4,7 +4,7 @@ 'product_name%': 'Electron', 'company_name%': 'GitHub, Inc', 'company_abbr%': 'github', - 'version%': '0.36.2', + 'version%': '0.36.3', }, 'includes': [ 'filenames.gypi', diff --git a/atom/browser/resources/mac/Info.plist b/atom/browser/resources/mac/Info.plist index 2f321fa8fc2d..105c034d250f 100644 --- a/atom/browser/resources/mac/Info.plist +++ b/atom/browser/resources/mac/Info.plist @@ -17,9 +17,9 @@ CFBundleIconFile atom.icns CFBundleVersion - 0.36.2 + 0.36.3 CFBundleShortVersionString - 0.36.2 + 0.36.3 LSApplicationCategoryType public.app-category.developer-tools LSMinimumSystemVersion diff --git a/atom/browser/resources/win/atom.rc b/atom/browser/resources/win/atom.rc index 225d910bc3f7..676b503fd3f9 100644 --- a/atom/browser/resources/win/atom.rc +++ b/atom/browser/resources/win/atom.rc @@ -56,8 +56,8 @@ END // VS_VERSION_INFO VERSIONINFO - FILEVERSION 0,36,2,0 - PRODUCTVERSION 0,36,2,0 + FILEVERSION 0,36,3,0 + PRODUCTVERSION 0,36,3,0 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -74,12 +74,12 @@ BEGIN BEGIN VALUE "CompanyName", "GitHub, Inc." VALUE "FileDescription", "Electron" - VALUE "FileVersion", "0.36.2" + VALUE "FileVersion", "0.36.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.36.2" + VALUE "ProductVersion", "0.36.3" VALUE "SquirrelAwareVersion", "1" END END diff --git a/atom/common/atom_version.h b/atom/common/atom_version.h index 9ad405faeb6c..55b5a3a402d9 100644 --- a/atom/common/atom_version.h +++ b/atom/common/atom_version.h @@ -7,7 +7,7 @@ #define ATOM_MAJOR_VERSION 0 #define ATOM_MINOR_VERSION 36 -#define ATOM_PATCH_VERSION 2 +#define ATOM_PATCH_VERSION 3 #define ATOM_VERSION_IS_RELEASE 1 diff --git a/package.json b/package.json index f7202f28d6a3..546be7dd52b1 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "electron", - "version": "0.36.2", + "version": "0.36.3", "devDependencies": { "asar": "^0.9.0", "coffee-script": "^1.9.2", From 6728d9291d45fe1ed167c43c6d2ec731f1867125 Mon Sep 17 00:00:00 2001 From: Luke Page Date: Fri, 8 Jan 2016 10:56:51 +0000 Subject: [PATCH 05/95] Correct misleading sentence on progress for transparent click through --- docs/api/frameless-window.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/docs/api/frameless-window.md b/docs/api/frameless-window.md index e70749f2894c..f9afa55af517 100644 --- a/docs/api/frameless-window.md +++ b/docs/api/frameless-window.md @@ -38,8 +38,7 @@ var win = new BrowserWindow({ transparent: true, frame: false }); ### Limitations * You can not click through the transparent area. We are going to introduce an - API to set window shape to solve this, but currently blocked at an - [upstream bug](https://code.google.com/p/chromium/issues/detail?id=387234). + API to set window shape to solve this, see [our issue](https://github.com/atom/electron/issues/1335) for details. * Transparent windows are not resizable. Setting `resizable` to `true` may make a transparent window stop working on some platforms. * The `blur` filter only applies to the web page, so there is no way to apply From f1edd5f26f38e28c53b3e2d5148dcc9081d57a23 Mon Sep 17 00:00:00 2001 From: leethomas Date: Thu, 7 Jan 2016 20:46:45 -0800 Subject: [PATCH 06/95] :apple: add default button index for osx --- atom/browser/api/atom_api_dialog.cc | 7 ++++--- atom/browser/api/lib/dialog.coffee | 10 ++++++---- atom/browser/ui/message_box.h | 2 ++ atom/browser/ui/message_box_mac.mm | 18 ++++++++++++++++-- 4 files changed, 28 insertions(+), 9 deletions(-) diff --git a/atom/browser/api/atom_api_dialog.cc b/atom/browser/api/atom_api_dialog.cc index 40ee4d0d9b51..e8c1ae3ba99f 100644 --- a/atom/browser/api/atom_api_dialog.cc +++ b/atom/browser/api/atom_api_dialog.cc @@ -41,6 +41,7 @@ namespace { void ShowMessageBox(int type, const std::vector& buttons, + int default_button_index, int cancel_id, int options, const std::string& title, @@ -54,11 +55,11 @@ void ShowMessageBox(int type, if (mate::Converter::FromV8(args->isolate(), peek, &callback)) { - atom::ShowMessageBox(window, (atom::MessageBoxType)type, buttons, cancel_id, - options, title, message, detail, icon, callback); + atom::ShowMessageBox(window, (atom::MessageBoxType)type, buttons, default_button_index, + cancel_id, options, title, message, detail, icon, callback); } else { int chosen = atom::ShowMessageBox(window, (atom::MessageBoxType)type, - buttons, cancel_id, options, title, + buttons, default_button_index, cancel_id, options, title, message, detail, icon); args->Return(chosen); } diff --git a/atom/browser/api/lib/dialog.coffee b/atom/browser/api/lib/dialog.coffee index f10ce58c17f5..03deb548cc76 100644 --- a/atom/browser/api/lib/dialog.coffee +++ b/atom/browser/api/lib/dialog.coffee @@ -91,10 +91,11 @@ module.exports = throw new TypeError('Buttons need to be array') unless Array.isArray options.buttons - options.title ?= '' - options.message ?= '' - options.detail ?= '' - options.icon ?= null + options.title ?= '' + options.message ?= '' + options.detail ?= '' + options.icon ?= null + options.defaultButtonIndex ?= -1 # Choose a default button to get selected when dialog is cancelled. unless options.cancelId? @@ -108,6 +109,7 @@ module.exports = binding.showMessageBox messageBoxType, options.buttons, + options.defaultButtonIndex, options.cancelId, flags, options.title, diff --git a/atom/browser/ui/message_box.h b/atom/browser/ui/message_box.h index 92052d3de4a4..cef3c79dc4aa 100644 --- a/atom/browser/ui/message_box.h +++ b/atom/browser/ui/message_box.h @@ -38,6 +38,7 @@ int ShowMessageBox(NativeWindow* parent_window, MessageBoxType type, const std::vector& buttons, int cancel_id, + int default_button_index, int options, const std::string& title, const std::string& message, @@ -47,6 +48,7 @@ int ShowMessageBox(NativeWindow* parent_window, void ShowMessageBox(NativeWindow* parent_window, MessageBoxType type, const std::vector& buttons, + int default_button_index, int cancel_id, int options, const std::string& title, diff --git a/atom/browser/ui/message_box_mac.mm b/atom/browser/ui/message_box_mac.mm index e518af653da4..f9a4f9aff0b7 100644 --- a/atom/browser/ui/message_box_mac.mm +++ b/atom/browser/ui/message_box_mac.mm @@ -54,6 +54,7 @@ namespace { NSAlert* CreateNSAlert(NativeWindow* parent_window, MessageBoxType type, const std::vector& buttons, + int default_button_index, const std::string& title, const std::string& message, const std::string& detail) { @@ -78,8 +79,17 @@ NSAlert* CreateNSAlert(NativeWindow* parent_window, // An empty title causes crash on OS X. if (buttons[i].empty()) title = @"(empty)"; + NSButton* button = [alert addButtonWithTitle:title]; [button setTag:i]; + + if (i == (size_t)default_button_index) { + // focus the button at default_button_index if the user opted to do so. + // The first button added gets set as the default selected. + // So remove that default, and make the requested button the default + [[[alert buttons] objectAtIndex:0] setKeyEquivalent:@""]; + [button setKeyEquivalent:@"\r"]; + } } return alert; @@ -94,6 +104,7 @@ void SetReturnCode(int* ret_code, int result) { int ShowMessageBox(NativeWindow* parent_window, MessageBoxType type, const std::vector& buttons, + int default_button_index, int cancel_id, int options, const std::string& title, @@ -101,7 +112,8 @@ int ShowMessageBox(NativeWindow* parent_window, const std::string& detail, const gfx::ImageSkia& icon) { NSAlert* alert = CreateNSAlert( - parent_window, type, buttons, title, message, detail); + parent_window, type, buttons, default_button_index, title, message, + detail); // Use runModal for synchronous alert without parent, since we don't have a // window to wait for. @@ -127,6 +139,7 @@ int ShowMessageBox(NativeWindow* parent_window, void ShowMessageBox(NativeWindow* parent_window, MessageBoxType type, const std::vector& buttons, + int default_button_index, int cancel_id, int options, const std::string& title, @@ -135,7 +148,8 @@ void ShowMessageBox(NativeWindow* parent_window, const gfx::ImageSkia& icon, const MessageBoxCallback& callback) { NSAlert* alert = CreateNSAlert( - parent_window, type, buttons, title, message, detail); + parent_window, type, buttons, default_button_index, title, message, + detail); ModalDelegate* delegate = [[ModalDelegate alloc] initWithCallback:callback andAlert:alert callEndModal:false]; From 22c455175aac98e8027ba4f2965c3e526ac84fe9 Mon Sep 17 00:00:00 2001 From: leethomas Date: Thu, 7 Jan 2016 21:23:15 -0800 Subject: [PATCH 07/95] :penguin: add default button index for linux/gtk --- atom/browser/ui/message_box_gtk.cc | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/atom/browser/ui/message_box_gtk.cc b/atom/browser/ui/message_box_gtk.cc index de8d994e5bca..65f557901fd0 100644 --- a/atom/browser/ui/message_box_gtk.cc +++ b/atom/browser/ui/message_box_gtk.cc @@ -29,6 +29,7 @@ class GtkMessageBox { GtkMessageBox(NativeWindow* parent_window, MessageBoxType type, const std::vector& buttons, + int default_button_index, int cancel_id, const std::string& title, const std::string& message, @@ -60,9 +61,16 @@ class GtkMessageBox { // Add buttons. for (size_t i = 0; i < buttons.size(); ++i) { - gtk_dialog_add_button(GTK_DIALOG(dialog_), + if (i == (size_t)default_button_index) { + GtkWidget* button = gtk_dialog_add_button(GTK_DIALOG(dialog_), + TranslateToStock(i, buttons[i]), + i); + gtk_widget_grab_focus(button); + } else { + gtk_dialog_add_button(GTK_DIALOG(dialog_), TranslateToStock(i, buttons[i]), i); + } } // Parent window. @@ -161,19 +169,21 @@ void GtkMessageBox::OnResponseDialog(GtkWidget* widget, int response) { int ShowMessageBox(NativeWindow* parent, MessageBoxType type, const std::vector& buttons, + int default_button_index, int cancel_id, int options, const std::string& title, const std::string& message, const std::string& detail, const gfx::ImageSkia& icon) { - return GtkMessageBox(parent, type, buttons, cancel_id, title, message, detail, + return GtkMessageBox(parent, type, buttons, default_button_index, cancel_id, title, message, detail, icon).RunSynchronous(); } void ShowMessageBox(NativeWindow* parent, MessageBoxType type, const std::vector& buttons, + int default_button_index, int cancel_id, int options, const std::string& title, @@ -181,13 +191,13 @@ void ShowMessageBox(NativeWindow* parent, const std::string& detail, const gfx::ImageSkia& icon, const MessageBoxCallback& callback) { - (new GtkMessageBox(parent, type, buttons, cancel_id, title, message, detail, + (new GtkMessageBox(parent, type, buttons, default_button_index, cancel_id, title, message, detail, icon))->RunAsynchronous(callback); } void ShowErrorBox(const base::string16& title, const base::string16& content) { if (Browser::Get()->is_ready()) { - GtkMessageBox(nullptr, MESSAGE_BOX_TYPE_ERROR, { "OK" }, 0, "Error", + GtkMessageBox(nullptr, MESSAGE_BOX_TYPE_ERROR, { "OK" }, -1, 0, "Error", base::UTF16ToUTF8(title).c_str(), base::UTF16ToUTF8(content).c_str(), gfx::ImageSkia()).RunSynchronous(); From c4c145ef6a8c340510f349ce4bc8cec335effc0b Mon Sep 17 00:00:00 2001 From: leethomas Date: Thu, 7 Jan 2016 22:10:34 -0800 Subject: [PATCH 08/95] :memo: add defaultButtonIndex to dialog docs --- docs/api/dialog.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/api/dialog.md b/docs/api/dialog.md index 80a5289e93f5..ecab70a59153 100644 --- a/docs/api/dialog.md +++ b/docs/api/dialog.md @@ -87,6 +87,7 @@ will be passed via `callback(filename)` `"warning"`. On Windows, "question" displays the same icon as "info", unless you set an icon using the "icon" option. * `buttons` Array - Array of texts for buttons. + * `defaultButtonIndex` Integer - Index of the button in the buttons array which will be selected by default when the message box opens. * `title` String - Title of the message box, some platforms will not show it. * `message` String - Content of the message box. * `detail` String - Extra information of the message. From dfce803045ebca20bf55c207bc9396d3430ad050 Mon Sep 17 00:00:00 2001 From: leethomas Date: Thu, 7 Jan 2016 22:34:16 -0800 Subject: [PATCH 09/95] :checkered_flag: update windows message_box function signatures to accept default_button_index....and do nothing with it --- atom/browser/api/atom_api_dialog.cc | 9 +++++---- atom/browser/ui/message_box_gtk.cc | 8 ++++---- atom/browser/ui/message_box_win.cc | 17 +++++++++++------ 3 files changed, 20 insertions(+), 14 deletions(-) diff --git a/atom/browser/api/atom_api_dialog.cc b/atom/browser/api/atom_api_dialog.cc index e8c1ae3ba99f..0ec9f1905806 100644 --- a/atom/browser/api/atom_api_dialog.cc +++ b/atom/browser/api/atom_api_dialog.cc @@ -55,12 +55,13 @@ void ShowMessageBox(int type, if (mate::Converter::FromV8(args->isolate(), peek, &callback)) { - atom::ShowMessageBox(window, (atom::MessageBoxType)type, buttons, default_button_index, - cancel_id, options, title, message, detail, icon, callback); + atom::ShowMessageBox(window, (atom::MessageBoxType)type, buttons, + default_button_index, cancel_id, options, title, + message, detail, icon, callback); } else { int chosen = atom::ShowMessageBox(window, (atom::MessageBoxType)type, - buttons, default_button_index, cancel_id, options, title, - message, detail, icon); + buttons, default_button_index, cancel_id, + options, title, message, detail, icon); args->Return(chosen); } } diff --git a/atom/browser/ui/message_box_gtk.cc b/atom/browser/ui/message_box_gtk.cc index 65f557901fd0..cf227d4e672f 100644 --- a/atom/browser/ui/message_box_gtk.cc +++ b/atom/browser/ui/message_box_gtk.cc @@ -176,8 +176,8 @@ int ShowMessageBox(NativeWindow* parent, const std::string& message, const std::string& detail, const gfx::ImageSkia& icon) { - return GtkMessageBox(parent, type, buttons, default_button_index, cancel_id, title, message, detail, - icon).RunSynchronous(); + return GtkMessageBox(parent, type, buttons, default_button_index, cancel_id, + title, message, detail, icon).RunSynchronous(); } void ShowMessageBox(NativeWindow* parent, @@ -191,8 +191,8 @@ void ShowMessageBox(NativeWindow* parent, const std::string& detail, const gfx::ImageSkia& icon, const MessageBoxCallback& callback) { - (new GtkMessageBox(parent, type, buttons, default_button_index, cancel_id, title, message, detail, - icon))->RunAsynchronous(callback); + (new GtkMessageBox(parent, type, buttons, default_button_index, cancel_id, + title, message, detail, icon))->RunAsynchronous(callback); } void ShowErrorBox(const base::string16& title, const base::string16& content) { diff --git a/atom/browser/ui/message_box_win.cc b/atom/browser/ui/message_box_win.cc index 656be9f10bb2..7ee72e64d2f2 100644 --- a/atom/browser/ui/message_box_win.cc +++ b/atom/browser/ui/message_box_win.cc @@ -72,6 +72,7 @@ void MapToCommonID(const std::vector& buttons, int ShowMessageBoxUTF16(HWND parent, MessageBoxType type, const std::vector& buttons, + int default_button_index, int cancel_id, int options, const base::string16& title, @@ -156,6 +157,7 @@ void RunMessageBoxInNewThread(base::Thread* thread, NativeWindow* parent, MessageBoxType type, const std::vector& buttons, + int default_button_index, int cancel_id, int options, const std::string& title, @@ -163,8 +165,8 @@ void RunMessageBoxInNewThread(base::Thread* thread, const std::string& detail, const gfx::ImageSkia& icon, const MessageBoxCallback& callback) { - int result = ShowMessageBox(parent, type, buttons, cancel_id, options, title, - message, detail, icon); + int result = ShowMessageBox(parent, type, buttons, default_button_index, + cancel_id, options, title, message, detail, icon); content::BrowserThread::PostTask( content::BrowserThread::UI, FROM_HERE, base::Bind(callback, result)); content::BrowserThread::DeleteSoon( @@ -176,6 +178,7 @@ void RunMessageBoxInNewThread(base::Thread* thread, int ShowMessageBox(NativeWindow* parent, MessageBoxType type, const std::vector& buttons, + int default_button_index, int cancel_id, int options, const std::string& title, @@ -194,6 +197,7 @@ int ShowMessageBox(NativeWindow* parent, return ShowMessageBoxUTF16(hwnd_parent, type, utf16_buttons, + default_button_index, cancel_id, options, base::UTF8ToUTF16(title), @@ -205,6 +209,7 @@ int ShowMessageBox(NativeWindow* parent, void ShowMessageBox(NativeWindow* parent, MessageBoxType type, const std::vector& buttons, + int default_button_index, int cancel_id, int options, const std::string& title, @@ -224,13 +229,13 @@ void ShowMessageBox(NativeWindow* parent, unretained->message_loop()->PostTask( FROM_HERE, base::Bind(&RunMessageBoxInNewThread, base::Unretained(unretained), - parent, type, buttons, cancel_id, options, title, message, - detail, icon, callback)); + parent, type, buttons, default_button_index, + cancel_id, options, title, message, detail, icon, callback)); } void ShowErrorBox(const base::string16& title, const base::string16& content) { - ShowMessageBoxUTF16(NULL, MESSAGE_BOX_TYPE_ERROR, {}, 0, 0, L"Error", title, - content, gfx::ImageSkia()); + ShowMessageBoxUTF16(NULL, MESSAGE_BOX_TYPE_ERROR, {}, -1, 0, 0, L"Error", + title, content, gfx::ImageSkia()); } } // namespace atom From a4636ba18c3d2bf0e63ce10419986d0f827c3e36 Mon Sep 17 00:00:00 2001 From: Omri Litov Date: Fri, 8 Jan 2016 20:53:59 +0200 Subject: [PATCH 10/95] Update browser-window.md --- docs/api/browser-window.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/api/browser-window.md b/docs/api/browser-window.md index 12c528a897d7..bb86e8ef6773 100644 --- a/docs/api/browser-window.md +++ b/docs/api/browser-window.md @@ -573,7 +573,9 @@ Returns whether the window is in kiosk mode. ### `win.getNativeWindowHandle()` -Returns the OS window handle in a buffer. +Returns the platform-specific handle of the window in a buffer. +Cast it to the appropriate type, such as HWND for Windows, NSView* for OS X or unsigned long for Linux. +Used for OS's Native API's for windows. ### `win.hookWindowMessage(message, callback)` _Windows_ From 56d1235bbdb95b87df8a39f9b1d7af47051196c8 Mon Sep 17 00:00:00 2001 From: ZhangYueqiu Date: Sun, 10 Jan 2016 15:43:25 +0800 Subject: [PATCH 11/95] Update supported-platforms.md Change a wrong word --- docs-translations/zh-CN/tutorial/supported-platforms.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs-translations/zh-CN/tutorial/supported-platforms.md b/docs-translations/zh-CN/tutorial/supported-platforms.md index a819e3a0817c..d4d42ec03ff3 100644 --- a/docs-translations/zh-CN/tutorial/supported-platforms.md +++ b/docs-translations/zh-CN/tutorial/supported-platforms.md @@ -20,7 +20,7 @@ Ubuntu 12.04 下编译的,`arm` 版的二进制文件是在 ARM v7(硬浮点 Debian Wheezy 版本的 NEON)下完成的。 预编译二进制文件是否能够运行,取决于其中是否包括了编译平台链接的库,所以只有 Ubuntu 12.04 -可以保证正常工作,但是以下的平台也被正事可以运行 Electron的预编译版本: +可以保证正常工作,但是以下的平台也被证实可以运行 Electron的预编译版本: * Ubuntu 12.04 及更新 * Fedora 21 From 8b07918650064485d45b44bddf6eb1def679e071 Mon Sep 17 00:00:00 2001 From: Joe Naha Date: Mon, 11 Jan 2016 03:59:05 +0900 Subject: [PATCH 12/95] :memo: Update to follow the latest version. [ci skip] --- docs-translations/jp/tutorial/quick-start.md | 101 +++++++++++++------ 1 file changed, 72 insertions(+), 29 deletions(-) diff --git a/docs-translations/jp/tutorial/quick-start.md b/docs-translations/jp/tutorial/quick-start.md index 4bd816cb6a46..bfb6e2a51f76 100644 --- a/docs-translations/jp/tutorial/quick-start.md +++ b/docs-translations/jp/tutorial/quick-start.md @@ -1,34 +1,32 @@ # クイックスタート -## 導入 +Electron ではリッチなネイティブ API を持ったランタイムを提供することによってピュアな JavaScript でデスクトップアプリケーションをつくることができます。ウェブサーバーの代わりにデスクトップアプリケーションに焦点をあてた Node.js ランタイムであるといえばわかりやすいかもしれません。 -ElectronではリッチなネイティブAPIを持ったランタイムを提供することによってピュアなJavaScriptでデスクトップアプリケーションをつくることができます。ウェブサーバーの代わりにデスクトップアプリケーションに焦点をあてたio.jsランタイムであるといえばわかりやすいかもしれません。 - -ElectronはJavaScriptをGUIライブラリにバインディングしません。その代わりに、ElectronはウェブページをGUIとして使用します。なのでElectronはJavaScriptによってコントロールされる最小のChromiumブラウザでもあるともいえます。 +Electron は JavaScript を GUI ライブラリにバインディングしません。その代わりに、Electron はウェブページを GUI として使用します。なので Electron は JavaScript によってコントロールされる最小のChromium ブラウザでもあるともいえます。 ### メインプロセス -Electronでは、`package.json` の `main`で実行されるプロセスを __メインプロセス__ と呼びます。メインスクリプトではGUIにウェブページを表示することができるプロセスを実行します。 +Electron では、`package.json` の `main` スクリプトで実行されるプロセスを __メインプロセス__ と呼びます。メインプロセスで実行されるスクリプトがウェブページを作ることによって GUI を表示することができます。 ### レンダラープロセス -Electronはウェブページを表示させるためにChromiumを使用しているので、Chromiumのマルチプロセスアーキテクチャが使用されることになります。Electronで実行されるウェブページはそれぞれ自身のプロセスで実行されます。それを __レンダラープロセス__ と呼びます。 +Electron はウェブページを表示させるために Chromium を使用しているので、Chromium のマルチプロセスアーキテクチャも使用されることになります。Electron で実行されるウェブページはそれぞれ自身のプロセスで実行されます。それを __レンダラープロセス__ と呼びます。 -通常、ブラウザのウェブページはサンドボックス環境で実行されネイティブなリソースへのアクセスができません。Electronではウェブページからio.jsのAPIを使って、ネイティブリソースへの権限が与えられます。そのおかげでウェブページの中からJavaScriptを使って低レベルなオペレーティングシステムとのインタラクションが可能になります。 +通常のブラウザでは、ウェブページはサンドボックス環境で実行されネイティブなリソースへのアクセスができません。Electron ではウェブページから Node.js の API を使えるためオペレーティングシステムと低レベルなやりとりが可能です。 ### メインプロセスとレンダラープロセスの違い -メインプロセスは `BrowserWindow` インスタンスを作ることによってウェブページをつくります。それぞれの `BrowserWindow` インスタンスはそれ自身の レンダラープロセス上でウェブページを実行します。`BrowserWindow` インスタンスが破棄されると、対応するレンダラープロセスも終了されます。 +メインプロセスは `BrowserWindow` インスタンスを作ることによってウェブページをつくります。それぞれの `BrowserWindow` インスタンスはそれ自身のレンダラープロセス上でウェブページを実行します。`BrowserWindow` インスタンスが破棄されると、対応するレンダラープロセスも終了されます。 -メインプロセスはすべてのウェブページとそれに対応するレンダラープロセスを管理しています。それぞれのレンダラープロセスは分離しているのでウェブページで実行されていることだけを気に留めておいてください。 +メインプロセスはすべてのウェブページとそれに対応するレンダラープロセスを管理しています。それぞれのレンダラープロセスは隔離されているので、自身の中で実行されているウェブページの面倒だけをみます。 -ウェブページでは、GUI関連のAPIを呼ぶことはできません。なぜならば、ウェブページで管理しているネイティブのGUIリソースは非常に危険で簡単にリークしてしまうからです。もしウェブページ内でGUIを操作したい場合には、メインプロセスと通信をする必要があります。 +ウェブページでは、GUI 関連の API を呼ぶことはできません。なぜならば、ウェブページからネイティブ GUI リソースを扱うことは非常に危険であり、簡単にリソースをリークしてしまうからです。もしウェブページ内でGUI を操作したい場合には、ウェブページのレンダラープロセスはメインプロセスにそれらの操作をするように伝える必要があります。 -Electronでは、メインプロセスとレンダラープロセスとのコミュニケーションをするために[ipc](../api/ipc-renderer.md)モジュールを提供しています。またそれと、RPC形式の通信を行う[remote](../api/remote.md)モジュールもあります。 +Electron では、メインプロセスとレンダラープロセスとのコミュニケーションをするために [ipc](../api/ipc-renderer.md) モジュールを提供しています。またそれと、RPC 形式の通信を行う [remote](../api/remote.md) モジュールもあります。 ## Electronアプリを作成する -一般的に Electronアプリの構成は次のようになります: +一般的に Electron アプリの構成は次のようになります: ```text your-app/ @@ -37,7 +35,7 @@ your-app/ └── index.html ``` -`package.json`の形式はNodeモジュールとまったく同じです。 `main` フィールドでアプリを起動するためのスクリプトを特定し、メインプロセスで実行します。 `package.json`の例は次のようになります: +`package.json` の形式は Node モジュールとまったく同じです。 `main` フィールドで指定するスクリプトはアプリの起動スクリプトであり、メインプロセスを実行します。 `package.json` の例は次のようになります: ```json { @@ -47,25 +45,32 @@ your-app/ } ``` +__注記__: `package.json` に `main` が存在しない場合、Electron は `index.js` のロードを試みます。 + `main.js` ではウィンドウを作成してシステムイベントを管理します。典型的な例は次のようになります: ```javascript -var app = require('app'); // Module to control application life. -var BrowserWindow = require('browser-window'); // Module to create native browser window. +'use strict'; + +const electron = require('electron'); +const app = electron.app; // Module to control application life. +const BrowserWindow = electron.BrowserWindow; // Module to create native browser window. // Keep a global reference of the window object, if you don't, the window will -// be closed automatically when the javascript object is GCed. +// be closed automatically when the JavaScript object is garbage collected. var mainWindow = null; // Quit when all windows are closed. app.on('window-all-closed', function() { + // On OS X it is common for applications and their menu bar + // to stay active until the user quits explicitly with Cmd + Q if (process.platform != 'darwin') { app.quit(); } }); -// This method will be called when Electron has done everything -// initialization and ready for creating browser windows. +// This method will be called when Electron has finished +// initialization and is ready to create browser windows. app.on('ready', function() { // Create the browser window. mainWindow = new BrowserWindow({width: 800, height: 600}); @@ -73,8 +78,8 @@ app.on('ready', function() { // and load the index.html of the app. mainWindow.loadURL('file://' + __dirname + '/index.html'); - // Open the devtools. - mainWindow.openDevTools(); + // Open the DevTools. + mainWindow.webContents.openDevTools(); // Emitted when the window is closed. mainWindow.on('closed', function() { @@ -86,43 +91,81 @@ app.on('ready', function() { }); ``` -最後に表示するウェブページ`index.html`は次のようになります: - +最後に表示するウェブページ `index.html` は次のようになります: ```html + Hello World!

Hello World!

- We are using io.js - and Electron . + We are using node , + Chrome , + and Electron . ``` ## アプリを実行する -アプリケーションを作り終えたら、[Application distribution](./application-distribution.md)ガイドにしたがってディストリビューションを作成します、そしてパッケージされたアプリケーションとして配布することが可能です。またダウンロードしたElectronのバイナリをアプリケーション・ディレクトリを実行するために利用することもできます。 +最初の `main.js`、`index.html`、`package.json` を作ったら、手元でアプリを実行し、思った通りに動くのを確認したいでしょう。 -Windowsの場合: +### electron-prebuilt + +`electron-prebuilt` を `npm` でグローバルインストールしているなら、アプリのソースディレクトリ内で以下を実行するだけで済みます: + +```bash +electron . +``` + +ローカルにインストールしているなら以下を実行してください: + +```bash +./node_modules/.bin/electron . +``` + +### 手動ダウンロードした Electron バイナリを使う場合 + +もしも Electron を手動ダウンロードしているなら、同梱されているバイナリであなたのアプリを直接実行できます。 + +#### Windows ```bash $ .\electron\electron.exe your-app\ ``` -Linuxの場合: +#### Linux ```bash $ ./electron/electron your-app/ ``` -OS Xの場合: +#### OS X ```bash $ ./Electron.app/Contents/MacOS/Electron your-app/ ``` -`Electron.app` はElectronのリリースパッケージに含まれており、[ここ](https://github.com/atom/electron/releases) からダウンロードできます。 +`Electron.app` は Electron のリリースパッケージの一部で、[ここ](https://github.com/atom/electron/releases) からダウンロードできます。 + +### Run as a distribution + +アプリケーションを作り終えたら、[Application distribution](./application-distribution.md) ガイドにしたがってディストリビューションを作成し、そしてパッケージされたアプリケーションとして実行することが可能です。 + +### 試してみよう + +このチュートリアルのコードは [`atom/electron-quick-start`](https://github.com/atom/electron-quick-start) リポジトリから clone して実行できます。 + +**注記**:例を試すには、[Git](https://git-scm.com) と [Node.js](https://nodejs.org/en/download/) ([npm](https://npmjs.org) もこれに含まれています) が必要です。 + +```bash +# Clone the repository +$ git clone https://github.com/atom/electron-quick-start +# Go into the repository +$ cd electron-quick-start +# Install dependencies and run the app +$ npm install && npm start +``` From be50ca26539e0cbcc58671aa8f229616d4125282 Mon Sep 17 00:00:00 2001 From: Robo Date: Mon, 11 Jan 2016 03:55:56 +0530 Subject: [PATCH 13/95] session: allow user to isolate pac script and proxy bypass rules --- atom/browser/api/atom_api_session.cc | 14 +++++++------- docs/api/session.md | 10 ++++------ 2 files changed, 11 insertions(+), 13 deletions(-) diff --git a/atom/browser/api/atom_api_session.cc b/atom/browser/api/atom_api_session.cc index 8b73d61622ec..0b2f4f9be979 100644 --- a/atom/browser/api/atom_api_session.cc +++ b/atom/browser/api/atom_api_session.cc @@ -114,15 +114,15 @@ struct Converter { static bool FromV8(v8::Isolate* isolate, v8::Local val, net::ProxyConfig* out) { - std::string proxy; - if (!ConvertFromV8(isolate, val, &proxy)) + mate::Dictionary options; + if (!ConvertFromV8(isolate, val, &options)) return false; - auto pac_url = GURL(proxy); - if (pac_url.is_valid()) { + GURL pac_url; + std::string rules; + if (options.Get("pacScript", &pac_url)) out->set_pac_url(pac_url); - } else { - out->proxy_rules().ParseFromString(proxy); - } + else if (options.Get("proxyRules", &rules)) + out->proxy_rules().ParseFromString(rules); return true; } }; diff --git a/docs/api/session.md b/docs/api/session.md index 09fa61e2112e..67dd537d44ee 100644 --- a/docs/api/session.md +++ b/docs/api/session.md @@ -181,15 +181,13 @@ Clears the data of web storages. #### `ses.setProxy(config, callback)` -* `config` String +* `config` Object + * `pacScript` String - The URL associated with the PAC file. + * `proxyRules` String - Rules indicating which proxies to use. * `callback` Function - Called when operation is done. -If `config` is a PAC url, it is used directly otherwise -`config` is parsed based on the following rules indicating which -proxies to use for the session. - ``` -config = scheme-proxies[";"] +proxyRules = scheme-proxies[";"] scheme-proxies = ["="] url-scheme = "http" | "https" | "ftp" | "socks" proxy-uri-list = [","] From f1d388fb36a3198763827f95f244930edbc011cd Mon Sep 17 00:00:00 2001 From: Eran Tiktin Date: Mon, 11 Jan 2016 01:33:22 +0200 Subject: [PATCH 14/95] Fix failing test on Windows The exit code tests include an assert on the output we get from a spawned electron process. This doesn't currently work on Windows, so we skip it for now --- spec/api-app-spec.coffee | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/spec/api-app-spec.coffee b/spec/api-app-spec.coffee index adb64d363eb1..5e6bca82091f 100644 --- a/spec/api-app-spec.coffee +++ b/spec/api-app-spec.coffee @@ -44,7 +44,10 @@ describe 'app module', -> output = '' appProcess.stdout.on 'data', (data) -> output += data appProcess.on 'close', (code) -> - assert.notEqual output.indexOf('Exit event with code: 123'), -1 + # We skip the following assert on Windows, since we can't currently get + # stdout from a spawned electron process on Windows + if process.platform isnt 'win32' + assert.notEqual output.indexOf('Exit event with code: 123'), -1 assert.equal code, 123 done() From ae5c6add11b8b4b5c1e5e8ade63d2e3d25b04977 Mon Sep 17 00:00:00 2001 From: leethomas Date: Sun, 10 Jan 2016 15:33:27 -0800 Subject: [PATCH 15/95] rename all references to default_button_index -> default_id to keep consistent with cancel_id --- atom/browser/api/atom_api_dialog.cc | 6 +++--- atom/browser/api/lib/dialog.coffee | 4 ++-- atom/browser/ui/message_box.h | 4 ++-- atom/browser/ui/message_box_gtk.cc | 12 ++++++------ atom/browser/ui/message_box_mac.mm | 14 +++++++------- atom/browser/ui/message_box_win.cc | 14 +++++++------- docs/api/dialog.md | 2 +- 7 files changed, 28 insertions(+), 28 deletions(-) diff --git a/atom/browser/api/atom_api_dialog.cc b/atom/browser/api/atom_api_dialog.cc index 0ec9f1905806..3ff53352cba1 100644 --- a/atom/browser/api/atom_api_dialog.cc +++ b/atom/browser/api/atom_api_dialog.cc @@ -41,7 +41,7 @@ namespace { void ShowMessageBox(int type, const std::vector& buttons, - int default_button_index, + int default_id, int cancel_id, int options, const std::string& title, @@ -56,11 +56,11 @@ void ShowMessageBox(int type, peek, &callback)) { atom::ShowMessageBox(window, (atom::MessageBoxType)type, buttons, - default_button_index, cancel_id, options, title, + default_id, cancel_id, options, title, message, detail, icon, callback); } else { int chosen = atom::ShowMessageBox(window, (atom::MessageBoxType)type, - buttons, default_button_index, cancel_id, + buttons, default_id, cancel_id, options, title, message, detail, icon); args->Return(chosen); } diff --git a/atom/browser/api/lib/dialog.coffee b/atom/browser/api/lib/dialog.coffee index 03deb548cc76..2768fe096a05 100644 --- a/atom/browser/api/lib/dialog.coffee +++ b/atom/browser/api/lib/dialog.coffee @@ -95,7 +95,7 @@ module.exports = options.message ?= '' options.detail ?= '' options.icon ?= null - options.defaultButtonIndex ?= -1 + options.defaultId ?= -1 # Choose a default button to get selected when dialog is cancelled. unless options.cancelId? @@ -109,7 +109,7 @@ module.exports = binding.showMessageBox messageBoxType, options.buttons, - options.defaultButtonIndex, + options.defaultId, options.cancelId, flags, options.title, diff --git a/atom/browser/ui/message_box.h b/atom/browser/ui/message_box.h index cef3c79dc4aa..d2eb70bcd938 100644 --- a/atom/browser/ui/message_box.h +++ b/atom/browser/ui/message_box.h @@ -38,7 +38,7 @@ int ShowMessageBox(NativeWindow* parent_window, MessageBoxType type, const std::vector& buttons, int cancel_id, - int default_button_index, + int default_id, int options, const std::string& title, const std::string& message, @@ -48,7 +48,7 @@ int ShowMessageBox(NativeWindow* parent_window, void ShowMessageBox(NativeWindow* parent_window, MessageBoxType type, const std::vector& buttons, - int default_button_index, + int default_id, int cancel_id, int options, const std::string& title, diff --git a/atom/browser/ui/message_box_gtk.cc b/atom/browser/ui/message_box_gtk.cc index cf227d4e672f..fe1068effd7c 100644 --- a/atom/browser/ui/message_box_gtk.cc +++ b/atom/browser/ui/message_box_gtk.cc @@ -29,7 +29,7 @@ class GtkMessageBox { GtkMessageBox(NativeWindow* parent_window, MessageBoxType type, const std::vector& buttons, - int default_button_index, + int default_id, int cancel_id, const std::string& title, const std::string& message, @@ -61,7 +61,7 @@ class GtkMessageBox { // Add buttons. for (size_t i = 0; i < buttons.size(); ++i) { - if (i == (size_t)default_button_index) { + if (i == (size_t)default_id) { GtkWidget* button = gtk_dialog_add_button(GTK_DIALOG(dialog_), TranslateToStock(i, buttons[i]), i); @@ -169,21 +169,21 @@ void GtkMessageBox::OnResponseDialog(GtkWidget* widget, int response) { int ShowMessageBox(NativeWindow* parent, MessageBoxType type, const std::vector& buttons, - int default_button_index, + int default_id, int cancel_id, int options, const std::string& title, const std::string& message, const std::string& detail, const gfx::ImageSkia& icon) { - return GtkMessageBox(parent, type, buttons, default_button_index, cancel_id, + return GtkMessageBox(parent, type, buttons, default_id, cancel_id, title, message, detail, icon).RunSynchronous(); } void ShowMessageBox(NativeWindow* parent, MessageBoxType type, const std::vector& buttons, - int default_button_index, + int default_id, int cancel_id, int options, const std::string& title, @@ -191,7 +191,7 @@ void ShowMessageBox(NativeWindow* parent, const std::string& detail, const gfx::ImageSkia& icon, const MessageBoxCallback& callback) { - (new GtkMessageBox(parent, type, buttons, default_button_index, cancel_id, + (new GtkMessageBox(parent, type, buttons, default_id, cancel_id, title, message, detail, icon))->RunAsynchronous(callback); } diff --git a/atom/browser/ui/message_box_mac.mm b/atom/browser/ui/message_box_mac.mm index f9a4f9aff0b7..79c60b5ffe3c 100644 --- a/atom/browser/ui/message_box_mac.mm +++ b/atom/browser/ui/message_box_mac.mm @@ -54,7 +54,7 @@ namespace { NSAlert* CreateNSAlert(NativeWindow* parent_window, MessageBoxType type, const std::vector& buttons, - int default_button_index, + int default_id, const std::string& title, const std::string& message, const std::string& detail) { @@ -83,8 +83,8 @@ NSAlert* CreateNSAlert(NativeWindow* parent_window, NSButton* button = [alert addButtonWithTitle:title]; [button setTag:i]; - if (i == (size_t)default_button_index) { - // focus the button at default_button_index if the user opted to do so. + if (i == (size_t)default_id) { + // focus the button at default_id if the user opted to do so. // The first button added gets set as the default selected. // So remove that default, and make the requested button the default [[[alert buttons] objectAtIndex:0] setKeyEquivalent:@""]; @@ -104,7 +104,7 @@ void SetReturnCode(int* ret_code, int result) { int ShowMessageBox(NativeWindow* parent_window, MessageBoxType type, const std::vector& buttons, - int default_button_index, + int default_id, int cancel_id, int options, const std::string& title, @@ -112,7 +112,7 @@ int ShowMessageBox(NativeWindow* parent_window, const std::string& detail, const gfx::ImageSkia& icon) { NSAlert* alert = CreateNSAlert( - parent_window, type, buttons, default_button_index, title, message, + parent_window, type, buttons, default_id, title, message, detail); // Use runModal for synchronous alert without parent, since we don't have a @@ -139,7 +139,7 @@ int ShowMessageBox(NativeWindow* parent_window, void ShowMessageBox(NativeWindow* parent_window, MessageBoxType type, const std::vector& buttons, - int default_button_index, + int default_id, int cancel_id, int options, const std::string& title, @@ -148,7 +148,7 @@ void ShowMessageBox(NativeWindow* parent_window, const gfx::ImageSkia& icon, const MessageBoxCallback& callback) { NSAlert* alert = CreateNSAlert( - parent_window, type, buttons, default_button_index, title, message, + parent_window, type, buttons, default_id, title, message, detail); ModalDelegate* delegate = [[ModalDelegate alloc] initWithCallback:callback andAlert:alert diff --git a/atom/browser/ui/message_box_win.cc b/atom/browser/ui/message_box_win.cc index 7ee72e64d2f2..58287dd5b7d5 100644 --- a/atom/browser/ui/message_box_win.cc +++ b/atom/browser/ui/message_box_win.cc @@ -72,7 +72,7 @@ void MapToCommonID(const std::vector& buttons, int ShowMessageBoxUTF16(HWND parent, MessageBoxType type, const std::vector& buttons, - int default_button_index, + int default_id, int cancel_id, int options, const base::string16& title, @@ -157,7 +157,7 @@ void RunMessageBoxInNewThread(base::Thread* thread, NativeWindow* parent, MessageBoxType type, const std::vector& buttons, - int default_button_index, + int default_id, int cancel_id, int options, const std::string& title, @@ -165,7 +165,7 @@ void RunMessageBoxInNewThread(base::Thread* thread, const std::string& detail, const gfx::ImageSkia& icon, const MessageBoxCallback& callback) { - int result = ShowMessageBox(parent, type, buttons, default_button_index, + int result = ShowMessageBox(parent, type, buttons, default_id, cancel_id, options, title, message, detail, icon); content::BrowserThread::PostTask( content::BrowserThread::UI, FROM_HERE, base::Bind(callback, result)); @@ -178,7 +178,7 @@ void RunMessageBoxInNewThread(base::Thread* thread, int ShowMessageBox(NativeWindow* parent, MessageBoxType type, const std::vector& buttons, - int default_button_index, + int default_id, int cancel_id, int options, const std::string& title, @@ -197,7 +197,7 @@ int ShowMessageBox(NativeWindow* parent, return ShowMessageBoxUTF16(hwnd_parent, type, utf16_buttons, - default_button_index, + default_id, cancel_id, options, base::UTF8ToUTF16(title), @@ -209,7 +209,7 @@ int ShowMessageBox(NativeWindow* parent, void ShowMessageBox(NativeWindow* parent, MessageBoxType type, const std::vector& buttons, - int default_button_index, + int default_id, int cancel_id, int options, const std::string& title, @@ -229,7 +229,7 @@ void ShowMessageBox(NativeWindow* parent, unretained->message_loop()->PostTask( FROM_HERE, base::Bind(&RunMessageBoxInNewThread, base::Unretained(unretained), - parent, type, buttons, default_button_index, + parent, type, buttons, default_id, cancel_id, options, title, message, detail, icon, callback)); } diff --git a/docs/api/dialog.md b/docs/api/dialog.md index ecab70a59153..519f89b9c5df 100644 --- a/docs/api/dialog.md +++ b/docs/api/dialog.md @@ -87,7 +87,7 @@ will be passed via `callback(filename)` `"warning"`. On Windows, "question" displays the same icon as "info", unless you set an icon using the "icon" option. * `buttons` Array - Array of texts for buttons. - * `defaultButtonIndex` Integer - Index of the button in the buttons array which will be selected by default when the message box opens. + * `defaultId` Integer - Index of the button in the buttons array which will be selected by default when the message box opens. * `title` String - Title of the message box, some platforms will not show it. * `message` String - Content of the message box. * `detail` String - Extra information of the message. From 803b06b7de60261df72233b130bb9ef4cfa875eb Mon Sep 17 00:00:00 2001 From: leethomas Date: Sun, 10 Jan 2016 15:55:26 -0800 Subject: [PATCH 16/95] :checkered_flag: support defaultId for dialog boxes on Windows --- atom/browser/ui/message_box_win.cc | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/atom/browser/ui/message_box_win.cc b/atom/browser/ui/message_box_win.cc index 58287dd5b7d5..253733de59df 100644 --- a/atom/browser/ui/message_box_win.cc +++ b/atom/browser/ui/message_box_win.cc @@ -84,10 +84,11 @@ int ShowMessageBoxUTF16(HWND parent, TDF_ALLOW_DIALOG_CANCELLATION; // Allow canceling the dialog. TASKDIALOGCONFIG config = { 0 }; - config.cbSize = sizeof(config); - config.hwndParent = parent; - config.hInstance = GetModuleHandle(NULL); - config.dwFlags = flags; + config.cbSize = sizeof(config); + config.hwndParent = parent; + config.hInstance = GetModuleHandle(NULL); + config.dwFlags = flags; + config.nDefaultButton = default_id ? (kIDStart + default_id) : 0; // TaskDialogIndirect doesn't allow empty name, if we set empty title it // will show "electron.exe" in title. From 29939dc0b7cd4340ac30fd7747607357f2416609 Mon Sep 17 00:00:00 2001 From: Eran Tiktin Date: Mon, 11 Jan 2016 02:11:40 +0200 Subject: [PATCH 17/95] Remove unneeded extra semicolons (;; -> ;) --- atom/app/uv_task_runner.cc | 2 +- atom/browser/api/atom_api_web_contents.cc | 2 +- atom/renderer/atom_render_view_observer.cc | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/atom/app/uv_task_runner.cc b/atom/app/uv_task_runner.cc index f49ba259bac8..097cc3bcda18 100644 --- a/atom/app/uv_task_runner.cc +++ b/atom/app/uv_task_runner.cc @@ -37,7 +37,7 @@ bool UvTaskRunner::PostNonNestableDelayedTask( const tracked_objects::Location& from_here, const base::Closure& task, base::TimeDelta delay) { - return PostDelayedTask(from_here, task, delay);; + return PostDelayedTask(from_here, task, delay); } // static diff --git a/atom/browser/api/atom_api_web_contents.cc b/atom/browser/api/atom_api_web_contents.cc index 3f39519a3f7b..43ce556264e9 100644 --- a/atom/browser/api/atom_api_web_contents.cc +++ b/atom/browser/api/atom_api_web_contents.cc @@ -992,7 +992,7 @@ void WebContents::SendInputEvent(v8::Isolate* isolate, return; } } else if (blink::WebInputEvent::isKeyboardEventType(type)) { - content::NativeWebKeyboardEvent keyboard_event;; + content::NativeWebKeyboardEvent keyboard_event; if (mate::ConvertFromV8(isolate, input_event, &keyboard_event)) { host->ForwardKeyboardEvent(keyboard_event); return; diff --git a/atom/renderer/atom_render_view_observer.cc b/atom/renderer/atom_render_view_observer.cc index 931913dd75d0..bf2e1a70b788 100644 --- a/atom/renderer/atom_render_view_observer.cc +++ b/atom/renderer/atom_render_view_observer.cc @@ -88,7 +88,7 @@ void AtomRenderViewObserver::DidCreateDocumentElement( // Read --zoom-factor from command line. std::string zoom_factor_str = base::CommandLine::ForCurrentProcess()-> - GetSwitchValueASCII(switches::kZoomFactor);; + GetSwitchValueASCII(switches::kZoomFactor); if (zoom_factor_str.empty()) return; double zoom_factor; From da52017d82c56a44254e78058134ee6cae99f8db Mon Sep 17 00:00:00 2001 From: Cheng Zhao Date: Mon, 11 Jan 2016 10:30:17 +0800 Subject: [PATCH 18/95] Revert "fix chrome app and user path conflicts" This reverts commit 25aaafde45bd3ac7d9a82184f67b79874da73aa8. --- chromium_src/chrome/common/chrome_paths.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chromium_src/chrome/common/chrome_paths.h b/chromium_src/chrome/common/chrome_paths.h index 3a76e3295f46..581fdc06f7c1 100644 --- a/chromium_src/chrome/common/chrome_paths.h +++ b/chromium_src/chrome/common/chrome_paths.h @@ -17,7 +17,7 @@ class FilePath; namespace chrome { enum { - PATH_START = 2000, + PATH_START = 1000, DIR_APP = PATH_START, // Directory where dlls and data reside. DIR_LOGS, // Directory where logs should be written. From adcdf123af0d1923e2336f0ee38c172d1624d025 Mon Sep 17 00:00:00 2001 From: Cheng Zhao Date: Mon, 11 Jan 2016 10:40:45 +0800 Subject: [PATCH 19/95] Change brightray's PATH_START to 11000 --- vendor/brightray | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vendor/brightray b/vendor/brightray index 8550f2a032b3..8b6c24dce25e 160000 --- a/vendor/brightray +++ b/vendor/brightray @@ -1 +1 @@ -Subproject commit 8550f2a032b332d86bd8a7ec235685e22d028906 +Subproject commit 8b6c24dce25e743ceecd06d1c175c1cf8b91627b From fee301e768be445b16698833111b263d8d8cd87b Mon Sep 17 00:00:00 2001 From: leethomas Date: Sun, 10 Jan 2016 19:15:40 -0800 Subject: [PATCH 20/95] follow style guidelines --- atom/browser/api/lib/dialog.coffee | 8 ++++---- atom/browser/ui/message_box_mac.mm | 4 ++-- docs/api/dialog.md | 3 ++- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/atom/browser/api/lib/dialog.coffee b/atom/browser/api/lib/dialog.coffee index 2768fe096a05..2daf346db468 100644 --- a/atom/browser/api/lib/dialog.coffee +++ b/atom/browser/api/lib/dialog.coffee @@ -91,10 +91,10 @@ module.exports = throw new TypeError('Buttons need to be array') unless Array.isArray options.buttons - options.title ?= '' - options.message ?= '' - options.detail ?= '' - options.icon ?= null + options.title ?= '' + options.message ?= '' + options.detail ?= '' + options.icon ?= null options.defaultId ?= -1 # Choose a default button to get selected when dialog is cancelled. diff --git a/atom/browser/ui/message_box_mac.mm b/atom/browser/ui/message_box_mac.mm index 79c60b5ffe3c..3acc46ec82f1 100644 --- a/atom/browser/ui/message_box_mac.mm +++ b/atom/browser/ui/message_box_mac.mm @@ -84,9 +84,9 @@ NSAlert* CreateNSAlert(NativeWindow* parent_window, [button setTag:i]; if (i == (size_t)default_id) { - // focus the button at default_id if the user opted to do so. + // Focus the button at default_id if the user opted to do so. // The first button added gets set as the default selected. - // So remove that default, and make the requested button the default + // So remove that default, and make the requested button the default. [[[alert buttons] objectAtIndex:0] setKeyEquivalent:@""]; [button setKeyEquivalent:@"\r"]; } diff --git a/docs/api/dialog.md b/docs/api/dialog.md index 519f89b9c5df..84a22ef692b3 100644 --- a/docs/api/dialog.md +++ b/docs/api/dialog.md @@ -87,7 +87,8 @@ will be passed via `callback(filename)` `"warning"`. On Windows, "question" displays the same icon as "info", unless you set an icon using the "icon" option. * `buttons` Array - Array of texts for buttons. - * `defaultId` Integer - Index of the button in the buttons array which will be selected by default when the message box opens. + * `defaultId` Integer - Index of the button in the buttons array which will + be selected by default when the message box opens. * `title` String - Title of the message box, some platforms will not show it. * `message` String - Content of the message box. * `detail` String - Extra information of the message. From 595a3469d9c3cc0a9a45e1a02f75028c927ae895 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=A4=A7=E5=92=8C=E5=B1=8B=20=E8=B2=B4=E4=BB=81?= Date: Mon, 11 Jan 2016 13:03:37 +0900 Subject: [PATCH 21/95] Add Japanese translation documentation for faq and tutorial --- docs-translations/jp/faq/electron-faq.md | 73 +++++ .../jp/tutorial/application-distribution.md | 108 ++++++++ .../jp/tutorial/application-packaging.md | 149 +++++++++++ .../jp/tutorial/debugging-main-process.md | 70 +++++ .../desktop-environment-integration.md | 251 ++++++++++++++++++ .../jp/tutorial/devtools-extension.md | 45 ++++ .../mac-app-store-submission-guide.md | 103 +++++++ .../jp/tutorial/online-offline-events.md | 81 ++++++ .../jp/tutorial/supported-platforms.md | 24 ++ .../jp/tutorial/using-native-node-modules.md | 50 ++++ .../jp/tutorial/using-pepper-flash-plugin.md | 46 ++++ .../tutorial/using-selenium-and-webdriver.md | 119 +++++++++ .../jp/tutorial/using-widevine-cdm-plugin.md | 57 ++++ 13 files changed, 1176 insertions(+) create mode 100644 docs-translations/jp/faq/electron-faq.md create mode 100644 docs-translations/jp/tutorial/application-distribution.md create mode 100644 docs-translations/jp/tutorial/application-packaging.md create mode 100644 docs-translations/jp/tutorial/debugging-main-process.md create mode 100644 docs-translations/jp/tutorial/desktop-environment-integration.md create mode 100644 docs-translations/jp/tutorial/devtools-extension.md create mode 100644 docs-translations/jp/tutorial/mac-app-store-submission-guide.md create mode 100644 docs-translations/jp/tutorial/online-offline-events.md create mode 100644 docs-translations/jp/tutorial/supported-platforms.md create mode 100644 docs-translations/jp/tutorial/using-native-node-modules.md create mode 100644 docs-translations/jp/tutorial/using-pepper-flash-plugin.md create mode 100644 docs-translations/jp/tutorial/using-selenium-and-webdriver.md create mode 100644 docs-translations/jp/tutorial/using-widevine-cdm-plugin.md diff --git a/docs-translations/jp/faq/electron-faq.md b/docs-translations/jp/faq/electron-faq.md new file mode 100644 index 000000000000..bfd99989c9b5 --- /dev/null +++ b/docs-translations/jp/faq/electron-faq.md @@ -0,0 +1,73 @@ +# Electron FAQ + +## Electronは、いつ最新のChromeにアップグレードされますか? + +ElectronのChromeバージョンは、通常、新しいChromeのstabeleバージョンがリリースされた後、1~2週間以内に上げられます。 + +また、Chromeのstableチャンネルのみを使用し、もし、重要な修正がbetaまたはdevチャンネルにある場合、それをバックポートします。 + +## Electronは、いつ最新のNode.jsにアップグレードされますか? + +Node.jsの新しいバージョンがリリースされたとき、とても頻繁に発生している新しいNode.jsバージョンで取り込まれたバグによる影響を避けるために、ElectronのNode.jsをアップグレードする前に、通常、約1カ月待ちます。 + +通常、Node.jsの新しい機能はV8のアップグレードによってもたらされ、 ElectronはChromeブラウザーに搭載されているV8を使用しているので、 +新しいNode.jsの重要な新しいJavaScript機能はElectronでは、すでに導入されています。 + +## 数分後、アプリのWindow/trayが表示されなくなります + +これは、Window/trayを格納するのに使用している変数がガベージ コレクションされたときに発生します。 + +この問題に遭遇した時には、次のドキュメントを読むことをお勧めします。 + +* [Memory Management][memory-management] +* [Variable Scope][variable-scope] + +もし簡単に修正したい場合は、グローバル変数を作成し、コードを変更します。 + +変更前: + +```javascript +app.on('ready', function() { + var tray = new Tray('/path/to/icon.png'); +}) +``` + +変更後: + +```javascript +var tray = null; +app.on('ready', function() { + tray = new Tray('/path/to/icon.png'); +}) +``` + +## ElectronでjQuery/RequireJS/Meteor/AngularJSを使用できません + +Electronに組み込まれているNode.jsの影響で, `module`, `exports`, `require`のようなシンボルがDOMに追加されています。いくつかのライブラリで、追加しようとしているシンボルと同じ名前があり、これが原因で問題が発生します。 +これを解決するために、Electronに組み込まれているnodeを無効にすることができます。 + +```javascript +// In the main process. +var mainWindow = new BrowserWindow({ + webPreferences: { + nodeIntegration: false + } +}); +``` + +しかし、Node.jsとElectron APIを使用した機能を維持したい場合は、ほかのライブラリを読み込む前に、ページのシンボルをリネームする必要があります。 + +```html + + + + +``` + +[memory-management]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Memory_Management +[variable-scope]: https://msdn.microsoft.com/library/bzt2dkta(v=vs.94).aspx diff --git a/docs-translations/jp/tutorial/application-distribution.md b/docs-translations/jp/tutorial/application-distribution.md new file mode 100644 index 000000000000..ad6f46a12a1d --- /dev/null +++ b/docs-translations/jp/tutorial/application-distribution.md @@ -0,0 +1,108 @@ +# アプリケーションの配布 + +Electronでアプリケーションを配布するために、アプリケーションを`app` という名前のディレクトリにし、Electronのリソースディレクトリ(OS X では +`Electron.app/Contents/Resources/` 、Linux と Windows では `resources/`)配下に置くべきです, + +OS X: + +```text +electron/Electron.app/Contents/Resources/app/ +├── package.json +├── main.js +└── index.html +``` + +Windows と Linux: + +```text +electron/resources/app +├── package.json +├── main.js +└── index.html +``` + +`Electron.app` (または Linux上では、`electron`、Windows上では、 `electron.exe`)を実行すると、Electronはアプリケーションを開始します。The `electron` ディレクトリを最終的なユーザーに提供するために配布します。 + +## ファイルにアプリケーションをパッケージングする + +すべてのソースコードをコピーすることでアプリケーションを提供する方法とは別に、アプリケーションのソースコードをユーザーに見えるのを避けるために、[asar](https://github.com/atom/asar) にアーカイブしてアプリケーションをパッケージ化することができます。 + +`asar`アーカイブを使用するために、`app`フォルダーと置き換え、アーカイブファイルを`app.asar`という名前に変更する必要があり、Electronのリソースディレクトリの下に置くと、Electronはアーカイブを読み込もうとし、それを開始します。 + +OS X: + +```text +electron/Electron.app/Contents/Resources/ +└── app.asar +``` + +Windows と Linux: + +```text +electron/resources/ +└── app.asar +``` + +[Application packaging](application-packaging.md)で、詳細を確認できます。 + +## ダウンローするバイナリのブランド名の変更 + +Electronにバンドルした後、ユーザーに配布する前に、 Electron名を変更したいでしょう。 + +### Windows + +`electron.exe`を任意の名前に変更でき、[rcedit](https://github.com/atom/rcedit) または +[ResEdit](http://www.resedit.net)のようなツールでアイコンやその他の情報を編集できます。 + +### OS X + + `Electron.app` を任意の名前に変更でき、次のファイルの `CFBundleDisplayName`と `CFBundleIdentifier`、 `CFBundleName`のフィールドの名前を変更する必要があります。 + +* `Electron.app/Contents/Info.plist` +* `Electron.app/Contents/Frameworks/Electron Helper.app/Contents/Info.plist` + +Activity Monitorで、`Electron Helper`と表示されるのを避けるために、helper appの名前を変更でき、 helper appの実行ファイルの名前を確認します。 + +次のようなappの変更する名前の構造 + +``` +MyApp.app/Contents +├── Info.plist +├── MacOS/ +│   └── MyApp +└── Frameworks/ + ├── MyApp Helper EH.app + | ├── Info.plist + | └── MacOS/ + |    └── MyApp Helper EH + ├── MyApp Helper NP.app + | ├── Info.plist + | └── MacOS/ + |    └── MyApp Helper NP + └── MyApp Helper.app + ├── Info.plist + └── MacOS/ +    └── MyApp Helper +``` + +### Linux + +`electron` を任意の名前に変更できます。 + +## ソースからElectronをリビルドしてブランド名を変更する + +プロダクト名を変更し、ソースからビルドすることで、Electronのブランド名を変更できます。これをするために、`atom.gyp` ファイルを変更し、クリーンリビルドする必要があります。 + +### grunt-build-atom-shell + +マニュアルでは、Electronのコードをダウンロードし、リビルドさせます。一方で、面倒なタスクはこれで自動化できます: +[grunt-build-atom-shell](https://github.com/paulcbetts/grunt-build-atom-shell). + +This task will automatically handle editing the 自動処理を管理するのに、`.gyp`ファイルを編集し、ソースからビルドし、新しい実行名に一致したときにはNativeのNodeモジュールをリビルドするようにできます。 + +## パッケージングツール + +マニュアルでパッケージ化するのとは別に、サードパーティのパッケジングツールを選ぶこともできます。 + +* [electron-packager](https://github.com/maxogden/electron-packager) +* [electron-builder](https://github.com/loopline-systems/electron-builder) diff --git a/docs-translations/jp/tutorial/application-packaging.md b/docs-translations/jp/tutorial/application-packaging.md new file mode 100644 index 000000000000..7b6a5b30c2b2 --- /dev/null +++ b/docs-translations/jp/tutorial/application-packaging.md @@ -0,0 +1,149 @@ +# アプリケーションのパッケージ化 + +Windows上の長いパス名周りの[issues](https://github.com/joyent/node/issues/6960) を軽減させるたり、`require`を若干スピードアップさせたり、 簡単な調査からソースコードを隠したりするために、ソースコードの少しの変更で、[asar][asar]にアーカイブし、パッケージ化を選択することもできます。 + +## `asar` アーカイブの生成 + +[asar][asar] アーカイブは、1つのファイルに連結されたtarライクのシンプルなフォーマットです。Electronは、すべてのファイルをアンパッキングせずに、任意のファイルを読み込めます。 + +アプリを `asar` アーカイブにパッケージ化する手順 + +### 1. asar ツールのインストール + +```bash +$ npm install -g asar +``` + +### 2. `asar pack`でパッケージ化する + +```bash +$ asar pack your-app app.asar +``` + +## `asar` アーカイブを使用する + +Electronには、2組のAPIがあります。Node APIは、Node.jsで提供されており、Web APIは、Chromiumで提供されています。両方のAPIは、 `asar` アーカイブからのファイル読み込みに対応しています。 + +### Node API + +Electronでは特定のパッチで、`fs.readFile` や `require` のようなNode APIは、`asar` アーカイブを仮想ディレクトリのように扱い、ファイルをファイルシステムで通常のファイルのように扱います。 + +例えば、`/path/to` 配下に、`example.asar` アーカイブがあると仮定します: + +```bash +$ asar list /path/to/example.asar +/app.js +/file.txt +/dir/module.js +/static/index.html +/static/main.css +/static/jquery.min.js +``` + +`asar` アーカイブでファイルを読み込む: + +```javascript +const fs = require('fs'); +fs.readFileSync('/path/to/example.asar/file.txt'); +``` + +アーカイブのルート直下にあるすべてのファイルを一覧にする: + +```javascript +const fs = require('fs'); +fs.readdirSync('/path/to/example.asar'); +``` + +アーカイブからモジュールを使用する: + +```javascript +require('/path/to/example.asar/dir/module.js'); +``` + + `BrowserWindow`で、`asar`アーカイブで、Webページを表示することができます: + +```javascript +const BrowserWindow = require('electron').BrowserWindow; +var win = new BrowserWindow({width: 800, height: 600}); +win.loadURL('file:///path/to/example.asar/static/index.html'); +``` + +### Web API + +Webページで、アーカイブ内のファイルを `file:` プロトコルでリクエストできます。 +Node APIのように、`asar` アーカイブはディレクトリのように扱われます。 + +例えば、 `$.get` でファイルを取得できます: + +```html + +``` + +### `asar` アーカイブを通常のファイルのように扱う + +For some cases like verifying the `asar` アーカイブのチェックサムを検証するようなケースで、 `asar` アーカイブのコンテンツをファイルのように扱う必要があります。この目的のために、 `asar` サポートしないオリジナルの `fs` API が提供する ビルトインの `original-fs` モジュールを使用できます。 + +```javascript +var originalFs = require('original-fs'); +originalFs.readFileSync('/path/to/example.asar'); +``` + +`fs` モジュールで、`asar` サポートを無効化するために、`process.noAsar` を `true` に設定します: + +```javascript +process.noAsar = true; +fs.readFileSync('/path/to/example.asar'); +``` + +## Node API の制限 + +Node APIで、`asar` アーカイブが可能な限りディレクトリのように動作するよう懸命に試してますが、Node APIの低レベル性質の影響で、まだ制限があります。 + +### アーカイブは読み取り専用です + +ファイルを変更できる全てのNode APIは、 `asar` アーカイブに対して動作しないので、アーカイブは変更されません。 + +### 作業ディレクトリは、アーカイブ内のディレクトリに設定できません + +`asar` アーカイブはディレクトリのように扱われるにも関わらず、ファイルシステム上では実際のディレクトリではなく、`asar` アーカイブ内に決して作業ディレクトリは設定されません。いくつかのAPIの`cwd`オプションを設定していて、それがエラー原因になります。 + +### いくつかのAPIで追加のアンパッキングがされます + +たいていの `fs` APIは、アンパッキングせずに、 `asar` アーカイブからファイルを読み込んだり、ファイル情報を取得できます。しかし、実際のファイルパスを通してシステムコールに依存するAPIもあり、Electronは必要なファイルを一時ファイルに解凍し、一時ファイルのパスを通して、APIが動作します。これは、APIに多少のオーバーヘッドがあります。 + +追加のアンパッキングに必要なAPIです。: + +* `child_process.execFile` +* `child_process.execFileSync` +* `fs.open` +* `fs.openSync` +* `process.dlopen` - ネイティブモジュール上の `require` で使用されます + +### `fs.stat` の偽の統計情報 + +ファイルシステム上にファイルが存在しないので、`fs.stat` および `asar` アーカイブ内のファイルへの関連情報によって返される`Stats` オブジェクトは、推測して生成されます。ファイルサイズの取得とファイルタイプのチェックを除いて、 `Stats` オブジェクトを信頼すべきではありません。 + +### `asar` アーカイブ内でバイナリを実行します + +`child_process.exec` と `child_process.spawn` 、 `child_process.execFile` のようなバイナリを実行できるNode APIがあります。しかし、`execFile` だけが、`asar` アーカイブ内でのバイナリ実行をサポートしています。 + +`exec` と `spawn` は、インプットを `file` の代わりに `command` を受け取り、`command` はシェル配下で実行されます。コマンドがasar アーカイブ内のファイルを使うかどうかを決定するための信頼できる方法はありません。影響なしで、コマンドでパスを置き換えることができるかどうかを確認することはできません。 + +## アンパッキングする `asar` アーカイブ内のファイルを追加する + +上記のように、いくつかのNode APIは、呼び出さすとき、ファイルをファイルパスへアンパックします。パフォーマンス問題は別として、ウィルススキャナーのアラートにつながる可能性があります。 + +これに対する対応として、`--unpack` オプションを使用して、アーカイブを作成する際に、いくつかのファイルをアンパックできます。例えば、ネイティブモジュールの共有ライブラリを除きます。 + +```bash +$ asar pack app app.asar --unpack *.node +``` + +このコマンドを実行した後、`app.asar` とは別に、アンパックファイルを含んだ`app.asar.unpacked` フォルダーが生成され、ユーザーに提供するときには、`app.asar` と一緒にコピーしなければなりません。 + +[asar]: https://github.com/atom/asar diff --git a/docs-translations/jp/tutorial/debugging-main-process.md b/docs-translations/jp/tutorial/debugging-main-process.md new file mode 100644 index 000000000000..0839d351598a --- /dev/null +++ b/docs-translations/jp/tutorial/debugging-main-process.md @@ -0,0 +1,70 @@ +# メインプロセスのデバッグ + +ブラウザウィンドウ DevToolsのみ、レンダリングプロセススクリプトをデバッグすることができます。メインプロセスからスクリプトをデバッグする方法を提供するために、Electronは、`--debug` と `--debug-brk` スイッチを提供します。 + +## コマンドライン スイッチ + +Electronのメインプロセスをデバッグするために次のコマンドラインスイッチを使用します + +### `--debug=[port]` + +このスイッチを使ったとき、Electronは、 `port` 上でV8デバッガープロトコルメッセージをリッスンします。デフォルトの `port` は `5858`です。 + +### `--debug-brk=[port]` + +`--debug` のようですが、最初の行でスクリプトをポーズします。 + +## デバッグ用のnode-inspectorを使用する + +__Note:__ Electron は今のところ、明確にはnode-inspectorは動作せず、node-inspectorのコンソール下で、`process` オブジェクトを調査した場合、メインプロセスはクラッシュするでしょう。 + +### 1. インストールされた[node-gyp required tools][node-gyp-required-tools] を確認する + +### 2. [node-inspector][node-inspector]をインストールする + +```bash +$ npm install node-inspector +``` + +### 3. `node-pre-gyp`のパッチバージョンをインストールする + +```bash +$ npm install git+https://git@github.com/enlight/node-pre-gyp.git#detect-electron-runtime-in-find +``` + +### 4. Electron用の `node-inspector` `v8` モジュールをリコンパイルする(対象のElectronのバージョン番号を変更する) + +```bash +$ node_modules/.bin/node-pre-gyp --target=0.36.2 --runtime=electron --fallback-to-build --directory node_modules/v8-debug/ --dist-url=https://atom.io/download/atom-shell reinstall +$ node_modules/.bin/node-pre-gyp --target=0.36.2 --runtime=electron --fallback-to-build --directory node_modules/v8-profiler/ --dist-url=https://atom.io/download/atom-shell reinstall +``` + +[How to install native modules](how-to-install-native-modules)を見る。 + +### 5. Electron用のデバッグモードを有効にする + +デバッグフラッグでElectronを開始する: + +```bash +$ electron --debug=5858 your/app +``` + +または、最初のライン上でスクリプトをポーズする: + +```bash +$ electron --debug-brk=5858 your/app +``` + +### 5. Electronを使用して、[node-inspector][node-inspector] サーバーを開始する + +```bash +$ ELECTRON_RUN_AS_NODE=true path/to/electron.exe node_modules/node-inspector/bin/inspector.js +``` + +### 6. デバッグUIを読み込みます + +Chromeブラウザで、 http://127.0.0.1:8080/debug?ws=127.0.0.1:8080&port=5858 を開きます。エントリーラインを見るために、debug-brkを始めるには、ポーズをクリックします。 + +[node-inspector]: https://github.com/node-inspector/node-inspector +[node-gyp-required-tools]: https://github.com/nodejs/node-gyp#installation +[how-to-install-native-modules]: using-native-node-modules.md#how-to-install-native-modules diff --git a/docs-translations/jp/tutorial/desktop-environment-integration.md b/docs-translations/jp/tutorial/desktop-environment-integration.md new file mode 100644 index 000000000000..24d3e9d2aaa7 --- /dev/null +++ b/docs-translations/jp/tutorial/desktop-environment-integration.md @@ -0,0 +1,251 @@ +# デスクトップ環境の統合 + +異なるオペレーティングシステムは、それぞれのデスクトップ環境でデスクトップに統合されたアプリケーション用に異なる機能を提供します。例えば、Windows アプリケーションではタスクバーのジャンプバーリストにショートカットをおけ、Macではドックメニューにカスタムメニューをおけます。 + +このガイドでは、Electron APIでデスクトップ環境にアプリケーションを統合する方法を説明します。 + +## 通知 (Windows, Linux, OS X) + +3つのオペレーティングシステム全てで、アプリケーションからユーザーに通知を送る手段が提供されています。通知を表示するためにオペレーティングシステムのネイティブ通知APIを使用しする[HTML5 Notification API](https://notifications.spec.whatwg.org/)で、Electronは、開発者に通知を送ることができます。 + +```javascript +var myNotification = new Notification('Title', { + body: 'Lorem Ipsum Dolor Sit Amet' +}); + +myNotification.onclick = function () { + console.log('Notification clicked') +} +``` + +オペレーティングシステム間でコードとユーザ体験は似ていますが、細かい違いがあります。 + +### Windows + +* Windows 10では、通知はすぐに動作します。 +* Windows 8.1 と Windows 8では、[Application User +Model ID][app-user-model-id]で、アプリへのショートカットはスタートメニューにインストールされます。しかし、スタートメニューにピン止めをする必要がありません。 +* Windows 7以前は、通知はサポートされていません。 しかし、[Tray API](tray-balloon)を使用してバルーンヒントを送信することができます。 + +通知にイメージを使うために、通知オプションの `icon` プロパティにローカルのイメージファイル(`png`が望ましい)を設定します。 正しくない、または`http/https`の URLを設定した場合でも、通知は表示されますが、イメージは表示されません。 + +```javascript +new Notification('Title', { + body: 'Notification with icon', + icon: 'file:///C:/Users/feriese/Desktop/icon.png' +}); +``` + +その上で、bodyの最大サイズは250文字であることに留意してください。Windowsチームは、通知は200文字にすることを推奨しています。 + +### Linux + +通知は、`libnotify`を使用して送信されます。[デスクトップ通知仕様][notification-spec]に対応したデスクトップ環境上(Cinnamon、Enlightenment、Unity、GNOME、KDEなど)で通知を表示できます。 + +### OS X + +通知は、そのままOS Xに通知されます。しかし、[通知に関するAppleのヒューマンインターフェイスガイドライン(英語版)](https://developer.apple.com/library/mac/documentation/UserExperience/Conceptual/OSXHIGuidelines/NotificationCenter.html)を知っておくべきです。 + +通知は、256バイトサイズに制限されており、制限を超えていた場合、通知が破棄されます。 + +## 最近のドキュメント (Windows と OS X) + +Windows と OS Xは、ジャンプリストやドックメニュー経由で、アプリケーションが開いた最近のドキュメント一覧に簡単にアクセスできます。 + +__JumpList:__ + +![JumpList Recent Files](http://i.msdn.microsoft.com/dynimg/IC420538.png) + +__Application dock menu:__ + + + +最近のドキュメントにファイルを追加するために、[app.addRecentDocument][addrecentdocument] APIを使用できます: + +```javascript +app.addRecentDocument('/Users/USERNAME/Desktop/work.type'); +``` + +[app.clearRecentDocuments][clearrecentdocuments] API を使用して、最近のドキュメント一覧を空にできます: + +```javascript +app.clearRecentDocuments(); +``` + +### Windows 留意点 + +Windows で、この機能を使用できるようにするために、アプリケーションにドキュメントのファイルタイプのハンドラーを登録すべきです。さもなければ、ジャンプリストに表示されません。[Application Registration][app-registration]で、登録しているアプリケーションをすべて見れます。 + +ユーザーがジャンプリストからファイルをクリックしたとき、アプリケーションの新しいインスタンスは、コマンドライン引数にファイルのパスを渡して開始します。 + +### OS X 留意点 + +ファイルが最近のドキュメントメニューからリクエストされた時、 `app` モジュールの `open-file` イベントが発行されます。 + +## ドックメニュー (OS X)のカスタマイズ + +通常アプリケーションで使用する共通機能用のショートカットを含める、ドック用のカスタムメニューをOS Xでは指定できます。 + +__Dock menu of Terminal.app:__ + + + +カスタムドックメニューを設定するために、OS Xのみに提供されている `app.dock.setMenu` APIを使用できます。 + +```javascript +const electron = require('electron'); +const app = electron.app; +const Menu = electron.Menu; + +var dockMenu = Menu.buildFromTemplate([ + { label: 'New Window', click: function() { console.log('New Window'); } }, + { label: 'New Window with Settings', submenu: [ + { label: 'Basic' }, + { label: 'Pro'} + ]}, + { label: 'New Command...'} +]); +app.dock.setMenu(dockMenu); +``` + +## ユーザータスク (Windows) + +Windowsでは、ジャンプリストの `Tasks` カテゴリでカスタムアクションを指定できます。 +MSDNから引用します。 + +>アプリケーションでは、プログラムの機能とユーザーがプログラムを使用して実行する可能性が最も高い主な操作の両方に基づいてタスクを定義します。タスクを実行するためにアプリケーションが起動している必要がないように、タスクは状況に依存しないものにする必要があります。また、タスクは、一般的なユーザーがアプリケーションで実行する操作の中で、統計上最も一般的な操作です。たとえば、メール プログラムでは電子メールの作成や予定表の表示、ワード プロセッサでは新しい文書の作成、特定のモードでのアプリケーションの起動、アプリケーションのサブコマンドを実行することなどです。一般的なユーザーが必要としない高度な機能や、登録などの 1 回限りの操作によって、メニューがわかりづらくなることがないようにしてください。アップグレードやキャンペーンなどの販売促進用の項目としてタスクを使用しないでください。 + +>タスク一覧は静的なものにすることを強くお勧めします。アプリケーションの状態や状況に関係なく、タスク一覧は同じ状態にすることをお勧めします。リストを動的に変更することも可能ですが、ユーザーはターゲット一覧のこの部分が変更されると考えていないので、ユーザーを混乱させる可能性があることを考慮してください。 + +__Internet Explorerのタスク:__ + +![IE](http://i.msdn.microsoft.com/dynimg/IC420539.png) + +実際のメニューであるOS Xのドックメニューとは異なり、ユーザーがタスクをクリックしたとき、Windowsではユーザータスクはアプリケーションのショートカットのように動作し、プログラムは指定された引数を実行します。 + +アプリケーション用のユーザータスクを設定するために、[app.setUserTasks][setusertaskstasks] APIを使用できます: + +```javascript +app.setUserTasks([ + { + program: process.execPath, + arguments: '--new-window', + iconPath: process.execPath, + iconIndex: 0, + title: 'New Window', + description: 'Create a new window' + } +]); +``` + +タスクリストをクリアするために、`app.setUserTasks` をコールし、配列を空にします。 + +```javascript +app.setUserTasks([]); +``` + +アプリケーションを閉じた後もユーザータスクは表示されていてるので、アプリケーションをアンインストールするまではタスクに指定したアイコンとプログラムのパスは存在し続けてる必要があります。 + +## サムネイルツールバー(縮小表示ツールバー) + +Windowsでは、アプリケーションウィンドウのタスクバーレイアウトに、指定のボタンを縮小表示ツールバーに追加できます。アプリケーションのウィンドウを元のサイズに戻したりアクティブ化したりすることなく、主要なコマンドにアクセスできるようにします。 + +MSDNからの引用: + +>このツール バーは、単純に、使い慣れた標準的なツール バー コモン コントロールです。最大で 7 個のボタンが配置されます。各ボタンの ID、イメージ、ツールヒント、および状態は構造体で定義され、その後タスク バーに渡されます。アプリケーションでは、現在の状態での必要に応じて、縮小表示ツール バーのボタンの表示、有効化、無効化、非表示を実行できます。 +>たとえば、Windows Media Player の縮小表示ツール バーでは、再生、一時停止、ミュート、停止などの、標準的なメディア トランスポート コントロールを提供できます。 + +__Windows Media Playerの縮小表示ツールバー:__ + +![player](https://i-msdn.sec.s-msft.com/dynimg/IC420540.png) + +アプリケーションに縮小表示ツールバーを設定するために、[BrowserWindow.setThumbarButtons][setthumbarbuttons]を使えます: + +```javascript +const BrowserWindow = require('electron').BrowserWindow; +const path = require('path'); + +var win = new BrowserWindow({ + width: 800, + height: 600 +}); +win.setThumbarButtons([ + { + tooltip: "button1", + icon: path.join(__dirname, 'button1.png'), + click: function() { console.log("button2 clicked"); } + }, + { + tooltip: "button2", + icon: path.join(__dirname, 'button2.png'), + flags:['enabled', 'dismissonclick'], + click: function() { console.log("button2 clicked."); } + } +]); +``` + +縮小表示ツールバーボタンをクリアするために、 `BrowserWindow.setThumbarButtons` をコールして配列を空にします: + +```javascript +win.setThumbarButtons([]); +``` + +## Unity ランチャーショートカット (Linux) + +Unityでは、`.desktop` ファイルの修正を経由してランチャーにカスタムエントリーを追加できます。[Adding Shortcuts to a Launcher][unity-launcher]を参照してください。 + +__Audaciousのランチャーショートカット:__ + +![audacious](https://help.ubuntu.com/community/UnityLaunchersAndDesktopFiles?action=AttachFile&do=get&target=shortcuts.png) + +## タスクバーの進行状況バー (Windows & Unity) + +Windowsでは、タスクバーボタンは、進行状況バーを表示するのに使えます。ウィンドウを切り替えることなくウィンドウの進行状況情報をユーザーに提供することができます。 + +Unity DEは、ランチャーに進行状況バーの表示をするのと同様の機能を持っています。 + +__タスクバーボタン上の進行状況バー:__ + +![Taskbar Progress Bar](https://cloud.githubusercontent.com/assets/639601/5081682/16691fda-6f0e-11e4-9676-49b6418f1264.png) + +__Unityランチャーでの進行状況バー:__ + +![Unity Launcher](https://cloud.githubusercontent.com/assets/639601/5081747/4a0a589e-6f0f-11e4-803f-91594716a546.png) + +ウィンドウに進行状況バーを設定するために、[BrowserWindow.setProgressBar][setprogressbar] APIを使えます: + +```javascript +var window = new BrowserWindow({...}); +window.setProgressBar(0.5); +``` + +## Windowのファイル表示 (OS X) + +OS Xでは、ウィンドウがrepresented fileを設定でき、タイトルバー上にファイルのアイコンを表示でき、タイトル上でCommand-クリックまたはControl-クリックをすると、パスがポップアップ表示されます。 + +ウィンドウの編集状態を設定できるように、このウィンドウのドキュメントが変更されたかどうかをファイルのアイコンで示せます。 + +__Represented file ポップアップメニュー:__ + + + +ウィンドウにrepresented fileを設定するために、[BrowserWindow.setRepresentedFilename][setrepresentedfilename] と [BrowserWindow.setDocumentEdited][setdocumentedited] APIsを使えます: + +```javascript +var window = new BrowserWindow({...}); +window.setRepresentedFilename('/etc/passwd'); +window.setDocumentEdited(true); +``` + +[addrecentdocument]: ../api/app.md#appaddrecentdocumentpath +[clearrecentdocuments]: ../api/app.md#appclearrecentdocuments +[setusertaskstasks]: ../api/app.md#appsetusertaskstasks +[setprogressbar]: ../api/browser-window.md#browserwindowsetprogressbarprogress +[setrepresentedfilename]: ../api/browser-window.md#browserwindowsetrepresentedfilenamefilename +[setdocumentedited]: ../api/browser-window.md#browserwindowsetdocumenteditededited +[app-registration]: http://msdn.microsoft.com/en-us/library/windows/desktop/ee872121(v=vs.85).aspx +[unity-launcher]: https://help.ubuntu.com/community/UnityLaunchersAndDesktopFiles#Adding_shortcuts_to_a_launcher +[setthumbarbuttons]: ../api/browser-window.md#browserwindowsetthumbarbuttonsbuttons +[tray-balloon]: ../api/tray.md#traydisplayballoonoptions-windows +[app-user-model-id]: https://msdn.microsoft.com/en-us/library/windows/desktop/dd378459(v=vs.85).aspx +[notification-spec]: https://developer.gnome.org/notification-spec/ diff --git a/docs-translations/jp/tutorial/devtools-extension.md b/docs-translations/jp/tutorial/devtools-extension.md new file mode 100644 index 000000000000..a0847091ab07 --- /dev/null +++ b/docs-translations/jp/tutorial/devtools-extension.md @@ -0,0 +1,45 @@ +# DevTools 拡張 + +簡単にデバッグをするために、Electronは[Chrome DevTools Extension][devtools-extension]に基本的な対応しています。 + +DevToolsエクステンションのために、ソースコードをダウンローし、`BrowserWindow.addDevToolsExtension` APIを使って読み込みます。読み込んだエクステンションは維持されているので、ウィンドウを作成するとき、毎回APIをコールする必要はありません。 + +** NOTE: React DevTools は動作しません。issue https://github.com/atom/electron/issues/915 でフォローしています** + +例えば、[React DevTools Extension](https://github.com/facebook/react-devtools)を使うために、最初にソースコードをダウンロードする必要があります。 + +```bash +$ cd /some-directory +$ git clone --recursive https://github.com/facebook/react-devtools.git +``` + +エクステンションをビルドするために、[`react-devtools/shells/chrome/Readme.md`](https://github.com/facebook/react-devtools/blob/master/shells/chrome/Readme.md)を参照してください。 + +複数のウィンドウで、DevToolsを開くために、Electronでエクステンションをロードし、DevToolsコンソールで次のコードを実行します。 + +```javascript +const BrowserWindow = require('electron').remote.BrowserWindow; +BrowserWindow.addDevToolsExtension('/some-directory/react-devtools/shells/chrome'); +``` + +エクステンションをアンロードするために、名前と`BrowserWindow.removeDevToolsExtension` APIをコールすると、次回DevToolsを開いた時にはロードされません。 + +```javascript +BrowserWindow.removeDevToolsExtension('React Developer Tools'); +``` + +## DevTools エクステンションのフォーマット + +理想的には、Chromeブラウザー用に書かれたすべてのDevToolsエクステンションをElectronがロードできることですが、それらはプレーンディレクトリにある必要があります。`crx` エクステンションパッケージは、ディレクトリに解凍できる方法がなければ、Electronはロードする方法はありません。 + +## バックグラウンドページ + +今のところ、ElectronはChromエクステンションのバックグラウンドページ機能に対応していません。そのため、Electronでは、この機能に依存するDevToolsエクステンションは動作しません。 + +## `chrome.*` APIs + +いくつかのChromeエクステンションは、`chrome.*` APIsを使用しており、ElectronでそれらのAPIを実装するための努力をしていますが、すべては実装されていません。 + +すべては実装されていない`chrome.*` APIについて考えると、もしDevToolsエクステンションが `chrome.devtools.*` 以外のAPIを使用していると、エクステンションは動作しない可能性が非常に高いです。 + +[devtools-extension]: https://developer.chrome.com/extensions/devtools diff --git a/docs-translations/jp/tutorial/mac-app-store-submission-guide.md b/docs-translations/jp/tutorial/mac-app-store-submission-guide.md new file mode 100644 index 000000000000..a04eff1d9b2b --- /dev/null +++ b/docs-translations/jp/tutorial/mac-app-store-submission-guide.md @@ -0,0 +1,103 @@ +# Mac App Store Submission Guide + +v0.34.0から、ElectronはMac App Store (MAS)にパッケージ化したアプリを登録することができます。このガイドでは、MASビルド用の制限とアプリを登録する方法についての情報を提供します。 + +__Note:__ Mac App Storeにアプリを登録するには、費用が発生する[Apple Developer Program][developer-program]に登録する必要があります。 + +## アプリを登録する方法 + +次の手順は、Mac App Sotreにアプリを登録する簡単な手順を説明します。しかし、これらの手順はAppleによってAppが承認されることを保証するものではありません。Mac App Storeの要件については、Appleの[Submitting Your App][submitting-your-app]ガイドを読んでおく必要があります。 + +### 証明書の取得 + +Mac App StoreにAppを登録するには、最初にAppleから証明書を取得しなければありません。Web上で、[existing guides][nwjs-guide] を参照してください。 + +### アプリケーションの署名 + +Appleから証明書を取得した後、[Application Distribution](application-distribution.md)を参照してアプリをパッケージ化し、アプリに証明をします。この手順は、基本的にほかのプログラムと同じですが、Electronが依存するすべてに1つ1つサインします。 + +最初に、2つの資格ファイルを用意する必要があります。 + +`child.plist`: + +```xml + + + + + com.apple.security.app-sandbox + + com.apple.security.inherit + + + +``` + +`parent.plist`: + +```xml + + + + + com.apple.security.app-sandbox + + + +``` + +次のスクリプトでアプリをサインします。 + +```bash +#!/bin/bash + +# Name of your app. +APP="YourApp" +# The path of you app to sign. +APP_PATH="/path/to/YouApp.app" +# The path to the location you want to put the signed package. +RESULT_PATH="~/Desktop/$APP.pkg" +# The name of certificates you requested. +APP_KEY="3rd Party Mac Developer Application: Company Name (APPIDENTITY)" +INSTALLER_KEY="3rd Party Mac Developer Installer: Company Name (APPIDENTITY)" + +FRAMEWORKS_PATH="$APP_PATH/Contents/Frameworks" + +codesign --deep -fs "$APP_KEY" --entitlements child.plist "$FRAMEWORKS_PATH/Electron Framework.framework/Libraries/libnode.dylib" +codesign --deep -fs "$APP_KEY" --entitlements child.plist "$FRAMEWORKS_PATH/Electron Framework.framework/Electron Framework" +codesign --deep -fs "$APP_KEY" --entitlements child.plist "$FRAMEWORKS_PATH/Electron Framework.framework/" +codesign --deep -fs "$APP_KEY" --entitlements child.plist "$FRAMEWORKS_PATH/$APP Helper.app/" +codesign --deep -fs "$APP_KEY" --entitlements child.plist "$FRAMEWORKS_PATH/$APP Helper EH.app/" +codesign --deep -fs "$APP_KEY" --entitlements child.plist "$FRAMEWORKS_PATH/$APP Helper NP.app/" +codesign -fs "$APP_KEY" --entitlements parent.plist "$APP_PATH" +productbuild --component "$APP_PATH" /Applications --sign "$INSTALLER_KEY" "$RESULT_PATH" +``` + +OS Xで、サンドボックスにアプリを新しく追加した場合、基本的な考え方は、Appleの[Enabling App Sandbox][enable-app-sandbox]を読み、エンタイトルメントファイルにアプリに必要なパーミッションキーを追加します。 + +### Appをアップロードし、レビューに登録する + +アプリに署名後、iTunes ConnectにアップロードするためにApplication Loaderを使用できます。アップロードする前に[created a record][create-record]を確認してください。そして[レビュー用にアプリを登録できます][submit-for-review]. + +## MAS Buildの制限 + +アプリのサンドボックスですべての要件を満たすために、MASビルドで次のモジュールを無効にしてください。 + +* `crash-reporter` +* `auto-updater` + +次の挙動を変更してください。 + +* ビデオキャプチャーはいくつかのマシンで動作しないかもしれません。 +* 一部のアクセシビリティ機能が動作しないことがあります。 +* アプリはDNSの変更を認識しません。 + +アプリのサンドボックスでの使用が原因で、アプリがアクセスできるリソースは厳密に制限されています。詳細は、 [App Sandboxing][app-sandboxing] を参照してください。 + +[developer-program]: https://developer.apple.com/support/compare-memberships/ +[submitting-your-app]: https://developer.apple.com/library/mac/documentation/IDEs/Conceptual/AppDistributionGuide/SubmittingYourApp/SubmittingYourApp.html +[nwjs-guide]: https://github.com/nwjs/nw.js/wiki/Mac-App-Store-%28MAS%29-Submission-Guideline#first-steps +[enable-app-sandbox]: https://developer.apple.com/library/ios/documentation/Miscellaneous/Reference/EntitlementKeyReference/Chapters/EnablingAppSandbox.html +[create-record]: https://developer.apple.com/library/ios/documentation/LanguagesUtilities/Conceptual/iTunesConnect_Guide/Chapters/CreatingiTunesConnectRecord.html +[submit-for-review]: https://developer.apple.com/library/ios/documentation/LanguagesUtilities/Conceptual/iTunesConnect_Guide/Chapters/SubmittingTheApp.html +[app-sandboxing]: https://developer.apple.com/app-sandboxing/ diff --git a/docs-translations/jp/tutorial/online-offline-events.md b/docs-translations/jp/tutorial/online-offline-events.md new file mode 100644 index 000000000000..d1fa8858232a --- /dev/null +++ b/docs-translations/jp/tutorial/online-offline-events.md @@ -0,0 +1,81 @@ +# オンライン/オフライン イベントの検知 + + + +オンラインとオフラインイベントの検知は、標準のHTML 5 APIを使用して、状況表示を実装できます。次の例を見てみましょう。 + +_main.js_ + +```javascript +const electron = require('electron'); +const app = electron.app; +const BrowserWindow = electron.BrowserWindow; + +var onlineStatusWindow; +app.on('ready', function() { + onlineStatusWindow = new BrowserWindow({ width: 0, height: 0, show: false }); + onlineStatusWindow.loadURL('file://' + __dirname + '/online-status.html'); +}); +``` + +_online-status.html_ + +```html + + + + + + +``` + +メインプロセスでそれらのイベントに反応するインスタンスがあるかもしれません。メインプロセスは、`navigator` オブジェクトをもたず、直接それらのイベントを検知できません。Electronの内部プロセスコミュニケーションツールを使用して、イベントはメインプロセスに転送され、必要があればハンドルできます。次の例を見てみましょう。 + +_main.js_ + +```javascript +const electron = require('electron'); +const app = electron.app; +const ipcMain = electron.ipcMain; +const BrowserWindow = electron.BrowserWindow; + +var onlineStatusWindow; +app.on('ready', function() { + onlineStatusWindow = new BrowserWindow({ width: 0, height: 0, show: false }); + onlineStatusWindow.loadURL('file://' + __dirname + '/online-status.html'); +}); + +ipcMain.on('online-status-changed', function(event, status) { + console.log(status); +}); +``` + +_online-status.html_ + +```html + + + + + + +``` diff --git a/docs-translations/jp/tutorial/supported-platforms.md b/docs-translations/jp/tutorial/supported-platforms.md new file mode 100644 index 000000000000..8482931ed21e --- /dev/null +++ b/docs-translations/jp/tutorial/supported-platforms.md @@ -0,0 +1,24 @@ +# サポートするプラットフォーム + +Electronでは次のプラットフォームをサポートします。 + +### OS X + +OS X用に提供しているバイナリは64bitのみで、サポートするOS Xのバージョンは、OS X 10.8 以降です。 + +### Windows + +Windows 7 以降をサポートしており、それ以前のオペレーティングシステムはサポートしていません(し、動作しません)。 + +`x86` と `amd64` (x64) の両方のバイナリが、Windows用に提供しています。 +ただし、`ARM` バージョンのWindowsは今のところサポートしていません。 + +### Linux + +`ia32`(`i686`) と `x64`(`amd64`) のビルド済みバイナリは、Ubuntu 12.04上でビルドされ、`arm` バイナリは、Debian Wheezy用のhard-float ABIとNEONのARM v7を対象にビルドしています。 + +Electronはビルドプラットフォームにリンクされているので、ディストリビューションに同梱されているライブラリに依存しているかどうかに関係なくディストリビューション上で動作します。そのため Ubuntu 12.04 のみを動作保証しますが、次のプラットフォームについてもビルド済みのElectronバイナリを実行できるか検証します。 + +* Ubuntu 12.04 以降 +* Fedora 21 +* Debian 8 diff --git a/docs-translations/jp/tutorial/using-native-node-modules.md b/docs-translations/jp/tutorial/using-native-node-modules.md new file mode 100644 index 000000000000..c0bce4fab8d8 --- /dev/null +++ b/docs-translations/jp/tutorial/using-native-node-modules.md @@ -0,0 +1,50 @@ +# ネイティブのNodeモジュールを使用する + +Electronは、ネイティブのNodeモジュールをサポートしていますが、Node公式とは異なるV8バージョンを使用しているので、ネイティブモジュールでビルドする時、Electronのヘッダーで指定する必要があります。 + +## ネイティブNodeモジュールとの互換性 + +Nodeが新しいV8バージョンを使用し始めた時、Nativeモジュールは動作しなくなるかもしれません。ElectronでNativeモジュールが動作するかどうかを確認するために、Electronで使用する内部のNodeバージョンがサポートしているかを確認すべきです。ElectronでNodeが使用しているバージョンを確認するには、[releases](https://github.com/atom/electron/releases)ページを見るか、`process.version` (例えば [Quick Start](https://github.com/atom/electron/blob/master/docs/tutorial/quick-start.md)を見てください)を使用してください。 + +Nodeの複数バージョンを簡単にサポートできるので、あなたのモジュールに [NAN](https://github.com/nodejs/nan/) を使うことを検討してください。古いバージョンからElectronで動作するNodeの新しいバージョンへ移植するのに役立ちます。 + +## ネイティブモジュールのインストール方法 + +ネイティブモジュールをインストールするための3つの方法: + +### 簡単な方法 + +ヘッダーをダウンロードし、ネイティブモジュールをビルドする手順をマニュアルで管理する、[`electron-rebuild`](https://github.com/paulcbetts/electron-rebuild) パッケージ経由で、ネイティブモジュールをリビルドするのが最も簡単な方法です。 + +```sh +npm install --save-dev electron-rebuild + +# Every time you run "npm install", run this +./node_modules/.bin/electron-rebuild + +# On Windows if you have trouble, try: +.\node_modules\.bin\electron-rebuild.cmd +``` + +### npmを使う方法 + +モジュールをインストールするために`npm` を使用できます。環境変数の設定を除いて、Nodeモジュールと完全に同じ手順です。 + +```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 +``` + +### node-gypを使う方法 + +ElectronのヘッダーでNodeモジュールをビルドするために、どこからヘッダーをダウンロードするかとどのバージョンを使用するかを選択して`node-gyp`を実行する必要があります。 + +```bash +$ cd /path-to-module/ +$ HOME=~/.electron-gyp node-gyp rebuild --target=0.29.1 --arch=x64 --dist-url=https://atom.io/download/atom-shell +``` + +開発ヘッダーを探し、 `HOME=~/.electron-gyp` を変更します。`--target=0.29.1`がElectronのバージョンです。 `--dist-url=...` で、どこからヘッダーをダウンロードするかを指定します。`--arch=x64`を使用して、64bit システム用にモジュールをビルドします。 diff --git a/docs-translations/jp/tutorial/using-pepper-flash-plugin.md b/docs-translations/jp/tutorial/using-pepper-flash-plugin.md new file mode 100644 index 000000000000..841a505c1e1a --- /dev/null +++ b/docs-translations/jp/tutorial/using-pepper-flash-plugin.md @@ -0,0 +1,46 @@ +# Pepper Flash プラグインを使用する + +Electronは、Pepper Flashプラグインをサポートしています。ElectronでPepper Flashプラグインを使用するために、マニュアルでPepper Flashプラグインのパスを指定し、アプリケーションで有効化しなければなりません。 + +Electron now supports the Pepper Flash plugin. To use the Pepper Flash plugin in + +## Flash プラグインのコピー準備 + +OS XとLinuxでは、Pepper Flashプラグインの詳細は、Chromeブラウザーで、`chrome://plugins` にアクセスして確認できます。そこで表示されるパスとバージョンは、ElectronのPepper Flashサポートに役立ちます。それを別のパスにコピーすることができます。 + +## Electron スイッチの追加 + +直接、Electronコマンドラインに`--ppapi-flash-path` と `ppapi-flash-version` を追加するか、 アプリのreadyイベントの前に、`app.commandLine.appendSwitch`メソッドを使用します。`browser-window`の`plugins`スイッチを追加します。 + +例: + +```javascript +// Specify flash path. +// On Windows, it might be /path/to/pepflashplayer.dll +// On OS X, /path/to/PepperFlashPlayer.plugin +// On Linux, /path/to/libpepflashplayer.so +app.commandLine.appendSwitch('ppapi-flash-path', '/path/to/libpepflashplayer.so'); + +// Specify flash version, for example, v17.0.0.169 +app.commandLine.appendSwitch('ppapi-flash-version', '17.0.0.169'); + +app.on('ready', function() { + mainWindow = new BrowserWindow({ + 'width': 800, + 'height': 600, + 'web-preferences': { + 'plugins': true + } + }); + mainWindow.loadURL('file://' + __dirname + '/index.html'); + // Something else +}); +``` + +## `` タグでFlashプラグインを有効か + +`` タグに`plugins`属性を追加する + +```html + +``` diff --git a/docs-translations/jp/tutorial/using-selenium-and-webdriver.md b/docs-translations/jp/tutorial/using-selenium-and-webdriver.md new file mode 100644 index 000000000000..3202028ebf5f --- /dev/null +++ b/docs-translations/jp/tutorial/using-selenium-and-webdriver.md @@ -0,0 +1,119 @@ +# Selenium と WebDriverを使用する + +[ChromeDriver - WebDriver for Chrome][chrome-driver]より: + +> WebDriverは、複数のブラウザ間でWebアプリの自動テストをするためのオープンソースツールです。Webページの移動、ユーザー入力、JavaScriptの実行などを可能にします。ChromeDriverはChromium用のWebDriverのワイヤープロトコルで実装されたスタンドアロンサーバーです。ChromiumとWebDriverチームメンバーが開発しています。 + +Electronで `chromedriver` を使用するために、Electronがどこにあるかを示し、ElectronはChromeブラウザーであると思わせます。 + +## WebDriverJsを設定します + +[WebDriverJs](https://code.google.com/p/selenium/wiki/WebDriverJs) は、web driver でテストするためのNodeパッケージを提供します。例のように使用します。 + +### 1. ChromeDriverを開始 + +最初に、 `chromedriver` バイナリをダウンロードし、実行します: + +```bash +$ ./chromedriver +Starting ChromeDriver (v2.10.291558) on port 9515 +Only local connections are allowed. +``` + +ポート番号 `9515`を覚えておいてください、あとで使用します。 + +### 2. WebDriverJSのインストール + +```bash +$ npm install selenium-webdriver +``` + +### 3. ChromeDriverに接続する + +Electronでの `selenium-webdriver` 使用方法は、chrome driverへの接続方法とElectronバイナリがどこにあるかをマニュアルで指定する以外は、upstreamと基本的に同じです。 + +```javascript +const webdriver = require('selenium-webdriver'); + +var driver = new webdriver.Builder() + // The "9515" is the port opened by chrome driver. + .usingServer('http://localhost:9515') + .withCapabilities({ + chromeOptions: { + // Here is the path to your Electron binary. + binary: '/Path-to-Your-App.app/Contents/MacOS/Atom', + } + }) + .forBrowser('electron') + .build(); + +driver.get('http://www.google.com'); +driver.findElement(webdriver.By.name('q')).sendKeys('webdriver'); +driver.findElement(webdriver.By.name('btnG')).click(); +driver.wait(function() { + return driver.getTitle().then(function(title) { + return title === 'webdriver - Google Search'; + }); +}, 1000); + +driver.quit(); +``` + +## WebdriverIOのセットアップをする + +[WebdriverIO](http://webdriver.io/) は、web driverでテストするNodeパッケージを提供します。 + +### 1. ChromeDriverを開始する + +最初に、 `chromedriver` バイナリをダウンロードし、実行します。: + +```bash +$ chromedriver --url-base=wd/hub --port=9515 +Starting ChromeDriver (v2.10.291558) on port 9515 +Only local connections are allowed. +``` + +ポート番号 `9515`を覚えておいてください、あとで使用します。 + +### 2. WebdriverIOをインストールする + +```bash +$ npm install webdriverio +``` + +### 3. chrome driverに接続する + +```javascript +const webdriverio = require('webdriverio'); +var options = { + host: "localhost", // Use localhost as chrome driver server + port: 9515, // "9515" is the port opened by chrome driver. + desiredCapabilities: { + browserName: 'chrome', + chromeOptions: { + binary: '/Path-to-Your-App/electron', // Path to your Electron binary. + args: [/* cli arguments */] // Optional, perhaps 'app=' + /path/to/your/app/ + } + } +}; + +var client = webdriverio.remote(options); + +client + .init() + .url('http://google.com') + .setValue('#q', 'webdriverio') + .click('#btnG') + .getTitle().then(function(title) { + console.log('Title was: ' + title); + }) + .end(); +``` + +## ワークフロー + +Electronはリビルドせずにアプリケーションをテストするために、単純にElectronのリソースディレクトリでアプリのソースを[配置します](https://github.com/atom/electron/blob/master/docs/tutorial/application-distribution.md)。 + +もしくは、アプリのフォルダーを引数にしてElectronバイナリを実行します。これは、Electronのリソースディレクトリにアプリをコピー&ペーストする必要性を除きます。 + +[chrome-driver]: https://sites.google.com/a/chromium.org/chromedriver/ diff --git a/docs-translations/jp/tutorial/using-widevine-cdm-plugin.md b/docs-translations/jp/tutorial/using-widevine-cdm-plugin.md new file mode 100644 index 000000000000..5cee7f26dc66 --- /dev/null +++ b/docs-translations/jp/tutorial/using-widevine-cdm-plugin.md @@ -0,0 +1,57 @@ +# Widevine CDM Pluginを使用する + +Electronで、Chromeブラウザーに同梱される Widevine CDMプラグインを使用できます。 + +## プラグインを取得する + +Electronは、ライセンス的な理由でWidevine CDMプラグインは同梱されません。Widevine CDMプラグインを取得するために、最初に、使用するElectronビルドのChromバージョンとアーキテクチャを合わせた公式のChromeブラウザーをインストールする必要があります。 + +### Windows & OS X + +Chromeブラウザーで、`chrome://components/`を開き、 `WidevineCdm` を探し、それが最新であることを確認し、`APP_DATA/Google/Chrome/WidevineCDM/VERSION/_platform_specific/PLATFORM_ARCH/`ディレクトリからすべてのプラグインバイナリを探します。 + +`APP_DATA` は、アプリデータを格納するシステムロケーションです。Windowsでは`%LOCALAPPDATA%`、OS Xでは`~/Library/Application Support`です。`VERSION` は、Widevine CDM プラグインのバージョン文字列で、 `1.4.8.866`のような文字列が格納されます。`PLATFORM` は、 `mac` か `win`です。`ARCH` は `x86` か `x64`です。 + +Windowsでは、`widevinecdm.dll` と `widevinecdmadapter.dll`が必要で、OS Xでは、`libwidevinecdm.dylib` と `widevinecdmadapter.plugin`です。任意の場所にコピーできますが、一緒に配置する必要があります。 + +### Linux + +Linux上では、プラグインバイナリは、Chromeブラウザーにいっほに格納され、 `/opt/google/chrome` 配下にあり、ファイル名は `libwidevinecdm.so` と `libwidevinecdmadapter.so`です。 + +## プラグインを使用する + +プラグインファイルを取得した後、Electronoの`--widevine-cdm-path`コマンドラインスイッチで`widevinecdmadapter`のパスを指定し、`--widevine-cdm-version`スイッチでプラグインのバージョンを指定します。 + +__Note:__ `widevinecdmadapter` バイナリはElectronにパスが通っていても`widevinecdm` バイナリはそこに置く必要があります。 + +コマンドラインスイッチは、`app`モジュールの`ready`イベントが発火する前に通り、プラグインが使用するページは、プラグインを有効にしなければなりません。 + +サンプルコード: + +```javascript +// You have to pass the filename of `widevinecdmadapter` here, it is +// * `widevinecdmadapter.plugin` on OS X, +// * `libwidevinecdmadapter.so` on Linux, +// * `widevinecdmadapter.dll` on Windows. +app.commandLine.appendSwitch('widevine-cdm-path', '/path/to/widevinecdmadapter.plugin'); +// The version of plugin can be got from `chrome://plugins` page in Chrome. +app.commandLine.appendSwitch('widevine-cdm-version', '1.4.8.866'); + +var mainWindow = null; +app.on('ready', function() { + mainWindow = new BrowserWindow({ + webPreferences: { + // The `plugins` have to be enabled. + plugins: true + } + }) +}); +``` + +## プラグインの検証 + +プラグインが動作するかどうかを検証するために、次の方法を使用できます。 + +* devtoolsを開き、Widevine CDMプラグインに`navigator.plugins`が含まれているかどうかを確認します。 +* https://shaka-player-demo.appspot.com/ を開き、`Widevine`で使用するマニフェストをロードします。 +* http://www.dash-player.com/demo/drm-test-area/を開き、`bitdash uses Widevine in your browser`をチェックし、ビデオを再生します。 From 373bed33c5b1406ead49237eda0b3dbee6dd045b Mon Sep 17 00:00:00 2001 From: Plusb Preco Date: Sat, 9 Jan 2016 08:13:25 +0900 Subject: [PATCH 22/95] :memo: Update as upstream [ci skip] --- docs-translations/ko-KR/README.md | 11 +- docs-translations/ko-KR/api/browser-window.md | 135 +++++++++--------- .../ko-KR/api/chrome-command-line-switches.md | 9 ++ .../ko-KR/api/global-shortcut.md | 23 +-- docs-translations/ko-KR/api/screen.md | 18 +++ docs-translations/ko-KR/faq/electron-faq.md | 81 +++++++++++ .../tutorial/application-distribution.md | 16 +-- .../ko-KR/tutorial/debugging-main-process.md | 36 ++++- 8 files changed, 240 insertions(+), 89 deletions(-) create mode 100644 docs-translations/ko-KR/faq/electron-faq.md diff --git a/docs-translations/ko-KR/README.md b/docs-translations/ko-KR/README.md index 473f521136bb..6f4a1c520f53 100644 --- a/docs-translations/ko-KR/README.md +++ b/docs-translations/ko-KR/README.md @@ -6,11 +6,18 @@ URL에 포함되어 있습니다. 만약 그렇지 않다면, 아마 현재 보 수 있습니다. 또한 GitHub 인터페이스의 "Switch branches/tags" 드롭다운 메뉴에서도 사용 중인 Electron 버전으로 변경할 수 있습니다. -**역주:** 한국어 번역 문서는 atom.io에 반영이 되어있지 않습니다. 따라서 번역 문서는 -GitHub 프로젝트내에서만 볼 수 있고 `master` 브랜치의 문서는 현재 개발중인 프로젝트의 +**역주:** 한국어 번역 문서는 `atom.io`에 반영되어 있지 않습니다. 따라서 번역 문서는 +GitHub 프로젝트내에서만 볼 수 있으며 `master` 브랜치의 문서는 현재 개발중인 프로젝트의 문서입니다. 한국어 번역 문서는 현재 `upstream` 원본 문서의 변경에 따라 최대한 문서의 버전을 맞추려고 노력하고 있지만 가끔 누락된 번역이 존재할 수 있습니다. +## FAQ + +Electron에 대해 자주 묻는 질문이 있습니다. 이슈를 생성하기 전에 다음 문서를 먼저 +확인해 보세요: + +* [Electron FAQ](faq/electron-faq.md) + ## 개발 가이드 * [지원하는 플랫폼](tutorial/supported-platforms.md) diff --git a/docs-translations/ko-KR/api/browser-window.md b/docs-translations/ko-KR/api/browser-window.md index a278a5075241..9086f8374241 100644 --- a/docs-translations/ko-KR/api/browser-window.md +++ b/docs-translations/ko-KR/api/browser-window.md @@ -77,73 +77,78 @@ win.show(); 몇몇 GTK+3 데스크톱 환경에서만 작동합니다. 기본값은 `false`입니다. * `transparent` Boolean - 윈도우 창을 [투명화](frameless-window.md)합니다. 기본값은 `false`입니다. -* `type` String - 특정 플랫폼에만 적용되는 윈도우 창의 종류를 지정합니다. 기본적으로 - 이 속성이 `undefined`일 경우 표준 윈도우가 사용됩니다. 사용할 수 있는 창의 종류는 - 다음과 같습니다: - * Linux의 경우: `desktop`, `dock`, `toolbar`, `splash`, `notification` 종류를 - 사용할 수 있습니다. - * OS X의 경우: `desktop`, `textured` 종류를 사용할 수 있습니다. `textured` 종류는 - 창을 그라디언트 형태로 표현합니다 (`NSTexturedBackgroundWindowMask`) `desktop` - 종류는 데스크탑 배경 레벨에 윈도우를 배치합니다 (`kCGDesktopWindowLevel - 1`). - 참고로 이렇게 만들어진 윈도우는 포커스, 키보드, 마우스 이벤트를 받을 수 없습니다. - 하지만 편법으로 `globalShortcut`을 통해 키 입력을 받을 수 있습니다. +* `type` String - 특정 플랫폼에만 적용되는 윈도우 창의 종류를 지정합니다. 기본값은 + 일반 윈도우 입니다. 사용할 수 있는 창의 종류는 아래를 참고하세요. * `standardWindow` Boolean - OS X의 표준 윈도우를 텍스쳐 윈도우 대신 사용합니다. 기본 값은 `true`입니다. -* `titleBarStyle` String, OS X - 윈도우 타이틀 바 스타일을 지정합니다. 이 속성은 - OS X 10.10 Yosemite 이후 버전만 지원합니다. 다음 3가지 종류의 값을 사용할 수 - 있습니다: - * `default` 또는 미지정: 표준 Mac 회색 불투명 스타일을 사용합니다. - * `hidden`: 타이틀 바를 숨기고 컨텐츠 전체를 윈도우 크기에 맞춥니다. - 타이틀 바는 없어지지만 표준 창 컨트롤 ("신호등 버튼")은 왼쪽 상단에 유지됩니다. - * `hidden-inset`: `hidden` 타이틀 바 속성과 함께 신호등 버튼이 윈도우 모서리로부터 - 약간 더 안쪽으로 들어가도록합니다. +* `titleBarStyle` String, OS X - 윈도우 타이틀 바 스타일을 지정합니다. 자세한 사항은 + 아래를 참고하세요. * `webPreferences` Object - 웹 페이지 기능을 설정합니다. 사용할 수 있는 속성은 - 다음과 같습니다: - * `nodeIntegration` Boolean - node(node.js) 통합 여부. 기본값은 `true`입니다. - * `preload` String - 스크립트를 지정하면 페이지 내의 다른 스크립트가 작동하기 전에 - 로드됩니다. 여기서 지정한 스크립트는 node 통합 활성화 여부에 상관없이 언제나 모든 - node API에 접근할 수 있습니다. 이 속성의 스크립트 경로는 절대 경로로 지정해야 - 합니다. node 통합이 비활성화되어있을 경우, preload 스크립트는 node의 global - 심볼들을 다시 global 스코프로 다시 포함 시킬 수 있습니다. - [여기](process.md#event-loaded)의 예제를 참고하세요. - * `partition` String - 페이지에서 사용할 세션을 지정합니다. 만약 `partition`이 - `persist:`로 시작하면 페이지는 지속성 세션을 사용하며 다른 모든 앱 내의 - 페이지에서 같은 `partition`을 사용할 수 있습니다. 만약 `persist:` 접두어로 - 시작하지 않으면 페이지는 인-메모리 세션을 사용합니다. 여러 페이지에서 같은 - `partition`을 지정하면 같은 세션을 공유할 수 있습니다. `partition`을 지정하지 - 않으면 어플리케이션의 기본 세션이 사용됩니다. - * `zoomFactor` Number - 페이지의 기본 줌 값을 지정합니다. 예를 들어 `300%`를 - 표현하려면 `3.0`으로 지정합니다. 기본값은 `1.0`입니다. - * `javascript` Boolean - 자바스크립트를 활성화합니다. 기본값은 `false`입니다. - * `webSecurity` Boolean - `false`로 지정하면 same-origin 정책을 비활성화합니다. - (이 속성은 보통 사람들에 의해 웹 사이트를 테스트할 때 사용합니다) 그리고 - `allowDisplayingInsecureContent`와 `allowRunningInsecureContent` 두 속성을 - 사용자가 `true`로 지정되지 않은 경우 `true`로 지정합니다. 기본값은 - `true`입니다. - * `allowDisplayingInsecureContent` Boolean - https 페이지에서 http URL에서 - 로드한 이미지 같은 리소스를 표시할 수 있도록 허용합니다. 기본값은 `false`입니다. - * `allowRunningInsecureContent` Boolean - https 페이지에서 http URL에서 로드한 - JavaScript와 CSS 또는 플러그인을 실행시킬 수 있도록 허용합니다. 기본값은 - `false`입니다. - * `images` Boolean - 이미지 지원을 활성화합니다. 기본값은 `true`입니다. - * `textAreasAreResizable` Boolean - HTML TextArea 요소의 크기를 재조정을 - 허용합니다. 기본값은 `true`입니다. - * `webgl` Boolean - WebGL 지원을 활성화합니다. 기본값은 `true`입니다. - * `webaudio` Boolean - WebAudio 지원을 활성화합니다. 기본값은 `true`입니다. - * `plugins` Boolean - 플러그인 활성화 여부를 지정합니다. 기본값은 `false`입니다. - * `experimentalFeatures` Boolean - Chrome의 실험적인 기능을 활성화합니다. - 기본값은 `false`입니다. - * `experimentalCanvasFeatures` Boolean - Chrome의 실험적인 캔버스(canvas) 기능을 - 활성화합니다. 기본값은 `false`입니다. - * `overlayScrollbars` Boolean - 오버레이 스크롤바를 활성화합니다. 기본값은 - `false`입니다. - * `sharedWorker` Boolean - SharedWorker 기능을 활성화합니다. 기본값은 - `false`입니다. - * `directWrite` Boolean - Windows에서 폰트 랜더링을 위해 DirectWrite를 - 사용하는지를 지정합니다. 기본값은 `true`입니다. - * `pageVisibility` Boolean - 현재 윈도우의 가시성을 반영하는 대신 페이지가 - visible 또는 hidden 중 지정된 상태를 계속 유지하도록 합니다. 이 속성을 `true`로 - 지정하면 DOM 타이머의 스로틀링을 방지할 수 있습니다. 기본값은 `false`입니다. + 아래를 참고하세요. + +`type` 속성에서 사용할 수 있는 값과 동작은 다음과 같으며, 플랫폼에 따라 다릅니다: + +* Linux의 경우, `desktop`, `dock`, `toolbar`, `splash`, `notification` 종류를 + 사용할 수 있습니다. +* OS X의 경우, `desktop`, `textured` 종류를 사용할 수 있습니다. + * `textured`는 창에 메탈 그라디언트 외관(`NSTexturedBackgroundWindowMask`)을 + 설정합니다. + * `desktop`은 데스크탑 배경 레벨(`kCGDesktopWindowLevel - 1`)에 윈도우를 + 배치합니다. 참고로 이렇게 만들어진 윈도우는 포커스, 키보드, 마우스 이벤트를 받을 + 수 없습니다. 하지만 편법으로 `globalShortcut`을 통해 키 입력을 받을 수 있습니다. + +`titleBarStyle` 속성은 OS X 10.10 Yosemite 이후 버전만 지원하며, 다음 3가지 종류의 +값을 사용할 수 있습니다: + +* `default` 또는 미지정: 표준 Mac 회색 불투명 스타일을 사용합니다. +* `hidden`: 타이틀 바를 숨기고 컨텐츠 전체를 윈도우 크기에 맞춥니다. + 타이틀 바는 없어지지만 표준 창 컨트롤 ("신호등 버튼")은 왼쪽 상단에 유지됩니다. +* `hidden-inset`: `hidden` 타이틀 바 속성과 함께 신호등 버튼이 윈도우 모서리로부터 + 약간 더 안쪽으로 들어가도록합니다. + +`webPreferences` 속성은 다음과 같은 속성을 가질 수 있습니다: + +* `nodeIntegration` Boolean - node(node.js) 통합 여부. 기본값은 `true`입니다. +* `preload` String - 스크립트를 지정하면 페이지 내의 다른 스크립트가 작동하기 전에 + 로드됩니다. 여기서 지정한 스크립트는 node 통합 활성화 여부에 상관없이 언제나 모든 + node API에 접근할 수 있습니다. 이 속성의 스크립트 경로는 절대 경로로 지정해야 + 합니다. node 통합이 비활성화되어있을 경우, preload 스크립트는 node의 global + 심볼들을 다시 global 스코프로 다시 포함 시킬 수 있습니다. + [여기](process.md#event-loaded)의 예제를 참고하세요. +* `partition` String - 페이지에서 사용할 세션을 지정합니다. 만약 `partition`이 + `persist:`로 시작하면 페이지는 지속성 세션을 사용하며 다른 모든 앱 내의 + 페이지에서 같은 `partition`을 사용할 수 있습니다. 만약 `persist:` 접두어로 + 시작하지 않으면 페이지는 인-메모리 세션을 사용합니다. 여러 페이지에서 같은 + `partition`을 지정하면 같은 세션을 공유할 수 있습니다. `partition`을 지정하지 + 않으면 어플리케이션의 기본 세션이 사용됩니다. +* `zoomFactor` Number - 페이지의 기본 줌 값을 지정합니다. 예를 들어 `300%`를 + 표현하려면 `3.0`으로 지정합니다. 기본값은 `1.0`입니다. +* `javascript` Boolean - 자바스크립트를 활성화합니다. 기본값은 `false`입니다. +* `webSecurity` Boolean - `false`로 지정하면 same-origin 정책을 비활성화합니다. + (이 속성은 보통 사람들에 의해 웹 사이트를 테스트할 때 사용합니다) 그리고 + `allowDisplayingInsecureContent`와 `allowRunningInsecureContent` 두 속성을 + 사용자가 `true`로 지정되지 않은 경우 `true`로 지정합니다. 기본값은 + `true`입니다. +* `allowDisplayingInsecureContent` Boolean - https 페이지에서 http URL에서 + 로드한 이미지 같은 리소스를 표시할 수 있도록 허용합니다. 기본값은 `false`입니다. +* `allowRunningInsecureContent` Boolean - https 페이지에서 http URL에서 로드한 + JavaScript와 CSS 또는 플러그인을 실행시킬 수 있도록 허용합니다. 기본값은 + `false`입니다. +* `images` Boolean - 이미지 지원을 활성화합니다. 기본값은 `true`입니다. +* `textAreasAreResizable` Boolean - HTML TextArea 요소의 크기를 재조정을 + 허용합니다. 기본값은 `true`입니다. +* `webgl` Boolean - WebGL 지원을 활성화합니다. 기본값은 `true`입니다. +* `webaudio` Boolean - WebAudio 지원을 활성화합니다. 기본값은 `true`입니다. +* `plugins` Boolean - 플러그인 활성화 여부를 지정합니다. 기본값은 `false`입니다. +* `experimentalFeatures` Boolean - Chrome의 실험적인 기능을 활성화합니다. + 기본값은 `false`입니다. +* `experimentalCanvasFeatures` Boolean - Chrome의 실험적인 캔버스(canvas) 기능을 + 활성화합니다. 기본값은 `false`입니다. +* `directWrite` Boolean - Windows에서 폰트 랜더링을 위해 DirectWrite를 + 사용하는지를 지정합니다. 기본값은 `true`입니다. +* `blinkFeatures` String - `CSSVariables,KeyboardEventKey`같은 `,`로 구분된 + 기능 문자열들의 리스트입니다. 지원하는 전체 기능 문자열들은 + [setFeatureEnabledFromString][blink-feature-string] 함수에서 찾을 수 있습니다. ## Events @@ -747,3 +752,5 @@ Linux 플랫폼에선 Unity 데스크톱 환경만 지원합니다. 그리고 * `ignore` Boolean 윈도우에서 일어나는 모든 마우스 이벤트를 무시합니다. + +[blink-feature-string]: https://code.google.com/p/chromium/codesearch#chromium/src/out/Debug/gen/blink/platform/RuntimeEnabledFeatures.cpp&sq=package:chromium&type=cs&l=527 diff --git a/docs-translations/ko-KR/api/chrome-command-line-switches.md b/docs-translations/ko-KR/api/chrome-command-line-switches.md index f13f37920aea..defa1e04841b 100644 --- a/docs-translations/ko-KR/api/chrome-command-line-switches.md +++ b/docs-translations/ko-KR/api/chrome-command-line-switches.md @@ -119,6 +119,14 @@ TLS fallback에서 사용할 SSL/TLS 최소 버전을 지정합니다. ("tls1", SSL 암호화를 비활성화할 대상 목록을 지정합니다. (`,`로 구분) +## --disable-renderer-backgrounding + +Chromium이 랜더러 프로세스의 보이지 않는 페이지의 우선순위를 낮추는 것을 방지합니다. + +이 플래그는 전역적이며 모든 랜더러 프로세스에 적용됩니다. 만약 하나의 윈도우창에만 +스로틀링을 비활성화하고 싶다면 [조용한 오디오를 재생하는][play-silent-audio] 핵을 사용할 +수 있습니다. + ## --enable-logging Chromium의 로그를 콘솔에 출력합니다. @@ -149,3 +157,4 @@ Chromium의 로그를 콘솔에 출력합니다. [app]: app.md [append-switch]: app.md#appcommandlineappendswitchswitch-value [ready]: app.md#event-ready +[play-silent-audio]: https://github.com/atom/atom/pull/9485/files diff --git a/docs-translations/ko-KR/api/global-shortcut.md b/docs-translations/ko-KR/api/global-shortcut.md index 9617d463e87e..658f723692a6 100644 --- a/docs-translations/ko-KR/api/global-shortcut.md +++ b/docs-translations/ko-KR/api/global-shortcut.md @@ -1,6 +1,6 @@ -# global-shortcut +# globalSortcut -`global-shortcut` 모듈은 운영체제의 전역 키보드 단축키를 등록/해제 하는 방법을 +`globalShortcut` 모듈은 운영체제의 전역 키보드 단축키를 등록/해제 하는 방법을 제공합니다. 이 모듈을 사용하여 사용자가 다양한 작업을 편하게 할 수 있도록 단축키를 정의 할 수 있습니다. @@ -38,26 +38,29 @@ app.on('will-quit', function() { ## Methods -`global-shortcut` 모듈은 다음과 같은 메서드를 가지고 있습니다: +`globalShortcut` 모듈은 다음과 같은 메서드를 가지고 있습니다: ### `globalShortcut.register(accelerator, callback)` * `accelerator` [Accelerator](accelerator.md) * `callback` Function -`accelerator`로 표현된 전역 단축키를 등록합니다. 유저로부터 등록된 단축키가 눌렸을 -경우 `callback` 함수가 호출됩니다. `accelerator` 단축키가 등록되었을 경우 -`true`를 반환합니다. 그 외엔 `false`를 반환합니다. 예를 들어 지정한 -`accelerator`가 이미 다른 호출자 또는 네이티브 어플리케이션에서 등록된 상태를 -생각할 수 있습니다. +`accelerator`의 전역 단축키를 등록합니다. 유저로부터 등록된 단축키가 눌렸을 경우 +`callback` 함수가 호출됩니다. +accelerator가 이미 다른 어플리케이션에서 사용 중일 경우, 이 작업은 조용히 실패합니다. +이러한 동작은 어플리케이션이 전역 키보드 단축키를 가지고 충돌이 일어나지 않도록 하기 +위해 운영체제에 의해 예정된 동작입니다. ### `globalShortcut.isRegistered(accelerator)` * `accelerator` [Accelerator](accelerator.md) -지정된 `accelerator` 단축키가 등록되었는지 여부를 확인합니다. 반환값은 boolean값 -입니다. +지정된 `accelerator` 단축키가 등록되었는지 여부를 확인합니다. + +Accelerator가 이미 다른 어플리케이션에서 사용 중일 경우, 여전히 `false`를 반환합니다. +이러한 동작은 어플리케이션이 전역 키보드 단축키를 가지고 충돌이 일어나지 않도록 하기 +위해 운영체제에 의해 예정된 동작입니다. ### `globalShortcut.unregister(accelerator)` diff --git a/docs-translations/ko-KR/api/screen.md b/docs-translations/ko-KR/api/screen.md index dfd85fb446e1..6cc6535235b6 100644 --- a/docs-translations/ko-KR/api/screen.md +++ b/docs-translations/ko-KR/api/screen.md @@ -54,6 +54,24 @@ app.on('ready', function() { }); ``` +## `Display` 객체 + +`Display` 객체는 시스템에 연결된 물리적인 디스플레이를 표현합니다. 헤드레스(headless) +시스템에선 가짜 `Display` 객체가 보여지거나 리모트(remote), 가상 디스플레이에 +해당하게 됩니다. + +* `display` object + * `id` Integer - 디스플레이에 관련된 유일 식별자. + * `rotation` Integer - 값은 0, 1, 2, 3이 될 수 있고, 각 값은 시계 방향을 기준으로 + 0, 90, 180, 270도의 화면 회전 상태로 표현됩니다. + * `scaleFactor` Number - 기기의 픽셀 스케일 크기. + * `touchSupport` String - 터치 스크린의 여부, `available`, `unavailable`, + `unknown` 값으로 반환됩니다. + * `bounds` Object + * `size` Object + * `workArea` Object + * `workAreaSize` Object + ## Events `screen` 모듈은 다음과 같은 이벤트를 가지고 있습니다: diff --git a/docs-translations/ko-KR/faq/electron-faq.md b/docs-translations/ko-KR/faq/electron-faq.md new file mode 100644 index 000000000000..54ecf64e435c --- /dev/null +++ b/docs-translations/ko-KR/faq/electron-faq.md @@ -0,0 +1,81 @@ +# Electron FAQ + +## 언제 Electron이 최신 버전의 Chrome으로 업그레이드 되나요? + +Electron의 Chrome 버전은 보통 새로운 Chrome 안정 버전이 릴리즈 된 이후 1주 내지 2주 +내로 업데이트됩니다. + +또한 우리는 크롬의 안정된 채널만을 이용합니다, 만약 중요한 수정이 베타 또는 개발 채널인 +경우, 우리는 해당 버전 대신 이전 버전을 다시 사용합니다. + +## Electron은 언제 최신 버전의 Node.js로 업그레이드 하나요? + +새로운 버전의 Node.js가 릴리즈 되면, 우리는 보통 Electron을 업그레이드 하기 전에 한 +달 정도 대기합니다. 이렇게 하면 새로운 Node.js 버전을 업데이트 함으로써 발생하는 +버그들을 피할 수 있습니다. 이러한 상황은 자주 발생합니다. + +Node.js의 새로운 기능은 보통 V8 업그레이드에서 가져옵니다. Electron은 Chrome +브라우저에 탑재된 V8을 사용하고 있습니다. 눈부신 새로운 Node.js 버전의 자바스크립트 +기능은 보통 이미 Electron에 있습니다. + +## 제작한 어플리케이션의 윈도우/트레이가 몇 분 후에나 나타납니다. + +이러한 문제가 발생하는 이유는 보통 윈도우/트레이를 담은 변수에 가비지 컬렉션이 작동해서 +그럴 가능성이 높습니다. + +이러한 문제를 맞닥뜨린 경우 다음 문서를 읽어보는 것이 좋습니다: + +* [메모리 관리][memory-management] +* [변수 스코프][variable-scope] + +만약 빠르게 고치고 싶다면, 다음과 같이 변수를 전역 변수로 만드는 방법이 있습니다: + +```javascript +app.on('ready', function() { + var tray = new Tray('/path/to/icon.png'); +}) +``` + +를 이렇게: + +```javascript +var tray = null; +app.on('ready', function() { + tray = new Tray('/path/to/icon.png'); +}) +``` + +## Electron에서 jQuery/RequireJS/Meteor/AngularJS를 사용할 수 없습니다. + +Node.js가 Electron에 합쳐졌기 때문에, DOM에 `module`, `exports`, `require` 같은 +몇 가지 심볼들이 추가됬습니다. 따라서 같은 이름의 심볼을 사용하는 몇몇 라이브러리들과 +충돌이 발생할 수 있습니다. + +이러한 문제를 해결하려면, Electron에서 node 포함을 비활성화시켜야 합니다: + +```javascript +// 메인 프로세스에서. +var mainWindow = new BrowserWindow({ + webPreferences: { + nodeIntegration: false + } +}); +``` + +하지만 Node.js의 기능과 Electron API를 유지하고 싶다면 페이지에 다른 라이브러리를 +추가하기 전에 심볼들의 이름을 변경해야 합니다: + +```html + + + + +``` + +[memory-management]: https://developer.mozilla.org/ko/docs/Web/JavaScript/Memory_Management +[variable-scope]: https://msdn.microsoft.com/library/bzt2dkta(v=vs.94).aspx diff --git a/docs-translations/ko-KR/tutorial/application-distribution.md b/docs-translations/ko-KR/tutorial/application-distribution.md index 73839f248b5b..34eb8cee71f7 100644 --- a/docs-translations/ko-KR/tutorial/application-distribution.md +++ b/docs-translations/ko-KR/tutorial/application-distribution.md @@ -106,14 +106,6 @@ MyApp.app/Contents 아이콘은 [.desktop](https://developer.gnome.org/integration-guide/stable/desktop-files.html.en) 파일을 사용하여 지정할 수 있습니다. -### 역주-자동화 - -어플리케이션 배포시 Electron의 리소스를 일일이 수정하는 것은 매우 반복적이고 복잡합니다. -하지만 이 작업을 자동화 시킬 수 있는 몇가지 방법이 있습니다: - -* [electron-builder](https://github.com/loopline-systems/electron-builder) -* [electron-packager](https://github.com/maxogden/electron-packager) - ## Electron 소스코드를 다시 빌드하여 리소스 수정하기 또한 Electron 소스코드를 다시 빌드할 때 어플리케이션 이름을 변경할 수 있습니다. @@ -146,3 +138,11 @@ Electron의 소스코드를 수정하고 다시 빌드하는 작업은 상당히 이 툴을 사용하면 자동으로 `.gyp`파일을 수정하고 다시 빌드합니다. 그리고 어플리케이션의 네이티브 Node 모듈 또한 새로운 실행파일 이름으로 일치시킵니다. + +## 패키징 툴 + +어플리케이션을 일일이 수동으로 패키지로 만드는 대신, 서드 파티 패키징 툴을 사용하며 +이러한 작업을 자동화 시킬 수 있습니다: + +* [electron-packager](https://github.com/maxogden/electron-packager) +* [electron-builder](https://github.com/loopline-systems/electron-builder) diff --git a/docs-translations/ko-KR/tutorial/debugging-main-process.md b/docs-translations/ko-KR/tutorial/debugging-main-process.md index ee7e8432d420..bea8ce6ccc0c 100644 --- a/docs-translations/ko-KR/tutorial/debugging-main-process.md +++ b/docs-translations/ko-KR/tutorial/debugging-main-process.md @@ -23,13 +23,30 @@ __참고:__ Electron은 현재 node-inspector 유틸리티와 호환성 문제 node-inspector 콘솔 내에서 메인 프로세스의 `process` 객체를 탐색할 경우 크래시가 발생할 수 있습니다. -### 1. [node-inspector][node-inspector] 서버 시작 +### 1. [node-gyp 필수 도구][node-gyp-required-tools]를 설치했는지 확인 + +### 2. [node-inspector][node-inspector] 설치 ```bash -$ node-inspector +$ npm install node-inspector ``` -### 2. Electron용 디버그 모드 활성화 +### 3. 패치된 버전의 `node-pre-gyp` 설치 + +```bash +$ npm install git+https://git@github.com/enlight/node-pre-gyp.git#detect-electron-runtime-in-find +``` + +### 4. Electron용 `node-inspector` `v8` 모듈을 재 컴파일 (target을 사용하는 Electron의 버전에 맞춰 변경) + +```bash +$ node_modules/.bin/node-pre-gyp --target=0.36.2 --runtime=electron --fallback-to-build --directory node_modules/v8-debug/ --dist-url=https://atom.io/download/atom-shell reinstall +$ node_modules/.bin/node-pre-gyp --target=0.36.2 --runtime=electron --fallback-to-build --directory node_modules/v8-profiler/ --dist-url=https://atom.io/download/atom-shell reinstall +``` + +또한 [네이티브 모듈을 사용하는 방법](how-to-install-native-modules) 문서도 참고해보세요. + +### 5. Electron 디버그 모드 활성화 다음과 같이 debung 플래그로 Electron을 실행할 수 있습니다: @@ -43,9 +60,18 @@ $ electron --debug=5858 your/app $ electron --debug-brk=5858 your/app ``` -### 3. 디버그 UI 로드 +### 5. Electron을 사용하는 [node-inspector][node-inspector] 시작 + +```bash +$ ELECTRON_RUN_AS_NODE=true path/to/electron.exe node_modules/node-inspector/bin/inspector.js +``` + +### 6. 디버거 UI 로드 Chrome 브라우저에서 http://127.0.0.1:8080/debug?ws=127.0.0.1:8080&port=5858 주소에 -접속합니다. (기본포트 또는 지정한 포트로 접속) +접속합니다. (기본 포트 또는 지정한 포트로 접속) 엔트리의 라인이 debug-brk로 시작하는 +경우 일시정지 버튼을 클릭해야 할 수도 있습니다. [node-inspector]: https://github.com/node-inspector/node-inspector +[node-gyp-required-tools]: https://github.com/nodejs/node-gyp#installation +[how-to-install-native-modules]: using-native-node-modules.md#네이티브-모듈을-설치하는-방법 From 4f1be903c47ad1eca42a9ca6f666bfbe8911932c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=A4=A7=E5=92=8C=E5=B1=8B=20=E8=B2=B4=E4=BB=81?= Date: Mon, 11 Jan 2016 13:19:14 +0900 Subject: [PATCH 23/95] Fix a document --- docs-translations/jp/README.md | 24 +++++++++++++++++++ .../jp/tutorial/devtools-extension.md | 2 +- .../mac-app-store-submission-guide.md | 2 +- .../jp/tutorial/online-offline-events.md | 2 -- 4 files changed, 26 insertions(+), 4 deletions(-) diff --git a/docs-translations/jp/README.md b/docs-translations/jp/README.md index 32b14b0fdd2b..e4ef797001a4 100644 --- a/docs-translations/jp/README.md +++ b/docs-translations/jp/README.md @@ -1,3 +1,27 @@ +## FAQ + +頻繁に聞かれる質問がありますので、issueを作成する前にこれをチェックしてください。 + +* [Electron FAQ](faq/electron-faq.md) + + +## ガイド + +* [サポートするプラットフォーム](tutorial/supported-platforms.md) +* [アプリケーションの配布](tutorial/application-distribution.md) +* [Mac App Store 提出ガイド](tutorial/mac-app-store-submission-guide.md) +* [アプリケーションのパッケージ化](tutorial/application-packaging.md) +* [ネイティブのNodeモジュールを使用する](tutorial/using-native-node-modules.md) +* [メインプロセスのデバッグ](tutorial/debugging-main-process.md) +* [Selenium と WebDriverを使用する](tutorial/using-selenium-and-webdriver.md) +* [DevTools エクステンション](tutorial/devtools-extension.md) +* [Pepper Flashプラグインを使用する](tutorial/using-pepper-flash-plugin.md) +* [Widevine CDMプラグインを使用する](tutorial/using-widevine-cdm-plugin.md) + + + # チュートリアル * [クイックスタート](tutorial/quick-start.md) +* [デスクトップ環境の統合](tutorial/desktop-environment-integration.md) +* [オンライン/オフライン イベントの検知](tutorial/online-offline-events.md) diff --git a/docs-translations/jp/tutorial/devtools-extension.md b/docs-translations/jp/tutorial/devtools-extension.md index a0847091ab07..85eff391a43b 100644 --- a/docs-translations/jp/tutorial/devtools-extension.md +++ b/docs-translations/jp/tutorial/devtools-extension.md @@ -1,4 +1,4 @@ -# DevTools 拡張 +# DevTools エクステンション 簡単にデバッグをするために、Electronは[Chrome DevTools Extension][devtools-extension]に基本的な対応しています。 diff --git a/docs-translations/jp/tutorial/mac-app-store-submission-guide.md b/docs-translations/jp/tutorial/mac-app-store-submission-guide.md index a04eff1d9b2b..b2cf9d26d30d 100644 --- a/docs-translations/jp/tutorial/mac-app-store-submission-guide.md +++ b/docs-translations/jp/tutorial/mac-app-store-submission-guide.md @@ -1,4 +1,4 @@ -# Mac App Store Submission Guide +# Mac App Store 提出ガイド v0.34.0から、ElectronはMac App Store (MAS)にパッケージ化したアプリを登録することができます。このガイドでは、MASビルド用の制限とアプリを登録する方法についての情報を提供します。 diff --git a/docs-translations/jp/tutorial/online-offline-events.md b/docs-translations/jp/tutorial/online-offline-events.md index d1fa8858232a..bf04f72d30dc 100644 --- a/docs-translations/jp/tutorial/online-offline-events.md +++ b/docs-translations/jp/tutorial/online-offline-events.md @@ -1,7 +1,5 @@ # オンライン/オフライン イベントの検知 - - オンラインとオフラインイベントの検知は、標準のHTML 5 APIを使用して、状況表示を実装できます。次の例を見てみましょう。 _main.js_ From 1de9cfd4ebde10e79efceb1f9abc4f2426134437 Mon Sep 17 00:00:00 2001 From: Cheng Zhao Date: Mon, 11 Jan 2016 12:59:02 +0800 Subject: [PATCH 24/95] Backport https://codereview.chromium.org/1500713003 --- script/lib/config.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/script/lib/config.py b/script/lib/config.py index 932562fdcbee..7570f3dc1a40 100644 --- a/script/lib/config.py +++ b/script/lib/config.py @@ -8,7 +8,7 @@ import sys BASE_URL = os.getenv('LIBCHROMIUMCONTENT_MIRROR') or \ 'https://s3.amazonaws.com/github-janky-artifacts/libchromiumcontent' -LIBCHROMIUMCONTENT_COMMIT = '0fbded6cf3d9244389db05f0c022e474a06ad32a' +LIBCHROMIUMCONTENT_COMMIT = '45f296cf0d169f8afec75e211f6f66c7a887e113' PLATFORM = { 'cygwin': 'win32', From 12f5e5072d878f8e6144b461851efb27ffdafb57 Mon Sep 17 00:00:00 2001 From: Christopher Dieringer Date: Sun, 10 Jan 2016 21:02:07 -0800 Subject: [PATCH 25/95] Specify enumerable property accessibility --- docs/api/remote.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/api/remote.md b/docs/api/remote.md index 2a5881d31ca6..7bdbe0362f60 100644 --- a/docs/api/remote.md +++ b/docs/api/remote.md @@ -36,6 +36,8 @@ process. Instead, it created a `BrowserWindow` object in the main process and returned the corresponding remote object in the renderer process, namely the `win` object. +Please note that only [enumerable properties](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Enumerability_and_ownership_of_properties) are accessible via remote. + ## Lifetime of Remote Objects Electron makes sure that as long as the remote object in the renderer process From 1944472c2fdc059b491f96c93e9740ce545afe85 Mon Sep 17 00:00:00 2001 From: Cheng Zhao Date: Mon, 11 Jan 2016 13:43:24 +0800 Subject: [PATCH 26/95] docs: Make win.getNativeWindowHandle more clear --- atom/browser/api/atom_api_window.cc | 5 ++--- docs/api/browser-window.md | 20 ++++++++++++-------- 2 files changed, 14 insertions(+), 11 deletions(-) diff --git a/atom/browser/api/atom_api_window.cc b/atom/browser/api/atom_api_window.cc index 494d3fedd76b..f32b6d19ccaf 100644 --- a/atom/browser/api/atom_api_window.cc +++ b/atom/browser/api/atom_api_window.cc @@ -594,9 +594,8 @@ void Window::SetAspectRatio(double aspect_ratio, mate::Arguments* args) { v8::Local Window::GetNativeWindowHandle() { gfx::AcceleratedWidget handle = window_->GetAcceleratedWidget(); - return ToBuffer(isolate(), - static_cast(&handle), - sizeof(gfx::AcceleratedWidget)); + return ToBuffer( + isolate(), static_cast(&handle), sizeof(gfx::AcceleratedWidget)); } void Window::SetVisibleOnAllWorkspaces(bool visible) { diff --git a/docs/api/browser-window.md b/docs/api/browser-window.md index bb86e8ef6773..577519951e2d 100644 --- a/docs/api/browser-window.md +++ b/docs/api/browser-window.md @@ -63,9 +63,10 @@ It creates a new `BrowserWindow` with native properties as set by the `options`. * `frame` Boolean - Specify `false` to create a [Frameless Window](frameless-window.md). Default is `true`. * `acceptFirstMouse` Boolean - Whether the web view accepts a single - mouse-down event that simultaneously activates the window. Default is `false`. - * `disableAutoHideCursor` Boolean - Whether to hide cursor when typing. Default - is `false`. + mouse-down event that simultaneously activates the window. Default is + `false`. + * `disableAutoHideCursor` Boolean - Whether to hide cursor when typing. + Default is `false`. * `autoHideMenuBar` Boolean - Auto hide the menu bar unless the `Alt` key is pressed. Default is `false`. * `enableLargerThanScreen` Boolean - Enable the window to be resized larger @@ -157,7 +158,8 @@ The `webPreferences` option is an object that can have following properties: The `BrowserWindow` object emits the following events: -**Note:** Some events are only available on specific operating systems and are labeled as such. +**Note:** Some events are only available on specific operating systems and are +labeled as such. ### Event: 'page-title-updated' @@ -341,7 +343,8 @@ The unique ID of this window. Objects created with `new BrowserWindow` have the following instance methods: -**Note:** Some methods are only available on specific operating systems and are labeled as such. +**Note:** Some methods are only available on specific operating systems and are +labeled as such. ### `win.destroy()` @@ -573,9 +576,10 @@ Returns whether the window is in kiosk mode. ### `win.getNativeWindowHandle()` -Returns the platform-specific handle of the window in a buffer. -Cast it to the appropriate type, such as HWND for Windows, NSView* for OS X or unsigned long for Linux. -Used for OS's Native API's for windows. +Returns the platform-specific handle of the window as `Buffer`. + +The native type of the handle is `HWND` on Windows, `NSView*` on OS X, and +`Window` (`unsigned long`) on Linux. ### `win.hookWindowMessage(message, callback)` _Windows_ From 33b7b774c11e71ec7114fd835136419fbfbaab37 Mon Sep 17 00:00:00 2001 From: Cheng Zhao Date: Mon, 11 Jan 2016 14:41:38 +0800 Subject: [PATCH 27/95] docs: Notification on Windows can use http:// icon now --- docs/tutorial/desktop-environment-integration.md | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) diff --git a/docs/tutorial/desktop-environment-integration.md b/docs/tutorial/desktop-environment-integration.md index c5b5cd680ac1..906f77ffa6b8 100644 --- a/docs/tutorial/desktop-environment-integration.md +++ b/docs/tutorial/desktop-environment-integration.md @@ -37,19 +37,7 @@ however, that it does not need to be pinned to the Start screen. * On Windows 7 and below, notifications are not supported. You can however send "balloon notifications" using the [Tray API](tray-balloon). -To use an image in your notification, pass a local image file (preferably `png`) -in the `icon` property of your notification's options. The notification will -still display if you submit an incorrect or `http/https`-based URL, but the -image will not be displayed. - -```javascript -new Notification('Title', { - body: 'Notification with icon', - icon: 'file:///C:/Users/feriese/Desktop/icon.png' -}); -``` - -Furthermore, keep in mind that the maximum length for the body is 250 characters, +Furthermore, the maximum length for the notification body is 250 characters, with the Windows team recommending that notifications should be kept to 200 characters. From 8557cd223cee2d4e61d33252ee0ec5cd900c1eeb Mon Sep 17 00:00:00 2001 From: Robo Date: Mon, 11 Jan 2016 12:24:01 +0530 Subject: [PATCH 28/95] maintain api compatibility --- atom/browser/api/atom_api_session.cc | 21 +++++++++++++++++---- docs/api/session.md | 3 +++ 2 files changed, 20 insertions(+), 4 deletions(-) diff --git a/atom/browser/api/atom_api_session.cc b/atom/browser/api/atom_api_session.cc index 0b2f4f9be979..379d16ecf857 100644 --- a/atom/browser/api/atom_api_session.cc +++ b/atom/browser/api/atom_api_session.cc @@ -115,14 +115,27 @@ struct Converter { v8::Local val, net::ProxyConfig* out) { mate::Dictionary options; - if (!ConvertFromV8(isolate, val, &options)) - return false; + if (!ConvertFromV8(isolate, val, &options)) { + // Fallback to previous api (https://git.io/vuhjj). + std::string proxy; + if (!ConvertFromV8(isolate, val, &proxy)) + return false; + auto pac_url = GURL(proxy); + if (pac_url.is_valid()) { + out->set_pac_url(pac_url); + } else { + out->proxy_rules().ParseFromString(proxy); + } + return true; + } + GURL pac_url; std::string rules; - if (options.Get("pacScript", &pac_url)) + if (options.Get("pacScript", &pac_url)) { out->set_pac_url(pac_url); - else if (options.Get("proxyRules", &rules)) + } else if (options.Get("proxyRules", &rules)) { out->proxy_rules().ParseFromString(rules); + } return true; } }; diff --git a/docs/api/session.md b/docs/api/session.md index 67dd537d44ee..41d27773f9a1 100644 --- a/docs/api/session.md +++ b/docs/api/session.md @@ -186,6 +186,9 @@ Clears the data of web storages. * `proxyRules` String - Rules indicating which proxies to use. * `callback` Function - Called when operation is done. +When `pacScript` and `proxyRules` are provided together, the `proxyRules` +option is ignored and `pacScript` configuration is applied. + ``` proxyRules = scheme-proxies[";"] scheme-proxies = ["="] From 018ae5189bb3b5c9bfb90f06a0738a5265eee031 Mon Sep 17 00:00:00 2001 From: Prince J Wesley Date: Mon, 11 Jan 2016 12:48:35 +0530 Subject: [PATCH 29/95] Return null for no focused window when calling BrowserWindow.getFocusedWindow() --- atom/browser/api/lib/browser-window.coffee | 1 + docs/api/browser-window.md | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/atom/browser/api/lib/browser-window.coffee b/atom/browser/api/lib/browser-window.coffee index 92a230ba45af..aa3bd022722c 100644 --- a/atom/browser/api/lib/browser-window.coffee +++ b/atom/browser/api/lib/browser-window.coffee @@ -66,6 +66,7 @@ BrowserWindow::_init = -> BrowserWindow.getFocusedWindow = -> windows = BrowserWindow.getAllWindows() return window for window in windows when window.isFocused() + null BrowserWindow.fromWebContents = (webContents) -> windows = BrowserWindow.getAllWindows() diff --git a/docs/api/browser-window.md b/docs/api/browser-window.md index 8fb64b561224..c4df2887f6ce 100644 --- a/docs/api/browser-window.md +++ b/docs/api/browser-window.md @@ -287,7 +287,7 @@ Returns an array of all opened browser windows. ### `BrowserWindow.getFocusedWindow()` -Returns the window that is focused in this application. +Returns the window that is focused in this application, otherwise returns `null`. ### `BrowserWindow.fromWebContents(webContents)` From 440c588a3371d110237536e3e21607e561e01fe1 Mon Sep 17 00:00:00 2001 From: Krzysztof Date: Mon, 11 Jan 2016 12:23:53 +0100 Subject: [PATCH 30/95] Pass --touch-devices to chromium contents under X11 --- atom/browser/atom_browser_main_parts.cc | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/atom/browser/atom_browser_main_parts.cc b/atom/browser/atom_browser_main_parts.cc index eadd52ac44c8..a046f34287ee 100644 --- a/atom/browser/atom_browser_main_parts.cc +++ b/atom/browser/atom_browser_main_parts.cc @@ -21,6 +21,7 @@ #if defined(USE_X11) #include "chrome/browser/ui/libgtk2ui/gtk2_util.h" +#include "ui/events/devices/x11/touch_factory_x11.h" #endif namespace atom { @@ -116,6 +117,10 @@ void AtomBrowserMainParts::PreMainMessageLoopRun() { node_bindings_->PrepareMessageLoop(); node_bindings_->RunMessageLoop(); +#if defined(USE_X11) + ui::TouchFactory::SetTouchDeviceListFromCommandLine(); +#endif + // Start idle gc. gc_timer_.Start( FROM_HERE, base::TimeDelta::FromMinutes(1), From e3d3cd1198380549259d0fc11e323d09ee257437 Mon Sep 17 00:00:00 2001 From: Cheng Zhao Date: Mon, 11 Jan 2016 20:52:32 +0800 Subject: [PATCH 31/95] docs: Update link of VS Community Also fix the version of VS requried. Close #3962. --- docs/development/build-instructions-windows.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/development/build-instructions-windows.md b/docs/development/build-instructions-windows.md index 2342131a78d3..06ce696a9e3c 100644 --- a/docs/development/build-instructions-windows.md +++ b/docs/development/build-instructions-windows.md @@ -5,8 +5,8 @@ Follow the guidelines below for building Electron on Windows. ## Prerequisites * Windows 7 / Server 2008 R2 or higher -* Visual Studio 2013 with Update 5 - [download VS 2013 Community Edition for - free](https://www.visualstudio.com/downloads/download-visual-studio-vs). +* Visual Studio 2013 with Update 4 - [download VS 2013 Community Edition for + free](https://www.visualstudio.com/news/vs2013-community-vs). * [Python 2.7](http://www.python.org/download/releases/2.7/) * [Node.js](http://nodejs.org/download/) * [Git](http://git-scm.com) From 26bd97d6cfd03cda3d12da0e144c21ee38beec35 Mon Sep 17 00:00:00 2001 From: Cheng Zhao Date: Mon, 11 Jan 2016 21:12:07 +0800 Subject: [PATCH 32/95] Fix style issues of #4029 --- atom/browser/api/atom_api_dialog.cc | 2 +- atom/browser/ui/message_box_gtk.cc | 16 +++++----------- atom/browser/ui/message_box_mac.mm | 16 ++++++++-------- atom/browser/ui/message_box_win.cc | 18 ++++++++++-------- 4 files changed, 24 insertions(+), 28 deletions(-) diff --git a/atom/browser/api/atom_api_dialog.cc b/atom/browser/api/atom_api_dialog.cc index 3ff53352cba1..0a544c56468c 100644 --- a/atom/browser/api/atom_api_dialog.cc +++ b/atom/browser/api/atom_api_dialog.cc @@ -57,7 +57,7 @@ void ShowMessageBox(int type, &callback)) { atom::ShowMessageBox(window, (atom::MessageBoxType)type, buttons, default_id, cancel_id, options, title, - message, detail, icon, callback); + message, detail, icon, callback); } else { int chosen = atom::ShowMessageBox(window, (atom::MessageBoxType)type, buttons, default_id, cancel_id, diff --git a/atom/browser/ui/message_box_gtk.cc b/atom/browser/ui/message_box_gtk.cc index fe1068effd7c..9615e958b275 100644 --- a/atom/browser/ui/message_box_gtk.cc +++ b/atom/browser/ui/message_box_gtk.cc @@ -61,16 +61,10 @@ class GtkMessageBox { // Add buttons. for (size_t i = 0; i < buttons.size(); ++i) { - if (i == (size_t)default_id) { - GtkWidget* button = gtk_dialog_add_button(GTK_DIALOG(dialog_), - TranslateToStock(i, buttons[i]), - i); + GtkWidget* button = gtk_dialog_add_button( + GTK_DIALOG(dialog_), TranslateToStock(i, buttons[i]), i); + if (static_cast(i) == default_id) gtk_widget_grab_focus(button); - } else { - gtk_dialog_add_button(GTK_DIALOG(dialog_), - TranslateToStock(i, buttons[i]), - i); - } } // Parent window. @@ -177,7 +171,7 @@ int ShowMessageBox(NativeWindow* parent, const std::string& detail, const gfx::ImageSkia& icon) { return GtkMessageBox(parent, type, buttons, default_id, cancel_id, - title, message, detail, icon).RunSynchronous(); + title, message, detail, icon).RunSynchronous(); } void ShowMessageBox(NativeWindow* parent, @@ -192,7 +186,7 @@ void ShowMessageBox(NativeWindow* parent, const gfx::ImageSkia& icon, const MessageBoxCallback& callback) { (new GtkMessageBox(parent, type, buttons, default_id, cancel_id, - title, message, detail, icon))->RunAsynchronous(callback); + title, message, detail, icon))->RunAsynchronous(callback); } void ShowErrorBox(const base::string16& title, const base::string16& content) { diff --git a/atom/browser/ui/message_box_mac.mm b/atom/browser/ui/message_box_mac.mm index 3acc46ec82f1..f9e9718ebf55 100644 --- a/atom/browser/ui/message_box_mac.mm +++ b/atom/browser/ui/message_box_mac.mm @@ -79,17 +79,17 @@ NSAlert* CreateNSAlert(NativeWindow* parent_window, // An empty title causes crash on OS X. if (buttons[i].empty()) title = @"(empty)"; - NSButton* button = [alert addButtonWithTitle:title]; [button setTag:i]; + } - if (i == (size_t)default_id) { - // Focus the button at default_id if the user opted to do so. - // The first button added gets set as the default selected. - // So remove that default, and make the requested button the default. - [[[alert buttons] objectAtIndex:0] setKeyEquivalent:@""]; - [button setKeyEquivalent:@"\r"]; - } + NSArray* ns_buttons = [alert buttons]; + if (default_id >= 0 && default_id < static_cast([ns_buttons count])) { + // Focus the button at default_id if the user opted to do so. + // The first button added gets set as the default selected. + // So remove that default, and make the requested button the default. + [[ns_buttons objectAtIndex:0] setKeyEquivalent:@""]; + [[ns_buttons objectAtIndex:default_id] setKeyEquivalent:@"\r"]; } return alert; diff --git a/atom/browser/ui/message_box_win.cc b/atom/browser/ui/message_box_win.cc index 253733de59df..2847ae21a164 100644 --- a/atom/browser/ui/message_box_win.cc +++ b/atom/browser/ui/message_box_win.cc @@ -84,11 +84,13 @@ int ShowMessageBoxUTF16(HWND parent, TDF_ALLOW_DIALOG_CANCELLATION; // Allow canceling the dialog. TASKDIALOGCONFIG config = { 0 }; - config.cbSize = sizeof(config); - config.hwndParent = parent; - config.hInstance = GetModuleHandle(NULL); - config.dwFlags = flags; - config.nDefaultButton = default_id ? (kIDStart + default_id) : 0; + config.cbSize = sizeof(config); + config.hwndParent = parent; + config.hInstance = GetModuleHandle(NULL); + config.dwFlags = flags; + + if (default_id > 0) + config.nDefaultButton = kIDStart + default_id; // TaskDialogIndirect doesn't allow empty name, if we set empty title it // will show "electron.exe" in title. @@ -230,13 +232,13 @@ void ShowMessageBox(NativeWindow* parent, unretained->message_loop()->PostTask( FROM_HERE, base::Bind(&RunMessageBoxInNewThread, base::Unretained(unretained), - parent, type, buttons, default_id, - cancel_id, options, title, message, detail, icon, callback)); + parent, type, buttons, default_id, cancel_id, options, title, + message, detail, icon, callback)); } void ShowErrorBox(const base::string16& title, const base::string16& content) { ShowMessageBoxUTF16(NULL, MESSAGE_BOX_TYPE_ERROR, {}, -1, 0, 0, L"Error", - title, content, gfx::ImageSkia()); + title, content, gfx::ImageSkia()); } } // namespace atom From 192fa4c86bb9ad179f8efe858618ed3a17c15bbb Mon Sep 17 00:00:00 2001 From: Cheng Zhao Date: Mon, 11 Jan 2016 22:45:34 +0800 Subject: [PATCH 33/95] Cleanup docs and code of setProxy --- atom/browser/api/atom_api_session.cc | 32 +++++++++--------- docs/api/session.md | 49 +++++++++++++--------------- 2 files changed, 38 insertions(+), 43 deletions(-) diff --git a/atom/browser/api/atom_api_session.cc b/atom/browser/api/atom_api_session.cc index 379d16ecf857..f71b28c1cb70 100644 --- a/atom/browser/api/atom_api_session.cc +++ b/atom/browser/api/atom_api_session.cc @@ -114,27 +114,25 @@ struct Converter { static bool FromV8(v8::Isolate* isolate, v8::Local val, net::ProxyConfig* out) { + std::string proxy_rules; + GURL pac_url; mate::Dictionary options; - if (!ConvertFromV8(isolate, val, &options)) { - // Fallback to previous api (https://git.io/vuhjj). - std::string proxy; - if (!ConvertFromV8(isolate, val, &proxy)) - return false; - auto pac_url = GURL(proxy); - if (pac_url.is_valid()) { - out->set_pac_url(pac_url); - } else { - out->proxy_rules().ParseFromString(proxy); - } - return true; + // Fallback to previous API when passed String. + // https://git.io/vuhjj + if (ConvertFromV8(isolate, val, &proxy_rules)) { + pac_url = GURL(proxy_rules); // Assume it is PAC script if it is URL. + } else if (ConvertFromV8(isolate, val, &options)) { + options.Get("pacScript", &pac_url); + options.Get("proxyRules", &proxy_rules); + } else { + return false; } - GURL pac_url; - std::string rules; - if (options.Get("pacScript", &pac_url)) { + // pacScript takes precedence over proxyRules. + if (!pac_url.is_empty() && pac_url.is_valid()) { out->set_pac_url(pac_url); - } else if (options.Get("proxyRules", &rules)) { - out->proxy_rules().ParseFromString(rules); + } else { + out->proxy_rules().ParseFromString(proxy_rules); } return true; } diff --git a/docs/api/session.md b/docs/api/session.md index 41d27773f9a1..a8a55b593f27 100644 --- a/docs/api/session.md +++ b/docs/api/session.md @@ -186,37 +186,34 @@ Clears the data of web storages. * `proxyRules` String - Rules indicating which proxies to use. * `callback` Function - Called when operation is done. +Sets the proxy settings. + When `pacScript` and `proxyRules` are provided together, the `proxyRules` option is ignored and `pacScript` configuration is applied. -``` -proxyRules = scheme-proxies[";"] -scheme-proxies = ["="] -url-scheme = "http" | "https" | "ftp" | "socks" -proxy-uri-list = [","] -proxy-uri = ["://"][":"] +The `proxyRules` has to follow the rules bellow: - For example: - "http=foopy:80;ftp=foopy2" -- use HTTP proxy "foopy:80" for http:// - URLs, and HTTP proxy "foopy2:80" for - ftp:// URLs. - "foopy:80" -- use HTTP proxy "foopy:80" for all URLs. - "foopy:80,bar,direct://" -- use HTTP proxy "foopy:80" for all URLs, - failing over to "bar" if "foopy:80" is - unavailable, and after that using no - proxy. - "socks4://foopy" -- use SOCKS v4 proxy "foopy:1080" for all - URLs. - "http=foopy,socks5://bar.com -- use HTTP proxy "foopy" for http URLs, - and fail over to the SOCKS5 proxy - "bar.com" if "foopy" is unavailable. - "http=foopy,direct:// -- use HTTP proxy "foopy" for http URLs, - and use no proxy if "foopy" is - unavailable. - "http=foopy;socks=foopy2 -- use HTTP proxy "foopy" for http URLs, - and use socks4://foopy2 for all other - URLs. ``` +proxyRules = schemeProxies[";"] +schemeProxies = ["="] +urlScheme = "http" | "https" | "ftp" | "socks" +proxyURIList = [","] +proxyURL = ["://"][":"] +``` + +For example: +* `http=foopy:80;ftp=foopy2` - Use HTTP proxy `foopy:80` for `http://` URLs, and + HTTP proxy `foopy2:80` for `ftp://` URLs. +* `foopy:80` - Use HTTP proxy `foopy:80` for all URLs. +* `foopy:80,bar,direct://` - Use HTTP proxy `foopy:80` for all URLs, failing + over to `bar` if `foopy:80` is unavailable, and after that using no proxy. +* `socks4://foopy` - Use SOCKS v4 proxy `foopy:1080` for all URLs. +* `http=foopy,socks5://bar.com` - Use HTTP proxy `foopy` for http URLs, and fail + over to the SOCKS5 proxy `bar.com` if `foopy` is unavailable. +* `http=foopy,direct://` - Use HTTP proxy `foopy` for http URLs, and use no + proxy if `foopy` is unavailable. +* `http=foopy;socks=foopy2` - Use HTTP proxy `foopy` for http URLs, and use + `socks4://foopy2` for all other URLs. ### `ses.resolveProxy(url, callback)` From 4702b3e0c7f9b3cbf0c0d20171c3ac99f7d57357 Mon Sep 17 00:00:00 2001 From: Joe Naha Date: Tue, 12 Jan 2016 02:58:50 +0900 Subject: [PATCH 34/95] :memo: Update some Japanese translated docs. [ci skip] --- docs-translations/jp/README.md | 8 ++-- .../jp/tutorial/application-distribution.md | 18 ++++---- .../jp/tutorial/application-packaging.md | 46 +++++++++---------- 3 files changed, 37 insertions(+), 35 deletions(-) diff --git a/docs-translations/jp/README.md b/docs-translations/jp/README.md index e4ef797001a4..c30bcec09a50 100644 --- a/docs-translations/jp/README.md +++ b/docs-translations/jp/README.md @@ -1,10 +1,14 @@ +使用している Electron のバージョンに応じたドキュメントを使うように確認してください。 +ドキュメントのバージョン番号はページの URL の一部になっています。 +そうでない場合、おそらくご使用の Electron のバージョンと互換性のない API 変更を含んだ development ブランチのドキュメントを使っているものと思われます。 +その場合、atom.io の [available versions](http://electron.atom.io/docs/) リストにある別のバージョンのドキュメントに切り替えることができます。また GitHub で閲覧している場合、"Switch branches/tags" ドロップダウンを開いて、バージョンに対応したタグを選ぶこともできます。 + ## FAQ 頻繁に聞かれる質問がありますので、issueを作成する前にこれをチェックしてください。 * [Electron FAQ](faq/electron-faq.md) - ## ガイド * [サポートするプラットフォーム](tutorial/supported-platforms.md) @@ -18,8 +22,6 @@ * [Pepper Flashプラグインを使用する](tutorial/using-pepper-flash-plugin.md) * [Widevine CDMプラグインを使用する](tutorial/using-widevine-cdm-plugin.md) - - # チュートリアル * [クイックスタート](tutorial/quick-start.md) diff --git a/docs-translations/jp/tutorial/application-distribution.md b/docs-translations/jp/tutorial/application-distribution.md index ad6f46a12a1d..96dce25134aa 100644 --- a/docs-translations/jp/tutorial/application-distribution.md +++ b/docs-translations/jp/tutorial/application-distribution.md @@ -21,13 +21,13 @@ electron/resources/app └── index.html ``` -`Electron.app` (または Linux上では、`electron`、Windows上では、 `electron.exe`)を実行すると、Electronはアプリケーションを開始します。The `electron` ディレクトリを最終的なユーザーに提供するために配布します。 +`Electron.app` (または Linux上では、`electron`、Windows上では、 `electron.exe`)を実行すると、Electronはアプリケーションを開始します。`electron` ディレクトリを最終的なユーザーに提供するために配布します。 ## ファイルにアプリケーションをパッケージングする すべてのソースコードをコピーすることでアプリケーションを提供する方法とは別に、アプリケーションのソースコードをユーザーに見えるのを避けるために、[asar](https://github.com/atom/asar) にアーカイブしてアプリケーションをパッケージ化することができます。 -`asar`アーカイブを使用するために、`app`フォルダーと置き換え、アーカイブファイルを`app.asar`という名前に変更する必要があり、Electronのリソースディレクトリの下に置くと、Electronはアーカイブを読み込もうとし、それを開始します。 +`app` フォルダの代わりに `asar` アーカイブを使用するためには、アーカイブファイルを `app.asar` という名前に変更し、Electron のリソースディレクトリに以下のように配置する必要があります。すると、Electron はアーカイブを読み込もうとし、それを開始します。 OS X: @@ -45,7 +45,7 @@ electron/resources/ [Application packaging](application-packaging.md)で、詳細を確認できます。 -## ダウンローするバイナリのブランド名の変更 +## ダウンロードするバイナリのブランド名の変更 Electronにバンドルした後、ユーザーに配布する前に、 Electron名を変更したいでしょう。 @@ -56,14 +56,14 @@ Electronにバンドルした後、ユーザーに配布する前に、 Electron ### OS X - `Electron.app` を任意の名前に変更でき、次のファイルの `CFBundleDisplayName`と `CFBundleIdentifier`、 `CFBundleName`のフィールドの名前を変更する必要があります。 +`Electron.app` を任意の名前に変更でき、次のファイルの `CFBundleDisplayName`と `CFBundleIdentifier`、 `CFBundleName`のフィールドの名前を変更する必要があります。 * `Electron.app/Contents/Info.plist` * `Electron.app/Contents/Frameworks/Electron Helper.app/Contents/Info.plist` -Activity Monitorで、`Electron Helper`と表示されるのを避けるために、helper appの名前を変更でき、 helper appの実行ファイルの名前を確認します。 +ヘルパーアプリケーションの名前を変更して、アクティビティモニタに `Electron Helper` と表示されないようにすることもできますが、その際はヘルパーアプリケーションの実行可能ファイルの名前を変更したことを確認してください。 -次のようなappの変更する名前の構造 +名前変更後のアプリケーションの構成は以下の通りです: ``` MyApp.app/Contents @@ -95,14 +95,14 @@ MyApp.app/Contents ### grunt-build-atom-shell -マニュアルでは、Electronのコードをダウンロードし、リビルドさせます。一方で、面倒なタスクはこれで自動化できます: +Electron のコードを手動チェックアウトして再構築するのには複雑な手順が必要ですが、これを自動的に扱うための Grunt タスクが作られています: [grunt-build-atom-shell](https://github.com/paulcbetts/grunt-build-atom-shell). -This task will automatically handle editing the 自動処理を管理するのに、`.gyp`ファイルを編集し、ソースからビルドし、新しい実行名に一致したときにはNativeのNodeモジュールをリビルドするようにできます。 +このタスクは自動的に `.gyp` ファイルの編集、ソースからのビルド、そして新しい実行可能ファイル名に一致するようにネイティブの Node モジュールを再構築します。 ## パッケージングツール -マニュアルでパッケージ化するのとは別に、サードパーティのパッケジングツールを選ぶこともできます。 +手動でアプリケーションをパッケージ化する以外の方法として、サードパーティのパッケジングツールを選ぶこともできます。 * [electron-packager](https://github.com/maxogden/electron-packager) * [electron-builder](https://github.com/loopline-systems/electron-builder) diff --git a/docs-translations/jp/tutorial/application-packaging.md b/docs-translations/jp/tutorial/application-packaging.md index 7b6a5b30c2b2..e5196a6f6262 100644 --- a/docs-translations/jp/tutorial/application-packaging.md +++ b/docs-translations/jp/tutorial/application-packaging.md @@ -1,14 +1,14 @@ # アプリケーションのパッケージ化 -Windows上の長いパス名周りの[issues](https://github.com/joyent/node/issues/6960) を軽減させるたり、`require`を若干スピードアップさせたり、 簡単な調査からソースコードを隠したりするために、ソースコードの少しの変更で、[asar][asar]にアーカイブし、パッケージ化を選択することもできます。 +Windows上の長いパス名周りの[問題](https://github.com/joyent/node/issues/6960) を軽減したり、`require`を若干スピードアップしたり、簡単な調査からソースコードを隠したりするために、ソースコードを少々変更して、アプリケーションを [asar][asar] アーカイブとしてパッケージ化することもできます。 ## `asar` アーカイブの生成 -[asar][asar] アーカイブは、1つのファイルに連結されたtarライクのシンプルなフォーマットです。Electronは、すべてのファイルをアンパッキングせずに、任意のファイルを読み込めます。 +[asar][asar] アーカイブは、1つのファイルに連結されたtarライクのシンプルなフォーマットです。Electron はファイル全体をアンパックしなくても任意のファイルを読み込めます。 -アプリを `asar` アーカイブにパッケージ化する手順 +アプリを `asar` アーカイブにパッケージ化する手順: -### 1. asar ツールのインストール +### 1. asar ユーティリティのインストール ```bash $ npm install -g asar @@ -22,11 +22,11 @@ $ asar pack your-app app.asar ## `asar` アーカイブを使用する -Electronには、2組のAPIがあります。Node APIは、Node.jsで提供されており、Web APIは、Chromiumで提供されています。両方のAPIは、 `asar` アーカイブからのファイル読み込みに対応しています。 +Electronには、2組のAPIがあります。Node.js により提供される Node API、そして Chromium により提供される Web API です。どちらの API も `asar` アーカイブからのファイル読み込みに対応しています。 ### Node API -Electronでは特定のパッチで、`fs.readFile` や `require` のようなNode APIは、`asar` アーカイブを仮想ディレクトリのように扱い、ファイルをファイルシステムで通常のファイルのように扱います。 +Electronでは特定のパッチで、`fs.readFile` や `require` のようなNode APIは、`asar` アーカイブを仮想ディレクトリのように扱い、ファイルをファイルシステム上の通常のファイルのように扱います。 例えば、`/path/to` 配下に、`example.asar` アーカイブがあると仮定します: @@ -40,7 +40,7 @@ $ asar list /path/to/example.asar /static/jquery.min.js ``` -`asar` アーカイブでファイルを読み込む: +`asar` アーカイブ内のファイルを読み込む: ```javascript const fs = require('fs'); @@ -60,7 +60,7 @@ fs.readdirSync('/path/to/example.asar'); require('/path/to/example.asar/dir/module.js'); ``` - `BrowserWindow`で、`asar`アーカイブで、Webページを表示することができます: +`BrowserWindow` を使って `asar` アーカイブ内の Web ページを表示することもできます: ```javascript const BrowserWindow = require('electron').BrowserWindow; @@ -71,7 +71,7 @@ win.loadURL('file:///path/to/example.asar/static/index.html'); ### Web API Webページで、アーカイブ内のファイルを `file:` プロトコルでリクエストできます。 -Node APIのように、`asar` アーカイブはディレクトリのように扱われます。 +Node API と同様、`asar` アーカイブはディレクトリのように扱われます。 例えば、 `$.get` でファイルを取得できます: @@ -86,14 +86,14 @@ $.get('file:///path/to/example.asar/file.txt', function(data) { ### `asar` アーカイブを通常のファイルのように扱う -For some cases like verifying the `asar` アーカイブのチェックサムを検証するようなケースで、 `asar` アーカイブのコンテンツをファイルのように扱う必要があります。この目的のために、 `asar` サポートしないオリジナルの `fs` API が提供する ビルトインの `original-fs` モジュールを使用できます。 +アーカイブのチェックサムを検証する等の幾つかのケースでは、`asar` アーカイブをファイルとして読み込む必要があります。この目的のために、 `asar` サポートしないオリジナルの `fs` API を提供するビルトインの `original-fs` モジュールを使用できます。 ```javascript var originalFs = require('original-fs'); originalFs.readFileSync('/path/to/example.asar'); ``` -`fs` モジュールで、`asar` サポートを無効化するために、`process.noAsar` を `true` に設定します: +`process.noAssar` に `true` をセットしても `fs` モジュールの `asar` サポートを無効にすることができます: ```javascript process.noAsar = true; @@ -102,21 +102,21 @@ fs.readFileSync('/path/to/example.asar'); ## Node API の制限 -Node APIで、`asar` アーカイブが可能な限りディレクトリのように動作するよう懸命に試してますが、Node APIの低レベル性質の影響で、まだ制限があります。 +Node APIで、`asar` アーカイブが可能な限りディレクトリのように動作するよう懸命に試してますが、低レベル環境での Node API に起因した制限が幾つかあります。 ### アーカイブは読み取り専用です -ファイルを変更できる全てのNode APIは、 `asar` アーカイブに対して動作しないので、アーカイブは変更されません。 +アーカイブは修正できないため、ファイルを変更できる変更できる全ての Node API は `asar` アーカイブに対して動作しません。 ### 作業ディレクトリは、アーカイブ内のディレクトリに設定できません -`asar` アーカイブはディレクトリのように扱われるにも関わらず、ファイルシステム上では実際のディレクトリではなく、`asar` アーカイブ内に決して作業ディレクトリは設定されません。いくつかのAPIの`cwd`オプションを設定していて、それがエラー原因になります。 +`asar` アーカイブはディレクトリのように扱われるにも関わらず、ファイルシステム上には実際のディレクトリが存在しないため、`asar` アーカイブ内のディレクトリを作業ディレクトリとして設定することはできません。幾つかの API の `cwd` オプションにアーカイブ内のディレクトリを渡すのも同様にエラーの原因になります。 ### いくつかのAPIで追加のアンパッキングがされます -たいていの `fs` APIは、アンパッキングせずに、 `asar` アーカイブからファイルを読み込んだり、ファイル情報を取得できます。しかし、実際のファイルパスを通してシステムコールに依存するAPIもあり、Electronは必要なファイルを一時ファイルに解凍し、一時ファイルのパスを通して、APIが動作します。これは、APIに多少のオーバーヘッドがあります。 +たいていの `fs` APIは、アンパッキングせずに、 `asar` アーカイブからファイルを読み込んだり、ファイル情報を取得できます。しかし、システムコールに実際のファイルパスを渡すようになっている幾つかの API では、Electron は必要なファイルを一時ファイルとして抽出し、API に一時ファイルのパスを渡して、API が動作するようにします。このため、当該 API には多少のオーバーヘッドがあります。 -追加のアンパッキングに必要なAPIです。: +追加のアンパッキングに必要なAPIです: * `child_process.execFile` * `child_process.execFileSync` @@ -126,24 +126,24 @@ Node APIで、`asar` アーカイブが可能な限りディレクトリのよ ### `fs.stat` の偽の統計情報 -ファイルシステム上にファイルが存在しないので、`fs.stat` および `asar` アーカイブ内のファイルへの関連情報によって返される`Stats` オブジェクトは、推測して生成されます。ファイルサイズの取得とファイルタイプのチェックを除いて、 `Stats` オブジェクトを信頼すべきではありません。 +`asar` アーカイブ内のファイルはファイルシステム上に存在しないので、`fs.stat` および `asar` アーカイブ内のファイルへの関連情報によって返される`Stats` オブジェクトは、推測して生成されます。ファイルサイズの取得とファイルタイプのチェックを除いて、 `Stats` オブジェクトを信頼すべきではありません。 -### `asar` アーカイブ内でバイナリを実行します +### `asar` アーカイブ内のバイナリの実行 `child_process.exec` と `child_process.spawn` 、 `child_process.execFile` のようなバイナリを実行できるNode APIがあります。しかし、`execFile` だけが、`asar` アーカイブ内でのバイナリ実行をサポートしています。 -`exec` と `spawn` は、インプットを `file` の代わりに `command` を受け取り、`command` はシェル配下で実行されます。コマンドがasar アーカイブ内のファイルを使うかどうかを決定するための信頼できる方法はありません。影響なしで、コマンドでパスを置き換えることができるかどうかを確認することはできません。 +なぜならば、`exec` と `spawn` は入力として `file` の代わりに `command` を受け取り、`command` はシェル配下で実行されるからです。コマンドが asar アーカイブ内のファイルを使うかどうかを決定するための信頼できる方法はありませんし、そうするとしてもコマンドで使うファイルパスを副作用なしに置き換えることができるかどうかを確認することはできません。 -## アンパッキングする `asar` アーカイブ内のファイルを追加する +## `asar` アーカイブ内のファイルをアンパックして追加 -上記のように、いくつかのNode APIは、呼び出さすとき、ファイルをファイルパスへアンパックします。パフォーマンス問題は別として、ウィルススキャナーのアラートにつながる可能性があります。 +上記のように、いくつかのNode APIが呼ばれると、ファイルシステム上にファイルをアンパックしますが,パフォーマンス問題は別として、ウィルススキャナーのアラートにつながる可能性があります。 -これに対する対応として、`--unpack` オプションを使用して、アーカイブを作成する際に、いくつかのファイルをアンパックできます。例えば、ネイティブモジュールの共有ライブラリを除きます。 +これに対応するために、`--unpack` オプションを使用して、アーカイブを作成する際に、いくつかのファイルをアンパックできます。例えば、ネイティブモジュールの共有ライブラリを除く場合: ```bash $ asar pack app app.asar --unpack *.node ``` -このコマンドを実行した後、`app.asar` とは別に、アンパックファイルを含んだ`app.asar.unpacked` フォルダーが生成され、ユーザーに提供するときには、`app.asar` と一緒にコピーしなければなりません。 +このコマンドを実行した後、`app.asar` とは別に、アンパックされたファイルを含んだ`app.asar.unpacked` フォルダーが生成されます。ユーザーに提供するときには、`app.asar` と一緒にコピーしなければなりません。 [asar]: https://github.com/atom/asar From 7333e403b7021c3daa4000e1fd8ec70c435ea86f Mon Sep 17 00:00:00 2001 From: Wei Wang Date: Mon, 11 Jan 2016 10:47:32 -0800 Subject: [PATCH 35/95] missing "var" in line 201 menu.md in line 201 at menu.md, should be ```var menu = Menu.buildFromTemplate(template);``` --- docs/api/menu.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/api/menu.md b/docs/api/menu.md index b5f2fbe9516e..38069140ad30 100644 --- a/docs/api/menu.md +++ b/docs/api/menu.md @@ -198,7 +198,7 @@ if (process.platform == 'darwin') { ); } -menu = Menu.buildFromTemplate(template); +var menu = Menu.buildFromTemplate(template); Menu.setApplicationMenu(menu); ``` From 6d850ea61ff7cc6d6b8bbb6f70f136d6bce32652 Mon Sep 17 00:00:00 2001 From: Cheng Zhao Date: Tue, 12 Jan 2016 10:59:45 +0800 Subject: [PATCH 36/95] docs: Mention the session object --- docs/api/browser-window.md | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/docs/api/browser-window.md b/docs/api/browser-window.md index 72fbd7fbeac0..61180d5b89a9 100644 --- a/docs/api/browser-window.md +++ b/docs/api/browser-window.md @@ -120,12 +120,17 @@ The `webPreferences` option is an object that can have following properties: When node integration is turned off, the preload script can reintroduce Node global symbols back to the global scope. See example [here](process.md#event-loaded). -* `partition` String - Sets the session used by the page. If `partition` - starts with `persist:`, the page will use a persistent session available to - all pages in the app with the same `partition`. if there is no `persist:` - prefix, the page will use an in-memory session. By assigning the same - `partition`, multiple pages can share the same session. If the `partition` - is unset then default session of the app will be used. +* `session` [Session](session.md#class-session) - Sets the session used by the + page. Instead of passing the Session object directly, you can also choose to + use the `partition` option instead, which accepts a partition string. When + both `session` and `partition` are provided, `session` would be preferred. + Default is the default session. +* `partition` String - Sets the session used by the page according to the + session's partition string. If `partition` starts with `persist:`, the page + will use a persistent session available to all pages in the app with the + same `partition`. if there is no `persist:` prefix, the page will use an + in-memory session. By assigning the same `partition`, multiple pages can share + the same session. Default is the default session. * `zoomFactor` Number - The default zoom factor of the page, `3.0` represents `300%`. Default is `1.0`. * `javascript` Boolean - Enables JavaScript support. Default is `true`. From 554575b0294fc37597dbe5ef0215adc7bdd41137 Mon Sep 17 00:00:00 2001 From: Cheng Zhao Date: Tue, 12 Jan 2016 20:46:47 +0800 Subject: [PATCH 37/95] Upgrade to Chrome 47.0.2526.110 --- script/lib/config.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/script/lib/config.py b/script/lib/config.py index 7570f3dc1a40..279fa7340a96 100644 --- a/script/lib/config.py +++ b/script/lib/config.py @@ -8,7 +8,7 @@ import sys BASE_URL = os.getenv('LIBCHROMIUMCONTENT_MIRROR') or \ 'https://s3.amazonaws.com/github-janky-artifacts/libchromiumcontent' -LIBCHROMIUMCONTENT_COMMIT = '45f296cf0d169f8afec75e211f6f66c7a887e113' +LIBCHROMIUMCONTENT_COMMIT = 'ad63d8ba890bcaad2f1b7e6de148b7992f4d3af7' PLATFORM = { 'cygwin': 'win32', From eb63e6b9a7f1db70be024987c34ec62ce75268f8 Mon Sep 17 00:00:00 2001 From: Cheng Zhao Date: Tue, 12 Jan 2016 21:10:24 +0800 Subject: [PATCH 38/95] Destroy the native class when webContents is destroyed --- atom/browser/api/atom_api_web_contents.cc | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/atom/browser/api/atom_api_web_contents.cc b/atom/browser/api/atom_api_web_contents.cc index 43ce556264e9..4d449ed9c39b 100644 --- a/atom/browser/api/atom_api_web_contents.cc +++ b/atom/browser/api/atom_api_web_contents.cc @@ -635,8 +635,16 @@ bool WebContents::OnMessageReceived(const IPC::Message& message) { void WebContents::WebContentsDestroyed() { // The RenderViewDeleted was not called when the WebContents is destroyed. RenderViewDeleted(web_contents()->GetRenderViewHost()); - Emit("destroyed"); RemoveFromWeakMap(); + + // 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("destroyed"); + + // Destroy the native class in next tick. + base::MessageLoop::current()->PostTask(FROM_HERE, GetDestroyClosure()); } void WebContents::NavigationEntryCommitted( From d674db6606032eaee53dc4112ad6c20a25628916 Mon Sep 17 00:00:00 2001 From: Cheng Zhao Date: Tue, 12 Jan 2016 21:15:12 +0800 Subject: [PATCH 39/95] spec: Calling methods of destroyed webContents should not crash --- spec/api-browser-window-spec.coffee | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/spec/api-browser-window-spec.coffee b/spec/api-browser-window-spec.coffee index 38c8217041e7..724f149cd9e5 100644 --- a/spec/api-browser-window-spec.coffee +++ b/spec/api-browser-window-spec.coffee @@ -55,6 +55,12 @@ describe 'browser-window module', -> done() w.loadURL 'file://' + path.join(fixtures, 'api', 'close-beforeunload-false.html') + describe 'BrowserWindow.destroy()', -> + it 'prevents users to access methods of webContents', -> + webContents = w.webContents + w.destroy() + assert.throws (-> webContents.getId()), /Object has been destroyed/ + describe 'BrowserWindow.loadURL(url)', -> it 'should emit did-start-loading event', (done) -> w.webContents.on 'did-start-loading', -> From 8832d7b77bad18ffaefa4bdb8884ffd5c6d4edcb Mon Sep 17 00:00:00 2001 From: Cheng Zhao Date: Tue, 12 Jan 2016 22:17:24 +0800 Subject: [PATCH 40/95] Import PepperFlashDRMHost class --- .../chrome_browser_pepper_host_factory.cc | 4 + .../renderer_host/pepper/monitor_finder_mac.h | 52 +++++ .../pepper/monitor_finder_mac.mm | 62 ++++++ .../pepper/pepper_flash_drm_host.cc | 182 ++++++++++++++++++ .../pepper/pepper_flash_drm_host.h | 55 ++++++ filenames.gypi | 4 + 6 files changed, 359 insertions(+) create mode 100644 chromium_src/chrome/browser/renderer_host/pepper/monitor_finder_mac.h create mode 100644 chromium_src/chrome/browser/renderer_host/pepper/monitor_finder_mac.mm create mode 100644 chromium_src/chrome/browser/renderer_host/pepper/pepper_flash_drm_host.cc create mode 100644 chromium_src/chrome/browser/renderer_host/pepper/pepper_flash_drm_host.h diff --git a/chromium_src/chrome/browser/renderer_host/pepper/chrome_browser_pepper_host_factory.cc b/chromium_src/chrome/browser/renderer_host/pepper/chrome_browser_pepper_host_factory.cc index c2992abcc11d..98932a494bf8 100644 --- a/chromium_src/chrome/browser/renderer_host/pepper/chrome_browser_pepper_host_factory.cc +++ b/chromium_src/chrome/browser/renderer_host/pepper/chrome_browser_pepper_host_factory.cc @@ -8,6 +8,7 @@ #include "chrome/browser/renderer_host/pepper/pepper_broker_message_filter.h" #include "chrome/browser/renderer_host/pepper/pepper_flash_browser_host.h" #include "chrome/browser/renderer_host/pepper/pepper_flash_clipboard_message_filter.h" +#include "chrome/browser/renderer_host/pepper/pepper_flash_drm_host.h" #include "chrome/browser/renderer_host/pepper/pepper_isolated_file_system_message_filter.h" #include "content/public/browser/browser_ppapi_host.h" #include "ppapi/host/message_filter_host.h" @@ -65,6 +66,9 @@ scoped_ptr ChromeBrowserPepperHostFactory::CreateResourceHost( return scoped_ptr(new MessageFilterHost( host_->GetPpapiHost(), instance, resource, clipboard_filter)); } + case PpapiHostMsg_FlashDRM_Create::ID: + return scoped_ptr( + new chrome::PepperFlashDRMHost(host_, instance, resource)); } } diff --git a/chromium_src/chrome/browser/renderer_host/pepper/monitor_finder_mac.h b/chromium_src/chrome/browser/renderer_host/pepper/monitor_finder_mac.h new file mode 100644 index 000000000000..cc10ee85780c --- /dev/null +++ b/chromium_src/chrome/browser/renderer_host/pepper/monitor_finder_mac.h @@ -0,0 +1,52 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_RENDERER_HOST_PEPPER_MONITOR_FINDER_MAC_H_ +#define CHROME_BROWSER_RENDERER_HOST_PEPPER_MONITOR_FINDER_MAC_H_ + +#include +#include + +#include "base/macros.h" +#include "base/memory/ref_counted.h" +#include "base/synchronization/lock.h" + +namespace chrome { + +// MonitorFinder maps a RenderFrameHost to the display ID on which the widget +// is painting. This class operates on the IO thread while the RenderFrameHost +// is on the UI thread, so the value returned by GetMonitor() may be 0 until +// the information can be retrieved asynchronously. +class MonitorFinder : public base::RefCountedThreadSafe { + public: + MonitorFinder(int process_id, int render_frame_id); + + // Gets the native display ID for the tuple. + int64_t GetMonitor(); + + // Checks if the given |monitor_id| represents a built-in display. + static bool IsMonitorBuiltIn(int64_t monitor_id); + + private: + friend class base::RefCountedThreadSafe; + ~MonitorFinder(); + + // Method run on the UI thread to get the display information. + void FetchMonitorFromWidget(); + + const int process_id_; + const int render_frame_id_; + + base::Lock mutex_; // Protects the two members below. + // Whether one request to FetchMonitorFromWidget() has been made already. + bool request_sent_; + // The native display ID for the RenderFrameHost. + CGDirectDisplayID display_id_; + + DISALLOW_COPY_AND_ASSIGN(MonitorFinder); +}; + +} // namespace chrome + +#endif // CHROME_BROWSER_RENDERER_HOST_PEPPER_MONITOR_FINDER_H_ diff --git a/chromium_src/chrome/browser/renderer_host/pepper/monitor_finder_mac.mm b/chromium_src/chrome/browser/renderer_host/pepper/monitor_finder_mac.mm new file mode 100644 index 000000000000..31f6cfd41060 --- /dev/null +++ b/chromium_src/chrome/browser/renderer_host/pepper/monitor_finder_mac.mm @@ -0,0 +1,62 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/renderer_host/pepper/monitor_finder_mac.h" + +#import + +#include "content/public/browser/browser_thread.h" +#include "content/public/browser/render_frame_host.h" + +namespace chrome { + +MonitorFinder::MonitorFinder(int process_id, int render_frame_id) + : process_id_(process_id), + render_frame_id_(render_frame_id), + request_sent_(false), + display_id_(kCGNullDirectDisplay) {} + +MonitorFinder::~MonitorFinder() {} + +int64_t MonitorFinder::GetMonitor() { + { + // The plugin may call this method several times, so avoid spamming the UI + // thread with requests by only allowing one outstanding request at a time. + base::AutoLock lock(mutex_); + if (request_sent_) + return display_id_; + request_sent_ = true; + } + + content::BrowserThread::PostTask( + content::BrowserThread::UI, + FROM_HERE, + base::Bind(&MonitorFinder::FetchMonitorFromWidget, this)); + return display_id_; +} + +// static +bool MonitorFinder::IsMonitorBuiltIn(int64_t display_id) { + return CGDisplayIsBuiltin(display_id); +} + +void MonitorFinder::FetchMonitorFromWidget() { + DCHECK_CURRENTLY_ON(content::BrowserThread::UI); + content::RenderFrameHost* rfh = + content::RenderFrameHost::FromID(process_id_, render_frame_id_); + if (!rfh) + return; + + gfx::NativeView native_view = rfh->GetNativeView(); + NSWindow* window = [native_view window]; + NSScreen* screen = [window screen]; + CGDirectDisplayID display_id = + [[[screen deviceDescription] objectForKey:@"NSScreenNumber"] intValue]; + + base::AutoLock lock(mutex_); + request_sent_ = false; + display_id_ = display_id; +} + +} // namespace chrome diff --git a/chromium_src/chrome/browser/renderer_host/pepper/pepper_flash_drm_host.cc b/chromium_src/chrome/browser/renderer_host/pepper/pepper_flash_drm_host.cc new file mode 100644 index 000000000000..892c26141aa9 --- /dev/null +++ b/chromium_src/chrome/browser/renderer_host/pepper/pepper_flash_drm_host.cc @@ -0,0 +1,182 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/renderer_host/pepper/pepper_flash_drm_host.h" + +#if defined(OS_WIN) +#include +#endif + +#include "base/bind.h" +#include "base/compiler_specific.h" +#include "base/logging.h" +#include "base/memory/ref_counted.h" +#include "build/build_config.h" +#include "content/public/browser/browser_ppapi_host.h" +#include "content/public/browser/browser_thread.h" +#include "content/public/browser/child_process_security_policy.h" +#include "content/public/browser/render_frame_host.h" +#include "content/public/common/pepper_plugin_info.h" +#include "ppapi/c/pp_errors.h" +#include "ppapi/host/dispatch_host_message.h" +#include "ppapi/host/host_message_context.h" +#include "ppapi/host/ppapi_host.h" +#include "ppapi/proxy/ppapi_messages.h" + +#if defined(USE_AURA) +#include "ui/aura/window.h" +#include "ui/aura/window_tree_host.h" +#endif + +#if defined(OS_MACOSX) +#include "chrome/browser/renderer_host/pepper/monitor_finder_mac.h" +#endif + +using content::BrowserPpapiHost; + +namespace chrome { + +namespace { +const char kVoucherFilename[] = "plugin.vch"; +} + +#if defined(OS_WIN) +// Helper class to get the UI thread which monitor is showing the +// window associated with the instance's render view. Since we get +// called by the IO thread and we cannot block, the first answer is +// of GetMonitor() may be NULL, but eventually it will contain the +// right monitor. +class MonitorFinder : public base::RefCountedThreadSafe { + public: + MonitorFinder(int process_id, int render_frame_id) + : process_id_(process_id), + render_frame_id_(render_frame_id), + monitor_(NULL), + request_sent_(0) {} + + int64_t GetMonitor() { + // We use |request_sent_| as an atomic boolean so that we + // never have more than one task posted at a given time. We + // do this because we don't know how often our client is going + // to call and we can't cache the |monitor_| value. + if (InterlockedCompareExchange(&request_sent_, 1, 0) == 0) { + content::BrowserThread::PostTask( + content::BrowserThread::UI, + FROM_HERE, + base::Bind(&MonitorFinder::FetchMonitorFromWidget, this)); + } + return reinterpret_cast(monitor_); + } + + private: + friend class base::RefCountedThreadSafe; + ~MonitorFinder() {} + + void FetchMonitorFromWidget() { + InterlockedExchange(&request_sent_, 0); + content::RenderFrameHost* rfh = + content::RenderFrameHost::FromID(process_id_, render_frame_id_); + if (!rfh) + return; + gfx::NativeView native_view = rfh->GetNativeView(); +#if defined(USE_AURA) + aura::WindowTreeHost* host = native_view->GetHost(); + if (!host) + return; + HWND window = host->GetAcceleratedWidget(); +#else + HWND window = native_view; +#endif + HMONITOR monitor = ::MonitorFromWindow(window, MONITOR_DEFAULTTONULL); + InterlockedExchangePointer(reinterpret_cast(&monitor_), + monitor); + } + + const int process_id_; + const int render_frame_id_; + volatile HMONITOR monitor_; + volatile long request_sent_; +}; +#elif !defined(OS_MACOSX) +// TODO(cpu): Support Linux someday. +class MonitorFinder : public base::RefCountedThreadSafe { + public: + MonitorFinder(int, int) {} + int64_t GetMonitor() { return 0; } + + private: + friend class base::RefCountedThreadSafe; + ~MonitorFinder() {} +}; +#endif + +PepperFlashDRMHost::PepperFlashDRMHost(BrowserPpapiHost* host, + PP_Instance instance, + PP_Resource resource) + : ppapi::host::ResourceHost(host->GetPpapiHost(), instance, resource), + weak_factory_(this) { + // Grant permissions to read the flash voucher file. + int render_process_id; + int render_frame_id; + bool success = host->GetRenderFrameIDsForInstance( + instance, &render_process_id, &render_frame_id); + base::FilePath plugin_dir = host->GetPluginPath().DirName(); + DCHECK(!plugin_dir.empty() && success); + base::FilePath voucher_file = plugin_dir.AppendASCII(kVoucherFilename); + content::ChildProcessSecurityPolicy::GetInstance()->GrantReadFile( + render_process_id, voucher_file); + + monitor_finder_ = new MonitorFinder(render_process_id, render_frame_id); + monitor_finder_->GetMonitor(); +} + +PepperFlashDRMHost::~PepperFlashDRMHost() {} + +int32_t PepperFlashDRMHost::OnResourceMessageReceived( + const IPC::Message& msg, + ppapi::host::HostMessageContext* context) { + PPAPI_BEGIN_MESSAGE_MAP(PepperFlashDRMHost, msg) + PPAPI_DISPATCH_HOST_RESOURCE_CALL_0(PpapiHostMsg_FlashDRM_GetDeviceID, + OnHostMsgGetDeviceID) + PPAPI_DISPATCH_HOST_RESOURCE_CALL_0(PpapiHostMsg_FlashDRM_GetHmonitor, + OnHostMsgGetHmonitor) + PPAPI_DISPATCH_HOST_RESOURCE_CALL_0(PpapiHostMsg_FlashDRM_MonitorIsExternal, + OnHostMsgMonitorIsExternal) + PPAPI_END_MESSAGE_MAP() + return PP_ERROR_FAILED; +} + +int32_t PepperFlashDRMHost::OnHostMsgGetDeviceID( + ppapi::host::HostMessageContext* context) { + context->reply_msg = PpapiPluginMsg_FlashDRM_GetDeviceIDReply(""); + return PP_OK; +} + +int32_t PepperFlashDRMHost::OnHostMsgGetHmonitor( + ppapi::host::HostMessageContext* context) { + int64_t monitor_id = monitor_finder_->GetMonitor(); + if (monitor_id) { + context->reply_msg = PpapiPluginMsg_FlashDRM_GetHmonitorReply(monitor_id); + return PP_OK; + } + return PP_ERROR_FAILED; +} + +int32_t PepperFlashDRMHost::OnHostMsgMonitorIsExternal( + ppapi::host::HostMessageContext* context) { + int64_t monitor_id = monitor_finder_->GetMonitor(); + if (!monitor_id) + return PP_ERROR_FAILED; + + PP_Bool is_external = PP_FALSE; +#if defined(OS_MACOSX) + if (!MonitorFinder::IsMonitorBuiltIn(monitor_id)) + is_external = PP_TRUE; +#endif + context->reply_msg = + PpapiPluginMsg_FlashDRM_MonitorIsExternalReply(is_external); + return PP_OK; +} + +} // namespace chrome diff --git a/chromium_src/chrome/browser/renderer_host/pepper/pepper_flash_drm_host.h b/chromium_src/chrome/browser/renderer_host/pepper/pepper_flash_drm_host.h new file mode 100644 index 000000000000..91bba9631e68 --- /dev/null +++ b/chromium_src/chrome/browser/renderer_host/pepper/pepper_flash_drm_host.h @@ -0,0 +1,55 @@ +// Copyright (c) 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_RENDERER_HOST_PEPPER_PEPPER_FLASH_DRM_HOST_H_ +#define CHROME_BROWSER_RENDERER_HOST_PEPPER_PEPPER_FLASH_DRM_HOST_H_ + +#include + +#include + +#include "base/macros.h" +#include "base/memory/weak_ptr.h" +#include "ppapi/host/host_message_context.h" +#include "ppapi/host/resource_host.h" + +namespace content { +class BrowserPpapiHost; +} + +namespace IPC { +class Message; +} + +namespace chrome { +class MonitorFinder; + +class PepperFlashDRMHost : public ppapi::host::ResourceHost { + public: + PepperFlashDRMHost(content::BrowserPpapiHost* host, + PP_Instance instance, + PP_Resource resource); + ~PepperFlashDRMHost() override; + + // ResourceHost override. + int32_t OnResourceMessageReceived( + const IPC::Message& msg, + ppapi::host::HostMessageContext* context) override; + + private: + // IPC message handler. + int32_t OnHostMsgGetDeviceID(ppapi::host::HostMessageContext* context); + int32_t OnHostMsgGetHmonitor(ppapi::host::HostMessageContext* context); + int32_t OnHostMsgMonitorIsExternal(ppapi::host::HostMessageContext* context); + + scoped_refptr monitor_finder_; + + base::WeakPtrFactory weak_factory_; + + DISALLOW_COPY_AND_ASSIGN(PepperFlashDRMHost); +}; + +} // namespace chrome + +#endif // CHROME_BROWSER_RENDERER_HOST_PEPPER_PEPPER_FLASH_DRM_HOST_H_ diff --git a/filenames.gypi b/filenames.gypi index d7eb8409261b..61791604ecc5 100644 --- a/filenames.gypi +++ b/filenames.gypi @@ -410,12 +410,16 @@ 'chromium_src/chrome/browser/process_singleton.h', 'chromium_src/chrome/browser/renderer_host/pepper/chrome_browser_pepper_host_factory.cc', 'chromium_src/chrome/browser/renderer_host/pepper/chrome_browser_pepper_host_factory.h', + 'chromium_src/chrome/browser/renderer_host/pepper/monitor_finder_mac.h', + 'chromium_src/chrome/browser/renderer_host/pepper/monitor_finder_mac.mm', 'chromium_src/chrome/browser/renderer_host/pepper/pepper_broker_message_filter.cc', 'chromium_src/chrome/browser/renderer_host/pepper/pepper_broker_message_filter.h', 'chromium_src/chrome/browser/renderer_host/pepper/pepper_flash_browser_host.cc', 'chromium_src/chrome/browser/renderer_host/pepper/pepper_flash_browser_host.h', 'chromium_src/chrome/browser/renderer_host/pepper/pepper_flash_clipboard_message_filter.cc', 'chromium_src/chrome/browser/renderer_host/pepper/pepper_flash_clipboard_message_filter.h', + 'chromium_src/chrome/browser/renderer_host/pepper/pepper_flash_drm_host.cc', + 'chromium_src/chrome/browser/renderer_host/pepper/pepper_flash_drm_host.h', 'chromium_src/chrome/browser/renderer_host/pepper/pepper_isolated_file_system_message_filter.cc', 'chromium_src/chrome/browser/renderer_host/pepper/pepper_isolated_file_system_message_filter.h', 'chromium_src/chrome/browser/renderer_host/pepper/widevine_cdm_message_filter.cc', From 57da8908b23258c2d6f3a43e15129af2d6048a30 Mon Sep 17 00:00:00 2001 From: Cheng Zhao Date: Tue, 12 Jan 2016 23:17:07 +0800 Subject: [PATCH 41/95] Use volume serial number as device id --- .../pepper/pepper_flash_drm_host.cc | 37 ++++++++++++++++++- 1 file changed, 36 insertions(+), 1 deletion(-) diff --git a/chromium_src/chrome/browser/renderer_host/pepper/pepper_flash_drm_host.cc b/chromium_src/chrome/browser/renderer_host/pepper/pepper_flash_drm_host.cc index 892c26141aa9..f94216461769 100644 --- a/chromium_src/chrome/browser/renderer_host/pepper/pepper_flash_drm_host.cc +++ b/chromium_src/chrome/browser/renderer_host/pepper/pepper_flash_drm_host.cc @@ -4,6 +4,8 @@ #include "chrome/browser/renderer_host/pepper/pepper_flash_drm_host.h" +#include + #if defined(OS_WIN) #include #endif @@ -12,12 +14,14 @@ #include "base/compiler_specific.h" #include "base/logging.h" #include "base/memory/ref_counted.h" +#include "base/strings/string_number_conversions.h" #include "build/build_config.h" #include "content/public/browser/browser_ppapi_host.h" #include "content/public/browser/browser_thread.h" #include "content/public/browser/child_process_security_policy.h" #include "content/public/browser/render_frame_host.h" #include "content/public/common/pepper_plugin_info.h" +#include "net/base/net_util.h" #include "ppapi/c/pp_errors.h" #include "ppapi/host/dispatch_host_message.h" #include "ppapi/host/host_message_context.h" @@ -38,7 +42,30 @@ using content::BrowserPpapiHost; namespace chrome { namespace { + const char kVoucherFilename[] = "plugin.vch"; + +#if defined(OS_WIN) +bool GetSystemVolumeSerialNumber(std::string* number) { + // Find the system root path (e.g: C:\). + wchar_t system_path[MAX_PATH + 1]; + if (!GetSystemDirectoryW(system_path, MAX_PATH)) + return false; + + wchar_t* first_slash = wcspbrk(system_path, L"\\/"); + if (first_slash != NULL) + *(first_slash + 1) = 0; + + DWORD number_local = 0; + if (!GetVolumeInformationW(system_path, NULL, 0, &number_local, NULL, NULL, + NULL, 0)) + return false; + + *number = base::IntToString(std::abs(static_cast(number_local))); + return true; +} +#endif + } #if defined(OS_WIN) @@ -149,7 +176,15 @@ int32_t PepperFlashDRMHost::OnResourceMessageReceived( int32_t PepperFlashDRMHost::OnHostMsgGetDeviceID( ppapi::host::HostMessageContext* context) { - context->reply_msg = PpapiPluginMsg_FlashDRM_GetDeviceIDReply(""); + static std::string id; +#if defined(OS_WIN) + if (id.empty() && !GetSystemVolumeSerialNumber(&id)) + id = net::GetHostName(); +#else + if (id.empty()) + id = net::GetHostName(); +#endif + context->reply_msg = PpapiPluginMsg_FlashDRM_GetDeviceIDReply(id); return PP_OK; } From 1fd1ae9694d60a0b58bfa35b4148525685705d4c Mon Sep 17 00:00:00 2001 From: Joe Naha Date: Wed, 13 Jan 2016 08:46:14 +0900 Subject: [PATCH 42/95] :memo: Add and update Japanese translated docs. [ci skip] --- docs-translations/jp/README.md | 4 ++ docs-translations/jp/api/synopsis.md | 69 +++++++++++++++++++ docs-translations/jp/faq/electron-faq.md | 14 ++-- .../jp/tutorial/online-offline-events.md | 4 +- 4 files changed, 82 insertions(+), 9 deletions(-) create mode 100644 docs-translations/jp/api/synopsis.md diff --git a/docs-translations/jp/README.md b/docs-translations/jp/README.md index c30bcec09a50..accde9739769 100644 --- a/docs-translations/jp/README.md +++ b/docs-translations/jp/README.md @@ -27,3 +27,7 @@ * [クイックスタート](tutorial/quick-start.md) * [デスクトップ環境の統合](tutorial/desktop-environment-integration.md) * [オンライン/オフライン イベントの検知](tutorial/online-offline-events.md) + +## API リファレンス + +* [概要](api/synopsis.md) diff --git a/docs-translations/jp/api/synopsis.md b/docs-translations/jp/api/synopsis.md new file mode 100644 index 000000000000..a2f701807ea0 --- /dev/null +++ b/docs-translations/jp/api/synopsis.md @@ -0,0 +1,69 @@ +# 概要 + +Electron では全ての [Node.js のビルトインモジュール](http://nodejs.org/api/) 利用可能です。また、サードパーティの Node モジュール ([ネイティブモジュール](../tutorial/using-native-node-modules.md)も含む) も完全にサポートされています。 + +Electron はネイティブのデスクトップアプリケーション開発のための幾つかの追加のビルトインモジュールも提供しています。メインプロセスでだけ使えるモジュールもあれば、レンダラプロセス(ウェブページ)でだけ使えるモジュール、あるいはメインプロセス、レンダラプロセスどちらでも使えるモジュールもあります。 + +基本的なルールは:[GUI][gui]、または低レベルのシステムに関連するモジュールはメインモジュールでだけ利用できるべきです。これらのモジュールを使用できるようにするためには [メインプロセス対レンダラプロセス][main-process] スクリプトの概念を理解する必要があります。 + +メインプロセススクリプトは普通の Node.js スクリプトのようなものです: + +```javascript +const electron = require('electron'); +const app = electron.app; +const BrowserWindow = electron.BrowserWindow; + +var window = null; + +app.on('ready', function() { + window = new BrowserWindow({width: 800, height: 600}); + window.loadURL('https://github.com'); +}); +``` + +レンダラプロセスは Node モジュールを使うための追加機能を除いて、通常のウェブページとなんら違いはありません: + +```html + + + + + + +``` + +アプリケーションを実行については、[アプリを実行する](../tutorial/quick-start.md#アプリを実行する)を参照してください。 + +## 分割代入 + +CoffeeScript か Babel を使っているなら、[分割代入][desctructuring-assignment]でビルトインモジュールの使用をより簡単にできます: + +```javascript +const {app, BrowserWindow} = require('electron') +``` + +しかし、素の JavaScript を使っている場合、Chrome が ES6 を完全サポートするまで待たなければいけません。 + +## Disable old styles of using built-in modules + +v0.35.0 以前は全てのビルトインモジュールは `require('module-name')` の形式で使われなければいけません。この形式は[多くの欠点][issue-387]がありますが、古いアプリケーションとの互換性のためにまだサポートしています。 + +古い形式を完全に無効にするために、環境変数 `ELECTRON_HIDE_INTERNAL_MODULES` を設定できます: + +```javascript +process.env.ELECTRON_HIDE_INTERNAL_MODULES = 'true' +``` + +もしくは `hideInternalModules` API を呼んでください: + +```javascript +require('electron').hideInternalModules() +``` + +[gui]: https://en.wikipedia.org/wiki/Graphical_user_interface +[main-process]: ../tutorial/quick-start.md#メインプロセス +[desctructuring-assignment]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment +[issue-387]: https://github.com/atom/electron/issues/387 diff --git a/docs-translations/jp/faq/electron-faq.md b/docs-translations/jp/faq/electron-faq.md index bfd99989c9b5..b73831974772 100644 --- a/docs-translations/jp/faq/electron-faq.md +++ b/docs-translations/jp/faq/electron-faq.md @@ -8,21 +8,20 @@ ElectronのChromeバージョンは、通常、新しいChromeのstabeleバー ## Electronは、いつ最新のNode.jsにアップグレードされますか? -Node.jsの新しいバージョンがリリースされたとき、とても頻繁に発生している新しいNode.jsバージョンで取り込まれたバグによる影響を避けるために、ElectronのNode.jsをアップグレードする前に、通常、約1カ月待ちます。 +Node.js の新しいバージョンがリリースされたとき、私たちは Electron の Node.js を更新するのを通常約1か月待ちます。そのようにして、とても頻繁に発生している、新しい Node.js バージョンによって取り込まれたバグによる影響を避けることができます。 -通常、Node.jsの新しい機能はV8のアップグレードによってもたらされ、 ElectronはChromeブラウザーに搭載されているV8を使用しているので、 -新しいNode.jsの重要な新しいJavaScript機能はElectronでは、すでに導入されています。 +通常、Node.js の新しい機能は V8 のアップグレードによってもたらされますが、Electron は Chrome ブラウザーに搭載されている V8 を使用しているので、新しい Node.js に入ったばかりのピカピカに新しい JavaScript 機能は Electron ではたいてい既に導入されています。 -## 数分後、アプリのWindow/trayが表示されなくなります +## 何分か経つと、アプリの Window/tray が消えてしまいます -これは、Window/trayを格納するのに使用している変数がガベージ コレクションされたときに発生します。 +これは、Window/trayを格納するのに使用している変数がガベージコレクトされたときに発生します。 この問題に遭遇した時には、次のドキュメントを読むことをお勧めします。 * [Memory Management][memory-management] * [Variable Scope][variable-scope] -もし簡単に修正したい場合は、グローバル変数を作成し、コードを変更します。 +もし簡単に修正したい場合は、コードを以下のように修正して変数をグローバルにすると良いでしょう: 変更前: @@ -43,7 +42,8 @@ app.on('ready', function() { ## ElectronでjQuery/RequireJS/Meteor/AngularJSを使用できません -Electronに組み込まれているNode.jsの影響で, `module`, `exports`, `require`のようなシンボルがDOMに追加されています。いくつかのライブラリで、追加しようとしているシンボルと同じ名前があり、これが原因で問題が発生します。 +Electronに組み込まれているNode.jsの影響で, `module`, `exports`, `require`のようなシンボルがDOMに追加されています。このため、いくつかのライブラリでは同名のシンボルを追加しようとして問題が発生することがあります。 + これを解決するために、Electronに組み込まれているnodeを無効にすることができます。 ```javascript diff --git a/docs-translations/jp/tutorial/online-offline-events.md b/docs-translations/jp/tutorial/online-offline-events.md index bf04f72d30dc..92503b04dfcb 100644 --- a/docs-translations/jp/tutorial/online-offline-events.md +++ b/docs-translations/jp/tutorial/online-offline-events.md @@ -1,6 +1,6 @@ # オンライン/オフライン イベントの検知 -オンラインとオフラインイベントの検知は、標準のHTML 5 APIを使用して、状況表示を実装できます。次の例を見てみましょう。 +オンラインとオフラインイベントの検知は、以下の例で示すように、標準のHTML 5 APIを使用してレンダラプロセスに実装することができます。 _main.js_ @@ -36,7 +36,7 @@ _online-status.html_ ``` -メインプロセスでそれらのイベントに反応するインスタンスがあるかもしれません。メインプロセスは、`navigator` オブジェクトをもたず、直接それらのイベントを検知できません。Electronの内部プロセスコミュニケーションツールを使用して、イベントはメインプロセスに転送され、必要があればハンドルできます。次の例を見てみましょう。 +メインプロセスでこれらのイベントに応答したいことがあるかもしれません。しかし、メインプロセスは `navigator` オブジェクトを持たないため、直接これらのイベントを検知することができません。Electronの inter-process communication ユーティリティを使用して、オンライン・オフラインイベントをメインプロセスに転送し、必要に応じて扱うことができます。次の例を見てみましょう。 _main.js_ From 403870a27eb036e35a5b9f280ff08084f4d6cd77 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 11 Jan 2016 18:03:02 -0800 Subject: [PATCH 43/95] Migrate to block comments --- atom/browser/api/lib/app.coffee | 15 +-- atom/browser/api/lib/auto-updater.coffee | 2 +- .../lib/auto-updater/auto-updater-win.coffee | 8 +- .../auto-updater/squirrel-update-win.coffee | 30 +++-- atom/browser/api/lib/browser-window.coffee | 43 ++++--- atom/browser/api/lib/dialog.coffee | 8 +- atom/browser/api/lib/exports/electron.coffee | 6 +- atom/browser/api/lib/ipc.coffee | 2 +- atom/browser/api/lib/menu-item.coffee | 6 +- atom/browser/api/lib/menu.coffee | 33 ++--- .../api/lib/navigation-controller.coffee | 31 +++-- atom/browser/api/lib/protocol.coffee | 2 +- atom/browser/api/lib/session.coffee | 6 +- atom/browser/api/lib/tray.coffee | 5 +- atom/browser/api/lib/web-contents.coffee | 28 +++-- atom/browser/lib/chrome-extension.coffee | 24 ++-- atom/browser/lib/desktop-capturer.coffee | 18 +-- atom/browser/lib/guest-view-manager.coffee | 39 +++--- atom/browser/lib/guest-window-manager.coffee | 22 ++-- atom/browser/lib/init.coffee | 52 ++++---- atom/browser/lib/objects-registry.coffee | 34 ++--- atom/browser/lib/rpc-server.coffee | 48 +++++--- atom/common/api/lib/callbacks-registry.coffee | 8 +- atom/common/api/lib/clipboard.coffee | 2 +- atom/common/api/lib/crash-reporter.coffee | 2 +- atom/common/api/lib/deprecate.coffee | 17 +-- atom/common/api/lib/exports/electron.coffee | 12 +- atom/common/api/lib/native-image.coffee | 2 +- atom/common/lib/asar.coffee | 46 ++++--- atom/common/lib/asar_init.coffee | 6 +- atom/common/lib/init.coffee | 26 ++-- atom/common/lib/reset-search-paths.coffee | 10 +- atom/renderer/api/lib/desktop-capturer.coffee | 2 +- atom/renderer/api/lib/exports/electron.coffee | 4 +- atom/renderer/api/lib/ipc-renderer.coffee | 2 +- atom/renderer/api/lib/ipc.coffee | 6 +- atom/renderer/api/lib/remote.coffee | 88 +++++++------ atom/renderer/api/lib/web-frame.coffee | 2 +- atom/renderer/lib/init.coffee | 44 +++---- atom/renderer/lib/inspector.coffee | 6 +- atom/renderer/lib/override.coffee | 28 ++--- .../lib/web-view/web-view-attributes.coffee | 78 +++++++----- .../lib/web-view/web-view-constants.coffee | 6 +- atom/renderer/lib/web-view/web-view.coffee | 116 ++++++++++-------- 44 files changed, 538 insertions(+), 437 deletions(-) diff --git a/atom/browser/api/lib/app.coffee b/atom/browser/api/lib/app.coffee index d0ec41c4d23c..fa9df9d9c70a 100644 --- a/atom/browser/api/lib/app.coffee +++ b/atom/browser/api/lib/app.coffee @@ -34,13 +34,13 @@ app.setAppPath = (path) -> app.getAppPath = -> appPath -# Routes the events to webContents. +### Routes the events to webContents. ### for name in ['login', 'certificate-error', 'select-client-certificate'] do (name) -> app.on name, (event, webContents, args...) -> webContents.emit name, event, args... -# Deprecated. +### Deprecated. ### app.getHomeDir = deprecate 'app.getHomeDir', 'app.getPath', -> @getPath 'home' app.getDataPath = deprecate 'app.getDataPath', 'app.getPath', -> @@ -51,22 +51,23 @@ app.resolveProxy = deprecate 'app.resolveProxy', 'session.defaultSession.resolve session.defaultSession.resolveProxy url, callback deprecate.rename app, 'terminate', 'quit' deprecate.event app, 'finish-launching', 'ready', -> - setImmediate => # give default app a chance to setup default menu. + ### give default app a chance to setup default menu. ### + setImmediate => @emit 'finish-launching' deprecate.event app, 'activate-with-no-open-windows', 'activate', (event, hasVisibleWindows) -> @emit 'activate-with-no-open-windows', event if not hasVisibleWindows deprecate.event app, 'select-certificate', 'select-client-certificate' -# Wrappers for native classes. +### Wrappers for native classes. ### wrapDownloadItem = (downloadItem) -> - # downloadItem is an EventEmitter. + ### downloadItem is an EventEmitter. ### downloadItem.__proto__ = EventEmitter.prototype - # Deprecated. + ### Deprecated. ### deprecate.property downloadItem, 'url', 'getURL' deprecate.property downloadItem, 'filename', 'getFilename' deprecate.property downloadItem, 'mimeType', 'getMimeType' deprecate.rename downloadItem, 'getUrl', 'getURL' downloadItemBindings._setWrapDownloadItem wrapDownloadItem -# Only one App object pemitted. +### Only one App object pemitted. ### module.exports = app diff --git a/atom/browser/api/lib/auto-updater.coffee b/atom/browser/api/lib/auto-updater.coffee index 28df59fbc3db..5cb75832c755 100644 --- a/atom/browser/api/lib/auto-updater.coffee +++ b/atom/browser/api/lib/auto-updater.coffee @@ -6,7 +6,7 @@ autoUpdater = else require './auto-updater/auto-updater-native' -# Deprecated. +### Deprecated. ### deprecate.rename autoUpdater, 'setFeedUrl', 'setFeedURL' module.exports = autoUpdater diff --git a/atom/browser/api/lib/auto-updater/auto-updater-win.coffee b/atom/browser/api/lib/auto-updater/auto-updater-win.coffee index e7cb194ffcf4..6d1caecb6bcb 100644 --- a/atom/browser/api/lib/auto-updater/auto-updater-win.coffee +++ b/atom/browser/api/lib/auto-updater/auto-updater-win.coffee @@ -28,14 +28,16 @@ class AutoUpdater extends EventEmitter return @emitError error if error? {releaseNotes, version} = update - # Following information is not available on Windows, so fake them. + ### Following information is not available on Windows, so fake them. ### date = new Date url = @updateURL @emit 'update-downloaded', {}, releaseNotes, version, date, url, => @quitAndInstall() - # Private: Emit both error object and message, this is to keep compatibility - # with Old APIs. + ### + Private: Emit both error object and message, this is to keep compatibility + with Old APIs. + ### emitError: (message) -> @emit 'error', new Error(message), message diff --git a/atom/browser/api/lib/auto-updater/squirrel-update-win.coffee b/atom/browser/api/lib/auto-updater/squirrel-update-win.coffee index ee914c4fa827..5c4342b0ff48 100644 --- a/atom/browser/api/lib/auto-updater/squirrel-update-win.coffee +++ b/atom/browser/api/lib/auto-updater/squirrel-update-win.coffee @@ -2,17 +2,21 @@ fs = require 'fs' path = require 'path' {spawn} = require 'child_process' -appFolder = path.dirname process.execPath # i.e. my-app/app-0.1.13/ -updateExe = path.resolve appFolder, '..', 'Update.exe' # i.e. my-app/Update.exe +### i.e. my-app/app-0.1.13/ ### +appFolder = path.dirname process.execPath +### i.e. my-app/Update.exe ### +updateExe = path.resolve appFolder, '..', 'Update.exe' exeName = path.basename process.execPath -# Spawn a command and invoke the callback when it completes with an error -# and the output from standard out. +### + Spawn a command and invoke the callback when it completes with an error + and the output from standard out. +### spawnUpdate = (args, detached, callback) -> try spawnedProcess = spawn updateExe, args, {detached} catch error - # Shouldn't happen, but still guard it. + ### Shouldn't happen, but still guard it. ### process.nextTick -> callback error return @@ -26,27 +30,27 @@ spawnUpdate = (args, detached, callback) -> errorEmitted = true callback error spawnedProcess.on 'exit', (code, signal) -> - # We may have already emitted an error. + ### We may have already emitted an error. ### return if errorEmitted - # Process terminated with error. + ### Process terminated with error. ### if code isnt 0 return callback "Command failed: #{signal ? code}\n#{stderr}" - # Success. + ### Success. ### callback null, stdout -# Start an instance of the installed app. +### Start an instance of the installed app. ### exports.processStart = (callback) -> spawnUpdate ['--processStart', exeName], true, -> -# Download the releases specified by the URL and write new results to stdout. +### Download the releases specified by the URL and write new results to stdout. ### exports.download = (updateURL, callback) -> spawnUpdate ['--download', updateURL], false, (error, stdout) -> return callback(error) if error? try - # Last line of output is the JSON details about the releases + ### Last line of output is the JSON details about the releases ### json = stdout.trim().split('\n').pop() update = JSON.parse(json)?.releasesToApply?.pop?() catch @@ -54,11 +58,11 @@ exports.download = (updateURL, callback) -> callback null, update -# Update the application to the latest remote version specified by URL. +### Update the application to the latest remote version specified by URL. ### exports.update = (updateURL, callback) -> spawnUpdate ['--update', updateURL], false, callback -# Is the Update.exe installed with the current application? +### Is the Update.exe installed with the current application? ### exports.supported = -> try fs.accessSync updateExe, fs.R_OK diff --git a/atom/browser/api/lib/browser-window.coffee b/atom/browser/api/lib/browser-window.coffee index aa3bd022722c..dd54f939df6f 100644 --- a/atom/browser/api/lib/browser-window.coffee +++ b/atom/browser/api/lib/browser-window.coffee @@ -5,56 +5,61 @@ BrowserWindow::__proto__ = EventEmitter.prototype BrowserWindow::_init = -> - {app} = require 'electron' # avoid recursive require. + ### avoid recursive require. ### + {app} = require 'electron' - # Simulate the application menu on platforms other than OS X. + ### Simulate the application menu on platforms other than OS X. ### if process.platform isnt 'darwin' menu = app.getApplicationMenu() @setMenu menu if menu? - # Make new windows requested by links behave like "window.open" + ### Make new windows requested by links behave like "window.open" ### @webContents.on '-new-window', (event, url, frameName) -> options = show: true, width: 800, height: 600 ipcMain.emit 'ATOM_SHELL_GUEST_WINDOW_MANAGER_WINDOW_OPEN', event, url, frameName, options - # window.resizeTo(...) - # window.moveTo(...) + ### + window.resizeTo(...) + window.moveTo(...) + ### @webContents.on 'move', (event, size) => @setBounds size - # Hide the auto-hide menu when webContents is focused. + ### Hide the auto-hide menu when webContents is focused. ### @webContents.on 'activate', => if process.platform isnt 'darwin' and @isMenuBarAutoHide() and @isMenuBarVisible() @setMenuBarVisibility false - # Forward the crashed event. + ### Forward the crashed event. ### @webContents.on 'crashed', => @emit 'crashed' - # Change window title to page title. + ### Change window title to page title. ### @webContents.on 'page-title-updated', (event, title, explicitSet) => @emit 'page-title-updated', event, title @setTitle title unless event.defaultPrevented - # Sometimes the webContents doesn't get focus when window is shown, so we have - # to force focusing on webContents in this case. The safest way is to focus it - # when we first start to load URL, if we do it earlier it won't have effect, - # if we do it later we might move focus in the page. - # Though this hack is only needed on OS X when the app is launched from - # Finder, we still do it on all platforms in case of other bugs we don't know. + ### + Sometimes the webContents doesn't get focus when window is shown, so we have + to force focusing on webContents in this case. The safest way is to focus it + when we first start to load URL, if we do it earlier it won't have effect, + if we do it later we might move focus in the page. + Though this hack is only needed on OS X when the app is launched from + Finder, we still do it on all platforms in case of other bugs we don't know. + ### @webContents.once 'load-url', -> @focus() - # Redirect focus/blur event to app instance too. + ### Redirect focus/blur event to app instance too. ### @on 'blur', (event) => app.emit 'browser-window-blur', event, this @on 'focus', (event) => app.emit 'browser-window-focus', event, this - # Notify the creation of the window. + ### Notify the creation of the window. ### app.emit 'browser-window-created', {}, this - # Be compatible with old APIs. + ### Be compatible with old APIs. ### @webContents.on 'devtools-focused', => @emit 'devtools-focused' @webContents.on 'devtools-opened', => @emit 'devtools-opened' @webContents.on 'devtools-closed', => @emit 'devtools-closed' @@ -76,7 +81,7 @@ BrowserWindow.fromDevToolsWebContents = (webContents) -> windows = BrowserWindow.getAllWindows() return window for window in windows when window.devToolsWebContents?.equal webContents -# Helpers. +### Helpers. ### BrowserWindow::loadURL = -> @webContents.loadURL.apply @webContents, arguments BrowserWindow::getURL = -> @webContents.getURL() BrowserWindow::reload = -> @webContents.reload.apply @webContents, arguments @@ -89,7 +94,7 @@ BrowserWindow::toggleDevTools = -> @webContents.toggleDevTools() BrowserWindow::inspectElement = -> @webContents.inspectElement.apply @webContents, arguments BrowserWindow::inspectServiceWorker = -> @webContents.inspectServiceWorker() -# Deprecated. +### Deprecated. ### deprecate.member BrowserWindow, 'undo', 'webContents' deprecate.member BrowserWindow, 'redo', 'webContents' deprecate.member BrowserWindow, 'cut', 'webContents' diff --git a/atom/browser/api/lib/dialog.coffee b/atom/browser/api/lib/dialog.coffee index 2daf346db468..98e613bbaab6 100644 --- a/atom/browser/api/lib/dialog.coffee +++ b/atom/browser/api/lib/dialog.coffee @@ -16,12 +16,12 @@ messageBoxOptions = parseArgs = (window, options, callback) -> unless window is null or window?.constructor is BrowserWindow - # Shift. + ### Shift. ### callback = options options = window window = null if not callback? and typeof options is 'function' - # Shift. + ### Shift. ### callback = options options = null [window, options, callback] @@ -97,7 +97,7 @@ module.exports = options.icon ?= null options.defaultId ?= -1 - # Choose a default button to get selected when dialog is cancelled. + ### Choose a default button to get selected when dialog is cancelled. ### unless options.cancelId? options.cancelId = 0 for text, i in options.buttons @@ -122,6 +122,6 @@ module.exports = showErrorBox: (args...) -> binding.showErrorBox args... -# Mark standard asynchronous functions. +### Mark standard asynchronous functions. ### for api in ['showMessageBox', 'showOpenDialog', 'showSaveDialog'] v8Util.setHiddenValue module.exports[api], 'asynchronous', true diff --git a/atom/browser/api/lib/exports/electron.coffee b/atom/browser/api/lib/exports/electron.coffee index 9c61a5507061..48ff349a29a3 100644 --- a/atom/browser/api/lib/exports/electron.coffee +++ b/atom/browser/api/lib/exports/electron.coffee @@ -1,10 +1,10 @@ common = require '../../../../common/api/lib/exports/electron' -# Import common modules. +### Import common modules. ### common.defineProperties exports Object.defineProperties exports, - # Browser side modules, please sort with alphabet order. + ### Browser side modules, please sort with alphabet order. ### app: enumerable: true get: -> require '../app' @@ -50,7 +50,7 @@ Object.defineProperties exports, Tray: enumerable: true get: -> require '../tray' - # The internal modules, invisible unless you know their names. + ### The internal modules, invisible unless you know their names. ### NavigationController: get: -> require '../navigation-controller' webContents: diff --git a/atom/browser/api/lib/ipc.coffee b/atom/browser/api/lib/ipc.coffee index 018cb6bb0437..348c7d0cd459 100644 --- a/atom/browser/api/lib/ipc.coffee +++ b/atom/browser/api/lib/ipc.coffee @@ -1,6 +1,6 @@ {deprecate, ipcMain} = require 'electron' -# This module is deprecated, we mirror everything from ipcMain. +### This module is deprecated, we mirror everything from ipcMain. ### deprecate.warn 'ipc module', 'require("electron").ipcMain' module.exports = ipcMain diff --git a/atom/browser/api/lib/menu-item.coffee b/atom/browser/api/lib/menu-item.coffee index 242a48f54d88..ab225d30095c 100644 --- a/atom/browser/api/lib/menu-item.coffee +++ b/atom/browser/api/lib/menu-item.coffee @@ -2,7 +2,7 @@ v8Util = process.atomBinding 'v8_util' nextCommandId = 0 -# Maps role to methods of webContents +### Maps role to methods of webContents ### rolesMap = undo: 'undo' redo: 'redo' @@ -13,7 +13,7 @@ rolesMap = minimize: 'minimize' close: 'close' -# Maps methods that should be called directly on the BrowserWindow instance +### Maps methods that should be called directly on the BrowserWindow instance ### methodInBrowserWindow = minimize: true close: true @@ -46,7 +46,7 @@ class MenuItem @commandId = ++nextCommandId @click = (focusedWindow) => - # Manually flip the checked flags when clicked. + ### Manually flip the checked flags when clicked. ### @checked = !@checked if @type in ['checkbox', 'radio'] if @role and rolesMap[@role] and process.platform isnt 'darwin' and focusedWindow? diff --git a/atom/browser/api/lib/menu.coffee b/atom/browser/api/lib/menu.coffee index d81c345f43a0..d987f304262c 100644 --- a/atom/browser/api/lib/menu.coffee +++ b/atom/browser/api/lib/menu.coffee @@ -4,11 +4,11 @@ v8Util = process.atomBinding 'v8_util' bindings = process.atomBinding 'menu' -# Automatically generated radio menu item's group id. +### Automatically generated radio menu item's group id. ### nextGroupId = 0 -# Search between seperators to find a radio menu item and return its group id, -# otherwise generate a group id. +### Search between seperators to find a radio menu item and return its group id, ### +### otherwise generate a group id. ### generateGroupId = (items, pos) -> if pos > 0 for i in [pos - 1..0] @@ -22,12 +22,12 @@ generateGroupId = (items, pos) -> break if item.type is 'separator' ++nextGroupId -# Returns the index of item according to |id|. +### Returns the index of item according to |id|. ### indexOfItemById = (items, id) -> return i for item, i in items when item.id is id -1 -# Returns the index of where to insert the item according to |position|. +### Returns the index of where to insert the item according to |position|. ### indexToInsertByPosition = (items, position) -> return items.length unless position @@ -41,12 +41,12 @@ indexToInsertByPosition = (items, position) -> when 'after' insertIndex++ when 'endof' - # If the |id| doesn't exist, then create a new group with the |id|. + ### If the |id| doesn't exist, then create a new group with the |id|. ### if insertIndex is -1 items.push id: id, type: 'separator' insertIndex = items.length - 1 - # Find the end of the group. + ### Find the end of the group. ### insertIndex++ while insertIndex < items.length and items[insertIndex].type isnt 'separator' insertIndex++ @@ -69,7 +69,7 @@ Menu::_init = -> executeCommand: (commandId) => @commandsMap[commandId]?.click BrowserWindow.getFocusedWindow() menuWillShow: => - # Make sure radio groups have at least one menu item seleted. + ### Make sure radio groups have at least one menu item seleted. ### for id, group of @groupsMap checked = false for radioItem in group when radioItem.checked @@ -79,7 +79,7 @@ Menu::_init = -> Menu::popup = (window, x, y) -> unless window?.constructor is BrowserWindow - # Shift. + ### Shift. ### y = x x = window window = BrowserWindow.getFocusedWindow() @@ -100,12 +100,12 @@ Menu::insert = (pos, item) -> when 'separator' then @insertSeparator pos when 'submenu' then @insertSubMenu pos, item.commandId, item.label, item.submenu when 'radio' - # Grouping radio menu items. + ### Grouping radio menu items. ### item.overrideReadOnlyProperty 'groupId', generateGroupId(@items, pos) @groupsMap[item.groupId] ?= [] @groupsMap[item.groupId].push item - # Setting a radio menu item should flip other items in the group. + ### Setting a radio menu item should flip other items in the group. ### v8Util.setHiddenValue item, 'checked', item.checked Object.defineProperty item, 'checked', enumerable: true @@ -121,14 +121,14 @@ Menu::insert = (pos, item) -> @setIcon pos, item.icon if item.icon? @setRole pos, item.role if item.role? - # Make menu accessable to items. + ### Make menu accessable to items. ### item.overrideReadOnlyProperty 'menu', this - # Remember the items. + ### Remember the items. ### @items.splice pos, 0, item @commandsMap[item.commandId] = item -# Force menuWillShow to be called +### Force menuWillShow to be called ### Menu::_callMenuWillShow = -> @delegate?.menuWillShow() item.submenu._callMenuWillShow() for item in @items when item.submenu? @@ -136,7 +136,8 @@ Menu::_callMenuWillShow = -> applicationMenu = null Menu.setApplicationMenu = (menu) -> throw new TypeError('Invalid menu') unless menu is null or menu.constructor is Menu - applicationMenu = menu # Keep a reference. + ### Keep a reference. ### + applicationMenu = menu if process.platform is 'darwin' return if menu is null @@ -160,7 +161,7 @@ Menu.buildFromTemplate = (template) -> if item.position insertIndex = indexToInsertByPosition positionedTemplate, item.position else - # If no |position| is specified, insert after last item. + ### If no |position| is specified, insert after last item. ### insertIndex++ positionedTemplate.splice insertIndex, 0, item diff --git a/atom/browser/api/lib/navigation-controller.coffee b/atom/browser/api/lib/navigation-controller.coffee index d0c539a99db5..3c7ef2492a8b 100644 --- a/atom/browser/api/lib/navigation-controller.coffee +++ b/atom/browser/api/lib/navigation-controller.coffee @@ -1,42 +1,47 @@ {ipcMain} = require 'electron' -# The history operation in renderer is redirected to browser. +### The history operation in renderer is redirected to browser. ### ipcMain.on 'ATOM_SHELL_NAVIGATION_CONTROLLER', (event, method, args...) -> event.sender[method] args... ipcMain.on 'ATOM_SHELL_SYNC_NAVIGATION_CONTROLLER', (event, method, args...) -> event.returnValue = event.sender[method] args... -# JavaScript implementation of Chromium's NavigationController. -# Instead of relying on Chromium for history control, we compeletely do history -# control on user land, and only rely on WebContents.loadURL for navigation. -# This helps us avoid Chromium's various optimizations so we can ensure renderer -# process is restarted everytime. +### + JavaScript implementation of Chromium's NavigationController. + Instead of relying on Chromium for history control, we compeletely do history + control on user land, and only rely on WebContents.loadURL for navigation. + This helps us avoid Chromium's various optimizations so we can ensure renderer + process is restarted everytime. +### class NavigationController constructor: (@webContents) -> @clearHistory() - # webContents may have already navigated to a page. + ### webContents may have already navigated to a page. ### if @webContents._getURL() @currentIndex++ @history.push @webContents._getURL() @webContents.on 'navigation-entry-commited', (event, url, inPage, replaceEntry) => if @inPageIndex > -1 and not inPage - # Navigated to a new page, clear in-page mark. + ### Navigated to a new page, clear in-page mark. ### @inPageIndex = -1 else if @inPageIndex is -1 and inPage - # Started in-page navigations. + ### Started in-page navigations. ### @inPageIndex = @currentIndex - if @pendingIndex >= 0 # Go to index. + if @pendingIndex >= 0 + ### Go to index. ### @currentIndex = @pendingIndex @pendingIndex = -1 @history[@currentIndex] = url - else if replaceEntry # Non-user initialized navigation. + else if replaceEntry + ### Non-user initialized navigation. ### @history[@currentIndex] = url - else # Normal navigation. - @history = @history.slice 0, @currentIndex + 1 # Clear history. + else + ### Normal navigation. Clear history. ### + @history = @history.slice 0, @currentIndex + 1 currentEntry = @history[@currentIndex] if currentEntry?.url isnt url @currentIndex++ diff --git a/atom/browser/api/lib/protocol.coffee b/atom/browser/api/lib/protocol.coffee index a1dbc7c17d75..1add325eaae0 100644 --- a/atom/browser/api/lib/protocol.coffee +++ b/atom/browser/api/lib/protocol.coffee @@ -4,7 +4,7 @@ throw new Error('Can not initialize protocol module before app is ready') unless {protocol} = process.atomBinding 'protocol' -# Warn about removed APIs. +### Warn about removed APIs. ### logAndThrow = (callback, message) -> console.error message if callback then callback(new Error(message)) else throw new Error(message) diff --git a/atom/browser/api/lib/session.coffee b/atom/browser/api/lib/session.coffee index 5c65aa29cf6a..95f9e474e090 100644 --- a/atom/browser/api/lib/session.coffee +++ b/atom/browser/api/lib/session.coffee @@ -4,7 +4,7 @@ bindings = process.atomBinding 'session' PERSIST_PERFIX = 'persist:' -# Returns the Session from |partition| string. +### Returns the Session from |partition| string. ### exports.fromPartition = (partition='') -> return exports.defaultSession if partition is '' if partition.startsWith PERSIST_PERFIX @@ -12,13 +12,13 @@ exports.fromPartition = (partition='') -> else bindings.fromPartition partition, true -# Returns the default session. +### Returns the default session. ### Object.defineProperty exports, 'defaultSession', enumerable: true get: -> bindings.fromPartition '', false wrapSession = (session) -> - # session is an EventEmitter. + ### session is an EventEmitter. ### session.__proto__ = EventEmitter.prototype bindings._setWrapSession wrapSession diff --git a/atom/browser/api/lib/tray.coffee b/atom/browser/api/lib/tray.coffee index db26ab5b7ed1..70a423dd97d5 100644 --- a/atom/browser/api/lib/tray.coffee +++ b/atom/browser/api/lib/tray.coffee @@ -5,7 +5,7 @@ Tray::__proto__ = EventEmitter.prototype Tray::_init = -> - # Deprecated. + ### Deprecated. ### deprecate.rename this, 'popContextMenu', 'popUpContextMenu' deprecate.event this, 'clicked', 'click' deprecate.event this, 'double-clicked', 'double-click' @@ -14,6 +14,7 @@ Tray::_init = -> Tray::setContextMenu = (menu) -> @_setContextMenu menu - @menu = menu # Keep a strong reference of menu. + ### Keep a strong reference of menu. ### + @menu = menu module.exports = Tray diff --git a/atom/browser/api/lib/web-contents.coffee b/atom/browser/api/lib/web-contents.coffee index 2eda00f0689d..75e35c4fdc49 100644 --- a/atom/browser/api/lib/web-contents.coffee +++ b/atom/browser/api/lib/web-contents.coffee @@ -40,28 +40,30 @@ PDFPageSize = custom_display_name: "Tabloid" wrapWebContents = (webContents) -> - # webContents is an EventEmitter. + ### webContents is an EventEmitter. ### webContents.__proto__ = EventEmitter.prototype - # WebContents::send(channel, args..) + ### WebContents::send(channel, args..) ### webContents.send = (channel, args...) -> @_send channel, [args...] - # Make sure webContents.executeJavaScript would run the code only when the - # web contents has been loaded. + ### + Make sure webContents.executeJavaScript would run the code only when the + web contents has been loaded. + ### webContents.executeJavaScript = (code, hasUserGesture=false) -> if @getURL() and not @isLoading() @_executeJavaScript code, hasUserGesture else webContents.once 'did-finish-load', @_executeJavaScript.bind(this, code, hasUserGesture) - # The navigation controller. + ### The navigation controller. ### controller = new NavigationController(webContents) for name, method of NavigationController.prototype when method instanceof Function do (name, method) -> webContents[name] = -> method.apply controller, arguments - # Dispatch IPC messages to the ipc module. + ### Dispatch IPC messages to the ipc module. ### webContents.on 'ipc-message', (event, packed) -> [channel, args...] = packed ipcMain.emit channel, event, args... @@ -70,22 +72,24 @@ wrapWebContents = (webContents) -> Object.defineProperty event, 'returnValue', set: (value) -> event.sendReply JSON.stringify(value) ipcMain.emit channel, event, args... - # Handle context menu action request from pepper plugin. + ### Handle context menu action request from pepper plugin. ### webContents.on 'pepper-context-menu', (event, params) -> menu = Menu.buildFromTemplate params.menu menu.popup params.x, params.y - # This error occurs when host could not be found. + ### This error occurs when host could not be found. ### webContents.on 'did-fail-provisional-load', (args...) -> - # Calling loadURL during this event might cause crash, so delay the event - # until next tick. + ### + Calling loadURL during this event might cause crash, so delay the event + until next tick. + ### setImmediate => @emit 'did-fail-load', args... - # Delays the page-title-updated event to next tick. + ### Delays the page-title-updated event to next tick. ### webContents.on '-page-title-updated', (args...) -> setImmediate => @emit 'page-title-updated', args... - # Deprecated. + ### Deprecated. ### deprecate.rename webContents, 'loadUrl', 'loadURL' deprecate.rename webContents, 'getUrl', 'getURL' deprecate.event webContents, 'page-title-set', 'page-title-updated', (args...) -> diff --git a/atom/browser/lib/chrome-extension.coffee b/atom/browser/lib/chrome-extension.coffee index 931b8168961e..d20e4c3d5e85 100644 --- a/atom/browser/lib/chrome-extension.coffee +++ b/atom/browser/lib/chrome-extension.coffee @@ -3,7 +3,7 @@ fs = require 'fs' path = require 'path' url = require 'url' -# Mapping between hostname and file path. +### Mapping between hostname and file path. ### hostPathMap = {} hostPathMapNextKey = 0 @@ -15,14 +15,16 @@ getHostForPath = (path) -> getPathForHost = (host) -> hostPathMap[host] -# Cache extensionInfo. +### Cache extensionInfo. ### extensionInfoMap = {} getExtensionInfoFromPath = (srcDirectory) -> manifest = JSON.parse fs.readFileSync(path.join(srcDirectory, 'manifest.json')) unless extensionInfoMap[manifest.name]? - # We can not use 'file://' directly because all resources in the extension - # will be treated as relative to the root in Chrome. + ### + We can not use 'file://' directly because all resources in the extension + will be treated as relative to the root in Chrome. + ### page = url.format protocol: 'chrome-extension' slashes: true @@ -35,11 +37,11 @@ getExtensionInfoFromPath = (srcDirectory) -> exposeExperimentalAPIs: true extensionInfoMap[manifest.name] -# The loaded extensions cache and its persistent path. +### The loaded extensions cache and its persistent path. ### loadedExtensions = null loadedExtensionsPath = null -# Persistent loaded extensions. +### Persistent loaded extensions. ### {app} = electron app.on 'will-quit', -> try @@ -50,21 +52,21 @@ app.on 'will-quit', -> fs.writeFileSync loadedExtensionsPath, JSON.stringify(loadedExtensions) catch e -# We can not use protocol or BrowserWindow until app is ready. +### We can not use protocol or BrowserWindow until app is ready. ### app.once 'ready', -> {protocol, BrowserWindow} = electron - # Load persistented extensions. + ### Load persistented extensions. ### loadedExtensionsPath = path.join app.getPath('userData'), 'DevTools Extensions' try loadedExtensions = JSON.parse fs.readFileSync(loadedExtensionsPath) loadedExtensions = [] unless Array.isArray loadedExtensions - # Preheat the extensionInfo cache. + ### Preheat the extensionInfo cache. ### getExtensionInfoFromPath srcDirectory for srcDirectory in loadedExtensions catch e - # The chrome-extension: can map a extension URL request to real file path. + ### The chrome-extension: can map a extension URL request to real file path. ### chromeExtensionHandler = (request, callback) -> parsed = url.parse request.url return callback() unless parsed.hostname and parsed.path? @@ -88,7 +90,7 @@ app.once 'ready', -> BrowserWindow.removeDevToolsExtension = (name) -> delete extensionInfoMap[name] - # Load persistented extensions when devtools is opened. + ### Load persistented extensions when devtools is opened. ### init = BrowserWindow::_init BrowserWindow::_init = -> init.call this diff --git a/atom/browser/lib/desktop-capturer.coffee b/atom/browser/lib/desktop-capturer.coffee index a7fb29ff76ed..f783ccc9f78b 100644 --- a/atom/browser/lib/desktop-capturer.coffee +++ b/atom/browser/lib/desktop-capturer.coffee @@ -4,26 +4,30 @@ deepEqual = (opt1, opt2) -> return JSON.stringify(opt1) is JSON.stringify(opt2) -# A queue for holding all requests from renderer process. +### A queue for holding all requests from renderer process. ### requestsQueue = [] ipcMain.on 'ATOM_BROWSER_DESKTOP_CAPTURER_GET_SOURCES', (event, captureWindow, captureScreen, thumbnailSize, id) -> request = id: id, options: {captureWindow, captureScreen, thumbnailSize}, webContents: event.sender requestsQueue.push request desktopCapturer.startHandling captureWindow, captureScreen, thumbnailSize if requestsQueue.length is 1 - # If the WebContents is destroyed before receiving result, just remove the - # reference from requestsQueue to make the module not send the result to it. + ### + If the WebContents is destroyed before receiving result, just remove the + reference from requestsQueue to make the module not send the result to it. + ### event.sender.once 'destroyed', -> request.webContents = null desktopCapturer.emit = (event, name, sources) -> - # Receiving sources result from main process, now send them back to renderer. + ### Receiving sources result from main process, now send them back to renderer. ### handledRequest = requestsQueue.shift 0 result = ({ id: source.id, name: source.name, thumbnail: source.thumbnail.toDataUrl() } for source in sources) handledRequest.webContents?.send "ATOM_RENDERER_DESKTOP_CAPTURER_RESULT_#{handledRequest.id}", result - # Check the queue to see whether there is other same request. If has, handle - # it for reducing redunplicated `desktopCaptuer.startHandling` calls. + ### + Check the queue to see whether there is other same request. If has, handle + it for reducing redunplicated `desktopCaptuer.startHandling` calls. + ### unhandledRequestsQueue = [] for request in requestsQueue if deepEqual handledRequest.options, request.options @@ -31,7 +35,7 @@ desktopCapturer.emit = (event, name, sources) -> else unhandledRequestsQueue.push request requestsQueue = unhandledRequestsQueue - # If the requestsQueue is not empty, start a new request handling. + ### If the requestsQueue is not empty, start a new request handling. ### if requestsQueue.length > 0 {captureWindow, captureScreen, thumbnailSize} = requestsQueue[0].options desktopCapturer.startHandling captureWindow, captureScreen, thumbnailSize diff --git a/atom/browser/lib/guest-view-manager.coffee b/atom/browser/lib/guest-view-manager.coffee index c99bf5757dc1..037b9a4db2d6 100644 --- a/atom/browser/lib/guest-view-manager.coffee +++ b/atom/browser/lib/guest-view-manager.coffee @@ -1,6 +1,7 @@ {ipcMain, webContents} = require 'electron' -webViewManager = null # Doesn't exist in early initialization. +### Doesn't exist in early initialization. ### +webViewManager = null supportedWebViewEvents = [ 'load-commit' @@ -40,15 +41,15 @@ guestInstances = {} embedderElementsMap = {} reverseEmbedderElementsMap = {} -# Moves the last element of array to the first one. +### Moves the last element of array to the first one. ### moveLastToFirst = (list) -> list.unshift list.pop() -# Generate guestInstanceId. +### Generate guestInstanceId. ### getNextInstanceId = (webContents) -> ++nextInstanceId -# Create a new guest instance. +### Create a new guest instance. ### createGuest = (embedder, params) -> webViewManager ?= process.atomBinding 'web_view_manager' @@ -56,21 +57,23 @@ createGuest = (embedder, params) -> guest = webContents.create {isGuest: true, partition: params.partition, embedder} guestInstances[id] = {guest, embedder} - # Destroy guest when the embedder is gone or navigated. + ### Destroy guest when the embedder is gone or navigated. ### destroyEvents = ['destroyed', 'crashed', 'did-navigate'] destroy = -> destroyGuest embedder, id if guestInstances[id]? for event in destroyEvents embedder.once event, destroy - # Users might also listen to the crashed event, so We must ensure the guest - # is destroyed before users' listener gets called. It is done by moving our - # listener to the first one in queue. + ### + Users might also listen to the crashed event, so We must ensure the guest + is destroyed before users' listener gets called. It is done by moving our + listener to the first one in queue. + ### listeners = embedder._events[event] moveLastToFirst listeners if Array.isArray listeners guest.once 'destroyed', -> embedder.removeListener event, destroy for event in destroyEvents - # Init guest web view after attached. + ### Init guest web view after attached. ### guest.once 'did-attach', -> params = @attachParams delete @attachParams @@ -96,32 +99,32 @@ createGuest = (embedder, params) -> guest.allowPopups = params.allowpopups - # Dispatch events to embedder. + ### Dispatch events to embedder. ### for event in supportedWebViewEvents do (event) -> guest.on event, (_, args...) -> embedder.send "ATOM_SHELL_GUEST_VIEW_INTERNAL_DISPATCH_EVENT-#{guest.viewInstanceId}", event, args... - # Dispatch guest's IPC messages to embedder. + ### Dispatch guest's IPC messages to embedder. ### guest.on 'ipc-message-host', (_, packed) -> [channel, args...] = packed embedder.send "ATOM_SHELL_GUEST_VIEW_INTERNAL_IPC_MESSAGE-#{guest.viewInstanceId}", channel, args... - # Autosize. + ### Autosize. ### guest.on 'size-changed', (_, args...) -> embedder.send "ATOM_SHELL_GUEST_VIEW_INTERNAL_SIZE_CHANGED-#{guest.viewInstanceId}", args... id -# Attach the guest to an element of embedder. +### Attach the guest to an element of embedder. ### attachGuest = (embedder, elementInstanceId, guestInstanceId, params) -> guest = guestInstances[guestInstanceId].guest - # Destroy the old guest when attaching. + ### Destroy the old guest when attaching. ### key = "#{embedder.getId()}-#{elementInstanceId}" oldGuestInstanceId = embedderElementsMap[key] if oldGuestInstanceId? - # Reattachment to the same guest is not currently supported. + ### Reattachment to the same guest is not currently supported. ### return unless oldGuestInstanceId != guestInstanceId return unless guestInstances[oldGuestInstanceId]? @@ -139,7 +142,7 @@ attachGuest = (embedder, elementInstanceId, guestInstanceId, params) -> embedderElementsMap[key] = guestInstanceId reverseEmbedderElementsMap[guestInstanceId] = key -# Destroy an existing guest instance. +### Destroy an existing guest instance. ### destroyGuest = (embedder, id) -> webViewManager.removeGuest embedder, id guestInstances[id].guest.destroy() @@ -165,10 +168,10 @@ ipcMain.on 'ATOM_SHELL_GUEST_VIEW_MANAGER_SET_SIZE', (event, id, params) -> ipcMain.on 'ATOM_SHELL_GUEST_VIEW_MANAGER_SET_ALLOW_TRANSPARENCY', (event, id, allowtransparency) -> guestInstances[id]?.guest.setAllowTransparency allowtransparency -# Returns WebContents from its guest id. +### Returns WebContents from its guest id. ### exports.getGuest = (id) -> guestInstances[id]?.guest -# Returns the embedder of the guest. +### Returns the embedder of the guest. ### exports.getEmbedder = (id) -> guestInstances[id]?.embedder diff --git a/atom/browser/lib/guest-window-manager.coffee b/atom/browser/lib/guest-window-manager.coffee index af73db5c78b8..101bd79951b7 100644 --- a/atom/browser/lib/guest-window-manager.coffee +++ b/atom/browser/lib/guest-window-manager.coffee @@ -3,7 +3,7 @@ v8Util = process.atomBinding 'v8_util' frameToGuest = {} -# Copy attribute of |parent| to |child| if it is not defined in |child|. +### Copy attribute of |parent| to |child| if it is not defined in |child|. ### mergeOptions = (child, parent) -> for own key, value of parent when key not of child if typeof value is 'object' @@ -12,34 +12,36 @@ mergeOptions = (child, parent) -> child[key] = value child -# Merge |options| with the |embedder|'s window's options. +### Merge |options| with the |embedder|'s window's options. ### mergeBrowserWindowOptions = (embedder, options) -> if embedder.browserWindowOptions? - # Inherit the original options if it is a BrowserWindow. + ### Inherit the original options if it is a BrowserWindow. ### mergeOptions options, embedder.browserWindowOptions else - # Or only inherit web-preferences if it is a webview. + ### Or only inherit web-preferences if it is a webview. ### options.webPreferences ?= {} mergeOptions options.webPreferences, embedder.getWebPreferences() options -# Create a new guest created by |embedder| with |options|. +### Create a new guest created by |embedder| with |options|. ### createGuest = (embedder, url, frameName, options) -> guest = frameToGuest[frameName] if frameName and guest? guest.loadURL url return guest.id - # Remember the embedder window's id. + ### Remember the embedder window's id. ### options.webPreferences ?= {} options.webPreferences.openerId = BrowserWindow.fromWebContents(embedder)?.id guest = new BrowserWindow(options) guest.loadURL url - # 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. + ### + 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 @@ -58,7 +60,7 @@ createGuest = (embedder, url, frameName, options) -> guest.id -# Routed window.open messages. +### Routed window.open messages. ### ipcMain.on 'ATOM_SHELL_GUEST_WINDOW_MANAGER_WINDOW_OPEN', (event, args...) -> [url, frameName, options] = args options = mergeBrowserWindowOptions event.sender, options diff --git a/atom/browser/lib/init.coffee b/atom/browser/lib/init.coffee index c3d56d9c7c82..ace81d50148d 100644 --- a/atom/browser/lib/init.coffee +++ b/atom/browser/lib/init.coffee @@ -3,26 +3,28 @@ path = require 'path' util = require 'util' Module = require 'module' -# We modified the original process.argv to let node.js load the atom.js, -# we need to restore it here. +### We modified the original process.argv to let node.js load the atom.js, ### +### we need to restore it here. ### process.argv.splice 1, 1 -# Clear search paths. +### Clear search paths. ### require path.resolve(__dirname, '..', '..', 'common', 'lib', 'reset-search-paths') -# Import common settings. +### Import common settings. ### require path.resolve(__dirname, '..', '..', 'common', 'lib', 'init') globalPaths = Module.globalPaths unless process.env.ELECTRON_HIDE_INTERNAL_MODULES globalPaths.push path.resolve(__dirname, '..', 'api', 'lib') -# Expose public APIs. +### Expose public APIs. ### globalPaths.push path.resolve(__dirname, '..', 'api', 'lib', 'exports') if process.platform is 'win32' - # Redirect node's console to use our own implementations, since node can not - # handle console output when running as GUI program. + ### + Redirect node's console to use our own implementations, since node can not + handle console output when running as GUI program. + ### consoleLog = (args...) -> process.log util.format(args...) + "\n" streamWrite = (chunk, encoding, callback) -> @@ -33,40 +35,40 @@ if process.platform is 'win32' console.log = console.error = console.warn = consoleLog process.stdout.write = process.stderr.write = streamWrite - # Always returns EOF for stdin stream. + ### Always returns EOF for stdin stream. ### Readable = require('stream').Readable stdin = new Readable stdin.push null process.__defineGetter__ 'stdin', -> stdin -# Don't quit on fatal error. +### Don't quit on fatal error. ### process.on 'uncaughtException', (error) -> - # Do nothing if the user has a custom uncaught exception handler. + ### Do nothing if the user has a custom uncaught exception handler. ### if process.listeners('uncaughtException').length > 1 return - # Show error in GUI. + ### Show error in GUI. ### {dialog} = require 'electron' stack = error.stack ? "#{error.name}: #{error.message}" message = "Uncaught Exception:\n#{stack}" dialog.showErrorBox 'A JavaScript error occurred in the main process', message -# Emit 'exit' event on quit. +### Emit 'exit' event on quit. ### {app} = require 'electron' app.on 'quit', (event, exitCode) -> process.emit 'exit', exitCode -# Map process.exit to app.exit, which quits gracefully. +### Map process.exit to app.exit, which quits gracefully. ### process.exit = app.exit -# Load the RPC server. +### Load the RPC server. ### require './rpc-server' -# Load the guest view manager. +### Load the guest view manager. ### require './guest-view-manager' require './guest-window-manager' -# Now we try to load app's package.json. +### Now we try to load app's package.json. ### packageJson = null searchPaths = [ 'app', 'app.asar', 'default_app' ] @@ -82,37 +84,37 @@ unless packageJson? process.nextTick -> process.exit 1 throw new Error("Unable to find a valid app") -# Set application's version. +### Set application's version. ### app.setVersion packageJson.version if packageJson.version? -# Set application's name. +### Set application's name. ### if packageJson.productName? app.setName packageJson.productName else if packageJson.name? app.setName packageJson.name -# Set application's desktop name. +### Set application's desktop name. ### if packageJson.desktopName? app.setDesktopName packageJson.desktopName else app.setDesktopName "#{app.getName()}.desktop" -# Chrome 42 disables NPAPI plugins by default, reenable them here +### Chrome 42 disables NPAPI plugins by default, reenable them here ### app.commandLine.appendSwitch 'enable-npapi' -# Set the user path according to application's name. +### Set the user path according to application's name. ### app.setPath 'userData', path.join(app.getPath('appData'), app.getName()) app.setPath 'userCache', path.join(app.getPath('cache'), app.getName()) app.setAppPath packagePath -# Load the chrome extension support. +### Load the chrome extension support. ### require './chrome-extension' -# Load internal desktop-capturer module. +### Load internal desktop-capturer module. ### require './desktop-capturer' -# Set main startup script of the app. +### Set main startup script of the app. ### mainStartupScript = packageJson.main or 'index.js' -# Finally load app's main.js and transfer control to C++. +### Finally load app's main.js and transfer control to C++. ### Module._load path.join(packagePath, mainStartupScript), Module, true diff --git a/atom/browser/lib/objects-registry.coffee b/atom/browser/lib/objects-registry.coffee index 53b00ed7f82b..661ee4958a1b 100644 --- a/atom/browser/lib/objects-registry.coffee +++ b/atom/browser/lib/objects-registry.coffee @@ -6,46 +6,52 @@ class ObjectsRegistry extends EventEmitter @setMaxListeners Number.MAX_VALUE @nextId = 0 - # Stores all objects by ref-counting. - # (id) => {object, count} + ### + Stores all objects by ref-counting. + (id) => {object, count} + ### @storage = {} - # Stores the IDs of objects referenced by WebContents. - # (webContentsId) => {(id) => (count)} + ### + Stores the IDs of objects referenced by WebContents. + (webContentsId) => {(id) => (count)} + ### @owners = {} - # Register a new object, the object would be kept referenced until you release - # it explicitly. + ### + Register a new object, the object would be kept referenced until you release + it explicitly. + ### add: (webContentsId, obj) -> id = @saveToStorage obj - # Remember the owner. + ### Remember the owner. ### @owners[webContentsId] ?= {} @owners[webContentsId][id] ?= 0 @owners[webContentsId][id]++ - # Returns object's id + ### Returns object's id ### id - # Get an object according to its ID. + ### Get an object according to its ID. ### get: (id) -> @storage[id]?.object - # Dereference an object according to its ID. + ### Dereference an object according to its ID. ### remove: (webContentsId, id) -> @dereference id, 1 - # Also reduce the count in owner. + ### Also reduce the count in owner. ### pointer = @owners[webContentsId] return unless pointer? --pointer[id] delete pointer[id] if pointer[id] is 0 - # Clear all references to objects refrenced by the WebContents. + ### Clear all references to objects refrenced by the WebContents. ### clear: (webContentsId) -> @emit "clear-#{webContentsId}" return unless @owners[webContentsId]? @dereference id, count for id, count of @owners[webContentsId] delete @owners[webContentsId] - # Private: Saves the object into storage and assigns an ID for it. + ### Private: Saves the object into storage and assigns an ID for it. ### saveToStorage: (object) -> id = v8Util.getHiddenValue object, 'atomId' unless id @@ -55,7 +61,7 @@ class ObjectsRegistry extends EventEmitter ++@storage[id].count id - # Private: Dereference the object from store. + ### Private: Dereference the object from store. ### dereference: (id, count) -> pointer = @storage[id] return unless pointer? diff --git a/atom/browser/lib/rpc-server.coffee b/atom/browser/lib/rpc-server.coffee index 7b05fa3d14ca..7880c6ce4a33 100644 --- a/atom/browser/lib/rpc-server.coffee +++ b/atom/browser/lib/rpc-server.coffee @@ -7,7 +7,7 @@ objectsRegistry = require './objects-registry' v8Util = process.atomBinding 'v8_util' {IDWeakMap} = process.atomBinding 'id_weak_map' -# Convert a real value into meta data. +### Convert a real value into meta data. ### valueToMeta = (sender, value, optimizeSimpleObject=false) -> meta = type: typeof value @@ -18,11 +18,11 @@ valueToMeta = (sender, value, optimizeSimpleObject=false) -> meta.type = 'date' if value instanceof Date meta.type = 'promise' if value?.constructor.name is 'Promise' - # Treat simple objects as value. + ### Treat simple objects as value. ### if optimizeSimpleObject and meta.type is 'object' and v8Util.getHiddenValue value, 'simple' meta.type = 'value' - # Treat the arguments object as array. + ### Treat the arguments object as array. ### meta.type = 'array' if meta.type is 'object' and value.callee? and value.length? if meta.type is 'array' @@ -31,9 +31,11 @@ valueToMeta = (sender, value, optimizeSimpleObject=false) -> else if meta.type is 'object' or meta.type is 'function' meta.name = value.constructor.name - # Reference the original value if it's an object, because when it's - # passed to renderer we would assume the renderer keeps a reference of - # it. + ### + Reference the original value if it's an object, because when it's + passed to renderer we would assume the renderer keeps a reference of + it. + ### meta.id = objectsRegistry.add sender.getId(), value meta.members = ({name, type: typeof field} for name, field of value) @@ -43,7 +45,7 @@ valueToMeta = (sender, value, optimizeSimpleObject=false) -> meta.then = valueToMeta sender, value.then.bind(value) else if meta.type is 'error' meta.members = plainObjectToMeta value - # Error.name is not part of own properties. + ### Error.name is not part of own properties. ### meta.members.push {name: 'name', value: value.name} else if meta.type is 'date' meta.value = value.getTime() @@ -53,15 +55,15 @@ valueToMeta = (sender, value, optimizeSimpleObject=false) -> meta -# Convert object to meta by value. +### Convert object to meta by value. ### plainObjectToMeta = (obj) -> Object.getOwnPropertyNames(obj).map (name) -> {name, value: obj[name]} -# Convert Error into meta data. +### Convert Error into meta data. ### exceptionToMeta = (error) -> type: 'exception', message: error.message, stack: (error.stack || error) -# Convert array of meta data from renderer into array of real values. +### Convert array of meta data from renderer into array of real values. ### unwrapArgs = (sender, args) -> metaToValue = (meta) -> switch meta.type @@ -80,7 +82,7 @@ unwrapArgs = (sender, args) -> returnValue = metaToValue meta.value -> returnValue when 'function' - # Cache the callbacks in renderer. + ### Cache the callbacks in renderer. ### unless sender.callbacks sender.callbacks = new IDWeakMap sender.on 'render-view-deleted', -> @@ -106,8 +108,10 @@ unwrapArgs = (sender, args) -> args.map metaToValue -# Call a function and send reply asynchronously if it's a an asynchronous -# style function and the caller didn't pass a callback. +### + Call a function and send reply asynchronously if it's a an asynchronous + style function and the caller didn't pass a callback. +### callFunction = (event, func, caller, args) -> funcMarkedAsync = v8Util.getHiddenValue(func, 'asynchronous') funcPassedCallback = typeof args[args.length - 1] is 'function' @@ -121,15 +125,17 @@ callFunction = (event, func, caller, args) -> ret = func.apply caller, args event.returnValue = valueToMeta event.sender, ret, true catch e - # Catch functions thrown further down in function invocation and wrap - # them with the function name so it's easier to trace things like - # `Error processing argument -1.` + ### + Catch functions thrown further down in function invocation and wrap + them with the function name so it's easier to trace things like + `Error processing argument -1.` + ### funcName = func.name ? "anonymous" throw new Error("Could not call remote function `#{funcName}`. Check that the function signature is correct. Underlying error: #{e.message}") -# Send by BrowserWindow when its render view is deleted. +### Send by BrowserWindow when its render view is deleted. ### process.on 'ATOM_BROWSER_RELEASE_RENDER_VIEW', (id) -> objectsRegistry.clear id @@ -164,8 +170,10 @@ ipcMain.on 'ATOM_BROWSER_CONSTRUCTOR', (event, id, args) -> try args = unwrapArgs event.sender, args constructor = objectsRegistry.get id - # Call new with array of arguments. - # http://stackoverflow.com/questions/1606797/use-of-apply-with-new-operator-is-this-possible + ### + Call new with array of arguments. + http://stackoverflow.com/questions/1606797/use-of-apply-with-new-operator-is-this-possible + ### obj = new (Function::bind.apply(constructor, [null].concat(args))) event.returnValue = valueToMeta event.sender, obj catch e @@ -183,7 +191,7 @@ ipcMain.on 'ATOM_BROWSER_MEMBER_CONSTRUCTOR', (event, id, method, args) -> try args = unwrapArgs event.sender, args constructor = objectsRegistry.get(id)[method] - # Call new with array of arguments. + ### Call new with array of arguments. ### obj = new (Function::bind.apply(constructor, [null].concat(args))) event.returnValue = valueToMeta event.sender, obj catch e diff --git a/atom/common/api/lib/callbacks-registry.coffee b/atom/common/api/lib/callbacks-registry.coffee index c546df34f9a8..04eafc64bb8b 100644 --- a/atom/common/api/lib/callbacks-registry.coffee +++ b/atom/common/api/lib/callbacks-registry.coffee @@ -7,14 +7,16 @@ class CallbacksRegistry @callbacks = {} add: (callback) -> - # The callback is already added. + ### The callback is already added. ### id = v8Util.getHiddenValue callback, 'callbackId' return id if id? id = ++@nextId - # Capture the location of the function and put it in the ID string, - # so that release errors can be tracked down easily. + ### + Capture the location of the function and put it in the ID string, + so that release errors can be tracked down easily. + ### regexp = /at (.*)/gi stackString = (new Error).stack diff --git a/atom/common/api/lib/clipboard.coffee b/atom/common/api/lib/clipboard.coffee index a3a6d555fe5c..47ee8abc7f7b 100644 --- a/atom/common/api/lib/clipboard.coffee +++ b/atom/common/api/lib/clipboard.coffee @@ -1,5 +1,5 @@ if process.platform is 'linux' and process.type is 'renderer' - # On Linux we could not access clipboard in renderer process. + ### On Linux we could not access clipboard in renderer process. ### module.exports = require('electron').remote.clipboard else module.exports = process.atomBinding 'clipboard' diff --git a/atom/common/api/lib/crash-reporter.coffee b/atom/common/api/lib/crash-reporter.coffee index 544791b7d1c0..af62dfd2f9df 100644 --- a/atom/common/api/lib/crash-reporter.coffee +++ b/atom/common/api/lib/crash-reporter.coffee @@ -10,7 +10,7 @@ class CrashReporter start: (options={}) -> {@productName, companyName, submitURL, autoSubmit, ignoreSystemCrashHandler, extra} = options - # Deprecated. + ### Deprecated. ### {deprecate} = electron if options.submitUrl submitURL ?= options.submitUrl diff --git a/atom/common/api/lib/deprecate.coffee b/atom/common/api/lib/deprecate.coffee index 71c2ee5cabac..7c03fc6f595d 100644 --- a/atom/common/api/lib/deprecate.coffee +++ b/atom/common/api/lib/deprecate.coffee @@ -1,4 +1,4 @@ -# Deprecate a method. +### Deprecate a method. ### deprecate = (oldName, newName, fn) -> warned = false -> @@ -7,7 +7,7 @@ deprecate = (oldName, newName, fn) -> deprecate.warn oldName, newName fn.apply this, arguments -# The method is renamed. +### The method is renamed. ### deprecate.rename = (object, oldName, newName) -> warned = false newMethod = -> @@ -20,7 +20,7 @@ deprecate.rename = (object, oldName, newName) -> else object[oldName] = newMethod -# Forward the method to member. +### Forward the method to member. ### deprecate.member = (object, method, member) -> warned = false object.prototype[method] = -> @@ -29,7 +29,7 @@ deprecate.member = (object, method, member) -> deprecate.warn method, "#{member}.#{method}" this[member][method].apply this[member], arguments -# Deprecate a property. +### Deprecate a property. ### deprecate.property = (object, property, method) -> Object.defineProperty object, property, get: -> @@ -39,11 +39,12 @@ deprecate.property = (object, property, method) -> deprecate.warn "#{property} property", "#{method} method" this[method]() -# Deprecate an event. +### Deprecate an event. ### deprecate.event = (emitter, oldName, newName, fn) -> warned = false emitter.on newName, (args...) -> - if @listenerCount(oldName) > 0 # there is listeners for old API. + ### there is listeners for old API. ### + if @listenerCount(oldName) > 0 unless warned or process.noDeprecation warned = true deprecate.warn "'#{oldName}' event", "'#{newName}' event" @@ -52,11 +53,11 @@ deprecate.event = (emitter, oldName, newName, fn) -> else @emit oldName, args... -# Print deprecation warning. +### Print deprecation warning. ### deprecate.warn = (oldName, newName) -> deprecate.log "#{oldName} is deprecated. Use #{newName} instead." -# Print deprecation message. +### Print deprecation message. ### deprecate.log = (message) -> if process.throwDeprecation throw new Error(message) diff --git a/atom/common/api/lib/exports/electron.coffee b/atom/common/api/lib/exports/electron.coffee index 7598f9ee32fd..c941ab919baa 100644 --- a/atom/common/api/lib/exports/electron.coffee +++ b/atom/common/api/lib/exports/electron.coffee @@ -1,16 +1,16 @@ -# Do not expose the internal modules to `require`. +### Do not expose the internal modules to `require`. ### exports.hideInternalModules = -> {globalPaths} = require 'module' if globalPaths.length is 3 - # Remove the "common/api/lib" and "browser-or-renderer/api/lib". + ### Remove the "common/api/lib" and "browser-or-renderer/api/lib". ### globalPaths.splice 0, 2 -# Attaches properties to |exports|. +### Attaches properties to |exports|. ### exports.defineProperties = (exports) -> Object.defineProperties exports, - # Common modules, please sort with alphabet order. + ### Common modules, please sort with alphabet order. ### clipboard: - # Must be enumerable, otherwise it woulde be invisible to remote module. + ### Must be enumerable, otherwise it woulde be invisible to remote module. ### enumerable: true get: -> require '../clipboard' crashReporter: @@ -22,7 +22,7 @@ exports.defineProperties = (exports) -> shell: enumerable: true get: -> require '../shell' - # The internal modules, invisible unless you know their names. + ### The internal modules, invisible unless you know their names. ### CallbacksRegistry: get: -> require '../callbacks-registry' deprecate: diff --git a/atom/common/api/lib/native-image.coffee b/atom/common/api/lib/native-image.coffee index 2bdfd494f44b..9884f6abf763 100644 --- a/atom/common/api/lib/native-image.coffee +++ b/atom/common/api/lib/native-image.coffee @@ -1,7 +1,7 @@ {deprecate} = require 'electron' nativeImage = process.atomBinding 'native_image' -# Deprecated. +### Deprecated. ### deprecate.rename nativeImage, 'createFromDataUrl', 'createFromDataURL' module.exports = nativeImage diff --git a/atom/common/lib/asar.coffee b/atom/common/lib/asar.coffee index 5f690e9a8f6b..3e785b4e6132 100644 --- a/atom/common/lib/asar.coffee +++ b/atom/common/lib/asar.coffee @@ -3,7 +3,7 @@ child_process = require 'child_process' path = require 'path' util = require 'util' -# Cache asar archive objects. +### Cache asar archive objects. ### cachedArchives = {} getOrCreateArchive = (p) -> archive = cachedArchives[p] @@ -12,13 +12,15 @@ getOrCreateArchive = (p) -> return false unless archive cachedArchives[p] = archive -# Clean cache on quit. +### Clean cache on quit. ### process.on 'exit', -> archive.destroy() for own p, archive of cachedArchives -# Separate asar package's path from full path. +### Separate asar package's path from full path. ### splitPath = (p) -> - return [false] if process.noAsar # shortcut to disable asar. + ### shortcut to disable asar. ### + return [false] if process.noAsar + return [false] if typeof p isnt 'string' return [true, p, ''] if p.substr(-5) is '.asar' p = path.normalize p @@ -26,7 +28,7 @@ splitPath = (p) -> return [false] if index is -1 [true, p.substr(0, index + 5), p.substr(index + 6)] -# Convert asar archive's Stats object to fs's Stats object. +### Convert asar archive's Stats object to fs's Stats object. ### nextInode = 0 uid = if process.getuid? then process.getuid() else 0 gid = if process.getgid? then process.getgid() else 0 @@ -54,7 +56,7 @@ asarStatsToFsStats = (stats) -> isSocket: -> false } -# Create a ENOENT error. +### Create a ENOENT error. ### notFoundError = (asarPath, filePath, callback) -> error = new Error("ENOENT, #{filePath} not found in #{asarPath}") error.code = "ENOENT" @@ -63,7 +65,7 @@ notFoundError = (asarPath, filePath, callback) -> throw error process.nextTick -> callback error -# Create a ENOTDIR error. +### Create a ENOTDIR error. ### notDirError = (callback) -> error = new Error('ENOTDIR, not a directory') error.code = 'ENOTDIR' @@ -72,14 +74,14 @@ notDirError = (callback) -> throw error process.nextTick -> callback error -# Create invalid archive error. +### Create invalid archive error. ### invalidArchiveError = (asarPath, callback) -> error = new Error("Invalid package #{asarPath}") unless typeof callback is 'function' throw error process.nextTick -> callback error -# Override APIs that rely on passing file path instead of content to C++. +### Override APIs that rely on passing file path instead of content to C++. ### overrideAPISync = (module, name, arg = 0) -> old = module[name] module[name] = -> @@ -115,7 +117,7 @@ overrideAPI = (module, name, arg = 0) -> arguments[arg] = newPath old.apply this, arguments -# Override fs APIs. +### Override fs APIs. ### exports.wrapFsWithAsar = (fs) -> lstatSync = fs.lstatSync fs.lstatSync = (p) -> @@ -148,7 +150,7 @@ exports.wrapFsWithAsar = (fs) -> [isAsar, asarPath, filePath] = splitPath p return statSync p unless isAsar - # Do not distinguish links for now. + ### Do not distinguish links for now. ### fs.lstatSync p stat = fs.stat @@ -156,7 +158,7 @@ exports.wrapFsWithAsar = (fs) -> [isAsar, asarPath, filePath] = splitPath p return stat p, callback unless isAsar - # Do not distinguish links for now. + ### Do not distinguish links for now. ### process.nextTick -> fs.lstat p, callback statSyncNoException = fs.statSyncNoException @@ -265,7 +267,9 @@ exports.wrapFsWithAsar = (fs) -> openSync = fs.openSync readFileSync = fs.readFileSync fs.readFileSync = (p, opts) -> - options = opts # this allows v8 to optimize this function + ### this allows v8 to optimize this function ### + options = opts + [isAsar, asarPath, filePath] = splitPath p return readFileSync.apply this, arguments unless isAsar @@ -353,17 +357,21 @@ exports.wrapFsWithAsar = (fs) -> return internalModuleStat p unless isAsar archive = getOrCreateArchive asarPath - return -34 unless archive # -ENOENT + ### -ENOENT ### + return -34 unless archive stats = archive.stat filePath - return -34 unless stats # -ENOENT + ### -ENOENT ### + return -34 unless stats if stats.isDirectory then return 1 else return 0 - # Calling mkdir for directory inside asar archive should throw ENOTDIR - # error, but on Windows it throws ENOENT. - # This is to work around the recursive looping bug of mkdirp since it is - # widely used. + ### + Calling mkdir for directory inside asar archive should throw ENOTDIR + error, but on Windows it throws ENOENT. + This is to work around the recursive looping bug of mkdirp since it is + widely used. + ### if process.platform is 'win32' mkdir = fs.mkdir fs.mkdir = (p, mode, callback) -> diff --git a/atom/common/lib/asar_init.coffee b/atom/common/lib/asar_init.coffee index 211c79ee9099..4bb03daa7607 100644 --- a/atom/common/lib/asar_init.coffee +++ b/atom/common/lib/asar_init.coffee @@ -1,13 +1,13 @@ return (process, require, asarSource) -> {createArchive} = process.binding 'atom_common_asar' - # Make asar.coffee accessible via "require". + ### Make asar.coffee accessible via "require". ### process.binding('natives').ATOM_SHELL_ASAR = asarSource - # Monkey-patch the fs module. + ### Monkey-patch the fs module. ### require('ATOM_SHELL_ASAR').wrapFsWithAsar require('fs') - # Make graceful-fs work with asar. + ### Make graceful-fs work with asar. ### source = process.binding 'natives' source['original-fs'] = source.fs source['fs'] = """ diff --git a/atom/common/lib/init.coffee b/atom/common/lib/init.coffee index 735d9b0a31e5..604c6590bdd5 100644 --- a/atom/common/lib/init.coffee +++ b/atom/common/lib/init.coffee @@ -10,15 +10,17 @@ process.atomBinding = (name) -> process.binding "atom_common_#{name}" if /No such module/.test e.message unless process.env.ELECTRON_HIDE_INTERNAL_MODULES - # Add common/api/lib to module search paths. + ### Add common/api/lib to module search paths. ### Module.globalPaths.push path.resolve(__dirname, '..', 'api', 'lib') -# setImmediate and process.nextTick makes use of uv_check and uv_prepare to -# run the callbacks, however since we only run uv loop on requests, the -# callbacks wouldn't be called until something else activated the uv loop, -# which would delay the callbacks for arbitrary long time. So we should -# initiatively activate the uv loop once setImmediate and process.nextTick is -# called. +### + setImmediate and process.nextTick makes use of uv_check and uv_prepare to + run the callbacks, however since we only run uv loop on requests, the + callbacks wouldn't be called until something else activated the uv loop, + which would delay the callbacks for arbitrary long time. So we should + initiatively activate the uv loop once setImmediate and process.nextTick is + called. +### wrapWithActivateUvLoop = (func) -> -> process.activateUvLoop() @@ -28,9 +30,11 @@ 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 - # called under Chromium's event loop the node's event loop won't get a chance - # to update the timeout, so we have to force the node's event loop to - # recalculate the timeout in browser process. + ### + setTimeout needs to update the polling timeout of the event loop, when + called under Chromium's event loop the node's event loop won't get a chance + to update the timeout, so we have to force the node's event loop to + recalculate the timeout in browser process. + ### global.setTimeout = wrapWithActivateUvLoop timers.setTimeout global.setInterval = wrapWithActivateUvLoop timers.setInterval diff --git a/atom/common/lib/reset-search-paths.coffee b/atom/common/lib/reset-search-paths.coffee index 7061103306aa..ae99abb4bf30 100644 --- a/atom/common/lib/reset-search-paths.coffee +++ b/atom/common/lib/reset-search-paths.coffee @@ -1,21 +1,21 @@ path = require 'path' Module = require 'module' -# Clear Node's global search paths. +### Clear Node's global search paths. ### Module.globalPaths.length = 0 -# Clear current and parent(init.coffee)'s search paths. +### Clear current and parent(init.coffee)'s search paths. ### module.paths = [] module.parent.paths = [] -# Prevent Node from adding paths outside this app to search paths. +### Prevent Node from adding paths outside this app to search paths. ### Module._nodeModulePaths = (from) -> from = path.resolve from - # If "from" is outside the app then we do nothing. + ### If "from" is outside the app then we do nothing. ### skipOutsidePaths = from.startsWith process.resourcesPath - # Following logoic is copied from module.js. + ### Following logoic is copied from module.js. ### splitRe = if process.platform is 'win32' then /[\/\\]/ else /\// paths = [] diff --git a/atom/renderer/api/lib/desktop-capturer.coffee b/atom/renderer/api/lib/desktop-capturer.coffee index 7c7c8982491f..4fd0763d7e55 100644 --- a/atom/renderer/api/lib/desktop-capturer.coffee +++ b/atom/renderer/api/lib/desktop-capturer.coffee @@ -3,7 +3,7 @@ nextId = 0 getNextId = -> ++nextId -# |options.type| can not be empty and has to include 'window' or 'screen'. +### |options.type| can not be empty and has to include 'window' or 'screen'. ### isValid = (options) -> return options?.types? and Array.isArray options.types diff --git a/atom/renderer/api/lib/exports/electron.coffee b/atom/renderer/api/lib/exports/electron.coffee index d0b3af3c5571..b53980905416 100644 --- a/atom/renderer/api/lib/exports/electron.coffee +++ b/atom/renderer/api/lib/exports/electron.coffee @@ -1,10 +1,10 @@ common = require '../../../../common/api/lib/exports/electron' -# Import common modules. +### Import common modules. ### common.defineProperties exports Object.defineProperties exports, - # Renderer side modules, please sort with alphabet order. + ### Renderer side modules, please sort with alphabet order. ### desktopCapturer: enumerable: true get: -> require '../desktop-capturer' diff --git a/atom/renderer/api/lib/ipc-renderer.coffee b/atom/renderer/api/lib/ipc-renderer.coffee index 0dd629e54f75..d468bd353e94 100644 --- a/atom/renderer/api/lib/ipc-renderer.coffee +++ b/atom/renderer/api/lib/ipc-renderer.coffee @@ -3,7 +3,7 @@ binding = process.atomBinding 'ipc' v8Util = process.atomBinding 'v8_util' -# Created by init.coffee. +### Created by init.coffee. ### ipcRenderer = v8Util.getHiddenValue global, 'ipc' ipcRenderer.send = (args...) -> diff --git a/atom/renderer/api/lib/ipc.coffee b/atom/renderer/api/lib/ipc.coffee index edd7d29b6f06..1eb49fb8d0de 100644 --- a/atom/renderer/api/lib/ipc.coffee +++ b/atom/renderer/api/lib/ipc.coffee @@ -1,16 +1,16 @@ {ipcRenderer, deprecate} = require 'electron' {EventEmitter} = require 'events' -# This module is deprecated, we mirror everything from ipcRenderer. +### This module is deprecated, we mirror everything from ipcRenderer. ### deprecate.warn 'ipc module', 'require("electron").ipcRenderer' -# Routes events of ipcRenderer. +### Routes events of ipcRenderer. ### ipc = new EventEmitter ipcRenderer.emit = (channel, event, args...) -> ipc.emit channel, args... EventEmitter::emit.apply ipcRenderer, arguments -# Deprecated. +### Deprecated. ### for method of ipcRenderer when method.startsWith 'send' ipc[method] = ipcRenderer[method] deprecate.rename ipc, 'sendChannel', 'send' diff --git a/atom/renderer/api/lib/remote.coffee b/atom/renderer/api/lib/remote.coffee index b73fbf50b7c1..b30e79e73ba5 100644 --- a/atom/renderer/api/lib/remote.coffee +++ b/atom/renderer/api/lib/remote.coffee @@ -3,7 +3,7 @@ v8Util = process.atomBinding 'v8_util' callbacksRegistry = new CallbacksRegistry -# Check for circular reference. +### Check for circular reference. ### isCircular = (field, visited) -> if typeof field is 'object' if field in visited @@ -11,7 +11,7 @@ isCircular = (field, visited) -> visited.push field return false -# Convert the arguments object into an array of meta data. +### Convert the arguments object into an array of meta data. ### wrapArgs = (args, visited=[]) -> valueToMeta = (value) -> if Array.isArray value @@ -40,7 +40,7 @@ wrapArgs = (args, visited=[]) -> Array::slice.call(args).map valueToMeta -# Convert meta data from browser into real value. +### Convert meta data from browser into real value. ### metaToValue = (meta) -> switch meta.type when 'value' then meta.value @@ -53,43 +53,47 @@ metaToValue = (meta) -> throw new Error("#{meta.message}\n#{meta.stack}") else if meta.type is 'function' - # A shadow class to represent the remote function object. + ### A shadow class to represent the remote function object. ### ret = class RemoteFunction constructor: -> if @constructor == RemoteFunction - # Constructor call. + ### Constructor call. ### obj = ipcRenderer.sendSync 'ATOM_BROWSER_CONSTRUCTOR', meta.id, wrapArgs(arguments) - # Returning object in constructor will replace constructed object - # with the returned object. - # http://stackoverflow.com/questions/1978049/what-values-can-a-constructor-return-to-avoid-returning-this + ### + Returning object in constructor will replace constructed object + with the returned object. + http://stackoverflow.com/questions/1978049/what-values-can-a-constructor-return-to-avoid-returning-this + ### return metaToValue obj else - # Function call. + ### Function call. ### obj = ipcRenderer.sendSync 'ATOM_BROWSER_FUNCTION_CALL', meta.id, wrapArgs(arguments) return metaToValue obj else ret = v8Util.createObjectWithName meta.name - # Polulate delegate members. + ### Polulate delegate members. ### for member in meta.members if member.type is 'function' ret[member.name] = createRemoteMemberFunction meta.id, member.name else Object.defineProperty ret, member.name, createRemoteMemberProperty(meta.id, member.name) - # Track delegate object's life time, and tell the browser to clean up - # when the object is GCed. + ### + Track delegate object's life time, and tell the browser to clean up + when the object is GCed. + ### v8Util.setDestructor ret, -> ipcRenderer.send 'ATOM_BROWSER_DEREFERENCE', meta.id - # Remember object's id. + ### Remember object's id. ### v8Util.setHiddenValue ret, 'atomId', meta.id ret -# Construct a plain object from the meta. +### Construct a plain object from the meta. ### metaToPlainObject = (meta) -> obj = switch meta.type when 'error' then new Error @@ -97,53 +101,59 @@ metaToPlainObject = (meta) -> obj[name] = value for {name, value} in meta.members obj -# Create a RemoteMemberFunction instance. -# This function's content should not be inlined into metaToValue, otherwise V8 -# may consider it circular reference. +### + Create a RemoteMemberFunction instance. + This function's content should not be inlined into metaToValue, otherwise V8 + may consider it circular reference. +### createRemoteMemberFunction = (metaId, name) -> class RemoteMemberFunction constructor: -> if @constructor is RemoteMemberFunction - # Constructor call. + ### Constructor call. ### ret = ipcRenderer.sendSync 'ATOM_BROWSER_MEMBER_CONSTRUCTOR', metaId, name, wrapArgs(arguments) return metaToValue ret else - # Call member function. + ### Call member function. ### ret = ipcRenderer.sendSync 'ATOM_BROWSER_MEMBER_CALL', metaId, name, wrapArgs(arguments) return metaToValue ret -# Create configuration for defineProperty. -# This function's content should not be inlined into metaToValue, otherwise V8 -# may consider it circular reference. +### + Create configuration for defineProperty. + This function's content should not be inlined into metaToValue, otherwise V8 + may consider it circular reference. +### createRemoteMemberProperty = (metaId, name) -> enumerable: true, configurable: false, set: (value) -> - # Set member data. + ### Set member data. ### ipcRenderer.sendSync 'ATOM_BROWSER_MEMBER_SET', metaId, name, value value get: -> - # Get member data. + ### Get member data. ### metaToValue ipcRenderer.sendSync('ATOM_BROWSER_MEMBER_GET', metaId, name) -# Browser calls a callback in renderer. +### Browser calls a callback in renderer. ### ipcRenderer.on 'ATOM_RENDERER_CALLBACK', (event, id, args) -> callbacksRegistry.apply id, metaToValue(args) -# A callback in browser is released. +### A callback in browser is released. ### ipcRenderer.on 'ATOM_RENDERER_RELEASE_CALLBACK', (event, id) -> callbacksRegistry.remove id -# List all built-in modules in browser process. +### List all built-in modules in browser process. ### browserModules = require '../../../browser/api/lib/exports/electron' -# And add a helper receiver for each one. +### And add a helper receiver for each one. ### for name of browserModules do (name) -> Object.defineProperty exports, name, get: -> exports.getBuiltin name -# Get remote module. -# (Just like node's require, the modules are cached permanently, note that this -# is safe leak since the object is not expected to get freed in browser) +### + Get remote module. + (Just like node's require, the modules are cached permanently, note that this + is safe leak since the object is not expected to get freed in browser) +### moduleCache = {} exports.require = (module) -> return moduleCache[module] if moduleCache[module]? @@ -151,10 +161,10 @@ exports.require = (module) -> meta = ipcRenderer.sendSync 'ATOM_BROWSER_REQUIRE', module moduleCache[module] = metaToValue meta -# Optimize require('electron'). +### Optimize require('electron'). ### moduleCache.electron = exports -# Alias to remote.require('electron').xxx. +### Alias to remote.require('electron').xxx. ### builtinCache = {} exports.getBuiltin = (module) -> return builtinCache[module] if builtinCache[module]? @@ -162,38 +172,38 @@ exports.getBuiltin = (module) -> meta = ipcRenderer.sendSync 'ATOM_BROWSER_GET_BUILTIN', module builtinCache[module] = metaToValue meta -# Get current BrowserWindow object. +### Get current BrowserWindow object. ### windowCache = null exports.getCurrentWindow = -> return windowCache if windowCache? meta = ipcRenderer.sendSync 'ATOM_BROWSER_CURRENT_WINDOW' windowCache = metaToValue meta -# Get current WebContents object. +### Get current WebContents object. ### webContentsCache = null exports.getCurrentWebContents = -> return webContentsCache if webContentsCache? meta = ipcRenderer.sendSync 'ATOM_BROWSER_CURRENT_WEB_CONTENTS' webContentsCache = metaToValue meta -# Get a global object in browser. +### Get a global object in browser. ### exports.getGlobal = (name) -> meta = ipcRenderer.sendSync 'ATOM_BROWSER_GLOBAL', name metaToValue meta -# Get the process object in browser. +### Get the process object in browser. ### processCache = null exports.__defineGetter__ 'process', -> processCache = exports.getGlobal('process') unless processCache? processCache -# Create a funtion that will return the specifed value when called in browser. +### Create a funtion that will return the specifed value when called in browser. ### exports.createFunctionWithReturnValue = (returnValue) -> func = -> returnValue v8Util.setHiddenValue func, 'returnValue', true func -# Get the guest WebContents from guestInstanceId. +### Get the guest WebContents from guestInstanceId. ### exports.getGuestWebContents = (guestInstanceId) -> meta = ipcRenderer.sendSync 'ATOM_BROWSER_GUEST_WEB_CONTENTS', guestInstanceId metaToValue meta diff --git a/atom/renderer/api/lib/web-frame.coffee b/atom/renderer/api/lib/web-frame.coffee index 53564c615ca4..e2ae3cae6192 100644 --- a/atom/renderer/api/lib/web-frame.coffee +++ b/atom/renderer/api/lib/web-frame.coffee @@ -1,7 +1,7 @@ {deprecate} = require 'electron' {webFrame} = process.atomBinding 'web_frame' -# Deprecated. +### Deprecated. ### deprecate.rename webFrame, 'registerUrlSchemeAsSecure', 'registerURLSchemeAsSecure' deprecate.rename webFrame, 'registerUrlSchemeAsBypassingCSP', 'registerURLSchemeAsBypassingCSP' deprecate.rename webFrame, 'registerUrlSchemeAsPrivileged', 'registerURLSchemeAsPrivileged' diff --git a/atom/renderer/lib/init.coffee b/atom/renderer/lib/init.coffee index b9028f2dd6a5..149c636ebeb4 100644 --- a/atom/renderer/lib/init.coffee +++ b/atom/renderer/lib/init.coffee @@ -3,35 +3,37 @@ 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. +### + We modified the original process.argv to let node.js load the + atom-renderer.js, we need to restore it here. +### process.argv.splice 1, 1 -# Clear search paths. +### Clear search paths. ### require path.resolve(__dirname, '..', '..', 'common', 'lib', 'reset-search-paths') -# Import common settings. +### Import common settings. ### require path.resolve(__dirname, '..', '..', 'common', 'lib', 'init') globalPaths = Module.globalPaths unless process.env.ELECTRON_HIDE_INTERNAL_MODULES globalPaths.push path.resolve(__dirname, '..', 'api', 'lib') -# Expose public APIs. +### Expose public APIs. ### globalPaths.push path.resolve(__dirname, '..', 'api', 'lib', 'exports') -# The global variable will be used by ipc for event dispatching +### The global variable will be used by ipc for event dispatching ### v8Util = process.atomBinding 'v8_util' v8Util.setHiddenValue global, 'ipc', new events.EventEmitter -# Process command line arguments. +### Process command line arguments. ### nodeIntegration = 'false' for arg in process.argv if arg.indexOf('--guest-instance-id=') == 0 - # This is a guest web view. + ### This is a guest web view. ### process.guestInstanceId = parseInt arg.substr(arg.indexOf('=') + 1) else if arg.indexOf('--opener-id=') == 0 - # This is a guest BrowserWindow. + ### This is a guest BrowserWindow. ### process.openerId = parseInt arg.substr(arg.indexOf('=') + 1) else if arg.indexOf('--node-integration=') == 0 nodeIntegration = arg.substr arg.indexOf('=') + 1 @@ -39,27 +41,27 @@ for arg in process.argv preloadScript = arg.substr arg.indexOf('=') + 1 if location.protocol is 'chrome-devtools:' - # Override some inspector APIs. + ### Override some inspector APIs. ### require './inspector' nodeIntegration = 'true' else if location.protocol is 'chrome-extension:' - # Add implementations of chrome API. + ### Add implementations of chrome API. ### require './chrome-api' nodeIntegration = 'true' else - # Override default web functions. + ### Override default web functions. ### require './override' - # Load webview tag implementation. + ### Load webview tag implementation. ### unless process.guestInstanceId? require './web-view/web-view' require './web-view/web-view-attributes' if nodeIntegration in ['true', 'all', 'except-iframe', 'manual-enable-iframe'] - # Export node bindings to global. + ### Export node bindings to global. ### global.require = require global.module = module - # Set the __filename to the path of html file if it is file: protocol. + ### Set the __filename to the path of html file if it is file: protocol. ### if window.location.protocol is 'file:' pathname = if process.platform is 'win32' and window.location.pathname[0] is '/' @@ -69,16 +71,16 @@ if nodeIntegration in ['true', 'all', 'except-iframe', 'manual-enable-iframe'] global.__filename = path.normalize decodeURIComponent(pathname) global.__dirname = path.dirname global.__filename - # Set module's filename so relative require can work as expected. + ### Set module's filename so relative require can work as expected. ### module.filename = global.__filename - # Also search for module under the html file. + ### Also search for module under the html file. ### module.paths = module.paths.concat Module._nodeModulePaths(global.__dirname) else global.__filename = __filename global.__dirname = __dirname - # Redirect window.onerror to uncaughtException. + ### Redirect window.onerror to uncaughtException. ### window.onerror = (message, filename, lineno, colno, error) -> if global.process.listeners('uncaughtException').length > 0 global.process.emit 'uncaughtException', error @@ -86,18 +88,18 @@ if nodeIntegration in ['true', 'all', 'except-iframe', 'manual-enable-iframe'] else false - # Emit the 'exit' event when page is unloading. + ### Emit the 'exit' event when page is unloading. ### window.addEventListener 'unload', -> process.emit 'exit' else - # Delete Node's symbols after the Environment has been loaded. + ### Delete Node's symbols after the Environment has been loaded. ### process.once 'loaded', -> delete global.process delete global.setImmediate delete global.clearImmediate delete global.global -# Load the script specfied by the "preload" attribute. +### Load the script specfied by the "preload" attribute. ### if preloadScript try require preloadScript diff --git a/atom/renderer/lib/inspector.coffee b/atom/renderer/lib/inspector.coffee index 364ccc39d42a..e49f4b77c7b5 100644 --- a/atom/renderer/lib/inspector.coffee +++ b/atom/renderer/lib/inspector.coffee @@ -1,8 +1,8 @@ window.onload = -> - # Use menu API to show context menu. + ### Use menu API to show context menu. ### InspectorFrontendHost.showContextMenuAtPoint = createMenu - # Use dialog API to override file chooser dialog. + ### Use dialog API to override file chooser dialog. ### WebInspector.createFileSelectorElement = createFileSelectorElement convertToMenuTemplate = (items) -> @@ -38,7 +38,7 @@ createMenu = (x, y, items, document) -> {Menu} = remote menu = Menu.buildFromTemplate convertToMenuTemplate(items) - # The menu is expected to show asynchronously. + ### The menu is expected to show asynchronously. ### setTimeout -> menu.popup remote.getCurrentWindow() showFileChooserDialog = (callback) -> diff --git a/atom/renderer/lib/override.coffee b/atom/renderer/lib/override.coffee index 5280f1927e80..5b031c0ad44a 100644 --- a/atom/renderer/lib/override.coffee +++ b/atom/renderer/lib/override.coffee @@ -1,12 +1,12 @@ {ipcRenderer, remote} = require 'electron' -# Helper function to resolve relative url. +### Helper function to resolve relative url. ### a = window.top.document.createElement 'a' resolveURL = (url) -> a.href = url a.href -# Window object returned by "window.open". +### Window object returned by "window.open". ### class BrowserWindowProxy @proxies: {} @@ -38,15 +38,15 @@ class BrowserWindowProxy ipcRenderer.send 'ATOM_SHELL_GUEST_WINDOW_MANAGER_WEB_CONTENTS_METHOD', @guestId, 'executeJavaScript', args... unless process.guestInstanceId? - # Override default window.close. + ### Override default window.close. ### window.close = -> remote.getCurrentWindow().close() -# Make the browser window or guest view emit "new-window" event. +### Make the browser window or guest view emit "new-window" event. ### window.open = (url, frameName='', features='') -> options = {} ints = [ 'x', 'y', 'width', 'height', 'min-width', 'max-width', 'min-height', 'max-height', 'zoom-factor' ] - # Make sure to get rid of excessive whitespace in the property name + ### Make sure to get rid of excessive whitespace in the property name ### for feature in features.split /,\s*/ [name, value] = feature.split /\s*=/ options[name] = @@ -62,7 +62,7 @@ window.open = (url, frameName='', features='') -> options.width ?= 800 options.height ?= 600 - # Resolve relative urls. + ### Resolve relative urls. ### url = resolveURL url (options[name] = parseInt(options[name], 10) if options[name]?) for name in ints @@ -73,21 +73,21 @@ window.open = (url, frameName='', features='') -> else null -# Use the dialog API to implement alert(). +### Use the dialog API to implement alert(). ### window.alert = (message, title='') -> buttons = ['OK'] message = message.toString() remote.dialog.showMessageBox remote.getCurrentWindow(), {message, title, buttons} - # Alert should always return undefined. + ### Alert should always return undefined. ### return -# And the confirm(). +### And the confirm(). ### window.confirm = (message, title='') -> buttons = ['OK', 'Cancel'] cancelId = 1 not remote.dialog.showMessageBox remote.getCurrentWindow(), {message, title, buttons, cancelId} -# But we do not support prompt(). +### But we do not support prompt(). ### window.prompt = -> throw new Error('prompt() is and will not be supported.') @@ -95,8 +95,8 @@ if process.openerId? window.opener = BrowserWindowProxy.getOrCreate process.openerId ipcRenderer.on 'ATOM_SHELL_GUEST_WINDOW_POSTMESSAGE', (event, sourceId, message, sourceOrigin) -> - # Manually dispatch event instead of using postMessage because we also need to - # set event.source. + ### Manually dispatch event instead of using postMessage because we also need to ### + ### set event.source. ### event = document.createEvent 'Event' event.initEvent 'message', false, false event.data = message @@ -104,7 +104,7 @@ ipcRenderer.on 'ATOM_SHELL_GUEST_WINDOW_POSTMESSAGE', (event, sourceId, message, event.source = BrowserWindowProxy.getOrCreate(sourceId) window.dispatchEvent event -# Forward history operations to browser. +### Forward history operations to browser. ### sendHistoryOperation = (args...) -> ipcRenderer.send 'ATOM_SHELL_NAVIGATION_CONTROLLER', args... @@ -118,7 +118,7 @@ Object.defineProperty window.history, 'length', get: -> getHistoryOperation 'length' -# Make document.hidden and document.visibilityState return the correct value. +### Make document.hidden and document.visibilityState return the correct value. ### Object.defineProperty document, 'hidden', get: -> currentWindow = remote.getCurrentWindow() diff --git a/atom/renderer/lib/web-view/web-view-attributes.coffee b/atom/renderer/lib/web-view/web-view-attributes.coffee index 7760b400ce17..051a0c8a86b3 100644 --- a/atom/renderer/lib/web-view/web-view-attributes.coffee +++ b/atom/renderer/lib/web-view/web-view-attributes.coffee @@ -4,14 +4,16 @@ webViewConstants = require './web-view-constants' {remote} = require 'electron' -# Helper function to resolve url set in attribute. +### Helper function to resolve url set in attribute. ### a = document.createElement 'a' resolveURL = (url) -> a.href = url a.href -# Attribute objects. -# Default implementation of a WebView attribute. +### + Attribute objects. + Default implementation of a WebView attribute. +### class WebViewAttribute constructor: (name, webViewImpl) -> @name = name @@ -20,29 +22,29 @@ class WebViewAttribute @defineProperty() - # Retrieves and returns the attribute's value. + ### Retrieves and returns the attribute's value. ### getValue: -> @webViewImpl.webviewNode.getAttribute(@name) || '' - # Sets the attribute's value. + ### Sets the attribute's value. ### setValue: (value) -> @webViewImpl.webviewNode.setAttribute(@name, value || '') - # Changes the attribute's value without triggering its mutation handler. + ### Changes the attribute's value without triggering its mutation handler. ### setValueIgnoreMutation: (value) -> @ignoreMutation = true @setValue value @ignoreMutation = false - # Defines this attribute as a property on the webview node. + ### Defines this attribute as a property on the webview node. ### defineProperty: -> Object.defineProperty @webViewImpl.webviewNode, @name, get: => @getValue() set: (value) => @setValue value enumerable: true - # Called when the attribute's value changes. + ### Called when the attribute's value changes. ### handleMutation: -> -# An attribute that is treated as a Boolean. +### An attribute that is treated as a Boolean. ### class BooleanAttribute extends WebViewAttribute constructor: (name, webViewImpl) -> super name, webViewImpl @@ -55,7 +57,7 @@ class BooleanAttribute extends WebViewAttribute else @webViewImpl.webviewNode.setAttribute @name, '' -# Attribute that specifies whether transparency is allowed in the webview. +### Attribute that specifies whether transparency is allowed in the webview. ### class AllowTransparencyAttribute extends BooleanAttribute constructor: (webViewImpl) -> super webViewConstants.ATTRIBUTE_ALLOWTRANSPARENCY, webViewImpl @@ -64,7 +66,7 @@ class AllowTransparencyAttribute extends BooleanAttribute return unless @webViewImpl.guestInstanceId guestViewInternal.setAllowTransparency @webViewImpl.guestInstanceId, @getValue() -# Attribute used to define the demension limits of autosizing. +### Attribute used to define the demension limits of autosizing. ### class AutosizeDimensionAttribute extends WebViewAttribute constructor: (name, webViewImpl) -> super name, webViewImpl @@ -82,14 +84,14 @@ class AutosizeDimensionAttribute extends WebViewAttribute width: parseInt @webViewImpl.attributes[webViewConstants.ATTRIBUTE_MAXWIDTH].getValue() || 0 height: parseInt @webViewImpl.attributes[webViewConstants.ATTRIBUTE_MAXHEIGHT].getValue() || 0 -# Attribute that specifies whether the webview should be autosized. +### Attribute that specifies whether the webview should be autosized. ### class AutosizeAttribute extends BooleanAttribute constructor: (webViewImpl) -> super webViewConstants.ATTRIBUTE_AUTOSIZE, webViewImpl handleMutation: AutosizeDimensionAttribute::handleMutation -# Attribute representing the state of the storage partition. +### Attribute representing the state of the storage partition. ### class PartitionAttribute extends WebViewAttribute constructor: (webViewImpl) -> super webViewConstants.ATTRIBUTE_PARTITION, webViewImpl @@ -98,7 +100,7 @@ class PartitionAttribute extends WebViewAttribute handleMutation: (oldValue, newValue) -> newValue = newValue || '' - # The partition cannot change if the webview has already navigated. + ### The partition cannot change if the webview has already navigated. ### unless @webViewImpl.beforeFirstNavigation window.console.error webViewConstants.ERROR_MSG_ALREADY_NAVIGATED @setValueIgnoreMutation oldValue @@ -108,7 +110,7 @@ class PartitionAttribute extends WebViewAttribute @validPartitionId = false window.console.error webViewConstants.ERROR_MSG_INVALID_PARTITION_ATTRIBUTE -# Attribute that handles the location and navigation of the webview. +### Attribute that handles the location and navigation of the webview. ### class SrcAttribute extends WebViewAttribute constructor: (webViewImpl) -> super webViewConstants.ATTRIBUTE_SRC, webViewImpl @@ -122,28 +124,36 @@ class SrcAttribute extends WebViewAttribute setValueIgnoreMutation: (value) -> WebViewAttribute::setValueIgnoreMutation.call(this, value) - # takeRecords() is needed to clear queued up src mutations. Without it, it - # is possible for this change to get picked up asyncronously by src's - # mutation observer |observer|, and then get handled even though we do not - # want to handle this mutation. + ### + takeRecords() is needed to clear queued up src mutations. Without it, it + is possible for this change to get picked up asyncronously by src's + mutation observer |observer|, and then get handled even though we do not + want to handle this mutation. + ### @observer.takeRecords() handleMutation: (oldValue, newValue) -> - # Once we have navigated, we don't allow clearing the src attribute. - # Once enters a navigated state, it cannot return to a - # placeholder state. + ### + Once we have navigated, we don't allow clearing the src attribute. + Once enters a navigated state, it cannot return to a + placeholder state. + ### if not newValue and oldValue - # src attribute changes normally initiate a navigation. We suppress - # the next src attribute handler call to avoid reloading the page - # on every guest-initiated navigation. + ### + src attribute changes normally initiate a navigation. We suppress + the next src attribute handler call to avoid reloading the page + on every guest-initiated navigation. + ### @setValueIgnoreMutation oldValue return @parse() - # The purpose of this mutation observer is to catch assignment to the src - # attribute without any changes to its value. This is useful in the case - # where the webview guest has crashed and navigating to the same address - # spawns off a new process. + ### + The purpose of this mutation observer is to catch assignment to the src + attribute without any changes to its value. This is useful in the case + where the webview guest has crashed and navigating to the same address + spawns off a new process. + ### setupMutationObserver: -> @observer = new MutationObserver (mutations) => for mutation in mutations @@ -169,7 +179,7 @@ class SrcAttribute extends WebViewAttribute @webViewImpl.createGuest() return - # Navigate to |this.src|. + ### Navigate to |this.src|. ### opts = {} httpreferrer = @webViewImpl.attributes[webViewConstants.ATTRIBUTE_HTTPREFERRER].getValue() if httpreferrer then opts.httpReferrer = httpreferrer @@ -180,17 +190,17 @@ class SrcAttribute extends WebViewAttribute guestContents = remote.getGuestWebContents(@webViewImpl.guestInstanceId) guestContents.loadURL @getValue(), opts -# Attribute specifies HTTP referrer. +### Attribute specifies HTTP referrer. ### class HttpReferrerAttribute extends WebViewAttribute constructor: (webViewImpl) -> super webViewConstants.ATTRIBUTE_HTTPREFERRER, webViewImpl -# Attribute specifies user agent +### Attribute specifies user agent ### class UserAgentAttribute extends WebViewAttribute constructor: (webViewImpl) -> super webViewConstants.ATTRIBUTE_USERAGENT, webViewImpl -# Attribute that set preload script. +### Attribute that set preload script. ### class PreloadAttribute extends WebViewAttribute constructor: (webViewImpl) -> super webViewConstants.ATTRIBUTE_PRELOAD, webViewImpl @@ -204,7 +214,7 @@ class PreloadAttribute extends WebViewAttribute preload = '' preload -# Sets up all of the webview attributes. +### Sets up all of the webview attributes. ### WebViewImpl::setupWebViewAttributes = -> @attributes = {} diff --git a/atom/renderer/lib/web-view/web-view-constants.coffee b/atom/renderer/lib/web-view/web-view-constants.coffee index bfb9376fa7ea..520517fbf58a 100644 --- a/atom/renderer/lib/web-view/web-view-constants.coffee +++ b/atom/renderer/lib/web-view/web-view-constants.coffee @@ -1,5 +1,5 @@ module.exports = - # Attributes. + ### Attributes. ### ATTRIBUTE_ALLOWTRANSPARENCY: 'allowtransparency' ATTRIBUTE_AUTOSIZE: 'autosize' ATTRIBUTE_MAXHEIGHT: 'maxheight' @@ -17,10 +17,10 @@ module.exports = ATTRIBUTE_PRELOAD: 'preload' ATTRIBUTE_USERAGENT: 'useragent' - # Internal attribute. + ### Internal attribute. ### ATTRIBUTE_INTERNALINSTANCEID: 'internalinstanceid' - # Error messages. + ### Error messages. ### ERROR_MSG_ALREADY_NAVIGATED: 'The object has already navigated, so its partition cannot be changed.' ERROR_MSG_CANNOT_INJECT_SCRIPT: ': ' + 'Script cannot be injected into content until the page has loaded.' diff --git a/atom/renderer/lib/web-view/web-view.coffee b/atom/renderer/lib/web-view/web-view.coffee index fc01725746ef..15610c85dd51 100644 --- a/atom/renderer/lib/web-view/web-view.coffee +++ b/atom/renderer/lib/web-view/web-view.coffee @@ -4,11 +4,11 @@ v8Util = process.atomBinding 'v8_util' guestViewInternal = require './guest-view-internal' webViewConstants = require './web-view-constants' -# ID generator. +### ID generator. ### nextId = 0 getNextId = -> ++nextId -# Represents the internal state of the WebView node. +### Represents the internal state of the WebView node. ### class WebViewImpl constructor: (@webviewNode) -> v8Util.setHiddenValue @webviewNode, 'internal', this @@ -17,7 +17,7 @@ class WebViewImpl @beforeFirstNavigation = true - # on* Event handlers. + ### on* Event handlers. ### @on = {} @browserPluginNode = @createBrowserPluginNode() @@ -30,20 +30,24 @@ class WebViewImpl shadowRoot.appendChild @browserPluginNode createBrowserPluginNode: -> - # We create BrowserPlugin as a custom element in order to observe changes - # to attributes synchronously. + ### + We create BrowserPlugin as a custom element in order to observe changes + to attributes synchronously. + ### browserPluginNode = new WebViewImpl.BrowserPlugin() v8Util.setHiddenValue browserPluginNode, 'internal', this browserPluginNode - # Resets some state upon reattaching element to the DOM. + ### Resets some state upon reattaching element to the DOM. ### reset: -> - # If guestInstanceId is defined then the has navigated and has - # already picked up a partition ID. Thus, we need to reset the initialization - # state. However, it may be the case that beforeFirstNavigation is false BUT - # guestInstanceId has yet to be initialized. This means that we have not - # heard back from createGuest yet. We will not reset the flag in this case so - # that we don't end up allocating a second guest. + ### + If guestInstanceId is defined then the has navigated and has + already picked up a partition ID. Thus, we need to reset the initialization + state. However, it may be the case that beforeFirstNavigation is false BUT + guestInstanceId has yet to be initialized. This means that we have not + heard back from createGuest yet. We will not reset the flag in this case so + that we don't end up allocating a second guest. + ### if @guestInstanceId guestViewInternal.destroyGuest @guestInstanceId @webContents = null @@ -52,34 +56,38 @@ class WebViewImpl @attributes[webViewConstants.ATTRIBUTE_PARTITION].validPartitionId = true @internalInstanceId = 0 - # Sets the .request property. + ### Sets the .request property. ### setRequestPropertyOnWebViewNode: (request) -> Object.defineProperty @webviewNode, 'request', value: request, enumerable: true setupFocusPropagation: -> unless @webviewNode.hasAttribute 'tabIndex' - # needs a tabIndex in order to be focusable. - # TODO(fsamuel): It would be nice to avoid exposing a tabIndex attribute - # to allow to be focusable. - # See http://crbug.com/231664. + ### + needs a tabIndex in order to be focusable. + TODO(fsamuel): It would be nice to avoid exposing a tabIndex attribute + to allow to be focusable. + See http://crbug.com/231664. + ### @webviewNode.setAttribute 'tabIndex', -1 @webviewNode.addEventListener 'focus', (e) => - # Focus the BrowserPlugin when the takes focus. + ### Focus the BrowserPlugin when the takes focus. ### @browserPluginNode.focus() @webviewNode.addEventListener 'blur', (e) => - # Blur the BrowserPlugin when the loses focus. + ### Blur the BrowserPlugin when the loses focus. ### @browserPluginNode.blur() - # This observer monitors mutations to attributes of the and - # updates the BrowserPlugin properties accordingly. In turn, updating - # a BrowserPlugin property will update the corresponding BrowserPlugin - # attribute, if necessary. See BrowserPlugin::UpdateDOMAttribute for more - # details. + ### + This observer monitors mutations to attributes of the and + updates the BrowserPlugin properties accordingly. In turn, updating + a BrowserPlugin property will update the corresponding BrowserPlugin + attribute, if necessary. See BrowserPlugin::UpdateDOMAttribute for more + details. + ### handleWebviewAttributeMutation: (attributeName, oldValue, newValue) -> if not @attributes[attributeName] or @attributes[attributeName].ignoreMutation return - # Let the changed attribute handle its own mutation; + ### Let the changed attribute handle its own mutation; ### @attributes[attributeName].handleMutation oldValue, newValue handleBrowserPluginAttributeMutation: (attributeName, oldValue, newValue) -> @@ -87,7 +95,7 @@ class WebViewImpl @browserPluginNode.removeAttribute webViewConstants.ATTRIBUTE_INTERNALINSTANCEID @internalInstanceId = parseInt newValue - # Track when the element resizes using the element resize callback. + ### Track when the element resizes using the element resize callback. ### webFrame.registerElementResizeCallback @internalInstanceId, @onElementResize.bind(this) return unless @guestInstanceId @@ -103,8 +111,8 @@ class WebViewImpl width = node.offsetWidth height = node.offsetHeight - # Check the current bounds to make sure we do not resize - # outside of current constraints. + ### Check the current bounds to make sure we do not resize ### + ### outside of current constraints. ### maxWidth = @attributes[webViewConstants.ATTRIBUTE_MAXWIDTH].getValue() | width maxHeight = @attributes[webViewConstants.ATTRIBUTE_MAXHEIGHT].getValue() | width minWidth = @attributes[webViewConstants.ATTRIBUTE_MINWIDTH].getValue() | width @@ -120,12 +128,14 @@ class WebViewImpl newHeight <= maxHeight) node.style.width = newWidth + 'px' node.style.height = newHeight + 'px' - # Only fire the DOM event if the size of the has actually - # changed. + ### + Only fire the DOM event if the size of the has actually + changed. + ### @dispatchEvent webViewEvent onElementResize: (newSize) -> - # Dispatch the 'resize' event. + ### Dispatch the 'resize' event. ### resizeEvent = new Event('resize', bubbles: true) resizeEvent.newWidth = newSize.width resizeEvent.newHeight = newSize.height @@ -141,8 +151,8 @@ class WebViewImpl dispatchEvent: (webViewEvent) -> @webviewNode.dispatchEvent webViewEvent - # Adds an 'on' property on the webview, which can be used to set/unset - # an event handler. + ### Adds an 'on' property on the webview, which can be used to set/unset ### + ### an event handler. ### setupEventProperty: (eventName) -> propertyName = 'on' + eventName.toLowerCase() Object.defineProperty @webviewNode, propertyName, @@ -155,14 +165,16 @@ class WebViewImpl @webviewNode.addEventListener eventName, value enumerable: true - # Updates state upon loadcommit. + ### Updates state upon loadcommit. ### onLoadCommit: (webViewEvent) -> oldValue = @webviewNode.getAttribute webViewConstants.ATTRIBUTE_SRC newValue = webViewEvent.url if webViewEvent.isMainFrame and (oldValue != newValue) - # Touching the src attribute triggers a navigation. To avoid - # triggering a page reload on every guest-initiated navigation, - # we do not handle this mutation + ### + Touching the src attribute triggers a navigation. To avoid + triggering a page reload on every guest-initiated navigation, + we do not handle this mutation. + ### @attributes[webViewConstants.ATTRIBUTE_SRC].setValueIgnoreMutation newValue onAttach: (storagePartitionId) -> @@ -174,11 +186,13 @@ class WebViewImpl userAgentOverride: @userAgentOverride for own attributeName, attribute of @attributes params[attributeName] = attribute.getValue() - # When the WebView is not participating in layout (display:none) - # then getBoundingClientRect() would report a width and height of 0. - # However, in the case where the WebView has a fixed size we can - # use that value to initially size the guest so as to avoid a relayout of - # the on display:block. + ### + When the WebView is not participating in layout (display:none) + then getBoundingClientRect() would report a width and height of 0. + However, in the case where the WebView has a fixed size we can + use that value to initially size the guest so as to avoid a relayout of + the on display:block. + ### css = window.getComputedStyle @webviewNode, null elementRect = @webviewNode.getBoundingClientRect() params.elementWidth = parseInt(elementRect.width) || @@ -194,14 +208,14 @@ class WebViewImpl guestViewInternal.attachGuest @internalInstanceId, @guestInstanceId, @buildParams() -# Registers browser plugin custom element. +### Registers browser plugin custom element. ### registerBrowserPluginElement = -> proto = Object.create HTMLObjectElement.prototype proto.createdCallback = -> @setAttribute 'type', 'application/browser-plugin' @setAttribute 'id', 'browser-plugin-' + getNextId() - # The node fills in the container. + ### The node fills in the container. ### @style.display = 'block' @style.width = '100%' @style.height = '100%' @@ -212,7 +226,7 @@ registerBrowserPluginElement = -> internal.handleBrowserPluginAttributeMutation name, oldValue, newValue proto.attachedCallback = -> - # Load the plugin immediately. + ### Load the plugin immediately. ### unused = this.nonExistentAttribute WebViewImpl.BrowserPlugin = webFrame.registerEmbedderCustomElement 'browserplugin', @@ -223,7 +237,7 @@ registerBrowserPluginElement = -> delete proto.detachedCallback delete proto.attributeChangedCallback -# Registers custom element. +### Registers custom element. ### registerWebViewElement = -> proto = Object.create HTMLObjectElement.prototype @@ -250,7 +264,7 @@ registerWebViewElement = -> internal.elementAttached = true internal.attributes[webViewConstants.ATTRIBUTE_SRC].parse() - # Public-facing API methods. + ### Public-facing API methods. ### methods = [ 'getURL' 'getTitle' @@ -304,7 +318,7 @@ registerWebViewElement = -> 'insertCSS' ] - # Forward proto.foo* method calls to WebViewImpl.foo*. + ### Forward proto.foo* method calls to WebViewImpl.foo*. ### createBlockHandler = (m) -> (args...) -> internal = v8Util.getHiddenValue this, 'internal' @@ -318,14 +332,14 @@ registerWebViewElement = -> proto[m] = createNonBlockHandler m for m in nonblockMethods - # Deprecated. + ### Deprecated. ### deprecate.rename proto, 'getUrl', 'getURL' window.WebView = webFrame.registerEmbedderCustomElement 'webview', prototype: proto - # Delete the callbacks so developers cannot call them and produce unexpected - # behavior. + ### Delete the callbacks so developers cannot call them and produce unexpected ### + ### behavior. ### delete proto.createdCallback delete proto.attachedCallback delete proto.detachedCallback From 1f9691ae13167fc9b60c637eb5fb629e5dcc5c75 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 11 Jan 2016 18:40:23 -0800 Subject: [PATCH 44/95] Convert all source files to JavaScript --- atom/browser/api/lib/app.coffee | 73 -- atom/browser/api/lib/app.js | 131 +++ atom/browser/api/lib/auto-updater.coffee | 12 - atom/browser/api/lib/auto-updater.js | 12 + .../auto-updater/auto-updater-native.coffee | 6 - .../lib/auto-updater/auto-updater-native.js | 9 + .../lib/auto-updater/auto-updater-win.coffee | 44 - .../api/lib/auto-updater/auto-updater-win.js | 78 ++ .../auto-updater/squirrel-update-win.coffee | 71 -- .../lib/auto-updater/squirrel-update-win.js | 118 +++ atom/browser/api/lib/browser-window.coffee | 119 --- atom/browser/api/lib/browser-window.js | 250 ++++++ atom/browser/api/lib/content-tracing.coffee | 1 - atom/browser/api/lib/content-tracing.js | 1 + atom/browser/api/lib/dialog.coffee | 127 --- atom/browser/api/lib/dialog.js | 175 ++++ atom/browser/api/lib/exports/electron.coffee | 57 -- atom/browser/api/lib/exports/electron.js | 115 +++ atom/browser/api/lib/global-shortcut.coffee | 3 - atom/browser/api/lib/global-shortcut.js | 5 + atom/browser/api/lib/ipc-main.coffee | 3 - atom/browser/api/lib/ipc-main.js | 5 + atom/browser/api/lib/ipc.coffee | 6 - atom/browser/api/lib/ipc.js | 10 + atom/browser/api/lib/menu-item.coffee | 73 -- atom/browser/api/lib/menu-item.js | 108 +++ atom/browser/api/lib/menu.coffee | 179 ---- atom/browser/api/lib/menu.js | 350 ++++++++ .../api/lib/navigation-controller.coffee | 127 --- atom/browser/api/lib/navigation-controller.js | 195 +++++ atom/browser/api/lib/power-monitor.coffee | 7 - atom/browser/api/lib/power-monitor.js | 9 + .../browser/api/lib/power-save-blocker.coffee | 3 - atom/browser/api/lib/power-save-blocker.js | 5 + atom/browser/api/lib/protocol.coffee | 25 - atom/browser/api/lib/protocol.js | 35 + atom/browser/api/lib/screen.coffee | 6 - atom/browser/api/lib/screen.js | 9 + atom/browser/api/lib/session.coffee | 24 - atom/browser/api/lib/session.js | 42 + atom/browser/api/lib/tray.coffee | 20 - atom/browser/api/lib/tray.js | 28 + atom/browser/api/lib/web-contents.coffee | 141 --- atom/browser/api/lib/web-contents.js | 210 +++++ atom/browser/lib/chrome-extension.coffee | 98 --- atom/browser/lib/chrome-extension.js | 163 ++++ atom/browser/lib/desktop-capturer.coffee | 41 - atom/browser/lib/desktop-capturer.js | 85 ++ atom/browser/lib/guest-view-manager.coffee | 177 ---- atom/browser/lib/guest-view-manager.js | 238 +++++ atom/browser/lib/guest-window-manager.coffee | 88 -- atom/browser/lib/guest-window-manager.js | 137 +++ atom/browser/lib/init.coffee | 120 --- atom/browser/lib/init.js | 201 +++++ atom/browser/lib/objects-registry.coffee | 73 -- atom/browser/lib/objects-registry.js | 133 +++ atom/browser/lib/rpc-server.coffee | 239 ----- atom/browser/lib/rpc-server.js | 389 +++++++++ atom/common/api/lib/callbacks-registry.coffee | 45 - atom/common/api/lib/callbacks-registry.js | 68 ++ atom/common/api/lib/clipboard.coffee | 5 - atom/common/api/lib/clipboard.js | 7 + atom/common/api/lib/crash-reporter.coffee | 69 -- atom/common/api/lib/crash-reporter.js | 104 +++ atom/common/api/lib/deprecate.coffee | 69 -- atom/common/api/lib/deprecate.js | 115 +++ atom/common/api/lib/exports/electron.coffee | 29 - atom/common/api/lib/exports/electron.js | 59 ++ atom/common/api/lib/native-image.coffee | 7 - atom/common/api/lib/native-image.js | 12 + atom/common/api/lib/shell.coffee | 1 - atom/common/api/lib/shell.js | 1 + atom/common/lib/asar.coffee | 394 --------- atom/common/lib/asar.js | 608 +++++++++++++ atom/common/lib/asar_init.coffee | 22 - atom/common/lib/asar_init.js | 15 + atom/common/lib/init.coffee | 40 - atom/common/lib/init.js | 62 ++ atom/common/lib/reset-search-paths.coffee | 29 - atom/common/lib/reset-search-paths.js | 45 + atom/renderer/api/lib/desktop-capturer.coffee | 20 - atom/renderer/api/lib/desktop-capturer.js | 50 ++ atom/renderer/api/lib/exports/electron.coffee | 22 - atom/renderer/api/lib/exports/electron.js | 43 + atom/renderer/api/lib/ipc-renderer.coffee | 18 - atom/renderer/api/lib/ipc-renderer.js | 33 + atom/renderer/api/lib/ipc.coffee | 19 - atom/renderer/api/lib/ipc.js | 38 + atom/renderer/api/lib/remote.coffee | 209 ----- atom/renderer/api/lib/remote.js | 394 +++++++++ atom/renderer/api/lib/screen.coffee | 1 - atom/renderer/api/lib/screen.js | 1 + atom/renderer/api/lib/web-frame.coffee | 9 - atom/renderer/api/lib/web-frame.js | 16 + atom/renderer/lib/chrome-api.coffee | 10 - atom/renderer/lib/chrome-api.js | 16 + atom/renderer/lib/init.coffee | 111 --- atom/renderer/lib/init.js | 154 ++++ atom/renderer/lib/inspector.coffee | 60 -- atom/renderer/lib/inspector.js | 85 ++ atom/renderer/lib/override.coffee | 129 --- atom/renderer/lib/override.js | 249 ++++++ .../lib/web-view/guest-view-internal.coffee | 89 -- .../lib/web-view/guest-view-internal.js | 113 +++ .../lib/web-view/web-view-attributes.coffee | 240 ----- .../lib/web-view/web-view-attributes.js | 410 +++++++++ .../lib/web-view/web-view-constants.coffee | 28 - .../lib/web-view/web-view-constants.js | 29 + atom/renderer/lib/web-view/web-view.coffee | 356 -------- atom/renderer/lib/web-view/web-view.js | 435 ++++++++++ spec/api-app-spec.coffee | 80 -- spec/api-app-spec.js | 111 +++ spec/api-browser-window-spec.coffee | 339 -------- spec/api-browser-window-spec.js | 492 +++++++++++ spec/api-clipboard-spec.coffee | 52 -- spec/api-clipboard-spec.js | 55 ++ spec/api-crash-reporter-spec.coffee | 66 -- spec/api-crash-reporter-spec.js | 94 ++ spec/api-desktop-capturer.coffee | 9 - spec/api-desktop-capturer.js | 17 + spec/api-ipc-spec.coffee | 110 --- spec/api-ipc-spec.js | 147 ++++ spec/api-menu-spec.coffee | 172 ---- spec/api-menu-spec.js | 349 ++++++++ spec/api-protocol-spec.coffee | 499 ----------- spec/api-protocol-spec.js | 820 ++++++++++++++++++ spec/api-screen-spec.coffee | 17 - spec/api-screen-spec.js | 25 + spec/api-session-spec.coffee | 138 --- spec/api-session-spec.js | 218 +++++ spec/api-web-frame-spec.coffee | 18 - spec/api-web-frame-spec.js | 25 + spec/api-web-request-spec.coffee | 243 ------ spec/api-web-request-spec.js | 372 ++++++++ spec/asar-spec.coffee | 578 ------------ spec/asar-spec.js | 805 +++++++++++++++++ spec/chromium-spec.coffee | 275 ------ spec/chromium-spec.js | 368 ++++++++ spec/modules-spec.coffee | 38 - spec/modules-spec.js | 53 ++ spec/node-spec.coffee | 156 ---- spec/node-spec.js | 213 +++++ spec/webview-spec.coffee | 517 ----------- spec/webview-spec.js | 639 ++++++++++++++ 144 files changed, 11211 insertions(+), 7301 deletions(-) delete mode 100644 atom/browser/api/lib/app.coffee create mode 100644 atom/browser/api/lib/app.js delete mode 100644 atom/browser/api/lib/auto-updater.coffee create mode 100644 atom/browser/api/lib/auto-updater.js delete mode 100644 atom/browser/api/lib/auto-updater/auto-updater-native.coffee create mode 100644 atom/browser/api/lib/auto-updater/auto-updater-native.js delete mode 100644 atom/browser/api/lib/auto-updater/auto-updater-win.coffee create mode 100644 atom/browser/api/lib/auto-updater/auto-updater-win.js delete mode 100644 atom/browser/api/lib/auto-updater/squirrel-update-win.coffee create mode 100644 atom/browser/api/lib/auto-updater/squirrel-update-win.js delete mode 100644 atom/browser/api/lib/browser-window.coffee create mode 100644 atom/browser/api/lib/browser-window.js delete mode 100644 atom/browser/api/lib/content-tracing.coffee create mode 100644 atom/browser/api/lib/content-tracing.js delete mode 100644 atom/browser/api/lib/dialog.coffee create mode 100644 atom/browser/api/lib/dialog.js delete mode 100644 atom/browser/api/lib/exports/electron.coffee create mode 100644 atom/browser/api/lib/exports/electron.js delete mode 100644 atom/browser/api/lib/global-shortcut.coffee create mode 100644 atom/browser/api/lib/global-shortcut.js delete mode 100644 atom/browser/api/lib/ipc-main.coffee create mode 100644 atom/browser/api/lib/ipc-main.js delete mode 100644 atom/browser/api/lib/ipc.coffee create mode 100644 atom/browser/api/lib/ipc.js delete mode 100644 atom/browser/api/lib/menu-item.coffee create mode 100644 atom/browser/api/lib/menu-item.js delete mode 100644 atom/browser/api/lib/menu.coffee create mode 100644 atom/browser/api/lib/menu.js delete mode 100644 atom/browser/api/lib/navigation-controller.coffee create mode 100644 atom/browser/api/lib/navigation-controller.js delete mode 100644 atom/browser/api/lib/power-monitor.coffee create mode 100644 atom/browser/api/lib/power-monitor.js delete mode 100644 atom/browser/api/lib/power-save-blocker.coffee create mode 100644 atom/browser/api/lib/power-save-blocker.js delete mode 100644 atom/browser/api/lib/protocol.coffee create mode 100644 atom/browser/api/lib/protocol.js delete mode 100644 atom/browser/api/lib/screen.coffee create mode 100644 atom/browser/api/lib/screen.js delete mode 100644 atom/browser/api/lib/session.coffee create mode 100644 atom/browser/api/lib/session.js delete mode 100644 atom/browser/api/lib/tray.coffee create mode 100644 atom/browser/api/lib/tray.js delete mode 100644 atom/browser/api/lib/web-contents.coffee create mode 100644 atom/browser/api/lib/web-contents.js delete mode 100644 atom/browser/lib/chrome-extension.coffee create mode 100644 atom/browser/lib/chrome-extension.js delete mode 100644 atom/browser/lib/desktop-capturer.coffee create mode 100644 atom/browser/lib/desktop-capturer.js delete mode 100644 atom/browser/lib/guest-view-manager.coffee create mode 100644 atom/browser/lib/guest-view-manager.js delete mode 100644 atom/browser/lib/guest-window-manager.coffee create mode 100644 atom/browser/lib/guest-window-manager.js delete mode 100644 atom/browser/lib/init.coffee create mode 100644 atom/browser/lib/init.js delete mode 100644 atom/browser/lib/objects-registry.coffee create mode 100644 atom/browser/lib/objects-registry.js delete mode 100644 atom/browser/lib/rpc-server.coffee create mode 100644 atom/browser/lib/rpc-server.js delete mode 100644 atom/common/api/lib/callbacks-registry.coffee create mode 100644 atom/common/api/lib/callbacks-registry.js delete mode 100644 atom/common/api/lib/clipboard.coffee create mode 100644 atom/common/api/lib/clipboard.js delete mode 100644 atom/common/api/lib/crash-reporter.coffee create mode 100644 atom/common/api/lib/crash-reporter.js delete mode 100644 atom/common/api/lib/deprecate.coffee create mode 100644 atom/common/api/lib/deprecate.js delete mode 100644 atom/common/api/lib/exports/electron.coffee create mode 100644 atom/common/api/lib/exports/electron.js delete mode 100644 atom/common/api/lib/native-image.coffee create mode 100644 atom/common/api/lib/native-image.js delete mode 100644 atom/common/api/lib/shell.coffee create mode 100644 atom/common/api/lib/shell.js delete mode 100644 atom/common/lib/asar.coffee create mode 100644 atom/common/lib/asar.js delete mode 100644 atom/common/lib/asar_init.coffee create mode 100644 atom/common/lib/asar_init.js delete mode 100644 atom/common/lib/init.coffee create mode 100644 atom/common/lib/init.js delete mode 100644 atom/common/lib/reset-search-paths.coffee create mode 100644 atom/common/lib/reset-search-paths.js delete mode 100644 atom/renderer/api/lib/desktop-capturer.coffee create mode 100644 atom/renderer/api/lib/desktop-capturer.js delete mode 100644 atom/renderer/api/lib/exports/electron.coffee create mode 100644 atom/renderer/api/lib/exports/electron.js delete mode 100644 atom/renderer/api/lib/ipc-renderer.coffee create mode 100644 atom/renderer/api/lib/ipc-renderer.js delete mode 100644 atom/renderer/api/lib/ipc.coffee create mode 100644 atom/renderer/api/lib/ipc.js delete mode 100644 atom/renderer/api/lib/remote.coffee create mode 100644 atom/renderer/api/lib/remote.js delete mode 100644 atom/renderer/api/lib/screen.coffee create mode 100644 atom/renderer/api/lib/screen.js delete mode 100644 atom/renderer/api/lib/web-frame.coffee create mode 100644 atom/renderer/api/lib/web-frame.js delete mode 100644 atom/renderer/lib/chrome-api.coffee create mode 100644 atom/renderer/lib/chrome-api.js delete mode 100644 atom/renderer/lib/init.coffee create mode 100644 atom/renderer/lib/init.js delete mode 100644 atom/renderer/lib/inspector.coffee create mode 100644 atom/renderer/lib/inspector.js delete mode 100644 atom/renderer/lib/override.coffee create mode 100644 atom/renderer/lib/override.js delete mode 100644 atom/renderer/lib/web-view/guest-view-internal.coffee create mode 100644 atom/renderer/lib/web-view/guest-view-internal.js delete mode 100644 atom/renderer/lib/web-view/web-view-attributes.coffee create mode 100644 atom/renderer/lib/web-view/web-view-attributes.js delete mode 100644 atom/renderer/lib/web-view/web-view-constants.coffee create mode 100644 atom/renderer/lib/web-view/web-view-constants.js delete mode 100644 atom/renderer/lib/web-view/web-view.coffee create mode 100644 atom/renderer/lib/web-view/web-view.js delete mode 100644 spec/api-app-spec.coffee create mode 100644 spec/api-app-spec.js delete mode 100644 spec/api-browser-window-spec.coffee create mode 100644 spec/api-browser-window-spec.js delete mode 100644 spec/api-clipboard-spec.coffee create mode 100644 spec/api-clipboard-spec.js delete mode 100644 spec/api-crash-reporter-spec.coffee create mode 100644 spec/api-crash-reporter-spec.js delete mode 100644 spec/api-desktop-capturer.coffee create mode 100644 spec/api-desktop-capturer.js delete mode 100644 spec/api-ipc-spec.coffee create mode 100644 spec/api-ipc-spec.js delete mode 100644 spec/api-menu-spec.coffee create mode 100644 spec/api-menu-spec.js delete mode 100644 spec/api-protocol-spec.coffee create mode 100644 spec/api-protocol-spec.js delete mode 100644 spec/api-screen-spec.coffee create mode 100644 spec/api-screen-spec.js delete mode 100644 spec/api-session-spec.coffee create mode 100644 spec/api-session-spec.js delete mode 100644 spec/api-web-frame-spec.coffee create mode 100644 spec/api-web-frame-spec.js delete mode 100644 spec/api-web-request-spec.coffee create mode 100644 spec/api-web-request-spec.js delete mode 100644 spec/asar-spec.coffee create mode 100644 spec/asar-spec.js delete mode 100644 spec/chromium-spec.coffee create mode 100644 spec/chromium-spec.js delete mode 100644 spec/modules-spec.coffee create mode 100644 spec/modules-spec.js delete mode 100644 spec/node-spec.coffee create mode 100644 spec/node-spec.js delete mode 100644 spec/webview-spec.coffee create mode 100644 spec/webview-spec.js diff --git a/atom/browser/api/lib/app.coffee b/atom/browser/api/lib/app.coffee deleted file mode 100644 index fa9df9d9c70a..000000000000 --- a/atom/browser/api/lib/app.coffee +++ /dev/null @@ -1,73 +0,0 @@ -{deprecate, session, Menu} = require 'electron' -{EventEmitter} = require 'events' - -bindings = process.atomBinding 'app' -downloadItemBindings = process.atomBinding 'download_item' - -app = bindings.app -app.__proto__ = EventEmitter.prototype - -app.setApplicationMenu = (menu) -> - Menu.setApplicationMenu menu - -app.getApplicationMenu = -> - Menu.getApplicationMenu() - -app.commandLine = - appendSwitch: bindings.appendSwitch, - appendArgument: bindings.appendArgument - -if process.platform is 'darwin' - app.dock = - bounce: (type='informational') -> bindings.dockBounce type - cancelBounce: bindings.dockCancelBounce - setBadge: bindings.dockSetBadgeText - getBadge: bindings.dockGetBadgeText - hide: bindings.dockHide - show: bindings.dockShow - setMenu: bindings.dockSetMenu - -appPath = null -app.setAppPath = (path) -> - appPath = path - -app.getAppPath = -> - appPath - -### Routes the events to webContents. ### -for name in ['login', 'certificate-error', 'select-client-certificate'] - do (name) -> - app.on name, (event, webContents, args...) -> - webContents.emit name, event, args... - -### Deprecated. ### -app.getHomeDir = deprecate 'app.getHomeDir', 'app.getPath', -> - @getPath 'home' -app.getDataPath = deprecate 'app.getDataPath', 'app.getPath', -> - @getPath 'userData' -app.setDataPath = deprecate 'app.setDataPath', 'app.setPath', (path) -> - @setPath 'userData', path -app.resolveProxy = deprecate 'app.resolveProxy', 'session.defaultSession.resolveProxy', (url, callback) -> - session.defaultSession.resolveProxy url, callback -deprecate.rename app, 'terminate', 'quit' -deprecate.event app, 'finish-launching', 'ready', -> - ### give default app a chance to setup default menu. ### - setImmediate => - @emit 'finish-launching' -deprecate.event app, 'activate-with-no-open-windows', 'activate', (event, hasVisibleWindows) -> - @emit 'activate-with-no-open-windows', event if not hasVisibleWindows -deprecate.event app, 'select-certificate', 'select-client-certificate' - -### Wrappers for native classes. ### -wrapDownloadItem = (downloadItem) -> - ### downloadItem is an EventEmitter. ### - downloadItem.__proto__ = EventEmitter.prototype - ### Deprecated. ### - deprecate.property downloadItem, 'url', 'getURL' - deprecate.property downloadItem, 'filename', 'getFilename' - deprecate.property downloadItem, 'mimeType', 'getMimeType' - deprecate.rename downloadItem, 'getUrl', 'getURL' -downloadItemBindings._setWrapDownloadItem wrapDownloadItem - -### Only one App object pemitted. ### -module.exports = app diff --git a/atom/browser/api/lib/app.js b/atom/browser/api/lib/app.js new file mode 100644 index 000000000000..84b0c3c77e89 --- /dev/null +++ b/atom/browser/api/lib/app.js @@ -0,0 +1,131 @@ +var EventEmitter, Menu, app, appPath, bindings, deprecate, downloadItemBindings, fn, i, len, name, ref, ref1, session, wrapDownloadItem, + slice = [].slice; + +ref = require('electron'), deprecate = ref.deprecate, session = ref.session, Menu = ref.Menu; + +EventEmitter = require('events').EventEmitter; + +bindings = process.atomBinding('app'); + +downloadItemBindings = process.atomBinding('download_item'); + +app = bindings.app; + +app.__proto__ = EventEmitter.prototype; + +app.setApplicationMenu = function(menu) { + return Menu.setApplicationMenu(menu); +}; + +app.getApplicationMenu = function() { + return Menu.getApplicationMenu(); +}; + +app.commandLine = { + appendSwitch: bindings.appendSwitch, + appendArgument: bindings.appendArgument +}; + +if (process.platform === 'darwin') { + app.dock = { + bounce: function(type) { + if (type == null) { + type = 'informational'; + } + return bindings.dockBounce(type); + }, + cancelBounce: bindings.dockCancelBounce, + setBadge: bindings.dockSetBadgeText, + getBadge: bindings.dockGetBadgeText, + hide: bindings.dockHide, + show: bindings.dockShow, + setMenu: bindings.dockSetMenu + }; +} + +appPath = null; + +app.setAppPath = function(path) { + return appPath = path; +}; + +app.getAppPath = function() { + return appPath; +}; + + +/* Routes the events to webContents. */ + +ref1 = ['login', 'certificate-error', 'select-client-certificate']; +fn = function(name) { + return app.on(name, function() { + var args, event, webContents; + event = arguments[0], webContents = arguments[1], args = 3 <= arguments.length ? slice.call(arguments, 2) : []; + return webContents.emit.apply(webContents, [name, event].concat(slice.call(args))); + }); +}; +for (i = 0, len = ref1.length; i < len; i++) { + name = ref1[i]; + fn(name); +} + + +/* Deprecated. */ + +app.getHomeDir = deprecate('app.getHomeDir', 'app.getPath', function() { + return this.getPath('home'); +}); + +app.getDataPath = deprecate('app.getDataPath', 'app.getPath', function() { + return this.getPath('userData'); +}); + +app.setDataPath = deprecate('app.setDataPath', 'app.setPath', function(path) { + return this.setPath('userData', path); +}); + +app.resolveProxy = deprecate('app.resolveProxy', 'session.defaultSession.resolveProxy', function(url, callback) { + return session.defaultSession.resolveProxy(url, callback); +}); + +deprecate.rename(app, 'terminate', 'quit'); + +deprecate.event(app, 'finish-launching', 'ready', function() { + + /* give default app a chance to setup default menu. */ + return setImmediate((function(_this) { + return function() { + return _this.emit('finish-launching'); + }; + })(this)); +}); + +deprecate.event(app, 'activate-with-no-open-windows', 'activate', function(event, hasVisibleWindows) { + if (!hasVisibleWindows) { + return this.emit('activate-with-no-open-windows', event); + } +}); + +deprecate.event(app, 'select-certificate', 'select-client-certificate'); + + +/* Wrappers for native classes. */ + +wrapDownloadItem = function(downloadItem) { + + /* downloadItem is an EventEmitter. */ + downloadItem.__proto__ = EventEmitter.prototype; + + /* Deprecated. */ + deprecate.property(downloadItem, 'url', 'getURL'); + deprecate.property(downloadItem, 'filename', 'getFilename'); + deprecate.property(downloadItem, 'mimeType', 'getMimeType'); + return deprecate.rename(downloadItem, 'getUrl', 'getURL'); +}; + +downloadItemBindings._setWrapDownloadItem(wrapDownloadItem); + + +/* Only one App object pemitted. */ + +module.exports = app; diff --git a/atom/browser/api/lib/auto-updater.coffee b/atom/browser/api/lib/auto-updater.coffee deleted file mode 100644 index 5cb75832c755..000000000000 --- a/atom/browser/api/lib/auto-updater.coffee +++ /dev/null @@ -1,12 +0,0 @@ -{deprecate} = require 'electron' - -autoUpdater = - if process.platform is 'win32' - require './auto-updater/auto-updater-win' - else - require './auto-updater/auto-updater-native' - -### Deprecated. ### -deprecate.rename autoUpdater, 'setFeedUrl', 'setFeedURL' - -module.exports = autoUpdater diff --git a/atom/browser/api/lib/auto-updater.js b/atom/browser/api/lib/auto-updater.js new file mode 100644 index 000000000000..d666ba8eed6c --- /dev/null +++ b/atom/browser/api/lib/auto-updater.js @@ -0,0 +1,12 @@ +var autoUpdater, deprecate; + +deprecate = require('electron').deprecate; + +autoUpdater = process.platform === 'win32' ? require('./auto-updater/auto-updater-win') : require('./auto-updater/auto-updater-native'); + + +/* Deprecated. */ + +deprecate.rename(autoUpdater, 'setFeedUrl', 'setFeedURL'); + +module.exports = autoUpdater; diff --git a/atom/browser/api/lib/auto-updater/auto-updater-native.coffee b/atom/browser/api/lib/auto-updater/auto-updater-native.coffee deleted file mode 100644 index 187be64f5ade..000000000000 --- a/atom/browser/api/lib/auto-updater/auto-updater-native.coffee +++ /dev/null @@ -1,6 +0,0 @@ -{EventEmitter} = require 'events' -{autoUpdater} = process.atomBinding 'auto_updater' - -autoUpdater.__proto__ = EventEmitter.prototype - -module.exports = autoUpdater diff --git a/atom/browser/api/lib/auto-updater/auto-updater-native.js b/atom/browser/api/lib/auto-updater/auto-updater-native.js new file mode 100644 index 000000000000..9f22b33feb1d --- /dev/null +++ b/atom/browser/api/lib/auto-updater/auto-updater-native.js @@ -0,0 +1,9 @@ +var EventEmitter, autoUpdater; + +EventEmitter = require('events').EventEmitter; + +autoUpdater = process.atomBinding('auto_updater').autoUpdater; + +autoUpdater.__proto__ = EventEmitter.prototype; + +module.exports = autoUpdater; diff --git a/atom/browser/api/lib/auto-updater/auto-updater-win.coffee b/atom/browser/api/lib/auto-updater/auto-updater-win.coffee deleted file mode 100644 index 6d1caecb6bcb..000000000000 --- a/atom/browser/api/lib/auto-updater/auto-updater-win.coffee +++ /dev/null @@ -1,44 +0,0 @@ -{app} = require 'electron' -{EventEmitter} = require 'events' -url = require 'url' - -squirrelUpdate = require './squirrel-update-win' - -class AutoUpdater extends EventEmitter - quitAndInstall: -> - squirrelUpdate.processStart() - app.quit() - - setFeedURL: (updateURL) -> - @updateURL = updateURL - - checkForUpdates: -> - return @emitError 'Update URL is not set' unless @updateURL - return @emitError 'Can not find Squirrel' unless squirrelUpdate.supported() - - @emit 'checking-for-update' - - squirrelUpdate.download @updateURL, (error, update) => - return @emitError error if error? - return @emit 'update-not-available' unless update? - - @emit 'update-available' - - squirrelUpdate.update @updateURL, (error) => - return @emitError error if error? - - {releaseNotes, version} = update - ### Following information is not available on Windows, so fake them. ### - date = new Date - url = @updateURL - - @emit 'update-downloaded', {}, releaseNotes, version, date, url, => @quitAndInstall() - - ### - Private: Emit both error object and message, this is to keep compatibility - with Old APIs. - ### - emitError: (message) -> - @emit 'error', new Error(message), message - -module.exports = new AutoUpdater diff --git a/atom/browser/api/lib/auto-updater/auto-updater-win.js b/atom/browser/api/lib/auto-updater/auto-updater-win.js new file mode 100644 index 000000000000..b2ef7361d2d3 --- /dev/null +++ b/atom/browser/api/lib/auto-updater/auto-updater-win.js @@ -0,0 +1,78 @@ +var AutoUpdater, EventEmitter, app, squirrelUpdate, url, + extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }, + hasProp = {}.hasOwnProperty; + +app = require('electron').app; + +EventEmitter = require('events').EventEmitter; + +url = require('url'); + +squirrelUpdate = require('./squirrel-update-win'); + +AutoUpdater = (function(superClass) { + extend(AutoUpdater, superClass); + + function AutoUpdater() { + return AutoUpdater.__super__.constructor.apply(this, arguments); + } + + AutoUpdater.prototype.quitAndInstall = function() { + squirrelUpdate.processStart(); + return app.quit(); + }; + + AutoUpdater.prototype.setFeedURL = function(updateURL) { + return this.updateURL = updateURL; + }; + + AutoUpdater.prototype.checkForUpdates = function() { + if (!this.updateURL) { + return this.emitError('Update URL is not set'); + } + if (!squirrelUpdate.supported()) { + return this.emitError('Can not find Squirrel'); + } + this.emit('checking-for-update'); + return squirrelUpdate.download(this.updateURL, (function(_this) { + return function(error, update) { + if (error != null) { + return _this.emitError(error); + } + if (update == null) { + return _this.emit('update-not-available'); + } + _this.emit('update-available'); + return squirrelUpdate.update(_this.updateURL, function(error) { + var date, releaseNotes, version; + if (error != null) { + return _this.emitError(error); + } + releaseNotes = update.releaseNotes, version = update.version; + + /* Following information is not available on Windows, so fake them. */ + date = new Date; + url = _this.updateURL; + return _this.emit('update-downloaded', {}, releaseNotes, version, date, url, function() { + return _this.quitAndInstall(); + }); + }); + }; + })(this)); + }; + + + /* + Private: Emit both error object and message, this is to keep compatibility + with Old APIs. + */ + + AutoUpdater.prototype.emitError = function(message) { + return this.emit('error', new Error(message), message); + }; + + return AutoUpdater; + +})(EventEmitter); + +module.exports = new AutoUpdater; diff --git a/atom/browser/api/lib/auto-updater/squirrel-update-win.coffee b/atom/browser/api/lib/auto-updater/squirrel-update-win.coffee deleted file mode 100644 index 5c4342b0ff48..000000000000 --- a/atom/browser/api/lib/auto-updater/squirrel-update-win.coffee +++ /dev/null @@ -1,71 +0,0 @@ -fs = require 'fs' -path = require 'path' -{spawn} = require 'child_process' - -### i.e. my-app/app-0.1.13/ ### -appFolder = path.dirname process.execPath -### i.e. my-app/Update.exe ### -updateExe = path.resolve appFolder, '..', 'Update.exe' -exeName = path.basename process.execPath - -### - Spawn a command and invoke the callback when it completes with an error - and the output from standard out. -### -spawnUpdate = (args, detached, callback) -> - try - spawnedProcess = spawn updateExe, args, {detached} - catch error - ### Shouldn't happen, but still guard it. ### - process.nextTick -> callback error - return - - stdout = '' - stderr = '' - spawnedProcess.stdout.on 'data', (data) -> stdout += data - spawnedProcess.stderr.on 'data', (data) -> stderr += data - - errorEmitted = false - spawnedProcess.on 'error', (error) -> - errorEmitted = true - callback error - spawnedProcess.on 'exit', (code, signal) -> - ### We may have already emitted an error. ### - return if errorEmitted - - ### Process terminated with error. ### - if code isnt 0 - return callback "Command failed: #{signal ? code}\n#{stderr}" - - ### Success. ### - callback null, stdout - -### Start an instance of the installed app. ### -exports.processStart = (callback) -> - spawnUpdate ['--processStart', exeName], true, -> - -### Download the releases specified by the URL and write new results to stdout. ### -exports.download = (updateURL, callback) -> - spawnUpdate ['--download', updateURL], false, (error, stdout) -> - return callback(error) if error? - - try - ### Last line of output is the JSON details about the releases ### - json = stdout.trim().split('\n').pop() - update = JSON.parse(json)?.releasesToApply?.pop?() - catch - return callback "Invalid result:\n#{stdout}" - - callback null, update - -### Update the application to the latest remote version specified by URL. ### -exports.update = (updateURL, callback) -> - spawnUpdate ['--update', updateURL], false, callback - -### Is the Update.exe installed with the current application? ### -exports.supported = -> - try - fs.accessSync updateExe, fs.R_OK - return true - catch - return false diff --git a/atom/browser/api/lib/auto-updater/squirrel-update-win.js b/atom/browser/api/lib/auto-updater/squirrel-update-win.js new file mode 100644 index 000000000000..205f08ce34f9 --- /dev/null +++ b/atom/browser/api/lib/auto-updater/squirrel-update-win.js @@ -0,0 +1,118 @@ +var appFolder, exeName, fs, path, spawn, spawnUpdate, updateExe; + +fs = require('fs'); + +path = require('path'); + +spawn = require('child_process').spawn; + + +/* i.e. my-app/app-0.1.13/ */ + +appFolder = path.dirname(process.execPath); + + +/* i.e. my-app/Update.exe */ + +updateExe = path.resolve(appFolder, '..', 'Update.exe'); + +exeName = path.basename(process.execPath); + + +/* + Spawn a command and invoke the callback when it completes with an error + and the output from standard out. + */ + +spawnUpdate = function(args, detached, callback) { + var error, error1, errorEmitted, spawnedProcess, stderr, stdout; + try { + spawnedProcess = spawn(updateExe, args, { + detached: detached + }); + } catch (error1) { + error = error1; + + /* Shouldn't happen, but still guard it. */ + process.nextTick(function() { + return callback(error); + }); + return; + } + stdout = ''; + stderr = ''; + spawnedProcess.stdout.on('data', function(data) { + return stdout += data; + }); + spawnedProcess.stderr.on('data', function(data) { + return stderr += data; + }); + errorEmitted = false; + spawnedProcess.on('error', function(error) { + errorEmitted = true; + return callback(error); + }); + return spawnedProcess.on('exit', function(code, signal) { + + /* We may have already emitted an error. */ + if (errorEmitted) { + return; + } + + /* Process terminated with error. */ + if (code !== 0) { + return callback("Command failed: " + (signal != null ? signal : code) + "\n" + stderr); + } + + /* Success. */ + return callback(null, stdout); + }); +}; + + +/* Start an instance of the installed app. */ + +exports.processStart = function(callback) { + return spawnUpdate(['--processStart', exeName], true, function() {}); +}; + + +/* Download the releases specified by the URL and write new results to stdout. */ + +exports.download = function(updateURL, callback) { + return spawnUpdate(['--download', updateURL], false, function(error, stdout) { + var error1, json, ref, ref1, update; + if (error != null) { + return callback(error); + } + try { + + /* Last line of output is the JSON details about the releases */ + json = stdout.trim().split('\n').pop(); + update = (ref = JSON.parse(json)) != null ? (ref1 = ref.releasesToApply) != null ? typeof ref1.pop === "function" ? ref1.pop() : void 0 : void 0 : void 0; + } catch (error1) { + return callback("Invalid result:\n" + stdout); + } + return callback(null, update); + }); +}; + + +/* Update the application to the latest remote version specified by URL. */ + +exports.update = function(updateURL, callback) { + return spawnUpdate(['--update', updateURL], false, callback); +}; + + +/* Is the Update.exe installed with the current application? */ + +exports.supported = function() { + var error1; + try { + fs.accessSync(updateExe, fs.R_OK); + return true; + } catch (error1) { + return false; + } +}; diff --git a/atom/browser/api/lib/browser-window.coffee b/atom/browser/api/lib/browser-window.coffee deleted file mode 100644 index dd54f939df6f..000000000000 --- a/atom/browser/api/lib/browser-window.coffee +++ /dev/null @@ -1,119 +0,0 @@ -{ipcMain, deprecate} = require 'electron' -{EventEmitter} = require 'events' - -{BrowserWindow} = process.atomBinding 'window' -BrowserWindow::__proto__ = EventEmitter.prototype - -BrowserWindow::_init = -> - ### avoid recursive require. ### - {app} = require 'electron' - - ### Simulate the application menu on platforms other than OS X. ### - if process.platform isnt 'darwin' - menu = app.getApplicationMenu() - @setMenu menu if menu? - - ### Make new windows requested by links behave like "window.open" ### - @webContents.on '-new-window', (event, url, frameName) -> - options = show: true, width: 800, height: 600 - ipcMain.emit 'ATOM_SHELL_GUEST_WINDOW_MANAGER_WINDOW_OPEN', event, url, frameName, options - - ### - window.resizeTo(...) - window.moveTo(...) - ### - @webContents.on 'move', (event, size) => - @setBounds size - - ### Hide the auto-hide menu when webContents is focused. ### - @webContents.on 'activate', => - if process.platform isnt 'darwin' and @isMenuBarAutoHide() and @isMenuBarVisible() - @setMenuBarVisibility false - - ### Forward the crashed event. ### - @webContents.on 'crashed', => - @emit 'crashed' - - ### Change window title to page title. ### - @webContents.on 'page-title-updated', (event, title, explicitSet) => - @emit 'page-title-updated', event, title - @setTitle title unless event.defaultPrevented - - ### - Sometimes the webContents doesn't get focus when window is shown, so we have - to force focusing on webContents in this case. The safest way is to focus it - when we first start to load URL, if we do it earlier it won't have effect, - if we do it later we might move focus in the page. - Though this hack is only needed on OS X when the app is launched from - Finder, we still do it on all platforms in case of other bugs we don't know. - ### - @webContents.once 'load-url', -> - @focus() - - ### Redirect focus/blur event to app instance too. ### - @on 'blur', (event) => - app.emit 'browser-window-blur', event, this - @on 'focus', (event) => - app.emit 'browser-window-focus', event, this - - ### Notify the creation of the window. ### - app.emit 'browser-window-created', {}, this - - ### Be compatible with old APIs. ### - @webContents.on 'devtools-focused', => @emit 'devtools-focused' - @webContents.on 'devtools-opened', => @emit 'devtools-opened' - @webContents.on 'devtools-closed', => @emit 'devtools-closed' - Object.defineProperty this, 'devToolsWebContents', - enumerable: true, - configurable: false, - get: -> @webContents.devToolsWebContents - -BrowserWindow.getFocusedWindow = -> - windows = BrowserWindow.getAllWindows() - return window for window in windows when window.isFocused() - null - -BrowserWindow.fromWebContents = (webContents) -> - windows = BrowserWindow.getAllWindows() - return window for window in windows when window.webContents?.equal webContents - -BrowserWindow.fromDevToolsWebContents = (webContents) -> - windows = BrowserWindow.getAllWindows() - return window for window in windows when window.devToolsWebContents?.equal webContents - -### Helpers. ### -BrowserWindow::loadURL = -> @webContents.loadURL.apply @webContents, arguments -BrowserWindow::getURL = -> @webContents.getURL() -BrowserWindow::reload = -> @webContents.reload.apply @webContents, arguments -BrowserWindow::send = -> @webContents.send.apply @webContents, arguments -BrowserWindow::openDevTools = -> @webContents.openDevTools.apply @webContents, arguments -BrowserWindow::closeDevTools = -> @webContents.closeDevTools() -BrowserWindow::isDevToolsOpened = -> @webContents.isDevToolsOpened() -BrowserWindow::isDevToolsFocused = -> @webContents.isDevToolsFocused() -BrowserWindow::toggleDevTools = -> @webContents.toggleDevTools() -BrowserWindow::inspectElement = -> @webContents.inspectElement.apply @webContents, arguments -BrowserWindow::inspectServiceWorker = -> @webContents.inspectServiceWorker() - -### Deprecated. ### -deprecate.member BrowserWindow, 'undo', 'webContents' -deprecate.member BrowserWindow, 'redo', 'webContents' -deprecate.member BrowserWindow, 'cut', 'webContents' -deprecate.member BrowserWindow, 'copy', 'webContents' -deprecate.member BrowserWindow, 'paste', 'webContents' -deprecate.member BrowserWindow, 'selectAll', 'webContents' -deprecate.member BrowserWindow, 'reloadIgnoringCache', 'webContents' -deprecate.member BrowserWindow, 'isLoading', 'webContents' -deprecate.member BrowserWindow, 'isWaitingForResponse', 'webContents' -deprecate.member BrowserWindow, 'stop', 'webContents' -deprecate.member BrowserWindow, 'isCrashed', 'webContents' -deprecate.member BrowserWindow, 'print', 'webContents' -deprecate.member BrowserWindow, 'printToPDF', 'webContents' -deprecate.rename BrowserWindow, 'restart', 'reload' -deprecate.rename BrowserWindow, 'loadUrl', 'loadURL' -deprecate.rename BrowserWindow, 'getUrl', 'getURL' -BrowserWindow::executeJavaScriptInDevTools = deprecate 'executeJavaScriptInDevTools', 'devToolsWebContents.executeJavaScript', (code) -> - @devToolsWebContents?.executeJavaScript code -BrowserWindow::getPageTitle = deprecate 'getPageTitle', 'webContents.getTitle', -> - @webContents?.getTitle() - -module.exports = BrowserWindow diff --git a/atom/browser/api/lib/browser-window.js b/atom/browser/api/lib/browser-window.js new file mode 100644 index 000000000000..694c7c25e237 --- /dev/null +++ b/atom/browser/api/lib/browser-window.js @@ -0,0 +1,250 @@ +var BrowserWindow, EventEmitter, deprecate, ipcMain, ref; + +ref = require('electron'), ipcMain = ref.ipcMain, deprecate = ref.deprecate; + +EventEmitter = require('events').EventEmitter; + +BrowserWindow = process.atomBinding('window').BrowserWindow; + +BrowserWindow.prototype.__proto__ = EventEmitter.prototype; + +BrowserWindow.prototype._init = function() { + + /* avoid recursive require. */ + var app, menu; + app = require('electron').app; + + /* Simulate the application menu on platforms other than OS X. */ + if (process.platform !== 'darwin') { + menu = app.getApplicationMenu(); + if (menu != null) { + this.setMenu(menu); + } + } + + /* Make new windows requested by links behave like "window.open" */ + this.webContents.on('-new-window', function(event, url, frameName) { + var options; + options = { + show: true, + width: 800, + height: 600 + }; + return ipcMain.emit('ATOM_SHELL_GUEST_WINDOW_MANAGER_WINDOW_OPEN', event, url, frameName, options); + }); + + /* + window.resizeTo(...) + window.moveTo(...) + */ + this.webContents.on('move', (function(_this) { + return function(event, size) { + return _this.setBounds(size); + }; + })(this)); + + /* Hide the auto-hide menu when webContents is focused. */ + this.webContents.on('activate', (function(_this) { + return function() { + if (process.platform !== 'darwin' && _this.isMenuBarAutoHide() && _this.isMenuBarVisible()) { + return _this.setMenuBarVisibility(false); + } + }; + })(this)); + + /* Forward the crashed event. */ + this.webContents.on('crashed', (function(_this) { + return function() { + return _this.emit('crashed'); + }; + })(this)); + + /* Change window title to page title. */ + this.webContents.on('page-title-updated', (function(_this) { + return function(event, title, explicitSet) { + _this.emit('page-title-updated', event, title); + if (!event.defaultPrevented) { + return _this.setTitle(title); + } + }; + })(this)); + + /* + Sometimes the webContents doesn't get focus when window is shown, so we have + to force focusing on webContents in this case. The safest way is to focus it + when we first start to load URL, if we do it earlier it won't have effect, + if we do it later we might move focus in the page. + Though this hack is only needed on OS X when the app is launched from + Finder, we still do it on all platforms in case of other bugs we don't know. + */ + this.webContents.once('load-url', function() { + return this.focus(); + }); + + /* Redirect focus/blur event to app instance too. */ + this.on('blur', (function(_this) { + return function(event) { + return app.emit('browser-window-blur', event, _this); + }; + })(this)); + this.on('focus', (function(_this) { + return function(event) { + return app.emit('browser-window-focus', event, _this); + }; + })(this)); + + /* Notify the creation of the window. */ + app.emit('browser-window-created', {}, this); + + /* Be compatible with old APIs. */ + this.webContents.on('devtools-focused', (function(_this) { + return function() { + return _this.emit('devtools-focused'); + }; + })(this)); + this.webContents.on('devtools-opened', (function(_this) { + return function() { + return _this.emit('devtools-opened'); + }; + })(this)); + this.webContents.on('devtools-closed', (function(_this) { + return function() { + return _this.emit('devtools-closed'); + }; + })(this)); + return Object.defineProperty(this, 'devToolsWebContents', { + enumerable: true, + configurable: false, + get: function() { + return this.webContents.devToolsWebContents; + } + }); +}; + +BrowserWindow.getFocusedWindow = function() { + var i, len, window, windows; + windows = BrowserWindow.getAllWindows(); + for (i = 0, len = windows.length; i < len; i++) { + window = windows[i]; + if (window.isFocused()) { + return window; + } + } + return null; +}; + +BrowserWindow.fromWebContents = function(webContents) { + var i, len, ref1, window, windows; + windows = BrowserWindow.getAllWindows(); + for (i = 0, len = windows.length; i < len; i++) { + window = windows[i]; + if ((ref1 = window.webContents) != null ? ref1.equal(webContents) : void 0) { + return window; + } + } +}; + +BrowserWindow.fromDevToolsWebContents = function(webContents) { + var i, len, ref1, window, windows; + windows = BrowserWindow.getAllWindows(); + for (i = 0, len = windows.length; i < len; i++) { + window = windows[i]; + if ((ref1 = window.devToolsWebContents) != null ? ref1.equal(webContents) : void 0) { + return window; + } + } +}; + + +/* Helpers. */ + +BrowserWindow.prototype.loadURL = function() { + return this.webContents.loadURL.apply(this.webContents, arguments); +}; + +BrowserWindow.prototype.getURL = function() { + return this.webContents.getURL(); +}; + +BrowserWindow.prototype.reload = function() { + return this.webContents.reload.apply(this.webContents, arguments); +}; + +BrowserWindow.prototype.send = function() { + return this.webContents.send.apply(this.webContents, arguments); +}; + +BrowserWindow.prototype.openDevTools = function() { + return this.webContents.openDevTools.apply(this.webContents, arguments); +}; + +BrowserWindow.prototype.closeDevTools = function() { + return this.webContents.closeDevTools(); +}; + +BrowserWindow.prototype.isDevToolsOpened = function() { + return this.webContents.isDevToolsOpened(); +}; + +BrowserWindow.prototype.isDevToolsFocused = function() { + return this.webContents.isDevToolsFocused(); +}; + +BrowserWindow.prototype.toggleDevTools = function() { + return this.webContents.toggleDevTools(); +}; + +BrowserWindow.prototype.inspectElement = function() { + return this.webContents.inspectElement.apply(this.webContents, arguments); +}; + +BrowserWindow.prototype.inspectServiceWorker = function() { + return this.webContents.inspectServiceWorker(); +}; + + +/* Deprecated. */ + +deprecate.member(BrowserWindow, 'undo', 'webContents'); + +deprecate.member(BrowserWindow, 'redo', 'webContents'); + +deprecate.member(BrowserWindow, 'cut', 'webContents'); + +deprecate.member(BrowserWindow, 'copy', 'webContents'); + +deprecate.member(BrowserWindow, 'paste', 'webContents'); + +deprecate.member(BrowserWindow, 'selectAll', 'webContents'); + +deprecate.member(BrowserWindow, 'reloadIgnoringCache', 'webContents'); + +deprecate.member(BrowserWindow, 'isLoading', 'webContents'); + +deprecate.member(BrowserWindow, 'isWaitingForResponse', 'webContents'); + +deprecate.member(BrowserWindow, 'stop', 'webContents'); + +deprecate.member(BrowserWindow, 'isCrashed', 'webContents'); + +deprecate.member(BrowserWindow, 'print', 'webContents'); + +deprecate.member(BrowserWindow, 'printToPDF', 'webContents'); + +deprecate.rename(BrowserWindow, 'restart', 'reload'); + +deprecate.rename(BrowserWindow, 'loadUrl', 'loadURL'); + +deprecate.rename(BrowserWindow, 'getUrl', 'getURL'); + +BrowserWindow.prototype.executeJavaScriptInDevTools = deprecate('executeJavaScriptInDevTools', 'devToolsWebContents.executeJavaScript', function(code) { + var ref1; + return (ref1 = this.devToolsWebContents) != null ? ref1.executeJavaScript(code) : void 0; +}); + +BrowserWindow.prototype.getPageTitle = deprecate('getPageTitle', 'webContents.getTitle', function() { + var ref1; + return (ref1 = this.webContents) != null ? ref1.getTitle() : void 0; +}); + +module.exports = BrowserWindow; diff --git a/atom/browser/api/lib/content-tracing.coffee b/atom/browser/api/lib/content-tracing.coffee deleted file mode 100644 index 08cd36e4aa59..000000000000 --- a/atom/browser/api/lib/content-tracing.coffee +++ /dev/null @@ -1 +0,0 @@ -module.exports = process.atomBinding 'content_tracing' diff --git a/atom/browser/api/lib/content-tracing.js b/atom/browser/api/lib/content-tracing.js new file mode 100644 index 000000000000..b00c5666df59 --- /dev/null +++ b/atom/browser/api/lib/content-tracing.js @@ -0,0 +1 @@ +module.exports = process.atomBinding('content_tracing'); diff --git a/atom/browser/api/lib/dialog.coffee b/atom/browser/api/lib/dialog.coffee deleted file mode 100644 index 98e613bbaab6..000000000000 --- a/atom/browser/api/lib/dialog.coffee +++ /dev/null @@ -1,127 +0,0 @@ -{app, BrowserWindow} = require 'electron' - -binding = process.atomBinding 'dialog' -v8Util = process.atomBinding 'v8_util' - -fileDialogProperties = - openFile: 1 << 0 - openDirectory: 1 << 1 - multiSelections: 1 << 2 - createDirectory: 1 << 3 - -messageBoxTypes = ['none', 'info', 'warning', 'error', 'question'] - -messageBoxOptions = - noLink: 1 << 0 - -parseArgs = (window, options, callback) -> - unless window is null or window?.constructor is BrowserWindow - ### Shift. ### - callback = options - options = window - window = null - if not callback? and typeof options is 'function' - ### Shift. ### - callback = options - options = null - [window, options, callback] - -checkAppInitialized = -> - throw new Error('dialog module can only be used after app is ready') unless app.isReady() - -module.exports = - showOpenDialog: (args...) -> - checkAppInitialized() - [window, options, callback] = parseArgs args... - - options ?= title: 'Open', properties: ['openFile'] - options.properties ?= ['openFile'] - throw new TypeError('Properties need to be array') unless Array.isArray options.properties - - properties = 0 - for prop, value of fileDialogProperties - properties |= value if prop in options.properties - - options.title ?= '' - options.defaultPath ?= '' - options.filters ?= [] - - wrappedCallback = - if typeof callback is 'function' - (success, result) -> callback(if success then result) - else - null - - binding.showOpenDialog String(options.title), - String(options.defaultPath), - options.filters - properties, - window, - wrappedCallback - - showSaveDialog: (args...) -> - checkAppInitialized() - [window, options, callback] = parseArgs args... - - options ?= title: 'Save' - options.title ?= '' - options.defaultPath ?= '' - options.filters ?= [] - - wrappedCallback = - if typeof callback is 'function' - (success, result) -> callback(if success then result) - else - null - - binding.showSaveDialog String(options.title), - String(options.defaultPath), - options.filters - window, - wrappedCallback - - showMessageBox: (args...) -> - checkAppInitialized() - [window, options, callback] = parseArgs args... - - options ?= type: 'none' - options.type ?= 'none' - messageBoxType = messageBoxTypes.indexOf options.type - throw new TypeError('Invalid message box type') unless messageBoxType > -1 - - throw new TypeError('Buttons need to be array') unless Array.isArray options.buttons - - options.title ?= '' - options.message ?= '' - options.detail ?= '' - options.icon ?= null - options.defaultId ?= -1 - - ### Choose a default button to get selected when dialog is cancelled. ### - unless options.cancelId? - options.cancelId = 0 - for text, i in options.buttons - if text.toLowerCase() in ['cancel', 'no'] - options.cancelId = i - break - - flags = if options.noLink then messageBoxOptions.noLink else 0 - - binding.showMessageBox messageBoxType, - options.buttons, - options.defaultId, - options.cancelId, - flags, - options.title, - options.message, - options.detail, - options.icon, - window, - callback - - showErrorBox: (args...) -> - binding.showErrorBox args... - -### Mark standard asynchronous functions. ### -for api in ['showMessageBox', 'showOpenDialog', 'showSaveDialog'] - v8Util.setHiddenValue module.exports[api], 'asynchronous', true diff --git a/atom/browser/api/lib/dialog.js b/atom/browser/api/lib/dialog.js new file mode 100644 index 000000000000..5210e5d20a25 --- /dev/null +++ b/atom/browser/api/lib/dialog.js @@ -0,0 +1,175 @@ +var BrowserWindow, api, app, binding, checkAppInitialized, fileDialogProperties, j, len, messageBoxOptions, messageBoxTypes, parseArgs, ref, ref1, v8Util, + slice = [].slice, + indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; }; + +ref = require('electron'), app = ref.app, BrowserWindow = ref.BrowserWindow; + +binding = process.atomBinding('dialog'); + +v8Util = process.atomBinding('v8_util'); + +fileDialogProperties = { + openFile: 1 << 0, + openDirectory: 1 << 1, + multiSelections: 1 << 2, + createDirectory: 1 << 3 +}; + +messageBoxTypes = ['none', 'info', 'warning', 'error', 'question']; + +messageBoxOptions = { + noLink: 1 << 0 +}; + +parseArgs = function(window, options, callback) { + if (!(window === null || (window != null ? window.constructor : void 0) === BrowserWindow)) { + + /* Shift. */ + callback = options; + options = window; + window = null; + } + if ((callback == null) && typeof options === 'function') { + + /* Shift. */ + callback = options; + options = null; + } + return [window, options, callback]; +}; + +checkAppInitialized = function() { + if (!app.isReady()) { + throw new Error('dialog module can only be used after app is ready'); + } +}; + +module.exports = { + showOpenDialog: function() { + var args, callback, options, prop, properties, ref1, value, window, wrappedCallback; + args = 1 <= arguments.length ? slice.call(arguments, 0) : []; + checkAppInitialized(); + ref1 = parseArgs.apply(null, args), window = ref1[0], options = ref1[1], callback = ref1[2]; + if (options == null) { + options = { + title: 'Open', + properties: ['openFile'] + }; + } + if (options.properties == null) { + options.properties = ['openFile']; + } + if (!Array.isArray(options.properties)) { + throw new TypeError('Properties need to be array'); + } + properties = 0; + for (prop in fileDialogProperties) { + value = fileDialogProperties[prop]; + if (indexOf.call(options.properties, prop) >= 0) { + properties |= value; + } + } + if (options.title == null) { + options.title = ''; + } + if (options.defaultPath == null) { + options.defaultPath = ''; + } + if (options.filters == null) { + options.filters = []; + } + wrappedCallback = typeof callback === 'function' ? function(success, result) { + return callback(success ? result : void 0); + } : null; + return binding.showOpenDialog(String(options.title), String(options.defaultPath), options.filters, properties, window, wrappedCallback); + }, + showSaveDialog: function() { + var args, callback, options, ref1, window, wrappedCallback; + args = 1 <= arguments.length ? slice.call(arguments, 0) : []; + checkAppInitialized(); + ref1 = parseArgs.apply(null, args), window = ref1[0], options = ref1[1], callback = ref1[2]; + if (options == null) { + options = { + title: 'Save' + }; + } + if (options.title == null) { + options.title = ''; + } + if (options.defaultPath == null) { + options.defaultPath = ''; + } + if (options.filters == null) { + options.filters = []; + } + wrappedCallback = typeof callback === 'function' ? function(success, result) { + return callback(success ? result : void 0); + } : null; + return binding.showSaveDialog(String(options.title), String(options.defaultPath), options.filters, window, wrappedCallback); + }, + showMessageBox: function() { + var args, callback, flags, i, j, len, messageBoxType, options, ref1, ref2, ref3, text, window; + args = 1 <= arguments.length ? slice.call(arguments, 0) : []; + checkAppInitialized(); + ref1 = parseArgs.apply(null, args), window = ref1[0], options = ref1[1], callback = ref1[2]; + if (options == null) { + options = { + type: 'none' + }; + } + if (options.type == null) { + options.type = 'none'; + } + messageBoxType = messageBoxTypes.indexOf(options.type); + if (!(messageBoxType > -1)) { + throw new TypeError('Invalid message box type'); + } + if (!Array.isArray(options.buttons)) { + throw new TypeError('Buttons need to be array'); + } + if (options.title == null) { + options.title = ''; + } + if (options.message == null) { + options.message = ''; + } + if (options.detail == null) { + options.detail = ''; + } + if (options.icon == null) { + options.icon = null; + } + if (options.defaultId == null) { + options.defaultId = -1; + } + + /* Choose a default button to get selected when dialog is cancelled. */ + if (options.cancelId == null) { + options.cancelId = 0; + ref2 = options.buttons; + for (i = j = 0, len = ref2.length; j < len; i = ++j) { + text = ref2[i]; + if ((ref3 = text.toLowerCase()) === 'cancel' || ref3 === 'no') { + options.cancelId = i; + break; + } + } + } + flags = options.noLink ? messageBoxOptions.noLink : 0; + return binding.showMessageBox(messageBoxType, options.buttons, options.defaultId, options.cancelId, flags, options.title, options.message, options.detail, options.icon, window, callback); + }, + showErrorBox: function() { + var args; + args = 1 <= arguments.length ? slice.call(arguments, 0) : []; + return binding.showErrorBox.apply(binding, args); + } +}; + + +/* Mark standard asynchronous functions. */ + +ref1 = ['showMessageBox', 'showOpenDialog', 'showSaveDialog']; +for (j = 0, len = ref1.length; j < len; j++) { + api = ref1[j]; + v8Util.setHiddenValue(module.exports[api], 'asynchronous', true); +} diff --git a/atom/browser/api/lib/exports/electron.coffee b/atom/browser/api/lib/exports/electron.coffee deleted file mode 100644 index 48ff349a29a3..000000000000 --- a/atom/browser/api/lib/exports/electron.coffee +++ /dev/null @@ -1,57 +0,0 @@ -common = require '../../../../common/api/lib/exports/electron' - -### Import common modules. ### -common.defineProperties exports - -Object.defineProperties exports, - ### Browser side modules, please sort with alphabet order. ### - app: - enumerable: true - get: -> require '../app' - autoUpdater: - enumerable: true - get: -> require '../auto-updater' - BrowserWindow: - enumerable: true - get: -> require '../browser-window' - contentTracing: - enumerable: true - get: -> require '../content-tracing' - dialog: - enumerable: true - get: -> require '../dialog' - ipcMain: - enumerable: true - get: -> require '../ipc-main' - globalShortcut: - enumerable: true - get: -> require '../global-shortcut' - Menu: - enumerable: true - get: -> require '../menu' - MenuItem: - enumerable: true - get: -> require '../menu-item' - powerMonitor: - enumerable: true - get: -> require '../power-monitor' - powerSaveBlocker: - enumerable: true - get: -> require '../power-save-blocker' - protocol: - enumerable: true - get: -> require '../protocol' - screen: - enumerable: true - get: -> require '../screen' - session: - enumerable: true - get: -> require '../session' - Tray: - enumerable: true - get: -> require '../tray' - ### The internal modules, invisible unless you know their names. ### - NavigationController: - get: -> require '../navigation-controller' - webContents: - get: -> require '../web-contents' diff --git a/atom/browser/api/lib/exports/electron.js b/atom/browser/api/lib/exports/electron.js new file mode 100644 index 000000000000..5ded35a401fb --- /dev/null +++ b/atom/browser/api/lib/exports/electron.js @@ -0,0 +1,115 @@ +var common; + +common = require('../../../../common/api/lib/exports/electron'); + + +/* Import common modules. */ + +common.defineProperties(exports); + +Object.defineProperties(exports, { + + /* Browser side modules, please sort with alphabet order. */ + app: { + enumerable: true, + get: function() { + return require('../app'); + } + }, + autoUpdater: { + enumerable: true, + get: function() { + return require('../auto-updater'); + } + }, + BrowserWindow: { + enumerable: true, + get: function() { + return require('../browser-window'); + } + }, + contentTracing: { + enumerable: true, + get: function() { + return require('../content-tracing'); + } + }, + dialog: { + enumerable: true, + get: function() { + return require('../dialog'); + } + }, + ipcMain: { + enumerable: true, + get: function() { + return require('../ipc-main'); + } + }, + globalShortcut: { + enumerable: true, + get: function() { + return require('../global-shortcut'); + } + }, + Menu: { + enumerable: true, + get: function() { + return require('../menu'); + } + }, + MenuItem: { + enumerable: true, + get: function() { + return require('../menu-item'); + } + }, + powerMonitor: { + enumerable: true, + get: function() { + return require('../power-monitor'); + } + }, + powerSaveBlocker: { + enumerable: true, + get: function() { + return require('../power-save-blocker'); + } + }, + protocol: { + enumerable: true, + get: function() { + return require('../protocol'); + } + }, + screen: { + enumerable: true, + get: function() { + return require('../screen'); + } + }, + session: { + enumerable: true, + get: function() { + return require('../session'); + } + }, + Tray: { + enumerable: true, + get: function() { + return require('../tray'); + } + }, + + /* The internal modules, invisible unless you know their names. */ + NavigationController: { + get: function() { + return require('../navigation-controller'); + } + }, + webContents: { + get: function() { + return require('../web-contents'); + } + } +}); diff --git a/atom/browser/api/lib/global-shortcut.coffee b/atom/browser/api/lib/global-shortcut.coffee deleted file mode 100644 index 56c3e128767e..000000000000 --- a/atom/browser/api/lib/global-shortcut.coffee +++ /dev/null @@ -1,3 +0,0 @@ -{globalShortcut} = process.atomBinding 'global_shortcut' - -module.exports = globalShortcut diff --git a/atom/browser/api/lib/global-shortcut.js b/atom/browser/api/lib/global-shortcut.js new file mode 100644 index 000000000000..daca6c232796 --- /dev/null +++ b/atom/browser/api/lib/global-shortcut.js @@ -0,0 +1,5 @@ +var globalShortcut; + +globalShortcut = process.atomBinding('global_shortcut').globalShortcut; + +module.exports = globalShortcut; diff --git a/atom/browser/api/lib/ipc-main.coffee b/atom/browser/api/lib/ipc-main.coffee deleted file mode 100644 index 8021544479d2..000000000000 --- a/atom/browser/api/lib/ipc-main.coffee +++ /dev/null @@ -1,3 +0,0 @@ -{EventEmitter} = require 'events' - -module.exports = new EventEmitter diff --git a/atom/browser/api/lib/ipc-main.js b/atom/browser/api/lib/ipc-main.js new file mode 100644 index 000000000000..bd4300d2c244 --- /dev/null +++ b/atom/browser/api/lib/ipc-main.js @@ -0,0 +1,5 @@ +var EventEmitter; + +EventEmitter = require('events').EventEmitter; + +module.exports = new EventEmitter; diff --git a/atom/browser/api/lib/ipc.coffee b/atom/browser/api/lib/ipc.coffee deleted file mode 100644 index 348c7d0cd459..000000000000 --- a/atom/browser/api/lib/ipc.coffee +++ /dev/null @@ -1,6 +0,0 @@ -{deprecate, ipcMain} = require 'electron' - -### This module is deprecated, we mirror everything from ipcMain. ### -deprecate.warn 'ipc module', 'require("electron").ipcMain' - -module.exports = ipcMain diff --git a/atom/browser/api/lib/ipc.js b/atom/browser/api/lib/ipc.js new file mode 100644 index 000000000000..162e56bea2c1 --- /dev/null +++ b/atom/browser/api/lib/ipc.js @@ -0,0 +1,10 @@ +var deprecate, ipcMain, ref; + +ref = require('electron'), deprecate = ref.deprecate, ipcMain = ref.ipcMain; + + +/* This module is deprecated, we mirror everything from ipcMain. */ + +deprecate.warn('ipc module', 'require("electron").ipcMain'); + +module.exports = ipcMain; diff --git a/atom/browser/api/lib/menu-item.coffee b/atom/browser/api/lib/menu-item.coffee deleted file mode 100644 index ab225d30095c..000000000000 --- a/atom/browser/api/lib/menu-item.coffee +++ /dev/null @@ -1,73 +0,0 @@ -v8Util = process.atomBinding 'v8_util' - -nextCommandId = 0 - -### Maps role to methods of webContents ### -rolesMap = - undo: 'undo' - redo: 'redo' - cut: 'cut' - copy: 'copy' - paste: 'paste' - selectall: 'selectAll' - minimize: 'minimize' - close: 'close' - -### Maps methods that should be called directly on the BrowserWindow instance ### -methodInBrowserWindow = - minimize: true - close: true - -class MenuItem - @types = ['normal', 'separator', 'submenu', 'checkbox', 'radio'] - - constructor: (options) -> - {Menu} = require 'electron' - - {click, @selector, @type, @role, @label, @sublabel, @accelerator, @icon, @enabled, @visible, @checked, @submenu} = options - - if @submenu? and @submenu.constructor isnt Menu - @submenu = Menu.buildFromTemplate @submenu - @type = 'submenu' if not @type? and @submenu? - throw new Error('Invalid submenu') if @type is 'submenu' and @submenu?.constructor isnt Menu - - @overrideReadOnlyProperty 'type', 'normal' - @overrideReadOnlyProperty 'role' - @overrideReadOnlyProperty 'accelerator' - @overrideReadOnlyProperty 'icon' - @overrideReadOnlyProperty 'submenu' - @overrideProperty 'label', '' - @overrideProperty 'sublabel', '' - @overrideProperty 'enabled', true - @overrideProperty 'visible', true - @overrideProperty 'checked', false - - throw new Error("Unknown menu type #{@type}") if MenuItem.types.indexOf(@type) is -1 - - @commandId = ++nextCommandId - @click = (focusedWindow) => - ### Manually flip the checked flags when clicked. ### - @checked = !@checked if @type in ['checkbox', 'radio'] - - if @role and rolesMap[@role] and process.platform isnt 'darwin' and focusedWindow? - methodName = rolesMap[@role] - if methodInBrowserWindow[methodName] - focusedWindow[methodName]() - else - focusedWindow.webContents?[methodName]() - else if typeof click is 'function' - click this, focusedWindow - else if typeof @selector is 'string' - Menu.sendActionToFirstResponder @selector - - overrideProperty: (name, defaultValue=null) -> - this[name] ?= defaultValue - - overrideReadOnlyProperty: (name, defaultValue=null) -> - this[name] ?= defaultValue - Object.defineProperty this, name, - enumerable: true - writable: false - value: this[name] - -module.exports = MenuItem diff --git a/atom/browser/api/lib/menu-item.js b/atom/browser/api/lib/menu-item.js new file mode 100644 index 000000000000..22d6c251f5e9 --- /dev/null +++ b/atom/browser/api/lib/menu-item.js @@ -0,0 +1,108 @@ +var MenuItem, methodInBrowserWindow, nextCommandId, rolesMap, v8Util; + +v8Util = process.atomBinding('v8_util'); + +nextCommandId = 0; + + +/* Maps role to methods of webContents */ + +rolesMap = { + undo: 'undo', + redo: 'redo', + cut: 'cut', + copy: 'copy', + paste: 'paste', + selectall: 'selectAll', + minimize: 'minimize', + close: 'close' +}; + + +/* Maps methods that should be called directly on the BrowserWindow instance */ + +methodInBrowserWindow = { + minimize: true, + close: true +}; + +MenuItem = (function() { + MenuItem.types = ['normal', 'separator', 'submenu', 'checkbox', 'radio']; + + function MenuItem(options) { + var Menu, click, ref; + Menu = require('electron').Menu; + click = options.click, this.selector = options.selector, this.type = options.type, this.role = options.role, this.label = options.label, this.sublabel = options.sublabel, this.accelerator = options.accelerator, this.icon = options.icon, this.enabled = options.enabled, this.visible = options.visible, this.checked = options.checked, this.submenu = options.submenu; + if ((this.submenu != null) && this.submenu.constructor !== Menu) { + this.submenu = Menu.buildFromTemplate(this.submenu); + } + if ((this.type == null) && (this.submenu != null)) { + this.type = 'submenu'; + } + if (this.type === 'submenu' && ((ref = this.submenu) != null ? ref.constructor : void 0) !== Menu) { + throw new Error('Invalid submenu'); + } + this.overrideReadOnlyProperty('type', 'normal'); + this.overrideReadOnlyProperty('role'); + this.overrideReadOnlyProperty('accelerator'); + this.overrideReadOnlyProperty('icon'); + this.overrideReadOnlyProperty('submenu'); + this.overrideProperty('label', ''); + this.overrideProperty('sublabel', ''); + this.overrideProperty('enabled', true); + this.overrideProperty('visible', true); + this.overrideProperty('checked', false); + if (MenuItem.types.indexOf(this.type) === -1) { + throw new Error("Unknown menu type " + this.type); + } + this.commandId = ++nextCommandId; + this.click = (function(_this) { + return function(focusedWindow) { + + /* Manually flip the checked flags when clicked. */ + var methodName, ref1, ref2; + if ((ref1 = _this.type) === 'checkbox' || ref1 === 'radio') { + _this.checked = !_this.checked; + } + if (_this.role && rolesMap[_this.role] && process.platform !== 'darwin' && (focusedWindow != null)) { + methodName = rolesMap[_this.role]; + if (methodInBrowserWindow[methodName]) { + return focusedWindow[methodName](); + } else { + return (ref2 = focusedWindow.webContents) != null ? ref2[methodName]() : void 0; + } + } else if (typeof click === 'function') { + return click(_this, focusedWindow); + } else if (typeof _this.selector === 'string') { + return Menu.sendActionToFirstResponder(_this.selector); + } + }; + })(this); + } + + MenuItem.prototype.overrideProperty = function(name, defaultValue) { + if (defaultValue == null) { + defaultValue = null; + } + return this[name] != null ? this[name] : this[name] = defaultValue; + }; + + MenuItem.prototype.overrideReadOnlyProperty = function(name, defaultValue) { + if (defaultValue == null) { + defaultValue = null; + } + if (this[name] == null) { + this[name] = defaultValue; + } + return Object.defineProperty(this, name, { + enumerable: true, + writable: false, + value: this[name] + }); + }; + + return MenuItem; + +})(); + +module.exports = MenuItem; diff --git a/atom/browser/api/lib/menu.coffee b/atom/browser/api/lib/menu.coffee deleted file mode 100644 index d987f304262c..000000000000 --- a/atom/browser/api/lib/menu.coffee +++ /dev/null @@ -1,179 +0,0 @@ -{BrowserWindow, MenuItem} = require 'electron' -{EventEmitter} = require 'events' - -v8Util = process.atomBinding 'v8_util' -bindings = process.atomBinding 'menu' - -### Automatically generated radio menu item's group id. ### -nextGroupId = 0 - -### Search between seperators to find a radio menu item and return its group id, ### -### otherwise generate a group id. ### -generateGroupId = (items, pos) -> - if pos > 0 - for i in [pos - 1..0] - item = items[i] - return item.groupId if item.type is 'radio' - break if item.type is 'separator' - else if pos < items.length - for i in [pos..items.length - 1] - item = items[i] - return item.groupId if item.type is 'radio' - break if item.type is 'separator' - ++nextGroupId - -### Returns the index of item according to |id|. ### -indexOfItemById = (items, id) -> - return i for item, i in items when item.id is id - -1 - -### Returns the index of where to insert the item according to |position|. ### -indexToInsertByPosition = (items, position) -> - return items.length unless position - - [query, id] = position.split '=' - insertIndex = indexOfItemById items, id - if insertIndex is -1 and query isnt 'endof' - console.warn "Item with id '#{id}' is not found" - return items.length - - switch query - when 'after' - insertIndex++ - when 'endof' - ### If the |id| doesn't exist, then create a new group with the |id|. ### - if insertIndex is -1 - items.push id: id, type: 'separator' - insertIndex = items.length - 1 - - ### Find the end of the group. ### - insertIndex++ - while insertIndex < items.length and items[insertIndex].type isnt 'separator' - insertIndex++ - - insertIndex - -Menu = bindings.Menu -Menu::__proto__ = EventEmitter.prototype - -Menu::_init = -> - @commandsMap = {} - @groupsMap = {} - @items = [] - @delegate = - isCommandIdChecked: (commandId) => @commandsMap[commandId]?.checked - isCommandIdEnabled: (commandId) => @commandsMap[commandId]?.enabled - isCommandIdVisible: (commandId) => @commandsMap[commandId]?.visible - getAcceleratorForCommandId: (commandId) => @commandsMap[commandId]?.accelerator - getIconForCommandId: (commandId) => @commandsMap[commandId]?.icon - executeCommand: (commandId) => - @commandsMap[commandId]?.click BrowserWindow.getFocusedWindow() - menuWillShow: => - ### Make sure radio groups have at least one menu item seleted. ### - for id, group of @groupsMap - checked = false - for radioItem in group when radioItem.checked - checked = true - break - v8Util.setHiddenValue group[0], 'checked', true unless checked - -Menu::popup = (window, x, y) -> - unless window?.constructor is BrowserWindow - ### Shift. ### - y = x - x = window - window = BrowserWindow.getFocusedWindow() - if x? and y? - @_popupAt(window, x, y) - else - @_popup window - -Menu::append = (item) -> - @insert @getItemCount(), item - -Menu::insert = (pos, item) -> - throw new TypeError('Invalid item') unless item?.constructor is MenuItem - - switch item.type - when 'normal' then @insertItem pos, item.commandId, item.label - when 'checkbox' then @insertCheckItem pos, item.commandId, item.label - when 'separator' then @insertSeparator pos - when 'submenu' then @insertSubMenu pos, item.commandId, item.label, item.submenu - when 'radio' - ### Grouping radio menu items. ### - item.overrideReadOnlyProperty 'groupId', generateGroupId(@items, pos) - @groupsMap[item.groupId] ?= [] - @groupsMap[item.groupId].push item - - ### Setting a radio menu item should flip other items in the group. ### - v8Util.setHiddenValue item, 'checked', item.checked - Object.defineProperty item, 'checked', - enumerable: true - get: -> v8Util.getHiddenValue item, 'checked' - set: (val) => - for otherItem in @groupsMap[item.groupId] when otherItem isnt item - v8Util.setHiddenValue otherItem, 'checked', false - v8Util.setHiddenValue item, 'checked', true - - @insertRadioItem pos, item.commandId, item.label, item.groupId - - @setSublabel pos, item.sublabel if item.sublabel? - @setIcon pos, item.icon if item.icon? - @setRole pos, item.role if item.role? - - ### Make menu accessable to items. ### - item.overrideReadOnlyProperty 'menu', this - - ### Remember the items. ### - @items.splice pos, 0, item - @commandsMap[item.commandId] = item - -### Force menuWillShow to be called ### -Menu::_callMenuWillShow = -> - @delegate?.menuWillShow() - item.submenu._callMenuWillShow() for item in @items when item.submenu? - -applicationMenu = null -Menu.setApplicationMenu = (menu) -> - throw new TypeError('Invalid menu') unless menu is null or menu.constructor is Menu - ### Keep a reference. ### - applicationMenu = menu - - if process.platform is 'darwin' - return if menu is null - menu._callMenuWillShow() - bindings.setApplicationMenu menu - else - windows = BrowserWindow.getAllWindows() - w.setMenu menu for w in windows - -Menu.getApplicationMenu = -> applicationMenu - -Menu.sendActionToFirstResponder = bindings.sendActionToFirstResponder - -Menu.buildFromTemplate = (template) -> - throw new TypeError('Invalid template for Menu') unless Array.isArray template - - positionedTemplate = [] - insertIndex = 0 - - for item in template - if item.position - insertIndex = indexToInsertByPosition positionedTemplate, item.position - else - ### If no |position| is specified, insert after last item. ### - insertIndex++ - positionedTemplate.splice insertIndex, 0, item - - menu = new Menu - - for item in positionedTemplate - throw new TypeError('Invalid template for MenuItem') unless typeof item is 'object' - - menuItem = new MenuItem(item) - menuItem[key] ?= value for key, value of item - menu.append menuItem - - menu - -module.exports = Menu diff --git a/atom/browser/api/lib/menu.js b/atom/browser/api/lib/menu.js new file mode 100644 index 000000000000..6ca5c9adde43 --- /dev/null +++ b/atom/browser/api/lib/menu.js @@ -0,0 +1,350 @@ +var BrowserWindow, EventEmitter, Menu, MenuItem, applicationMenu, bindings, generateGroupId, indexOfItemById, indexToInsertByPosition, nextGroupId, ref, v8Util; + +ref = require('electron'), BrowserWindow = ref.BrowserWindow, MenuItem = ref.MenuItem; + +EventEmitter = require('events').EventEmitter; + +v8Util = process.atomBinding('v8_util'); + +bindings = process.atomBinding('menu'); + + +/* Automatically generated radio menu item's group id. */ + +nextGroupId = 0; + + +/* Search between seperators to find a radio menu item and return its group id, */ + + +/* otherwise generate a group id. */ + +generateGroupId = function(items, pos) { + var i, item, j, k, ref1, ref2, ref3; + if (pos > 0) { + for (i = j = ref1 = pos - 1; ref1 <= 0 ? j <= 0 : j >= 0; i = ref1 <= 0 ? ++j : --j) { + item = items[i]; + if (item.type === 'radio') { + return item.groupId; + } + if (item.type === 'separator') { + break; + } + } + } else if (pos < items.length) { + for (i = k = ref2 = pos, ref3 = items.length - 1; ref2 <= ref3 ? k <= ref3 : k >= ref3; i = ref2 <= ref3 ? ++k : --k) { + item = items[i]; + if (item.type === 'radio') { + return item.groupId; + } + if (item.type === 'separator') { + break; + } + } + } + return ++nextGroupId; +}; + + +/* Returns the index of item according to |id|. */ + +indexOfItemById = function(items, id) { + var i, item, j, len; + for (i = j = 0, len = items.length; j < len; i = ++j) { + item = items[i]; + if (item.id === id) { + return i; + } + } + return -1; +}; + + +/* Returns the index of where to insert the item according to |position|. */ + +indexToInsertByPosition = function(items, position) { + var id, insertIndex, query, ref1; + if (!position) { + return items.length; + } + ref1 = position.split('='), query = ref1[0], id = ref1[1]; + insertIndex = indexOfItemById(items, id); + if (insertIndex === -1 && query !== 'endof') { + console.warn("Item with id '" + id + "' is not found"); + return items.length; + } + switch (query) { + case 'after': + insertIndex++; + break; + case 'endof': + + /* If the |id| doesn't exist, then create a new group with the |id|. */ + if (insertIndex === -1) { + items.push({ + id: id, + type: 'separator' + }); + insertIndex = items.length - 1; + } + + /* Find the end of the group. */ + insertIndex++; + while (insertIndex < items.length && items[insertIndex].type !== 'separator') { + insertIndex++; + } + } + return insertIndex; +}; + +Menu = bindings.Menu; + +Menu.prototype.__proto__ = EventEmitter.prototype; + +Menu.prototype._init = function() { + this.commandsMap = {}; + this.groupsMap = {}; + this.items = []; + return this.delegate = { + isCommandIdChecked: (function(_this) { + return function(commandId) { + var ref1; + return (ref1 = _this.commandsMap[commandId]) != null ? ref1.checked : void 0; + }; + })(this), + isCommandIdEnabled: (function(_this) { + return function(commandId) { + var ref1; + return (ref1 = _this.commandsMap[commandId]) != null ? ref1.enabled : void 0; + }; + })(this), + isCommandIdVisible: (function(_this) { + return function(commandId) { + var ref1; + return (ref1 = _this.commandsMap[commandId]) != null ? ref1.visible : void 0; + }; + })(this), + getAcceleratorForCommandId: (function(_this) { + return function(commandId) { + var ref1; + return (ref1 = _this.commandsMap[commandId]) != null ? ref1.accelerator : void 0; + }; + })(this), + getIconForCommandId: (function(_this) { + return function(commandId) { + var ref1; + return (ref1 = _this.commandsMap[commandId]) != null ? ref1.icon : void 0; + }; + })(this), + executeCommand: (function(_this) { + return function(commandId) { + var ref1; + return (ref1 = _this.commandsMap[commandId]) != null ? ref1.click(BrowserWindow.getFocusedWindow()) : void 0; + }; + })(this), + menuWillShow: (function(_this) { + return function() { + + /* Make sure radio groups have at least one menu item seleted. */ + var checked, group, id, j, len, radioItem, ref1, results; + ref1 = _this.groupsMap; + results = []; + for (id in ref1) { + group = ref1[id]; + checked = false; + for (j = 0, len = group.length; j < len; j++) { + radioItem = group[j]; + if (!radioItem.checked) { + continue; + } + checked = true; + break; + } + if (!checked) { + results.push(v8Util.setHiddenValue(group[0], 'checked', true)); + } else { + results.push(void 0); + } + } + return results; + }; + })(this) + }; +}; + +Menu.prototype.popup = function(window, x, y) { + if ((window != null ? window.constructor : void 0) !== BrowserWindow) { + + /* Shift. */ + y = x; + x = window; + window = BrowserWindow.getFocusedWindow(); + } + if ((x != null) && (y != null)) { + return this._popupAt(window, x, y); + } else { + return this._popup(window); + } +}; + +Menu.prototype.append = function(item) { + return this.insert(this.getItemCount(), item); +}; + +Menu.prototype.insert = function(pos, item) { + var base, name; + if ((item != null ? item.constructor : void 0) !== MenuItem) { + throw new TypeError('Invalid item'); + } + switch (item.type) { + case 'normal': + this.insertItem(pos, item.commandId, item.label); + break; + case 'checkbox': + this.insertCheckItem(pos, item.commandId, item.label); + break; + case 'separator': + this.insertSeparator(pos); + break; + case 'submenu': + this.insertSubMenu(pos, item.commandId, item.label, item.submenu); + break; + case 'radio': + + /* Grouping radio menu items. */ + item.overrideReadOnlyProperty('groupId', generateGroupId(this.items, pos)); + if ((base = this.groupsMap)[name = item.groupId] == null) { + base[name] = []; + } + this.groupsMap[item.groupId].push(item); + + /* Setting a radio menu item should flip other items in the group. */ + v8Util.setHiddenValue(item, 'checked', item.checked); + Object.defineProperty(item, 'checked', { + enumerable: true, + get: function() { + return v8Util.getHiddenValue(item, 'checked'); + }, + set: (function(_this) { + return function(val) { + var j, len, otherItem, ref1; + ref1 = _this.groupsMap[item.groupId]; + for (j = 0, len = ref1.length; j < len; j++) { + otherItem = ref1[j]; + if (otherItem !== item) { + v8Util.setHiddenValue(otherItem, 'checked', false); + } + } + return v8Util.setHiddenValue(item, 'checked', true); + }; + })(this) + }); + this.insertRadioItem(pos, item.commandId, item.label, item.groupId); + } + if (item.sublabel != null) { + this.setSublabel(pos, item.sublabel); + } + if (item.icon != null) { + this.setIcon(pos, item.icon); + } + if (item.role != null) { + this.setRole(pos, item.role); + } + + /* Make menu accessable to items. */ + item.overrideReadOnlyProperty('menu', this); + + /* Remember the items. */ + this.items.splice(pos, 0, item); + return this.commandsMap[item.commandId] = item; +}; + + +/* Force menuWillShow to be called */ + +Menu.prototype._callMenuWillShow = function() { + var item, j, len, ref1, ref2, results; + if ((ref1 = this.delegate) != null) { + ref1.menuWillShow(); + } + ref2 = this.items; + results = []; + for (j = 0, len = ref2.length; j < len; j++) { + item = ref2[j]; + if (item.submenu != null) { + results.push(item.submenu._callMenuWillShow()); + } + } + return results; +}; + +applicationMenu = null; + +Menu.setApplicationMenu = function(menu) { + var j, len, results, w, windows; + if (!(menu === null || menu.constructor === Menu)) { + throw new TypeError('Invalid menu'); + } + + /* Keep a reference. */ + applicationMenu = menu; + if (process.platform === 'darwin') { + if (menu === null) { + return; + } + menu._callMenuWillShow(); + return bindings.setApplicationMenu(menu); + } else { + windows = BrowserWindow.getAllWindows(); + results = []; + for (j = 0, len = windows.length; j < len; j++) { + w = windows[j]; + results.push(w.setMenu(menu)); + } + return results; + } +}; + +Menu.getApplicationMenu = function() { + return applicationMenu; +}; + +Menu.sendActionToFirstResponder = bindings.sendActionToFirstResponder; + +Menu.buildFromTemplate = function(template) { + var insertIndex, item, j, k, key, len, len1, menu, menuItem, positionedTemplate, value; + if (!Array.isArray(template)) { + throw new TypeError('Invalid template for Menu'); + } + positionedTemplate = []; + insertIndex = 0; + for (j = 0, len = template.length; j < len; j++) { + item = template[j]; + if (item.position) { + insertIndex = indexToInsertByPosition(positionedTemplate, item.position); + } else { + + /* If no |position| is specified, insert after last item. */ + insertIndex++; + } + positionedTemplate.splice(insertIndex, 0, item); + } + menu = new Menu; + for (k = 0, len1 = positionedTemplate.length; k < len1; k++) { + item = positionedTemplate[k]; + if (typeof item !== 'object') { + throw new TypeError('Invalid template for MenuItem'); + } + menuItem = new MenuItem(item); + for (key in item) { + value = item[key]; + if (menuItem[key] == null) { + menuItem[key] = value; + } + } + menu.append(menuItem); + } + return menu; +}; + +module.exports = Menu; diff --git a/atom/browser/api/lib/navigation-controller.coffee b/atom/browser/api/lib/navigation-controller.coffee deleted file mode 100644 index 3c7ef2492a8b..000000000000 --- a/atom/browser/api/lib/navigation-controller.coffee +++ /dev/null @@ -1,127 +0,0 @@ -{ipcMain} = require 'electron' - -### The history operation in renderer is redirected to browser. ### -ipcMain.on 'ATOM_SHELL_NAVIGATION_CONTROLLER', (event, method, args...) -> - event.sender[method] args... - -ipcMain.on 'ATOM_SHELL_SYNC_NAVIGATION_CONTROLLER', (event, method, args...) -> - event.returnValue = event.sender[method] args... - -### - JavaScript implementation of Chromium's NavigationController. - Instead of relying on Chromium for history control, we compeletely do history - control on user land, and only rely on WebContents.loadURL for navigation. - This helps us avoid Chromium's various optimizations so we can ensure renderer - process is restarted everytime. -### -class NavigationController - constructor: (@webContents) -> - @clearHistory() - - ### webContents may have already navigated to a page. ### - if @webContents._getURL() - @currentIndex++ - @history.push @webContents._getURL() - - @webContents.on 'navigation-entry-commited', (event, url, inPage, replaceEntry) => - if @inPageIndex > -1 and not inPage - ### Navigated to a new page, clear in-page mark. ### - @inPageIndex = -1 - else if @inPageIndex is -1 and inPage - ### Started in-page navigations. ### - @inPageIndex = @currentIndex - - if @pendingIndex >= 0 - ### Go to index. ### - @currentIndex = @pendingIndex - @pendingIndex = -1 - @history[@currentIndex] = url - else if replaceEntry - ### Non-user initialized navigation. ### - @history[@currentIndex] = url - else - ### Normal navigation. Clear history. ### - @history = @history.slice 0, @currentIndex + 1 - currentEntry = @history[@currentIndex] - if currentEntry?.url isnt url - @currentIndex++ - @history.push url - - loadURL: (url, options={}) -> - @pendingIndex = -1 - @webContents._loadURL url, options - @webContents.emit 'load-url', url, options - - getURL: -> - if @currentIndex is -1 - '' - else - @history[@currentIndex] - - stop: -> - @pendingIndex = -1 - @webContents._stop() - - reload: -> - @pendingIndex = @currentIndex - @webContents._loadURL @getURL(), {} - - reloadIgnoringCache: -> - @pendingIndex = @currentIndex - @webContents._loadURL @getURL(), {extraHeaders: "pragma: no-cache\n"} - - canGoBack: -> - @getActiveIndex() > 0 - - canGoForward: -> - @getActiveIndex() < @history.length - 1 - - canGoToIndex: (index) -> - index >=0 and index < @history.length - - canGoToOffset: (offset) -> - @canGoToIndex @currentIndex + offset - - clearHistory: -> - @history = [] - @currentIndex = -1 - @pendingIndex = -1 - @inPageIndex = -1 - - goBack: -> - return unless @canGoBack() - @pendingIndex = @getActiveIndex() - 1 - if @inPageIndex > -1 and @pendingIndex >= @inPageIndex - @webContents._goBack() - else - @webContents._loadURL @history[@pendingIndex], {} - - goForward: -> - return unless @canGoForward() - @pendingIndex = @getActiveIndex() + 1 - if @inPageIndex > -1 and @pendingIndex >= @inPageIndex - @webContents._goForward() - else - @webContents._loadURL @history[@pendingIndex], {} - - goToIndex: (index) -> - return unless @canGoToIndex index - @pendingIndex = index - @webContents._loadURL @history[@pendingIndex], {} - - goToOffset: (offset) -> - return unless @canGoToOffset offset - pendingIndex = @currentIndex + offset - if @inPageIndex > -1 and pendingIndex >= @inPageIndex - @pendingIndex = pendingIndex - @webContents._goToOffset offset - else - @goToIndex pendingIndex - - getActiveIndex: -> - if @pendingIndex is -1 then @currentIndex else @pendingIndex - - length: -> - @history.length - -module.exports = NavigationController diff --git a/atom/browser/api/lib/navigation-controller.js b/atom/browser/api/lib/navigation-controller.js new file mode 100644 index 000000000000..8e7753de5e3b --- /dev/null +++ b/atom/browser/api/lib/navigation-controller.js @@ -0,0 +1,195 @@ +var NavigationController, ipcMain, + slice = [].slice; + +ipcMain = require('electron').ipcMain; + + +/* The history operation in renderer is redirected to browser. */ + +ipcMain.on('ATOM_SHELL_NAVIGATION_CONTROLLER', function() { + var args, event, method, ref; + event = arguments[0], method = arguments[1], args = 3 <= arguments.length ? slice.call(arguments, 2) : []; + return (ref = event.sender)[method].apply(ref, args); +}); + +ipcMain.on('ATOM_SHELL_SYNC_NAVIGATION_CONTROLLER', function() { + var args, event, method, ref; + event = arguments[0], method = arguments[1], args = 3 <= arguments.length ? slice.call(arguments, 2) : []; + return event.returnValue = (ref = event.sender)[method].apply(ref, args); +}); + + +/* + JavaScript implementation of Chromium's NavigationController. + Instead of relying on Chromium for history control, we compeletely do history + control on user land, and only rely on WebContents.loadURL for navigation. + This helps us avoid Chromium's various optimizations so we can ensure renderer + process is restarted everytime. + */ + +NavigationController = (function() { + function NavigationController(webContents) { + this.webContents = webContents; + this.clearHistory(); + + /* webContents may have already navigated to a page. */ + if (this.webContents._getURL()) { + this.currentIndex++; + this.history.push(this.webContents._getURL()); + } + this.webContents.on('navigation-entry-commited', (function(_this) { + return function(event, url, inPage, replaceEntry) { + var currentEntry; + if (_this.inPageIndex > -1 && !inPage) { + + /* Navigated to a new page, clear in-page mark. */ + _this.inPageIndex = -1; + } else if (_this.inPageIndex === -1 && inPage) { + + /* Started in-page navigations. */ + _this.inPageIndex = _this.currentIndex; + } + if (_this.pendingIndex >= 0) { + + /* Go to index. */ + _this.currentIndex = _this.pendingIndex; + _this.pendingIndex = -1; + return _this.history[_this.currentIndex] = url; + } else if (replaceEntry) { + + /* Non-user initialized navigation. */ + return _this.history[_this.currentIndex] = url; + } else { + + /* Normal navigation. Clear history. */ + _this.history = _this.history.slice(0, _this.currentIndex + 1); + currentEntry = _this.history[_this.currentIndex]; + if ((currentEntry != null ? currentEntry.url : void 0) !== url) { + _this.currentIndex++; + return _this.history.push(url); + } + } + }; + })(this)); + } + + NavigationController.prototype.loadURL = function(url, options) { + if (options == null) { + options = {}; + } + this.pendingIndex = -1; + this.webContents._loadURL(url, options); + return this.webContents.emit('load-url', url, options); + }; + + NavigationController.prototype.getURL = function() { + if (this.currentIndex === -1) { + return ''; + } else { + return this.history[this.currentIndex]; + } + }; + + NavigationController.prototype.stop = function() { + this.pendingIndex = -1; + return this.webContents._stop(); + }; + + NavigationController.prototype.reload = function() { + this.pendingIndex = this.currentIndex; + return this.webContents._loadURL(this.getURL(), {}); + }; + + NavigationController.prototype.reloadIgnoringCache = function() { + this.pendingIndex = this.currentIndex; + return this.webContents._loadURL(this.getURL(), { + extraHeaders: "pragma: no-cache\n" + }); + }; + + NavigationController.prototype.canGoBack = function() { + return this.getActiveIndex() > 0; + }; + + NavigationController.prototype.canGoForward = function() { + return this.getActiveIndex() < this.history.length - 1; + }; + + NavigationController.prototype.canGoToIndex = function(index) { + return index >= 0 && index < this.history.length; + }; + + NavigationController.prototype.canGoToOffset = function(offset) { + return this.canGoToIndex(this.currentIndex + offset); + }; + + NavigationController.prototype.clearHistory = function() { + this.history = []; + this.currentIndex = -1; + this.pendingIndex = -1; + return this.inPageIndex = -1; + }; + + NavigationController.prototype.goBack = function() { + if (!this.canGoBack()) { + return; + } + this.pendingIndex = this.getActiveIndex() - 1; + if (this.inPageIndex > -1 && this.pendingIndex >= this.inPageIndex) { + return this.webContents._goBack(); + } else { + return this.webContents._loadURL(this.history[this.pendingIndex], {}); + } + }; + + NavigationController.prototype.goForward = function() { + if (!this.canGoForward()) { + return; + } + this.pendingIndex = this.getActiveIndex() + 1; + if (this.inPageIndex > -1 && this.pendingIndex >= this.inPageIndex) { + return this.webContents._goForward(); + } else { + return this.webContents._loadURL(this.history[this.pendingIndex], {}); + } + }; + + NavigationController.prototype.goToIndex = function(index) { + if (!this.canGoToIndex(index)) { + return; + } + this.pendingIndex = index; + return this.webContents._loadURL(this.history[this.pendingIndex], {}); + }; + + NavigationController.prototype.goToOffset = function(offset) { + var pendingIndex; + if (!this.canGoToOffset(offset)) { + return; + } + pendingIndex = this.currentIndex + offset; + if (this.inPageIndex > -1 && pendingIndex >= this.inPageIndex) { + this.pendingIndex = pendingIndex; + return this.webContents._goToOffset(offset); + } else { + return this.goToIndex(pendingIndex); + } + }; + + NavigationController.prototype.getActiveIndex = function() { + if (this.pendingIndex === -1) { + return this.currentIndex; + } else { + return this.pendingIndex; + } + }; + + NavigationController.prototype.length = function() { + return this.history.length; + }; + + return NavigationController; + +})(); + +module.exports = NavigationController; diff --git a/atom/browser/api/lib/power-monitor.coffee b/atom/browser/api/lib/power-monitor.coffee deleted file mode 100644 index 54bf9391827c..000000000000 --- a/atom/browser/api/lib/power-monitor.coffee +++ /dev/null @@ -1,7 +0,0 @@ -{EventEmitter} = require 'events' - -{powerMonitor} = process.atomBinding 'power_monitor' - -powerMonitor.__proto__ = EventEmitter.prototype - -module.exports = powerMonitor diff --git a/atom/browser/api/lib/power-monitor.js b/atom/browser/api/lib/power-monitor.js new file mode 100644 index 000000000000..df4b28c6eb66 --- /dev/null +++ b/atom/browser/api/lib/power-monitor.js @@ -0,0 +1,9 @@ +var EventEmitter, powerMonitor; + +EventEmitter = require('events').EventEmitter; + +powerMonitor = process.atomBinding('power_monitor').powerMonitor; + +powerMonitor.__proto__ = EventEmitter.prototype; + +module.exports = powerMonitor; diff --git a/atom/browser/api/lib/power-save-blocker.coffee b/atom/browser/api/lib/power-save-blocker.coffee deleted file mode 100644 index 58392bc9aa8b..000000000000 --- a/atom/browser/api/lib/power-save-blocker.coffee +++ /dev/null @@ -1,3 +0,0 @@ -{powerSaveBlocker} = process.atomBinding 'power_save_blocker' - -module.exports = powerSaveBlocker diff --git a/atom/browser/api/lib/power-save-blocker.js b/atom/browser/api/lib/power-save-blocker.js new file mode 100644 index 000000000000..c44e3e2b63a2 --- /dev/null +++ b/atom/browser/api/lib/power-save-blocker.js @@ -0,0 +1,5 @@ +var powerSaveBlocker; + +powerSaveBlocker = process.atomBinding('power_save_blocker').powerSaveBlocker; + +module.exports = powerSaveBlocker; diff --git a/atom/browser/api/lib/protocol.coffee b/atom/browser/api/lib/protocol.coffee deleted file mode 100644 index 1add325eaae0..000000000000 --- a/atom/browser/api/lib/protocol.coffee +++ /dev/null @@ -1,25 +0,0 @@ -{app} = require 'electron' - -throw new Error('Can not initialize protocol module before app is ready') unless app.isReady() - -{protocol} = process.atomBinding 'protocol' - -### Warn about removed APIs. ### -logAndThrow = (callback, message) -> - console.error message - if callback then callback(new Error(message)) else throw new Error(message) -protocol.registerProtocol = (scheme, handler, callback) -> - logAndThrow callback, - 'registerProtocol API has been replaced by the - register[File/Http/Buffer/String]Protocol API family, please - switch to the new APIs.' -protocol.isHandledProtocol = (scheme, callback) -> - logAndThrow callback, - 'isHandledProtocol API has been replaced by isProtocolHandled.' -protocol.interceptProtocol = (scheme, handler, callback) -> - logAndThrow callback, - 'interceptProtocol API has been replaced by the - intercept[File/Http/Buffer/String]Protocol API family, please - switch to the new APIs.' - -module.exports = protocol diff --git a/atom/browser/api/lib/protocol.js b/atom/browser/api/lib/protocol.js new file mode 100644 index 000000000000..d601e588cf32 --- /dev/null +++ b/atom/browser/api/lib/protocol.js @@ -0,0 +1,35 @@ +var app, logAndThrow, protocol; + +app = require('electron').app; + +if (!app.isReady()) { + throw new Error('Can not initialize protocol module before app is ready'); +} + +protocol = process.atomBinding('protocol').protocol; + + +/* Warn about removed APIs. */ + +logAndThrow = function(callback, message) { + console.error(message); + if (callback) { + return callback(new Error(message)); + } else { + throw new Error(message); + } +}; + +protocol.registerProtocol = function(scheme, handler, callback) { + return logAndThrow(callback, 'registerProtocol API has been replaced by the register[File/Http/Buffer/String]Protocol API family, please switch to the new APIs.'); +}; + +protocol.isHandledProtocol = function(scheme, callback) { + return logAndThrow(callback, 'isHandledProtocol API has been replaced by isProtocolHandled.'); +}; + +protocol.interceptProtocol = function(scheme, handler, callback) { + return logAndThrow(callback, 'interceptProtocol API has been replaced by the intercept[File/Http/Buffer/String]Protocol API family, please switch to the new APIs.'); +}; + +module.exports = protocol; diff --git a/atom/browser/api/lib/screen.coffee b/atom/browser/api/lib/screen.coffee deleted file mode 100644 index 87c42f091df2..000000000000 --- a/atom/browser/api/lib/screen.coffee +++ /dev/null @@ -1,6 +0,0 @@ -{EventEmitter} = require 'events' -{screen} = process.atomBinding 'screen' - -screen.__proto__ = EventEmitter.prototype - -module.exports = screen diff --git a/atom/browser/api/lib/screen.js b/atom/browser/api/lib/screen.js new file mode 100644 index 000000000000..3dca49e99d90 --- /dev/null +++ b/atom/browser/api/lib/screen.js @@ -0,0 +1,9 @@ +var EventEmitter, screen; + +EventEmitter = require('events').EventEmitter; + +screen = process.atomBinding('screen').screen; + +screen.__proto__ = EventEmitter.prototype; + +module.exports = screen; diff --git a/atom/browser/api/lib/session.coffee b/atom/browser/api/lib/session.coffee deleted file mode 100644 index 95f9e474e090..000000000000 --- a/atom/browser/api/lib/session.coffee +++ /dev/null @@ -1,24 +0,0 @@ -{EventEmitter} = require 'events' - -bindings = process.atomBinding 'session' - -PERSIST_PERFIX = 'persist:' - -### Returns the Session from |partition| string. ### -exports.fromPartition = (partition='') -> - return exports.defaultSession if partition is '' - if partition.startsWith PERSIST_PERFIX - bindings.fromPartition partition.substr(PERSIST_PERFIX.length), false - else - bindings.fromPartition partition, true - -### Returns the default session. ### -Object.defineProperty exports, 'defaultSession', - enumerable: true - get: -> bindings.fromPartition '', false - -wrapSession = (session) -> - ### session is an EventEmitter. ### - session.__proto__ = EventEmitter.prototype - -bindings._setWrapSession wrapSession diff --git a/atom/browser/api/lib/session.js b/atom/browser/api/lib/session.js new file mode 100644 index 000000000000..fa43a2ae219d --- /dev/null +++ b/atom/browser/api/lib/session.js @@ -0,0 +1,42 @@ +var EventEmitter, PERSIST_PERFIX, bindings, wrapSession; + +EventEmitter = require('events').EventEmitter; + +bindings = process.atomBinding('session'); + +PERSIST_PERFIX = 'persist:'; + + +/* Returns the Session from |partition| string. */ + +exports.fromPartition = function(partition) { + if (partition == null) { + partition = ''; + } + if (partition === '') { + return exports.defaultSession; + } + if (partition.startsWith(PERSIST_PERFIX)) { + return bindings.fromPartition(partition.substr(PERSIST_PERFIX.length), false); + } else { + return bindings.fromPartition(partition, true); + } +}; + + +/* Returns the default session. */ + +Object.defineProperty(exports, 'defaultSession', { + enumerable: true, + get: function() { + return bindings.fromPartition('', false); + } +}); + +wrapSession = function(session) { + + /* session is an EventEmitter. */ + return session.__proto__ = EventEmitter.prototype; +}; + +bindings._setWrapSession(wrapSession); diff --git a/atom/browser/api/lib/tray.coffee b/atom/browser/api/lib/tray.coffee deleted file mode 100644 index 70a423dd97d5..000000000000 --- a/atom/browser/api/lib/tray.coffee +++ /dev/null @@ -1,20 +0,0 @@ -{deprecate} = require 'electron' -{EventEmitter} = require 'events' - -{Tray} = process.atomBinding 'tray' -Tray::__proto__ = EventEmitter.prototype - -Tray::_init = -> - ### Deprecated. ### - deprecate.rename this, 'popContextMenu', 'popUpContextMenu' - deprecate.event this, 'clicked', 'click' - deprecate.event this, 'double-clicked', 'double-click' - deprecate.event this, 'right-clicked', 'right-click' - deprecate.event this, 'balloon-clicked', 'balloon-click' - -Tray::setContextMenu = (menu) -> - @_setContextMenu menu - ### Keep a strong reference of menu. ### - @menu = menu - -module.exports = Tray diff --git a/atom/browser/api/lib/tray.js b/atom/browser/api/lib/tray.js new file mode 100644 index 000000000000..822bf31eb3af --- /dev/null +++ b/atom/browser/api/lib/tray.js @@ -0,0 +1,28 @@ +var EventEmitter, Tray, deprecate; + +deprecate = require('electron').deprecate; + +EventEmitter = require('events').EventEmitter; + +Tray = process.atomBinding('tray').Tray; + +Tray.prototype.__proto__ = EventEmitter.prototype; + +Tray.prototype._init = function() { + + /* Deprecated. */ + deprecate.rename(this, 'popContextMenu', 'popUpContextMenu'); + deprecate.event(this, 'clicked', 'click'); + deprecate.event(this, 'double-clicked', 'double-click'); + deprecate.event(this, 'right-clicked', 'right-click'); + return deprecate.event(this, 'balloon-clicked', 'balloon-click'); +}; + +Tray.prototype.setContextMenu = function(menu) { + this._setContextMenu(menu); + + /* Keep a strong reference of menu. */ + return this.menu = menu; +}; + +module.exports = Tray; diff --git a/atom/browser/api/lib/web-contents.coffee b/atom/browser/api/lib/web-contents.coffee deleted file mode 100644 index 75e35c4fdc49..000000000000 --- a/atom/browser/api/lib/web-contents.coffee +++ /dev/null @@ -1,141 +0,0 @@ -{EventEmitter} = require 'events' -{deprecate, ipcMain, session, NavigationController, Menu} = require 'electron' - -binding = process.atomBinding 'web_contents' - -nextId = 0 -getNextId = -> ++nextId - -PDFPageSize = - A5: - custom_display_name: "A5" - height_microns: 210000 - name: "ISO_A5" - width_microns: 148000 - A4: - custom_display_name: "A4" - height_microns: 297000 - name: "ISO_A4" - is_default: "true" - width_microns: 210000 - A3: - custom_display_name: "A3" - height_microns: 420000 - name: "ISO_A3" - width_microns: 297000 - Legal: - custom_display_name: "Legal" - height_microns: 355600 - name: "NA_LEGAL" - width_microns: 215900 - Letter: - custom_display_name: "Letter" - height_microns: 279400 - name: "NA_LETTER" - width_microns: 215900 - Tabloid: - height_microns: 431800 - name: "NA_LEDGER" - width_microns: 279400 - custom_display_name: "Tabloid" - -wrapWebContents = (webContents) -> - ### webContents is an EventEmitter. ### - webContents.__proto__ = EventEmitter.prototype - - ### WebContents::send(channel, args..) ### - webContents.send = (channel, args...) -> - @_send channel, [args...] - - ### - Make sure webContents.executeJavaScript would run the code only when the - web contents has been loaded. - ### - webContents.executeJavaScript = (code, hasUserGesture=false) -> - if @getURL() and not @isLoading() - @_executeJavaScript code, hasUserGesture - else - webContents.once 'did-finish-load', @_executeJavaScript.bind(this, code, hasUserGesture) - - ### The navigation controller. ### - controller = new NavigationController(webContents) - for name, method of NavigationController.prototype when method instanceof Function - do (name, method) -> - webContents[name] = -> method.apply controller, arguments - - ### Dispatch IPC messages to the ipc module. ### - webContents.on 'ipc-message', (event, packed) -> - [channel, args...] = packed - ipcMain.emit channel, event, args... - webContents.on 'ipc-message-sync', (event, packed) -> - [channel, args...] = packed - Object.defineProperty event, 'returnValue', set: (value) -> event.sendReply JSON.stringify(value) - ipcMain.emit channel, event, args... - - ### Handle context menu action request from pepper plugin. ### - webContents.on 'pepper-context-menu', (event, params) -> - menu = Menu.buildFromTemplate params.menu - menu.popup params.x, params.y - - ### This error occurs when host could not be found. ### - webContents.on 'did-fail-provisional-load', (args...) -> - ### - Calling loadURL during this event might cause crash, so delay the event - until next tick. - ### - setImmediate => @emit 'did-fail-load', args... - - ### Delays the page-title-updated event to next tick. ### - webContents.on '-page-title-updated', (args...) -> - setImmediate => @emit 'page-title-updated', args... - - ### Deprecated. ### - deprecate.rename webContents, 'loadUrl', 'loadURL' - deprecate.rename webContents, 'getUrl', 'getURL' - deprecate.event webContents, 'page-title-set', 'page-title-updated', (args...) -> - @emit 'page-title-set', args... - - webContents.printToPDF = (options, callback) -> - printingSetting = - pageRage: [] - mediaSize: {} - landscape: false - color: 2 - headerFooterEnabled: false - marginsType: 0 - isFirstRequest: false - requestID: getNextId() - previewModifiable: true - printToPDF: true - printWithCloudPrint: false - printWithPrivet: false - printWithExtension: false - deviceName: "Save as PDF" - generateDraftData: true - fitToPageEnabled: false - duplex: 0 - copies: 1 - collate: true - shouldPrintBackgrounds: false - shouldPrintSelectionOnly: false - - if options.landscape - printingSetting.landscape = options.landscape - if options.marginsType - printingSetting.marginsType = options.marginsType - if options.printSelectionOnly - printingSetting.shouldPrintSelectionOnly = options.printSelectionOnly - if options.printBackground - printingSetting.shouldPrintBackgrounds = options.printBackground - - if options.pageSize and PDFPageSize[options.pageSize] - printingSetting.mediaSize = PDFPageSize[options.pageSize] - else - printingSetting.mediaSize = PDFPageSize['A4'] - - @_printToPDF printingSetting, callback - -binding._setWrapWebContents wrapWebContents - -module.exports.create = (options={}) -> - binding.create(options) diff --git a/atom/browser/api/lib/web-contents.js b/atom/browser/api/lib/web-contents.js new file mode 100644 index 000000000000..0d1b8b24bdd0 --- /dev/null +++ b/atom/browser/api/lib/web-contents.js @@ -0,0 +1,210 @@ +var EventEmitter, Menu, NavigationController, PDFPageSize, binding, deprecate, getNextId, ipcMain, nextId, ref, session, wrapWebContents, + slice = [].slice; + +EventEmitter = require('events').EventEmitter; + +ref = require('electron'), deprecate = ref.deprecate, ipcMain = ref.ipcMain, session = ref.session, NavigationController = ref.NavigationController, Menu = ref.Menu; + +binding = process.atomBinding('web_contents'); + +nextId = 0; + +getNextId = function() { + return ++nextId; +}; + +PDFPageSize = { + A5: { + custom_display_name: "A5", + height_microns: 210000, + name: "ISO_A5", + width_microns: 148000 + }, + A4: { + custom_display_name: "A4", + height_microns: 297000, + name: "ISO_A4", + is_default: "true", + width_microns: 210000 + }, + A3: { + custom_display_name: "A3", + height_microns: 420000, + name: "ISO_A3", + width_microns: 297000 + }, + Legal: { + custom_display_name: "Legal", + height_microns: 355600, + name: "NA_LEGAL", + width_microns: 215900 + }, + Letter: { + custom_display_name: "Letter", + height_microns: 279400, + name: "NA_LETTER", + width_microns: 215900 + }, + Tabloid: { + height_microns: 431800, + name: "NA_LEDGER", + width_microns: 279400, + custom_display_name: "Tabloid" + } +}; + +wrapWebContents = function(webContents) { + + /* webContents is an EventEmitter. */ + var controller, method, name, ref1; + webContents.__proto__ = EventEmitter.prototype; + + /* WebContents::send(channel, args..) */ + webContents.send = function() { + var args, channel; + channel = arguments[0], args = 2 <= arguments.length ? slice.call(arguments, 1) : []; + return this._send(channel, slice.call(args)); + }; + + /* + Make sure webContents.executeJavaScript would run the code only when the + web contents has been loaded. + */ + webContents.executeJavaScript = function(code, hasUserGesture) { + if (hasUserGesture == null) { + hasUserGesture = false; + } + if (this.getURL() && !this.isLoading()) { + return this._executeJavaScript(code, hasUserGesture); + } else { + return webContents.once('did-finish-load', this._executeJavaScript.bind(this, code, hasUserGesture)); + } + }; + + /* The navigation controller. */ + controller = new NavigationController(webContents); + ref1 = NavigationController.prototype; + for (name in ref1) { + method = ref1[name]; + if (method instanceof Function) { + (function(name, method) { + return webContents[name] = function() { + return method.apply(controller, arguments); + }; + })(name, method); + } + } + + /* Dispatch IPC messages to the ipc module. */ + webContents.on('ipc-message', function(event, packed) { + var args, channel; + channel = packed[0], args = 2 <= packed.length ? slice.call(packed, 1) : []; + return ipcMain.emit.apply(ipcMain, [channel, event].concat(slice.call(args))); + }); + webContents.on('ipc-message-sync', function(event, packed) { + var args, channel; + channel = packed[0], args = 2 <= packed.length ? slice.call(packed, 1) : []; + Object.defineProperty(event, 'returnValue', { + set: function(value) { + return event.sendReply(JSON.stringify(value)); + } + }); + return ipcMain.emit.apply(ipcMain, [channel, event].concat(slice.call(args))); + }); + + /* Handle context menu action request from pepper plugin. */ + webContents.on('pepper-context-menu', function(event, params) { + var menu; + menu = Menu.buildFromTemplate(params.menu); + return menu.popup(params.x, params.y); + }); + + /* This error occurs when host could not be found. */ + webContents.on('did-fail-provisional-load', function() { + var args; + args = 1 <= arguments.length ? slice.call(arguments, 0) : []; + + /* + Calling loadURL during this event might cause crash, so delay the event + until next tick. + */ + return setImmediate((function(_this) { + return function() { + return _this.emit.apply(_this, ['did-fail-load'].concat(slice.call(args))); + }; + })(this)); + }); + + /* Delays the page-title-updated event to next tick. */ + webContents.on('-page-title-updated', function() { + var args; + args = 1 <= arguments.length ? slice.call(arguments, 0) : []; + return setImmediate((function(_this) { + return function() { + return _this.emit.apply(_this, ['page-title-updated'].concat(slice.call(args))); + }; + })(this)); + }); + + /* Deprecated. */ + deprecate.rename(webContents, 'loadUrl', 'loadURL'); + deprecate.rename(webContents, 'getUrl', 'getURL'); + deprecate.event(webContents, 'page-title-set', 'page-title-updated', function() { + var args; + args = 1 <= arguments.length ? slice.call(arguments, 0) : []; + return this.emit.apply(this, ['page-title-set'].concat(slice.call(args))); + }); + return webContents.printToPDF = function(options, callback) { + var printingSetting; + printingSetting = { + pageRage: [], + mediaSize: {}, + landscape: false, + color: 2, + headerFooterEnabled: false, + marginsType: 0, + isFirstRequest: false, + requestID: getNextId(), + previewModifiable: true, + printToPDF: true, + printWithCloudPrint: false, + printWithPrivet: false, + printWithExtension: false, + deviceName: "Save as PDF", + generateDraftData: true, + fitToPageEnabled: false, + duplex: 0, + copies: 1, + collate: true, + shouldPrintBackgrounds: false, + shouldPrintSelectionOnly: false + }; + if (options.landscape) { + printingSetting.landscape = options.landscape; + } + if (options.marginsType) { + printingSetting.marginsType = options.marginsType; + } + if (options.printSelectionOnly) { + printingSetting.shouldPrintSelectionOnly = options.printSelectionOnly; + } + if (options.printBackground) { + printingSetting.shouldPrintBackgrounds = options.printBackground; + } + if (options.pageSize && PDFPageSize[options.pageSize]) { + printingSetting.mediaSize = PDFPageSize[options.pageSize]; + } else { + printingSetting.mediaSize = PDFPageSize['A4']; + } + return this._printToPDF(printingSetting, callback); + }; +}; + +binding._setWrapWebContents(wrapWebContents); + +module.exports.create = function(options) { + if (options == null) { + options = {}; + } + return binding.create(options); +}; diff --git a/atom/browser/lib/chrome-extension.coffee b/atom/browser/lib/chrome-extension.coffee deleted file mode 100644 index d20e4c3d5e85..000000000000 --- a/atom/browser/lib/chrome-extension.coffee +++ /dev/null @@ -1,98 +0,0 @@ -electron = require 'electron' -fs = require 'fs' -path = require 'path' -url = require 'url' - -### Mapping between hostname and file path. ### -hostPathMap = {} -hostPathMapNextKey = 0 - -getHostForPath = (path) -> - key = "extension-#{++hostPathMapNextKey}" - hostPathMap[key] = path - key - -getPathForHost = (host) -> - hostPathMap[host] - -### Cache extensionInfo. ### -extensionInfoMap = {} - -getExtensionInfoFromPath = (srcDirectory) -> - manifest = JSON.parse fs.readFileSync(path.join(srcDirectory, 'manifest.json')) - unless extensionInfoMap[manifest.name]? - ### - We can not use 'file://' directly because all resources in the extension - will be treated as relative to the root in Chrome. - ### - page = url.format - protocol: 'chrome-extension' - slashes: true - hostname: getHostForPath srcDirectory - pathname: manifest.devtools_page - extensionInfoMap[manifest.name] = - startPage: page - name: manifest.name - srcDirectory: srcDirectory - exposeExperimentalAPIs: true - extensionInfoMap[manifest.name] - -### The loaded extensions cache and its persistent path. ### -loadedExtensions = null -loadedExtensionsPath = null - -### Persistent loaded extensions. ### -{app} = electron -app.on 'will-quit', -> - try - loadedExtensions = Object.keys(extensionInfoMap).map (key) -> extensionInfoMap[key].srcDirectory - try - fs.mkdirSync path.dirname(loadedExtensionsPath) - catch e - fs.writeFileSync loadedExtensionsPath, JSON.stringify(loadedExtensions) - catch e - -### We can not use protocol or BrowserWindow until app is ready. ### -app.once 'ready', -> - {protocol, BrowserWindow} = electron - - ### Load persistented extensions. ### - loadedExtensionsPath = path.join app.getPath('userData'), 'DevTools Extensions' - - try - loadedExtensions = JSON.parse fs.readFileSync(loadedExtensionsPath) - loadedExtensions = [] unless Array.isArray loadedExtensions - ### Preheat the extensionInfo cache. ### - getExtensionInfoFromPath srcDirectory for srcDirectory in loadedExtensions - catch e - - ### The chrome-extension: can map a extension URL request to real file path. ### - chromeExtensionHandler = (request, callback) -> - parsed = url.parse request.url - return callback() unless parsed.hostname and parsed.path? - return callback() unless /extension-\d+/.test parsed.hostname - - directory = getPathForHost parsed.hostname - return callback() unless directory? - callback path.join(directory, parsed.path) - protocol.registerFileProtocol 'chrome-extension', chromeExtensionHandler, (error) -> - console.error 'Unable to register chrome-extension protocol' if error - - BrowserWindow::_loadDevToolsExtensions = (extensionInfoArray) -> - @devToolsWebContents?.executeJavaScript "DevToolsAPI.addExtensions(#{JSON.stringify(extensionInfoArray)});" - - BrowserWindow.addDevToolsExtension = (srcDirectory) -> - extensionInfo = getExtensionInfoFromPath srcDirectory - if extensionInfo - window._loadDevToolsExtensions [extensionInfo] for window in BrowserWindow.getAllWindows() - extensionInfo.name - - BrowserWindow.removeDevToolsExtension = (name) -> - delete extensionInfoMap[name] - - ### Load persistented extensions when devtools is opened. ### - init = BrowserWindow::_init - BrowserWindow::_init = -> - init.call this - @on 'devtools-opened', -> - @_loadDevToolsExtensions Object.keys(extensionInfoMap).map (key) -> extensionInfoMap[key] diff --git a/atom/browser/lib/chrome-extension.js b/atom/browser/lib/chrome-extension.js new file mode 100644 index 000000000000..e4de0b6779b3 --- /dev/null +++ b/atom/browser/lib/chrome-extension.js @@ -0,0 +1,163 @@ +var app, electron, extensionInfoMap, fs, getExtensionInfoFromPath, getHostForPath, getPathForHost, hostPathMap, hostPathMapNextKey, loadedExtensions, loadedExtensionsPath, path, url; + +electron = require('electron'); + +fs = require('fs'); + +path = require('path'); + +url = require('url'); + + +/* Mapping between hostname and file path. */ + +hostPathMap = {}; + +hostPathMapNextKey = 0; + +getHostForPath = function(path) { + var key; + key = "extension-" + (++hostPathMapNextKey); + hostPathMap[key] = path; + return key; +}; + +getPathForHost = function(host) { + return hostPathMap[host]; +}; + + +/* Cache extensionInfo. */ + +extensionInfoMap = {}; + +getExtensionInfoFromPath = function(srcDirectory) { + var manifest, page; + manifest = JSON.parse(fs.readFileSync(path.join(srcDirectory, 'manifest.json'))); + if (extensionInfoMap[manifest.name] == null) { + + /* + We can not use 'file://' directly because all resources in the extension + will be treated as relative to the root in Chrome. + */ + page = url.format({ + protocol: 'chrome-extension', + slashes: true, + hostname: getHostForPath(srcDirectory), + pathname: manifest.devtools_page + }); + extensionInfoMap[manifest.name] = { + startPage: page, + name: manifest.name, + srcDirectory: srcDirectory, + exposeExperimentalAPIs: true + }; + return extensionInfoMap[manifest.name]; + } +}; + + +/* The loaded extensions cache and its persistent path. */ + +loadedExtensions = null; + +loadedExtensionsPath = null; + + +/* Persistent loaded extensions. */ + +app = electron.app; + +app.on('will-quit', function() { + var e, error1, error2; + try { + loadedExtensions = Object.keys(extensionInfoMap).map(function(key) { + return extensionInfoMap[key].srcDirectory; + }); + try { + fs.mkdirSync(path.dirname(loadedExtensionsPath)); + } catch (error1) { + e = error1; + } + return fs.writeFileSync(loadedExtensionsPath, JSON.stringify(loadedExtensions)); + } catch (error2) { + e = error2; + } +}); + + +/* We can not use protocol or BrowserWindow until app is ready. */ + +app.once('ready', function() { + var BrowserWindow, chromeExtensionHandler, e, error1, i, init, len, protocol, srcDirectory; + protocol = electron.protocol, BrowserWindow = electron.BrowserWindow; + + /* Load persistented extensions. */ + loadedExtensionsPath = path.join(app.getPath('userData'), 'DevTools Extensions'); + try { + loadedExtensions = JSON.parse(fs.readFileSync(loadedExtensionsPath)); + if (!Array.isArray(loadedExtensions)) { + loadedExtensions = []; + } + + /* Preheat the extensionInfo cache. */ + for (i = 0, len = loadedExtensions.length; i < len; i++) { + srcDirectory = loadedExtensions[i]; + getExtensionInfoFromPath(srcDirectory); + } + } catch (error1) { + e = error1; + } + + /* The chrome-extension: can map a extension URL request to real file path. */ + chromeExtensionHandler = function(request, callback) { + var directory, parsed; + parsed = url.parse(request.url); + if (!(parsed.hostname && (parsed.path != null))) { + return callback(); + } + if (!/extension-\d+/.test(parsed.hostname)) { + return callback(); + } + directory = getPathForHost(parsed.hostname); + if (directory == null) { + return callback(); + } + return callback(path.join(directory, parsed.path)); + }; + protocol.registerFileProtocol('chrome-extension', chromeExtensionHandler, function(error) { + if (error) { + return console.error('Unable to register chrome-extension protocol'); + } + }); + BrowserWindow.prototype._loadDevToolsExtensions = function(extensionInfoArray) { + var ref; + return (ref = this.devToolsWebContents) != null ? ref.executeJavaScript("DevToolsAPI.addExtensions(" + (JSON.stringify(extensionInfoArray)) + ");") : void 0; + }; + BrowserWindow.addDevToolsExtension = function(srcDirectory) { + var extensionInfo, j, len1, ref, window; + extensionInfo = getExtensionInfoFromPath(srcDirectory); + if (extensionInfo) { + ref = BrowserWindow.getAllWindows(); + for (j = 0, len1 = ref.length; j < len1; j++) { + window = ref[j]; + window._loadDevToolsExtensions([extensionInfo]); + } + return extensionInfo.name; + } + }; + BrowserWindow.removeDevToolsExtension = function(name) { + return delete extensionInfoMap[name]; + }; + + /* Load persistented extensions when devtools is opened. */ + init = BrowserWindow.prototype._init; + return BrowserWindow.prototype._init = function() { + init.call(this); + return this.on('devtools-opened', function() { + return this._loadDevToolsExtensions(Object.keys(extensionInfoMap).map(function(key) { + return extensionInfoMap[key]; + })); + }); + }; +}); diff --git a/atom/browser/lib/desktop-capturer.coffee b/atom/browser/lib/desktop-capturer.coffee deleted file mode 100644 index f783ccc9f78b..000000000000 --- a/atom/browser/lib/desktop-capturer.coffee +++ /dev/null @@ -1,41 +0,0 @@ -{ipcMain} = require 'electron' -{desktopCapturer} = process.atomBinding 'desktop_capturer' - -deepEqual = (opt1, opt2) -> - return JSON.stringify(opt1) is JSON.stringify(opt2) - -### A queue for holding all requests from renderer process. ### -requestsQueue = [] - -ipcMain.on 'ATOM_BROWSER_DESKTOP_CAPTURER_GET_SOURCES', (event, captureWindow, captureScreen, thumbnailSize, id) -> - request = id: id, options: {captureWindow, captureScreen, thumbnailSize}, webContents: event.sender - requestsQueue.push request - desktopCapturer.startHandling captureWindow, captureScreen, thumbnailSize if requestsQueue.length is 1 - ### - If the WebContents is destroyed before receiving result, just remove the - reference from requestsQueue to make the module not send the result to it. - ### - event.sender.once 'destroyed', -> - request.webContents = null - -desktopCapturer.emit = (event, name, sources) -> - ### Receiving sources result from main process, now send them back to renderer. ### - handledRequest = requestsQueue.shift 0 - result = ({ id: source.id, name: source.name, thumbnail: source.thumbnail.toDataUrl() } for source in sources) - handledRequest.webContents?.send "ATOM_RENDERER_DESKTOP_CAPTURER_RESULT_#{handledRequest.id}", result - - ### - Check the queue to see whether there is other same request. If has, handle - it for reducing redunplicated `desktopCaptuer.startHandling` calls. - ### - unhandledRequestsQueue = [] - for request in requestsQueue - if deepEqual handledRequest.options, request.options - request.webContents?.send "ATOM_RENDERER_DESKTOP_CAPTURER_RESULT_#{request.id}", errorMessage, result - else - unhandledRequestsQueue.push request - requestsQueue = unhandledRequestsQueue - ### If the requestsQueue is not empty, start a new request handling. ### - if requestsQueue.length > 0 - {captureWindow, captureScreen, thumbnailSize} = requestsQueue[0].options - desktopCapturer.startHandling captureWindow, captureScreen, thumbnailSize diff --git a/atom/browser/lib/desktop-capturer.js b/atom/browser/lib/desktop-capturer.js new file mode 100644 index 000000000000..789aa37ebc8d --- /dev/null +++ b/atom/browser/lib/desktop-capturer.js @@ -0,0 +1,85 @@ +var deepEqual, desktopCapturer, ipcMain, requestsQueue; + +ipcMain = require('electron').ipcMain; + +desktopCapturer = process.atomBinding('desktop_capturer').desktopCapturer; + +deepEqual = function(opt1, opt2) { + return JSON.stringify(opt1) === JSON.stringify(opt2); +}; + + +/* A queue for holding all requests from renderer process. */ + +requestsQueue = []; + +ipcMain.on('ATOM_BROWSER_DESKTOP_CAPTURER_GET_SOURCES', function(event, captureWindow, captureScreen, thumbnailSize, id) { + var request; + request = { + id: id, + options: { + captureWindow: captureWindow, + captureScreen: captureScreen, + thumbnailSize: thumbnailSize + }, + webContents: event.sender + }; + requestsQueue.push(request); + if (requestsQueue.length === 1) { + desktopCapturer.startHandling(captureWindow, captureScreen, thumbnailSize); + } + + /* + If the WebContents is destroyed before receiving result, just remove the + reference from requestsQueue to make the module not send the result to it. + */ + return event.sender.once('destroyed', function() { + return request.webContents = null; + }); +}); + +desktopCapturer.emit = function(event, name, sources) { + + /* Receiving sources result from main process, now send them back to renderer. */ + var captureScreen, captureWindow, handledRequest, i, len, ref, ref1, ref2, request, result, source, thumbnailSize, unhandledRequestsQueue; + handledRequest = requestsQueue.shift(0); + result = (function() { + var i, len, results; + results = []; + for (i = 0, len = sources.length; i < len; i++) { + source = sources[i]; + results.push({ + id: source.id, + name: source.name, + thumbnail: source.thumbnail.toDataUrl() + }); + } + return results; + })(); + if ((ref = handledRequest.webContents) != null) { + ref.send("ATOM_RENDERER_DESKTOP_CAPTURER_RESULT_" + handledRequest.id, result); + } + + /* + Check the queue to see whether there is other same request. If has, handle + it for reducing redunplicated `desktopCaptuer.startHandling` calls. + */ + unhandledRequestsQueue = []; + for (i = 0, len = requestsQueue.length; i < len; i++) { + request = requestsQueue[i]; + if (deepEqual(handledRequest.options, request.options)) { + if ((ref1 = request.webContents) != null) { + ref1.send("ATOM_RENDERER_DESKTOP_CAPTURER_RESULT_" + request.id, errorMessage, result); + } + } else { + unhandledRequestsQueue.push(request); + } + } + requestsQueue = unhandledRequestsQueue; + + /* If the requestsQueue is not empty, start a new request handling. */ + if (requestsQueue.length > 0) { + ref2 = requestsQueue[0].options, captureWindow = ref2.captureWindow, captureScreen = ref2.captureScreen, thumbnailSize = ref2.thumbnailSize; + return desktopCapturer.startHandling(captureWindow, captureScreen, thumbnailSize); + } +}; diff --git a/atom/browser/lib/guest-view-manager.coffee b/atom/browser/lib/guest-view-manager.coffee deleted file mode 100644 index 037b9a4db2d6..000000000000 --- a/atom/browser/lib/guest-view-manager.coffee +++ /dev/null @@ -1,177 +0,0 @@ -{ipcMain, webContents} = require 'electron' - -### Doesn't exist in early initialization. ### -webViewManager = null - -supportedWebViewEvents = [ - 'load-commit' - 'did-finish-load' - 'did-fail-load' - 'did-frame-finish-load' - 'did-start-loading' - 'did-stop-loading' - 'did-get-response-details' - 'did-get-redirect-request' - 'dom-ready' - 'console-message' - 'devtools-opened' - 'devtools-closed' - 'devtools-focused' - 'new-window' - 'will-navigate' - 'did-navigate' - 'did-navigate-in-page' - 'close' - 'crashed' - 'gpu-crashed' - 'plugin-crashed' - 'destroyed' - 'page-title-updated' - 'page-favicon-updated' - 'enter-html-full-screen' - 'leave-html-full-screen' - 'media-started-playing' - 'media-paused' - 'found-in-page' - 'did-change-theme-color' -] - -nextInstanceId = 0 -guestInstances = {} -embedderElementsMap = {} -reverseEmbedderElementsMap = {} - -### Moves the last element of array to the first one. ### -moveLastToFirst = (list) -> - list.unshift list.pop() - -### Generate guestInstanceId. ### -getNextInstanceId = (webContents) -> - ++nextInstanceId - -### Create a new guest instance. ### -createGuest = (embedder, params) -> - webViewManager ?= process.atomBinding 'web_view_manager' - - id = getNextInstanceId embedder - guest = webContents.create {isGuest: true, partition: params.partition, embedder} - guestInstances[id] = {guest, embedder} - - ### Destroy guest when the embedder is gone or navigated. ### - destroyEvents = ['destroyed', 'crashed', 'did-navigate'] - destroy = -> - destroyGuest embedder, id if guestInstances[id]? - for event in destroyEvents - embedder.once event, destroy - ### - Users might also listen to the crashed event, so We must ensure the guest - is destroyed before users' listener gets called. It is done by moving our - listener to the first one in queue. - ### - listeners = embedder._events[event] - moveLastToFirst listeners if Array.isArray listeners - guest.once 'destroyed', -> - embedder.removeListener event, destroy for event in destroyEvents - - ### Init guest web view after attached. ### - guest.once 'did-attach', -> - params = @attachParams - delete @attachParams - - @viewInstanceId = params.instanceId - @setSize - normal: - width: params.elementWidth, height: params.elementHeight - enableAutoSize: params.autosize - min: - width: params.minwidth, height: params.minheight - max: - width: params.maxwidth, height: params.maxheight - - if params.src - opts = {} - opts.httpReferrer = params.httpreferrer if params.httpreferrer - opts.userAgent = params.useragent if params.useragent - @loadURL params.src, opts - - if params.allowtransparency? - @setAllowTransparency params.allowtransparency - - guest.allowPopups = params.allowpopups - - ### Dispatch events to embedder. ### - for event in supportedWebViewEvents - do (event) -> - guest.on event, (_, args...) -> - embedder.send "ATOM_SHELL_GUEST_VIEW_INTERNAL_DISPATCH_EVENT-#{guest.viewInstanceId}", event, args... - - ### Dispatch guest's IPC messages to embedder. ### - guest.on 'ipc-message-host', (_, packed) -> - [channel, args...] = packed - embedder.send "ATOM_SHELL_GUEST_VIEW_INTERNAL_IPC_MESSAGE-#{guest.viewInstanceId}", channel, args... - - ### Autosize. ### - guest.on 'size-changed', (_, args...) -> - embedder.send "ATOM_SHELL_GUEST_VIEW_INTERNAL_SIZE_CHANGED-#{guest.viewInstanceId}", args... - - id - -### Attach the guest to an element of embedder. ### -attachGuest = (embedder, elementInstanceId, guestInstanceId, params) -> - guest = guestInstances[guestInstanceId].guest - - ### Destroy the old guest when attaching. ### - key = "#{embedder.getId()}-#{elementInstanceId}" - oldGuestInstanceId = embedderElementsMap[key] - if oldGuestInstanceId? - ### Reattachment to the same guest is not currently supported. ### - return unless oldGuestInstanceId != guestInstanceId - - return unless guestInstances[oldGuestInstanceId]? - destroyGuest embedder, oldGuestInstanceId - - webPreferences = - guestInstanceId: guestInstanceId - nodeIntegration: params.nodeintegration ? false - plugins: params.plugins - webSecurity: !params.disablewebsecurity - webPreferences.preloadURL = params.preload if params.preload - webViewManager.addGuest guestInstanceId, elementInstanceId, embedder, guest, webPreferences - - guest.attachParams = params - embedderElementsMap[key] = guestInstanceId - reverseEmbedderElementsMap[guestInstanceId] = key - -### Destroy an existing guest instance. ### -destroyGuest = (embedder, id) -> - webViewManager.removeGuest embedder, id - guestInstances[id].guest.destroy() - delete guestInstances[id] - - key = reverseEmbedderElementsMap[id] - if key? - delete reverseEmbedderElementsMap[id] - delete embedderElementsMap[key] - -ipcMain.on 'ATOM_SHELL_GUEST_VIEW_MANAGER_CREATE_GUEST', (event, params, requestId) -> - event.sender.send "ATOM_SHELL_RESPONSE_#{requestId}", createGuest(event.sender, params) - -ipcMain.on 'ATOM_SHELL_GUEST_VIEW_MANAGER_ATTACH_GUEST', (event, elementInstanceId, guestInstanceId, params) -> - attachGuest event.sender, elementInstanceId, guestInstanceId, params - -ipcMain.on 'ATOM_SHELL_GUEST_VIEW_MANAGER_DESTROY_GUEST', (event, id) -> - destroyGuest event.sender, id - -ipcMain.on 'ATOM_SHELL_GUEST_VIEW_MANAGER_SET_SIZE', (event, id, params) -> - guestInstances[id]?.guest.setSize params - -ipcMain.on 'ATOM_SHELL_GUEST_VIEW_MANAGER_SET_ALLOW_TRANSPARENCY', (event, id, allowtransparency) -> - guestInstances[id]?.guest.setAllowTransparency allowtransparency - -### Returns WebContents from its guest id. ### -exports.getGuest = (id) -> - guestInstances[id]?.guest - -### Returns the embedder of the guest. ### -exports.getEmbedder = (id) -> - guestInstances[id]?.embedder diff --git a/atom/browser/lib/guest-view-manager.js b/atom/browser/lib/guest-view-manager.js new file mode 100644 index 000000000000..a1d82483a954 --- /dev/null +++ b/atom/browser/lib/guest-view-manager.js @@ -0,0 +1,238 @@ +var attachGuest, createGuest, destroyGuest, embedderElementsMap, getNextInstanceId, guestInstances, ipcMain, moveLastToFirst, nextInstanceId, ref, reverseEmbedderElementsMap, supportedWebViewEvents, webContents, webViewManager, + slice = [].slice; + +ref = require('electron'), ipcMain = ref.ipcMain, webContents = ref.webContents; + + +/* Doesn't exist in early initialization. */ + +webViewManager = null; + +supportedWebViewEvents = ['load-commit', 'did-finish-load', 'did-fail-load', 'did-frame-finish-load', 'did-start-loading', 'did-stop-loading', 'did-get-response-details', 'did-get-redirect-request', 'dom-ready', 'console-message', 'devtools-opened', 'devtools-closed', 'devtools-focused', 'new-window', 'will-navigate', 'did-navigate', 'did-navigate-in-page', 'close', 'crashed', 'gpu-crashed', 'plugin-crashed', 'destroyed', 'page-title-updated', 'page-favicon-updated', 'enter-html-full-screen', 'leave-html-full-screen', 'media-started-playing', 'media-paused', 'found-in-page', 'did-change-theme-color']; + +nextInstanceId = 0; + +guestInstances = {}; + +embedderElementsMap = {}; + +reverseEmbedderElementsMap = {}; + + +/* Moves the last element of array to the first one. */ + +moveLastToFirst = function(list) { + return list.unshift(list.pop()); +}; + + +/* Generate guestInstanceId. */ + +getNextInstanceId = function(webContents) { + return ++nextInstanceId; +}; + + +/* Create a new guest instance. */ + +createGuest = function(embedder, params) { + var destroy, destroyEvents, event, fn, guest, i, id, j, len, len1, listeners; + if (webViewManager == null) { + webViewManager = process.atomBinding('web_view_manager'); + } + id = getNextInstanceId(embedder); + guest = webContents.create({ + isGuest: true, + partition: params.partition, + embedder: embedder + }); + guestInstances[id] = { + guest: guest, + embedder: embedder + }; + + /* Destroy guest when the embedder is gone or navigated. */ + destroyEvents = ['destroyed', 'crashed', 'did-navigate']; + destroy = function() { + if (guestInstances[id] != null) { + return destroyGuest(embedder, id); + } + }; + for (i = 0, len = destroyEvents.length; i < len; i++) { + event = destroyEvents[i]; + embedder.once(event, destroy); + + /* + Users might also listen to the crashed event, so We must ensure the guest + is destroyed before users' listener gets called. It is done by moving our + listener to the first one in queue. + */ + listeners = embedder._events[event]; + if (Array.isArray(listeners)) { + moveLastToFirst(listeners); + } + } + guest.once('destroyed', function() { + var j, len1, results; + results = []; + for (j = 0, len1 = destroyEvents.length; j < len1; j++) { + event = destroyEvents[j]; + results.push(embedder.removeListener(event, destroy)); + } + return results; + }); + + /* Init guest web view after attached. */ + guest.once('did-attach', function() { + var opts; + params = this.attachParams; + delete this.attachParams; + this.viewInstanceId = params.instanceId; + this.setSize({ + normal: { + width: params.elementWidth, + height: params.elementHeight + }, + enableAutoSize: params.autosize, + min: { + width: params.minwidth, + height: params.minheight + }, + max: { + width: params.maxwidth, + height: params.maxheight + } + }); + if (params.src) { + opts = {}; + if (params.httpreferrer) { + opts.httpReferrer = params.httpreferrer; + } + if (params.useragent) { + opts.userAgent = params.useragent; + } + this.loadURL(params.src, opts); + } + if (params.allowtransparency != null) { + this.setAllowTransparency(params.allowtransparency); + } + return guest.allowPopups = params.allowpopups; + }); + + /* Dispatch events to embedder. */ + fn = function(event) { + return guest.on(event, function() { + var _, args; + _ = arguments[0], args = 2 <= arguments.length ? slice.call(arguments, 1) : []; + return embedder.send.apply(embedder, ["ATOM_SHELL_GUEST_VIEW_INTERNAL_DISPATCH_EVENT-" + guest.viewInstanceId, event].concat(slice.call(args))); + }); + }; + for (j = 0, len1 = supportedWebViewEvents.length; j < len1; j++) { + event = supportedWebViewEvents[j]; + fn(event); + } + + /* Dispatch guest's IPC messages to embedder. */ + guest.on('ipc-message-host', function(_, packed) { + var args, channel; + channel = packed[0], args = 2 <= packed.length ? slice.call(packed, 1) : []; + return embedder.send.apply(embedder, ["ATOM_SHELL_GUEST_VIEW_INTERNAL_IPC_MESSAGE-" + guest.viewInstanceId, channel].concat(slice.call(args))); + }); + + /* Autosize. */ + guest.on('size-changed', function() { + var _, args; + _ = arguments[0], args = 2 <= arguments.length ? slice.call(arguments, 1) : []; + return embedder.send.apply(embedder, ["ATOM_SHELL_GUEST_VIEW_INTERNAL_SIZE_CHANGED-" + guest.viewInstanceId].concat(slice.call(args))); + }); + return id; +}; + + +/* Attach the guest to an element of embedder. */ + +attachGuest = function(embedder, elementInstanceId, guestInstanceId, params) { + var guest, key, oldGuestInstanceId, ref1, webPreferences; + guest = guestInstances[guestInstanceId].guest; + + /* Destroy the old guest when attaching. */ + key = (embedder.getId()) + "-" + elementInstanceId; + oldGuestInstanceId = embedderElementsMap[key]; + if (oldGuestInstanceId != null) { + + /* Reattachment to the same guest is not currently supported. */ + if (oldGuestInstanceId === guestInstanceId) { + return; + } + if (guestInstances[oldGuestInstanceId] == null) { + return; + } + destroyGuest(embedder, oldGuestInstanceId); + } + webPreferences = { + guestInstanceId: guestInstanceId, + nodeIntegration: (ref1 = params.nodeintegration) != null ? ref1 : false, + plugins: params.plugins, + webSecurity: !params.disablewebsecurity + }; + if (params.preload) { + webPreferences.preloadURL = params.preload; + } + webViewManager.addGuest(guestInstanceId, elementInstanceId, embedder, guest, webPreferences); + guest.attachParams = params; + embedderElementsMap[key] = guestInstanceId; + return reverseEmbedderElementsMap[guestInstanceId] = key; +}; + + +/* Destroy an existing guest instance. */ + +destroyGuest = function(embedder, id) { + var key; + webViewManager.removeGuest(embedder, id); + guestInstances[id].guest.destroy(); + delete guestInstances[id]; + key = reverseEmbedderElementsMap[id]; + if (key != null) { + delete reverseEmbedderElementsMap[id]; + return delete embedderElementsMap[key]; + } +}; + +ipcMain.on('ATOM_SHELL_GUEST_VIEW_MANAGER_CREATE_GUEST', function(event, params, requestId) { + return event.sender.send("ATOM_SHELL_RESPONSE_" + requestId, createGuest(event.sender, params)); +}); + +ipcMain.on('ATOM_SHELL_GUEST_VIEW_MANAGER_ATTACH_GUEST', function(event, elementInstanceId, guestInstanceId, params) { + return attachGuest(event.sender, elementInstanceId, guestInstanceId, params); +}); + +ipcMain.on('ATOM_SHELL_GUEST_VIEW_MANAGER_DESTROY_GUEST', function(event, id) { + return destroyGuest(event.sender, id); +}); + +ipcMain.on('ATOM_SHELL_GUEST_VIEW_MANAGER_SET_SIZE', function(event, id, params) { + var ref1; + return (ref1 = guestInstances[id]) != null ? ref1.guest.setSize(params) : void 0; +}); + +ipcMain.on('ATOM_SHELL_GUEST_VIEW_MANAGER_SET_ALLOW_TRANSPARENCY', function(event, id, allowtransparency) { + var ref1; + return (ref1 = guestInstances[id]) != null ? ref1.guest.setAllowTransparency(allowtransparency) : void 0; +}); + + +/* Returns WebContents from its guest id. */ + +exports.getGuest = function(id) { + var ref1; + return (ref1 = guestInstances[id]) != null ? ref1.guest : void 0; +}; + + +/* Returns the embedder of the guest. */ + +exports.getEmbedder = function(id) { + var ref1; + return (ref1 = guestInstances[id]) != null ? ref1.embedder : void 0; +}; diff --git a/atom/browser/lib/guest-window-manager.coffee b/atom/browser/lib/guest-window-manager.coffee deleted file mode 100644 index 101bd79951b7..000000000000 --- a/atom/browser/lib/guest-window-manager.coffee +++ /dev/null @@ -1,88 +0,0 @@ -{ipcMain, BrowserWindow} = require 'electron' -v8Util = process.atomBinding 'v8_util' - -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 of child - if typeof value is 'object' - child[key] = mergeOptions {}, value - else - child[key] = value - child - -### Merge |options| with the |embedder|'s window's options. ### -mergeBrowserWindowOptions = (embedder, options) -> - if embedder.browserWindowOptions? - ### Inherit the original options if it is a BrowserWindow. ### - mergeOptions options, embedder.browserWindowOptions - else - ### Or only inherit web-preferences if it is a webview. ### - options.webPreferences ?= {} - mergeOptions options.webPreferences, embedder.getWebPreferences() - options - -### Create a new guest created by |embedder| with |options|. ### -createGuest = (embedder, url, frameName, options) -> - guest = frameToGuest[frameName] - if frameName and guest? - guest.loadURL url - return guest.id - - ### Remember the embedder window's id. ### - options.webPreferences ?= {} - options.webPreferences.openerId = BrowserWindow.fromWebContents(embedder)?.id - - guest = new BrowserWindow(options) - guest.loadURL url - - ### - 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_#{guestId}" - embedder.removeListener 'render-view-deleted', closedByEmbedder - embedder.once 'render-view-deleted', closedByEmbedder - guest.once 'closed', closedByUser - - if frameName - frameToGuest[frameName] = guest - guest.frameName = frameName - guest.once 'closed', -> - delete frameToGuest[frameName] - - guest.id - -### Routed window.open messages. ### -ipcMain.on 'ATOM_SHELL_GUEST_WINDOW_MANAGER_WINDOW_OPEN', (event, args...) -> - [url, frameName, options] = args - 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, url, frameName, options - -ipcMain.on 'ATOM_SHELL_GUEST_WINDOW_MANAGER_WINDOW_CLOSE', (event, guestId) -> - BrowserWindow.fromId(guestId)?.destroy() - -ipcMain.on 'ATOM_SHELL_GUEST_WINDOW_MANAGER_WINDOW_METHOD', (event, guestId, method, args...) -> - BrowserWindow.fromId(guestId)?[method] args... - -ipcMain.on 'ATOM_SHELL_GUEST_WINDOW_MANAGER_WINDOW_POSTMESSAGE', (event, guestId, message, targetOrigin, sourceOrigin) -> - sourceId = BrowserWindow.fromWebContents(event.sender)?.id - return unless sourceId? - - guestContents = BrowserWindow.fromId(guestId)?.webContents - if guestContents?.getURL().indexOf(targetOrigin) is 0 or targetOrigin is '*' - guestContents?.send 'ATOM_SHELL_GUEST_WINDOW_POSTMESSAGE', sourceId, message, sourceOrigin - -ipcMain.on 'ATOM_SHELL_GUEST_WINDOW_MANAGER_WEB_CONTENTS_METHOD', (event, guestId, method, args...) -> - BrowserWindow.fromId(guestId)?.webContents?[method] args... diff --git a/atom/browser/lib/guest-window-manager.js b/atom/browser/lib/guest-window-manager.js new file mode 100644 index 000000000000..5b1290c282ec --- /dev/null +++ b/atom/browser/lib/guest-window-manager.js @@ -0,0 +1,137 @@ +var BrowserWindow, createGuest, frameToGuest, ipcMain, mergeBrowserWindowOptions, mergeOptions, ref, v8Util, + hasProp = {}.hasOwnProperty, + slice = [].slice; + +ref = require('electron'), ipcMain = ref.ipcMain, BrowserWindow = ref.BrowserWindow; + +v8Util = process.atomBinding('v8_util'); + +frameToGuest = {}; + + +/* Copy attribute of |parent| to |child| if it is not defined in |child|. */ + +mergeOptions = function(child, parent) { + var key, value; + for (key in parent) { + if (!hasProp.call(parent, key)) continue; + value = parent[key]; + if (!(key in child)) { + if (typeof value === 'object') { + child[key] = mergeOptions({}, value); + } else { + child[key] = value; + } + } + } + return child; +}; + + +/* Merge |options| with the |embedder|'s window's options. */ + +mergeBrowserWindowOptions = function(embedder, options) { + if (embedder.browserWindowOptions != null) { + + /* Inherit the original options if it is a BrowserWindow. */ + mergeOptions(options, embedder.browserWindowOptions); + } else { + + /* Or only inherit web-preferences if it is a webview. */ + if (options.webPreferences == null) { + options.webPreferences = {}; + } + mergeOptions(options.webPreferences, embedder.getWebPreferences()); + } + return options; +}; + + +/* Create a new guest created by |embedder| with |options|. */ + +createGuest = function(embedder, url, frameName, options) { + var closedByEmbedder, closedByUser, guest, guestId, ref1; + guest = frameToGuest[frameName]; + if (frameName && (guest != null)) { + guest.loadURL(url); + return guest.id; + } + + /* Remember the embedder window's id. */ + if (options.webPreferences == null) { + options.webPreferences = {}; + } + options.webPreferences.openerId = (ref1 = BrowserWindow.fromWebContents(embedder)) != null ? ref1.id : void 0; + guest = new BrowserWindow(options); + guest.loadURL(url); + + /* + 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 = function() { + guest.removeListener('closed', closedByUser); + return guest.destroy(); + }; + closedByUser = function() { + embedder.send("ATOM_SHELL_GUEST_WINDOW_MANAGER_WINDOW_CLOSED_" + guestId); + return embedder.removeListener('render-view-deleted', closedByEmbedder); + }; + embedder.once('render-view-deleted', closedByEmbedder); + guest.once('closed', closedByUser); + if (frameName) { + frameToGuest[frameName] = guest; + guest.frameName = frameName; + guest.once('closed', function() { + return delete frameToGuest[frameName]; + }); + } + return guest.id; +}; + + +/* Routed window.open messages. */ + +ipcMain.on('ATOM_SHELL_GUEST_WINDOW_MANAGER_WINDOW_OPEN', function() { + var args, event, frameName, options, url; + event = arguments[0], args = 2 <= arguments.length ? slice.call(arguments, 1) : []; + url = args[0], frameName = args[1], options = args[2]; + options = mergeBrowserWindowOptions(event.sender, options); + event.sender.emit('new-window', event, url, frameName, 'new-window', options); + if ((event.sender.isGuest() && !event.sender.allowPopups) || event.defaultPrevented) { + return event.returnValue = null; + } else { + return event.returnValue = createGuest(event.sender, url, frameName, options); + } +}); + +ipcMain.on('ATOM_SHELL_GUEST_WINDOW_MANAGER_WINDOW_CLOSE', function(event, guestId) { + var ref1; + return (ref1 = BrowserWindow.fromId(guestId)) != null ? ref1.destroy() : void 0; +}); + +ipcMain.on('ATOM_SHELL_GUEST_WINDOW_MANAGER_WINDOW_METHOD', function() { + var args, event, guestId, method, ref1; + event = arguments[0], guestId = arguments[1], method = arguments[2], args = 4 <= arguments.length ? slice.call(arguments, 3) : []; + return (ref1 = BrowserWindow.fromId(guestId)) != null ? ref1[method].apply(ref1, args) : void 0; +}); + +ipcMain.on('ATOM_SHELL_GUEST_WINDOW_MANAGER_WINDOW_POSTMESSAGE', function(event, guestId, message, targetOrigin, sourceOrigin) { + var guestContents, ref1, ref2, sourceId; + sourceId = (ref1 = BrowserWindow.fromWebContents(event.sender)) != null ? ref1.id : void 0; + if (sourceId == null) { + return; + } + guestContents = (ref2 = BrowserWindow.fromId(guestId)) != null ? ref2.webContents : void 0; + if ((guestContents != null ? guestContents.getURL().indexOf(targetOrigin) : void 0) === 0 || targetOrigin === '*') { + return guestContents != null ? guestContents.send('ATOM_SHELL_GUEST_WINDOW_POSTMESSAGE', sourceId, message, sourceOrigin) : void 0; + } +}); + +ipcMain.on('ATOM_SHELL_GUEST_WINDOW_MANAGER_WEB_CONTENTS_METHOD', function() { + var args, event, guestId, method, ref1, ref2; + event = arguments[0], guestId = arguments[1], method = arguments[2], args = 4 <= arguments.length ? slice.call(arguments, 3) : []; + return (ref1 = BrowserWindow.fromId(guestId)) != null ? (ref2 = ref1.webContents) != null ? ref2[method].apply(ref2, args) : void 0 : void 0; +}); diff --git a/atom/browser/lib/init.coffee b/atom/browser/lib/init.coffee deleted file mode 100644 index ace81d50148d..000000000000 --- a/atom/browser/lib/init.coffee +++ /dev/null @@ -1,120 +0,0 @@ -fs = require 'fs' -path = require 'path' -util = require 'util' -Module = require 'module' - -### We modified the original process.argv to let node.js load the atom.js, ### -### we need to restore it here. ### -process.argv.splice 1, 1 - -### Clear search paths. ### -require path.resolve(__dirname, '..', '..', 'common', 'lib', 'reset-search-paths') - -### Import common settings. ### -require path.resolve(__dirname, '..', '..', 'common', 'lib', 'init') - -globalPaths = Module.globalPaths -unless process.env.ELECTRON_HIDE_INTERNAL_MODULES - globalPaths.push path.resolve(__dirname, '..', 'api', 'lib') - -### Expose public APIs. ### -globalPaths.push path.resolve(__dirname, '..', 'api', 'lib', 'exports') - -if process.platform is 'win32' - ### - Redirect node's console to use our own implementations, since node can not - handle console output when running as GUI program. - ### - consoleLog = (args...) -> - process.log util.format(args...) + "\n" - streamWrite = (chunk, encoding, callback) -> - chunk = chunk.toString(encoding) if Buffer.isBuffer chunk - process.log chunk - callback() if callback - true - console.log = console.error = console.warn = consoleLog - process.stdout.write = process.stderr.write = streamWrite - - ### Always returns EOF for stdin stream. ### - Readable = require('stream').Readable - stdin = new Readable - stdin.push null - process.__defineGetter__ 'stdin', -> stdin - -### Don't quit on fatal error. ### -process.on 'uncaughtException', (error) -> - ### Do nothing if the user has a custom uncaught exception handler. ### - if process.listeners('uncaughtException').length > 1 - return - - ### Show error in GUI. ### - {dialog} = require 'electron' - stack = error.stack ? "#{error.name}: #{error.message}" - message = "Uncaught Exception:\n#{stack}" - dialog.showErrorBox 'A JavaScript error occurred in the main process', message - -### Emit 'exit' event on quit. ### -{app} = require 'electron' -app.on 'quit', (event, exitCode) -> - process.emit 'exit', exitCode - -### Map process.exit to app.exit, which quits gracefully. ### -process.exit = app.exit - -### Load the RPC server. ### -require './rpc-server' - -### Load the guest view manager. ### -require './guest-view-manager' -require './guest-window-manager' - -### Now we try to load app's package.json. ### -packageJson = null - -searchPaths = [ 'app', 'app.asar', 'default_app' ] -for packagePath in searchPaths - try - packagePath = path.join process.resourcesPath, packagePath - packageJson = JSON.parse(fs.readFileSync(path.join(packagePath, 'package.json'))) - break - catch e - continue - -unless packageJson? - process.nextTick -> process.exit 1 - throw new Error("Unable to find a valid app") - -### Set application's version. ### -app.setVersion packageJson.version if packageJson.version? - -### Set application's name. ### -if packageJson.productName? - app.setName packageJson.productName -else if packageJson.name? - app.setName packageJson.name - -### Set application's desktop name. ### -if packageJson.desktopName? - app.setDesktopName packageJson.desktopName -else - app.setDesktopName "#{app.getName()}.desktop" - -### Chrome 42 disables NPAPI plugins by default, reenable them here ### -app.commandLine.appendSwitch 'enable-npapi' - -### Set the user path according to application's name. ### -app.setPath 'userData', path.join(app.getPath('appData'), app.getName()) -app.setPath 'userCache', path.join(app.getPath('cache'), app.getName()) -app.setAppPath packagePath - -### Load the chrome extension support. ### -require './chrome-extension' - -### Load internal desktop-capturer module. ### -require './desktop-capturer' - -### Set main startup script of the app. ### -mainStartupScript = packageJson.main or 'index.js' - -### Finally load app's main.js and transfer control to C++. ### -Module._load path.join(packagePath, mainStartupScript), Module, true diff --git a/atom/browser/lib/init.js b/atom/browser/lib/init.js new file mode 100644 index 000000000000..ea44e2c9b04e --- /dev/null +++ b/atom/browser/lib/init.js @@ -0,0 +1,201 @@ +var Module, Readable, app, consoleLog, e, error1, fs, globalPaths, i, len, mainStartupScript, packageJson, packagePath, path, searchPaths, stdin, streamWrite, util, + slice = [].slice; + +fs = require('fs'); + +path = require('path'); + +util = require('util'); + +Module = require('module'); + + +/* We modified the original process.argv to let node.js load the atom.js, */ + + +/* we need to restore it here. */ + +process.argv.splice(1, 1); + + +/* Clear search paths. */ + +require(path.resolve(__dirname, '..', '..', 'common', 'lib', 'reset-search-paths')); + + +/* Import common settings. */ + +require(path.resolve(__dirname, '..', '..', 'common', 'lib', 'init')); + +globalPaths = Module.globalPaths; + +if (!process.env.ELECTRON_HIDE_INTERNAL_MODULES) { + globalPaths.push(path.resolve(__dirname, '..', 'api', 'lib')); +} + + +/* Expose public APIs. */ + +globalPaths.push(path.resolve(__dirname, '..', 'api', 'lib', 'exports')); + +if (process.platform === 'win32') { + + /* + Redirect node's console to use our own implementations, since node can not + handle console output when running as GUI program. + */ + consoleLog = function() { + var args; + args = 1 <= arguments.length ? slice.call(arguments, 0) : []; + return process.log(util.format.apply(util, args) + "\n"); + }; + streamWrite = function(chunk, encoding, callback) { + if (Buffer.isBuffer(chunk)) { + chunk = chunk.toString(encoding); + } + process.log(chunk); + if (callback) { + callback(); + } + return true; + }; + console.log = console.error = console.warn = consoleLog; + process.stdout.write = process.stderr.write = streamWrite; + + /* Always returns EOF for stdin stream. */ + Readable = require('stream').Readable; + stdin = new Readable; + stdin.push(null); + process.__defineGetter__('stdin', function() { + return stdin; + }); +} + + +/* Don't quit on fatal error. */ + +process.on('uncaughtException', function(error) { + + /* Do nothing if the user has a custom uncaught exception handler. */ + var dialog, message, ref, stack; + if (process.listeners('uncaughtException').length > 1) { + return; + } + + /* Show error in GUI. */ + dialog = require('electron').dialog; + stack = (ref = error.stack) != null ? ref : error.name + ": " + error.message; + message = "Uncaught Exception:\n" + stack; + return dialog.showErrorBox('A JavaScript error occurred in the main process', message); +}); + + +/* Emit 'exit' event on quit. */ + +app = require('electron').app; + +app.on('quit', function(event, exitCode) { + return process.emit('exit', exitCode); +}); + + +/* Map process.exit to app.exit, which quits gracefully. */ + +process.exit = app.exit; + + +/* Load the RPC server. */ + +require('./rpc-server'); + + +/* Load the guest view manager. */ + +require('./guest-view-manager'); + +require('./guest-window-manager'); + + +/* Now we try to load app's package.json. */ + +packageJson = null; + +searchPaths = ['app', 'app.asar', 'default_app']; + +for (i = 0, len = searchPaths.length; i < len; i++) { + packagePath = searchPaths[i]; + try { + packagePath = path.join(process.resourcesPath, packagePath); + packageJson = JSON.parse(fs.readFileSync(path.join(packagePath, 'package.json'))); + break; + } catch (error1) { + e = error1; + continue; + } +} + +if (packageJson == null) { + process.nextTick(function() { + return process.exit(1); + }); + throw new Error("Unable to find a valid app"); +} + + +/* Set application's version. */ + +if (packageJson.version != null) { + app.setVersion(packageJson.version); +} + + +/* Set application's name. */ + +if (packageJson.productName != null) { + app.setName(packageJson.productName); +} else if (packageJson.name != null) { + app.setName(packageJson.name); +} + + +/* Set application's desktop name. */ + +if (packageJson.desktopName != null) { + app.setDesktopName(packageJson.desktopName); +} else { + app.setDesktopName((app.getName()) + ".desktop"); +} + + +/* Chrome 42 disables NPAPI plugins by default, reenable them here */ + +app.commandLine.appendSwitch('enable-npapi'); + + +/* Set the user path according to application's name. */ + +app.setPath('userData', path.join(app.getPath('appData'), app.getName())); + +app.setPath('userCache', path.join(app.getPath('cache'), app.getName())); + +app.setAppPath(packagePath); + + +/* Load the chrome extension support. */ + +require('./chrome-extension'); + + +/* Load internal desktop-capturer module. */ + +require('./desktop-capturer'); + + +/* Set main startup script of the app. */ + +mainStartupScript = packageJson.main || 'index.js'; + + +/* Finally load app's main.js and transfer control to C++. */ + +Module._load(path.join(packagePath, mainStartupScript), Module, true); diff --git a/atom/browser/lib/objects-registry.coffee b/atom/browser/lib/objects-registry.coffee deleted file mode 100644 index 661ee4958a1b..000000000000 --- a/atom/browser/lib/objects-registry.coffee +++ /dev/null @@ -1,73 +0,0 @@ -{EventEmitter} = require 'events' -v8Util = process.atomBinding 'v8_util' - -class ObjectsRegistry extends EventEmitter - constructor: -> - @setMaxListeners Number.MAX_VALUE - @nextId = 0 - - ### - Stores all objects by ref-counting. - (id) => {object, count} - ### - @storage = {} - - ### - Stores the IDs of objects referenced by WebContents. - (webContentsId) => {(id) => (count)} - ### - @owners = {} - - ### - Register a new object, the object would be kept referenced until you release - it explicitly. - ### - add: (webContentsId, obj) -> - id = @saveToStorage obj - ### Remember the owner. ### - @owners[webContentsId] ?= {} - @owners[webContentsId][id] ?= 0 - @owners[webContentsId][id]++ - ### Returns object's id ### - id - - ### Get an object according to its ID. ### - get: (id) -> - @storage[id]?.object - - ### Dereference an object according to its ID. ### - remove: (webContentsId, id) -> - @dereference id, 1 - ### Also reduce the count in owner. ### - pointer = @owners[webContentsId] - return unless pointer? - --pointer[id] - delete pointer[id] if pointer[id] is 0 - - ### Clear all references to objects refrenced by the WebContents. ### - clear: (webContentsId) -> - @emit "clear-#{webContentsId}" - return unless @owners[webContentsId]? - @dereference id, count for id, count of @owners[webContentsId] - delete @owners[webContentsId] - - ### Private: Saves the object into storage and assigns an ID for it. ### - saveToStorage: (object) -> - id = v8Util.getHiddenValue object, 'atomId' - unless id - id = ++@nextId - @storage[id] = {count: 0, object} - v8Util.setHiddenValue object, 'atomId', id - ++@storage[id].count - id - - ### Private: Dereference the object from store. ### - dereference: (id, count) -> - pointer = @storage[id] - return unless pointer? - pointer.count -= count - if pointer.count is 0 - v8Util.deleteHiddenValue pointer.object, 'atomId' - delete @storage[id] - -module.exports = new ObjectsRegistry diff --git a/atom/browser/lib/objects-registry.js b/atom/browser/lib/objects-registry.js new file mode 100644 index 000000000000..81fe1c2398f1 --- /dev/null +++ b/atom/browser/lib/objects-registry.js @@ -0,0 +1,133 @@ +var EventEmitter, ObjectsRegistry, v8Util, + extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }, + hasProp = {}.hasOwnProperty; + +EventEmitter = require('events').EventEmitter; + +v8Util = process.atomBinding('v8_util'); + +ObjectsRegistry = (function(superClass) { + extend(ObjectsRegistry, superClass); + + function ObjectsRegistry() { + this.setMaxListeners(Number.MAX_VALUE); + this.nextId = 0; + + /* + Stores all objects by ref-counting. + (id) => {object, count} + */ + this.storage = {}; + + /* + Stores the IDs of objects referenced by WebContents. + (webContentsId) => {(id) => (count)} + */ + this.owners = {}; + } + + + /* + Register a new object, the object would be kept referenced until you release + it explicitly. + */ + + ObjectsRegistry.prototype.add = function(webContentsId, obj) { + var base, base1, id; + id = this.saveToStorage(obj); + + /* Remember the owner. */ + if ((base = this.owners)[webContentsId] == null) { + base[webContentsId] = {}; + } + if ((base1 = this.owners[webContentsId])[id] == null) { + base1[id] = 0; + } + this.owners[webContentsId][id]++; + + /* Returns object's id */ + return id; + }; + + + /* Get an object according to its ID. */ + + ObjectsRegistry.prototype.get = function(id) { + var ref; + return (ref = this.storage[id]) != null ? ref.object : void 0; + }; + + + /* Dereference an object according to its ID. */ + + ObjectsRegistry.prototype.remove = function(webContentsId, id) { + var pointer; + this.dereference(id, 1); + + /* Also reduce the count in owner. */ + pointer = this.owners[webContentsId]; + if (pointer == null) { + return; + } + --pointer[id]; + if (pointer[id] === 0) { + return delete pointer[id]; + } + }; + + + /* Clear all references to objects refrenced by the WebContents. */ + + ObjectsRegistry.prototype.clear = function(webContentsId) { + var count, id, ref; + this.emit("clear-" + webContentsId); + if (this.owners[webContentsId] == null) { + return; + } + ref = this.owners[webContentsId]; + for (id in ref) { + count = ref[id]; + this.dereference(id, count); + } + return delete this.owners[webContentsId]; + }; + + + /* Private: Saves the object into storage and assigns an ID for it. */ + + ObjectsRegistry.prototype.saveToStorage = function(object) { + var id; + id = v8Util.getHiddenValue(object, 'atomId'); + if (!id) { + id = ++this.nextId; + this.storage[id] = { + count: 0, + object: object + }; + v8Util.setHiddenValue(object, 'atomId', id); + } + ++this.storage[id].count; + return id; + }; + + + /* Private: Dereference the object from store. */ + + ObjectsRegistry.prototype.dereference = function(id, count) { + var pointer; + pointer = this.storage[id]; + if (pointer == null) { + return; + } + pointer.count -= count; + if (pointer.count === 0) { + v8Util.deleteHiddenValue(pointer.object, 'atomId'); + return delete this.storage[id]; + } + }; + + return ObjectsRegistry; + +})(EventEmitter); + +module.exports = new ObjectsRegistry; diff --git a/atom/browser/lib/rpc-server.coffee b/atom/browser/lib/rpc-server.coffee deleted file mode 100644 index 7880c6ce4a33..000000000000 --- a/atom/browser/lib/rpc-server.coffee +++ /dev/null @@ -1,239 +0,0 @@ -path = require 'path' - -electron = require 'electron' -{ipcMain} = electron -objectsRegistry = require './objects-registry' - -v8Util = process.atomBinding 'v8_util' -{IDWeakMap} = process.atomBinding 'id_weak_map' - -### Convert a real value into meta data. ### -valueToMeta = (sender, value, optimizeSimpleObject=false) -> - meta = type: typeof value - - meta.type = 'buffer' if Buffer.isBuffer value - meta.type = 'value' if value is null - meta.type = 'array' if Array.isArray value - meta.type = 'error' if value instanceof Error - meta.type = 'date' if value instanceof Date - meta.type = 'promise' if value?.constructor.name is 'Promise' - - ### Treat simple objects as value. ### - if optimizeSimpleObject and meta.type is 'object' and v8Util.getHiddenValue value, 'simple' - meta.type = 'value' - - ### Treat the arguments object as array. ### - meta.type = 'array' if meta.type is 'object' and value.callee? and value.length? - - if meta.type is 'array' - meta.members = [] - meta.members.push valueToMeta(sender, el) for el in value - else if meta.type is 'object' or meta.type is 'function' - meta.name = value.constructor.name - - ### - Reference the original value if it's an object, because when it's - passed to renderer we would assume the renderer keeps a reference of - it. - ### - meta.id = objectsRegistry.add sender.getId(), value - - meta.members = ({name, type: typeof field} for name, field of value) - else if meta.type is 'buffer' - meta.value = Array::slice.call value, 0 - else if meta.type is 'promise' - meta.then = valueToMeta sender, value.then.bind(value) - else if meta.type is 'error' - meta.members = plainObjectToMeta value - ### Error.name is not part of own properties. ### - meta.members.push {name: 'name', value: value.name} - else if meta.type is 'date' - meta.value = value.getTime() - else - meta.type = 'value' - meta.value = value - - meta - -### Convert object to meta by value. ### -plainObjectToMeta = (obj) -> - Object.getOwnPropertyNames(obj).map (name) -> {name, value: obj[name]} - -### Convert Error into meta data. ### -exceptionToMeta = (error) -> - type: 'exception', message: error.message, stack: (error.stack || error) - -### Convert array of meta data from renderer into array of real values. ### -unwrapArgs = (sender, args) -> - metaToValue = (meta) -> - switch meta.type - when 'value' then meta.value - when 'remote-object' then objectsRegistry.get meta.id - when 'array' then unwrapArgs sender, meta.value - when 'buffer' then new Buffer(meta.value) - when 'date' then new Date(meta.value) - when 'promise' then Promise.resolve(then: metaToValue(meta.then)) - when 'object' - ret = v8Util.createObjectWithName meta.name - for member in meta.members - ret[member.name] = metaToValue(member.value) - ret - when 'function-with-return-value' - returnValue = metaToValue meta.value - -> returnValue - when 'function' - ### Cache the callbacks in renderer. ### - unless sender.callbacks - sender.callbacks = new IDWeakMap - sender.on 'render-view-deleted', -> - sender.callbacks.clear() - return sender.callbacks.get meta.id if sender.callbacks.has meta.id - - rendererReleased = false - objectsRegistry.once "clear-#{sender.getId()}", -> - rendererReleased = true - - ret = -> - if rendererReleased - throw new Error("Attempting to call a function in a renderer window - that has been closed or released. Function provided here: #{meta.location}.") - sender.send 'ATOM_RENDERER_CALLBACK', meta.id, valueToMeta(sender, arguments) - v8Util.setDestructor ret, -> - return if rendererReleased - sender.callbacks.remove meta.id - sender.send 'ATOM_RENDERER_RELEASE_CALLBACK', meta.id - sender.callbacks.set meta.id, ret - ret - else throw new TypeError("Unknown type: #{meta.type}") - - args.map metaToValue - -### - Call a function and send reply asynchronously if it's a an asynchronous - style function and the caller didn't pass a callback. -### -callFunction = (event, func, caller, args) -> - funcMarkedAsync = v8Util.getHiddenValue(func, 'asynchronous') - funcPassedCallback = typeof args[args.length - 1] is 'function' - - try - if funcMarkedAsync and not funcPassedCallback - args.push (ret) -> - event.returnValue = valueToMeta event.sender, ret, true - func.apply caller, args - else - ret = func.apply caller, args - event.returnValue = valueToMeta event.sender, ret, true - catch e - ### - Catch functions thrown further down in function invocation and wrap - them with the function name so it's easier to trace things like - `Error processing argument -1.` - ### - funcName = func.name ? "anonymous" - throw new Error("Could not call remote function `#{funcName}`. - Check that the function signature is correct. - Underlying error: #{e.message}") - -### Send by BrowserWindow when its render view is deleted. ### -process.on 'ATOM_BROWSER_RELEASE_RENDER_VIEW', (id) -> - objectsRegistry.clear id - -ipcMain.on 'ATOM_BROWSER_REQUIRE', (event, module) -> - try - event.returnValue = valueToMeta event.sender, process.mainModule.require(module) - catch e - event.returnValue = exceptionToMeta e - -ipcMain.on 'ATOM_BROWSER_GET_BUILTIN', (event, module) -> - try - event.returnValue = valueToMeta event.sender, electron[module] - catch e - event.returnValue = exceptionToMeta e - -ipcMain.on 'ATOM_BROWSER_GLOBAL', (event, name) -> - try - event.returnValue = valueToMeta event.sender, global[name] - catch e - event.returnValue = exceptionToMeta e - -ipcMain.on 'ATOM_BROWSER_CURRENT_WINDOW', (event) -> - try - event.returnValue = valueToMeta event.sender, event.sender.getOwnerBrowserWindow() - catch e - event.returnValue = exceptionToMeta e - -ipcMain.on 'ATOM_BROWSER_CURRENT_WEB_CONTENTS', (event) -> - event.returnValue = valueToMeta event.sender, event.sender - -ipcMain.on 'ATOM_BROWSER_CONSTRUCTOR', (event, id, args) -> - try - args = unwrapArgs event.sender, args - constructor = objectsRegistry.get id - ### - Call new with array of arguments. - http://stackoverflow.com/questions/1606797/use-of-apply-with-new-operator-is-this-possible - ### - obj = new (Function::bind.apply(constructor, [null].concat(args))) - event.returnValue = valueToMeta event.sender, obj - catch e - event.returnValue = exceptionToMeta e - -ipcMain.on 'ATOM_BROWSER_FUNCTION_CALL', (event, id, args) -> - try - args = unwrapArgs event.sender, args - func = objectsRegistry.get id - callFunction event, func, global, args - catch e - event.returnValue = exceptionToMeta e - -ipcMain.on 'ATOM_BROWSER_MEMBER_CONSTRUCTOR', (event, id, method, args) -> - try - args = unwrapArgs event.sender, args - constructor = objectsRegistry.get(id)[method] - ### Call new with array of arguments. ### - obj = new (Function::bind.apply(constructor, [null].concat(args))) - event.returnValue = valueToMeta event.sender, obj - catch e - event.returnValue = exceptionToMeta e - -ipcMain.on 'ATOM_BROWSER_MEMBER_CALL', (event, id, method, args) -> - try - args = unwrapArgs event.sender, args - obj = objectsRegistry.get id - callFunction event, obj[method], obj, args - catch e - event.returnValue = exceptionToMeta e - -ipcMain.on 'ATOM_BROWSER_MEMBER_SET', (event, id, name, value) -> - try - obj = objectsRegistry.get id - obj[name] = value - event.returnValue = null - catch e - event.returnValue = exceptionToMeta e - -ipcMain.on 'ATOM_BROWSER_MEMBER_GET', (event, id, name) -> - try - obj = objectsRegistry.get id - event.returnValue = valueToMeta event.sender, obj[name] - catch e - event.returnValue = exceptionToMeta e - -ipcMain.on 'ATOM_BROWSER_DEREFERENCE', (event, id) -> - objectsRegistry.remove event.sender.getId(), id - -ipcMain.on 'ATOM_BROWSER_GUEST_WEB_CONTENTS', (event, guestInstanceId) -> - try - guestViewManager = require './guest-view-manager' - event.returnValue = valueToMeta event.sender, guestViewManager.getGuest(guestInstanceId) - catch e - event.returnValue = exceptionToMeta e - -ipcMain.on 'ATOM_BROWSER_ASYNC_CALL_TO_GUEST_VIEW', (event, guestInstanceId, method, args...) -> - try - guestViewManager = require './guest-view-manager' - guest = guestViewManager.getGuest(guestInstanceId) - guest[method].apply(guest, args) - catch e - event.returnValue = exceptionToMeta e diff --git a/atom/browser/lib/rpc-server.js b/atom/browser/lib/rpc-server.js new file mode 100644 index 000000000000..426ebe4a3906 --- /dev/null +++ b/atom/browser/lib/rpc-server.js @@ -0,0 +1,389 @@ +var IDWeakMap, callFunction, electron, exceptionToMeta, ipcMain, objectsRegistry, path, plainObjectToMeta, unwrapArgs, v8Util, valueToMeta, + slice = [].slice; + +path = require('path'); + +electron = require('electron'); + +ipcMain = electron.ipcMain; + +objectsRegistry = require('./objects-registry'); + +v8Util = process.atomBinding('v8_util'); + +IDWeakMap = process.atomBinding('id_weak_map').IDWeakMap; + + +/* Convert a real value into meta data. */ + +valueToMeta = function(sender, value, optimizeSimpleObject) { + var el, field, i, len, meta, name; + if (optimizeSimpleObject == null) { + optimizeSimpleObject = false; + } + meta = { + type: typeof value + }; + if (Buffer.isBuffer(value)) { + meta.type = 'buffer'; + } + if (value === null) { + meta.type = 'value'; + } + if (Array.isArray(value)) { + meta.type = 'array'; + } + if (value instanceof Error) { + meta.type = 'error'; + } + if (value instanceof Date) { + meta.type = 'date'; + } + if ((value != null ? value.constructor.name : void 0) === 'Promise') { + meta.type = 'promise'; + } + + /* Treat simple objects as value. */ + if (optimizeSimpleObject && meta.type === 'object' && v8Util.getHiddenValue(value, 'simple')) { + meta.type = 'value'; + } + + /* Treat the arguments object as array. */ + if (meta.type === 'object' && (value.callee != null) && (value.length != null)) { + meta.type = 'array'; + } + if (meta.type === 'array') { + meta.members = []; + for (i = 0, len = value.length; i < len; i++) { + el = value[i]; + meta.members.push(valueToMeta(sender, el)); + } + } else if (meta.type === 'object' || meta.type === 'function') { + meta.name = value.constructor.name; + + /* + Reference the original value if it's an object, because when it's + passed to renderer we would assume the renderer keeps a reference of + it. + */ + meta.id = objectsRegistry.add(sender.getId(), value); + meta.members = (function() { + var results; + results = []; + for (name in value) { + field = value[name]; + results.push({ + name: name, + type: typeof field + }); + } + return results; + })(); + } else if (meta.type === 'buffer') { + meta.value = Array.prototype.slice.call(value, 0); + } else if (meta.type === 'promise') { + meta.then = valueToMeta(sender, value.then.bind(value)); + } else if (meta.type === 'error') { + meta.members = plainObjectToMeta(value); + + /* Error.name is not part of own properties. */ + meta.members.push({ + name: 'name', + value: value.name + }); + } else if (meta.type === 'date') { + meta.value = value.getTime(); + } else { + meta.type = 'value'; + meta.value = value; + } + return meta; +}; + + +/* Convert object to meta by value. */ + +plainObjectToMeta = function(obj) { + return Object.getOwnPropertyNames(obj).map(function(name) { + return { + name: name, + value: obj[name] + }; + }); +}; + + +/* Convert Error into meta data. */ + +exceptionToMeta = function(error) { + return { + type: 'exception', + message: error.message, + stack: error.stack || error + }; +}; + + +/* Convert array of meta data from renderer into array of real values. */ + +unwrapArgs = function(sender, args) { + var metaToValue; + metaToValue = function(meta) { + var i, len, member, ref, rendererReleased, ret, returnValue; + switch (meta.type) { + case 'value': + return meta.value; + case 'remote-object': + return objectsRegistry.get(meta.id); + case 'array': + return unwrapArgs(sender, meta.value); + case 'buffer': + return new Buffer(meta.value); + case 'date': + return new Date(meta.value); + case 'promise': + return Promise.resolve({ + then: metaToValue(meta.then) + }); + case 'object': + ret = v8Util.createObjectWithName(meta.name); + ref = meta.members; + for (i = 0, len = ref.length; i < len; i++) { + member = ref[i]; + ret[member.name] = metaToValue(member.value); + } + return ret; + case 'function-with-return-value': + returnValue = metaToValue(meta.value); + return function() { + return returnValue; + }; + case 'function': + + /* Cache the callbacks in renderer. */ + if (!sender.callbacks) { + sender.callbacks = new IDWeakMap; + sender.on('render-view-deleted', function() { + return sender.callbacks.clear(); + }); + } + if (sender.callbacks.has(meta.id)) { + return sender.callbacks.get(meta.id); + } + rendererReleased = false; + objectsRegistry.once("clear-" + (sender.getId()), function() { + return rendererReleased = true; + }); + ret = function() { + if (rendererReleased) { + throw new Error("Attempting to call a function in a renderer window that has been closed or released. Function provided here: " + meta.location + "."); + } + return sender.send('ATOM_RENDERER_CALLBACK', meta.id, valueToMeta(sender, arguments)); + }; + v8Util.setDestructor(ret, function() { + if (rendererReleased) { + return; + } + sender.callbacks.remove(meta.id); + return sender.send('ATOM_RENDERER_RELEASE_CALLBACK', meta.id); + }); + sender.callbacks.set(meta.id, ret); + return ret; + default: + throw new TypeError("Unknown type: " + meta.type); + } + }; + return args.map(metaToValue); +}; + + +/* + Call a function and send reply asynchronously if it's a an asynchronous + style function and the caller didn't pass a callback. + */ + +callFunction = function(event, func, caller, args) { + var e, error1, funcMarkedAsync, funcName, funcPassedCallback, ref, ret; + funcMarkedAsync = v8Util.getHiddenValue(func, 'asynchronous'); + funcPassedCallback = typeof args[args.length - 1] === 'function'; + try { + if (funcMarkedAsync && !funcPassedCallback) { + args.push(function(ret) { + return event.returnValue = valueToMeta(event.sender, ret, true); + }); + return func.apply(caller, args); + } else { + ret = func.apply(caller, args); + return event.returnValue = valueToMeta(event.sender, ret, true); + } + } catch (error1) { + e = error1; + + /* + Catch functions thrown further down in function invocation and wrap + them with the function name so it's easier to trace things like + `Error processing argument -1.` + */ + funcName = (ref = func.name) != null ? ref : "anonymous"; + throw new Error("Could not call remote function `" + funcName + "`. Check that the function signature is correct. Underlying error: " + e.message); + } +}; + + +/* Send by BrowserWindow when its render view is deleted. */ + +process.on('ATOM_BROWSER_RELEASE_RENDER_VIEW', function(id) { + return objectsRegistry.clear(id); +}); + +ipcMain.on('ATOM_BROWSER_REQUIRE', function(event, module) { + var e, error1; + try { + return event.returnValue = valueToMeta(event.sender, process.mainModule.require(module)); + } catch (error1) { + e = error1; + return event.returnValue = exceptionToMeta(e); + } +}); + +ipcMain.on('ATOM_BROWSER_GET_BUILTIN', function(event, module) { + var e, error1; + try { + return event.returnValue = valueToMeta(event.sender, electron[module]); + } catch (error1) { + e = error1; + return event.returnValue = exceptionToMeta(e); + } +}); + +ipcMain.on('ATOM_BROWSER_GLOBAL', function(event, name) { + var e, error1; + try { + return event.returnValue = valueToMeta(event.sender, global[name]); + } catch (error1) { + e = error1; + return event.returnValue = exceptionToMeta(e); + } +}); + +ipcMain.on('ATOM_BROWSER_CURRENT_WINDOW', function(event) { + var e, error1; + try { + return event.returnValue = valueToMeta(event.sender, event.sender.getOwnerBrowserWindow()); + } catch (error1) { + e = error1; + return event.returnValue = exceptionToMeta(e); + } +}); + +ipcMain.on('ATOM_BROWSER_CURRENT_WEB_CONTENTS', function(event) { + return event.returnValue = valueToMeta(event.sender, event.sender); +}); + +ipcMain.on('ATOM_BROWSER_CONSTRUCTOR', function(event, id, args) { + var constructor, e, error1, obj; + try { + args = unwrapArgs(event.sender, args); + constructor = objectsRegistry.get(id); + + /* + Call new with array of arguments. + http://stackoverflow.com/questions/1606797/use-of-apply-with-new-operator-is-this-possible + */ + obj = new (Function.prototype.bind.apply(constructor, [null].concat(args))); + return event.returnValue = valueToMeta(event.sender, obj); + } catch (error1) { + e = error1; + return event.returnValue = exceptionToMeta(e); + } +}); + +ipcMain.on('ATOM_BROWSER_FUNCTION_CALL', function(event, id, args) { + var e, error1, func; + try { + args = unwrapArgs(event.sender, args); + func = objectsRegistry.get(id); + return callFunction(event, func, global, args); + } catch (error1) { + e = error1; + return event.returnValue = exceptionToMeta(e); + } +}); + +ipcMain.on('ATOM_BROWSER_MEMBER_CONSTRUCTOR', function(event, id, method, args) { + var constructor, e, error1, obj; + try { + args = unwrapArgs(event.sender, args); + constructor = objectsRegistry.get(id)[method]; + + /* Call new with array of arguments. */ + obj = new (Function.prototype.bind.apply(constructor, [null].concat(args))); + return event.returnValue = valueToMeta(event.sender, obj); + } catch (error1) { + e = error1; + return event.returnValue = exceptionToMeta(e); + } +}); + +ipcMain.on('ATOM_BROWSER_MEMBER_CALL', function(event, id, method, args) { + var e, error1, obj; + try { + args = unwrapArgs(event.sender, args); + obj = objectsRegistry.get(id); + return callFunction(event, obj[method], obj, args); + } catch (error1) { + e = error1; + return event.returnValue = exceptionToMeta(e); + } +}); + +ipcMain.on('ATOM_BROWSER_MEMBER_SET', function(event, id, name, value) { + var e, error1, obj; + try { + obj = objectsRegistry.get(id); + obj[name] = value; + return event.returnValue = null; + } catch (error1) { + e = error1; + return event.returnValue = exceptionToMeta(e); + } +}); + +ipcMain.on('ATOM_BROWSER_MEMBER_GET', function(event, id, name) { + var e, error1, obj; + try { + obj = objectsRegistry.get(id); + return event.returnValue = valueToMeta(event.sender, obj[name]); + } catch (error1) { + e = error1; + return event.returnValue = exceptionToMeta(e); + } +}); + +ipcMain.on('ATOM_BROWSER_DEREFERENCE', function(event, id) { + return objectsRegistry.remove(event.sender.getId(), id); +}); + +ipcMain.on('ATOM_BROWSER_GUEST_WEB_CONTENTS', function(event, guestInstanceId) { + var e, error1, guestViewManager; + try { + guestViewManager = require('./guest-view-manager'); + return event.returnValue = valueToMeta(event.sender, guestViewManager.getGuest(guestInstanceId)); + } catch (error1) { + e = error1; + return event.returnValue = exceptionToMeta(e); + } +}); + +ipcMain.on('ATOM_BROWSER_ASYNC_CALL_TO_GUEST_VIEW', function() { + var args, e, error1, event, guest, guestInstanceId, guestViewManager, method; + event = arguments[0], guestInstanceId = arguments[1], method = arguments[2], args = 4 <= arguments.length ? slice.call(arguments, 3) : []; + try { + guestViewManager = require('./guest-view-manager'); + guest = guestViewManager.getGuest(guestInstanceId); + return guest[method].apply(guest, args); + } catch (error1) { + e = error1; + return event.returnValue = exceptionToMeta(e); + } +}); diff --git a/atom/common/api/lib/callbacks-registry.coffee b/atom/common/api/lib/callbacks-registry.coffee deleted file mode 100644 index 04eafc64bb8b..000000000000 --- a/atom/common/api/lib/callbacks-registry.coffee +++ /dev/null @@ -1,45 +0,0 @@ -v8Util = process.atomBinding 'v8_util' - -module.exports = -class CallbacksRegistry - constructor: -> - @nextId = 0 - @callbacks = {} - - add: (callback) -> - ### The callback is already added. ### - id = v8Util.getHiddenValue callback, 'callbackId' - return id if id? - - id = ++@nextId - - ### - Capture the location of the function and put it in the ID string, - so that release errors can be tracked down easily. - ### - regexp = /at (.*)/gi - stackString = (new Error).stack - - while (match = regexp.exec(stackString)) isnt null - [x, location] = match - continue if location.indexOf('(native)') isnt -1 - continue if location.indexOf('atom.asar') isnt -1 - [x, filenameAndLine] = /([^/^\)]*)\)?$/gi.exec(location) - break - - @callbacks[id] = callback - v8Util.setHiddenValue callback, 'callbackId', id - v8Util.setHiddenValue callback, 'location', filenameAndLine - id - - get: (id) -> - @callbacks[id] ? -> - - call: (id, args...) -> - @get(id).call global, args... - - apply: (id, args...) -> - @get(id).apply global, args... - - remove: (id) -> - delete @callbacks[id] diff --git a/atom/common/api/lib/callbacks-registry.js b/atom/common/api/lib/callbacks-registry.js new file mode 100644 index 000000000000..1b93bf128e1f --- /dev/null +++ b/atom/common/api/lib/callbacks-registry.js @@ -0,0 +1,68 @@ +var CallbacksRegistry, v8Util, + slice = [].slice; + +v8Util = process.atomBinding('v8_util'); + +module.exports = CallbacksRegistry = (function() { + function CallbacksRegistry() { + this.nextId = 0; + this.callbacks = {}; + } + + CallbacksRegistry.prototype.add = function(callback) { + + /* The callback is already added. */ + var filenameAndLine, id, location, match, ref, regexp, stackString, x; + id = v8Util.getHiddenValue(callback, 'callbackId'); + if (id != null) { + return id; + } + id = ++this.nextId; + + /* + Capture the location of the function and put it in the ID string, + so that release errors can be tracked down easily. + */ + regexp = /at (.*)/gi; + stackString = (new Error).stack; + while ((match = regexp.exec(stackString)) !== null) { + x = match[0], location = match[1]; + if (location.indexOf('(native)') !== -1) { + continue; + } + if (location.indexOf('atom.asar') !== -1) { + continue; + } + ref = /([^\/^\)]*)\)?$/gi.exec(location), x = ref[0], filenameAndLine = ref[1]; + break; + } + this.callbacks[id] = callback; + v8Util.setHiddenValue(callback, 'callbackId', id); + v8Util.setHiddenValue(callback, 'location', filenameAndLine); + return id; + }; + + CallbacksRegistry.prototype.get = function(id) { + var ref; + return (ref = this.callbacks[id]) != null ? ref : function() {}; + }; + + CallbacksRegistry.prototype.call = function() { + var args, id, ref; + id = arguments[0], args = 2 <= arguments.length ? slice.call(arguments, 1) : []; + return (ref = this.get(id)).call.apply(ref, [global].concat(slice.call(args))); + }; + + CallbacksRegistry.prototype.apply = function() { + var args, id, ref; + id = arguments[0], args = 2 <= arguments.length ? slice.call(arguments, 1) : []; + return (ref = this.get(id)).apply.apply(ref, [global].concat(slice.call(args))); + }; + + CallbacksRegistry.prototype.remove = function(id) { + return delete this.callbacks[id]; + }; + + return CallbacksRegistry; + +})(); diff --git a/atom/common/api/lib/clipboard.coffee b/atom/common/api/lib/clipboard.coffee deleted file mode 100644 index 47ee8abc7f7b..000000000000 --- a/atom/common/api/lib/clipboard.coffee +++ /dev/null @@ -1,5 +0,0 @@ -if process.platform is 'linux' and process.type is 'renderer' - ### On Linux we could not access clipboard in renderer process. ### - module.exports = require('electron').remote.clipboard -else - module.exports = process.atomBinding 'clipboard' diff --git a/atom/common/api/lib/clipboard.js b/atom/common/api/lib/clipboard.js new file mode 100644 index 000000000000..4e7a668167e8 --- /dev/null +++ b/atom/common/api/lib/clipboard.js @@ -0,0 +1,7 @@ +if (process.platform === 'linux' && process.type === 'renderer') { + + /* On Linux we could not access clipboard in renderer process. */ + module.exports = require('electron').remote.clipboard; +} else { + module.exports = process.atomBinding('clipboard'); +} diff --git a/atom/common/api/lib/crash-reporter.coffee b/atom/common/api/lib/crash-reporter.coffee deleted file mode 100644 index af62dfd2f9df..000000000000 --- a/atom/common/api/lib/crash-reporter.coffee +++ /dev/null @@ -1,69 +0,0 @@ -fs = require 'fs' -os = require 'os' -path = require 'path' -{spawn} = require 'child_process' - -electron = require 'electron' -binding = process.atomBinding 'crash_reporter' - -class CrashReporter - start: (options={}) -> - {@productName, companyName, submitURL, autoSubmit, ignoreSystemCrashHandler, extra} = options - - ### Deprecated. ### - {deprecate} = electron - if options.submitUrl - submitURL ?= options.submitUrl - deprecate.warn 'submitUrl', 'submitURL' - - {app} = if process.type is 'browser' then electron else electron.remote - - @productName ?= app.getName() - autoSubmit ?= true - ignoreSystemCrashHandler ?= false - extra ?= {} - - extra._productName ?= @productName - extra._companyName ?= companyName - extra._version ?= app.getVersion() - - unless companyName? - deprecate.log('companyName is now a required option to crashReporter.start') - return - - unless submitURL? - deprecate.log('submitURL is now a required option to crashReporter.start') - return - - start = => binding.start @productName, companyName, submitURL, autoSubmit, ignoreSystemCrashHandler, extra - - if process.platform is 'win32' - args = [ - "--reporter-url=#{submitURL}" - "--application-name=#{@productName}" - "--v=1" - ] - env = ATOM_SHELL_INTERNAL_CRASH_SERVICE: 1 - - spawn process.execPath, args, {env, detached: true} - start() - - getLastCrashReport: -> - reports = this.getUploadedReports() - if reports.length > 0 then reports[0] else null - - getUploadedReports: -> - tmpdir = - if process.platform is 'win32' - os.tmpdir() - else - '/tmp' - log = - if process.platform is 'darwin' - path.join tmpdir, "#{@productName} Crashes" - else - path.join tmpdir, "#{@productName} Crashes", 'uploads.log' - binding._getUploadedReports log - -crashRepoter = new CrashReporter -module.exports = crashRepoter diff --git a/atom/common/api/lib/crash-reporter.js b/atom/common/api/lib/crash-reporter.js new file mode 100644 index 000000000000..75a60a1a998a --- /dev/null +++ b/atom/common/api/lib/crash-reporter.js @@ -0,0 +1,104 @@ +var CrashReporter, binding, crashRepoter, electron, fs, os, path, spawn; + +fs = require('fs'); + +os = require('os'); + +path = require('path'); + +spawn = require('child_process').spawn; + +electron = require('electron'); + +binding = process.atomBinding('crash_reporter'); + +CrashReporter = (function() { + function CrashReporter() {} + + CrashReporter.prototype.start = function(options) { + var app, args, autoSubmit, companyName, deprecate, env, extra, ignoreSystemCrashHandler, start, submitURL; + if (options == null) { + options = {}; + } + this.productName = options.productName, companyName = options.companyName, submitURL = options.submitURL, autoSubmit = options.autoSubmit, ignoreSystemCrashHandler = options.ignoreSystemCrashHandler, extra = options.extra; + + /* Deprecated. */ + deprecate = electron.deprecate; + if (options.submitUrl) { + if (submitURL == null) { + submitURL = options.submitUrl; + } + deprecate.warn('submitUrl', 'submitURL'); + } + app = (process.type === 'browser' ? electron : electron.remote).app; + if (this.productName == null) { + this.productName = app.getName(); + } + if (autoSubmit == null) { + autoSubmit = true; + } + if (ignoreSystemCrashHandler == null) { + ignoreSystemCrashHandler = false; + } + if (extra == null) { + extra = {}; + } + if (extra._productName == null) { + extra._productName = this.productName; + } + if (extra._companyName == null) { + extra._companyName = companyName; + } + if (extra._version == null) { + extra._version = app.getVersion(); + } + if (companyName == null) { + deprecate.log('companyName is now a required option to crashReporter.start'); + return; + } + if (submitURL == null) { + deprecate.log('submitURL is now a required option to crashReporter.start'); + return; + } + start = (function(_this) { + return function() { + return binding.start(_this.productName, companyName, submitURL, autoSubmit, ignoreSystemCrashHandler, extra); + }; + })(this); + if (process.platform === 'win32') { + args = ["--reporter-url=" + submitURL, "--application-name=" + this.productName, "--v=1"]; + env = { + ATOM_SHELL_INTERNAL_CRASH_SERVICE: 1 + }; + spawn(process.execPath, args, { + env: env, + detached: true + }); + } + return start(); + }; + + CrashReporter.prototype.getLastCrashReport = function() { + var reports; + reports = this.getUploadedReports(); + if (reports.length > 0) { + return reports[0]; + } else { + return null; + } + }; + + CrashReporter.prototype.getUploadedReports = function() { + var log, tmpdir; + tmpdir = process.platform === 'win32' ? os.tmpdir() : '/tmp'; + log = process.platform === 'darwin' ? path.join(tmpdir, this.productName + " Crashes") : path.join(tmpdir, this.productName + " Crashes", 'uploads.log'); + return binding._getUploadedReports(log); + }; + + return CrashReporter; + +})(); + +crashRepoter = new CrashReporter; + +module.exports = crashRepoter; diff --git a/atom/common/api/lib/deprecate.coffee b/atom/common/api/lib/deprecate.coffee deleted file mode 100644 index 7c03fc6f595d..000000000000 --- a/atom/common/api/lib/deprecate.coffee +++ /dev/null @@ -1,69 +0,0 @@ -### Deprecate a method. ### -deprecate = (oldName, newName, fn) -> - warned = false - -> - unless warned or process.noDeprecation - warned = true - deprecate.warn oldName, newName - fn.apply this, arguments - -### The method is renamed. ### -deprecate.rename = (object, oldName, newName) -> - warned = false - newMethod = -> - unless warned or process.noDeprecation - warned = true - deprecate.warn oldName, newName - this[newName].apply this, arguments - if typeof object is 'function' - object.prototype[oldName] = newMethod - else - object[oldName] = newMethod - -### Forward the method to member. ### -deprecate.member = (object, method, member) -> - warned = false - object.prototype[method] = -> - unless warned or process.noDeprecation - warned = true - deprecate.warn method, "#{member}.#{method}" - this[member][method].apply this[member], arguments - -### Deprecate a property. ### -deprecate.property = (object, property, method) -> - Object.defineProperty object, property, - get: -> - warned = false - unless warned or process.noDeprecation - warned = true - deprecate.warn "#{property} property", "#{method} method" - this[method]() - -### Deprecate an event. ### -deprecate.event = (emitter, oldName, newName, fn) -> - warned = false - emitter.on newName, (args...) -> - ### there is listeners for old API. ### - if @listenerCount(oldName) > 0 - unless warned or process.noDeprecation - warned = true - deprecate.warn "'#{oldName}' event", "'#{newName}' event" - if fn? - fn.apply this, arguments - else - @emit oldName, args... - -### Print deprecation warning. ### -deprecate.warn = (oldName, newName) -> - deprecate.log "#{oldName} is deprecated. Use #{newName} instead." - -### Print deprecation message. ### -deprecate.log = (message) -> - if process.throwDeprecation - throw new Error(message) - else if process.traceDeprecation - console.trace message - else - console.warn "(electron) #{message}" - -module.exports = deprecate diff --git a/atom/common/api/lib/deprecate.js b/atom/common/api/lib/deprecate.js new file mode 100644 index 000000000000..be04b1fe18a0 --- /dev/null +++ b/atom/common/api/lib/deprecate.js @@ -0,0 +1,115 @@ + +/* Deprecate a method. */ +var deprecate, + slice = [].slice; + +deprecate = function(oldName, newName, fn) { + var warned; + warned = false; + return function() { + if (!(warned || process.noDeprecation)) { + warned = true; + deprecate.warn(oldName, newName); + } + return fn.apply(this, arguments); + }; +}; + + +/* The method is renamed. */ + +deprecate.rename = function(object, oldName, newName) { + var newMethod, warned; + warned = false; + newMethod = function() { + if (!(warned || process.noDeprecation)) { + warned = true; + deprecate.warn(oldName, newName); + } + return this[newName].apply(this, arguments); + }; + if (typeof object === 'function') { + return object.prototype[oldName] = newMethod; + } else { + return object[oldName] = newMethod; + } +}; + + +/* Forward the method to member. */ + +deprecate.member = function(object, method, member) { + var warned; + warned = false; + return object.prototype[method] = function() { + if (!(warned || process.noDeprecation)) { + warned = true; + deprecate.warn(method, member + "." + method); + } + return this[member][method].apply(this[member], arguments); + }; +}; + + +/* Deprecate a property. */ + +deprecate.property = function(object, property, method) { + return Object.defineProperty(object, property, { + get: function() { + var warned; + warned = false; + if (!(warned || process.noDeprecation)) { + warned = true; + deprecate.warn(property + " property", method + " method"); + } + return this[method](); + } + }); +}; + + +/* Deprecate an event. */ + +deprecate.event = function(emitter, oldName, newName, fn) { + var warned; + warned = false; + return emitter.on(newName, function() { + var args; + args = 1 <= arguments.length ? slice.call(arguments, 0) : []; + + /* there is listeners for old API. */ + if (this.listenerCount(oldName) > 0) { + if (!(warned || process.noDeprecation)) { + warned = true; + deprecate.warn("'" + oldName + "' event", "'" + newName + "' event"); + } + if (fn != null) { + return fn.apply(this, arguments); + } else { + return this.emit.apply(this, [oldName].concat(slice.call(args))); + } + } + }); +}; + + +/* Print deprecation warning. */ + +deprecate.warn = function(oldName, newName) { + return deprecate.log(oldName + " is deprecated. Use " + newName + " instead."); +}; + + +/* Print deprecation message. */ + +deprecate.log = function(message) { + if (process.throwDeprecation) { + throw new Error(message); + } else if (process.traceDeprecation) { + return console.trace(message); + } else { + return console.warn("(electron) " + message); + } +}; + +module.exports = deprecate; diff --git a/atom/common/api/lib/exports/electron.coffee b/atom/common/api/lib/exports/electron.coffee deleted file mode 100644 index c941ab919baa..000000000000 --- a/atom/common/api/lib/exports/electron.coffee +++ /dev/null @@ -1,29 +0,0 @@ -### Do not expose the internal modules to `require`. ### -exports.hideInternalModules = -> - {globalPaths} = require 'module' - if globalPaths.length is 3 - ### Remove the "common/api/lib" and "browser-or-renderer/api/lib". ### - globalPaths.splice 0, 2 - -### Attaches properties to |exports|. ### -exports.defineProperties = (exports) -> - Object.defineProperties exports, - ### Common modules, please sort with alphabet order. ### - clipboard: - ### Must be enumerable, otherwise it woulde be invisible to remote module. ### - enumerable: true - get: -> require '../clipboard' - crashReporter: - enumerable: true - get: -> require '../crash-reporter' - nativeImage: - enumerable: true - get: -> require '../native-image' - shell: - enumerable: true - get: -> require '../shell' - ### The internal modules, invisible unless you know their names. ### - CallbacksRegistry: - get: -> require '../callbacks-registry' - deprecate: - get: -> require '../deprecate' diff --git a/atom/common/api/lib/exports/electron.js b/atom/common/api/lib/exports/electron.js new file mode 100644 index 000000000000..56443d376062 --- /dev/null +++ b/atom/common/api/lib/exports/electron.js @@ -0,0 +1,59 @@ + +/* Do not expose the internal modules to `require`. */ +exports.hideInternalModules = function() { + var globalPaths; + globalPaths = require('module').globalPaths; + if (globalPaths.length === 3) { + + /* Remove the "common/api/lib" and "browser-or-renderer/api/lib". */ + return globalPaths.splice(0, 2); + } +}; + + +/* Attaches properties to |exports|. */ + +exports.defineProperties = function(exports) { + return Object.defineProperties(exports, { + + /* Common modules, please sort with alphabet order. */ + clipboard: { + + /* Must be enumerable, otherwise it woulde be invisible to remote module. */ + enumerable: true, + get: function() { + return require('../clipboard'); + } + }, + crashReporter: { + enumerable: true, + get: function() { + return require('../crash-reporter'); + } + }, + nativeImage: { + enumerable: true, + get: function() { + return require('../native-image'); + } + }, + shell: { + enumerable: true, + get: function() { + return require('../shell'); + } + }, + + /* The internal modules, invisible unless you know their names. */ + CallbacksRegistry: { + get: function() { + return require('../callbacks-registry'); + } + }, + deprecate: { + get: function() { + return require('../deprecate'); + } + } + }); +}; diff --git a/atom/common/api/lib/native-image.coffee b/atom/common/api/lib/native-image.coffee deleted file mode 100644 index 9884f6abf763..000000000000 --- a/atom/common/api/lib/native-image.coffee +++ /dev/null @@ -1,7 +0,0 @@ -{deprecate} = require 'electron' -nativeImage = process.atomBinding 'native_image' - -### Deprecated. ### -deprecate.rename nativeImage, 'createFromDataUrl', 'createFromDataURL' - -module.exports = nativeImage diff --git a/atom/common/api/lib/native-image.js b/atom/common/api/lib/native-image.js new file mode 100644 index 000000000000..b1e1b2610ff4 --- /dev/null +++ b/atom/common/api/lib/native-image.js @@ -0,0 +1,12 @@ +var deprecate, nativeImage; + +deprecate = require('electron').deprecate; + +nativeImage = process.atomBinding('native_image'); + + +/* Deprecated. */ + +deprecate.rename(nativeImage, 'createFromDataUrl', 'createFromDataURL'); + +module.exports = nativeImage; diff --git a/atom/common/api/lib/shell.coffee b/atom/common/api/lib/shell.coffee deleted file mode 100644 index 5fb935bacd21..000000000000 --- a/atom/common/api/lib/shell.coffee +++ /dev/null @@ -1 +0,0 @@ -module.exports = process.atomBinding 'shell' diff --git a/atom/common/api/lib/shell.js b/atom/common/api/lib/shell.js new file mode 100644 index 000000000000..08cc4e8eb41c --- /dev/null +++ b/atom/common/api/lib/shell.js @@ -0,0 +1 @@ +module.exports = process.atomBinding('shell'); diff --git a/atom/common/lib/asar.coffee b/atom/common/lib/asar.coffee deleted file mode 100644 index 3e785b4e6132..000000000000 --- a/atom/common/lib/asar.coffee +++ /dev/null @@ -1,394 +0,0 @@ -asar = process.binding 'atom_common_asar' -child_process = require 'child_process' -path = require 'path' -util = require 'util' - -### Cache asar archive objects. ### -cachedArchives = {} -getOrCreateArchive = (p) -> - archive = cachedArchives[p] - return archive if archive? - archive = asar.createArchive p - return false unless archive - cachedArchives[p] = archive - -### Clean cache on quit. ### -process.on 'exit', -> - archive.destroy() for own p, archive of cachedArchives - -### Separate asar package's path from full path. ### -splitPath = (p) -> - ### shortcut to disable asar. ### - return [false] if process.noAsar - - return [false] if typeof p isnt 'string' - return [true, p, ''] if p.substr(-5) is '.asar' - p = path.normalize p - index = p.lastIndexOf ".asar#{path.sep}" - return [false] if index is -1 - [true, p.substr(0, index + 5), p.substr(index + 6)] - -### Convert asar archive's Stats object to fs's Stats object. ### -nextInode = 0 -uid = if process.getuid? then process.getuid() else 0 -gid = if process.getgid? then process.getgid() else 0 -fakeTime = new Date() -asarStatsToFsStats = (stats) -> - { - dev: 1, - ino: ++nextInode, - mode: 33188, - nlink: 1, - uid: uid, - gid: gid, - rdev: 0, - atime: stats.atime || fakeTime, - birthtime: stats.birthtime || fakeTime, - mtime: stats.mtime || fakeTime, - ctime: stats.ctime || fakeTime, - size: stats.size, - isFile: -> stats.isFile - isDirectory: -> stats.isDirectory - isSymbolicLink: -> stats.isLink - isBlockDevice: -> false - isCharacterDevice: -> false - isFIFO: -> false - isSocket: -> false - } - -### Create a ENOENT error. ### -notFoundError = (asarPath, filePath, callback) -> - error = new Error("ENOENT, #{filePath} not found in #{asarPath}") - error.code = "ENOENT" - error.errno = -2 - unless typeof callback is 'function' - throw error - process.nextTick -> callback error - -### Create a ENOTDIR error. ### -notDirError = (callback) -> - error = new Error('ENOTDIR, not a directory') - error.code = 'ENOTDIR' - error.errno = -20 - unless typeof callback is 'function' - throw error - process.nextTick -> callback error - -### Create invalid archive error. ### -invalidArchiveError = (asarPath, callback) -> - error = new Error("Invalid package #{asarPath}") - unless typeof callback is 'function' - throw error - process.nextTick -> callback error - -### Override APIs that rely on passing file path instead of content to C++. ### -overrideAPISync = (module, name, arg = 0) -> - old = module[name] - module[name] = -> - p = arguments[arg] - [isAsar, asarPath, filePath] = splitPath p - return old.apply this, arguments unless isAsar - - archive = getOrCreateArchive asarPath - invalidArchiveError asarPath unless archive - - newPath = archive.copyFileOut filePath - notFoundError asarPath, filePath unless newPath - - arguments[arg] = newPath - old.apply this, arguments - -overrideAPI = (module, name, arg = 0) -> - old = module[name] - module[name] = -> - p = arguments[arg] - [isAsar, asarPath, filePath] = splitPath p - return old.apply this, arguments unless isAsar - - callback = arguments[arguments.length - 1] - return overrideAPISync module, name, arg unless typeof callback is 'function' - - archive = getOrCreateArchive asarPath - return invalidArchiveError asarPath, callback unless archive - - newPath = archive.copyFileOut filePath - return notFoundError asarPath, filePath, callback unless newPath - - arguments[arg] = newPath - old.apply this, arguments - -### Override fs APIs. ### -exports.wrapFsWithAsar = (fs) -> - lstatSync = fs.lstatSync - fs.lstatSync = (p) -> - [isAsar, asarPath, filePath] = splitPath p - return lstatSync p unless isAsar - - archive = getOrCreateArchive asarPath - invalidArchiveError asarPath unless archive - - stats = archive.stat filePath - notFoundError asarPath, filePath unless stats - - asarStatsToFsStats stats - - lstat = fs.lstat - fs.lstat = (p, callback) -> - [isAsar, asarPath, filePath] = splitPath p - return lstat p, callback unless isAsar - - archive = getOrCreateArchive asarPath - return invalidArchiveError asarPath, callback unless archive - - stats = getOrCreateArchive(asarPath).stat filePath - return notFoundError asarPath, filePath, callback unless stats - - process.nextTick -> callback null, asarStatsToFsStats stats - - statSync = fs.statSync - fs.statSync = (p) -> - [isAsar, asarPath, filePath] = splitPath p - return statSync p unless isAsar - - ### Do not distinguish links for now. ### - fs.lstatSync p - - stat = fs.stat - fs.stat = (p, callback) -> - [isAsar, asarPath, filePath] = splitPath p - return stat p, callback unless isAsar - - ### Do not distinguish links for now. ### - process.nextTick -> fs.lstat p, callback - - statSyncNoException = fs.statSyncNoException - fs.statSyncNoException = (p) -> - [isAsar, asarPath, filePath] = splitPath p - return statSyncNoException p unless isAsar - - archive = getOrCreateArchive asarPath - return false unless archive - stats = archive.stat filePath - return false unless stats - asarStatsToFsStats stats - - realpathSync = fs.realpathSync - fs.realpathSync = (p) -> - [isAsar, asarPath, filePath] = splitPath p - return realpathSync.apply this, arguments unless isAsar - - archive = getOrCreateArchive asarPath - invalidArchiveError asarPath unless archive - - real = archive.realpath filePath - notFoundError asarPath, filePath if real is false - - path.join realpathSync(asarPath), real - - realpath = fs.realpath - fs.realpath = (p, cache, callback) -> - [isAsar, asarPath, filePath] = splitPath p - return realpath.apply this, arguments unless isAsar - - if typeof cache is 'function' - callback = cache - cache = undefined - - archive = getOrCreateArchive asarPath - return invalidArchiveError asarPath, callback unless archive - - real = archive.realpath filePath - if real is false - return notFoundError asarPath, filePath, callback - - realpath asarPath, (err, p) -> - return callback err if err - callback null, path.join(p, real) - - exists = fs.exists - fs.exists = (p, callback) -> - [isAsar, asarPath, filePath] = splitPath p - return exists p, callback unless isAsar - - archive = getOrCreateArchive asarPath - return invalidArchiveError asarPath, callback unless archive - - process.nextTick -> callback archive.stat(filePath) isnt false - - existsSync = fs.existsSync - fs.existsSync = (p) -> - [isAsar, asarPath, filePath] = splitPath p - return existsSync p unless isAsar - - archive = getOrCreateArchive asarPath - return false unless archive - - archive.stat(filePath) isnt false - - open = fs.open - readFile = fs.readFile - fs.readFile = (p, options, callback) -> - [isAsar, asarPath, filePath] = splitPath p - return readFile.apply this, arguments unless isAsar - - if typeof options is 'function' - callback = options - options = undefined - - archive = getOrCreateArchive asarPath - return invalidArchiveError asarPath, callback unless archive - - info = archive.getFileInfo filePath - return notFoundError asarPath, filePath, callback unless info - - if info.size is 0 - return process.nextTick -> callback null, new Buffer(0) - - if info.unpacked - realPath = archive.copyFileOut filePath - return fs.readFile realPath, options, callback - - if not options - options = encoding: null - else if util.isString options - options = encoding: options - else if not util.isObject options - throw new TypeError('Bad arguments') - - encoding = options.encoding - - buffer = new Buffer(info.size) - fd = archive.getFd() - return notFoundError asarPath, filePath, callback unless fd >= 0 - - fs.read fd, buffer, 0, info.size, info.offset, (error) -> - callback error, if encoding then buffer.toString encoding else buffer - - openSync = fs.openSync - readFileSync = fs.readFileSync - fs.readFileSync = (p, opts) -> - ### this allows v8 to optimize this function ### - options = opts - - [isAsar, asarPath, filePath] = splitPath p - return readFileSync.apply this, arguments unless isAsar - - archive = getOrCreateArchive asarPath - invalidArchiveError asarPath unless archive - - info = archive.getFileInfo filePath - notFoundError asarPath, filePath unless info - - if info.size is 0 - return if options then '' else new Buffer(0) - - if info.unpacked - realPath = archive.copyFileOut filePath - return fs.readFileSync realPath, options - - if not options - options = encoding: null - else if util.isString options - options = encoding: options - else if not util.isObject options - throw new TypeError('Bad arguments') - - encoding = options.encoding - - buffer = new Buffer(info.size) - fd = archive.getFd() - notFoundError asarPath, filePath unless fd >= 0 - - fs.readSync fd, buffer, 0, info.size, info.offset - if encoding then buffer.toString encoding else buffer - - readdir = fs.readdir - fs.readdir = (p, callback) -> - [isAsar, asarPath, filePath] = splitPath p - return readdir.apply this, arguments unless isAsar - - archive = getOrCreateArchive asarPath - return invalidArchiveError asarPath, callback unless archive - - files = archive.readdir filePath - return notFoundError asarPath, filePath, callback unless files - - process.nextTick -> callback null, files - - readdirSync = fs.readdirSync - fs.readdirSync = (p) -> - [isAsar, asarPath, filePath] = splitPath p - return readdirSync.apply this, arguments unless isAsar - - archive = getOrCreateArchive asarPath - invalidArchiveError asarPath unless archive - - files = archive.readdir filePath - notFoundError asarPath, filePath unless files - - files - - internalModuleReadFile = process.binding('fs').internalModuleReadFile - process.binding('fs').internalModuleReadFile = (p) -> - [isAsar, asarPath, filePath] = splitPath p - return internalModuleReadFile p unless isAsar - - archive = getOrCreateArchive asarPath - return undefined unless archive - - info = archive.getFileInfo filePath - return undefined unless info - return '' if info.size is 0 - - if info.unpacked - realPath = archive.copyFileOut filePath - return fs.readFileSync realPath, encoding: 'utf8' - - buffer = new Buffer(info.size) - fd = archive.getFd() - return undefined unless fd >= 0 - - fs.readSync fd, buffer, 0, info.size, info.offset - buffer.toString 'utf8' - - internalModuleStat = process.binding('fs').internalModuleStat - process.binding('fs').internalModuleStat = (p) -> - [isAsar, asarPath, filePath] = splitPath p - return internalModuleStat p unless isAsar - - archive = getOrCreateArchive asarPath - ### -ENOENT ### - return -34 unless archive - - stats = archive.stat filePath - ### -ENOENT ### - return -34 unless stats - - if stats.isDirectory then return 1 else return 0 - - ### - Calling mkdir for directory inside asar archive should throw ENOTDIR - error, but on Windows it throws ENOENT. - This is to work around the recursive looping bug of mkdirp since it is - widely used. - ### - if process.platform is 'win32' - mkdir = fs.mkdir - fs.mkdir = (p, mode, callback) -> - callback = mode if typeof mode is 'function' - [isAsar, asarPath, filePath] = splitPath p - return notDirError callback if isAsar and filePath.length - mkdir p, mode, callback - - mkdirSync = fs.mkdirSync - fs.mkdirSync = (p, mode) -> - [isAsar, asarPath, filePath] = splitPath p - notDirError() if isAsar and filePath.length - mkdirSync p, mode - - overrideAPI fs, 'open' - overrideAPI child_process, 'execFile' - overrideAPISync process, 'dlopen', 1 - overrideAPISync require('module')._extensions, '.node', 1 - overrideAPISync fs, 'openSync' - overrideAPISync child_process, 'execFileSync' diff --git a/atom/common/lib/asar.js b/atom/common/lib/asar.js new file mode 100644 index 000000000000..60e4c5c69f8c --- /dev/null +++ b/atom/common/lib/asar.js @@ -0,0 +1,608 @@ +var asar, asarStatsToFsStats, cachedArchives, child_process, fakeTime, getOrCreateArchive, gid, invalidArchiveError, nextInode, notDirError, notFoundError, overrideAPI, overrideAPISync, path, splitPath, uid, util, + hasProp = {}.hasOwnProperty; + +asar = process.binding('atom_common_asar'); + +child_process = require('child_process'); + +path = require('path'); + +util = require('util'); + + +/* Cache asar archive objects. */ + +cachedArchives = {}; + +getOrCreateArchive = function(p) { + var archive; + archive = cachedArchives[p]; + if (archive != null) { + return archive; + } + archive = asar.createArchive(p); + if (!archive) { + return false; + } + return cachedArchives[p] = archive; +}; + + +/* Clean cache on quit. */ + +process.on('exit', function() { + var archive, p, results; + results = []; + for (p in cachedArchives) { + if (!hasProp.call(cachedArchives, p)) continue; + archive = cachedArchives[p]; + results.push(archive.destroy()); + } + return results; +}); + + +/* Separate asar package's path from full path. */ + +splitPath = function(p) { + + /* shortcut to disable asar. */ + var index; + if (process.noAsar) { + return [false]; + } + if (typeof p !== 'string') { + return [false]; + } + if (p.substr(-5) === '.asar') { + return [true, p, '']; + } + p = path.normalize(p); + index = p.lastIndexOf(".asar" + path.sep); + if (index === -1) { + return [false]; + } + return [true, p.substr(0, index + 5), p.substr(index + 6)]; +}; + + +/* Convert asar archive's Stats object to fs's Stats object. */ + +nextInode = 0; + +uid = process.getuid != null ? process.getuid() : 0; + +gid = process.getgid != null ? process.getgid() : 0; + +fakeTime = new Date(); + +asarStatsToFsStats = function(stats) { + return { + dev: 1, + ino: ++nextInode, + mode: 33188, + nlink: 1, + uid: uid, + gid: gid, + rdev: 0, + atime: stats.atime || fakeTime, + birthtime: stats.birthtime || fakeTime, + mtime: stats.mtime || fakeTime, + ctime: stats.ctime || fakeTime, + size: stats.size, + isFile: function() { + return stats.isFile; + }, + isDirectory: function() { + return stats.isDirectory; + }, + isSymbolicLink: function() { + return stats.isLink; + }, + isBlockDevice: function() { + return false; + }, + isCharacterDevice: function() { + return false; + }, + isFIFO: function() { + return false; + }, + isSocket: function() { + return false; + } + }; +}; + + +/* Create a ENOENT error. */ + +notFoundError = function(asarPath, filePath, callback) { + var error; + error = new Error("ENOENT, " + filePath + " not found in " + asarPath); + error.code = "ENOENT"; + error.errno = -2; + if (typeof callback !== 'function') { + throw error; + } + return process.nextTick(function() { + return callback(error); + }); +}; + + +/* Create a ENOTDIR error. */ + +notDirError = function(callback) { + var error; + error = new Error('ENOTDIR, not a directory'); + error.code = 'ENOTDIR'; + error.errno = -20; + if (typeof callback !== 'function') { + throw error; + } + return process.nextTick(function() { + return callback(error); + }); +}; + + +/* Create invalid archive error. */ + +invalidArchiveError = function(asarPath, callback) { + var error; + error = new Error("Invalid package " + asarPath); + if (typeof callback !== 'function') { + throw error; + } + return process.nextTick(function() { + return callback(error); + }); +}; + + +/* Override APIs that rely on passing file path instead of content to C++. */ + +overrideAPISync = function(module, name, arg) { + var old; + if (arg == null) { + arg = 0; + } + old = module[name]; + return module[name] = function() { + var archive, asarPath, filePath, isAsar, newPath, p, ref; + p = arguments[arg]; + ref = splitPath(p), isAsar = ref[0], asarPath = ref[1], filePath = ref[2]; + if (!isAsar) { + return old.apply(this, arguments); + } + archive = getOrCreateArchive(asarPath); + if (!archive) { + invalidArchiveError(asarPath); + } + newPath = archive.copyFileOut(filePath); + if (!newPath) { + notFoundError(asarPath, filePath); + } + arguments[arg] = newPath; + return old.apply(this, arguments); + }; +}; + +overrideAPI = function(module, name, arg) { + var old; + if (arg == null) { + arg = 0; + } + old = module[name]; + return module[name] = function() { + var archive, asarPath, callback, filePath, isAsar, newPath, p, ref; + p = arguments[arg]; + ref = splitPath(p), isAsar = ref[0], asarPath = ref[1], filePath = ref[2]; + if (!isAsar) { + return old.apply(this, arguments); + } + callback = arguments[arguments.length - 1]; + if (typeof callback !== 'function') { + return overrideAPISync(module, name, arg); + } + archive = getOrCreateArchive(asarPath); + if (!archive) { + return invalidArchiveError(asarPath, callback); + } + newPath = archive.copyFileOut(filePath); + if (!newPath) { + return notFoundError(asarPath, filePath, callback); + } + arguments[arg] = newPath; + return old.apply(this, arguments); + }; +}; + + +/* Override fs APIs. */ + +exports.wrapFsWithAsar = function(fs) { + var exists, existsSync, internalModuleReadFile, internalModuleStat, lstat, lstatSync, mkdir, mkdirSync, open, openSync, readFile, readFileSync, readdir, readdirSync, realpath, realpathSync, stat, statSync, statSyncNoException; + lstatSync = fs.lstatSync; + fs.lstatSync = function(p) { + var archive, asarPath, filePath, isAsar, ref, stats; + ref = splitPath(p), isAsar = ref[0], asarPath = ref[1], filePath = ref[2]; + if (!isAsar) { + return lstatSync(p); + } + archive = getOrCreateArchive(asarPath); + if (!archive) { + invalidArchiveError(asarPath); + } + stats = archive.stat(filePath); + if (!stats) { + notFoundError(asarPath, filePath); + } + return asarStatsToFsStats(stats); + }; + lstat = fs.lstat; + fs.lstat = function(p, callback) { + var archive, asarPath, filePath, isAsar, ref, stats; + ref = splitPath(p), isAsar = ref[0], asarPath = ref[1], filePath = ref[2]; + if (!isAsar) { + return lstat(p, callback); + } + archive = getOrCreateArchive(asarPath); + if (!archive) { + return invalidArchiveError(asarPath, callback); + } + stats = getOrCreateArchive(asarPath).stat(filePath); + if (!stats) { + return notFoundError(asarPath, filePath, callback); + } + return process.nextTick(function() { + return callback(null, asarStatsToFsStats(stats)); + }); + }; + statSync = fs.statSync; + fs.statSync = function(p) { + var asarPath, filePath, isAsar, ref; + ref = splitPath(p), isAsar = ref[0], asarPath = ref[1], filePath = ref[2]; + if (!isAsar) { + return statSync(p); + } + + /* Do not distinguish links for now. */ + return fs.lstatSync(p); + }; + stat = fs.stat; + fs.stat = function(p, callback) { + var asarPath, filePath, isAsar, ref; + ref = splitPath(p), isAsar = ref[0], asarPath = ref[1], filePath = ref[2]; + if (!isAsar) { + return stat(p, callback); + } + + /* Do not distinguish links for now. */ + return process.nextTick(function() { + return fs.lstat(p, callback); + }); + }; + statSyncNoException = fs.statSyncNoException; + fs.statSyncNoException = function(p) { + var archive, asarPath, filePath, isAsar, ref, stats; + ref = splitPath(p), isAsar = ref[0], asarPath = ref[1], filePath = ref[2]; + if (!isAsar) { + return statSyncNoException(p); + } + archive = getOrCreateArchive(asarPath); + if (!archive) { + return false; + } + stats = archive.stat(filePath); + if (!stats) { + return false; + } + return asarStatsToFsStats(stats); + }; + realpathSync = fs.realpathSync; + fs.realpathSync = function(p) { + var archive, asarPath, filePath, isAsar, real, ref; + ref = splitPath(p), isAsar = ref[0], asarPath = ref[1], filePath = ref[2]; + if (!isAsar) { + return realpathSync.apply(this, arguments); + } + archive = getOrCreateArchive(asarPath); + if (!archive) { + invalidArchiveError(asarPath); + } + real = archive.realpath(filePath); + if (real === false) { + notFoundError(asarPath, filePath); + } + return path.join(realpathSync(asarPath), real); + }; + realpath = fs.realpath; + fs.realpath = function(p, cache, callback) { + var archive, asarPath, filePath, isAsar, real, ref; + ref = splitPath(p), isAsar = ref[0], asarPath = ref[1], filePath = ref[2]; + if (!isAsar) { + return realpath.apply(this, arguments); + } + if (typeof cache === 'function') { + callback = cache; + cache = void 0; + } + archive = getOrCreateArchive(asarPath); + if (!archive) { + return invalidArchiveError(asarPath, callback); + } + real = archive.realpath(filePath); + if (real === false) { + return notFoundError(asarPath, filePath, callback); + } + return realpath(asarPath, function(err, p) { + if (err) { + return callback(err); + } + return callback(null, path.join(p, real)); + }); + }; + exists = fs.exists; + fs.exists = function(p, callback) { + var archive, asarPath, filePath, isAsar, ref; + ref = splitPath(p), isAsar = ref[0], asarPath = ref[1], filePath = ref[2]; + if (!isAsar) { + return exists(p, callback); + } + archive = getOrCreateArchive(asarPath); + if (!archive) { + return invalidArchiveError(asarPath, callback); + } + return process.nextTick(function() { + return callback(archive.stat(filePath) !== false); + }); + }; + existsSync = fs.existsSync; + fs.existsSync = function(p) { + var archive, asarPath, filePath, isAsar, ref; + ref = splitPath(p), isAsar = ref[0], asarPath = ref[1], filePath = ref[2]; + if (!isAsar) { + return existsSync(p); + } + archive = getOrCreateArchive(asarPath); + if (!archive) { + return false; + } + return archive.stat(filePath) !== false; + }; + open = fs.open; + readFile = fs.readFile; + fs.readFile = function(p, options, callback) { + var archive, asarPath, buffer, encoding, fd, filePath, info, isAsar, realPath, ref; + ref = splitPath(p), isAsar = ref[0], asarPath = ref[1], filePath = ref[2]; + if (!isAsar) { + return readFile.apply(this, arguments); + } + if (typeof options === 'function') { + callback = options; + options = void 0; + } + archive = getOrCreateArchive(asarPath); + if (!archive) { + return invalidArchiveError(asarPath, callback); + } + info = archive.getFileInfo(filePath); + if (!info) { + return notFoundError(asarPath, filePath, callback); + } + if (info.size === 0) { + return process.nextTick(function() { + return callback(null, new Buffer(0)); + }); + } + if (info.unpacked) { + realPath = archive.copyFileOut(filePath); + return fs.readFile(realPath, options, callback); + } + if (!options) { + options = { + encoding: null + }; + } else if (util.isString(options)) { + options = { + encoding: options + }; + } else if (!util.isObject(options)) { + throw new TypeError('Bad arguments'); + } + encoding = options.encoding; + buffer = new Buffer(info.size); + fd = archive.getFd(); + if (!(fd >= 0)) { + return notFoundError(asarPath, filePath, callback); + } + return fs.read(fd, buffer, 0, info.size, info.offset, function(error) { + return callback(error, encoding ? buffer.toString(encoding) : buffer); + }); + }; + openSync = fs.openSync; + readFileSync = fs.readFileSync; + fs.readFileSync = function(p, opts) { + + /* this allows v8 to optimize this function */ + var archive, asarPath, buffer, encoding, fd, filePath, info, isAsar, options, realPath, ref; + options = opts; + ref = splitPath(p), isAsar = ref[0], asarPath = ref[1], filePath = ref[2]; + if (!isAsar) { + return readFileSync.apply(this, arguments); + } + archive = getOrCreateArchive(asarPath); + if (!archive) { + invalidArchiveError(asarPath); + } + info = archive.getFileInfo(filePath); + if (!info) { + notFoundError(asarPath, filePath); + } + if (info.size === 0) { + if (options) { + return ''; + } else { + return new Buffer(0); + } + } + if (info.unpacked) { + realPath = archive.copyFileOut(filePath); + return fs.readFileSync(realPath, options); + } + if (!options) { + options = { + encoding: null + }; + } else if (util.isString(options)) { + options = { + encoding: options + }; + } else if (!util.isObject(options)) { + throw new TypeError('Bad arguments'); + } + encoding = options.encoding; + buffer = new Buffer(info.size); + fd = archive.getFd(); + if (!(fd >= 0)) { + notFoundError(asarPath, filePath); + } + fs.readSync(fd, buffer, 0, info.size, info.offset); + if (encoding) { + return buffer.toString(encoding); + } else { + return buffer; + } + }; + readdir = fs.readdir; + fs.readdir = function(p, callback) { + var archive, asarPath, filePath, files, isAsar, ref; + ref = splitPath(p), isAsar = ref[0], asarPath = ref[1], filePath = ref[2]; + if (!isAsar) { + return readdir.apply(this, arguments); + } + archive = getOrCreateArchive(asarPath); + if (!archive) { + return invalidArchiveError(asarPath, callback); + } + files = archive.readdir(filePath); + if (!files) { + return notFoundError(asarPath, filePath, callback); + } + return process.nextTick(function() { + return callback(null, files); + }); + }; + readdirSync = fs.readdirSync; + fs.readdirSync = function(p) { + var archive, asarPath, filePath, files, isAsar, ref; + ref = splitPath(p), isAsar = ref[0], asarPath = ref[1], filePath = ref[2]; + if (!isAsar) { + return readdirSync.apply(this, arguments); + } + archive = getOrCreateArchive(asarPath); + if (!archive) { + invalidArchiveError(asarPath); + } + files = archive.readdir(filePath); + if (!files) { + notFoundError(asarPath, filePath); + } + return files; + }; + internalModuleReadFile = process.binding('fs').internalModuleReadFile; + process.binding('fs').internalModuleReadFile = function(p) { + var archive, asarPath, buffer, fd, filePath, info, isAsar, realPath, ref; + ref = splitPath(p), isAsar = ref[0], asarPath = ref[1], filePath = ref[2]; + if (!isAsar) { + return internalModuleReadFile(p); + } + archive = getOrCreateArchive(asarPath); + if (!archive) { + return void 0; + } + info = archive.getFileInfo(filePath); + if (!info) { + return void 0; + } + if (info.size === 0) { + return ''; + } + if (info.unpacked) { + realPath = archive.copyFileOut(filePath); + return fs.readFileSync(realPath, { + encoding: 'utf8' + }); + } + buffer = new Buffer(info.size); + fd = archive.getFd(); + if (!(fd >= 0)) { + return void 0; + } + fs.readSync(fd, buffer, 0, info.size, info.offset); + return buffer.toString('utf8'); + }; + internalModuleStat = process.binding('fs').internalModuleStat; + process.binding('fs').internalModuleStat = function(p) { + var archive, asarPath, filePath, isAsar, ref, stats; + ref = splitPath(p), isAsar = ref[0], asarPath = ref[1], filePath = ref[2]; + if (!isAsar) { + return internalModuleStat(p); + } + archive = getOrCreateArchive(asarPath); + + /* -ENOENT */ + if (!archive) { + return -34; + } + stats = archive.stat(filePath); + + /* -ENOENT */ + if (!stats) { + return -34; + } + if (stats.isDirectory) { + return 1; + } else { + return 0; + } + }; + + /* + Calling mkdir for directory inside asar archive should throw ENOTDIR + error, but on Windows it throws ENOENT. + This is to work around the recursive looping bug of mkdirp since it is + widely used. + */ + if (process.platform === 'win32') { + mkdir = fs.mkdir; + fs.mkdir = function(p, mode, callback) { + var asarPath, filePath, isAsar, ref; + if (typeof mode === 'function') { + callback = mode; + } + ref = splitPath(p), isAsar = ref[0], asarPath = ref[1], filePath = ref[2]; + if (isAsar && filePath.length) { + return notDirError(callback); + } + return mkdir(p, mode, callback); + }; + mkdirSync = fs.mkdirSync; + fs.mkdirSync = function(p, mode) { + var asarPath, filePath, isAsar, ref; + ref = splitPath(p), isAsar = ref[0], asarPath = ref[1], filePath = ref[2]; + if (isAsar && filePath.length) { + notDirError(); + } + return mkdirSync(p, mode); + }; + } + overrideAPI(fs, 'open'); + overrideAPI(child_process, 'execFile'); + overrideAPISync(process, 'dlopen', 1); + overrideAPISync(require('module')._extensions, '.node', 1); + overrideAPISync(fs, 'openSync'); + return overrideAPISync(child_process, 'execFileSync'); +}; diff --git a/atom/common/lib/asar_init.coffee b/atom/common/lib/asar_init.coffee deleted file mode 100644 index 4bb03daa7607..000000000000 --- a/atom/common/lib/asar_init.coffee +++ /dev/null @@ -1,22 +0,0 @@ -return (process, require, asarSource) -> - {createArchive} = process.binding 'atom_common_asar' - - ### Make asar.coffee accessible via "require". ### - process.binding('natives').ATOM_SHELL_ASAR = asarSource - - ### Monkey-patch the fs module. ### - require('ATOM_SHELL_ASAR').wrapFsWithAsar require('fs') - - ### Make graceful-fs work with asar. ### - source = process.binding 'natives' - source['original-fs'] = source.fs - source['fs'] = """ - var src = '(function (exports, require, module, __filename, __dirname) { ' + - process.binding('natives')['original-fs'] + - ' });'; - var vm = require('vm'); - var fn = vm.runInThisContext(src, { filename: 'fs.js' }); - fn(exports, require, module); - var asar = require('ATOM_SHELL_ASAR'); - asar.wrapFsWithAsar(exports); - """ diff --git a/atom/common/lib/asar_init.js b/atom/common/lib/asar_init.js new file mode 100644 index 000000000000..51d438c2c001 --- /dev/null +++ b/atom/common/lib/asar_init.js @@ -0,0 +1,15 @@ +return function(process, require, asarSource) { + var createArchive, source; + createArchive = process.binding('atom_common_asar').createArchive; + + /* Make asar.coffee accessible via "require". */ + process.binding('natives').ATOM_SHELL_ASAR = asarSource; + + /* Monkey-patch the fs module. */ + require('ATOM_SHELL_ASAR').wrapFsWithAsar(require('fs')); + + /* Make graceful-fs work with asar. */ + source = process.binding('natives'); + source['original-fs'] = source.fs; + return source['fs'] = "var src = '(function (exports, require, module, __filename, __dirname) { ' +\n process.binding('natives')['original-fs'] +\n ' });';\nvar vm = require('vm');\nvar fn = vm.runInThisContext(src, { filename: 'fs.js' });\nfn(exports, require, module);\nvar asar = require('ATOM_SHELL_ASAR');\nasar.wrapFsWithAsar(exports);"; +}; diff --git a/atom/common/lib/init.coffee b/atom/common/lib/init.coffee deleted file mode 100644 index 604c6590bdd5..000000000000 --- a/atom/common/lib/init.coffee +++ /dev/null @@ -1,40 +0,0 @@ -fs = require 'fs' -path = require 'path' -timers = require 'timers' -Module = require 'module' - -process.atomBinding = (name) -> - try - process.binding "atom_#{process.type}_#{name}" - catch e - process.binding "atom_common_#{name}" if /No such module/.test e.message - -unless process.env.ELECTRON_HIDE_INTERNAL_MODULES - ### Add common/api/lib to module search paths. ### - Module.globalPaths.push path.resolve(__dirname, '..', 'api', 'lib') - -### - setImmediate and process.nextTick makes use of uv_check and uv_prepare to - run the callbacks, however since we only run uv loop on requests, the - callbacks wouldn't be called until something else activated the uv loop, - which would delay the callbacks for arbitrary long time. So we should - initiatively activate the uv loop once setImmediate and process.nextTick is - called. -### -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 - called under Chromium's event loop the node's event loop won't get a chance - to update the timeout, so we have to force the node's event loop to - recalculate the timeout in browser process. - ### - global.setTimeout = wrapWithActivateUvLoop timers.setTimeout - global.setInterval = wrapWithActivateUvLoop timers.setInterval diff --git a/atom/common/lib/init.js b/atom/common/lib/init.js new file mode 100644 index 000000000000..c1c21d4e819b --- /dev/null +++ b/atom/common/lib/init.js @@ -0,0 +1,62 @@ +var Module, fs, path, timers, wrapWithActivateUvLoop; + +fs = require('fs'); + +path = require('path'); + +timers = require('timers'); + +Module = require('module'); + +process.atomBinding = function(name) { + var e, error; + try { + return process.binding("atom_" + process.type + "_" + name); + } catch (error) { + e = error; + if (/No such module/.test(e.message)) { + return process.binding("atom_common_" + name); + } + } +}; + +if (!process.env.ELECTRON_HIDE_INTERNAL_MODULES) { + + /* Add common/api/lib to module search paths. */ + Module.globalPaths.push(path.resolve(__dirname, '..', 'api', 'lib')); +} + + +/* + setImmediate and process.nextTick makes use of uv_check and uv_prepare to + run the callbacks, however since we only run uv loop on requests, the + callbacks wouldn't be called until something else activated the uv loop, + which would delay the callbacks for arbitrary long time. So we should + initiatively activate the uv loop once setImmediate and process.nextTick is + called. + */ + +wrapWithActivateUvLoop = function(func) { + return function() { + process.activateUvLoop(); + return func.apply(this, arguments); + }; +}; + +process.nextTick = wrapWithActivateUvLoop(process.nextTick); + +global.setImmediate = wrapWithActivateUvLoop(timers.setImmediate); + +global.clearImmediate = timers.clearImmediate; + +if (process.type === 'browser') { + + /* + setTimeout needs to update the polling timeout of the event loop, when + called under Chromium's event loop the node's event loop won't get a chance + to update the timeout, so we have to force the node's event loop to + recalculate the timeout in browser process. + */ + global.setTimeout = wrapWithActivateUvLoop(timers.setTimeout); + global.setInterval = wrapWithActivateUvLoop(timers.setInterval); +} diff --git a/atom/common/lib/reset-search-paths.coffee b/atom/common/lib/reset-search-paths.coffee deleted file mode 100644 index ae99abb4bf30..000000000000 --- a/atom/common/lib/reset-search-paths.coffee +++ /dev/null @@ -1,29 +0,0 @@ -path = require 'path' -Module = require 'module' - -### Clear Node's global search paths. ### -Module.globalPaths.length = 0 - -### Clear current and parent(init.coffee)'s search paths. ### -module.paths = [] -module.parent.paths = [] - -### Prevent Node from adding paths outside this app to search paths. ### -Module._nodeModulePaths = (from) -> - from = path.resolve from - - ### If "from" is outside the app then we do nothing. ### - skipOutsidePaths = from.startsWith process.resourcesPath - - ### Following logoic is copied from module.js. ### - splitRe = if process.platform is 'win32' then /[\/\\]/ else /\// - paths = [] - - parts = from.split splitRe - for part, tip in parts by -1 - continue if part is 'node_modules' - dir = parts.slice(0, tip + 1).join path.sep - break if skipOutsidePaths and not dir.startsWith process.resourcesPath - paths.push path.join(dir, 'node_modules') - - paths diff --git a/atom/common/lib/reset-search-paths.js b/atom/common/lib/reset-search-paths.js new file mode 100644 index 000000000000..61486b570e2c --- /dev/null +++ b/atom/common/lib/reset-search-paths.js @@ -0,0 +1,45 @@ +var Module, path; + +path = require('path'); + +Module = require('module'); + + +/* Clear Node's global search paths. */ + +Module.globalPaths.length = 0; + + +/* Clear current and parent(init.coffee)'s search paths. */ + +module.paths = []; + +module.parent.paths = []; + + +/* Prevent Node from adding paths outside this app to search paths. */ + +Module._nodeModulePaths = function(from) { + var dir, i, part, parts, paths, skipOutsidePaths, splitRe, tip; + from = path.resolve(from); + + /* If "from" is outside the app then we do nothing. */ + skipOutsidePaths = from.startsWith(process.resourcesPath); + + /* Following logoic is copied from module.js. */ + splitRe = process.platform === 'win32' ? /[\/\\]/ : /\//; + paths = []; + parts = from.split(splitRe); + for (tip = i = parts.length - 1; i >= 0; tip = i += -1) { + part = parts[tip]; + if (part === 'node_modules') { + continue; + } + dir = parts.slice(0, tip + 1).join(path.sep); + if (skipOutsidePaths && !dir.startsWith(process.resourcesPath)) { + break; + } + paths.push(path.join(dir, 'node_modules')); + } + return paths; +}; diff --git a/atom/renderer/api/lib/desktop-capturer.coffee b/atom/renderer/api/lib/desktop-capturer.coffee deleted file mode 100644 index 4fd0763d7e55..000000000000 --- a/atom/renderer/api/lib/desktop-capturer.coffee +++ /dev/null @@ -1,20 +0,0 @@ -{ipcRenderer, nativeImage} = require 'electron' - -nextId = 0 -getNextId = -> ++nextId - -### |options.type| can not be empty and has to include 'window' or 'screen'. ### -isValid = (options) -> - return options?.types? and Array.isArray options.types - -exports.getSources = (options, callback) -> - return callback new Error('Invalid options') unless isValid options - - captureWindow = 'window' in options.types - captureScreen = 'screen' in options.types - options.thumbnailSize ?= width: 150, height: 150 - - id = getNextId() - ipcRenderer.send 'ATOM_BROWSER_DESKTOP_CAPTURER_GET_SOURCES', captureWindow, captureScreen, options.thumbnailSize, id - ipcRenderer.once "ATOM_RENDERER_DESKTOP_CAPTURER_RESULT_#{id}", (event, sources) -> - callback null, ({id: source.id, name: source.name, thumbnail: nativeImage.createFromDataURL source.thumbnail} for source in sources) diff --git a/atom/renderer/api/lib/desktop-capturer.js b/atom/renderer/api/lib/desktop-capturer.js new file mode 100644 index 000000000000..4cc5362fbb73 --- /dev/null +++ b/atom/renderer/api/lib/desktop-capturer.js @@ -0,0 +1,50 @@ +var getNextId, ipcRenderer, isValid, nativeImage, nextId, ref, + indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; }; + +ref = require('electron'), ipcRenderer = ref.ipcRenderer, nativeImage = ref.nativeImage; + +nextId = 0; + +getNextId = function() { + return ++nextId; +}; + + +/* |options.type| can not be empty and has to include 'window' or 'screen'. */ + +isValid = function(options) { + return ((options != null ? options.types : void 0) != null) && Array.isArray(options.types); +}; + +exports.getSources = function(options, callback) { + var captureScreen, captureWindow, id; + if (!isValid(options)) { + return callback(new Error('Invalid options')); + } + captureWindow = indexOf.call(options.types, 'window') >= 0; + captureScreen = indexOf.call(options.types, 'screen') >= 0; + if (options.thumbnailSize == null) { + options.thumbnailSize = { + width: 150, + height: 150 + }; + } + id = getNextId(); + ipcRenderer.send('ATOM_BROWSER_DESKTOP_CAPTURER_GET_SOURCES', captureWindow, captureScreen, options.thumbnailSize, id); + return ipcRenderer.once("ATOM_RENDERER_DESKTOP_CAPTURER_RESULT_" + id, function(event, sources) { + var source; + return callback(null, (function() { + var i, len, results; + results = []; + for (i = 0, len = sources.length; i < len; i++) { + source = sources[i]; + results.push({ + id: source.id, + name: source.name, + thumbnail: nativeImage.createFromDataURL(source.thumbnail) + }); + } + return results; + })()); + }); +}; diff --git a/atom/renderer/api/lib/exports/electron.coffee b/atom/renderer/api/lib/exports/electron.coffee deleted file mode 100644 index b53980905416..000000000000 --- a/atom/renderer/api/lib/exports/electron.coffee +++ /dev/null @@ -1,22 +0,0 @@ -common = require '../../../../common/api/lib/exports/electron' - -### Import common modules. ### -common.defineProperties exports - -Object.defineProperties exports, - ### Renderer side modules, please sort with alphabet order. ### - desktopCapturer: - enumerable: true - get: -> require '../desktop-capturer' - ipcRenderer: - enumerable: true - get: -> require '../ipc-renderer' - remote: - enumerable: true - get: -> require '../remote' - screen: - enumerable: true - get: -> require '../screen' - webFrame: - enumerable: true - get: -> require '../web-frame' diff --git a/atom/renderer/api/lib/exports/electron.js b/atom/renderer/api/lib/exports/electron.js new file mode 100644 index 000000000000..e1c960c4b365 --- /dev/null +++ b/atom/renderer/api/lib/exports/electron.js @@ -0,0 +1,43 @@ +var common; + +common = require('../../../../common/api/lib/exports/electron'); + + +/* Import common modules. */ + +common.defineProperties(exports); + +Object.defineProperties(exports, { + + /* Renderer side modules, please sort with alphabet order. */ + desktopCapturer: { + enumerable: true, + get: function() { + return require('../desktop-capturer'); + } + }, + ipcRenderer: { + enumerable: true, + get: function() { + return require('../ipc-renderer'); + } + }, + remote: { + enumerable: true, + get: function() { + return require('../remote'); + } + }, + screen: { + enumerable: true, + get: function() { + return require('../screen'); + } + }, + webFrame: { + enumerable: true, + get: function() { + return require('../web-frame'); + } + } +}); diff --git a/atom/renderer/api/lib/ipc-renderer.coffee b/atom/renderer/api/lib/ipc-renderer.coffee deleted file mode 100644 index d468bd353e94..000000000000 --- a/atom/renderer/api/lib/ipc-renderer.coffee +++ /dev/null @@ -1,18 +0,0 @@ -{EventEmitter} = require 'events' - -binding = process.atomBinding 'ipc' -v8Util = process.atomBinding 'v8_util' - -### Created by init.coffee. ### -ipcRenderer = v8Util.getHiddenValue global, 'ipc' - -ipcRenderer.send = (args...) -> - binding.send 'ipc-message', [args...] - -ipcRenderer.sendSync = (args...) -> - JSON.parse binding.sendSync('ipc-message-sync', [args...]) - -ipcRenderer.sendToHost = (args...) -> - binding.send 'ipc-message-host', [args...] - -module.exports = ipcRenderer diff --git a/atom/renderer/api/lib/ipc-renderer.js b/atom/renderer/api/lib/ipc-renderer.js new file mode 100644 index 000000000000..b5f23030117f --- /dev/null +++ b/atom/renderer/api/lib/ipc-renderer.js @@ -0,0 +1,33 @@ +var EventEmitter, binding, ipcRenderer, v8Util, + slice = [].slice; + +EventEmitter = require('events').EventEmitter; + +binding = process.atomBinding('ipc'); + +v8Util = process.atomBinding('v8_util'); + + +/* Created by init.coffee. */ + +ipcRenderer = v8Util.getHiddenValue(global, 'ipc'); + +ipcRenderer.send = function() { + var args; + args = 1 <= arguments.length ? slice.call(arguments, 0) : []; + return binding.send('ipc-message', slice.call(args)); +}; + +ipcRenderer.sendSync = function() { + var args; + args = 1 <= arguments.length ? slice.call(arguments, 0) : []; + return JSON.parse(binding.sendSync('ipc-message-sync', slice.call(args))); +}; + +ipcRenderer.sendToHost = function() { + var args; + args = 1 <= arguments.length ? slice.call(arguments, 0) : []; + return binding.send('ipc-message-host', slice.call(args)); +}; + +module.exports = ipcRenderer; diff --git a/atom/renderer/api/lib/ipc.coffee b/atom/renderer/api/lib/ipc.coffee deleted file mode 100644 index 1eb49fb8d0de..000000000000 --- a/atom/renderer/api/lib/ipc.coffee +++ /dev/null @@ -1,19 +0,0 @@ -{ipcRenderer, deprecate} = require 'electron' -{EventEmitter} = require 'events' - -### This module is deprecated, we mirror everything from ipcRenderer. ### -deprecate.warn 'ipc module', 'require("electron").ipcRenderer' - -### Routes events of ipcRenderer. ### -ipc = new EventEmitter -ipcRenderer.emit = (channel, event, args...) -> - ipc.emit channel, args... - EventEmitter::emit.apply ipcRenderer, arguments - -### Deprecated. ### -for method of ipcRenderer when method.startsWith 'send' - ipc[method] = ipcRenderer[method] -deprecate.rename ipc, 'sendChannel', 'send' -deprecate.rename ipc, 'sendChannelSync', 'sendSync' - -module.exports = ipc diff --git a/atom/renderer/api/lib/ipc.js b/atom/renderer/api/lib/ipc.js new file mode 100644 index 000000000000..7758ce5d5188 --- /dev/null +++ b/atom/renderer/api/lib/ipc.js @@ -0,0 +1,38 @@ +var EventEmitter, deprecate, ipc, ipcRenderer, method, ref, + slice = [].slice; + +ref = require('electron'), ipcRenderer = ref.ipcRenderer, deprecate = ref.deprecate; + +EventEmitter = require('events').EventEmitter; + + +/* This module is deprecated, we mirror everything from ipcRenderer. */ + +deprecate.warn('ipc module', 'require("electron").ipcRenderer'); + + +/* Routes events of ipcRenderer. */ + +ipc = new EventEmitter; + +ipcRenderer.emit = function() { + var args, channel, event; + channel = arguments[0], event = arguments[1], args = 3 <= arguments.length ? slice.call(arguments, 2) : []; + ipc.emit.apply(ipc, [channel].concat(slice.call(args))); + return EventEmitter.prototype.emit.apply(ipcRenderer, arguments); +}; + + +/* Deprecated. */ + +for (method in ipcRenderer) { + if (method.startsWith('send')) { + ipc[method] = ipcRenderer[method]; + } +} + +deprecate.rename(ipc, 'sendChannel', 'send'); + +deprecate.rename(ipc, 'sendChannelSync', 'sendSync'); + +module.exports = ipc; diff --git a/atom/renderer/api/lib/remote.coffee b/atom/renderer/api/lib/remote.coffee deleted file mode 100644 index b30e79e73ba5..000000000000 --- a/atom/renderer/api/lib/remote.coffee +++ /dev/null @@ -1,209 +0,0 @@ -{ipcRenderer, CallbacksRegistry} = require 'electron' -v8Util = process.atomBinding 'v8_util' - -callbacksRegistry = new CallbacksRegistry - -### Check for circular reference. ### -isCircular = (field, visited) -> - if typeof field is 'object' - if field in visited - return true - visited.push field - return false - -### Convert the arguments object into an array of meta data. ### -wrapArgs = (args, visited=[]) -> - valueToMeta = (value) -> - if Array.isArray value - type: 'array', value: wrapArgs(value, visited) - else if Buffer.isBuffer value - type: 'buffer', value: Array::slice.call(value, 0) - else if value instanceof Date - type: 'date', value: value.getTime() - else if value?.constructor.name is 'Promise' - type: 'promise', then: valueToMeta(value.then.bind(value)) - else if value? and typeof value is 'object' and v8Util.getHiddenValue value, 'atomId' - type: 'remote-object', id: v8Util.getHiddenValue value, 'atomId' - else if value? and typeof value is 'object' - ret = type: 'object', name: value.constructor.name, members: [] - for prop, field of value - ret.members.push - name: prop - value: valueToMeta(if isCircular(field, visited) then null else field) - ret - else if typeof value is 'function' and v8Util.getHiddenValue value, 'returnValue' - type: 'function-with-return-value', value: valueToMeta(value()) - else if typeof value is 'function' - type: 'function', id: callbacksRegistry.add(value), location: v8Util.getHiddenValue value, 'location' - else - type: 'value', value: value - - Array::slice.call(args).map valueToMeta - -### Convert meta data from browser into real value. ### -metaToValue = (meta) -> - switch meta.type - when 'value' then meta.value - when 'array' then (metaToValue(el) for el in meta.members) - when 'buffer' then new Buffer(meta.value) - when 'promise' then Promise.resolve(then: metaToValue(meta.then)) - when 'error' then metaToPlainObject meta - when 'date' then new Date(meta.value) - when 'exception' - throw new Error("#{meta.message}\n#{meta.stack}") - else - if meta.type is 'function' - ### A shadow class to represent the remote function object. ### - ret = - class RemoteFunction - constructor: -> - if @constructor == RemoteFunction - ### Constructor call. ### - obj = ipcRenderer.sendSync 'ATOM_BROWSER_CONSTRUCTOR', meta.id, wrapArgs(arguments) - - ### - Returning object in constructor will replace constructed object - with the returned object. - http://stackoverflow.com/questions/1978049/what-values-can-a-constructor-return-to-avoid-returning-this - ### - return metaToValue obj - else - ### Function call. ### - obj = ipcRenderer.sendSync 'ATOM_BROWSER_FUNCTION_CALL', meta.id, wrapArgs(arguments) - return metaToValue obj - else - ret = v8Util.createObjectWithName meta.name - - ### Polulate delegate members. ### - for member in meta.members - if member.type is 'function' - ret[member.name] = createRemoteMemberFunction meta.id, member.name - else - Object.defineProperty ret, member.name, createRemoteMemberProperty(meta.id, member.name) - - ### - Track delegate object's life time, and tell the browser to clean up - when the object is GCed. - ### - v8Util.setDestructor ret, -> - ipcRenderer.send 'ATOM_BROWSER_DEREFERENCE', meta.id - - ### Remember object's id. ### - v8Util.setHiddenValue ret, 'atomId', meta.id - - ret - -### Construct a plain object from the meta. ### -metaToPlainObject = (meta) -> - obj = switch meta.type - when 'error' then new Error - else {} - obj[name] = value for {name, value} in meta.members - obj - -### - Create a RemoteMemberFunction instance. - This function's content should not be inlined into metaToValue, otherwise V8 - may consider it circular reference. -### -createRemoteMemberFunction = (metaId, name) -> - class RemoteMemberFunction - constructor: -> - if @constructor is RemoteMemberFunction - ### Constructor call. ### - ret = ipcRenderer.sendSync 'ATOM_BROWSER_MEMBER_CONSTRUCTOR', metaId, name, wrapArgs(arguments) - return metaToValue ret - else - ### Call member function. ### - ret = ipcRenderer.sendSync 'ATOM_BROWSER_MEMBER_CALL', metaId, name, wrapArgs(arguments) - return metaToValue ret - -### - Create configuration for defineProperty. - This function's content should not be inlined into metaToValue, otherwise V8 - may consider it circular reference. -### -createRemoteMemberProperty = (metaId, name) -> - enumerable: true, - configurable: false, - set: (value) -> - ### Set member data. ### - ipcRenderer.sendSync 'ATOM_BROWSER_MEMBER_SET', metaId, name, value - value - get: -> - ### Get member data. ### - metaToValue ipcRenderer.sendSync('ATOM_BROWSER_MEMBER_GET', metaId, name) - -### Browser calls a callback in renderer. ### -ipcRenderer.on 'ATOM_RENDERER_CALLBACK', (event, id, args) -> - callbacksRegistry.apply id, metaToValue(args) - -### A callback in browser is released. ### -ipcRenderer.on 'ATOM_RENDERER_RELEASE_CALLBACK', (event, id) -> - callbacksRegistry.remove id - -### List all built-in modules in browser process. ### -browserModules = require '../../../browser/api/lib/exports/electron' -### And add a helper receiver for each one. ### -for name of browserModules - do (name) -> - Object.defineProperty exports, name, get: -> exports.getBuiltin name - -### - Get remote module. - (Just like node's require, the modules are cached permanently, note that this - is safe leak since the object is not expected to get freed in browser) -### -moduleCache = {} -exports.require = (module) -> - return moduleCache[module] if moduleCache[module]? - - meta = ipcRenderer.sendSync 'ATOM_BROWSER_REQUIRE', module - moduleCache[module] = metaToValue meta - -### Optimize require('electron'). ### -moduleCache.electron = exports - -### Alias to remote.require('electron').xxx. ### -builtinCache = {} -exports.getBuiltin = (module) -> - return builtinCache[module] if builtinCache[module]? - - meta = ipcRenderer.sendSync 'ATOM_BROWSER_GET_BUILTIN', module - builtinCache[module] = metaToValue meta - -### Get current BrowserWindow object. ### -windowCache = null -exports.getCurrentWindow = -> - return windowCache if windowCache? - meta = ipcRenderer.sendSync 'ATOM_BROWSER_CURRENT_WINDOW' - windowCache = metaToValue meta - -### Get current WebContents object. ### -webContentsCache = null -exports.getCurrentWebContents = -> - return webContentsCache if webContentsCache? - meta = ipcRenderer.sendSync 'ATOM_BROWSER_CURRENT_WEB_CONTENTS' - webContentsCache = metaToValue meta - -### Get a global object in browser. ### -exports.getGlobal = (name) -> - meta = ipcRenderer.sendSync 'ATOM_BROWSER_GLOBAL', name - metaToValue meta - -### Get the process object in browser. ### -processCache = null -exports.__defineGetter__ 'process', -> - processCache = exports.getGlobal('process') unless processCache? - processCache - -### Create a funtion that will return the specifed value when called in browser. ### -exports.createFunctionWithReturnValue = (returnValue) -> - func = -> returnValue - v8Util.setHiddenValue func, 'returnValue', true - func - -### Get the guest WebContents from guestInstanceId. ### -exports.getGuestWebContents = (guestInstanceId) -> - meta = ipcRenderer.sendSync 'ATOM_BROWSER_GUEST_WEB_CONTENTS', guestInstanceId - metaToValue meta diff --git a/atom/renderer/api/lib/remote.js b/atom/renderer/api/lib/remote.js new file mode 100644 index 000000000000..3c0324c0ba27 --- /dev/null +++ b/atom/renderer/api/lib/remote.js @@ -0,0 +1,394 @@ +var CallbacksRegistry, browserModules, builtinCache, callbacksRegistry, createRemoteMemberFunction, createRemoteMemberProperty, fn, ipcRenderer, isCircular, metaToPlainObject, metaToValue, moduleCache, name, processCache, ref, v8Util, webContentsCache, windowCache, wrapArgs, + indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; }; + +ref = require('electron'), ipcRenderer = ref.ipcRenderer, CallbacksRegistry = ref.CallbacksRegistry; + +v8Util = process.atomBinding('v8_util'); + +callbacksRegistry = new CallbacksRegistry; + + +/* Check for circular reference. */ + +isCircular = function(field, visited) { + if (typeof field === 'object') { + if (indexOf.call(visited, field) >= 0) { + return true; + } + visited.push(field); + } + return false; +}; + + +/* Convert the arguments object into an array of meta data. */ + +wrapArgs = function(args, visited) { + var valueToMeta; + if (visited == null) { + visited = []; + } + valueToMeta = function(value) { + var field, prop, ret; + if (Array.isArray(value)) { + return { + type: 'array', + value: wrapArgs(value, visited) + }; + } else if (Buffer.isBuffer(value)) { + return { + type: 'buffer', + value: Array.prototype.slice.call(value, 0) + }; + } else if (value instanceof Date) { + return { + type: 'date', + value: value.getTime() + }; + } else if ((value != null ? value.constructor.name : void 0) === 'Promise') { + return { + type: 'promise', + then: valueToMeta(value.then.bind(value)) + }; + } else if ((value != null) && typeof value === 'object' && v8Util.getHiddenValue(value, 'atomId')) { + return { + type: 'remote-object', + id: v8Util.getHiddenValue(value, 'atomId') + }; + } else if ((value != null) && typeof value === 'object') { + ret = { + type: 'object', + name: value.constructor.name, + members: [] + }; + for (prop in value) { + field = value[prop]; + ret.members.push({ + name: prop, + value: valueToMeta(isCircular(field, visited) ? null : field) + }); + } + return ret; + } else if (typeof value === 'function' && v8Util.getHiddenValue(value, 'returnValue')) { + return { + type: 'function-with-return-value', + value: valueToMeta(value()) + }; + } else if (typeof value === 'function') { + return { + type: 'function', + id: callbacksRegistry.add(value), + location: v8Util.getHiddenValue(value, 'location') + }; + } else { + return { + type: 'value', + value: value + }; + } + }; + return Array.prototype.slice.call(args).map(valueToMeta); +}; + + +/* Convert meta data from browser into real value. */ + +metaToValue = function(meta) { + var RemoteFunction, el, i, j, len, len1, member, ref1, ref2, results, ret; + switch (meta.type) { + case 'value': + return meta.value; + case 'array': + ref1 = meta.members; + results = []; + for (i = 0, len = ref1.length; i < len; i++) { + el = ref1[i]; + results.push(metaToValue(el)); + } + return results; + case 'buffer': + return new Buffer(meta.value); + case 'promise': + return Promise.resolve({ + then: metaToValue(meta.then) + }); + case 'error': + return metaToPlainObject(meta); + case 'date': + return new Date(meta.value); + case 'exception': + throw new Error(meta.message + "\n" + meta.stack); + break; + default: + if (meta.type === 'function') { + + /* A shadow class to represent the remote function object. */ + ret = RemoteFunction = (function() { + function RemoteFunction() { + var obj; + if (this.constructor === RemoteFunction) { + + /* Constructor call. */ + obj = ipcRenderer.sendSync('ATOM_BROWSER_CONSTRUCTOR', meta.id, wrapArgs(arguments)); + + /* + Returning object in constructor will replace constructed object + with the returned object. + http://stackoverflow.com/questions/1978049/what-values-can-a-constructor-return-to-avoid-returning-this + */ + return metaToValue(obj); + } else { + + /* Function call. */ + obj = ipcRenderer.sendSync('ATOM_BROWSER_FUNCTION_CALL', meta.id, wrapArgs(arguments)); + return metaToValue(obj); + } + } + + return RemoteFunction; + + })(); + } else { + ret = v8Util.createObjectWithName(meta.name); + } + + /* Polulate delegate members. */ + ref2 = meta.members; + for (j = 0, len1 = ref2.length; j < len1; j++) { + member = ref2[j]; + if (member.type === 'function') { + ret[member.name] = createRemoteMemberFunction(meta.id, member.name); + } else { + Object.defineProperty(ret, member.name, createRemoteMemberProperty(meta.id, member.name)); + } + } + + /* + Track delegate object's life time, and tell the browser to clean up + when the object is GCed. + */ + v8Util.setDestructor(ret, function() { + return ipcRenderer.send('ATOM_BROWSER_DEREFERENCE', meta.id); + }); + + /* Remember object's id. */ + v8Util.setHiddenValue(ret, 'atomId', meta.id); + return ret; + } +}; + + +/* Construct a plain object from the meta. */ + +metaToPlainObject = function(meta) { + var i, len, name, obj, ref1, ref2, value; + obj = (function() { + switch (meta.type) { + case 'error': + return new Error; + default: + return {}; + } + })(); + ref1 = meta.members; + for (i = 0, len = ref1.length; i < len; i++) { + ref2 = ref1[i], name = ref2.name, value = ref2.value; + obj[name] = value; + } + return obj; +}; + + +/* + Create a RemoteMemberFunction instance. + This function's content should not be inlined into metaToValue, otherwise V8 + may consider it circular reference. + */ + +createRemoteMemberFunction = function(metaId, name) { + var RemoteMemberFunction; + return RemoteMemberFunction = (function() { + function RemoteMemberFunction() { + var ret; + if (this.constructor === RemoteMemberFunction) { + + /* Constructor call. */ + ret = ipcRenderer.sendSync('ATOM_BROWSER_MEMBER_CONSTRUCTOR', metaId, name, wrapArgs(arguments)); + return metaToValue(ret); + } else { + + /* Call member function. */ + ret = ipcRenderer.sendSync('ATOM_BROWSER_MEMBER_CALL', metaId, name, wrapArgs(arguments)); + return metaToValue(ret); + } + } + + return RemoteMemberFunction; + + })(); +}; + + +/* + Create configuration for defineProperty. + This function's content should not be inlined into metaToValue, otherwise V8 + may consider it circular reference. + */ + +createRemoteMemberProperty = function(metaId, name) { + return { + enumerable: true, + configurable: false, + set: function(value) { + + /* Set member data. */ + ipcRenderer.sendSync('ATOM_BROWSER_MEMBER_SET', metaId, name, value); + return value; + }, + get: function() { + + /* Get member data. */ + return metaToValue(ipcRenderer.sendSync('ATOM_BROWSER_MEMBER_GET', metaId, name)); + } + }; +}; + + +/* Browser calls a callback in renderer. */ + +ipcRenderer.on('ATOM_RENDERER_CALLBACK', function(event, id, args) { + return callbacksRegistry.apply(id, metaToValue(args)); +}); + + +/* A callback in browser is released. */ + +ipcRenderer.on('ATOM_RENDERER_RELEASE_CALLBACK', function(event, id) { + return callbacksRegistry.remove(id); +}); + + +/* List all built-in modules in browser process. */ + +browserModules = require('../../../browser/api/lib/exports/electron'); + + +/* And add a helper receiver for each one. */ + +fn = function(name) { + return Object.defineProperty(exports, name, { + get: function() { + return exports.getBuiltin(name); + } + }); +}; +for (name in browserModules) { + fn(name); +} + + +/* + Get remote module. + (Just like node's require, the modules are cached permanently, note that this + is safe leak since the object is not expected to get freed in browser) + */ + +moduleCache = {}; + +exports.require = function(module) { + var meta; + if (moduleCache[module] != null) { + return moduleCache[module]; + } + meta = ipcRenderer.sendSync('ATOM_BROWSER_REQUIRE', module); + return moduleCache[module] = metaToValue(meta); +}; + + +/* Optimize require('electron'). */ + +moduleCache.electron = exports; + + +/* Alias to remote.require('electron').xxx. */ + +builtinCache = {}; + +exports.getBuiltin = function(module) { + var meta; + if (builtinCache[module] != null) { + return builtinCache[module]; + } + meta = ipcRenderer.sendSync('ATOM_BROWSER_GET_BUILTIN', module); + return builtinCache[module] = metaToValue(meta); +}; + + +/* Get current BrowserWindow object. */ + +windowCache = null; + +exports.getCurrentWindow = function() { + var meta; + if (windowCache != null) { + return windowCache; + } + meta = ipcRenderer.sendSync('ATOM_BROWSER_CURRENT_WINDOW'); + return windowCache = metaToValue(meta); +}; + + +/* Get current WebContents object. */ + +webContentsCache = null; + +exports.getCurrentWebContents = function() { + var meta; + if (webContentsCache != null) { + return webContentsCache; + } + meta = ipcRenderer.sendSync('ATOM_BROWSER_CURRENT_WEB_CONTENTS'); + return webContentsCache = metaToValue(meta); +}; + + +/* Get a global object in browser. */ + +exports.getGlobal = function(name) { + var meta; + meta = ipcRenderer.sendSync('ATOM_BROWSER_GLOBAL', name); + return metaToValue(meta); +}; + + +/* Get the process object in browser. */ + +processCache = null; + +exports.__defineGetter__('process', function() { + if (processCache == null) { + processCache = exports.getGlobal('process'); + } + return processCache; +}); + + +/* Create a funtion that will return the specifed value when called in browser. */ + +exports.createFunctionWithReturnValue = function(returnValue) { + var func; + func = function() { + return returnValue; + }; + v8Util.setHiddenValue(func, 'returnValue', true); + return func; +}; + + +/* Get the guest WebContents from guestInstanceId. */ + +exports.getGuestWebContents = function(guestInstanceId) { + var meta; + meta = ipcRenderer.sendSync('ATOM_BROWSER_GUEST_WEB_CONTENTS', guestInstanceId); + return metaToValue(meta); +}; diff --git a/atom/renderer/api/lib/screen.coffee b/atom/renderer/api/lib/screen.coffee deleted file mode 100644 index 9eecd49dc5bf..000000000000 --- a/atom/renderer/api/lib/screen.coffee +++ /dev/null @@ -1 +0,0 @@ -module.exports = require('electron').remote.screen diff --git a/atom/renderer/api/lib/screen.js b/atom/renderer/api/lib/screen.js new file mode 100644 index 000000000000..fb74d78f79d2 --- /dev/null +++ b/atom/renderer/api/lib/screen.js @@ -0,0 +1 @@ +module.exports = require('electron').remote.screen; diff --git a/atom/renderer/api/lib/web-frame.coffee b/atom/renderer/api/lib/web-frame.coffee deleted file mode 100644 index e2ae3cae6192..000000000000 --- a/atom/renderer/api/lib/web-frame.coffee +++ /dev/null @@ -1,9 +0,0 @@ -{deprecate} = require 'electron' -{webFrame} = process.atomBinding 'web_frame' - -### Deprecated. ### -deprecate.rename webFrame, 'registerUrlSchemeAsSecure', 'registerURLSchemeAsSecure' -deprecate.rename webFrame, 'registerUrlSchemeAsBypassingCSP', 'registerURLSchemeAsBypassingCSP' -deprecate.rename webFrame, 'registerUrlSchemeAsPrivileged', 'registerURLSchemeAsPrivileged' - -module.exports = webFrame diff --git a/atom/renderer/api/lib/web-frame.js b/atom/renderer/api/lib/web-frame.js new file mode 100644 index 000000000000..90d1c5a87bd2 --- /dev/null +++ b/atom/renderer/api/lib/web-frame.js @@ -0,0 +1,16 @@ +var deprecate, webFrame; + +deprecate = require('electron').deprecate; + +webFrame = process.atomBinding('web_frame').webFrame; + + +/* Deprecated. */ + +deprecate.rename(webFrame, 'registerUrlSchemeAsSecure', 'registerURLSchemeAsSecure'); + +deprecate.rename(webFrame, 'registerUrlSchemeAsBypassingCSP', 'registerURLSchemeAsBypassingCSP'); + +deprecate.rename(webFrame, 'registerUrlSchemeAsPrivileged', 'registerURLSchemeAsPrivileged'); + +module.exports = webFrame; diff --git a/atom/renderer/lib/chrome-api.coffee b/atom/renderer/lib/chrome-api.coffee deleted file mode 100644 index 288afaf55457..000000000000 --- a/atom/renderer/lib/chrome-api.coffee +++ /dev/null @@ -1,10 +0,0 @@ -url = require 'url' - -chrome = window.chrome = window.chrome || {} -chrome.extension = - getURL: (path) -> - url.format - protocol: location.protocol - slashes: true - hostname: location.hostname - pathname: path diff --git a/atom/renderer/lib/chrome-api.js b/atom/renderer/lib/chrome-api.js new file mode 100644 index 000000000000..535f7f2103b5 --- /dev/null +++ b/atom/renderer/lib/chrome-api.js @@ -0,0 +1,16 @@ +var chrome, url; + +url = require('url'); + +chrome = window.chrome = window.chrome || {}; + +chrome.extension = { + getURL: function(path) { + return url.format({ + protocol: location.protocol, + slashes: true, + hostname: location.hostname, + pathname: path + }); + } +}; diff --git a/atom/renderer/lib/init.coffee b/atom/renderer/lib/init.coffee deleted file mode 100644 index 149c636ebeb4..000000000000 --- a/atom/renderer/lib/init.coffee +++ /dev/null @@ -1,111 +0,0 @@ -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. -### -process.argv.splice 1, 1 - -### Clear search paths. ### -require path.resolve(__dirname, '..', '..', 'common', 'lib', 'reset-search-paths') - -### Import common settings. ### -require path.resolve(__dirname, '..', '..', 'common', 'lib', 'init') - -globalPaths = Module.globalPaths -unless process.env.ELECTRON_HIDE_INTERNAL_MODULES - globalPaths.push path.resolve(__dirname, '..', 'api', 'lib') - -### Expose public APIs. ### -globalPaths.push path.resolve(__dirname, '..', 'api', 'lib', 'exports') - -### The global variable will be used by ipc for event dispatching ### -v8Util = process.atomBinding 'v8_util' -v8Util.setHiddenValue global, 'ipc', new events.EventEmitter - -### Process command line arguments. ### -nodeIntegration = 'false' -for arg in process.argv - if arg.indexOf('--guest-instance-id=') == 0 - ### This is a guest web view. ### - process.guestInstanceId = parseInt arg.substr(arg.indexOf('=') + 1) - else if arg.indexOf('--opener-id=') == 0 - ### This is a guest BrowserWindow. ### - process.openerId = parseInt arg.substr(arg.indexOf('=') + 1) - else if arg.indexOf('--node-integration=') == 0 - nodeIntegration = arg.substr arg.indexOf('=') + 1 - else if arg.indexOf('--preload=') == 0 - preloadScript = arg.substr arg.indexOf('=') + 1 - -if location.protocol is 'chrome-devtools:' - ### Override some inspector APIs. ### - require './inspector' - nodeIntegration = 'true' -else if location.protocol is 'chrome-extension:' - ### Add implementations of chrome API. ### - require './chrome-api' - nodeIntegration = 'true' -else - ### Override default web functions. ### - require './override' - ### Load webview tag implementation. ### - unless process.guestInstanceId? - require './web-view/web-view' - require './web-view/web-view-attributes' - -if nodeIntegration in ['true', 'all', 'except-iframe', 'manual-enable-iframe'] - ### Export node bindings to global. ### - global.require = require - global.module = module - - ### Set the __filename to the path of html file if it is file: protocol. ### - if window.location.protocol is 'file:' - pathname = - if process.platform is 'win32' and window.location.pathname[0] is '/' - window.location.pathname.substr 1 - else - window.location.pathname - global.__filename = path.normalize decodeURIComponent(pathname) - global.__dirname = path.dirname global.__filename - - ### Set module's filename so relative require can work as expected. ### - module.filename = global.__filename - - ### Also search for module under the html file. ### - module.paths = module.paths.concat Module._nodeModulePaths(global.__dirname) - else - global.__filename = __filename - global.__dirname = __dirname - - ### Redirect window.onerror to uncaughtException. ### - window.onerror = (message, filename, lineno, colno, error) -> - if global.process.listeners('uncaughtException').length > 0 - global.process.emit 'uncaughtException', error - true - else - false - - ### Emit the 'exit' event when page is unloading. ### - window.addEventListener 'unload', -> - process.emit 'exit' -else - ### Delete Node's symbols after the Environment has been loaded. ### - process.once 'loaded', -> - delete global.process - delete global.setImmediate - delete global.clearImmediate - delete global.global - -### Load the script specfied by the "preload" attribute. ### -if preloadScript - try - require preloadScript - catch error - if error.code is 'MODULE_NOT_FOUND' - console.error "Unable to load preload script #{preloadScript}" - else - console.error(error) - console.error(error.stack) diff --git a/atom/renderer/lib/init.js b/atom/renderer/lib/init.js new file mode 100644 index 000000000000..3d3026b595ef --- /dev/null +++ b/atom/renderer/lib/init.js @@ -0,0 +1,154 @@ +var Module, arg, error, error1, events, globalPaths, i, len, nodeIntegration, path, pathname, preloadScript, ref, url, v8Util; + +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. + */ + +process.argv.splice(1, 1); + + +/* Clear search paths. */ + +require(path.resolve(__dirname, '..', '..', 'common', 'lib', 'reset-search-paths')); + + +/* Import common settings. */ + +require(path.resolve(__dirname, '..', '..', 'common', 'lib', 'init')); + +globalPaths = Module.globalPaths; + +if (!process.env.ELECTRON_HIDE_INTERNAL_MODULES) { + globalPaths.push(path.resolve(__dirname, '..', 'api', 'lib')); +} + + +/* Expose public APIs. */ + +globalPaths.push(path.resolve(__dirname, '..', 'api', 'lib', 'exports')); + + +/* The global variable will be used by ipc for event dispatching */ + +v8Util = process.atomBinding('v8_util'); + +v8Util.setHiddenValue(global, 'ipc', new events.EventEmitter); + + +/* Process command line arguments. */ + +nodeIntegration = 'false'; + +ref = process.argv; +for (i = 0, len = ref.length; i < len; i++) { + arg = ref[i]; + if (arg.indexOf('--guest-instance-id=') === 0) { + + /* This is a guest web view. */ + process.guestInstanceId = parseInt(arg.substr(arg.indexOf('=') + 1)); + } else if (arg.indexOf('--opener-id=') === 0) { + + /* This is a guest BrowserWindow. */ + process.openerId = parseInt(arg.substr(arg.indexOf('=') + 1)); + } else if (arg.indexOf('--node-integration=') === 0) { + nodeIntegration = arg.substr(arg.indexOf('=') + 1); + } else if (arg.indexOf('--preload=') === 0) { + preloadScript = arg.substr(arg.indexOf('=') + 1); + } +} + +if (location.protocol === 'chrome-devtools:') { + + /* Override some inspector APIs. */ + require('./inspector'); + nodeIntegration = 'true'; +} else if (location.protocol === 'chrome-extension:') { + + /* Add implementations of chrome API. */ + require('./chrome-api'); + nodeIntegration = 'true'; +} else { + + /* Override default web functions. */ + require('./override'); + + /* Load webview tag implementation. */ + if (process.guestInstanceId == null) { + require('./web-view/web-view'); + require('./web-view/web-view-attributes'); + } +} + +if (nodeIntegration === 'true' || nodeIntegration === 'all' || nodeIntegration === 'except-iframe' || nodeIntegration === 'manual-enable-iframe') { + + /* Export node bindings to global. */ + global.require = require; + global.module = module; + + /* Set the __filename to the path of html file if it is file: protocol. */ + if (window.location.protocol === 'file:') { + pathname = process.platform === 'win32' && window.location.pathname[0] === '/' ? window.location.pathname.substr(1) : window.location.pathname; + global.__filename = path.normalize(decodeURIComponent(pathname)); + global.__dirname = path.dirname(global.__filename); + + /* Set module's filename so relative require can work as expected. */ + module.filename = global.__filename; + + /* Also search for module under the html file. */ + module.paths = module.paths.concat(Module._nodeModulePaths(global.__dirname)); + } else { + global.__filename = __filename; + global.__dirname = __dirname; + } + + /* Redirect window.onerror to uncaughtException. */ + window.onerror = function(message, filename, lineno, colno, error) { + if (global.process.listeners('uncaughtException').length > 0) { + global.process.emit('uncaughtException', error); + return true; + } else { + return false; + } + }; + + /* Emit the 'exit' event when page is unloading. */ + window.addEventListener('unload', function() { + return process.emit('exit'); + }); +} else { + + /* Delete Node's symbols after the Environment has been loaded. */ + process.once('loaded', function() { + delete global.process; + delete global.setImmediate; + delete global.clearImmediate; + return delete global.global; + }); +} + + +/* Load the script specfied by the "preload" attribute. */ + +if (preloadScript) { + try { + require(preloadScript); + } catch (error1) { + error = error1; + if (error.code === 'MODULE_NOT_FOUND') { + console.error("Unable to load preload script " + preloadScript); + } else { + console.error(error); + console.error(error.stack); + } + } +} diff --git a/atom/renderer/lib/inspector.coffee b/atom/renderer/lib/inspector.coffee deleted file mode 100644 index e49f4b77c7b5..000000000000 --- a/atom/renderer/lib/inspector.coffee +++ /dev/null @@ -1,60 +0,0 @@ -window.onload = -> - ### Use menu API to show context menu. ### - InspectorFrontendHost.showContextMenuAtPoint = createMenu - - ### Use dialog API to override file chooser dialog. ### - WebInspector.createFileSelectorElement = createFileSelectorElement - -convertToMenuTemplate = (items) -> - template = [] - for item in items - do (item) -> - transformed = - if item.type is 'subMenu' - type: 'submenu' - label: item.label - enabled: item.enabled - submenu: convertToMenuTemplate item.subItems - else if item.type is 'separator' - type: 'separator' - else if item.type is 'checkbox' - type: 'checkbox' - label: item.label - enabled: item.enabled - checked: item.checked - else - type: 'normal' - label: item.label - enabled: item.enabled - if item.id? - transformed.click = -> - DevToolsAPI.contextMenuItemSelected item.id - DevToolsAPI.contextMenuCleared() - template.push transformed - template - -createMenu = (x, y, items, document) -> - {remote} = require 'electron' - {Menu} = remote - - menu = Menu.buildFromTemplate convertToMenuTemplate(items) - ### The menu is expected to show asynchronously. ### - setTimeout -> menu.popup remote.getCurrentWindow() - -showFileChooserDialog = (callback) -> - {remote} = require 'electron' - {dialog} = remote - files = dialog.showOpenDialog {} - callback pathToHtml5FileObject files[0] if files? - -pathToHtml5FileObject = (path) -> - fs = require 'fs' - blob = new Blob([fs.readFileSync(path)]) - blob.name = path - blob - -createFileSelectorElement = (callback) -> - fileSelectorElement = document.createElement 'span' - fileSelectorElement.style.display = 'none' - fileSelectorElement.click = showFileChooserDialog.bind this, callback - return fileSelectorElement diff --git a/atom/renderer/lib/inspector.js b/atom/renderer/lib/inspector.js new file mode 100644 index 000000000000..ee578aefcfa2 --- /dev/null +++ b/atom/renderer/lib/inspector.js @@ -0,0 +1,85 @@ +var convertToMenuTemplate, createFileSelectorElement, createMenu, pathToHtml5FileObject, showFileChooserDialog; + +window.onload = function() { + + /* Use menu API to show context menu. */ + InspectorFrontendHost.showContextMenuAtPoint = createMenu; + + /* Use dialog API to override file chooser dialog. */ + return WebInspector.createFileSelectorElement = createFileSelectorElement; +}; + +convertToMenuTemplate = function(items) { + var fn, i, item, len, template; + template = []; + fn = function(item) { + var transformed; + transformed = item.type === 'subMenu' ? { + type: 'submenu', + label: item.label, + enabled: item.enabled, + submenu: convertToMenuTemplate(item.subItems) + } : item.type === 'separator' ? { + type: 'separator' + } : item.type === 'checkbox' ? { + type: 'checkbox', + label: item.label, + enabled: item.enabled, + checked: item.checked + } : { + type: 'normal', + label: item.label, + enabled: item.enabled + }; + if (item.id != null) { + transformed.click = function() { + DevToolsAPI.contextMenuItemSelected(item.id); + return DevToolsAPI.contextMenuCleared(); + }; + } + return template.push(transformed); + }; + for (i = 0, len = items.length; i < len; i++) { + item = items[i]; + fn(item); + } + return template; +}; + +createMenu = function(x, y, items, document) { + var Menu, menu, remote; + remote = require('electron').remote; + Menu = remote.Menu; + menu = Menu.buildFromTemplate(convertToMenuTemplate(items)); + + /* The menu is expected to show asynchronously. */ + return setTimeout(function() { + return menu.popup(remote.getCurrentWindow()); + }); +}; + +showFileChooserDialog = function(callback) { + var dialog, files, remote; + remote = require('electron').remote; + dialog = remote.dialog; + files = dialog.showOpenDialog({}); + if (files != null) { + return callback(pathToHtml5FileObject(files[0])); + } +}; + +pathToHtml5FileObject = function(path) { + var blob, fs; + fs = require('fs'); + blob = new Blob([fs.readFileSync(path)]); + blob.name = path; + return blob; +}; + +createFileSelectorElement = function(callback) { + var fileSelectorElement; + fileSelectorElement = document.createElement('span'); + fileSelectorElement.style.display = 'none'; + fileSelectorElement.click = showFileChooserDialog.bind(this, callback); + return fileSelectorElement; +}; diff --git a/atom/renderer/lib/override.coffee b/atom/renderer/lib/override.coffee deleted file mode 100644 index 5b031c0ad44a..000000000000 --- a/atom/renderer/lib/override.coffee +++ /dev/null @@ -1,129 +0,0 @@ -{ipcRenderer, remote} = require 'electron' - -### Helper function to resolve relative url. ### -a = window.top.document.createElement 'a' -resolveURL = (url) -> - a.href = url - a.href - -### Window object returned by "window.open". ### -class BrowserWindowProxy - @proxies: {} - - @getOrCreate: (guestId) -> - @proxies[guestId] ?= new BrowserWindowProxy(guestId) - - @remove: (guestId) -> - delete @proxies[guestId] - - constructor: (@guestId) -> - @closed = false - ipcRenderer.once "ATOM_SHELL_GUEST_WINDOW_MANAGER_WINDOW_CLOSED_#{@guestId}", => - BrowserWindowProxy.remove(@guestId) - @closed = true - - close: -> - ipcRenderer.send 'ATOM_SHELL_GUEST_WINDOW_MANAGER_WINDOW_CLOSE', @guestId - - focus: -> - ipcRenderer.send 'ATOM_SHELL_GUEST_WINDOW_MANAGER_WINDOW_METHOD', @guestId, 'focus' - - blur: -> - ipcRenderer.send 'ATOM_SHELL_GUEST_WINDOW_MANAGER_WINDOW_METHOD', @guestId, 'blur' - - postMessage: (message, targetOrigin='*') -> - ipcRenderer.send 'ATOM_SHELL_GUEST_WINDOW_MANAGER_WINDOW_POSTMESSAGE', @guestId, message, targetOrigin, location.origin - - eval: (args...) -> - ipcRenderer.send 'ATOM_SHELL_GUEST_WINDOW_MANAGER_WEB_CONTENTS_METHOD', @guestId, 'executeJavaScript', args... - -unless process.guestInstanceId? - ### Override default window.close. ### - window.close = -> - remote.getCurrentWindow().close() - -### Make the browser window or guest view emit "new-window" event. ### -window.open = (url, frameName='', features='') -> - options = {} - ints = [ 'x', 'y', 'width', 'height', 'min-width', 'max-width', 'min-height', 'max-height', 'zoom-factor' ] - ### Make sure to get rid of excessive whitespace in the property name ### - for feature in features.split /,\s*/ - [name, value] = feature.split /\s*=/ - options[name] = - if value is 'yes' or value is '1' - true - else if value is 'no' or value is '0' - false - else - value - options.x ?= options.left if options.left - options.y ?= options.top if options.top - options.title ?= frameName - options.width ?= 800 - options.height ?= 600 - - ### Resolve relative urls. ### - url = resolveURL url - - (options[name] = parseInt(options[name], 10) if options[name]?) for name in ints - - guestId = ipcRenderer.sendSync 'ATOM_SHELL_GUEST_WINDOW_MANAGER_WINDOW_OPEN', url, frameName, options - if guestId - BrowserWindowProxy.getOrCreate(guestId) - else - null - -### Use the dialog API to implement alert(). ### -window.alert = (message, title='') -> - buttons = ['OK'] - message = message.toString() - remote.dialog.showMessageBox remote.getCurrentWindow(), {message, title, buttons} - ### Alert should always return undefined. ### - return - -### And the confirm(). ### -window.confirm = (message, title='') -> - buttons = ['OK', 'Cancel'] - cancelId = 1 - not remote.dialog.showMessageBox remote.getCurrentWindow(), {message, title, buttons, cancelId} - -### But we do not support prompt(). ### -window.prompt = -> - throw new Error('prompt() is and will not be supported.') - -if process.openerId? - window.opener = BrowserWindowProxy.getOrCreate process.openerId - -ipcRenderer.on 'ATOM_SHELL_GUEST_WINDOW_POSTMESSAGE', (event, sourceId, message, sourceOrigin) -> - ### Manually dispatch event instead of using postMessage because we also need to ### - ### set event.source. ### - event = document.createEvent 'Event' - event.initEvent 'message', false, false - event.data = message - event.origin = sourceOrigin - event.source = BrowserWindowProxy.getOrCreate(sourceId) - window.dispatchEvent event - -### Forward history operations to browser. ### -sendHistoryOperation = (args...) -> - ipcRenderer.send 'ATOM_SHELL_NAVIGATION_CONTROLLER', args... - -getHistoryOperation = (args...) -> - ipcRenderer.sendSync 'ATOM_SHELL_SYNC_NAVIGATION_CONTROLLER', args... - -window.history.back = -> sendHistoryOperation 'goBack' -window.history.forward = -> sendHistoryOperation 'goForward' -window.history.go = (offset) -> sendHistoryOperation 'goToOffset', offset -Object.defineProperty window.history, 'length', - get: -> - getHistoryOperation 'length' - -### Make document.hidden and document.visibilityState return the correct value. ### -Object.defineProperty document, 'hidden', - get: -> - currentWindow = remote.getCurrentWindow() - currentWindow.isMinimized() || !currentWindow.isVisible() - -Object.defineProperty document, 'visibilityState', - get: -> - if document.hidden then "hidden" else "visible" diff --git a/atom/renderer/lib/override.js b/atom/renderer/lib/override.js new file mode 100644 index 000000000000..1a5791feb3fc --- /dev/null +++ b/atom/renderer/lib/override.js @@ -0,0 +1,249 @@ +var BrowserWindowProxy, a, getHistoryOperation, ipcRenderer, ref, remote, resolveURL, sendHistoryOperation, + slice = [].slice; + +ref = require('electron'), ipcRenderer = ref.ipcRenderer, remote = ref.remote; + + +/* Helper function to resolve relative url. */ + +a = window.top.document.createElement('a'); + +resolveURL = function(url) { + a.href = url; + return a.href; +}; + + +/* Window object returned by "window.open". */ + +BrowserWindowProxy = (function() { + BrowserWindowProxy.proxies = {}; + + BrowserWindowProxy.getOrCreate = function(guestId) { + var base; + return (base = this.proxies)[guestId] != null ? base[guestId] : base[guestId] = new BrowserWindowProxy(guestId); + }; + + BrowserWindowProxy.remove = function(guestId) { + return delete this.proxies[guestId]; + }; + + function BrowserWindowProxy(guestId1) { + this.guestId = guestId1; + this.closed = false; + ipcRenderer.once("ATOM_SHELL_GUEST_WINDOW_MANAGER_WINDOW_CLOSED_" + this.guestId, (function(_this) { + return function() { + BrowserWindowProxy.remove(_this.guestId); + return _this.closed = true; + }; + })(this)); + } + + BrowserWindowProxy.prototype.close = function() { + return ipcRenderer.send('ATOM_SHELL_GUEST_WINDOW_MANAGER_WINDOW_CLOSE', this.guestId); + }; + + BrowserWindowProxy.prototype.focus = function() { + return ipcRenderer.send('ATOM_SHELL_GUEST_WINDOW_MANAGER_WINDOW_METHOD', this.guestId, 'focus'); + }; + + BrowserWindowProxy.prototype.blur = function() { + return ipcRenderer.send('ATOM_SHELL_GUEST_WINDOW_MANAGER_WINDOW_METHOD', this.guestId, 'blur'); + }; + + BrowserWindowProxy.prototype.postMessage = function(message, targetOrigin) { + if (targetOrigin == null) { + targetOrigin = '*'; + } + return ipcRenderer.send('ATOM_SHELL_GUEST_WINDOW_MANAGER_WINDOW_POSTMESSAGE', this.guestId, message, targetOrigin, location.origin); + }; + + BrowserWindowProxy.prototype["eval"] = function() { + var args; + args = 1 <= arguments.length ? slice.call(arguments, 0) : []; + return ipcRenderer.send.apply(ipcRenderer, ['ATOM_SHELL_GUEST_WINDOW_MANAGER_WEB_CONTENTS_METHOD', this.guestId, 'executeJavaScript'].concat(slice.call(args))); + }; + + return BrowserWindowProxy; + +})(); + +if (process.guestInstanceId == null) { + + /* Override default window.close. */ + window.close = function() { + return remote.getCurrentWindow().close(); + }; +} + + +/* Make the browser window or guest view emit "new-window" event. */ + +window.open = function(url, frameName, features) { + var feature, guestId, i, ints, j, len, len1, name, options, ref1, ref2, value; + if (frameName == null) { + frameName = ''; + } + if (features == null) { + features = ''; + } + options = {}; + ints = ['x', 'y', 'width', 'height', 'min-width', 'max-width', 'min-height', 'max-height', 'zoom-factor']; + + /* Make sure to get rid of excessive whitespace in the property name */ + ref1 = features.split(/,\s*/); + for (i = 0, len = ref1.length; i < len; i++) { + feature = ref1[i]; + ref2 = feature.split(/\s*=/), name = ref2[0], value = ref2[1]; + options[name] = value === 'yes' || value === '1' ? true : value === 'no' || value === '0' ? false : value; + } + if (options.left) { + if (options.x == null) { + options.x = options.left; + } + } + if (options.top) { + if (options.y == null) { + options.y = options.top; + } + } + if (options.title == null) { + options.title = frameName; + } + if (options.width == null) { + options.width = 800; + } + if (options.height == null) { + options.height = 600; + } + + /* Resolve relative urls. */ + url = resolveURL(url); + for (j = 0, len1 = ints.length; j < len1; j++) { + name = ints[j]; + if (options[name] != null) { + options[name] = parseInt(options[name], 10); + } + } + guestId = ipcRenderer.sendSync('ATOM_SHELL_GUEST_WINDOW_MANAGER_WINDOW_OPEN', url, frameName, options); + if (guestId) { + return BrowserWindowProxy.getOrCreate(guestId); + } else { + return null; + } +}; + + +/* Use the dialog API to implement alert(). */ + +window.alert = function(message, title) { + var buttons; + if (title == null) { + title = ''; + } + buttons = ['OK']; + message = message.toString(); + remote.dialog.showMessageBox(remote.getCurrentWindow(), { + message: message, + title: title, + buttons: buttons + }); + + /* Alert should always return undefined. */ +}; + + +/* And the confirm(). */ + +window.confirm = function(message, title) { + var buttons, cancelId; + if (title == null) { + title = ''; + } + buttons = ['OK', 'Cancel']; + cancelId = 1; + return !remote.dialog.showMessageBox(remote.getCurrentWindow(), { + message: message, + title: title, + buttons: buttons, + cancelId: cancelId + }); +}; + + +/* But we do not support prompt(). */ + +window.prompt = function() { + throw new Error('prompt() is and will not be supported.'); +}; + +if (process.openerId != null) { + window.opener = BrowserWindowProxy.getOrCreate(process.openerId); +} + +ipcRenderer.on('ATOM_SHELL_GUEST_WINDOW_POSTMESSAGE', function(event, sourceId, message, sourceOrigin) { + + /* Manually dispatch event instead of using postMessage because we also need to */ + + /* set event.source. */ + event = document.createEvent('Event'); + event.initEvent('message', false, false); + event.data = message; + event.origin = sourceOrigin; + event.source = BrowserWindowProxy.getOrCreate(sourceId); + return window.dispatchEvent(event); +}); + + +/* Forward history operations to browser. */ + +sendHistoryOperation = function() { + var args; + args = 1 <= arguments.length ? slice.call(arguments, 0) : []; + return ipcRenderer.send.apply(ipcRenderer, ['ATOM_SHELL_NAVIGATION_CONTROLLER'].concat(slice.call(args))); +}; + +getHistoryOperation = function() { + var args; + args = 1 <= arguments.length ? slice.call(arguments, 0) : []; + return ipcRenderer.sendSync.apply(ipcRenderer, ['ATOM_SHELL_SYNC_NAVIGATION_CONTROLLER'].concat(slice.call(args))); +}; + +window.history.back = function() { + return sendHistoryOperation('goBack'); +}; + +window.history.forward = function() { + return sendHistoryOperation('goForward'); +}; + +window.history.go = function(offset) { + return sendHistoryOperation('goToOffset', offset); +}; + +Object.defineProperty(window.history, 'length', { + get: function() { + return getHistoryOperation('length'); + } +}); + + +/* Make document.hidden and document.visibilityState return the correct value. */ + +Object.defineProperty(document, 'hidden', { + get: function() { + var currentWindow; + currentWindow = remote.getCurrentWindow(); + return currentWindow.isMinimized() || !currentWindow.isVisible(); + } +}); + +Object.defineProperty(document, 'visibilityState', { + get: function() { + if (document.hidden) { + return "hidden"; + } else { + return "visible"; + } + } +}); diff --git a/atom/renderer/lib/web-view/guest-view-internal.coffee b/atom/renderer/lib/web-view/guest-view-internal.coffee deleted file mode 100644 index 30fe3d2a6e3d..000000000000 --- a/atom/renderer/lib/web-view/guest-view-internal.coffee +++ /dev/null @@ -1,89 +0,0 @@ -{ipcRenderer, webFrame} = require 'electron' - -requestId = 0 - -WEB_VIEW_EVENTS = - 'load-commit': ['url', 'isMainFrame'] - 'did-finish-load': [] - 'did-fail-load': ['errorCode', 'errorDescription', 'validatedURL'] - 'did-frame-finish-load': ['isMainFrame'] - 'did-start-loading': [] - 'did-stop-loading': [] - 'did-get-response-details': ['status', 'newURL', 'originalURL', - 'httpResponseCode', 'requestMethod', 'referrer', - 'headers'] - 'did-get-redirect-request': ['oldURL', 'newURL', 'isMainFrame'] - 'dom-ready': [] - 'console-message': ['level', 'message', 'line', 'sourceId'] - 'devtools-opened': [] - 'devtools-closed': [] - 'devtools-focused': [] - 'new-window': ['url', 'frameName', 'disposition', 'options'] - 'will-navigate': ['url'] - 'did-navigate': ['url'] - 'did-navigate-in-page': ['url'] - 'close': [] - 'crashed': [] - 'gpu-crashed': [] - 'plugin-crashed': ['name', 'version'] - 'media-started-playing': [] - 'media-paused': [] - 'did-change-theme-color': ['themeColor'] - 'destroyed': [] - 'page-title-updated': ['title', 'explicitSet'] - 'page-favicon-updated': ['favicons'] - 'enter-html-full-screen': [] - 'leave-html-full-screen': [] - 'found-in-page': ['result'] - -DEPRECATED_EVENTS = - 'page-title-updated': 'page-title-set' - -dispatchEvent = (webView, eventName, eventKey, args...) -> - if DEPRECATED_EVENTS[eventName]? - dispatchEvent webView, DEPRECATED_EVENTS[eventName], eventKey, args... - domEvent = new Event(eventName) - for f, i in WEB_VIEW_EVENTS[eventKey] - domEvent[f] = args[i] - webView.dispatchEvent domEvent - webView.onLoadCommit domEvent if eventName is 'load-commit' - -module.exports = - registerEvents: (webView, viewInstanceId) -> - ipcRenderer.on "ATOM_SHELL_GUEST_VIEW_INTERNAL_DISPATCH_EVENT-#{viewInstanceId}", (event, eventName, args...) -> - dispatchEvent webView, eventName, eventName, args... - - ipcRenderer.on "ATOM_SHELL_GUEST_VIEW_INTERNAL_IPC_MESSAGE-#{viewInstanceId}", (event, channel, args...) -> - domEvent = new Event('ipc-message') - domEvent.channel = channel - domEvent.args = [args...] - webView.dispatchEvent domEvent - - ipcRenderer.on "ATOM_SHELL_GUEST_VIEW_INTERNAL_SIZE_CHANGED-#{viewInstanceId}", (event, args...) -> - domEvent = new Event('size-changed') - for f, i in ['oldWidth', 'oldHeight', 'newWidth', 'newHeight'] - domEvent[f] = args[i] - webView.onSizeChanged domEvent - - deregisterEvents: (viewInstanceId) -> - ipcRenderer.removeAllListeners "ATOM_SHELL_GUEST_VIEW_INTERNAL_DISPATCH_EVENT-#{viewInstanceId}" - ipcRenderer.removeAllListeners "ATOM_SHELL_GUEST_VIEW_INTERNAL_IPC_MESSAGE-#{viewInstanceId}" - ipcRenderer.removeAllListeners "ATOM_SHELL_GUEST_VIEW_INTERNAL_SIZE_CHANGED-#{viewInstanceId}" - - createGuest: (params, callback) -> - requestId++ - ipcRenderer.send 'ATOM_SHELL_GUEST_VIEW_MANAGER_CREATE_GUEST', params, requestId - ipcRenderer.once "ATOM_SHELL_RESPONSE_#{requestId}", callback - - attachGuest: (elementInstanceId, guestInstanceId, params) -> - ipcRenderer.send 'ATOM_SHELL_GUEST_VIEW_MANAGER_ATTACH_GUEST', elementInstanceId, guestInstanceId, params - webFrame.attachGuest elementInstanceId - - destroyGuest: (guestInstanceId) -> - ipcRenderer.send 'ATOM_SHELL_GUEST_VIEW_MANAGER_DESTROY_GUEST', guestInstanceId - - setSize: (guestInstanceId, params) -> - ipcRenderer.send 'ATOM_SHELL_GUEST_VIEW_MANAGER_SET_SIZE', guestInstanceId, params - - setAllowTransparency: (guestInstanceId, allowtransparency) -> - ipcRenderer.send 'ATOM_SHELL_GUEST_VIEW_MANAGER_SET_ALLOW_TRANSPARENCY', guestInstanceId, allowtransparency diff --git a/atom/renderer/lib/web-view/guest-view-internal.js b/atom/renderer/lib/web-view/guest-view-internal.js new file mode 100644 index 000000000000..5dd86aff6613 --- /dev/null +++ b/atom/renderer/lib/web-view/guest-view-internal.js @@ -0,0 +1,113 @@ +var DEPRECATED_EVENTS, WEB_VIEW_EVENTS, dispatchEvent, ipcRenderer, ref, requestId, webFrame, + slice = [].slice; + +ref = require('electron'), ipcRenderer = ref.ipcRenderer, webFrame = ref.webFrame; + +requestId = 0; + +WEB_VIEW_EVENTS = { + 'load-commit': ['url', 'isMainFrame'], + 'did-finish-load': [], + 'did-fail-load': ['errorCode', 'errorDescription', 'validatedURL'], + 'did-frame-finish-load': ['isMainFrame'], + 'did-start-loading': [], + 'did-stop-loading': [], + 'did-get-response-details': ['status', 'newURL', 'originalURL', 'httpResponseCode', 'requestMethod', 'referrer', 'headers'], + 'did-get-redirect-request': ['oldURL', 'newURL', 'isMainFrame'], + 'dom-ready': [], + 'console-message': ['level', 'message', 'line', 'sourceId'], + 'devtools-opened': [], + 'devtools-closed': [], + 'devtools-focused': [], + 'new-window': ['url', 'frameName', 'disposition', 'options'], + 'will-navigate': ['url'], + 'did-navigate': ['url'], + 'did-navigate-in-page': ['url'], + 'close': [], + 'crashed': [], + 'gpu-crashed': [], + 'plugin-crashed': ['name', 'version'], + 'media-started-playing': [], + 'media-paused': [], + 'did-change-theme-color': ['themeColor'], + 'destroyed': [], + 'page-title-updated': ['title', 'explicitSet'], + 'page-favicon-updated': ['favicons'], + 'enter-html-full-screen': [], + 'leave-html-full-screen': [], + 'found-in-page': ['result'] +}; + +DEPRECATED_EVENTS = { + 'page-title-updated': 'page-title-set' +}; + +dispatchEvent = function() { + var args, domEvent, eventKey, eventName, f, i, j, len, ref1, webView; + webView = arguments[0], eventName = arguments[1], eventKey = arguments[2], args = 4 <= arguments.length ? slice.call(arguments, 3) : []; + if (DEPRECATED_EVENTS[eventName] != null) { + dispatchEvent.apply(null, [webView, DEPRECATED_EVENTS[eventName], eventKey].concat(slice.call(args))); + } + domEvent = new Event(eventName); + ref1 = WEB_VIEW_EVENTS[eventKey]; + for (i = j = 0, len = ref1.length; j < len; i = ++j) { + f = ref1[i]; + domEvent[f] = args[i]; + } + webView.dispatchEvent(domEvent); + if (eventName === 'load-commit') { + return webView.onLoadCommit(domEvent); + } +}; + +module.exports = { + registerEvents: function(webView, viewInstanceId) { + ipcRenderer.on("ATOM_SHELL_GUEST_VIEW_INTERNAL_DISPATCH_EVENT-" + viewInstanceId, function() { + var args, event, eventName; + event = arguments[0], eventName = arguments[1], args = 3 <= arguments.length ? slice.call(arguments, 2) : []; + return dispatchEvent.apply(null, [webView, eventName, eventName].concat(slice.call(args))); + }); + ipcRenderer.on("ATOM_SHELL_GUEST_VIEW_INTERNAL_IPC_MESSAGE-" + viewInstanceId, function() { + var args, channel, domEvent, event; + event = arguments[0], channel = arguments[1], args = 3 <= arguments.length ? slice.call(arguments, 2) : []; + domEvent = new Event('ipc-message'); + domEvent.channel = channel; + domEvent.args = slice.call(args); + return webView.dispatchEvent(domEvent); + }); + return ipcRenderer.on("ATOM_SHELL_GUEST_VIEW_INTERNAL_SIZE_CHANGED-" + viewInstanceId, function() { + var args, domEvent, event, f, i, j, len, ref1; + event = arguments[0], args = 2 <= arguments.length ? slice.call(arguments, 1) : []; + domEvent = new Event('size-changed'); + ref1 = ['oldWidth', 'oldHeight', 'newWidth', 'newHeight']; + for (i = j = 0, len = ref1.length; j < len; i = ++j) { + f = ref1[i]; + domEvent[f] = args[i]; + } + return webView.onSizeChanged(domEvent); + }); + }, + deregisterEvents: function(viewInstanceId) { + ipcRenderer.removeAllListeners("ATOM_SHELL_GUEST_VIEW_INTERNAL_DISPATCH_EVENT-" + viewInstanceId); + ipcRenderer.removeAllListeners("ATOM_SHELL_GUEST_VIEW_INTERNAL_IPC_MESSAGE-" + viewInstanceId); + return ipcRenderer.removeAllListeners("ATOM_SHELL_GUEST_VIEW_INTERNAL_SIZE_CHANGED-" + viewInstanceId); + }, + createGuest: function(params, callback) { + requestId++; + ipcRenderer.send('ATOM_SHELL_GUEST_VIEW_MANAGER_CREATE_GUEST', params, requestId); + return ipcRenderer.once("ATOM_SHELL_RESPONSE_" + requestId, callback); + }, + attachGuest: function(elementInstanceId, guestInstanceId, params) { + ipcRenderer.send('ATOM_SHELL_GUEST_VIEW_MANAGER_ATTACH_GUEST', elementInstanceId, guestInstanceId, params); + return webFrame.attachGuest(elementInstanceId); + }, + destroyGuest: function(guestInstanceId) { + return ipcRenderer.send('ATOM_SHELL_GUEST_VIEW_MANAGER_DESTROY_GUEST', guestInstanceId); + }, + setSize: function(guestInstanceId, params) { + return ipcRenderer.send('ATOM_SHELL_GUEST_VIEW_MANAGER_SET_SIZE', guestInstanceId, params); + }, + setAllowTransparency: function(guestInstanceId, allowtransparency) { + return ipcRenderer.send('ATOM_SHELL_GUEST_VIEW_MANAGER_SET_ALLOW_TRANSPARENCY', guestInstanceId, allowtransparency); + } +}; diff --git a/atom/renderer/lib/web-view/web-view-attributes.coffee b/atom/renderer/lib/web-view/web-view-attributes.coffee deleted file mode 100644 index 051a0c8a86b3..000000000000 --- a/atom/renderer/lib/web-view/web-view-attributes.coffee +++ /dev/null @@ -1,240 +0,0 @@ -WebViewImpl = require './web-view' -guestViewInternal = require './guest-view-internal' -webViewConstants = require './web-view-constants' - -{remote} = require 'electron' - -### Helper function to resolve url set in attribute. ### -a = document.createElement 'a' -resolveURL = (url) -> - a.href = url - a.href - -### - Attribute objects. - Default implementation of a WebView attribute. -### -class WebViewAttribute - constructor: (name, webViewImpl) -> - @name = name - @webViewImpl = webViewImpl - @ignoreMutation = false - - @defineProperty() - - ### Retrieves and returns the attribute's value. ### - getValue: -> @webViewImpl.webviewNode.getAttribute(@name) || '' - - ### Sets the attribute's value. ### - setValue: (value) -> @webViewImpl.webviewNode.setAttribute(@name, value || '') - - ### Changes the attribute's value without triggering its mutation handler. ### - setValueIgnoreMutation: (value) -> - @ignoreMutation = true - @setValue value - @ignoreMutation = false - - ### Defines this attribute as a property on the webview node. ### - defineProperty: -> - Object.defineProperty @webViewImpl.webviewNode, @name, - get: => @getValue() - set: (value) => @setValue value - enumerable: true - - ### Called when the attribute's value changes. ### - handleMutation: -> - -### An attribute that is treated as a Boolean. ### -class BooleanAttribute extends WebViewAttribute - constructor: (name, webViewImpl) -> - super name, webViewImpl - - getValue: -> @webViewImpl.webviewNode.hasAttribute @name - - setValue: (value) -> - unless value - @webViewImpl.webviewNode.removeAttribute @name - else - @webViewImpl.webviewNode.setAttribute @name, '' - -### Attribute that specifies whether transparency is allowed in the webview. ### -class AllowTransparencyAttribute extends BooleanAttribute - constructor: (webViewImpl) -> - super webViewConstants.ATTRIBUTE_ALLOWTRANSPARENCY, webViewImpl - - handleMutation: (oldValue, newValue) -> - return unless @webViewImpl.guestInstanceId - guestViewInternal.setAllowTransparency @webViewImpl.guestInstanceId, @getValue() - -### Attribute used to define the demension limits of autosizing. ### -class AutosizeDimensionAttribute extends WebViewAttribute - constructor: (name, webViewImpl) -> - super name, webViewImpl - - getValue: -> parseInt(@webViewImpl.webviewNode.getAttribute(@name)) || 0 - - handleMutation: (oldValue, newValue) -> - return unless @webViewImpl.guestInstanceId - guestViewInternal.setSize @webViewImpl.guestInstanceId, - enableAutoSize: @webViewImpl.attributes[webViewConstants.ATTRIBUTE_AUTOSIZE].getValue() - min: - width: parseInt @webViewImpl.attributes[webViewConstants.ATTRIBUTE_MINWIDTH].getValue() || 0 - height: parseInt @webViewImpl.attributes[webViewConstants.ATTRIBUTE_MINHEIGHT].getValue() || 0 - max: - width: parseInt @webViewImpl.attributes[webViewConstants.ATTRIBUTE_MAXWIDTH].getValue() || 0 - height: parseInt @webViewImpl.attributes[webViewConstants.ATTRIBUTE_MAXHEIGHT].getValue() || 0 - -### Attribute that specifies whether the webview should be autosized. ### -class AutosizeAttribute extends BooleanAttribute - constructor: (webViewImpl) -> - super webViewConstants.ATTRIBUTE_AUTOSIZE, webViewImpl - - handleMutation: AutosizeDimensionAttribute::handleMutation - -### Attribute representing the state of the storage partition. ### -class PartitionAttribute extends WebViewAttribute - constructor: (webViewImpl) -> - super webViewConstants.ATTRIBUTE_PARTITION, webViewImpl - @validPartitionId = true - - handleMutation: (oldValue, newValue) -> - newValue = newValue || '' - - ### The partition cannot change if the webview has already navigated. ### - unless @webViewImpl.beforeFirstNavigation - window.console.error webViewConstants.ERROR_MSG_ALREADY_NAVIGATED - @setValueIgnoreMutation oldValue - return - - if newValue is 'persist:' - @validPartitionId = false - window.console.error webViewConstants.ERROR_MSG_INVALID_PARTITION_ATTRIBUTE - -### Attribute that handles the location and navigation of the webview. ### -class SrcAttribute extends WebViewAttribute - constructor: (webViewImpl) -> - super webViewConstants.ATTRIBUTE_SRC, webViewImpl - @setupMutationObserver() - - getValue: -> - if @webViewImpl.webviewNode.hasAttribute @name - resolveURL @webViewImpl.webviewNode.getAttribute(@name) - else - '' - - setValueIgnoreMutation: (value) -> - WebViewAttribute::setValueIgnoreMutation.call(this, value) - ### - takeRecords() is needed to clear queued up src mutations. Without it, it - is possible for this change to get picked up asyncronously by src's - mutation observer |observer|, and then get handled even though we do not - want to handle this mutation. - ### - @observer.takeRecords() - - handleMutation: (oldValue, newValue) -> - ### - Once we have navigated, we don't allow clearing the src attribute. - Once enters a navigated state, it cannot return to a - placeholder state. - ### - if not newValue and oldValue - ### - src attribute changes normally initiate a navigation. We suppress - the next src attribute handler call to avoid reloading the page - on every guest-initiated navigation. - ### - @setValueIgnoreMutation oldValue - return - @parse() - - ### - The purpose of this mutation observer is to catch assignment to the src - attribute without any changes to its value. This is useful in the case - where the webview guest has crashed and navigating to the same address - spawns off a new process. - ### - setupMutationObserver: -> - @observer = new MutationObserver (mutations) => - for mutation in mutations - oldValue = mutation.oldValue - newValue = @getValue() - return if oldValue isnt newValue - @handleMutation oldValue, newValue - params = - attributes: true, - attributeOldValue: true, - attributeFilter: [@name] - @observer.observe @webViewImpl.webviewNode, params - - parse: -> - if not @webViewImpl.elementAttached or - not @webViewImpl.attributes[webViewConstants.ATTRIBUTE_PARTITION].validPartitionId or - not @.getValue() - return - - unless @webViewImpl.guestInstanceId? - if @webViewImpl.beforeFirstNavigation - @webViewImpl.beforeFirstNavigation = false - @webViewImpl.createGuest() - return - - ### Navigate to |this.src|. ### - opts = {} - httpreferrer = @webViewImpl.attributes[webViewConstants.ATTRIBUTE_HTTPREFERRER].getValue() - if httpreferrer then opts.httpReferrer = httpreferrer - - useragent = @webViewImpl.attributes[webViewConstants.ATTRIBUTE_USERAGENT].getValue() - if useragent then opts.userAgent = useragent - - guestContents = remote.getGuestWebContents(@webViewImpl.guestInstanceId) - guestContents.loadURL @getValue(), opts - -### Attribute specifies HTTP referrer. ### -class HttpReferrerAttribute extends WebViewAttribute - constructor: (webViewImpl) -> - super webViewConstants.ATTRIBUTE_HTTPREFERRER, webViewImpl - -### Attribute specifies user agent ### -class UserAgentAttribute extends WebViewAttribute - constructor: (webViewImpl) -> - super webViewConstants.ATTRIBUTE_USERAGENT, webViewImpl - -### Attribute that set preload script. ### -class PreloadAttribute extends WebViewAttribute - constructor: (webViewImpl) -> - super webViewConstants.ATTRIBUTE_PRELOAD, webViewImpl - - getValue: -> - return '' unless @webViewImpl.webviewNode.hasAttribute @name - preload = resolveURL @webViewImpl.webviewNode.getAttribute(@name) - protocol = preload.substr 0, 5 - unless protocol is 'file:' - console.error webViewConstants.ERROR_MSG_INVALID_PRELOAD_ATTRIBUTE - preload = '' - preload - -### Sets up all of the webview attributes. ### -WebViewImpl::setupWebViewAttributes = -> - @attributes = {} - - @attributes[webViewConstants.ATTRIBUTE_ALLOWTRANSPARENCY] = new AllowTransparencyAttribute(this) - @attributes[webViewConstants.ATTRIBUTE_AUTOSIZE] = new AutosizeAttribute(this) - @attributes[webViewConstants.ATTRIBUTE_PARTITION] = new PartitionAttribute(this) - @attributes[webViewConstants.ATTRIBUTE_SRC] = new SrcAttribute(this) - @attributes[webViewConstants.ATTRIBUTE_HTTPREFERRER] = new HttpReferrerAttribute(this) - @attributes[webViewConstants.ATTRIBUTE_USERAGENT] = new UserAgentAttribute(this) - @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 = [ - webViewConstants.ATTRIBUTE_MAXHEIGHT - webViewConstants.ATTRIBUTE_MAXWIDTH - webViewConstants.ATTRIBUTE_MINHEIGHT - webViewConstants.ATTRIBUTE_MINWIDTH - ] - for attribute in autosizeAttributes - @attributes[attribute] = new AutosizeDimensionAttribute(attribute, this) diff --git a/atom/renderer/lib/web-view/web-view-attributes.js b/atom/renderer/lib/web-view/web-view-attributes.js new file mode 100644 index 000000000000..fd5dad21c58e --- /dev/null +++ b/atom/renderer/lib/web-view/web-view-attributes.js @@ -0,0 +1,410 @@ +var AllowTransparencyAttribute, AutosizeAttribute, AutosizeDimensionAttribute, BooleanAttribute, HttpReferrerAttribute, PartitionAttribute, PreloadAttribute, SrcAttribute, UserAgentAttribute, WebViewAttribute, WebViewImpl, a, guestViewInternal, remote, resolveURL, webViewConstants, + extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }, + hasProp = {}.hasOwnProperty; + +WebViewImpl = require('./web-view'); + +guestViewInternal = require('./guest-view-internal'); + +webViewConstants = require('./web-view-constants'); + +remote = require('electron').remote; + + +/* Helper function to resolve url set in attribute. */ + +a = document.createElement('a'); + +resolveURL = function(url) { + a.href = url; + return a.href; +}; + + +/* + Attribute objects. + Default implementation of a WebView attribute. + */ + +WebViewAttribute = (function() { + function WebViewAttribute(name, webViewImpl) { + this.name = name; + this.webViewImpl = webViewImpl; + this.ignoreMutation = false; + this.defineProperty(); + } + + + /* Retrieves and returns the attribute's value. */ + + WebViewAttribute.prototype.getValue = function() { + return this.webViewImpl.webviewNode.getAttribute(this.name) || ''; + }; + + + /* Sets the attribute's value. */ + + WebViewAttribute.prototype.setValue = function(value) { + return this.webViewImpl.webviewNode.setAttribute(this.name, value || ''); + }; + + + /* Changes the attribute's value without triggering its mutation handler. */ + + WebViewAttribute.prototype.setValueIgnoreMutation = function(value) { + this.ignoreMutation = true; + this.setValue(value); + return this.ignoreMutation = false; + }; + + + /* Defines this attribute as a property on the webview node. */ + + WebViewAttribute.prototype.defineProperty = function() { + return Object.defineProperty(this.webViewImpl.webviewNode, this.name, { + get: (function(_this) { + return function() { + return _this.getValue(); + }; + })(this), + set: (function(_this) { + return function(value) { + return _this.setValue(value); + }; + })(this), + enumerable: true + }); + }; + + + /* Called when the attribute's value changes. */ + + WebViewAttribute.prototype.handleMutation = function() {}; + + return WebViewAttribute; + +})(); + + +/* An attribute that is treated as a Boolean. */ + +BooleanAttribute = (function(superClass) { + extend(BooleanAttribute, superClass); + + function BooleanAttribute(name, webViewImpl) { + BooleanAttribute.__super__.constructor.call(this, name, webViewImpl); + } + + BooleanAttribute.prototype.getValue = function() { + return this.webViewImpl.webviewNode.hasAttribute(this.name); + }; + + BooleanAttribute.prototype.setValue = function(value) { + if (!value) { + return this.webViewImpl.webviewNode.removeAttribute(this.name); + } else { + return this.webViewImpl.webviewNode.setAttribute(this.name, ''); + } + }; + + return BooleanAttribute; + +})(WebViewAttribute); + + +/* Attribute that specifies whether transparency is allowed in the webview. */ + +AllowTransparencyAttribute = (function(superClass) { + extend(AllowTransparencyAttribute, superClass); + + function AllowTransparencyAttribute(webViewImpl) { + AllowTransparencyAttribute.__super__.constructor.call(this, webViewConstants.ATTRIBUTE_ALLOWTRANSPARENCY, webViewImpl); + } + + AllowTransparencyAttribute.prototype.handleMutation = function(oldValue, newValue) { + if (!this.webViewImpl.guestInstanceId) { + return; + } + return guestViewInternal.setAllowTransparency(this.webViewImpl.guestInstanceId, this.getValue()); + }; + + return AllowTransparencyAttribute; + +})(BooleanAttribute); + + +/* Attribute used to define the demension limits of autosizing. */ + +AutosizeDimensionAttribute = (function(superClass) { + extend(AutosizeDimensionAttribute, superClass); + + function AutosizeDimensionAttribute(name, webViewImpl) { + AutosizeDimensionAttribute.__super__.constructor.call(this, name, webViewImpl); + } + + AutosizeDimensionAttribute.prototype.getValue = function() { + return parseInt(this.webViewImpl.webviewNode.getAttribute(this.name)) || 0; + }; + + AutosizeDimensionAttribute.prototype.handleMutation = function(oldValue, newValue) { + if (!this.webViewImpl.guestInstanceId) { + return; + } + return guestViewInternal.setSize(this.webViewImpl.guestInstanceId, { + enableAutoSize: this.webViewImpl.attributes[webViewConstants.ATTRIBUTE_AUTOSIZE].getValue(), + min: { + width: parseInt(this.webViewImpl.attributes[webViewConstants.ATTRIBUTE_MINWIDTH].getValue() || 0), + height: parseInt(this.webViewImpl.attributes[webViewConstants.ATTRIBUTE_MINHEIGHT].getValue() || 0) + }, + max: { + width: parseInt(this.webViewImpl.attributes[webViewConstants.ATTRIBUTE_MAXWIDTH].getValue() || 0), + height: parseInt(this.webViewImpl.attributes[webViewConstants.ATTRIBUTE_MAXHEIGHT].getValue() || 0) + } + }); + }; + + return AutosizeDimensionAttribute; + +})(WebViewAttribute); + + +/* Attribute that specifies whether the webview should be autosized. */ + +AutosizeAttribute = (function(superClass) { + extend(AutosizeAttribute, superClass); + + function AutosizeAttribute(webViewImpl) { + AutosizeAttribute.__super__.constructor.call(this, webViewConstants.ATTRIBUTE_AUTOSIZE, webViewImpl); + } + + AutosizeAttribute.prototype.handleMutation = AutosizeDimensionAttribute.prototype.handleMutation; + + return AutosizeAttribute; + +})(BooleanAttribute); + + +/* Attribute representing the state of the storage partition. */ + +PartitionAttribute = (function(superClass) { + extend(PartitionAttribute, superClass); + + function PartitionAttribute(webViewImpl) { + PartitionAttribute.__super__.constructor.call(this, webViewConstants.ATTRIBUTE_PARTITION, webViewImpl); + this.validPartitionId = true; + } + + PartitionAttribute.prototype.handleMutation = function(oldValue, newValue) { + newValue = newValue || ''; + + /* The partition cannot change if the webview has already navigated. */ + if (!this.webViewImpl.beforeFirstNavigation) { + window.console.error(webViewConstants.ERROR_MSG_ALREADY_NAVIGATED); + this.setValueIgnoreMutation(oldValue); + return; + } + if (newValue === 'persist:') { + this.validPartitionId = false; + return window.console.error(webViewConstants.ERROR_MSG_INVALID_PARTITION_ATTRIBUTE); + } + }; + + return PartitionAttribute; + +})(WebViewAttribute); + + +/* Attribute that handles the location and navigation of the webview. */ + +SrcAttribute = (function(superClass) { + extend(SrcAttribute, superClass); + + function SrcAttribute(webViewImpl) { + SrcAttribute.__super__.constructor.call(this, webViewConstants.ATTRIBUTE_SRC, webViewImpl); + this.setupMutationObserver(); + } + + SrcAttribute.prototype.getValue = function() { + if (this.webViewImpl.webviewNode.hasAttribute(this.name)) { + return resolveURL(this.webViewImpl.webviewNode.getAttribute(this.name)); + } else { + return ''; + } + }; + + SrcAttribute.prototype.setValueIgnoreMutation = function(value) { + WebViewAttribute.prototype.setValueIgnoreMutation.call(this, value); + + /* + takeRecords() is needed to clear queued up src mutations. Without it, it + is possible for this change to get picked up asyncronously by src's + mutation observer |observer|, and then get handled even though we do not + want to handle this mutation. + */ + return this.observer.takeRecords(); + }; + + SrcAttribute.prototype.handleMutation = function(oldValue, newValue) { + + /* + Once we have navigated, we don't allow clearing the src attribute. + Once enters a navigated state, it cannot return to a + placeholder state. + */ + if (!newValue && oldValue) { + + /* + src attribute changes normally initiate a navigation. We suppress + the next src attribute handler call to avoid reloading the page + on every guest-initiated navigation. + */ + this.setValueIgnoreMutation(oldValue); + return; + } + return this.parse(); + }; + + + /* + The purpose of this mutation observer is to catch assignment to the src + attribute without any changes to its value. This is useful in the case + where the webview guest has crashed and navigating to the same address + spawns off a new process. + */ + + SrcAttribute.prototype.setupMutationObserver = function() { + var params; + this.observer = new MutationObserver((function(_this) { + return function(mutations) { + var i, len, mutation, newValue, oldValue; + for (i = 0, len = mutations.length; i < len; i++) { + mutation = mutations[i]; + oldValue = mutation.oldValue; + newValue = _this.getValue(); + if (oldValue !== newValue) { + return; + } + _this.handleMutation(oldValue, newValue); + } + }; + })(this)); + params = { + attributes: true, + attributeOldValue: true, + attributeFilter: [this.name] + }; + return this.observer.observe(this.webViewImpl.webviewNode, params); + }; + + SrcAttribute.prototype.parse = function() { + var guestContents, httpreferrer, opts, useragent; + if (!this.webViewImpl.elementAttached || !this.webViewImpl.attributes[webViewConstants.ATTRIBUTE_PARTITION].validPartitionId || !this.getValue()) { + return; + } + if (this.webViewImpl.guestInstanceId == null) { + if (this.webViewImpl.beforeFirstNavigation) { + this.webViewImpl.beforeFirstNavigation = false; + this.webViewImpl.createGuest(); + } + return; + } + + /* Navigate to |this.src|. */ + opts = {}; + httpreferrer = this.webViewImpl.attributes[webViewConstants.ATTRIBUTE_HTTPREFERRER].getValue(); + if (httpreferrer) { + opts.httpReferrer = httpreferrer; + } + useragent = this.webViewImpl.attributes[webViewConstants.ATTRIBUTE_USERAGENT].getValue(); + if (useragent) { + opts.userAgent = useragent; + } + guestContents = remote.getGuestWebContents(this.webViewImpl.guestInstanceId); + return guestContents.loadURL(this.getValue(), opts); + }; + + return SrcAttribute; + +})(WebViewAttribute); + + +/* Attribute specifies HTTP referrer. */ + +HttpReferrerAttribute = (function(superClass) { + extend(HttpReferrerAttribute, superClass); + + function HttpReferrerAttribute(webViewImpl) { + HttpReferrerAttribute.__super__.constructor.call(this, webViewConstants.ATTRIBUTE_HTTPREFERRER, webViewImpl); + } + + return HttpReferrerAttribute; + +})(WebViewAttribute); + + +/* Attribute specifies user agent */ + +UserAgentAttribute = (function(superClass) { + extend(UserAgentAttribute, superClass); + + function UserAgentAttribute(webViewImpl) { + UserAgentAttribute.__super__.constructor.call(this, webViewConstants.ATTRIBUTE_USERAGENT, webViewImpl); + } + + return UserAgentAttribute; + +})(WebViewAttribute); + + +/* Attribute that set preload script. */ + +PreloadAttribute = (function(superClass) { + extend(PreloadAttribute, superClass); + + function PreloadAttribute(webViewImpl) { + PreloadAttribute.__super__.constructor.call(this, webViewConstants.ATTRIBUTE_PRELOAD, webViewImpl); + } + + PreloadAttribute.prototype.getValue = function() { + var preload, protocol; + if (!this.webViewImpl.webviewNode.hasAttribute(this.name)) { + return ''; + } + preload = resolveURL(this.webViewImpl.webviewNode.getAttribute(this.name)); + protocol = preload.substr(0, 5); + if (protocol !== 'file:') { + console.error(webViewConstants.ERROR_MSG_INVALID_PRELOAD_ATTRIBUTE); + preload = ''; + } + return preload; + }; + + return PreloadAttribute; + +})(WebViewAttribute); + + +/* Sets up all of the webview attributes. */ + +WebViewImpl.prototype.setupWebViewAttributes = function() { + var attribute, autosizeAttributes, i, len, results; + this.attributes = {}; + this.attributes[webViewConstants.ATTRIBUTE_ALLOWTRANSPARENCY] = new AllowTransparencyAttribute(this); + this.attributes[webViewConstants.ATTRIBUTE_AUTOSIZE] = new AutosizeAttribute(this); + this.attributes[webViewConstants.ATTRIBUTE_PARTITION] = new PartitionAttribute(this); + this.attributes[webViewConstants.ATTRIBUTE_SRC] = new SrcAttribute(this); + this.attributes[webViewConstants.ATTRIBUTE_HTTPREFERRER] = new HttpReferrerAttribute(this); + this.attributes[webViewConstants.ATTRIBUTE_USERAGENT] = new UserAgentAttribute(this); + this.attributes[webViewConstants.ATTRIBUTE_NODEINTEGRATION] = new BooleanAttribute(webViewConstants.ATTRIBUTE_NODEINTEGRATION, this); + this.attributes[webViewConstants.ATTRIBUTE_PLUGINS] = new BooleanAttribute(webViewConstants.ATTRIBUTE_PLUGINS, this); + this.attributes[webViewConstants.ATTRIBUTE_DISABLEWEBSECURITY] = new BooleanAttribute(webViewConstants.ATTRIBUTE_DISABLEWEBSECURITY, this); + this.attributes[webViewConstants.ATTRIBUTE_ALLOWPOPUPS] = new BooleanAttribute(webViewConstants.ATTRIBUTE_ALLOWPOPUPS, this); + this.attributes[webViewConstants.ATTRIBUTE_PRELOAD] = new PreloadAttribute(this); + autosizeAttributes = [webViewConstants.ATTRIBUTE_MAXHEIGHT, webViewConstants.ATTRIBUTE_MAXWIDTH, webViewConstants.ATTRIBUTE_MINHEIGHT, webViewConstants.ATTRIBUTE_MINWIDTH]; + results = []; + for (i = 0, len = autosizeAttributes.length; i < len; i++) { + attribute = autosizeAttributes[i]; + results.push(this.attributes[attribute] = new AutosizeDimensionAttribute(attribute, this)); + } + return results; +}; diff --git a/atom/renderer/lib/web-view/web-view-constants.coffee b/atom/renderer/lib/web-view/web-view-constants.coffee deleted file mode 100644 index 520517fbf58a..000000000000 --- a/atom/renderer/lib/web-view/web-view-constants.coffee +++ /dev/null @@ -1,28 +0,0 @@ -module.exports = - ### Attributes. ### - ATTRIBUTE_ALLOWTRANSPARENCY: 'allowtransparency' - ATTRIBUTE_AUTOSIZE: 'autosize' - ATTRIBUTE_MAXHEIGHT: 'maxheight' - ATTRIBUTE_MAXWIDTH: 'maxwidth' - ATTRIBUTE_MINHEIGHT: 'minheight' - ATTRIBUTE_MINWIDTH: 'minwidth' - ATTRIBUTE_NAME: 'name' - ATTRIBUTE_PARTITION: 'partition' - ATTRIBUTE_SRC: 'src' - ATTRIBUTE_HTTPREFERRER: 'httpreferrer' - ATTRIBUTE_NODEINTEGRATION: 'nodeintegration' - ATTRIBUTE_PLUGINS: 'plugins' - ATTRIBUTE_DISABLEWEBSECURITY: 'disablewebsecurity' - ATTRIBUTE_ALLOWPOPUPS: 'allowpopups' - ATTRIBUTE_PRELOAD: 'preload' - ATTRIBUTE_USERAGENT: 'useragent' - - ### Internal attribute. ### - ATTRIBUTE_INTERNALINSTANCEID: 'internalinstanceid' - - ### Error messages. ### - ERROR_MSG_ALREADY_NAVIGATED: 'The object has already navigated, so its partition cannot be changed.' - ERROR_MSG_CANNOT_INJECT_SCRIPT: ': ' + - 'Script cannot be injected into content until the page has loaded.' - ERROR_MSG_INVALID_PARTITION_ATTRIBUTE: 'Invalid partition attribute.' - ERROR_MSG_INVALID_PRELOAD_ATTRIBUTE: 'Only "file:" protocol is supported in "preload" attribute.' diff --git a/atom/renderer/lib/web-view/web-view-constants.js b/atom/renderer/lib/web-view/web-view-constants.js new file mode 100644 index 000000000000..098e02eb8875 --- /dev/null +++ b/atom/renderer/lib/web-view/web-view-constants.js @@ -0,0 +1,29 @@ +module.exports = { + + /* Attributes. */ + ATTRIBUTE_ALLOWTRANSPARENCY: 'allowtransparency', + ATTRIBUTE_AUTOSIZE: 'autosize', + ATTRIBUTE_MAXHEIGHT: 'maxheight', + ATTRIBUTE_MAXWIDTH: 'maxwidth', + ATTRIBUTE_MINHEIGHT: 'minheight', + ATTRIBUTE_MINWIDTH: 'minwidth', + ATTRIBUTE_NAME: 'name', + ATTRIBUTE_PARTITION: 'partition', + ATTRIBUTE_SRC: 'src', + ATTRIBUTE_HTTPREFERRER: 'httpreferrer', + ATTRIBUTE_NODEINTEGRATION: 'nodeintegration', + ATTRIBUTE_PLUGINS: 'plugins', + ATTRIBUTE_DISABLEWEBSECURITY: 'disablewebsecurity', + ATTRIBUTE_ALLOWPOPUPS: 'allowpopups', + ATTRIBUTE_PRELOAD: 'preload', + ATTRIBUTE_USERAGENT: 'useragent', + + /* Internal attribute. */ + ATTRIBUTE_INTERNALINSTANCEID: 'internalinstanceid', + + /* Error messages. */ + ERROR_MSG_ALREADY_NAVIGATED: 'The object has already navigated, so its partition cannot be changed.', + ERROR_MSG_CANNOT_INJECT_SCRIPT: ': ' + 'Script cannot be injected into content until the page has loaded.', + ERROR_MSG_INVALID_PARTITION_ATTRIBUTE: 'Invalid partition attribute.', + ERROR_MSG_INVALID_PRELOAD_ATTRIBUTE: 'Only "file:" protocol is supported in "preload" attribute.' +}; diff --git a/atom/renderer/lib/web-view/web-view.coffee b/atom/renderer/lib/web-view/web-view.coffee deleted file mode 100644 index 15610c85dd51..000000000000 --- a/atom/renderer/lib/web-view/web-view.coffee +++ /dev/null @@ -1,356 +0,0 @@ -{deprecate, webFrame, remote, ipcRenderer} = require 'electron' -v8Util = process.atomBinding 'v8_util' - -guestViewInternal = require './guest-view-internal' -webViewConstants = require './web-view-constants' - -### ID generator. ### -nextId = 0 -getNextId = -> ++nextId - -### Represents the internal state of the WebView node. ### -class WebViewImpl - constructor: (@webviewNode) -> - v8Util.setHiddenValue @webviewNode, 'internal', this - @attached = false - @elementAttached = false - - @beforeFirstNavigation = true - - ### on* Event handlers. ### - @on = {} - - @browserPluginNode = @createBrowserPluginNode() - shadowRoot = @webviewNode.createShadowRoot() - @setupWebViewAttributes() - @setupFocusPropagation() - - @viewInstanceId = getNextId() - - shadowRoot.appendChild @browserPluginNode - - createBrowserPluginNode: -> - ### - We create BrowserPlugin as a custom element in order to observe changes - to attributes synchronously. - ### - browserPluginNode = new WebViewImpl.BrowserPlugin() - v8Util.setHiddenValue browserPluginNode, 'internal', this - browserPluginNode - - ### Resets some state upon reattaching element to the DOM. ### - reset: -> - ### - If guestInstanceId is defined then the has navigated and has - already picked up a partition ID. Thus, we need to reset the initialization - state. However, it may be the case that beforeFirstNavigation is false BUT - guestInstanceId has yet to be initialized. This means that we have not - heard back from createGuest yet. We will not reset the flag in this case so - that we don't end up allocating a second guest. - ### - if @guestInstanceId - guestViewInternal.destroyGuest @guestInstanceId - @webContents = null - @guestInstanceId = undefined - @beforeFirstNavigation = true - @attributes[webViewConstants.ATTRIBUTE_PARTITION].validPartitionId = true - @internalInstanceId = 0 - - ### Sets the .request property. ### - setRequestPropertyOnWebViewNode: (request) -> - Object.defineProperty @webviewNode, 'request', value: request, enumerable: true - - setupFocusPropagation: -> - unless @webviewNode.hasAttribute 'tabIndex' - ### - needs a tabIndex in order to be focusable. - TODO(fsamuel): It would be nice to avoid exposing a tabIndex attribute - to allow to be focusable. - See http://crbug.com/231664. - ### - @webviewNode.setAttribute 'tabIndex', -1 - @webviewNode.addEventListener 'focus', (e) => - ### Focus the BrowserPlugin when the takes focus. ### - @browserPluginNode.focus() - @webviewNode.addEventListener 'blur', (e) => - ### Blur the BrowserPlugin when the loses focus. ### - @browserPluginNode.blur() - - ### - This observer monitors mutations to attributes of the and - updates the BrowserPlugin properties accordingly. In turn, updating - a BrowserPlugin property will update the corresponding BrowserPlugin - attribute, if necessary. See BrowserPlugin::UpdateDOMAttribute for more - details. - ### - handleWebviewAttributeMutation: (attributeName, oldValue, newValue) -> - if not @attributes[attributeName] or @attributes[attributeName].ignoreMutation - return - - ### Let the changed attribute handle its own mutation; ### - @attributes[attributeName].handleMutation oldValue, newValue - - handleBrowserPluginAttributeMutation: (attributeName, oldValue, newValue) -> - if attributeName is webViewConstants.ATTRIBUTE_INTERNALINSTANCEID and !oldValue and !!newValue - @browserPluginNode.removeAttribute webViewConstants.ATTRIBUTE_INTERNALINSTANCEID - @internalInstanceId = parseInt newValue - - ### Track when the element resizes using the element resize callback. ### - webFrame.registerElementResizeCallback @internalInstanceId, @onElementResize.bind(this) - - return unless @guestInstanceId - - guestViewInternal.attachGuest @internalInstanceId, @guestInstanceId, @buildParams() - - onSizeChanged: (webViewEvent) -> - newWidth = webViewEvent.newWidth - newHeight = webViewEvent.newHeight - - node = @webviewNode - - width = node.offsetWidth - height = node.offsetHeight - - ### Check the current bounds to make sure we do not resize ### - ### outside of current constraints. ### - maxWidth = @attributes[webViewConstants.ATTRIBUTE_MAXWIDTH].getValue() | width - maxHeight = @attributes[webViewConstants.ATTRIBUTE_MAXHEIGHT].getValue() | width - minWidth = @attributes[webViewConstants.ATTRIBUTE_MINWIDTH].getValue() | width - minHeight = @attributes[webViewConstants.ATTRIBUTE_MINHEIGHT].getValue() | width - - minWidth = Math.min minWidth, maxWidth - minHeight = Math.min minHeight, maxHeight - - if not @attributes[webViewConstants.ATTRIBUTE_AUTOSIZE].getValue() or - (newWidth >= minWidth and - newWidth <= maxWidth and - newHeight >= minHeight and - newHeight <= maxHeight) - node.style.width = newWidth + 'px' - node.style.height = newHeight + 'px' - ### - Only fire the DOM event if the size of the has actually - changed. - ### - @dispatchEvent webViewEvent - - onElementResize: (newSize) -> - ### Dispatch the 'resize' event. ### - resizeEvent = new Event('resize', bubbles: true) - resizeEvent.newWidth = newSize.width - resizeEvent.newHeight = newSize.height - @dispatchEvent resizeEvent - - if @guestInstanceId - guestViewInternal.setSize @guestInstanceId, normal: newSize - - createGuest: -> - guestViewInternal.createGuest @buildParams(), (event, guestInstanceId) => - @attachWindow guestInstanceId - - dispatchEvent: (webViewEvent) -> - @webviewNode.dispatchEvent webViewEvent - - ### Adds an 'on' property on the webview, which can be used to set/unset ### - ### an event handler. ### - setupEventProperty: (eventName) -> - propertyName = 'on' + eventName.toLowerCase() - Object.defineProperty @webviewNode, propertyName, - get: => @on[propertyName] - set: (value) => - if @on[propertyName] - @webviewNode.removeEventListener eventName, @on[propertyName] - @on[propertyName] = value - if value - @webviewNode.addEventListener eventName, value - enumerable: true - - ### Updates state upon loadcommit. ### - onLoadCommit: (webViewEvent) -> - oldValue = @webviewNode.getAttribute webViewConstants.ATTRIBUTE_SRC - newValue = webViewEvent.url - if webViewEvent.isMainFrame and (oldValue != newValue) - ### - Touching the src attribute triggers a navigation. To avoid - triggering a page reload on every guest-initiated navigation, - we do not handle this mutation. - ### - @attributes[webViewConstants.ATTRIBUTE_SRC].setValueIgnoreMutation newValue - - onAttach: (storagePartitionId) -> - @attributes[webViewConstants.ATTRIBUTE_PARTITION].setValue storagePartitionId - - buildParams: -> - params = - instanceId: @viewInstanceId - userAgentOverride: @userAgentOverride - for own attributeName, attribute of @attributes - params[attributeName] = attribute.getValue() - ### - When the WebView is not participating in layout (display:none) - then getBoundingClientRect() would report a width and height of 0. - However, in the case where the WebView has a fixed size we can - use that value to initially size the guest so as to avoid a relayout of - the on display:block. - ### - css = window.getComputedStyle @webviewNode, null - elementRect = @webviewNode.getBoundingClientRect() - params.elementWidth = parseInt(elementRect.width) || - parseInt(css.getPropertyValue('width')) - params.elementHeight = parseInt(elementRect.height) || - parseInt(css.getPropertyValue('height')) - params - - attachWindow: (guestInstanceId) -> - @guestInstanceId = guestInstanceId - @webContents = remote.getGuestWebContents @guestInstanceId - return true unless @internalInstanceId - - guestViewInternal.attachGuest @internalInstanceId, @guestInstanceId, @buildParams() - -### Registers browser plugin custom element. ### -registerBrowserPluginElement = -> - proto = Object.create HTMLObjectElement.prototype - - proto.createdCallback = -> - @setAttribute 'type', 'application/browser-plugin' - @setAttribute 'id', 'browser-plugin-' + getNextId() - ### The node fills in the container. ### - @style.display = 'block' - @style.width = '100%' - @style.height = '100%' - - proto.attributeChangedCallback = (name, oldValue, newValue) -> - internal = v8Util.getHiddenValue this, 'internal' - return unless internal - internal.handleBrowserPluginAttributeMutation name, oldValue, newValue - - proto.attachedCallback = -> - ### Load the plugin immediately. ### - unused = this.nonExistentAttribute - - WebViewImpl.BrowserPlugin = webFrame.registerEmbedderCustomElement 'browserplugin', - extends: 'object', prototype: proto - - delete proto.createdCallback - delete proto.attachedCallback - delete proto.detachedCallback - delete proto.attributeChangedCallback - -### Registers custom element. ### -registerWebViewElement = -> - proto = Object.create HTMLObjectElement.prototype - - proto.createdCallback = -> - new WebViewImpl(this) - - proto.attributeChangedCallback = (name, oldValue, newValue) -> - internal = v8Util.getHiddenValue this, 'internal' - return unless internal - internal.handleWebviewAttributeMutation name, oldValue, newValue - - proto.detachedCallback = -> - internal = v8Util.getHiddenValue this, 'internal' - return unless internal - guestViewInternal.deregisterEvents internal.viewInstanceId - internal.elementAttached = false - internal.reset() - - proto.attachedCallback = -> - internal = v8Util.getHiddenValue this, 'internal' - return unless internal - unless internal.elementAttached - guestViewInternal.registerEvents internal, internal.viewInstanceId - internal.elementAttached = true - internal.attributes[webViewConstants.ATTRIBUTE_SRC].parse() - - ### Public-facing API methods. ### - methods = [ - 'getURL' - 'getTitle' - 'isLoading' - 'isWaitingForResponse' - 'stop' - 'reload' - 'reloadIgnoringCache' - 'canGoBack' - 'canGoForward' - 'canGoToOffset' - 'clearHistory' - 'goBack' - 'goForward' - 'goToIndex' - 'goToOffset' - 'isCrashed' - 'setUserAgent' - 'getUserAgent' - 'openDevTools' - 'closeDevTools' - 'isDevToolsOpened' - 'isDevToolsFocused' - 'inspectElement' - 'setAudioMuted' - 'isAudioMuted' - 'undo' - 'redo' - 'cut' - 'copy' - 'paste' - 'pasteAndMatchStyle' - 'delete' - 'selectAll' - 'unselect' - 'replace' - 'replaceMisspelling' - 'findInPage' - 'stopFindInPage' - 'getId' - 'downloadURL' - 'inspectServiceWorker' - 'print' - 'printToPDF' - ] - - nonblockMethods = [ - 'send', - 'sendInputEvent', - 'executeJavaScript', - 'insertCSS' - ] - - ### Forward proto.foo* method calls to WebViewImpl.foo*. ### - createBlockHandler = (m) -> - (args...) -> - internal = v8Util.getHiddenValue this, 'internal' - internal.webContents[m] args... - proto[m] = createBlockHandler m for m in methods - - createNonBlockHandler = (m) -> - (args...) -> - internal = v8Util.getHiddenValue this, 'internal' - ipcRenderer.send('ATOM_BROWSER_ASYNC_CALL_TO_GUEST_VIEW', internal.guestInstanceId, m, args...) - - proto[m] = createNonBlockHandler m for m in nonblockMethods - - ### Deprecated. ### - deprecate.rename proto, 'getUrl', 'getURL' - - window.WebView = webFrame.registerEmbedderCustomElement 'webview', - prototype: proto - - ### Delete the callbacks so developers cannot call them and produce unexpected ### - ### behavior. ### - delete proto.createdCallback - delete proto.attachedCallback - delete proto.detachedCallback - delete proto.attributeChangedCallback - -useCapture = true -listener = (event) -> - return if document.readyState == 'loading' - registerBrowserPluginElement() - registerWebViewElement() - window.removeEventListener event.type, listener, useCapture -window.addEventListener 'readystatechange', listener, true - -module.exports = WebViewImpl diff --git a/atom/renderer/lib/web-view/web-view.js b/atom/renderer/lib/web-view/web-view.js new file mode 100644 index 000000000000..fcdfad1877ed --- /dev/null +++ b/atom/renderer/lib/web-view/web-view.js @@ -0,0 +1,435 @@ +var WebViewImpl, deprecate, getNextId, guestViewInternal, ipcRenderer, listener, nextId, ref, registerBrowserPluginElement, registerWebViewElement, remote, useCapture, v8Util, webFrame, webViewConstants, + hasProp = {}.hasOwnProperty, + slice = [].slice; + +ref = require('electron'), deprecate = ref.deprecate, webFrame = ref.webFrame, remote = ref.remote, ipcRenderer = ref.ipcRenderer; + +v8Util = process.atomBinding('v8_util'); + +guestViewInternal = require('./guest-view-internal'); + +webViewConstants = require('./web-view-constants'); + + +/* ID generator. */ + +nextId = 0; + +getNextId = function() { + return ++nextId; +}; + + +/* Represents the internal state of the WebView node. */ + +WebViewImpl = (function() { + function WebViewImpl(webviewNode) { + var shadowRoot; + this.webviewNode = webviewNode; + v8Util.setHiddenValue(this.webviewNode, 'internal', this); + this.attached = false; + this.elementAttached = false; + this.beforeFirstNavigation = true; + + /* on* Event handlers. */ + this.on = {}; + this.browserPluginNode = this.createBrowserPluginNode(); + shadowRoot = this.webviewNode.createShadowRoot(); + this.setupWebViewAttributes(); + this.setupFocusPropagation(); + this.viewInstanceId = getNextId(); + shadowRoot.appendChild(this.browserPluginNode); + } + + WebViewImpl.prototype.createBrowserPluginNode = function() { + + /* + We create BrowserPlugin as a custom element in order to observe changes + to attributes synchronously. + */ + var browserPluginNode; + browserPluginNode = new WebViewImpl.BrowserPlugin(); + v8Util.setHiddenValue(browserPluginNode, 'internal', this); + return browserPluginNode; + }; + + + /* Resets some state upon reattaching element to the DOM. */ + + WebViewImpl.prototype.reset = function() { + + /* + If guestInstanceId is defined then the has navigated and has + already picked up a partition ID. Thus, we need to reset the initialization + state. However, it may be the case that beforeFirstNavigation is false BUT + guestInstanceId has yet to be initialized. This means that we have not + heard back from createGuest yet. We will not reset the flag in this case so + that we don't end up allocating a second guest. + */ + if (this.guestInstanceId) { + guestViewInternal.destroyGuest(this.guestInstanceId); + this.webContents = null; + this.guestInstanceId = void 0; + this.beforeFirstNavigation = true; + this.attributes[webViewConstants.ATTRIBUTE_PARTITION].validPartitionId = true; + } + return this.internalInstanceId = 0; + }; + + + /* Sets the .request property. */ + + WebViewImpl.prototype.setRequestPropertyOnWebViewNode = function(request) { + return Object.defineProperty(this.webviewNode, 'request', { + value: request, + enumerable: true + }); + }; + + WebViewImpl.prototype.setupFocusPropagation = function() { + if (!this.webviewNode.hasAttribute('tabIndex')) { + + /* + needs a tabIndex in order to be focusable. + TODO(fsamuel): It would be nice to avoid exposing a tabIndex attribute + to allow to be focusable. + See http://crbug.com/231664. + */ + this.webviewNode.setAttribute('tabIndex', -1); + } + this.webviewNode.addEventListener('focus', (function(_this) { + return function(e) { + + /* Focus the BrowserPlugin when the takes focus. */ + return _this.browserPluginNode.focus(); + }; + })(this)); + return this.webviewNode.addEventListener('blur', (function(_this) { + return function(e) { + + /* Blur the BrowserPlugin when the loses focus. */ + return _this.browserPluginNode.blur(); + }; + })(this)); + }; + + + /* + This observer monitors mutations to attributes of the and + updates the BrowserPlugin properties accordingly. In turn, updating + a BrowserPlugin property will update the corresponding BrowserPlugin + attribute, if necessary. See BrowserPlugin::UpdateDOMAttribute for more + details. + */ + + WebViewImpl.prototype.handleWebviewAttributeMutation = function(attributeName, oldValue, newValue) { + if (!this.attributes[attributeName] || this.attributes[attributeName].ignoreMutation) { + return; + } + + /* Let the changed attribute handle its own mutation; */ + return this.attributes[attributeName].handleMutation(oldValue, newValue); + }; + + WebViewImpl.prototype.handleBrowserPluginAttributeMutation = function(attributeName, oldValue, newValue) { + if (attributeName === webViewConstants.ATTRIBUTE_INTERNALINSTANCEID && !oldValue && !!newValue) { + this.browserPluginNode.removeAttribute(webViewConstants.ATTRIBUTE_INTERNALINSTANCEID); + this.internalInstanceId = parseInt(newValue); + + /* Track when the element resizes using the element resize callback. */ + webFrame.registerElementResizeCallback(this.internalInstanceId, this.onElementResize.bind(this)); + if (!this.guestInstanceId) { + return; + } + return guestViewInternal.attachGuest(this.internalInstanceId, this.guestInstanceId, this.buildParams()); + } + }; + + WebViewImpl.prototype.onSizeChanged = function(webViewEvent) { + var height, maxHeight, maxWidth, minHeight, minWidth, newHeight, newWidth, node, width; + newWidth = webViewEvent.newWidth; + newHeight = webViewEvent.newHeight; + node = this.webviewNode; + width = node.offsetWidth; + height = node.offsetHeight; + + /* Check the current bounds to make sure we do not resize */ + + /* outside of current constraints. */ + maxWidth = this.attributes[webViewConstants.ATTRIBUTE_MAXWIDTH].getValue() | width; + maxHeight = this.attributes[webViewConstants.ATTRIBUTE_MAXHEIGHT].getValue() | width; + minWidth = this.attributes[webViewConstants.ATTRIBUTE_MINWIDTH].getValue() | width; + minHeight = this.attributes[webViewConstants.ATTRIBUTE_MINHEIGHT].getValue() | width; + minWidth = Math.min(minWidth, maxWidth); + minHeight = Math.min(minHeight, maxHeight); + if (!this.attributes[webViewConstants.ATTRIBUTE_AUTOSIZE].getValue() || (newWidth >= minWidth && newWidth <= maxWidth && newHeight >= minHeight && newHeight <= maxHeight)) { + node.style.width = newWidth + 'px'; + node.style.height = newHeight + 'px'; + + /* + Only fire the DOM event if the size of the has actually + changed. + */ + return this.dispatchEvent(webViewEvent); + } + }; + + WebViewImpl.prototype.onElementResize = function(newSize) { + + /* Dispatch the 'resize' event. */ + var resizeEvent; + resizeEvent = new Event('resize', { + bubbles: true + }); + resizeEvent.newWidth = newSize.width; + resizeEvent.newHeight = newSize.height; + this.dispatchEvent(resizeEvent); + if (this.guestInstanceId) { + return guestViewInternal.setSize(this.guestInstanceId, { + normal: newSize + }); + } + }; + + WebViewImpl.prototype.createGuest = function() { + return guestViewInternal.createGuest(this.buildParams(), (function(_this) { + return function(event, guestInstanceId) { + return _this.attachWindow(guestInstanceId); + }; + })(this)); + }; + + WebViewImpl.prototype.dispatchEvent = function(webViewEvent) { + return this.webviewNode.dispatchEvent(webViewEvent); + }; + + + /* Adds an 'on' property on the webview, which can be used to set/unset */ + + + /* an event handler. */ + + WebViewImpl.prototype.setupEventProperty = function(eventName) { + var propertyName; + propertyName = 'on' + eventName.toLowerCase(); + return Object.defineProperty(this.webviewNode, propertyName, { + get: (function(_this) { + return function() { + return _this.on[propertyName]; + }; + })(this), + set: (function(_this) { + return function(value) { + if (_this.on[propertyName]) { + _this.webviewNode.removeEventListener(eventName, _this.on[propertyName]); + } + _this.on[propertyName] = value; + if (value) { + return _this.webviewNode.addEventListener(eventName, value); + } + }; + })(this), + enumerable: true + }); + }; + + + /* Updates state upon loadcommit. */ + + WebViewImpl.prototype.onLoadCommit = function(webViewEvent) { + var newValue, oldValue; + oldValue = this.webviewNode.getAttribute(webViewConstants.ATTRIBUTE_SRC); + newValue = webViewEvent.url; + if (webViewEvent.isMainFrame && (oldValue !== newValue)) { + + /* + Touching the src attribute triggers a navigation. To avoid + triggering a page reload on every guest-initiated navigation, + we do not handle this mutation. + */ + return this.attributes[webViewConstants.ATTRIBUTE_SRC].setValueIgnoreMutation(newValue); + } + }; + + WebViewImpl.prototype.onAttach = function(storagePartitionId) { + return this.attributes[webViewConstants.ATTRIBUTE_PARTITION].setValue(storagePartitionId); + }; + + WebViewImpl.prototype.buildParams = function() { + var attribute, attributeName, css, elementRect, params, ref1; + params = { + instanceId: this.viewInstanceId, + userAgentOverride: this.userAgentOverride + }; + ref1 = this.attributes; + for (attributeName in ref1) { + if (!hasProp.call(ref1, attributeName)) continue; + attribute = ref1[attributeName]; + params[attributeName] = attribute.getValue(); + } + + /* + When the WebView is not participating in layout (display:none) + then getBoundingClientRect() would report a width and height of 0. + However, in the case where the WebView has a fixed size we can + use that value to initially size the guest so as to avoid a relayout of + the on display:block. + */ + css = window.getComputedStyle(this.webviewNode, null); + elementRect = this.webviewNode.getBoundingClientRect(); + params.elementWidth = parseInt(elementRect.width) || parseInt(css.getPropertyValue('width')); + params.elementHeight = parseInt(elementRect.height) || parseInt(css.getPropertyValue('height')); + return params; + }; + + WebViewImpl.prototype.attachWindow = function(guestInstanceId) { + this.guestInstanceId = guestInstanceId; + this.webContents = remote.getGuestWebContents(this.guestInstanceId); + if (!this.internalInstanceId) { + return true; + } + return guestViewInternal.attachGuest(this.internalInstanceId, this.guestInstanceId, this.buildParams()); + }; + + return WebViewImpl; + +})(); + + +/* Registers browser plugin custom element. */ + +registerBrowserPluginElement = function() { + var proto; + proto = Object.create(HTMLObjectElement.prototype); + proto.createdCallback = function() { + this.setAttribute('type', 'application/browser-plugin'); + this.setAttribute('id', 'browser-plugin-' + getNextId()); + + /* The node fills in the container. */ + this.style.display = 'block'; + this.style.width = '100%'; + return this.style.height = '100%'; + }; + proto.attributeChangedCallback = function(name, oldValue, newValue) { + var internal; + internal = v8Util.getHiddenValue(this, 'internal'); + if (!internal) { + return; + } + return internal.handleBrowserPluginAttributeMutation(name, oldValue, newValue); + }; + proto.attachedCallback = function() { + + /* Load the plugin immediately. */ + var unused; + return unused = this.nonExistentAttribute; + }; + WebViewImpl.BrowserPlugin = webFrame.registerEmbedderCustomElement('browserplugin', { + "extends": 'object', + prototype: proto + }); + delete proto.createdCallback; + delete proto.attachedCallback; + delete proto.detachedCallback; + return delete proto.attributeChangedCallback; +}; + + +/* Registers custom element. */ + +registerWebViewElement = function() { + var createBlockHandler, createNonBlockHandler, i, j, len, len1, m, methods, nonblockMethods, proto; + proto = Object.create(HTMLObjectElement.prototype); + proto.createdCallback = function() { + return new WebViewImpl(this); + }; + proto.attributeChangedCallback = function(name, oldValue, newValue) { + var internal; + internal = v8Util.getHiddenValue(this, 'internal'); + if (!internal) { + return; + } + return internal.handleWebviewAttributeMutation(name, oldValue, newValue); + }; + proto.detachedCallback = function() { + var internal; + internal = v8Util.getHiddenValue(this, 'internal'); + if (!internal) { + return; + } + guestViewInternal.deregisterEvents(internal.viewInstanceId); + internal.elementAttached = false; + return internal.reset(); + }; + proto.attachedCallback = function() { + var internal; + internal = v8Util.getHiddenValue(this, 'internal'); + if (!internal) { + return; + } + if (!internal.elementAttached) { + guestViewInternal.registerEvents(internal, internal.viewInstanceId); + internal.elementAttached = true; + return internal.attributes[webViewConstants.ATTRIBUTE_SRC].parse(); + } + }; + + /* Public-facing API methods. */ + methods = ['getURL', 'getTitle', 'isLoading', 'isWaitingForResponse', 'stop', 'reload', 'reloadIgnoringCache', 'canGoBack', 'canGoForward', 'canGoToOffset', 'clearHistory', 'goBack', 'goForward', 'goToIndex', 'goToOffset', 'isCrashed', 'setUserAgent', 'getUserAgent', 'openDevTools', 'closeDevTools', 'isDevToolsOpened', 'isDevToolsFocused', 'inspectElement', 'setAudioMuted', 'isAudioMuted', 'undo', 'redo', 'cut', 'copy', 'paste', 'pasteAndMatchStyle', 'delete', 'selectAll', 'unselect', 'replace', 'replaceMisspelling', 'findInPage', 'stopFindInPage', 'getId', 'downloadURL', 'inspectServiceWorker', 'print', 'printToPDF']; + nonblockMethods = ['send', 'sendInputEvent', 'executeJavaScript', 'insertCSS']; + + /* Forward proto.foo* method calls to WebViewImpl.foo*. */ + createBlockHandler = function(m) { + return function() { + var args, internal, ref1; + args = 1 <= arguments.length ? slice.call(arguments, 0) : []; + internal = v8Util.getHiddenValue(this, 'internal'); + return (ref1 = internal.webContents)[m].apply(ref1, args); + }; + }; + for (i = 0, len = methods.length; i < len; i++) { + m = methods[i]; + proto[m] = createBlockHandler(m); + } + createNonBlockHandler = function(m) { + return function() { + var args, internal; + args = 1 <= arguments.length ? slice.call(arguments, 0) : []; + internal = v8Util.getHiddenValue(this, 'internal'); + return ipcRenderer.send.apply(ipcRenderer, ['ATOM_BROWSER_ASYNC_CALL_TO_GUEST_VIEW', internal.guestInstanceId, m].concat(slice.call(args))); + }; + }; + for (j = 0, len1 = nonblockMethods.length; j < len1; j++) { + m = nonblockMethods[j]; + proto[m] = createNonBlockHandler(m); + } + + /* Deprecated. */ + deprecate.rename(proto, 'getUrl', 'getURL'); + window.WebView = webFrame.registerEmbedderCustomElement('webview', { + prototype: proto + }); + + /* Delete the callbacks so developers cannot call them and produce unexpected */ + + /* behavior. */ + delete proto.createdCallback; + delete proto.attachedCallback; + delete proto.detachedCallback; + return delete proto.attributeChangedCallback; +}; + +useCapture = true; + +listener = function(event) { + if (document.readyState === 'loading') { + return; + } + registerBrowserPluginElement(); + registerWebViewElement(); + return window.removeEventListener(event.type, listener, useCapture); +}; + +window.addEventListener('readystatechange', listener, true); + +module.exports = WebViewImpl; diff --git a/spec/api-app-spec.coffee b/spec/api-app-spec.coffee deleted file mode 100644 index 5e6bca82091f..000000000000 --- a/spec/api-app-spec.coffee +++ /dev/null @@ -1,80 +0,0 @@ -assert = require 'assert' -ChildProcess = require 'child_process' -path = require 'path' -{remote} = require 'electron' -{app, BrowserWindow} = remote.require 'electron' - -describe 'app module', -> - describe 'app.getVersion()', -> - it 'returns the version field of package.json', -> - assert.equal app.getVersion(), '0.1.0' - - describe 'app.setVersion(version)', -> - it 'overrides the version', -> - assert.equal app.getVersion(), '0.1.0' - app.setVersion 'test-version' - assert.equal app.getVersion(), 'test-version' - app.setVersion '0.1.0' - - describe 'app.getName()', -> - it 'returns the name field of package.json', -> - assert.equal app.getName(), 'Electron Test' - - describe 'app.setName(name)', -> - it 'overrides the name', -> - assert.equal app.getName(), 'Electron Test' - app.setName 'test-name' - assert.equal app.getName(), 'test-name' - app.setName 'Electron Test' - - describe 'app.getLocale()', -> - it 'should not be empty', -> - assert.notEqual app.getLocale(), '' - - describe 'app.exit(exitCode)', -> - appProcess = null - afterEach -> - appProcess?.kill() - - it 'emits a process exit event with the code', (done) -> - appPath = path.join(__dirname, 'fixtures', 'api', 'quit-app') - electronPath = remote.getGlobal('process').execPath - appProcess = ChildProcess.spawn(electronPath, [appPath]) - - output = '' - appProcess.stdout.on 'data', (data) -> output += data - appProcess.on 'close', (code) -> - # We skip the following assert on Windows, since we can't currently get - # stdout from a spawned electron process on Windows - if process.platform isnt 'win32' - assert.notEqual output.indexOf('Exit event with code: 123'), -1 - assert.equal code, 123 - done() - - describe 'BrowserWindow events', -> - w = null - afterEach -> - w.destroy() if w? - w = null - - it 'should emit browser-window-focus event when window is focused', (done) -> - app.once 'browser-window-focus', (e, window) -> - assert.equal w.id, window.id - done() - w = new BrowserWindow(show: false) - w.emit 'focus' - - it 'should emit browser-window-blur event when window is blured', (done) -> - app.once 'browser-window-blur', (e, window) -> - assert.equal w.id, window.id - done() - w = new BrowserWindow(show: false) - w.emit 'blur' - - it 'should emit browser-window-created event when window is created', (done) -> - app.once 'browser-window-created', (e, window) -> - setImmediate -> - assert.equal w.id, window.id - done() - w = new BrowserWindow(show: false) - w.emit 'blur' diff --git a/spec/api-app-spec.js b/spec/api-app-spec.js new file mode 100644 index 000000000000..dafaf44a2d15 --- /dev/null +++ b/spec/api-app-spec.js @@ -0,0 +1,111 @@ +var BrowserWindow, ChildProcess, app, assert, path, ref, remote; + +assert = require('assert'); + +ChildProcess = require('child_process'); + +path = require('path'); + +remote = require('electron').remote; + +ref = remote.require('electron'), app = ref.app, BrowserWindow = ref.BrowserWindow; + +describe('app module', function() { + describe('app.getVersion()', function() { + return it('returns the version field of package.json', function() { + return assert.equal(app.getVersion(), '0.1.0'); + }); + }); + describe('app.setVersion(version)', function() { + return it('overrides the version', function() { + assert.equal(app.getVersion(), '0.1.0'); + app.setVersion('test-version'); + assert.equal(app.getVersion(), 'test-version'); + return app.setVersion('0.1.0'); + }); + }); + describe('app.getName()', function() { + return it('returns the name field of package.json', function() { + return assert.equal(app.getName(), 'Electron Test'); + }); + }); + describe('app.setName(name)', function() { + return it('overrides the name', function() { + assert.equal(app.getName(), 'Electron Test'); + app.setName('test-name'); + assert.equal(app.getName(), 'test-name'); + return app.setName('Electron Test'); + }); + }); + describe('app.getLocale()', function() { + return it('should not be empty', function() { + return assert.notEqual(app.getLocale(), ''); + }); + }); + describe('app.exit(exitCode)', function() { + var appProcess; + appProcess = null; + afterEach(function() { + return appProcess != null ? appProcess.kill() : void 0; + }); + return it('emits a process exit event with the code', function(done) { + var appPath, electronPath, output; + appPath = path.join(__dirname, 'fixtures', 'api', 'quit-app'); + electronPath = remote.getGlobal('process').execPath; + appProcess = ChildProcess.spawn(electronPath, [appPath]); + output = ''; + appProcess.stdout.on('data', function(data) { + return output += data; + }); + return appProcess.on('close', function(code) { + if (process.platform !== 'win32') { + assert.notEqual(output.indexOf('Exit event with code: 123'), -1); + } + assert.equal(code, 123); + return done(); + }); + }); + }); + return describe('BrowserWindow events', function() { + var w; + w = null; + afterEach(function() { + if (w != null) { + w.destroy(); + } + return w = null; + }); + it('should emit browser-window-focus event when window is focused', function(done) { + app.once('browser-window-focus', function(e, window) { + assert.equal(w.id, window.id); + return done(); + }); + w = new BrowserWindow({ + show: false + }); + return w.emit('focus'); + }); + it('should emit browser-window-blur event when window is blured', function(done) { + app.once('browser-window-blur', function(e, window) { + assert.equal(w.id, window.id); + return done(); + }); + w = new BrowserWindow({ + show: false + }); + return w.emit('blur'); + }); + return it('should emit browser-window-created event when window is created', function(done) { + app.once('browser-window-created', function(e, window) { + return setImmediate(function() { + assert.equal(w.id, window.id); + return done(); + }); + }); + w = new BrowserWindow({ + show: false + }); + return w.emit('blur'); + }); + }); +}); diff --git a/spec/api-browser-window-spec.coffee b/spec/api-browser-window-spec.coffee deleted file mode 100644 index 724f149cd9e5..000000000000 --- a/spec/api-browser-window-spec.coffee +++ /dev/null @@ -1,339 +0,0 @@ -assert = require 'assert' -fs = require 'fs' -path = require 'path' -http = require 'http' -url = require 'url' -os = require 'os' - -{remote, screen} = require 'electron' -{ipcMain, BrowserWindow} = remote.require 'electron' - -isCI = remote.getGlobal('isCi') - -describe 'browser-window module', -> - fixtures = path.resolve __dirname, 'fixtures' - - w = null - beforeEach -> - w.destroy() if w? - w = new BrowserWindow(show: false, width: 400, height: 400) - afterEach -> - w.destroy() if w? - w = null - - describe 'BrowserWindow.close()', -> - it 'should emit unload handler', (done) -> - w.webContents.on 'did-finish-load', -> - w.close() - w.on 'closed', -> - test = path.join(fixtures, 'api', 'unload') - content = fs.readFileSync(test) - fs.unlinkSync(test) - assert.equal String(content), 'unload' - done() - w.loadURL 'file://' + path.join(fixtures, 'api', 'unload.html') - - it 'should emit beforeunload handler', (done) -> - w.on 'onbeforeunload', -> - done() - w.webContents.on 'did-finish-load', -> - w.close() - w.loadURL 'file://' + path.join(fixtures, 'api', 'beforeunload-false.html') - - describe 'window.close()', -> - it 'should emit unload handler', (done) -> - w.on 'closed', -> - test = path.join(fixtures, 'api', 'close') - content = fs.readFileSync(test) - fs.unlinkSync(test) - assert.equal String(content), 'close' - done() - w.loadURL 'file://' + path.join(fixtures, 'api', 'close.html') - - it 'should emit beforeunload handler', (done) -> - w.on 'onbeforeunload', -> - done() - w.loadURL 'file://' + path.join(fixtures, 'api', 'close-beforeunload-false.html') - - describe 'BrowserWindow.destroy()', -> - it 'prevents users to access methods of webContents', -> - webContents = w.webContents - w.destroy() - assert.throws (-> webContents.getId()), /Object has been destroyed/ - - describe 'BrowserWindow.loadURL(url)', -> - it 'should emit did-start-loading event', (done) -> - w.webContents.on 'did-start-loading', -> - done() - w.loadURL 'about:blank' - - it 'should emit did-fail-load event', (done) -> - w.webContents.on 'did-fail-load', -> - done() - w.loadURL 'file://a.txt' - - describe 'BrowserWindow.show()', -> - it 'should focus on window', -> - return if isCI - w.show() - assert w.isFocused() - - describe 'BrowserWindow.showInactive()', -> - it 'should not focus on window', -> - w.showInactive() - assert !w.isFocused() - - describe 'BrowserWindow.focus()', -> - it 'does not make the window become visible', -> - assert.equal w.isVisible(), false - w.focus() - assert.equal w.isVisible(), false - - describe 'BrowserWindow.capturePage(rect, callback)', -> - it 'calls the callback with a Buffer', (done) -> - w.capturePage {x: 0, y: 0, width: 100, height: 100}, (image) -> - assert.equal image.isEmpty(), true - done() - - describe 'BrowserWindow.setSize(width, height)', -> - it 'sets the window size', (done) -> - size = [300, 400] - w.once 'resize', -> - newSize = w.getSize() - assert.equal newSize[0], size[0] - assert.equal newSize[1], size[1] - done() - w.setSize size[0], size[1] - - describe 'BrowserWindow.setPosition(x, y)', -> - it 'sets the window position', (done) -> - pos = [10, 10] - w.once 'move', -> - newPos = w.getPosition() - assert.equal newPos[0], pos[0] - assert.equal newPos[1], pos[1] - done() - w.setPosition pos[0], pos[1] - - describe 'BrowserWindow.setContentSize(width, height)', -> - it 'sets the content size', -> - size = [400, 400] - w.setContentSize size[0], size[1] - after = w.getContentSize() - assert.equal after[0], size[0] - assert.equal after[1], size[1] - - it 'works for framless window', -> - w.destroy() - w = new BrowserWindow(show: false, frame: false, width: 400, height: 400) - size = [400, 400] - w.setContentSize size[0], size[1] - after = w.getContentSize() - assert.equal after[0], size[0] - assert.equal after[1], size[1] - - describe 'BrowserWindow.fromId(id)', -> - it 'returns the window with id', -> - assert.equal w.id, BrowserWindow.fromId(w.id).id - - describe 'BrowserWindow.setResizable(resizable)', -> - it 'does not change window size for frameless window', -> - w.destroy() - w = new BrowserWindow(show: true, frame: false) - s = w.getSize() - w.setResizable not w.isResizable() - assert.deepEqual s, w.getSize() - - describe '"useContentSize" option', -> - it 'make window created with content size when used', -> - w.destroy() - w = new BrowserWindow(show: false, width: 400, height: 400, useContentSize: true) - contentSize = w.getContentSize() - assert.equal contentSize[0], 400 - assert.equal contentSize[1], 400 - - it 'make window created with window size when not used', -> - size = w.getSize() - assert.equal size[0], 400 - assert.equal size[1], 400 - - it 'works for framless window', -> - w.destroy() - w = new BrowserWindow(show: false, frame: false, width: 400, height: 400, useContentSize: true) - contentSize = w.getContentSize() - assert.equal contentSize[0], 400 - assert.equal contentSize[1], 400 - size = w.getSize() - assert.equal size[0], 400 - assert.equal size[1], 400 - - describe '"title-bar-style" option', -> - return if process.platform isnt 'darwin' - return if parseInt(os.release().split('.')[0]) < 14 # only run these tests on Yosemite or newer - - it 'creates browser window with hidden title bar', -> - w.destroy() - w = new BrowserWindow(show: false, width: 400, height: 400, titleBarStyle: 'hidden') - contentSize = w.getContentSize() - assert.equal contentSize[1], 400 - - it 'creates browser window with hidden inset title bar', -> - w.destroy() - w = new BrowserWindow(show: false, width: 400, height: 400, titleBarStyle: 'hidden-inset') - contentSize = w.getContentSize() - assert.equal contentSize[1], 400 - - describe '"enableLargerThanScreen" option', -> - return if process.platform is 'linux' - - beforeEach -> - w.destroy() - w = new BrowserWindow(show: true, width: 400, height: 400, enableLargerThanScreen: true) - - it 'can move the window out of screen', -> - w.setPosition -10, -10 - after = w.getPosition() - assert.equal after[0], -10 - assert.equal after[1], -10 - - it 'can set the window larger than screen', -> - size = screen.getPrimaryDisplay().size - size.width += 100 - size.height += 100 - w.setSize size.width, size.height - after = w.getSize() - assert.equal after[0], size.width - assert.equal after[1], size.height - - describe '"web-preferences" option', -> - afterEach -> - ipcMain.removeAllListeners('answer') - - describe '"preload" option', -> - it 'loads the script before other scripts in window', (done) -> - preload = path.join fixtures, 'module', 'set-global.js' - ipcMain.once 'answer', (event, test) -> - assert.equal(test, 'preload') - done() - w.destroy() - w = new BrowserWindow - show: false - webPreferences: - preload: preload - w.loadURL 'file://' + path.join(fixtures, 'api', 'preload.html') - - describe '"node-integration" option', -> - it 'disables node integration when specified to false', (done) -> - preload = path.join fixtures, 'module', 'send-later.js' - ipcMain.once 'answer', (event, test) -> - assert.equal(test, 'undefined') - done() - w.destroy() - w = new BrowserWindow - show: false - webPreferences: - preload: preload - nodeIntegration: false - w.loadURL 'file://' + path.join(fixtures, 'api', 'blank.html') - - describe 'beforeunload handler', -> - it 'returning true would not prevent close', (done) -> - w.on 'closed', -> - done() - w.loadURL 'file://' + path.join(fixtures, 'api', 'close-beforeunload-true.html') - - it 'returning non-empty string would not prevent close', (done) -> - w.on 'closed', -> - done() - w.loadURL 'file://' + path.join(fixtures, 'api', 'close-beforeunload-string.html') - - it 'returning false would prevent close', (done) -> - w.on 'onbeforeunload', -> - done() - w.loadURL 'file://' + path.join(fixtures, 'api', 'close-beforeunload-false.html') - - it 'returning empty string would prevent close', (done) -> - w.on 'onbeforeunload', -> - done() - w.loadURL 'file://' + path.join(fixtures, 'api', 'close-beforeunload-empty-string.html') - - describe 'new-window event', -> - return if isCI and process.platform is 'darwin' - it 'emits when window.open is called', (done) -> - w.webContents.once 'new-window', (e, url, frameName) -> - e.preventDefault() - assert.equal url, 'http://host/' - assert.equal frameName, 'host' - done() - 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/' - assert.equal frameName, 'target' - done() - w.loadURL "file://#{fixtures}/pages/target-name.html" - - describe 'maximize event', -> - return if isCI - it 'emits when window is maximized', (done) -> - @timeout 10000 - w.once 'maximize', -> done() - w.show() - w.maximize() - - describe 'unmaximize event', -> - return if isCI - it 'emits when window is unmaximized', (done) -> - @timeout 10000 - w.once 'unmaximize', -> done() - w.show() - w.maximize() - w.unmaximize() - - describe 'minimize event', -> - return if isCI - it 'emits when window is minimized', (done) -> - @timeout 10000 - w.once 'minimize', -> done() - w.show() - w.minimize() - - xdescribe 'beginFrameSubscription method', -> - it 'subscribes frame updates', (done) -> - w.loadURL "file://#{fixtures}/api/blank.html" - w.webContents.beginFrameSubscription (data) -> - assert.notEqual data.length, 0 - w.webContents.endFrameSubscription() - done() - - describe 'save page', -> - savePageDir = path.join fixtures, 'save_page' - savePageHtmlPath = path.join savePageDir, 'save_page.html' - savePageJsPath = path.join savePageDir, 'save_page_files', 'test.js' - savePageCssPath = path.join savePageDir, 'save_page_files', 'test.css' - it 'should save page', (done) -> - w.webContents.on 'did-finish-load', -> - w.webContents.savePage savePageHtmlPath, 'HTMLComplete', (error) -> - assert.equal error, null - assert fs.existsSync savePageHtmlPath - assert fs.existsSync savePageJsPath - assert fs.existsSync savePageCssPath - fs.unlinkSync savePageCssPath - fs.unlinkSync savePageJsPath - fs.unlinkSync savePageHtmlPath - fs.rmdirSync path.join savePageDir, 'save_page_files' - fs.rmdirSync savePageDir - done() - - w.loadURL "file://#{fixtures}/pages/save_page/index.html" - - describe 'BrowserWindow options argument is optional', -> - it 'should create a window with default size (800x600)', -> - w.destroy() - w = new BrowserWindow() - size = w.getSize() - assert.equal size[0], 800 - assert.equal size[1], 600 diff --git a/spec/api-browser-window-spec.js b/spec/api-browser-window-spec.js new file mode 100644 index 000000000000..432c9a739cde --- /dev/null +++ b/spec/api-browser-window-spec.js @@ -0,0 +1,492 @@ +var BrowserWindow, assert, fs, http, ipcMain, isCI, os, path, ref, ref1, remote, screen, url; + +assert = require('assert'); + +fs = require('fs'); + +path = require('path'); + +http = require('http'); + +url = require('url'); + +os = require('os'); + +ref = require('electron'), remote = ref.remote, screen = ref.screen; + +ref1 = remote.require('electron'), ipcMain = ref1.ipcMain, BrowserWindow = ref1.BrowserWindow; + +isCI = remote.getGlobal('isCi'); + +describe('browser-window module', function() { + var fixtures, w; + fixtures = path.resolve(__dirname, 'fixtures'); + w = null; + beforeEach(function() { + if (w != null) { + w.destroy(); + } + return w = new BrowserWindow({ + show: false, + width: 400, + height: 400 + }); + }); + afterEach(function() { + if (w != null) { + w.destroy(); + } + return w = null; + }); + describe('BrowserWindow.close()', function() { + it('should emit unload handler', function(done) { + w.webContents.on('did-finish-load', function() { + return w.close(); + }); + w.on('closed', function() { + var content, test; + test = path.join(fixtures, 'api', 'unload'); + content = fs.readFileSync(test); + fs.unlinkSync(test); + assert.equal(String(content), 'unload'); + return done(); + }); + return w.loadURL('file://' + path.join(fixtures, 'api', 'unload.html')); + }); + return it('should emit beforeunload handler', function(done) { + w.on('onbeforeunload', function() { + return done(); + }); + w.webContents.on('did-finish-load', function() { + return w.close(); + }); + return w.loadURL('file://' + path.join(fixtures, 'api', 'beforeunload-false.html')); + }); + }); + describe('window.close()', function() { + it('should emit unload handler', function(done) { + w.on('closed', function() { + var content, test; + test = path.join(fixtures, 'api', 'close'); + content = fs.readFileSync(test); + fs.unlinkSync(test); + assert.equal(String(content), 'close'); + return done(); + }); + return w.loadURL('file://' + path.join(fixtures, 'api', 'close.html')); + }); + return it('should emit beforeunload handler', function(done) { + w.on('onbeforeunload', function() { + return done(); + }); + return w.loadURL('file://' + path.join(fixtures, 'api', 'close-beforeunload-false.html')); + }); + }); + describe('BrowserWindow.destroy()', function() { + return it('prevents users to access methods of webContents', function() { + var webContents; + webContents = w.webContents; + w.destroy(); + return assert.throws((function() { + return webContents.getId(); + }), /Object has been destroyed/); + }); + }); + describe('BrowserWindow.loadURL(url)', function() { + it('should emit did-start-loading event', function(done) { + w.webContents.on('did-start-loading', function() { + return done(); + }); + return w.loadURL('about:blank'); + }); + return it('should emit did-fail-load event', function(done) { + w.webContents.on('did-fail-load', function() { + return done(); + }); + return w.loadURL('file://a.txt'); + }); + }); + describe('BrowserWindow.show()', function() { + return it('should focus on window', function() { + if (isCI) { + return; + } + w.show(); + return assert(w.isFocused()); + }); + }); + describe('BrowserWindow.showInactive()', function() { + return it('should not focus on window', function() { + w.showInactive(); + return assert(!w.isFocused()); + }); + }); + describe('BrowserWindow.focus()', function() { + return it('does not make the window become visible', function() { + assert.equal(w.isVisible(), false); + w.focus(); + return assert.equal(w.isVisible(), false); + }); + }); + describe('BrowserWindow.capturePage(rect, callback)', function() { + return it('calls the callback with a Buffer', function(done) { + return w.capturePage({ + x: 0, + y: 0, + width: 100, + height: 100 + }, function(image) { + assert.equal(image.isEmpty(), true); + return done(); + }); + }); + }); + describe('BrowserWindow.setSize(width, height)', function() { + return it('sets the window size', function(done) { + var size; + size = [300, 400]; + w.once('resize', function() { + var newSize; + newSize = w.getSize(); + assert.equal(newSize[0], size[0]); + assert.equal(newSize[1], size[1]); + return done(); + }); + return w.setSize(size[0], size[1]); + }); + }); + describe('BrowserWindow.setPosition(x, y)', function() { + return it('sets the window position', function(done) { + var pos; + pos = [10, 10]; + w.once('move', function() { + var newPos; + newPos = w.getPosition(); + assert.equal(newPos[0], pos[0]); + assert.equal(newPos[1], pos[1]); + return done(); + }); + return w.setPosition(pos[0], pos[1]); + }); + }); + describe('BrowserWindow.setContentSize(width, height)', function() { + it('sets the content size', function() { + var after, size; + size = [400, 400]; + w.setContentSize(size[0], size[1]); + after = w.getContentSize(); + assert.equal(after[0], size[0]); + return assert.equal(after[1], size[1]); + }); + return it('works for framless window', function() { + var after, size; + w.destroy(); + w = new BrowserWindow({ + show: false, + frame: false, + width: 400, + height: 400 + }); + size = [400, 400]; + w.setContentSize(size[0], size[1]); + after = w.getContentSize(); + assert.equal(after[0], size[0]); + return assert.equal(after[1], size[1]); + }); + }); + describe('BrowserWindow.fromId(id)', function() { + return it('returns the window with id', function() { + return assert.equal(w.id, BrowserWindow.fromId(w.id).id); + }); + }); + describe('BrowserWindow.setResizable(resizable)', function() { + return it('does not change window size for frameless window', function() { + var s; + w.destroy(); + w = new BrowserWindow({ + show: true, + frame: false + }); + s = w.getSize(); + w.setResizable(!w.isResizable()); + return assert.deepEqual(s, w.getSize()); + }); + }); + describe('"useContentSize" option', function() { + it('make window created with content size when used', function() { + var contentSize; + w.destroy(); + w = new BrowserWindow({ + show: false, + width: 400, + height: 400, + useContentSize: true + }); + contentSize = w.getContentSize(); + assert.equal(contentSize[0], 400); + return assert.equal(contentSize[1], 400); + }); + it('make window created with window size when not used', function() { + var size; + size = w.getSize(); + assert.equal(size[0], 400); + return assert.equal(size[1], 400); + }); + return it('works for framless window', function() { + var contentSize, size; + w.destroy(); + w = new BrowserWindow({ + show: false, + frame: false, + width: 400, + height: 400, + useContentSize: true + }); + contentSize = w.getContentSize(); + assert.equal(contentSize[0], 400); + assert.equal(contentSize[1], 400); + size = w.getSize(); + assert.equal(size[0], 400); + return assert.equal(size[1], 400); + }); + }); + describe('"title-bar-style" option', function() { + if (process.platform !== 'darwin') { + return; + } + if (parseInt(os.release().split('.')[0]) < 14) { + return; + } + it('creates browser window with hidden title bar', function() { + var contentSize; + w.destroy(); + w = new BrowserWindow({ + show: false, + width: 400, + height: 400, + titleBarStyle: 'hidden' + }); + contentSize = w.getContentSize(); + return assert.equal(contentSize[1], 400); + }); + return it('creates browser window with hidden inset title bar', function() { + var contentSize; + w.destroy(); + w = new BrowserWindow({ + show: false, + width: 400, + height: 400, + titleBarStyle: 'hidden-inset' + }); + contentSize = w.getContentSize(); + return assert.equal(contentSize[1], 400); + }); + }); + describe('"enableLargerThanScreen" option', function() { + if (process.platform === 'linux') { + return; + } + beforeEach(function() { + w.destroy(); + return w = new BrowserWindow({ + show: true, + width: 400, + height: 400, + enableLargerThanScreen: true + }); + }); + it('can move the window out of screen', function() { + var after; + w.setPosition(-10, -10); + after = w.getPosition(); + assert.equal(after[0], -10); + return assert.equal(after[1], -10); + }); + return it('can set the window larger than screen', function() { + var after, size; + size = screen.getPrimaryDisplay().size; + size.width += 100; + size.height += 100; + w.setSize(size.width, size.height); + after = w.getSize(); + assert.equal(after[0], size.width); + return assert.equal(after[1], size.height); + }); + }); + describe('"web-preferences" option', function() { + afterEach(function() { + return ipcMain.removeAllListeners('answer'); + }); + describe('"preload" option', function() { + return it('loads the script before other scripts in window', function(done) { + var preload; + preload = path.join(fixtures, 'module', 'set-global.js'); + ipcMain.once('answer', function(event, test) { + assert.equal(test, 'preload'); + return done(); + }); + w.destroy(); + w = new BrowserWindow({ + show: false, + webPreferences: { + preload: preload + } + }); + return w.loadURL('file://' + path.join(fixtures, 'api', 'preload.html')); + }); + }); + return describe('"node-integration" option', function() { + return it('disables node integration when specified to false', function(done) { + var preload; + preload = path.join(fixtures, 'module', 'send-later.js'); + ipcMain.once('answer', function(event, test) { + assert.equal(test, 'undefined'); + return done(); + }); + w.destroy(); + w = new BrowserWindow({ + show: false, + webPreferences: { + preload: preload, + nodeIntegration: false + } + }); + return w.loadURL('file://' + path.join(fixtures, 'api', 'blank.html')); + }); + }); + }); + describe('beforeunload handler', function() { + it('returning true would not prevent close', function(done) { + w.on('closed', function() { + return done(); + }); + return w.loadURL('file://' + path.join(fixtures, 'api', 'close-beforeunload-true.html')); + }); + it('returning non-empty string would not prevent close', function(done) { + w.on('closed', function() { + return done(); + }); + return w.loadURL('file://' + path.join(fixtures, 'api', 'close-beforeunload-string.html')); + }); + it('returning false would prevent close', function(done) { + w.on('onbeforeunload', function() { + return done(); + }); + return w.loadURL('file://' + path.join(fixtures, 'api', 'close-beforeunload-false.html')); + }); + return it('returning empty string would prevent close', function(done) { + w.on('onbeforeunload', function() { + return done(); + }); + return w.loadURL('file://' + path.join(fixtures, 'api', 'close-beforeunload-empty-string.html')); + }); + }); + describe('new-window event', function() { + if (isCI && process.platform === 'darwin') { + return; + } + it('emits when window.open is called', function(done) { + w.webContents.once('new-window', function(e, url, frameName) { + e.preventDefault(); + assert.equal(url, 'http://host/'); + assert.equal(frameName, 'host'); + return done(); + }); + return w.loadURL("file://" + fixtures + "/pages/window-open.html"); + }); + return it('emits when link with target is called', function(done) { + this.timeout(10000); + w.webContents.once('new-window', function(e, url, frameName) { + e.preventDefault(); + assert.equal(url, 'http://host/'); + assert.equal(frameName, 'target'); + return done(); + }); + return w.loadURL("file://" + fixtures + "/pages/target-name.html"); + }); + }); + describe('maximize event', function() { + if (isCI) { + return; + } + return it('emits when window is maximized', function(done) { + this.timeout(10000); + w.once('maximize', function() { + return done(); + }); + w.show(); + return w.maximize(); + }); + }); + describe('unmaximize event', function() { + if (isCI) { + return; + } + return it('emits when window is unmaximized', function(done) { + this.timeout(10000); + w.once('unmaximize', function() { + return done(); + }); + w.show(); + w.maximize(); + return w.unmaximize(); + }); + }); + describe('minimize event', function() { + if (isCI) { + return; + } + return it('emits when window is minimized', function(done) { + this.timeout(10000); + w.once('minimize', function() { + return done(); + }); + w.show(); + return w.minimize(); + }); + }); + xdescribe('beginFrameSubscription method', function() { + return it('subscribes frame updates', function(done) { + w.loadURL("file://" + fixtures + "/api/blank.html"); + return w.webContents.beginFrameSubscription(function(data) { + assert.notEqual(data.length, 0); + w.webContents.endFrameSubscription(); + return done(); + }); + }); + }); + describe('save page', function() { + var savePageCssPath, savePageDir, savePageHtmlPath, savePageJsPath; + savePageDir = path.join(fixtures, 'save_page'); + savePageHtmlPath = path.join(savePageDir, 'save_page.html'); + savePageJsPath = path.join(savePageDir, 'save_page_files', 'test.js'); + savePageCssPath = path.join(savePageDir, 'save_page_files', 'test.css'); + return it('should save page', function(done) { + w.webContents.on('did-finish-load', function() { + return w.webContents.savePage(savePageHtmlPath, 'HTMLComplete', function(error) { + assert.equal(error, null); + assert(fs.existsSync(savePageHtmlPath)); + assert(fs.existsSync(savePageJsPath)); + assert(fs.existsSync(savePageCssPath)); + fs.unlinkSync(savePageCssPath); + fs.unlinkSync(savePageJsPath); + fs.unlinkSync(savePageHtmlPath); + fs.rmdirSync(path.join(savePageDir, 'save_page_files')); + fs.rmdirSync(savePageDir); + return done(); + }); + }); + return w.loadURL("file://" + fixtures + "/pages/save_page/index.html"); + }); + }); + return describe('BrowserWindow options argument is optional', function() { + return it('should create a window with default size (800x600)', function() { + var size; + w.destroy(); + w = new BrowserWindow(); + size = w.getSize(); + assert.equal(size[0], 800); + return assert.equal(size[1], 600); + }); + }); +}); diff --git a/spec/api-clipboard-spec.coffee b/spec/api-clipboard-spec.coffee deleted file mode 100644 index 19da3fc75f1b..000000000000 --- a/spec/api-clipboard-spec.coffee +++ /dev/null @@ -1,52 +0,0 @@ -assert = require 'assert' -path = require 'path' - -{clipboard, nativeImage} = require 'electron' - -describe 'clipboard module', -> - fixtures = path.resolve __dirname, 'fixtures' - - describe 'clipboard.readImage()', -> - it 'returns NativeImage intance', -> - p = path.join fixtures, 'assets', 'logo.png' - i = nativeImage.createFromPath p - clipboard.writeImage p - assert.equal clipboard.readImage().toDataURL(), i.toDataURL() - - describe 'clipboard.readText()', -> - it 'returns unicode string correctly', -> - text = '千江有水千江月,万里无云万里天' - clipboard.writeText text - assert.equal clipboard.readText(), text - - describe 'clipboard.readHtml()', -> - it 'returns markup correctly', -> - text = 'Hi' - markup = - if process.platform is 'darwin' - 'Hi' - else if process.platform is 'linux' - 'Hi' - else - 'Hi' - clipboard.writeHtml text - assert.equal clipboard.readHtml(), markup - - describe 'clipboard.write()', -> - it 'returns data correctly', -> - text = 'test' - p = path.join fixtures, 'assets', 'logo.png' - i = nativeImage.createFromPath p - markup = - if process.platform is 'darwin' - 'Hi' - else if process.platform is 'linux' - 'Hi' - else - 'Hi' - clipboard.write {text: "test", html: 'Hi', image: p} - assert.equal clipboard.readText(), text - assert.equal clipboard.readHtml(), markup - assert.equal clipboard.readImage().toDataURL(), i.toDataURL() diff --git a/spec/api-clipboard-spec.js b/spec/api-clipboard-spec.js new file mode 100644 index 000000000000..6154181f0926 --- /dev/null +++ b/spec/api-clipboard-spec.js @@ -0,0 +1,55 @@ +var assert, clipboard, nativeImage, path, ref; + +assert = require('assert'); + +path = require('path'); + +ref = require('electron'), clipboard = ref.clipboard, nativeImage = ref.nativeImage; + +describe('clipboard module', function() { + var fixtures; + fixtures = path.resolve(__dirname, 'fixtures'); + describe('clipboard.readImage()', function() { + return it('returns NativeImage intance', function() { + var i, p; + p = path.join(fixtures, 'assets', 'logo.png'); + i = nativeImage.createFromPath(p); + clipboard.writeImage(p); + return assert.equal(clipboard.readImage().toDataURL(), i.toDataURL()); + }); + }); + describe('clipboard.readText()', function() { + return it('returns unicode string correctly', function() { + var text; + text = '千江有水千江月,万里无云万里天'; + clipboard.writeText(text); + return assert.equal(clipboard.readText(), text); + }); + }); + describe('clipboard.readHtml()', function() { + return it('returns markup correctly', function() { + var markup, text; + text = 'Hi'; + markup = process.platform === 'darwin' ? 'Hi' : process.platform === 'linux' ? 'Hi' : 'Hi'; + clipboard.writeHtml(text); + return assert.equal(clipboard.readHtml(), markup); + }); + }); + return describe('clipboard.write()', function() { + return it('returns data correctly', function() { + var i, markup, p, text; + text = 'test'; + p = path.join(fixtures, 'assets', 'logo.png'); + i = nativeImage.createFromPath(p); + markup = process.platform === 'darwin' ? 'Hi' : process.platform === 'linux' ? 'Hi' : 'Hi'; + clipboard.write({ + text: "test", + html: 'Hi', + image: p + }); + assert.equal(clipboard.readText(), text); + assert.equal(clipboard.readHtml(), markup); + return assert.equal(clipboard.readImage().toDataURL(), i.toDataURL()); + }); + }); +}); diff --git a/spec/api-crash-reporter-spec.coffee b/spec/api-crash-reporter-spec.coffee deleted file mode 100644 index 334956d3c06b..000000000000 --- a/spec/api-crash-reporter-spec.coffee +++ /dev/null @@ -1,66 +0,0 @@ -assert = require 'assert' -path = require 'path' -http = require 'http' -url = require 'url' -multiparty = require 'multiparty' - -{remote} = require 'electron' -{app, crashReporter, BrowserWindow} = remote.require 'electron' - -describe 'crash-reporter module', -> - fixtures = path.resolve __dirname, 'fixtures' - - w = null - beforeEach -> w = new BrowserWindow(show: false) - afterEach -> w.destroy() - - # It is not working for mas build. - return if process.mas - - # The crash-reporter test is not reliable on CI machine. - isCI = remote.getGlobal('isCi') - return if isCI - - it 'should send minidump when renderer crashes', (done) -> - @timeout 120000 - called = false - server = http.createServer (req, res) -> - server.close() - form = new multiparty.Form() - form.parse req, (error, fields, files) -> - # This callback can be called for twice sometimes. - return if called - called = true - - assert.equal fields['prod'], 'Electron' - assert.equal fields['ver'], process.versions['electron'] - assert.equal fields['process_type'], 'renderer' - assert.equal fields['platform'], process.platform - assert.equal fields['extra1'], 'extra1' - assert.equal fields['extra2'], 'extra2' - assert.equal fields['_productName'], 'Zombies' - assert.equal fields['_companyName'], 'Umbrella Corporation' - assert.equal fields['_version'], app.getVersion() - - res.end('abc-123-def') - done() - # Server port is generated randomly for the first run, it will be reused - # when page is refreshed. - port = remote.process.port - server.listen port, '127.0.0.1', -> - {port} = server.address() - remote.process.port = port - url = url.format - protocol: 'file' - pathname: path.join fixtures, 'api', 'crash.html' - search: "?port=#{port}" - if process.platform is 'darwin' - crashReporter.start - companyName: 'Umbrella Corporation' - submitURL: "http://127.0.0.1:#{port}" - w.loadURL url - - describe ".start(options)", -> - it 'requires that the companyName and submitURL options be specified', -> - assert.throws(-> crashReporter.start({companyName: 'Missing submitURL'})) - assert.throws(-> crashReporter.start({submitURL: 'Missing companyName'})) diff --git a/spec/api-crash-reporter-spec.js b/spec/api-crash-reporter-spec.js new file mode 100644 index 000000000000..88cbe0a666dc --- /dev/null +++ b/spec/api-crash-reporter-spec.js @@ -0,0 +1,94 @@ +var BrowserWindow, app, assert, crashReporter, http, multiparty, path, ref, remote, url; + +assert = require('assert'); + +path = require('path'); + +http = require('http'); + +url = require('url'); + +multiparty = require('multiparty'); + +remote = require('electron').remote; + +ref = remote.require('electron'), app = ref.app, crashReporter = ref.crashReporter, BrowserWindow = ref.BrowserWindow; + +describe('crash-reporter module', function() { + var fixtures, isCI, w; + fixtures = path.resolve(__dirname, 'fixtures'); + w = null; + beforeEach(function() { + return w = new BrowserWindow({ + show: false + }); + }); + afterEach(function() { + return w.destroy(); + }); + if (process.mas) { + return; + } + isCI = remote.getGlobal('isCi'); + if (isCI) { + return; + } + it('should send minidump when renderer crashes', function(done) { + var called, port, server; + this.timeout(120000); + called = false; + server = http.createServer(function(req, res) { + var form; + server.close(); + form = new multiparty.Form(); + return form.parse(req, function(error, fields, files) { + if (called) { + return; + } + called = true; + assert.equal(fields['prod'], 'Electron'); + assert.equal(fields['ver'], process.versions['electron']); + assert.equal(fields['process_type'], 'renderer'); + assert.equal(fields['platform'], process.platform); + assert.equal(fields['extra1'], 'extra1'); + assert.equal(fields['extra2'], 'extra2'); + assert.equal(fields['_productName'], 'Zombies'); + assert.equal(fields['_companyName'], 'Umbrella Corporation'); + assert.equal(fields['_version'], app.getVersion()); + res.end('abc-123-def'); + return done(); + }); + }); + port = remote.process.port; + return server.listen(port, '127.0.0.1', function() { + port = server.address().port; + remote.process.port = port; + url = url.format({ + protocol: 'file', + pathname: path.join(fixtures, 'api', 'crash.html'), + search: "?port=" + port + }); + if (process.platform === 'darwin') { + crashReporter.start({ + companyName: 'Umbrella Corporation', + submitURL: "http://127.0.0.1:" + port + }); + } + return w.loadURL(url); + }); + }); + return describe(".start(options)", function() { + return it('requires that the companyName and submitURL options be specified', function() { + assert.throws(function() { + return crashReporter.start({ + companyName: 'Missing submitURL' + }); + }); + return assert.throws(function() { + return crashReporter.start({ + submitURL: 'Missing companyName' + }); + }); + }); + }); +}); diff --git a/spec/api-desktop-capturer.coffee b/spec/api-desktop-capturer.coffee deleted file mode 100644 index 6f1842dd145c..000000000000 --- a/spec/api-desktop-capturer.coffee +++ /dev/null @@ -1,9 +0,0 @@ -assert = require 'assert' -{desktopCapturer} = require 'electron' - -describe 'desktopCapturer', -> - it 'should returns something', (done) -> - desktopCapturer.getSources {types: ['window', 'screen']}, (error, sources) -> - assert.equal error, null - assert.notEqual sources.length, 0 - done() diff --git a/spec/api-desktop-capturer.js b/spec/api-desktop-capturer.js new file mode 100644 index 000000000000..288e57ee4489 --- /dev/null +++ b/spec/api-desktop-capturer.js @@ -0,0 +1,17 @@ +var assert, desktopCapturer; + +assert = require('assert'); + +desktopCapturer = require('electron').desktopCapturer; + +describe('desktopCapturer', function() { + return it('should returns something', function(done) { + return desktopCapturer.getSources({ + types: ['window', 'screen'] + }, function(error, sources) { + assert.equal(error, null); + assert.notEqual(sources.length, 0); + return done(); + }); + }); +}); diff --git a/spec/api-ipc-spec.coffee b/spec/api-ipc-spec.coffee deleted file mode 100644 index 67ef717d5045..000000000000 --- a/spec/api-ipc-spec.coffee +++ /dev/null @@ -1,110 +0,0 @@ -assert = require 'assert' -path = require 'path' - -{ipcRenderer, remote} = require 'electron' -{ipcMain, BrowserWindow} = remote.require 'electron' - -comparePaths = (path1, path2) -> - if process.platform is 'win32' - # Paths in Windows are case insensitive. - path1 = path1.toLowerCase() - path2 = path2.toLowerCase() - assert.equal path1, path2 - -describe 'ipc module', -> - fixtures = path.join __dirname, 'fixtures' - - describe 'remote.require', -> - it 'should returns same object for the same module', -> - dialog1 = remote.require 'electron' - dialog2 = remote.require 'electron' - assert.equal dialog1, dialog2 - - it 'should work when object contains id property', -> - a = remote.require path.join(fixtures, 'module', 'id.js') - assert.equal a.id, 1127 - - it 'should search module from the user app', -> - comparePaths path.normalize(remote.process.mainModule.filename), path.resolve(__dirname, 'static', 'main.js') - comparePaths path.normalize(remote.process.mainModule.paths[0]), path.resolve(__dirname, 'static', 'node_modules') - - describe 'remote.createFunctionWithReturnValue', -> - it 'should be called in browser synchronously', -> - buf = new Buffer('test') - call = remote.require path.join(fixtures, 'module', 'call.js') - result = call.call remote.createFunctionWithReturnValue(buf) - assert.equal result.constructor.name, 'Buffer' - - describe 'remote object in renderer', -> - it 'can change its properties', -> - property = remote.require path.join(fixtures, 'module', 'property.js') - assert.equal property.property, 1127 - property.property = 1007 - assert.equal property.property, 1007 - property2 = remote.require path.join(fixtures, 'module', 'property.js') - assert.equal property2.property, 1007 - - # Restore. - property.property = 1127 - - it 'can construct an object from its member', -> - call = remote.require path.join(fixtures, 'module', 'call.js') - obj = new call.constructor - assert.equal obj.test, 'test' - - describe 'remote value in browser', -> - print = path.join(fixtures, 'module', 'print_name.js') - - it 'keeps its constructor name for objects', -> - buf = new Buffer('test') - print_name = remote.require print - assert.equal print_name.print(buf), 'Buffer' - - it 'supports instanceof Date', -> - now = new Date() - print_name = remote.require print - assert.equal print_name.print(now), 'Date' - assert.deepEqual print_name.echo(now), now - - describe 'remote promise', -> - it 'can be used as promise in each side', (done) -> - promise = remote.require path.join(fixtures, 'module', 'promise.js') - promise.twicePromise(Promise.resolve(1234)) - .then (value) => - assert.equal value, 2468 - done() - - describe 'ipc.sender.send', -> - it 'should work when sending an object containing id property', (done) -> - obj = id: 1, name: 'ly' - ipcRenderer.once 'message', (event, message) -> - assert.deepEqual message, obj - done() - ipcRenderer.send 'message', obj - - describe 'ipc.sendSync', -> - it 'can be replied by setting event.returnValue', -> - msg = ipcRenderer.sendSync 'echo', 'test' - assert.equal msg, 'test' - - it 'does not crash when reply is not sent and browser is destroyed', (done) -> - @timeout 10000 - w = new BrowserWindow(show: false) - ipcMain.once 'send-sync-message', (event) -> - event.returnValue = null - w.destroy() - done() - w.loadURL 'file://' + path.join(fixtures, 'api', 'send-sync-message.html') - - describe 'remote listeners', -> - w = null - afterEach -> - w.destroy() - - it 'can be added and removed correctly', -> - w = new BrowserWindow(show: false) - listener = -> - w.on 'test', listener - assert.equal w.listenerCount('test'), 1 - w.removeListener 'test', listener - assert.equal w.listenerCount('test'), 0 diff --git a/spec/api-ipc-spec.js b/spec/api-ipc-spec.js new file mode 100644 index 000000000000..fba5b6d68402 --- /dev/null +++ b/spec/api-ipc-spec.js @@ -0,0 +1,147 @@ +var BrowserWindow, assert, comparePaths, ipcMain, ipcRenderer, path, ref, ref1, remote; + +assert = require('assert'); + +path = require('path'); + +ref = require('electron'), ipcRenderer = ref.ipcRenderer, remote = ref.remote; + +ref1 = remote.require('electron'), ipcMain = ref1.ipcMain, BrowserWindow = ref1.BrowserWindow; + +comparePaths = function(path1, path2) { + if (process.platform === 'win32') { + path1 = path1.toLowerCase(); + path2 = path2.toLowerCase(); + } + return assert.equal(path1, path2); +}; + +describe('ipc module', function() { + var fixtures; + fixtures = path.join(__dirname, 'fixtures'); + describe('remote.require', function() { + it('should returns same object for the same module', function() { + var dialog1, dialog2; + dialog1 = remote.require('electron'); + dialog2 = remote.require('electron'); + return assert.equal(dialog1, dialog2); + }); + it('should work when object contains id property', function() { + var a; + a = remote.require(path.join(fixtures, 'module', 'id.js')); + return assert.equal(a.id, 1127); + }); + return it('should search module from the user app', function() { + comparePaths(path.normalize(remote.process.mainModule.filename), path.resolve(__dirname, 'static', 'main.js')); + return comparePaths(path.normalize(remote.process.mainModule.paths[0]), path.resolve(__dirname, 'static', 'node_modules')); + }); + }); + describe('remote.createFunctionWithReturnValue', function() { + return it('should be called in browser synchronously', function() { + var buf, call, result; + buf = new Buffer('test'); + call = remote.require(path.join(fixtures, 'module', 'call.js')); + result = call.call(remote.createFunctionWithReturnValue(buf)); + return assert.equal(result.constructor.name, 'Buffer'); + }); + }); + describe('remote object in renderer', function() { + it('can change its properties', function() { + var property, property2; + property = remote.require(path.join(fixtures, 'module', 'property.js')); + assert.equal(property.property, 1127); + property.property = 1007; + assert.equal(property.property, 1007); + property2 = remote.require(path.join(fixtures, 'module', 'property.js')); + assert.equal(property2.property, 1007); + return property.property = 1127; + }); + return it('can construct an object from its member', function() { + var call, obj; + call = remote.require(path.join(fixtures, 'module', 'call.js')); + obj = new call.constructor; + return assert.equal(obj.test, 'test'); + }); + }); + describe('remote value in browser', function() { + var print; + print = path.join(fixtures, 'module', 'print_name.js'); + it('keeps its constructor name for objects', function() { + var buf, print_name; + buf = new Buffer('test'); + print_name = remote.require(print); + return assert.equal(print_name.print(buf), 'Buffer'); + }); + return it('supports instanceof Date', function() { + var now, print_name; + now = new Date(); + print_name = remote.require(print); + assert.equal(print_name.print(now), 'Date'); + return assert.deepEqual(print_name.echo(now), now); + }); + }); + describe('remote promise', function() { + return it('can be used as promise in each side', function(done) { + var promise; + promise = remote.require(path.join(fixtures, 'module', 'promise.js')); + return promise.twicePromise(Promise.resolve(1234)).then((function(_this) { + return function(value) { + assert.equal(value, 2468); + return done(); + }; + })(this)); + }); + }); + describe('ipc.sender.send', function() { + return it('should work when sending an object containing id property', function(done) { + var obj; + obj = { + id: 1, + name: 'ly' + }; + ipcRenderer.once('message', function(event, message) { + assert.deepEqual(message, obj); + return done(); + }); + return ipcRenderer.send('message', obj); + }); + }); + describe('ipc.sendSync', function() { + it('can be replied by setting event.returnValue', function() { + var msg; + msg = ipcRenderer.sendSync('echo', 'test'); + return assert.equal(msg, 'test'); + }); + return it('does not crash when reply is not sent and browser is destroyed', function(done) { + var w; + this.timeout(10000); + w = new BrowserWindow({ + show: false + }); + ipcMain.once('send-sync-message', function(event) { + event.returnValue = null; + w.destroy(); + return done(); + }); + return w.loadURL('file://' + path.join(fixtures, 'api', 'send-sync-message.html')); + }); + }); + return describe('remote listeners', function() { + var w; + w = null; + afterEach(function() { + return w.destroy(); + }); + return it('can be added and removed correctly', function() { + var listener; + w = new BrowserWindow({ + show: false + }); + listener = function() {}; + w.on('test', listener); + assert.equal(w.listenerCount('test'), 1); + w.removeListener('test', listener); + return assert.equal(w.listenerCount('test'), 0); + }); + }); +}); diff --git a/spec/api-menu-spec.coffee b/spec/api-menu-spec.coffee deleted file mode 100644 index 2f1f6465898f..000000000000 --- a/spec/api-menu-spec.coffee +++ /dev/null @@ -1,172 +0,0 @@ -assert = require 'assert' - -{remote, ipcRenderer} = require 'electron' -{Menu, MenuItem} = remote.require 'electron' - -describe 'menu module', -> - describe 'Menu.buildFromTemplate', -> - it 'should be able to attach extra fields', -> - menu = Menu.buildFromTemplate [label: 'text', extra: 'field'] - assert.equal menu.items[0].extra, 'field' - - it 'does not modify the specified template', -> - template = ipcRenderer.sendSync 'eval', """ - var template = [{label: 'text', submenu: [{label: 'sub'}]}]; - require('electron').Menu.buildFromTemplate(template); - template; - """ - assert.deepStrictEqual template, [label: 'text', submenu: [label: 'sub']] - - describe 'Menu.buildFromTemplate should reorder based on item position specifiers', -> - it 'should position before existing item', -> - menu = Menu.buildFromTemplate [ - {label: '2', id: '2'} - {label: '3', id: '3'} - {label: '1', id: '1', position: 'before=2'} - ] - assert.equal menu.items[0].label, '1' - assert.equal menu.items[1].label, '2' - assert.equal menu.items[2].label, '3' - - it 'should position after existing item', -> - menu = Menu.buildFromTemplate [ - {label: '1', id: '1'} - {label: '3', id: '3'} - {label: '2', id: '2', position: 'after=1'} - ] - assert.equal menu.items[0].label, '1' - assert.equal menu.items[1].label, '2' - assert.equal menu.items[2].label, '3' - - it 'should position at endof existing separator groups', -> - menu = Menu.buildFromTemplate [ - {type: 'separator', id: 'numbers'} - {type: 'separator', id: 'letters'} - {label: 'a', id: 'a', position: 'endof=letters'} - {label: '1', id: '1', position: 'endof=numbers'} - {label: 'b', id: 'b', position: 'endof=letters'} - {label: '2', id: '2', position: 'endof=numbers'} - {label: 'c', id: 'c', position: 'endof=letters'} - {label: '3', id: '3', position: 'endof=numbers'} - ] - assert.equal menu.items[0].id, 'numbers' - assert.equal menu.items[1].label, '1' - assert.equal menu.items[2].label, '2' - assert.equal menu.items[3].label, '3' - assert.equal menu.items[4].id, 'letters' - assert.equal menu.items[5].label, 'a' - assert.equal menu.items[6].label, 'b' - assert.equal menu.items[7].label, 'c' - - it 'should create separator group if endof does not reference existing separator group', -> - menu = Menu.buildFromTemplate [ - {label: 'a', id: 'a', position: 'endof=letters'} - {label: '1', id: '1', position: 'endof=numbers'} - {label: 'b', id: 'b', position: 'endof=letters'} - {label: '2', id: '2', position: 'endof=numbers'} - {label: 'c', id: 'c', position: 'endof=letters'} - {label: '3', id: '3', position: 'endof=numbers'} - ] - - assert.equal menu.items[0].id, 'letters' - assert.equal menu.items[1].label, 'a' - assert.equal menu.items[2].label, 'b' - assert.equal menu.items[3].label, 'c' - assert.equal menu.items[4].id, 'numbers' - assert.equal menu.items[5].label, '1' - assert.equal menu.items[6].label, '2' - assert.equal menu.items[7].label, '3' - - it 'should continue inserting items at next index when no specifier is present', -> - menu = Menu.buildFromTemplate [ - {label: '4', id: '4'} - {label: '5', id: '5'} - {label: '1', id: '1', position: 'before=4'} - {label: '2', id: '2'} - {label: '3', id: '3'} - ] - assert.equal menu.items[0].label, '1' - assert.equal menu.items[1].label, '2' - assert.equal menu.items[2].label, '3' - assert.equal menu.items[3].label, '4' - assert.equal menu.items[4].label, '5' - - describe 'Menu.insert', -> - it 'should store item in @items by its index', -> - menu = Menu.buildFromTemplate [ - {label: '1'} - {label: '2'} - {label: '3'} - ] - item = new MenuItem(label: 'inserted') - menu.insert 1, item - - assert.equal menu.items[0].label, '1' - assert.equal menu.items[1].label, 'inserted' - assert.equal menu.items[2].label, '2' - assert.equal menu.items[3].label, '3' - - describe 'MenuItem.click', -> - it 'should be called with the item object passed', (done) -> - menu = Menu.buildFromTemplate [ - label: 'text' - click: (item) -> - assert.equal item.constructor.name, 'MenuItem' - assert.equal item.label, 'text' - done() - ] - menu.delegate.executeCommand menu.items[0].commandId - - describe 'MenuItem with checked property', -> - it 'clicking an checkbox item should flip the checked property', -> - menu = Menu.buildFromTemplate [ label: 'text', type: 'checkbox' ] - assert.equal menu.items[0].checked, false - menu.delegate.executeCommand menu.items[0].commandId - assert.equal menu.items[0].checked, true - - it 'clicking an radio item should always make checked property true', -> - menu = Menu.buildFromTemplate [ label: 'text', type: 'radio' ] - menu.delegate.executeCommand menu.items[0].commandId - assert.equal menu.items[0].checked, true - menu.delegate.executeCommand menu.items[0].commandId - assert.equal menu.items[0].checked, true - - it 'at least have one item checked in each group', -> - template = [] - template.push label: "#{i}", type: 'radio' for i in [0..10] - template.push type: 'separator' - template.push label: "#{i}", type: 'radio' for i in [12..20] - menu = Menu.buildFromTemplate template - menu.delegate.menuWillShow() - assert.equal menu.items[0].checked, true - assert.equal menu.items[12].checked, true - - it 'should assign groupId automatically', -> - template = [] - template.push label: "#{i}", type: 'radio' for i in [0..10] - template.push type: 'separator' - template.push label: "#{i}", type: 'radio' for i in [12..20] - menu = Menu.buildFromTemplate template - groupId = menu.items[0].groupId - assert.equal menu.items[i].groupId, groupId for i in [0..10] - assert.equal menu.items[i].groupId, groupId + 1 for i in [12..20] - - it "setting 'checked' should flip other items' 'checked' property", -> - template = [] - template.push label: "#{i}", type: 'radio' for i in [0..10] - template.push type: 'separator' - template.push label: "#{i}", type: 'radio' for i in [12..20] - menu = Menu.buildFromTemplate template - assert.equal menu.items[i].checked, false for i in [0..10] - menu.items[0].checked = true - assert.equal menu.items[0].checked, true - assert.equal menu.items[i].checked, false for i in [1..10] - menu.items[10].checked = true - assert.equal menu.items[10].checked, true - assert.equal menu.items[i].checked, false for i in [0..9] - assert.equal menu.items[i].checked, false for i in [12..20] - menu.items[12].checked = true - assert.equal menu.items[10].checked, true - assert.equal menu.items[i].checked, false for i in [0..9] - assert.equal menu.items[12].checked, true - assert.equal menu.items[i].checked, false for i in [13..20] diff --git a/spec/api-menu-spec.js b/spec/api-menu-spec.js new file mode 100644 index 000000000000..5771358337e4 --- /dev/null +++ b/spec/api-menu-spec.js @@ -0,0 +1,349 @@ +var Menu, MenuItem, assert, ipcRenderer, ref, ref1, remote; + +assert = require('assert'); + +ref = require('electron'), remote = ref.remote, ipcRenderer = ref.ipcRenderer; + +ref1 = remote.require('electron'), Menu = ref1.Menu, MenuItem = ref1.MenuItem; + +describe('menu module', function() { + describe('Menu.buildFromTemplate', function() { + it('should be able to attach extra fields', function() { + var menu; + menu = Menu.buildFromTemplate([ + { + label: 'text', + extra: 'field' + } + ]); + return assert.equal(menu.items[0].extra, 'field'); + }); + it('does not modify the specified template', function() { + var template; + template = ipcRenderer.sendSync('eval', "var template = [{label: 'text', submenu: [{label: 'sub'}]}];\nrequire('electron').Menu.buildFromTemplate(template);\ntemplate;"); + return assert.deepStrictEqual(template, [ + { + label: 'text', + submenu: [ + { + label: 'sub' + } + ] + } + ]); + }); + return describe('Menu.buildFromTemplate should reorder based on item position specifiers', function() { + it('should position before existing item', function() { + var menu; + menu = Menu.buildFromTemplate([ + { + label: '2', + id: '2' + }, { + label: '3', + id: '3' + }, { + label: '1', + id: '1', + position: 'before=2' + } + ]); + assert.equal(menu.items[0].label, '1'); + assert.equal(menu.items[1].label, '2'); + return assert.equal(menu.items[2].label, '3'); + }); + it('should position after existing item', function() { + var menu; + menu = Menu.buildFromTemplate([ + { + label: '1', + id: '1' + }, { + label: '3', + id: '3' + }, { + label: '2', + id: '2', + position: 'after=1' + } + ]); + assert.equal(menu.items[0].label, '1'); + assert.equal(menu.items[1].label, '2'); + return assert.equal(menu.items[2].label, '3'); + }); + it('should position at endof existing separator groups', function() { + var menu; + menu = Menu.buildFromTemplate([ + { + type: 'separator', + id: 'numbers' + }, { + type: 'separator', + id: 'letters' + }, { + label: 'a', + id: 'a', + position: 'endof=letters' + }, { + label: '1', + id: '1', + position: 'endof=numbers' + }, { + label: 'b', + id: 'b', + position: 'endof=letters' + }, { + label: '2', + id: '2', + position: 'endof=numbers' + }, { + label: 'c', + id: 'c', + position: 'endof=letters' + }, { + label: '3', + id: '3', + position: 'endof=numbers' + } + ]); + assert.equal(menu.items[0].id, 'numbers'); + assert.equal(menu.items[1].label, '1'); + assert.equal(menu.items[2].label, '2'); + assert.equal(menu.items[3].label, '3'); + assert.equal(menu.items[4].id, 'letters'); + assert.equal(menu.items[5].label, 'a'); + assert.equal(menu.items[6].label, 'b'); + return assert.equal(menu.items[7].label, 'c'); + }); + it('should create separator group if endof does not reference existing separator group', function() { + var menu; + menu = Menu.buildFromTemplate([ + { + label: 'a', + id: 'a', + position: 'endof=letters' + }, { + label: '1', + id: '1', + position: 'endof=numbers' + }, { + label: 'b', + id: 'b', + position: 'endof=letters' + }, { + label: '2', + id: '2', + position: 'endof=numbers' + }, { + label: 'c', + id: 'c', + position: 'endof=letters' + }, { + label: '3', + id: '3', + position: 'endof=numbers' + } + ]); + assert.equal(menu.items[0].id, 'letters'); + assert.equal(menu.items[1].label, 'a'); + assert.equal(menu.items[2].label, 'b'); + assert.equal(menu.items[3].label, 'c'); + assert.equal(menu.items[4].id, 'numbers'); + assert.equal(menu.items[5].label, '1'); + assert.equal(menu.items[6].label, '2'); + return assert.equal(menu.items[7].label, '3'); + }); + return it('should continue inserting items at next index when no specifier is present', function() { + var menu; + menu = Menu.buildFromTemplate([ + { + label: '4', + id: '4' + }, { + label: '5', + id: '5' + }, { + label: '1', + id: '1', + position: 'before=4' + }, { + label: '2', + id: '2' + }, { + label: '3', + id: '3' + } + ]); + assert.equal(menu.items[0].label, '1'); + assert.equal(menu.items[1].label, '2'); + assert.equal(menu.items[2].label, '3'); + assert.equal(menu.items[3].label, '4'); + return assert.equal(menu.items[4].label, '5'); + }); + }); + }); + describe('Menu.insert', function() { + return it('should store item in @items by its index', function() { + var item, menu; + menu = Menu.buildFromTemplate([ + { + label: '1' + }, { + label: '2' + }, { + label: '3' + } + ]); + item = new MenuItem({ + label: 'inserted' + }); + menu.insert(1, item); + assert.equal(menu.items[0].label, '1'); + assert.equal(menu.items[1].label, 'inserted'); + assert.equal(menu.items[2].label, '2'); + return assert.equal(menu.items[3].label, '3'); + }); + }); + describe('MenuItem.click', function() { + return it('should be called with the item object passed', function(done) { + var menu; + menu = Menu.buildFromTemplate([ + { + label: 'text', + click: function(item) { + assert.equal(item.constructor.name, 'MenuItem'); + assert.equal(item.label, 'text'); + return done(); + } + } + ]); + return menu.delegate.executeCommand(menu.items[0].commandId); + }); + }); + return describe('MenuItem with checked property', function() { + it('clicking an checkbox item should flip the checked property', function() { + var menu; + menu = Menu.buildFromTemplate([ + { + label: 'text', + type: 'checkbox' + } + ]); + assert.equal(menu.items[0].checked, false); + menu.delegate.executeCommand(menu.items[0].commandId); + return assert.equal(menu.items[0].checked, true); + }); + it('clicking an radio item should always make checked property true', function() { + var menu; + menu = Menu.buildFromTemplate([ + { + label: 'text', + type: 'radio' + } + ]); + menu.delegate.executeCommand(menu.items[0].commandId); + assert.equal(menu.items[0].checked, true); + menu.delegate.executeCommand(menu.items[0].commandId); + return assert.equal(menu.items[0].checked, true); + }); + it('at least have one item checked in each group', function() { + var i, j, k, menu, template; + template = []; + for (i = j = 0; j <= 10; i = ++j) { + template.push({ + label: "" + i, + type: 'radio' + }); + } + template.push({ + type: 'separator' + }); + for (i = k = 12; k <= 20; i = ++k) { + template.push({ + label: "" + i, + type: 'radio' + }); + } + menu = Menu.buildFromTemplate(template); + menu.delegate.menuWillShow(); + assert.equal(menu.items[0].checked, true); + return assert.equal(menu.items[12].checked, true); + }); + it('should assign groupId automatically', function() { + var groupId, i, j, k, l, m, menu, results, template; + template = []; + for (i = j = 0; j <= 10; i = ++j) { + template.push({ + label: "" + i, + type: 'radio' + }); + } + template.push({ + type: 'separator' + }); + for (i = k = 12; k <= 20; i = ++k) { + template.push({ + label: "" + i, + type: 'radio' + }); + } + menu = Menu.buildFromTemplate(template); + groupId = menu.items[0].groupId; + for (i = l = 0; l <= 10; i = ++l) { + assert.equal(menu.items[i].groupId, groupId); + } + results = []; + for (i = m = 12; m <= 20; i = ++m) { + results.push(assert.equal(menu.items[i].groupId, groupId + 1)); + } + return results; + }); + return it("setting 'checked' should flip other items' 'checked' property", function() { + var i, j, k, l, m, menu, n, o, p, q, results, template; + template = []; + for (i = j = 0; j <= 10; i = ++j) { + template.push({ + label: "" + i, + type: 'radio' + }); + } + template.push({ + type: 'separator' + }); + for (i = k = 12; k <= 20; i = ++k) { + template.push({ + label: "" + i, + type: 'radio' + }); + } + menu = Menu.buildFromTemplate(template); + for (i = l = 0; l <= 10; i = ++l) { + assert.equal(menu.items[i].checked, false); + } + menu.items[0].checked = true; + assert.equal(menu.items[0].checked, true); + for (i = m = 1; m <= 10; i = ++m) { + assert.equal(menu.items[i].checked, false); + } + menu.items[10].checked = true; + assert.equal(menu.items[10].checked, true); + for (i = n = 0; n <= 9; i = ++n) { + assert.equal(menu.items[i].checked, false); + } + for (i = o = 12; o <= 20; i = ++o) { + assert.equal(menu.items[i].checked, false); + } + menu.items[12].checked = true; + assert.equal(menu.items[10].checked, true); + for (i = p = 0; p <= 9; i = ++p) { + assert.equal(menu.items[i].checked, false); + } + assert.equal(menu.items[12].checked, true); + results = []; + for (i = q = 13; q <= 20; i = ++q) { + results.push(assert.equal(menu.items[i].checked, false)); + } + return results; + }); + }); +}); diff --git a/spec/api-protocol-spec.coffee b/spec/api-protocol-spec.coffee deleted file mode 100644 index 77eb90259bb2..000000000000 --- a/spec/api-protocol-spec.coffee +++ /dev/null @@ -1,499 +0,0 @@ -assert = require 'assert' -http = require 'http' -path = require 'path' -qs = require 'querystring' - -{remote} = require 'electron' -{protocol} = remote.require 'electron' - -describe 'protocol module', -> - protocolName = 'sp' - text = 'valar morghulis' - postData = - name: 'post test' - type: 'string' - - afterEach (done) -> - protocol.unregisterProtocol protocolName, -> - protocol.uninterceptProtocol 'http', -> done() - - describe 'protocol.register(Any)Protocol', -> - emptyHandler = (request, callback) -> callback() - it 'throws error when scheme is already registered', (done) -> - protocol.registerStringProtocol protocolName, emptyHandler, (error) -> - assert.equal error, null - protocol.registerBufferProtocol protocolName, emptyHandler, (error) -> - assert.notEqual error, null - done() - - it 'does not crash when handler is called twice', (done) -> - doubleHandler = (request, callback) -> - try - callback(text) - callback() - catch - protocol.registerStringProtocol protocolName, doubleHandler, (error) -> - return done(error) if error - $.ajax - url: "#{protocolName}://fake-host" - success: (data) -> - assert.equal data, text - done() - error: (xhr, errorType, error) -> - done(error) - - it 'sends error when callback is called with nothing', (done) -> - protocol.registerBufferProtocol protocolName, emptyHandler, (error) -> - return done(error) if error - $.ajax - url: "#{protocolName}://fake-host" - success: (data) -> - done('request succeeded but it should not') - error: (xhr, errorType, error) -> - assert.equal errorType, 'error' - done() - - it 'does not crash when callback is called in next tick', (done) -> - handler = (request, callback) -> - setImmediate -> callback(text) - protocol.registerStringProtocol protocolName, handler, (error) -> - return done(error) if error - $.ajax - url: "#{protocolName}://fake-host" - success: (data) -> - assert.equal data, text - done() - error: (xhr, errorType, error) -> - done(error) - - describe 'protocol.unregisterProtocol', -> - it 'returns error when scheme does not exist', (done) -> - protocol.unregisterProtocol 'not-exist', (error) -> - assert.notEqual error, null - done() - - describe 'protocol.registerStringProtocol', -> - it 'sends string as response', (done) -> - handler = (request, callback) -> callback(text) - protocol.registerStringProtocol protocolName, handler, (error) -> - return done(error) if error - $.ajax - url: "#{protocolName}://fake-host" - success: (data) -> - assert.equal data, text - done() - error: (xhr, errorType, error) -> - done(error) - - it 'sets Access-Control-Allow-Origin', (done) -> - handler = (request, callback) -> callback(text) - protocol.registerStringProtocol protocolName, handler, (error) -> - return done(error) if error - $.ajax - url: "#{protocolName}://fake-host" - success: (data, status, request) -> - assert.equal data, text - assert.equal( - request.getResponseHeader('Access-Control-Allow-Origin'), - '*') - done() - error: (xhr, errorType, error) -> - done(error) - - it 'sends object as response', (done) -> - handler = (request, callback) -> callback(data: text, mimeType: 'text/html') - protocol.registerStringProtocol protocolName, handler, (error) -> - return done(error) if error - $.ajax - url: "#{protocolName}://fake-host" - success: (data, statux, request) -> - assert.equal data, text - done() - error: (xhr, errorType, error) -> - done(error) - - it 'fails when sending object other than string', (done) -> - handler = (request, callback) -> callback(new Date) - protocol.registerBufferProtocol protocolName, handler, (error) -> - return done(error) if error - $.ajax - url: "#{protocolName}://fake-host" - success: (data) -> - done('request succeeded but it should not') - error: (xhr, errorType, error) -> - assert.equal errorType, 'error' - done() - - describe 'protocol.registerBufferProtocol', -> - buffer = new Buffer(text) - - it 'sends Buffer as response', (done) -> - handler = (request, callback) -> callback(buffer) - protocol.registerBufferProtocol protocolName, handler, (error) -> - return done(error) if error - $.ajax - url: "#{protocolName}://fake-host" - success: (data) -> - assert.equal data, text - done() - error: (xhr, errorType, error) -> - done(error) - - it 'sets Access-Control-Allow-Origin', (done) -> - handler = (request, callback) -> callback(buffer) - protocol.registerBufferProtocol protocolName, handler, (error) -> - return done(error) if error - $.ajax - url: "#{protocolName}://fake-host" - success: (data, status, request) -> - assert.equal data, text - assert.equal( - request.getResponseHeader('Access-Control-Allow-Origin'), - '*') - done() - error: (xhr, errorType, error) -> - done(error) - - it 'sends object as response', (done) -> - handler = (request, callback) -> callback(data: buffer, mimeType: 'text/html') - protocol.registerBufferProtocol protocolName, handler, (error) -> - return done(error) if error - $.ajax - url: "#{protocolName}://fake-host" - success: (data, statux, request) -> - assert.equal data, text - done() - error: (xhr, errorType, error) -> - done(error) - - it 'fails when sending string', (done) -> - handler = (request, callback) -> callback(text) - protocol.registerBufferProtocol protocolName, handler, (error) -> - return done(error) if error - $.ajax - url: "#{protocolName}://fake-host" - success: (data) -> - done('request succeeded but it should not') - error: (xhr, errorType, error) -> - assert.equal errorType, 'error' - done() - - describe 'protocol.registerFileProtocol', -> - filePath = path.join __dirname, 'fixtures', 'asar', 'a.asar', 'file1' - fileContent = require('fs').readFileSync(filePath) - - normalPath = path.join __dirname, 'fixtures', 'pages', 'a.html' - normalContent = require('fs').readFileSync(normalPath) - - it 'sends file path as response', (done) -> - handler = (request, callback) -> callback(filePath) - protocol.registerFileProtocol protocolName, handler, (error) -> - return done(error) if error - $.ajax - url: "#{protocolName}://fake-host" - success: (data) -> - assert.equal data, String(fileContent) - done() - error: (xhr, errorType, error) -> - done(error) - - it 'sets Access-Control-Allow-Origin', (done) -> - handler = (request, callback) -> callback(filePath) - protocol.registerFileProtocol protocolName, handler, (error) -> - return done(error) if error - $.ajax - url: "#{protocolName}://fake-host" - success: (data, status, request) -> - assert.equal data, String(fileContent) - assert.equal( - request.getResponseHeader('Access-Control-Allow-Origin'), - '*') - done() - error: (xhr, errorType, error) -> - done(error) - - it 'sends object as response', (done) -> - handler = (request, callback) -> callback(path: filePath) - protocol.registerFileProtocol protocolName, handler, (error) -> - return done(error) if error - $.ajax - url: "#{protocolName}://fake-host" - success: (data, statux, request) -> - assert.equal data, String(fileContent) - done() - error: (xhr, errorType, error) -> - done(error) - - it 'can send normal file', (done) -> - handler = (request, callback) -> callback(normalPath) - protocol.registerFileProtocol protocolName, handler, (error) -> - return done(error) if error - $.ajax - url: "#{protocolName}://fake-host" - success: (data) -> - assert.equal data, String(normalContent) - done() - error: (xhr, errorType, error) -> - done(error) - - it 'fails when sending unexist-file', (done) -> - fakeFilePath = path.join __dirname, 'fixtures', 'asar', 'a.asar', 'not-exist' - handler = (request, callback) -> callback(fakeFilePath) - protocol.registerBufferProtocol protocolName, handler, (error) -> - return done(error) if error - $.ajax - url: "#{protocolName}://fake-host" - success: (data) -> - done('request succeeded but it should not') - error: (xhr, errorType, error) -> - assert.equal errorType, 'error' - done() - - it 'fails when sending unsupported content', (done) -> - handler = (request, callback) -> callback(new Date) - protocol.registerBufferProtocol protocolName, handler, (error) -> - return done(error) if error - $.ajax - url: "#{protocolName}://fake-host" - success: (data) -> - done('request succeeded but it should not') - error: (xhr, errorType, error) -> - assert.equal errorType, 'error' - done() - - describe 'protocol.registerHttpProtocol', -> - it 'sends url as response', (done) -> - server = http.createServer (req, res) -> - assert.notEqual req.headers.accept, '' - res.end(text) - server.close() - server.listen 0, '127.0.0.1', -> - {port} = server.address() - url = "http://127.0.0.1:#{port}" - handler = (request, callback) -> callback({url}) - protocol.registerHttpProtocol protocolName, handler, (error) -> - return done(error) if error - $.ajax - url: "#{protocolName}://fake-host" - success: (data) -> - assert.equal data, text - done() - error: (xhr, errorType, error) -> - done(error) - - it 'fails when sending invalid url', (done) -> - handler = (request, callback) -> callback({url: 'url'}) - protocol.registerHttpProtocol protocolName, handler, (error) -> - return done(error) if error - $.ajax - url: "#{protocolName}://fake-host" - success: (data) -> - done('request succeeded but it should not') - error: (xhr, errorType, error) -> - assert.equal errorType, 'error' - done() - - it 'fails when sending unsupported content', (done) -> - handler = (request, callback) -> callback(new Date) - protocol.registerHttpProtocol protocolName, handler, (error) -> - return done(error) if error - $.ajax - url: "#{protocolName}://fake-host" - success: (data) -> - done('request succeeded but it should not') - error: (xhr, errorType, error) -> - assert.equal errorType, 'error' - done() - - describe 'protocol.isProtocolHandled', -> - it 'returns true for file:', (done) -> - protocol.isProtocolHandled 'file', (result) -> - assert.equal result, true - done() - - it 'returns true for http:', (done) -> - protocol.isProtocolHandled 'http', (result) -> - assert.equal result, true - done() - - it 'returns true for https:', (done) -> - protocol.isProtocolHandled 'https', (result) -> - assert.equal result, true - done() - - it 'returns false when scheme is not registred', (done) -> - protocol.isProtocolHandled 'no-exist', (result) -> - assert.equal result, false - done() - - it 'returns true for custom protocol', (done) -> - emptyHandler = (request, callback) -> callback() - protocol.registerStringProtocol protocolName, emptyHandler, (error) -> - assert.equal error, null - protocol.isProtocolHandled protocolName, (result) -> - assert.equal result, true - done() - - it 'returns true for intercepted protocol', (done) -> - emptyHandler = (request, callback) -> callback() - protocol.interceptStringProtocol 'http', emptyHandler, (error) -> - assert.equal error, null - protocol.isProtocolHandled 'http', (result) -> - assert.equal result, true - done() - - describe 'protocol.intercept(Any)Protocol', -> - emptyHandler = (request, callback) -> callback() - - it 'throws error when scheme is already intercepted', (done) -> - protocol.interceptStringProtocol 'http', emptyHandler, (error) -> - assert.equal error, null - protocol.interceptBufferProtocol 'http', emptyHandler, (error) -> - assert.notEqual error, null - done() - - it 'does not crash when handler is called twice', (done) -> - doubleHandler = (request, callback) -> - try - callback(text) - callback() - catch - protocol.interceptStringProtocol 'http', doubleHandler, (error) -> - return done(error) if error - $.ajax - url: 'http://fake-host' - success: (data) -> - assert.equal data, text - done() - error: (xhr, errorType, error) -> - done(error) - - it 'sends error when callback is called with nothing', (done) -> - # Flaky on Travis. - return done() if process.env.TRAVIS is 'true' - - protocol.interceptBufferProtocol 'http', emptyHandler, (error) -> - return done(error) if error - $.ajax - url: 'http://fake-host' - success: (data) -> - done('request succeeded but it should not') - error: (xhr, errorType, error) -> - assert.equal errorType, 'error' - done() - - describe 'protocol.interceptStringProtocol', -> - it 'can intercept http protocol', (done) -> - handler = (request, callback) -> callback(text) - protocol.interceptStringProtocol 'http', handler, (error) -> - return done(error) if error - $.ajax - url: 'http://fake-host' - success: (data) -> - assert.equal data, text - done() - error: (xhr, errorType, error) -> - done(error) - - it 'can set content-type', (done) -> - handler = (request, callback) -> - callback({mimeType: 'application/json', data: '{"value": 1}'}) - protocol.interceptStringProtocol 'http', handler, (error) -> - return done(error) if error - $.ajax - url: 'http://fake-host' - success: (data) -> - assert.equal typeof(data), 'object' - assert.equal data.value, 1 - done() - error: (xhr, errorType, error) -> - done(error) - - it 'can receive post data', (done) -> - handler = (request, callback) -> - uploadData = request.uploadData[0].bytes.toString() - callback({data: uploadData}) - protocol.interceptStringProtocol 'http', handler, (error) -> - return done(error) if error - $.ajax - url: "http://fake-host" - type: "POST" - data: postData - success: (data) -> - assert.deepEqual qs.parse(data), postData - done() - error: (xhr, errorType, error) -> - done(error) - - describe 'protocol.interceptBufferProtocol', -> - it 'can intercept http protocol', (done) -> - handler = (request, callback) -> callback(new Buffer(text)) - protocol.interceptBufferProtocol 'http', handler, (error) -> - return done(error) if error - $.ajax - url: 'http://fake-host' - success: (data) -> - assert.equal data, text - done() - error: (xhr, errorType, error) -> - done(error) - - it 'can receive post data', (done) -> - handler = (request, callback) -> - uploadData = request.uploadData[0].bytes - callback(uploadData) - protocol.interceptBufferProtocol 'http', handler, (error) -> - return done(error) if error - $.ajax - url: "http://fake-host" - type: "POST" - data: postData - success: (data) -> - assert.equal data, $.param postData - done() - error: (xhr, errorType, error) -> - done(error) - - describe 'protocol.interceptHttpProtocol', -> - it 'can send POST request', (done) -> - server = http.createServer (req, res) -> - body = '' - req.on 'data', (chunk) -> - body += chunk - req.on 'end', -> - res.end body - server.close() - server.listen 0, '127.0.0.1', -> - {port} = server.address() - url = "http://127.0.0.1:#{port}" - handler = (request, callback) -> - data = - url: url - method: 'POST' - uploadData: - contentType: 'application/x-www-form-urlencoded' - data: request.uploadData[0].bytes.toString() - session: null - callback(data) - protocol.interceptHttpProtocol 'http', handler, (error) -> - return done(error) if error - $.ajax - url: "http://fake-host" - type: "POST" - data: postData - success: (data) -> - assert.deepEqual qs.parse(data), postData - done() - error: (xhr, errorType, error) -> - done(error) - - describe 'protocol.uninterceptProtocol', -> - it 'returns error when scheme does not exist', (done) -> - protocol.uninterceptProtocol 'not-exist', (error) -> - assert.notEqual error, null - done() - - it 'returns error when scheme is not intercepted', (done) -> - protocol.uninterceptProtocol 'http', (error) -> - assert.notEqual error, null - done() diff --git a/spec/api-protocol-spec.js b/spec/api-protocol-spec.js new file mode 100644 index 000000000000..f0f19ecc5fb7 --- /dev/null +++ b/spec/api-protocol-spec.js @@ -0,0 +1,820 @@ +var assert, http, path, protocol, qs, remote; + +assert = require('assert'); + +http = require('http'); + +path = require('path'); + +qs = require('querystring'); + +remote = require('electron').remote; + +protocol = remote.require('electron').protocol; + +describe('protocol module', function() { + var postData, protocolName, text; + protocolName = 'sp'; + text = 'valar morghulis'; + postData = { + name: 'post test', + type: 'string' + }; + afterEach(function(done) { + return protocol.unregisterProtocol(protocolName, function() { + return protocol.uninterceptProtocol('http', function() { + return done(); + }); + }); + }); + describe('protocol.register(Any)Protocol', function() { + var emptyHandler; + emptyHandler = function(request, callback) { + return callback(); + }; + it('throws error when scheme is already registered', function(done) { + return protocol.registerStringProtocol(protocolName, emptyHandler, function(error) { + assert.equal(error, null); + return protocol.registerBufferProtocol(protocolName, emptyHandler, function(error) { + assert.notEqual(error, null); + return done(); + }); + }); + }); + it('does not crash when handler is called twice', function(done) { + var doubleHandler; + doubleHandler = function(request, callback) { + var error1; + try { + callback(text); + return callback(); + } catch (error1) { + + } + }; + return protocol.registerStringProtocol(protocolName, doubleHandler, function(error) { + if (error) { + return done(error); + } + return $.ajax({ + url: protocolName + "://fake-host", + success: function(data) { + assert.equal(data, text); + return done(); + }, + error: function(xhr, errorType, error) { + return done(error); + } + }); + }); + }); + it('sends error when callback is called with nothing', function(done) { + return protocol.registerBufferProtocol(protocolName, emptyHandler, function(error) { + if (error) { + return done(error); + } + return $.ajax({ + url: protocolName + "://fake-host", + success: function(data) { + return done('request succeeded but it should not'); + }, + error: function(xhr, errorType, error) { + assert.equal(errorType, 'error'); + return done(); + } + }); + }); + }); + return it('does not crash when callback is called in next tick', function(done) { + var handler; + handler = function(request, callback) { + return setImmediate(function() { + return callback(text); + }); + }; + return protocol.registerStringProtocol(protocolName, handler, function(error) { + if (error) { + return done(error); + } + return $.ajax({ + url: protocolName + "://fake-host", + success: function(data) { + assert.equal(data, text); + return done(); + }, + error: function(xhr, errorType, error) { + return done(error); + } + }); + }); + }); + }); + describe('protocol.unregisterProtocol', function() { + return it('returns error when scheme does not exist', function(done) { + return protocol.unregisterProtocol('not-exist', function(error) { + assert.notEqual(error, null); + return done(); + }); + }); + }); + describe('protocol.registerStringProtocol', function() { + it('sends string as response', function(done) { + var handler; + handler = function(request, callback) { + return callback(text); + }; + return protocol.registerStringProtocol(protocolName, handler, function(error) { + if (error) { + return done(error); + } + return $.ajax({ + url: protocolName + "://fake-host", + success: function(data) { + assert.equal(data, text); + return done(); + }, + error: function(xhr, errorType, error) { + return done(error); + } + }); + }); + }); + it('sets Access-Control-Allow-Origin', function(done) { + var handler; + handler = function(request, callback) { + return callback(text); + }; + return protocol.registerStringProtocol(protocolName, handler, function(error) { + if (error) { + return done(error); + } + return $.ajax({ + url: protocolName + "://fake-host", + success: function(data, status, request) { + assert.equal(data, text); + assert.equal(request.getResponseHeader('Access-Control-Allow-Origin'), '*'); + return done(); + }, + error: function(xhr, errorType, error) { + return done(error); + } + }); + }); + }); + it('sends object as response', function(done) { + var handler; + handler = function(request, callback) { + return callback({ + data: text, + mimeType: 'text/html' + }); + }; + return protocol.registerStringProtocol(protocolName, handler, function(error) { + if (error) { + return done(error); + } + return $.ajax({ + url: protocolName + "://fake-host", + success: function(data, statux, request) { + assert.equal(data, text); + return done(); + }, + error: function(xhr, errorType, error) { + return done(error); + } + }); + }); + }); + return it('fails when sending object other than string', function(done) { + var handler; + handler = function(request, callback) { + return callback(new Date); + }; + return protocol.registerBufferProtocol(protocolName, handler, function(error) { + if (error) { + return done(error); + } + return $.ajax({ + url: protocolName + "://fake-host", + success: function(data) { + return done('request succeeded but it should not'); + }, + error: function(xhr, errorType, error) { + assert.equal(errorType, 'error'); + return done(); + } + }); + }); + }); + }); + describe('protocol.registerBufferProtocol', function() { + var buffer; + buffer = new Buffer(text); + it('sends Buffer as response', function(done) { + var handler; + handler = function(request, callback) { + return callback(buffer); + }; + return protocol.registerBufferProtocol(protocolName, handler, function(error) { + if (error) { + return done(error); + } + return $.ajax({ + url: protocolName + "://fake-host", + success: function(data) { + assert.equal(data, text); + return done(); + }, + error: function(xhr, errorType, error) { + return done(error); + } + }); + }); + }); + it('sets Access-Control-Allow-Origin', function(done) { + var handler; + handler = function(request, callback) { + return callback(buffer); + }; + return protocol.registerBufferProtocol(protocolName, handler, function(error) { + if (error) { + return done(error); + } + return $.ajax({ + url: protocolName + "://fake-host", + success: function(data, status, request) { + assert.equal(data, text); + assert.equal(request.getResponseHeader('Access-Control-Allow-Origin'), '*'); + return done(); + }, + error: function(xhr, errorType, error) { + return done(error); + } + }); + }); + }); + it('sends object as response', function(done) { + var handler; + handler = function(request, callback) { + return callback({ + data: buffer, + mimeType: 'text/html' + }); + }; + return protocol.registerBufferProtocol(protocolName, handler, function(error) { + if (error) { + return done(error); + } + return $.ajax({ + url: protocolName + "://fake-host", + success: function(data, statux, request) { + assert.equal(data, text); + return done(); + }, + error: function(xhr, errorType, error) { + return done(error); + } + }); + }); + }); + return it('fails when sending string', function(done) { + var handler; + handler = function(request, callback) { + return callback(text); + }; + return protocol.registerBufferProtocol(protocolName, handler, function(error) { + if (error) { + return done(error); + } + return $.ajax({ + url: protocolName + "://fake-host", + success: function(data) { + return done('request succeeded but it should not'); + }, + error: function(xhr, errorType, error) { + assert.equal(errorType, 'error'); + return done(); + } + }); + }); + }); + }); + describe('protocol.registerFileProtocol', function() { + var fileContent, filePath, normalContent, normalPath; + filePath = path.join(__dirname, 'fixtures', 'asar', 'a.asar', 'file1'); + fileContent = require('fs').readFileSync(filePath); + normalPath = path.join(__dirname, 'fixtures', 'pages', 'a.html'); + normalContent = require('fs').readFileSync(normalPath); + it('sends file path as response', function(done) { + var handler; + handler = function(request, callback) { + return callback(filePath); + }; + return protocol.registerFileProtocol(protocolName, handler, function(error) { + if (error) { + return done(error); + } + return $.ajax({ + url: protocolName + "://fake-host", + success: function(data) { + assert.equal(data, String(fileContent)); + return done(); + }, + error: function(xhr, errorType, error) { + return done(error); + } + }); + }); + }); + it('sets Access-Control-Allow-Origin', function(done) { + var handler; + handler = function(request, callback) { + return callback(filePath); + }; + return protocol.registerFileProtocol(protocolName, handler, function(error) { + if (error) { + return done(error); + } + return $.ajax({ + url: protocolName + "://fake-host", + success: function(data, status, request) { + assert.equal(data, String(fileContent)); + assert.equal(request.getResponseHeader('Access-Control-Allow-Origin'), '*'); + return done(); + }, + error: function(xhr, errorType, error) { + return done(error); + } + }); + }); + }); + it('sends object as response', function(done) { + var handler; + handler = function(request, callback) { + return callback({ + path: filePath + }); + }; + return protocol.registerFileProtocol(protocolName, handler, function(error) { + if (error) { + return done(error); + } + return $.ajax({ + url: protocolName + "://fake-host", + success: function(data, statux, request) { + assert.equal(data, String(fileContent)); + return done(); + }, + error: function(xhr, errorType, error) { + return done(error); + } + }); + }); + }); + it('can send normal file', function(done) { + var handler; + handler = function(request, callback) { + return callback(normalPath); + }; + return protocol.registerFileProtocol(protocolName, handler, function(error) { + if (error) { + return done(error); + } + return $.ajax({ + url: protocolName + "://fake-host", + success: function(data) { + assert.equal(data, String(normalContent)); + return done(); + }, + error: function(xhr, errorType, error) { + return done(error); + } + }); + }); + }); + it('fails when sending unexist-file', function(done) { + var fakeFilePath, handler; + fakeFilePath = path.join(__dirname, 'fixtures', 'asar', 'a.asar', 'not-exist'); + handler = function(request, callback) { + return callback(fakeFilePath); + }; + return protocol.registerBufferProtocol(protocolName, handler, function(error) { + if (error) { + return done(error); + } + return $.ajax({ + url: protocolName + "://fake-host", + success: function(data) { + return done('request succeeded but it should not'); + }, + error: function(xhr, errorType, error) { + assert.equal(errorType, 'error'); + return done(); + } + }); + }); + }); + return it('fails when sending unsupported content', function(done) { + var handler; + handler = function(request, callback) { + return callback(new Date); + }; + return protocol.registerBufferProtocol(protocolName, handler, function(error) { + if (error) { + return done(error); + } + return $.ajax({ + url: protocolName + "://fake-host", + success: function(data) { + return done('request succeeded but it should not'); + }, + error: function(xhr, errorType, error) { + assert.equal(errorType, 'error'); + return done(); + } + }); + }); + }); + }); + describe('protocol.registerHttpProtocol', function() { + it('sends url as response', function(done) { + var server; + server = http.createServer(function(req, res) { + assert.notEqual(req.headers.accept, ''); + res.end(text); + return server.close(); + }); + return server.listen(0, '127.0.0.1', function() { + var handler, port, url; + port = server.address().port; + url = "http://127.0.0.1:" + port; + handler = function(request, callback) { + return callback({ + url: url + }); + }; + return protocol.registerHttpProtocol(protocolName, handler, function(error) { + if (error) { + return done(error); + } + return $.ajax({ + url: protocolName + "://fake-host", + success: function(data) { + assert.equal(data, text); + return done(); + }, + error: function(xhr, errorType, error) { + return done(error); + } + }); + }); + }); + }); + it('fails when sending invalid url', function(done) { + var handler; + handler = function(request, callback) { + return callback({ + url: 'url' + }); + }; + return protocol.registerHttpProtocol(protocolName, handler, function(error) { + if (error) { + return done(error); + } + return $.ajax({ + url: protocolName + "://fake-host", + success: function(data) { + return done('request succeeded but it should not'); + }, + error: function(xhr, errorType, error) { + assert.equal(errorType, 'error'); + return done(); + } + }); + }); + }); + return it('fails when sending unsupported content', function(done) { + var handler; + handler = function(request, callback) { + return callback(new Date); + }; + return protocol.registerHttpProtocol(protocolName, handler, function(error) { + if (error) { + return done(error); + } + return $.ajax({ + url: protocolName + "://fake-host", + success: function(data) { + return done('request succeeded but it should not'); + }, + error: function(xhr, errorType, error) { + assert.equal(errorType, 'error'); + return done(); + } + }); + }); + }); + }); + describe('protocol.isProtocolHandled', function() { + it('returns true for file:', function(done) { + return protocol.isProtocolHandled('file', function(result) { + assert.equal(result, true); + return done(); + }); + }); + it('returns true for http:', function(done) { + return protocol.isProtocolHandled('http', function(result) { + assert.equal(result, true); + return done(); + }); + }); + it('returns true for https:', function(done) { + return protocol.isProtocolHandled('https', function(result) { + assert.equal(result, true); + return done(); + }); + }); + it('returns false when scheme is not registred', function(done) { + return protocol.isProtocolHandled('no-exist', function(result) { + assert.equal(result, false); + return done(); + }); + }); + it('returns true for custom protocol', function(done) { + var emptyHandler; + emptyHandler = function(request, callback) { + return callback(); + }; + return protocol.registerStringProtocol(protocolName, emptyHandler, function(error) { + assert.equal(error, null); + return protocol.isProtocolHandled(protocolName, function(result) { + assert.equal(result, true); + return done(); + }); + }); + }); + return it('returns true for intercepted protocol', function(done) { + var emptyHandler; + emptyHandler = function(request, callback) { + return callback(); + }; + return protocol.interceptStringProtocol('http', emptyHandler, function(error) { + assert.equal(error, null); + return protocol.isProtocolHandled('http', function(result) { + assert.equal(result, true); + return done(); + }); + }); + }); + }); + describe('protocol.intercept(Any)Protocol', function() { + var emptyHandler; + emptyHandler = function(request, callback) { + return callback(); + }; + it('throws error when scheme is already intercepted', function(done) { + return protocol.interceptStringProtocol('http', emptyHandler, function(error) { + assert.equal(error, null); + return protocol.interceptBufferProtocol('http', emptyHandler, function(error) { + assert.notEqual(error, null); + return done(); + }); + }); + }); + it('does not crash when handler is called twice', function(done) { + var doubleHandler; + doubleHandler = function(request, callback) { + var error1; + try { + callback(text); + return callback(); + } catch (error1) { + + } + }; + return protocol.interceptStringProtocol('http', doubleHandler, function(error) { + if (error) { + return done(error); + } + return $.ajax({ + url: 'http://fake-host', + success: function(data) { + assert.equal(data, text); + return done(); + }, + error: function(xhr, errorType, error) { + return done(error); + } + }); + }); + }); + return it('sends error when callback is called with nothing', function(done) { + if (process.env.TRAVIS === 'true') { + return done(); + } + return protocol.interceptBufferProtocol('http', emptyHandler, function(error) { + if (error) { + return done(error); + } + return $.ajax({ + url: 'http://fake-host', + success: function(data) { + return done('request succeeded but it should not'); + }, + error: function(xhr, errorType, error) { + assert.equal(errorType, 'error'); + return done(); + } + }); + }); + }); + }); + describe('protocol.interceptStringProtocol', function() { + it('can intercept http protocol', function(done) { + var handler; + handler = function(request, callback) { + return callback(text); + }; + return protocol.interceptStringProtocol('http', handler, function(error) { + if (error) { + return done(error); + } + return $.ajax({ + url: 'http://fake-host', + success: function(data) { + assert.equal(data, text); + return done(); + }, + error: function(xhr, errorType, error) { + return done(error); + } + }); + }); + }); + it('can set content-type', function(done) { + var handler; + handler = function(request, callback) { + return callback({ + mimeType: 'application/json', + data: '{"value": 1}' + }); + }; + return protocol.interceptStringProtocol('http', handler, function(error) { + if (error) { + return done(error); + } + return $.ajax({ + url: 'http://fake-host', + success: function(data) { + assert.equal(typeof data, 'object'); + assert.equal(data.value, 1); + return done(); + }, + error: function(xhr, errorType, error) { + return done(error); + } + }); + }); + }); + return it('can receive post data', function(done) { + var handler; + handler = function(request, callback) { + var uploadData; + uploadData = request.uploadData[0].bytes.toString(); + return callback({ + data: uploadData + }); + }; + return protocol.interceptStringProtocol('http', handler, function(error) { + if (error) { + return done(error); + } + return $.ajax({ + url: "http://fake-host", + type: "POST", + data: postData, + success: function(data) { + assert.deepEqual(qs.parse(data), postData); + return done(); + }, + error: function(xhr, errorType, error) { + return done(error); + } + }); + }); + }); + }); + describe('protocol.interceptBufferProtocol', function() { + it('can intercept http protocol', function(done) { + var handler; + handler = function(request, callback) { + return callback(new Buffer(text)); + }; + return protocol.interceptBufferProtocol('http', handler, function(error) { + if (error) { + return done(error); + } + return $.ajax({ + url: 'http://fake-host', + success: function(data) { + assert.equal(data, text); + return done(); + }, + error: function(xhr, errorType, error) { + return done(error); + } + }); + }); + }); + return it('can receive post data', function(done) { + var handler; + handler = function(request, callback) { + var uploadData; + uploadData = request.uploadData[0].bytes; + return callback(uploadData); + }; + return protocol.interceptBufferProtocol('http', handler, function(error) { + if (error) { + return done(error); + } + return $.ajax({ + url: "http://fake-host", + type: "POST", + data: postData, + success: function(data) { + assert.equal(data, $.param(postData)); + return done(); + }, + error: function(xhr, errorType, error) { + return done(error); + } + }); + }); + }); + }); + describe('protocol.interceptHttpProtocol', function() { + return it('can send POST request', function(done) { + var server; + server = http.createServer(function(req, res) { + var body; + body = ''; + req.on('data', function(chunk) { + return body += chunk; + }); + req.on('end', function() { + return res.end(body); + }); + return server.close(); + }); + return server.listen(0, '127.0.0.1', function() { + var handler, port, url; + port = server.address().port; + url = "http://127.0.0.1:" + port; + handler = function(request, callback) { + var data; + data = { + url: url, + method: 'POST', + uploadData: { + contentType: 'application/x-www-form-urlencoded', + data: request.uploadData[0].bytes.toString() + }, + session: null + }; + return callback(data); + }; + return protocol.interceptHttpProtocol('http', handler, function(error) { + if (error) { + return done(error); + } + return $.ajax({ + url: "http://fake-host", + type: "POST", + data: postData, + success: function(data) { + assert.deepEqual(qs.parse(data), postData); + return done(); + }, + error: function(xhr, errorType, error) { + return done(error); + } + }); + }); + }); + }); + }); + return describe('protocol.uninterceptProtocol', function() { + it('returns error when scheme does not exist', function(done) { + return protocol.uninterceptProtocol('not-exist', function(error) { + assert.notEqual(error, null); + return done(); + }); + }); + return it('returns error when scheme is not intercepted', function(done) { + return protocol.uninterceptProtocol('http', function(error) { + assert.notEqual(error, null); + return done(); + }); + }); + }); +}); diff --git a/spec/api-screen-spec.coffee b/spec/api-screen-spec.coffee deleted file mode 100644 index 59ef49631cbc..000000000000 --- a/spec/api-screen-spec.coffee +++ /dev/null @@ -1,17 +0,0 @@ -assert = require 'assert' - -{screen} = require 'electron' - -describe 'screen module', -> - describe 'screen.getCursorScreenPoint()', -> - it 'returns a point object', -> - point = screen.getCursorScreenPoint() - assert.equal typeof(point.x), 'number' - assert.equal typeof(point.y), 'number' - - describe 'screen.getPrimaryDisplay()', -> - it 'returns a display object', -> - display = screen.getPrimaryDisplay() - assert.equal typeof(display.scaleFactor), 'number' - assert display.size.width > 0 - assert display.size.height > 0 diff --git a/spec/api-screen-spec.js b/spec/api-screen-spec.js new file mode 100644 index 000000000000..b393d4b99ee8 --- /dev/null +++ b/spec/api-screen-spec.js @@ -0,0 +1,25 @@ +var assert, screen; + +assert = require('assert'); + +screen = require('electron').screen; + +describe('screen module', function() { + describe('screen.getCursorScreenPoint()', function() { + return it('returns a point object', function() { + var point; + point = screen.getCursorScreenPoint(); + assert.equal(typeof point.x, 'number'); + return assert.equal(typeof point.y, 'number'); + }); + }); + return describe('screen.getPrimaryDisplay()', function() { + return it('returns a display object', function() { + var display; + display = screen.getPrimaryDisplay(); + assert.equal(typeof display.scaleFactor, 'number'); + assert(display.size.width > 0); + return assert(display.size.height > 0); + }); + }); +}); diff --git a/spec/api-session-spec.coffee b/spec/api-session-spec.coffee deleted file mode 100644 index 03c62c1f1db6..000000000000 --- a/spec/api-session-spec.coffee +++ /dev/null @@ -1,138 +0,0 @@ -assert = require 'assert' -http = require 'http' -path = require 'path' -fs = require 'fs' - -{ipcRenderer, remote} = require 'electron' -{app, ipcMain, session, BrowserWindow} = remote - -describe 'session module', -> - @timeout 10000 - fixtures = path.resolve __dirname, 'fixtures' - w = null - url = "http://127.0.0.1" - - beforeEach -> w = new BrowserWindow(show: false, width: 400, height: 400) - afterEach -> w.destroy() - - it 'should get cookies', (done) -> - server = http.createServer (req, res) -> - res.setHeader('Set-Cookie', ['0=0']) - res.end('finished') - server.close() - - server.listen 0, '127.0.0.1', -> - {port} = server.address() - w.loadURL "#{url}:#{port}" - w.webContents.on 'did-finish-load', -> - w.webContents.session.cookies.get {url: url}, (error, list) -> - return done(error) if error - for cookie in list when cookie.name is '0' - if cookie.value is '0' - return done() - else - return done("cookie value is #{cookie.value} while expecting 0") - done('Can not find cookie') - - it 'should over-write the existent cookie', (done) -> - session.defaultSession.cookies.set {url: url, name: '1', value: '1'}, (error) -> - return done(error) if error - session.defaultSession.cookies.get {url: url}, (error, list) -> - return done(error) if error - for cookie in list when cookie.name is '1' - if cookie.value is '1' - return done() - else - return done("cookie value is #{cookie.value} while expecting 1") - done('Can not find cookie') - - it 'should remove cookies', (done) -> - session.defaultSession.cookies.set {url: url, name: '2', value: '2'}, (error) -> - return done(error) if error - session.defaultSession.cookies.remove url, '2', -> - session.defaultSession.cookies.get {url: url}, (error, list) -> - return done(error) if error - for cookie in list when cookie.name is '2' - return done('Cookie not deleted') - done() - - describe 'session.clearStorageData(options)', -> - fixtures = path.resolve __dirname, 'fixtures' - it 'clears localstorage data', (done) -> - ipcMain.on 'count', (event, count) -> - ipcMain.removeAllListeners 'count' - assert not count - done() - w.loadURL 'file://' + path.join(fixtures, 'api', 'localstorage.html') - w.webContents.on 'did-finish-load', -> - options = - origin: "file://", - storages: ['localstorage'], - 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"' - 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() - - 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) -> - 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() - ipcRenderer.sendSync 'set-download-option', true - w.loadURL "#{url}:#{port}/" - ipcRenderer.once 'download-done', (event, 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() diff --git a/spec/api-session-spec.js b/spec/api-session-spec.js new file mode 100644 index 000000000000..403e715cf5c6 --- /dev/null +++ b/spec/api-session-spec.js @@ -0,0 +1,218 @@ +var BrowserWindow, app, assert, fs, http, ipcMain, ipcRenderer, path, ref, remote, session; + +assert = require('assert'); + +http = require('http'); + +path = require('path'); + +fs = require('fs'); + +ref = require('electron'), ipcRenderer = ref.ipcRenderer, remote = ref.remote; + +app = remote.app, ipcMain = remote.ipcMain, session = remote.session, BrowserWindow = remote.BrowserWindow; + +describe('session module', function() { + var fixtures, url, w; + this.timeout(10000); + fixtures = path.resolve(__dirname, 'fixtures'); + w = null; + url = "http://127.0.0.1"; + beforeEach(function() { + return w = new BrowserWindow({ + show: false, + width: 400, + height: 400 + }); + }); + afterEach(function() { + return w.destroy(); + }); + it('should get cookies', function(done) { + var server; + server = http.createServer(function(req, res) { + res.setHeader('Set-Cookie', ['0=0']); + res.end('finished'); + return server.close(); + }); + return server.listen(0, '127.0.0.1', function() { + var port; + port = server.address().port; + w.loadURL(url + ":" + port); + return w.webContents.on('did-finish-load', function() { + return w.webContents.session.cookies.get({ + url: url + }, function(error, list) { + var cookie, i, len; + if (error) { + return done(error); + } + for (i = 0, len = list.length; i < len; i++) { + cookie = list[i]; + if (cookie.name === '0') { + if (cookie.value === '0') { + return done(); + } else { + return done("cookie value is " + cookie.value + " while expecting 0"); + } + } + } + return done('Can not find cookie'); + }); + }); + }); + }); + it('should over-write the existent cookie', function(done) { + return session.defaultSession.cookies.set({ + url: url, + name: '1', + value: '1' + }, function(error) { + if (error) { + return done(error); + } + return session.defaultSession.cookies.get({ + url: url + }, function(error, list) { + var cookie, i, len; + if (error) { + return done(error); + } + for (i = 0, len = list.length; i < len; i++) { + cookie = list[i]; + if (cookie.name === '1') { + if (cookie.value === '1') { + return done(); + } else { + return done("cookie value is " + cookie.value + " while expecting 1"); + } + } + } + return done('Can not find cookie'); + }); + }); + }); + it('should remove cookies', function(done) { + return session.defaultSession.cookies.set({ + url: url, + name: '2', + value: '2' + }, function(error) { + if (error) { + return done(error); + } + return session.defaultSession.cookies.remove(url, '2', function() { + return session.defaultSession.cookies.get({ + url: url + }, function(error, list) { + var cookie, i, len; + if (error) { + return done(error); + } + for (i = 0, len = list.length; i < len; i++) { + cookie = list[i]; + if (cookie.name === '2') { + return done('Cookie not deleted'); + } + } + return done(); + }); + }); + }); + }); + describe('session.clearStorageData(options)', function() { + fixtures = path.resolve(__dirname, 'fixtures'); + return it('clears localstorage data', function(done) { + ipcMain.on('count', function(event, count) { + ipcMain.removeAllListeners('count'); + assert(!count); + return done(); + }); + w.loadURL('file://' + path.join(fixtures, 'api', 'localstorage.html')); + return w.webContents.on('did-finish-load', function() { + var options; + options = { + origin: "file://", + storages: ['localstorage'], + quotas: ['persistent'] + }; + return w.webContents.session.clearStorageData(options, function() { + return w.webContents.send('getcount'); + }); + }); + }); + }); + return describe('DownloadItem', function() { + var assertDownload, contentDisposition, downloadFilePath, downloadServer, mockPDF; + mockPDF = new Buffer(1024 * 1024 * 5); + contentDisposition = 'inline; filename="mock.pdf"'; + downloadFilePath = path.join(fixtures, 'mock.pdf'); + downloadServer = http.createServer(function(req, res) { + res.writeHead(200, { + 'Content-Length': mockPDF.length, + 'Content-Type': 'application/pdf', + 'Content-Disposition': contentDisposition + }); + res.end(mockPDF); + return downloadServer.close(); + }); + assertDownload = function(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)); + return fs.unlinkSync(downloadFilePath); + }; + it('can download using BrowserWindow.loadURL', function(done) { + return downloadServer.listen(0, '127.0.0.1', function() { + var port; + port = downloadServer.address().port; + ipcRenderer.sendSync('set-download-option', false); + w.loadURL(url + ":" + port); + return ipcRenderer.once('download-done', function(event, state, url, mimeType, receivedBytes, totalBytes, disposition, filename) { + assertDownload(event, state, url, mimeType, receivedBytes, totalBytes, disposition, filename, port); + return done(); + }); + }); + }); + it('can download using WebView.downloadURL', function(done) { + return downloadServer.listen(0, '127.0.0.1', function() { + var port, webview; + port = downloadServer.address().port; + ipcRenderer.sendSync('set-download-option', false); + webview = new WebView; + webview.src = "file://" + fixtures + "/api/blank.html"; + webview.addEventListener('did-finish-load', function() { + return webview.downloadURL(url + ":" + port + "/"); + }); + ipcRenderer.once('download-done', function(event, state, url, mimeType, receivedBytes, totalBytes, disposition, filename) { + assertDownload(event, state, url, mimeType, receivedBytes, totalBytes, disposition, filename, port); + document.body.removeChild(webview); + return done(); + }); + return document.body.appendChild(webview); + }); + }); + return it('can cancel download', function(done) { + return downloadServer.listen(0, '127.0.0.1', function() { + var port; + port = downloadServer.address().port; + ipcRenderer.sendSync('set-download-option', true); + w.loadURL(url + ":" + port + "/"); + return ipcRenderer.once('download-done', function(event, 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); + return done(); + }); + }); + }); + }); +}); diff --git a/spec/api-web-frame-spec.coffee b/spec/api-web-frame-spec.coffee deleted file mode 100644 index cece329084e1..000000000000 --- a/spec/api-web-frame-spec.coffee +++ /dev/null @@ -1,18 +0,0 @@ -assert = require 'assert' -path = require 'path' - -{webFrame} = require 'electron' - -describe 'webFrame module', -> - fixtures = path.resolve __dirname, 'fixtures' - - describe 'webFrame.registerURLSchemeAsPrivileged', -> - it 'supports fetch api', (done) -> - webFrame.registerURLSchemeAsPrivileged 'file' - url = "file://#{fixtures}/assets/logo.png" - - fetch(url).then((response) -> - assert response.ok - done() - ).catch (err) -> - done('unexpected error : ' + err) diff --git a/spec/api-web-frame-spec.js b/spec/api-web-frame-spec.js new file mode 100644 index 000000000000..3d287a6acba9 --- /dev/null +++ b/spec/api-web-frame-spec.js @@ -0,0 +1,25 @@ +var assert, path, webFrame; + +assert = require('assert'); + +path = require('path'); + +webFrame = require('electron').webFrame; + +describe('webFrame module', function() { + var fixtures; + fixtures = path.resolve(__dirname, 'fixtures'); + return describe('webFrame.registerURLSchemeAsPrivileged', function() { + return it('supports fetch api', function(done) { + var url; + webFrame.registerURLSchemeAsPrivileged('file'); + url = "file://" + fixtures + "/assets/logo.png"; + return fetch(url).then(function(response) { + assert(response.ok); + return done(); + })["catch"](function(err) { + return done('unexpected error : ' + err); + }); + }); + }); +}); diff --git a/spec/api-web-request-spec.coffee b/spec/api-web-request-spec.coffee deleted file mode 100644 index 5c78ef1d30a6..000000000000 --- a/spec/api-web-request-spec.coffee +++ /dev/null @@ -1,243 +0,0 @@ -assert = require 'assert' -http = require 'http' - -{remote} = require 'electron' -{session} = remote - -describe 'webRequest module', -> - ses = session.defaultSession - server = http.createServer (req, res) -> - res.setHeader('Custom', ['Header']) - content = req.url - if req.headers.accept is '*/*;test/header' - content += 'header/received' - res.end content - defaultURL = null - - before (done) -> - server.listen 0, '127.0.0.1', -> - {port} = server.address() - defaultURL = "http://127.0.0.1:#{port}/" - done() - after -> - server.close() - - describe 'webRequest.onBeforeRequest', -> - afterEach -> - ses.webRequest.onBeforeRequest null - - it 'can cancel the request', (done) -> - ses.webRequest.onBeforeRequest (details, callback) -> - callback(cancel: true) - $.ajax - url: defaultURL - success: (data) -> done('unexpected success') - error: (xhr, errorType, error) -> done() - - it 'can filter URLs', (done) -> - filter = urls: ["#{defaultURL}filter/*"] - ses.webRequest.onBeforeRequest filter, (details, callback) -> - callback(cancel: true) - $.ajax - url: "#{defaultURL}nofilter/test" - success: (data) -> - assert.equal data, '/nofilter/test' - $.ajax - url: "#{defaultURL}filter/test" - success: (data) -> done('unexpected success') - error: (xhr, errorType, error) -> done() - error: (xhr, errorType, error) -> done(errorType) - - it 'receives details object', (done) -> - ses.webRequest.onBeforeRequest (details, callback) -> - assert.equal typeof details.id, 'number' - assert.equal typeof details.timestamp, 'number' - assert.equal details.url, defaultURL - assert.equal details.method, 'GET' - assert.equal details.resourceType, 'xhr' - callback({}) - $.ajax - url: defaultURL - success: (data) -> - assert.equal data, '/' - done() - error: (xhr, errorType, error) -> done(errorType) - - it 'can redirect the request', (done) -> - ses.webRequest.onBeforeRequest (details, callback) -> - if details.url is defaultURL - callback(redirectURL: "#{defaultURL}redirect") - else - callback({}) - $.ajax - url: defaultURL - success: (data) -> - assert.equal data, '/redirect' - done() - error: (xhr, errorType, error) -> done(errorType) - - describe 'webRequest.onBeforeSendHeaders', -> - afterEach -> - ses.webRequest.onBeforeSendHeaders null - - it 'receives details object', (done) -> - ses.webRequest.onBeforeSendHeaders (details, callback) -> - assert.equal typeof details.requestHeaders, 'object' - callback({}) - $.ajax - url: defaultURL - success: (data) -> - assert.equal data, '/' - done() - error: (xhr, errorType, error) -> done(errorType) - - it 'can change the request headers', (done) -> - ses.webRequest.onBeforeSendHeaders (details, callback) -> - {requestHeaders} = details - requestHeaders.Accept = '*/*;test/header' - callback({requestHeaders}) - $.ajax - url: defaultURL - success: (data, textStatus, request) -> - assert.equal data, '/header/received' - done() - error: (xhr, errorType, error) -> done(errorType) - - it 'resets the whole headers', (done) -> - requestHeaders = Test: 'header' - ses.webRequest.onBeforeSendHeaders (details, callback) -> - callback({requestHeaders}) - ses.webRequest.onSendHeaders (details) -> - assert.deepEqual details.requestHeaders, requestHeaders - done() - $.ajax - url: defaultURL - error: (xhr, errorType, error) -> done(errorType) - - describe 'webRequest.onSendHeaders', -> - afterEach -> - ses.webRequest.onSendHeaders null - - it 'receives details object', (done) -> - ses.webRequest.onSendHeaders (details) -> - assert.equal typeof details.requestHeaders, 'object' - $.ajax - url: defaultURL - success: (data) -> - assert.equal data, '/' - done() - error: (xhr, errorType, error) -> done(errorType) - - describe 'webRequest.onHeadersReceived', -> - afterEach -> - ses.webRequest.onHeadersReceived null - - it 'receives details object', (done) -> - ses.webRequest.onHeadersReceived (details, callback) -> - assert.equal details.statusLine, 'HTTP/1.1 200 OK' - assert.equal details.statusCode, 200 - assert.equal details.responseHeaders['Custom'], 'Header' - callback({}) - $.ajax - url: defaultURL - success: (data) -> - assert.equal data, '/' - done() - error: (xhr, errorType, error) -> done(errorType) - - it 'can change the response header', (done) -> - ses.webRequest.onHeadersReceived (details, callback) -> - {responseHeaders} = details - responseHeaders['Custom'] = ['Changed'] - callback({responseHeaders}) - $.ajax - url: defaultURL - success: (data, status, xhr) -> - assert.equal xhr.getResponseHeader('Custom'), 'Changed' - assert.equal data, '/' - done() - error: (xhr, errorType, error) -> done(errorType) - - it 'does not change header by default', (done) -> - ses.webRequest.onHeadersReceived (details, callback) -> - callback({}) - $.ajax - url: defaultURL - success: (data, status, xhr) -> - assert.equal xhr.getResponseHeader('Custom'), 'Header' - assert.equal data, '/' - done() - error: (xhr, errorType, error) -> done(errorType) - - describe 'webRequest.onResponseStarted', -> - afterEach -> - ses.webRequest.onResponseStarted null - - it 'receives details object', (done) -> - ses.webRequest.onResponseStarted (details) -> - assert.equal typeof details.fromCache, 'boolean' - assert.equal details.statusLine, 'HTTP/1.1 200 OK' - assert.equal details.statusCode, 200 - assert.equal details.responseHeaders['Custom'], 'Header' - $.ajax - url: defaultURL - success: (data, status, xhr) -> - assert.equal xhr.getResponseHeader('Custom'), 'Header' - assert.equal data, '/' - done() - error: (xhr, errorType, error) -> done(errorType) - - describe 'webRequest.onBeforeRedirect', -> - afterEach -> - ses.webRequest.onBeforeRedirect null - ses.webRequest.onBeforeRequest null - - it 'receives details object', (done) -> - redirectURL = "#{defaultURL}redirect" - ses.webRequest.onBeforeRequest (details, callback) -> - if details.url is defaultURL - callback({redirectURL}) - else - callback({}) - ses.webRequest.onBeforeRedirect (details) -> - assert.equal typeof details.fromCache, 'boolean' - assert.equal details.statusLine, 'HTTP/1.1 307 Internal Redirect' - assert.equal details.statusCode, 307 - assert.equal details.redirectURL, redirectURL - $.ajax - url: defaultURL - success: (data, status, xhr) -> - assert.equal data, '/redirect' - done() - error: (xhr, errorType, error) -> done(errorType) - - describe 'webRequest.onCompleted', -> - afterEach -> - ses.webRequest.onCompleted null - - it 'receives details object', (done) -> - ses.webRequest.onCompleted (details) -> - assert.equal typeof details.fromCache, 'boolean' - assert.equal details.statusLine, 'HTTP/1.1 200 OK' - assert.equal details.statusCode, 200 - $.ajax - url: defaultURL - success: (data, status, xhr) -> - assert.equal data, '/' - done() - error: (xhr, errorType, error) -> done(errorType) - - describe 'webRequest.onErrorOccurred', -> - afterEach -> - ses.webRequest.onErrorOccurred null - ses.webRequest.onBeforeRequest null - - it 'receives details object', (done) -> - ses.webRequest.onBeforeRequest (details, callback) -> - callback(cancel: true) - ses.webRequest.onErrorOccurred (details) -> - assert.equal details.error, 'net::ERR_BLOCKED_BY_CLIENT' - done() - $.ajax - url: defaultURL - success: (data) -> done('unexpected success') diff --git a/spec/api-web-request-spec.js b/spec/api-web-request-spec.js new file mode 100644 index 000000000000..854b28391213 --- /dev/null +++ b/spec/api-web-request-spec.js @@ -0,0 +1,372 @@ +var assert, http, remote, session; + +assert = require('assert'); + +http = require('http'); + +remote = require('electron').remote; + +session = remote.session; + +describe('webRequest module', function() { + var defaultURL, server, ses; + ses = session.defaultSession; + server = http.createServer(function(req, res) { + var content; + res.setHeader('Custom', ['Header']); + content = req.url; + if (req.headers.accept === '*/*;test/header') { + content += 'header/received'; + } + return res.end(content); + }); + defaultURL = null; + before(function(done) { + return server.listen(0, '127.0.0.1', function() { + var port; + port = server.address().port; + defaultURL = "http://127.0.0.1:" + port + "/"; + return done(); + }); + }); + after(function() { + return server.close(); + }); + describe('webRequest.onBeforeRequest', function() { + afterEach(function() { + return ses.webRequest.onBeforeRequest(null); + }); + it('can cancel the request', function(done) { + ses.webRequest.onBeforeRequest(function(details, callback) { + return callback({ + cancel: true + }); + }); + return $.ajax({ + url: defaultURL, + success: function(data) { + return done('unexpected success'); + }, + error: function(xhr, errorType, error) { + return done(); + } + }); + }); + it('can filter URLs', function(done) { + var filter; + filter = { + urls: [defaultURL + "filter/*"] + }; + ses.webRequest.onBeforeRequest(filter, function(details, callback) { + return callback({ + cancel: true + }); + }); + return $.ajax({ + url: defaultURL + "nofilter/test", + success: function(data) { + assert.equal(data, '/nofilter/test'); + return $.ajax({ + url: defaultURL + "filter/test", + success: function(data) { + return done('unexpected success'); + }, + error: function(xhr, errorType, error) { + return done(); + } + }); + }, + error: function(xhr, errorType, error) { + return done(errorType); + } + }); + }); + it('receives details object', function(done) { + ses.webRequest.onBeforeRequest(function(details, callback) { + assert.equal(typeof details.id, 'number'); + assert.equal(typeof details.timestamp, 'number'); + assert.equal(details.url, defaultURL); + assert.equal(details.method, 'GET'); + assert.equal(details.resourceType, 'xhr'); + return callback({}); + }); + return $.ajax({ + url: defaultURL, + success: function(data) { + assert.equal(data, '/'); + return done(); + }, + error: function(xhr, errorType, error) { + return done(errorType); + } + }); + }); + return it('can redirect the request', function(done) { + ses.webRequest.onBeforeRequest(function(details, callback) { + if (details.url === defaultURL) { + return callback({ + redirectURL: defaultURL + "redirect" + }); + } else { + return callback({}); + } + }); + return $.ajax({ + url: defaultURL, + success: function(data) { + assert.equal(data, '/redirect'); + return done(); + }, + error: function(xhr, errorType, error) { + return done(errorType); + } + }); + }); + }); + describe('webRequest.onBeforeSendHeaders', function() { + afterEach(function() { + return ses.webRequest.onBeforeSendHeaders(null); + }); + it('receives details object', function(done) { + ses.webRequest.onBeforeSendHeaders(function(details, callback) { + assert.equal(typeof details.requestHeaders, 'object'); + return callback({}); + }); + return $.ajax({ + url: defaultURL, + success: function(data) { + assert.equal(data, '/'); + return done(); + }, + error: function(xhr, errorType, error) { + return done(errorType); + } + }); + }); + it('can change the request headers', function(done) { + ses.webRequest.onBeforeSendHeaders(function(details, callback) { + var requestHeaders; + requestHeaders = details.requestHeaders; + requestHeaders.Accept = '*/*;test/header'; + return callback({ + requestHeaders: requestHeaders + }); + }); + return $.ajax({ + url: defaultURL, + success: function(data, textStatus, request) { + assert.equal(data, '/header/received'); + return done(); + }, + error: function(xhr, errorType, error) { + return done(errorType); + } + }); + }); + return it('resets the whole headers', function(done) { + var requestHeaders; + requestHeaders = { + Test: 'header' + }; + ses.webRequest.onBeforeSendHeaders(function(details, callback) { + return callback({ + requestHeaders: requestHeaders + }); + }); + ses.webRequest.onSendHeaders(function(details) { + assert.deepEqual(details.requestHeaders, requestHeaders); + return done(); + }); + return $.ajax({ + url: defaultURL, + error: function(xhr, errorType, error) { + return done(errorType); + } + }); + }); + }); + describe('webRequest.onSendHeaders', function() { + afterEach(function() { + return ses.webRequest.onSendHeaders(null); + }); + return it('receives details object', function(done) { + ses.webRequest.onSendHeaders(function(details) { + return assert.equal(typeof details.requestHeaders, 'object'); + }); + return $.ajax({ + url: defaultURL, + success: function(data) { + assert.equal(data, '/'); + return done(); + }, + error: function(xhr, errorType, error) { + return done(errorType); + } + }); + }); + }); + describe('webRequest.onHeadersReceived', function() { + afterEach(function() { + return ses.webRequest.onHeadersReceived(null); + }); + it('receives details object', function(done) { + ses.webRequest.onHeadersReceived(function(details, callback) { + assert.equal(details.statusLine, 'HTTP/1.1 200 OK'); + assert.equal(details.statusCode, 200); + assert.equal(details.responseHeaders['Custom'], 'Header'); + return callback({}); + }); + return $.ajax({ + url: defaultURL, + success: function(data) { + assert.equal(data, '/'); + return done(); + }, + error: function(xhr, errorType, error) { + return done(errorType); + } + }); + }); + it('can change the response header', function(done) { + ses.webRequest.onHeadersReceived(function(details, callback) { + var responseHeaders; + responseHeaders = details.responseHeaders; + responseHeaders['Custom'] = ['Changed']; + return callback({ + responseHeaders: responseHeaders + }); + }); + return $.ajax({ + url: defaultURL, + success: function(data, status, xhr) { + assert.equal(xhr.getResponseHeader('Custom'), 'Changed'); + assert.equal(data, '/'); + return done(); + }, + error: function(xhr, errorType, error) { + return done(errorType); + } + }); + }); + return it('does not change header by default', function(done) { + ses.webRequest.onHeadersReceived(function(details, callback) { + return callback({}); + }); + return $.ajax({ + url: defaultURL, + success: function(data, status, xhr) { + assert.equal(xhr.getResponseHeader('Custom'), 'Header'); + assert.equal(data, '/'); + return done(); + }, + error: function(xhr, errorType, error) { + return done(errorType); + } + }); + }); + }); + describe('webRequest.onResponseStarted', function() { + afterEach(function() { + return ses.webRequest.onResponseStarted(null); + }); + return it('receives details object', function(done) { + ses.webRequest.onResponseStarted(function(details) { + assert.equal(typeof details.fromCache, 'boolean'); + assert.equal(details.statusLine, 'HTTP/1.1 200 OK'); + assert.equal(details.statusCode, 200); + return assert.equal(details.responseHeaders['Custom'], 'Header'); + }); + return $.ajax({ + url: defaultURL, + success: function(data, status, xhr) { + assert.equal(xhr.getResponseHeader('Custom'), 'Header'); + assert.equal(data, '/'); + return done(); + }, + error: function(xhr, errorType, error) { + return done(errorType); + } + }); + }); + }); + describe('webRequest.onBeforeRedirect', function() { + afterEach(function() { + ses.webRequest.onBeforeRedirect(null); + return ses.webRequest.onBeforeRequest(null); + }); + return it('receives details object', function(done) { + var redirectURL; + redirectURL = defaultURL + "redirect"; + ses.webRequest.onBeforeRequest(function(details, callback) { + if (details.url === defaultURL) { + return callback({ + redirectURL: redirectURL + }); + } else { + return callback({}); + } + }); + ses.webRequest.onBeforeRedirect(function(details) { + assert.equal(typeof details.fromCache, 'boolean'); + assert.equal(details.statusLine, 'HTTP/1.1 307 Internal Redirect'); + assert.equal(details.statusCode, 307); + return assert.equal(details.redirectURL, redirectURL); + }); + return $.ajax({ + url: defaultURL, + success: function(data, status, xhr) { + assert.equal(data, '/redirect'); + return done(); + }, + error: function(xhr, errorType, error) { + return done(errorType); + } + }); + }); + }); + describe('webRequest.onCompleted', function() { + afterEach(function() { + return ses.webRequest.onCompleted(null); + }); + return it('receives details object', function(done) { + ses.webRequest.onCompleted(function(details) { + assert.equal(typeof details.fromCache, 'boolean'); + assert.equal(details.statusLine, 'HTTP/1.1 200 OK'); + return assert.equal(details.statusCode, 200); + }); + return $.ajax({ + url: defaultURL, + success: function(data, status, xhr) { + assert.equal(data, '/'); + return done(); + }, + error: function(xhr, errorType, error) { + return done(errorType); + } + }); + }); + }); + return describe('webRequest.onErrorOccurred', function() { + afterEach(function() { + ses.webRequest.onErrorOccurred(null); + return ses.webRequest.onBeforeRequest(null); + }); + return it('receives details object', function(done) { + ses.webRequest.onBeforeRequest(function(details, callback) { + return callback({ + cancel: true + }); + }); + ses.webRequest.onErrorOccurred(function(details) { + assert.equal(details.error, 'net::ERR_BLOCKED_BY_CLIENT'); + return done(); + }); + return $.ajax({ + url: defaultURL, + success: function(data) { + return done('unexpected success'); + } + }); + }); + }); +}); diff --git a/spec/asar-spec.coffee b/spec/asar-spec.coffee deleted file mode 100644 index 7642283cea4d..000000000000 --- a/spec/asar-spec.coffee +++ /dev/null @@ -1,578 +0,0 @@ -assert = require 'assert' -child_process = require 'child_process' -fs = require 'fs' -path = require 'path' - -{nativeImage, remote} = require 'electron' -{ipcMain, BrowserWindow} = remote.require 'electron' - -describe 'asar package', -> - fixtures = path.join __dirname, 'fixtures' - - 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' - file2 = path.join fixtures, 'asar', 'a.asar', 'file2' - assert.equal fs.readFileSync(file2).toString().trim(), 'file2' - file3 = path.join fixtures, 'asar', 'a.asar', 'file3' - assert.equal fs.readFileSync(file3).toString().trim(), 'file3' - - it 'reads from a empty file', -> - file = path.join fixtures, 'asar', 'empty.asar', 'file1' - buffer = fs.readFileSync(file) - assert.equal buffer.length, 0 - assert.equal buffer.toString(), '' - - it 'reads a linked file', -> - p = path.join fixtures, 'asar', 'a.asar', 'link1' - assert.equal fs.readFileSync(p).toString().trim(), 'file1' - - it 'reads a file from linked directory', -> - p = path.join fixtures, 'asar', 'a.asar', 'link2', 'file1' - assert.equal fs.readFileSync(p).toString().trim(), 'file1' - p = path.join fixtures, 'asar', 'a.asar', 'link2', 'link2', 'file1' - assert.equal fs.readFileSync(p).toString().trim(), 'file1' - - it 'throws ENOENT error when can not find file', -> - p = path.join fixtures, 'asar', 'a.asar', 'not-exist' - throws = -> fs.readFileSync p - assert.throws throws, /ENOENT/ - - it 'passes ENOENT error to callback when can not find file', -> - p = path.join fixtures, 'asar', 'a.asar', 'not-exist' - async = false - fs.readFile p, (e) -> - assert async - assert /ENOENT/.test e - async = true - - it 'reads a normal file with unpacked files', -> - p = path.join fixtures, 'asar', 'unpack.asar', 'a.txt' - assert.equal fs.readFileSync(p).toString().trim(), 'a' - - describe 'fs.readFile', -> - it 'reads a normal file', (done) -> - p = path.join fixtures, 'asar', 'a.asar', 'file1' - fs.readFile p, (err, content) -> - assert.equal err, null - assert.equal String(content).trim(), 'file1' - done() - - it 'reads from a empty file', (done) -> - p = path.join fixtures, 'asar', 'empty.asar', 'file1' - fs.readFile p, (err, content) -> - assert.equal err, null - assert.equal String(content), '' - done() - - it 'reads a linked file', (done) -> - p = path.join fixtures, 'asar', 'a.asar', 'link1' - fs.readFile p, (err, content) -> - assert.equal err, null - assert.equal String(content).trim(), 'file1' - done() - - it 'reads a file from linked directory', (done) -> - p = path.join fixtures, 'asar', 'a.asar', 'link2', 'link2', 'file1' - fs.readFile p, (err, content) -> - assert.equal err, null - assert.equal String(content).trim(), 'file1' - done() - - it 'throws ENOENT error when can not find file', (done) -> - p = path.join fixtures, 'asar', 'a.asar', 'not-exist' - fs.readFile p, (err, content) -> - assert.equal err.code, 'ENOENT' - done() - - describe 'fs.lstatSync', -> - it 'handles path with trailing slash correctly', -> - p = path.join fixtures, 'asar', 'a.asar', 'link2', 'link2', 'file1' - fs.lstatSync p - fs.lstatSync p + '/' - - it 'returns information of root', -> - p = path.join fixtures, 'asar', 'a.asar' - stats = fs.lstatSync p - assert.equal stats.isFile(), false - assert.equal stats.isDirectory(), true - assert.equal stats.isSymbolicLink(), false - assert.equal stats.size, 0 - - it 'returns information of a normal file', -> - for file in ['file1', 'file2', 'file3', path.join('dir1', 'file1'), path.join('link2', 'file1')] - p = path.join fixtures, 'asar', 'a.asar', file - stats = fs.lstatSync p - assert.equal stats.isFile(), true - assert.equal stats.isDirectory(), false - assert.equal stats.isSymbolicLink(), false - assert.equal stats.size, 6 - - it 'returns information of a normal directory', -> - for file in ['dir1', 'dir2', 'dir3'] - p = path.join fixtures, 'asar', 'a.asar', file - stats = fs.lstatSync p - assert.equal stats.isFile(), false - assert.equal stats.isDirectory(), true - assert.equal stats.isSymbolicLink(), false - assert.equal stats.size, 0 - - it 'returns information of a linked file', -> - for file in ['link1', path.join('dir1', 'link1'), path.join('link2', 'link2')] - p = path.join fixtures, 'asar', 'a.asar', file - stats = fs.lstatSync p - assert.equal stats.isFile(), false - assert.equal stats.isDirectory(), false - assert.equal stats.isSymbolicLink(), true - assert.equal stats.size, 0 - - it 'returns information of a linked directory', -> - for file in ['link2', path.join('dir1', 'link2'), path.join('link2', 'link2')] - p = path.join fixtures, 'asar', 'a.asar', file - stats = fs.lstatSync p - assert.equal stats.isFile(), false - assert.equal stats.isDirectory(), false - assert.equal stats.isSymbolicLink(), true - assert.equal stats.size, 0 - - it 'throws ENOENT error when can not find file', -> - for file in ['file4', 'file5', path.join('dir1', 'file4')] - p = path.join fixtures, 'asar', 'a.asar', file - throws = -> fs.lstatSync p - assert.throws throws, /ENOENT/ - - describe 'fs.lstat', -> - it 'handles path with trailing slash correctly', (done) -> - p = path.join fixtures, 'asar', 'a.asar', 'link2', 'link2', 'file1' - fs.lstat p + '/', done - - it 'returns information of root', (done) -> - p = path.join fixtures, 'asar', 'a.asar' - stats = fs.lstat p, (err, stats) -> - assert.equal err, null - assert.equal stats.isFile(), false - assert.equal stats.isDirectory(), true - assert.equal stats.isSymbolicLink(), false - assert.equal stats.size, 0 - done() - - it 'returns information of a normal file', (done) -> - p = path.join fixtures, 'asar', 'a.asar', 'link2', 'file1' - stats = fs.lstat p, (err, stats) -> - assert.equal err, null - assert.equal stats.isFile(), true - assert.equal stats.isDirectory(), false - assert.equal stats.isSymbolicLink(), false - assert.equal stats.size, 6 - done() - - it 'returns information of a normal directory', (done) -> - p = path.join fixtures, 'asar', 'a.asar', 'dir1' - stats = fs.lstat p, (err, stats) -> - assert.equal err, null - assert.equal stats.isFile(), false - assert.equal stats.isDirectory(), true - assert.equal stats.isSymbolicLink(), false - assert.equal stats.size, 0 - done() - - it 'returns information of a linked file', (done) -> - p = path.join fixtures, 'asar', 'a.asar', 'link2', 'link1' - stats = fs.lstat p, (err, stats) -> - assert.equal err, null - assert.equal stats.isFile(), false - assert.equal stats.isDirectory(), false - assert.equal stats.isSymbolicLink(), true - assert.equal stats.size, 0 - done() - - it 'returns information of a linked directory', (done) -> - p = path.join fixtures, 'asar', 'a.asar', 'link2', 'link2' - stats = fs.lstat p, (err, stats) -> - assert.equal err, null - assert.equal stats.isFile(), false - assert.equal stats.isDirectory(), false - assert.equal stats.isSymbolicLink(), true - assert.equal stats.size, 0 - done() - - it 'throws ENOENT error when can not find file', (done) -> - p = path.join fixtures, 'asar', 'a.asar', 'file4' - stats = fs.lstat p, (err, stats) -> - assert.equal err.code, 'ENOENT' - done() - - describe 'fs.realpathSync', -> - it 'returns real path root', -> - parent = fs.realpathSync path.join(fixtures, 'asar') - p = 'a.asar' - r = fs.realpathSync path.join(parent, p) - assert.equal r, path.join(parent, p) - - it 'returns real path of a normal file', -> - parent = fs.realpathSync path.join(fixtures, 'asar') - p = path.join 'a.asar', 'file1' - r = fs.realpathSync path.join(parent, p) - assert.equal r, path.join(parent, p) - - it 'returns real path of a normal directory', -> - parent = fs.realpathSync path.join(fixtures, 'asar') - p = path.join 'a.asar', 'dir1' - r = fs.realpathSync path.join(parent, p) - assert.equal r, path.join(parent, p) - - it 'returns real path of a linked file', -> - parent = fs.realpathSync path.join(fixtures, 'asar') - p = path.join 'a.asar', 'link2', 'link1' - r = fs.realpathSync path.join(parent, p) - assert.equal r, path.join(parent, 'a.asar', 'file1') - - it 'returns real path of a linked directory', -> - parent = fs.realpathSync path.join(fixtures, 'asar') - p = path.join 'a.asar', 'link2', 'link2' - r = fs.realpathSync path.join(parent, p) - assert.equal r, path.join(parent, 'a.asar', 'dir1') - - it 'throws ENOENT error when can not find file', -> - parent = fs.realpathSync path.join(fixtures, 'asar') - p = path.join 'a.asar', 'not-exist' - throws = -> fs.realpathSync path.join(parent, p) - assert.throws throws, /ENOENT/ - - describe 'fs.realpath', -> - it 'returns real path root', (done) -> - parent = fs.realpathSync path.join(fixtures, 'asar') - p = 'a.asar' - fs.realpath path.join(parent, p), (err, r) -> - assert.equal err, null - assert.equal r, path.join(parent, p) - done() - - it 'returns real path of a normal file', (done) -> - parent = fs.realpathSync path.join(fixtures, 'asar') - p = path.join 'a.asar', 'file1' - fs.realpath path.join(parent, p), (err, r) -> - assert.equal err, null - assert.equal r, path.join(parent, p) - done() - - it 'returns real path of a normal directory', (done) -> - parent = fs.realpathSync path.join(fixtures, 'asar') - p = path.join 'a.asar', 'dir1' - fs.realpath path.join(parent, p), (err, r) -> - assert.equal err, null - assert.equal r, path.join(parent, p) - done() - - it 'returns real path of a linked file', (done) -> - parent = fs.realpathSync path.join(fixtures, 'asar') - p = path.join 'a.asar', 'link2', 'link1' - fs.realpath path.join(parent, p), (err, r) -> - assert.equal err, null - assert.equal r, path.join(parent, 'a.asar', 'file1') - done() - - it 'returns real path of a linked directory', (done) -> - parent = fs.realpathSync path.join(fixtures, 'asar') - p = path.join 'a.asar', 'link2', 'link2' - fs.realpath path.join(parent, p), (err, r) -> - assert.equal err, null - assert.equal r, path.join(parent, 'a.asar', 'dir1') - done() - - it 'throws ENOENT error when can not find file', (done) -> - parent = fs.realpathSync path.join(fixtures, 'asar') - p = path.join 'a.asar', 'not-exist' - fs.realpath path.join(parent, p), (err, stats) -> - assert.equal err.code, 'ENOENT' - done() - - describe 'fs.readdirSync', -> - it 'reads dirs from root', -> - p = path.join fixtures, 'asar', 'a.asar' - dirs = fs.readdirSync p - assert.deepEqual dirs, ['dir1', 'dir2', 'dir3', 'file1', 'file2', 'file3', 'link1', 'link2', 'ping.js'] - - it 'reads dirs from a normal dir', -> - p = path.join fixtures, 'asar', 'a.asar', 'dir1' - dirs = fs.readdirSync p - assert.deepEqual dirs, ['file1', 'file2', 'file3', 'link1', 'link2'] - - it 'reads dirs from a linked dir', -> - p = path.join fixtures, 'asar', 'a.asar', 'link2', 'link2' - dirs = fs.readdirSync p - assert.deepEqual dirs, ['file1', 'file2', 'file3', 'link1', 'link2'] - - it 'throws ENOENT error when can not find file', -> - p = path.join fixtures, 'asar', 'a.asar', 'not-exist' - throws = -> fs.readdirSync p - assert.throws throws, /ENOENT/ - - describe 'fs.readdir', -> - it 'reads dirs from root', (done) -> - p = path.join fixtures, 'asar', 'a.asar' - dirs = fs.readdir p, (err, dirs) -> - assert.equal err, null - assert.deepEqual dirs, ['dir1', 'dir2', 'dir3', 'file1', 'file2', 'file3', 'link1', 'link2', 'ping.js'] - done() - - it 'reads dirs from a normal dir', (done) -> - p = path.join fixtures, 'asar', 'a.asar', 'dir1' - dirs = fs.readdir p, (err, dirs) -> - assert.equal err, null - assert.deepEqual dirs, ['file1', 'file2', 'file3', 'link1', 'link2'] - done() - - it 'reads dirs from a linked dir', (done) -> - p = path.join fixtures, 'asar', 'a.asar', 'link2', 'link2' - dirs = fs.readdir p, (err, dirs) -> - assert.equal err, null - assert.deepEqual dirs, ['file1', 'file2', 'file3', 'link1', 'link2'] - done() - - it 'throws ENOENT error when can not find file', (done) -> - p = path.join fixtures, 'asar', 'a.asar', 'not-exist' - fs.readdir p, (err, stats) -> - assert.equal err.code, 'ENOENT' - done() - - describe 'fs.openSync', -> - it 'opens a normal/linked/under-linked-directory file', -> - for file in ['file1', 'link1', path.join('link2', 'file1')] - p = path.join fixtures, 'asar', 'a.asar', file - fd = fs.openSync p, 'r' - buffer = new Buffer(6) - fs.readSync fd, buffer, 0, 6, 0 - assert.equal String(buffer).trim(), 'file1' - fs.closeSync fd - - it 'throws ENOENT error when can not find file', -> - p = path.join fixtures, 'asar', 'a.asar', 'not-exist' - throws = -> fs.openSync p - assert.throws throws, /ENOENT/ - - describe 'fs.open', -> - it 'opens a normal file', (done) -> - p = path.join fixtures, 'asar', 'a.asar', 'file1' - fs.open p, 'r', (err, fd) -> - assert.equal err, null - buffer = new Buffer(6) - fs.read fd, buffer, 0, 6, 0, (err) -> - assert.equal err, null - assert.equal String(buffer).trim(), 'file1' - fs.close fd, done - - it 'throws ENOENT error when can not find file', (done) -> - p = path.join fixtures, 'asar', 'a.asar', 'not-exist' - fs.open p, 'r', (err, stats) -> - assert.equal err.code, 'ENOENT' - done() - - describe 'fs.mkdir', -> - it 'throws error when calling inside asar archive', (done) -> - p = path.join fixtures, 'asar', 'a.asar', 'not-exist' - fs.mkdir p, (err) -> - assert.equal err.code, 'ENOTDIR' - done() - - describe 'fs.mkdirSync', -> - it 'throws error when calling inside asar archive', -> - p = path.join fixtures, 'asar', 'a.asar', 'not-exist' - assert.throws (-> fs.mkdirSync p), new RegExp('ENOTDIR') - - describe 'child_process.fork', -> - child_process = require 'child_process' - - it 'opens a normal js file', (done) -> - child = child_process.fork path.join(fixtures, 'asar', 'a.asar', 'ping.js') - child.on 'message', (msg) -> - assert.equal msg, 'message' - done() - child.send 'message' - - it 'supports asar in the forked js', (done) -> - file = path.join fixtures, 'asar', 'a.asar', 'file1' - child = child_process.fork path.join(fixtures, 'module', 'asar.js') - child.on 'message', (content) -> - assert.equal content, fs.readFileSync(file).toString() - done() - child.send file - - describe 'child_process.execFile', -> - return unless process.platform is 'darwin' - - {execFile, execFileSync} = require 'child_process' - echo = path.join fixtures, 'asar', 'echo.asar', 'echo' - - it 'executes binaries', (done) -> - child = execFile echo, ['test'], (error, stdout) -> - assert.equal error, null - assert.equal stdout, 'test\n' - done() - - # execFileSync makes the test flaky after a refresh. - xit 'execFileSync executes binaries', -> - output = execFileSync echo, ['test'] - assert.equal String(output), 'test\n' - - describe 'internalModuleReadFile', -> - internalModuleReadFile = process.binding('fs').internalModuleReadFile - - it 'read a normal file', -> - file1 = path.join fixtures, 'asar', 'a.asar', 'file1' - assert.equal internalModuleReadFile(file1).toString().trim(), 'file1' - file2 = path.join fixtures, 'asar', 'a.asar', 'file2' - assert.equal internalModuleReadFile(file2).toString().trim(), 'file2' - file3 = path.join fixtures, 'asar', 'a.asar', 'file3' - assert.equal internalModuleReadFile(file3).toString().trim(), 'file3' - - it 'reads a normal file with unpacked files', -> - p = path.join fixtures, 'asar', 'unpack.asar', 'a.txt' - assert.equal internalModuleReadFile(p).toString().trim(), 'a' - - describe 'process.noAsar', -> - errorName = if process.platform is 'win32' then 'ENOENT' else 'ENOTDIR' - - beforeEach -> - process.noAsar = true - afterEach -> - process.noAsar = false - - it 'disables asar support in sync API', -> - file = path.join fixtures, 'asar', 'a.asar', 'file1' - dir = path.join fixtures, 'asar', 'a.asar', 'dir1' - assert.throws (-> fs.readFileSync file), new RegExp(errorName) - assert.throws (-> fs.lstatSync file), new RegExp(errorName) - assert.throws (-> fs.realpathSync file), new RegExp(errorName) - assert.throws (-> fs.readdirSync dir), new RegExp(errorName) - - it 'disables asar support in async API', (done) -> - file = path.join fixtures, 'asar', 'a.asar', 'file1' - dir = path.join fixtures, 'asar', 'a.asar', 'dir1' - fs.readFile file, (error) -> - assert.equal error.code, errorName - fs.lstat file, (error) -> - assert.equal error.code, errorName - fs.realpath file, (error) -> - assert.equal error.code, errorName - fs.readdir dir, (error) -> - assert.equal error.code, errorName - done() - - it 'treats *.asar as normal file', -> - originalFs = require 'original-fs' - asar = path.join fixtures, 'asar', 'a.asar' - content1 = fs.readFileSync asar - content2 = originalFs.readFileSync asar - assert.equal content1.compare(content2), 0 - assert.throws (-> fs.readdirSync asar), /ENOTDIR/ - - describe 'asar protocol', -> - url = require 'url' - - it 'can request a file in package', (done) -> - p = path.resolve fixtures, 'asar', 'a.asar', 'file1' - $.get "file://#{p}", (data) -> - assert.equal data.trim(), 'file1' - done() - - it 'can request a file in package with unpacked files', (done) -> - p = path.resolve fixtures, 'asar', 'unpack.asar', 'a.txt' - $.get "file://#{p}", (data) -> - assert.equal data.trim(), 'a' - done() - - it 'can request a linked file in package', (done) -> - p = path.resolve fixtures, 'asar', 'a.asar', 'link2', 'link1' - $.get "file://#{p}", (data) -> - assert.equal data.trim(), 'file1' - done() - - it 'can request a file in filesystem', (done) -> - p = path.resolve fixtures, 'asar', 'file' - $.get "file://#{p}", (data) -> - assert.equal data.trim(), 'file' - done() - - it 'gets 404 when file is not found', (done) -> - p = path.resolve fixtures, 'asar', 'a.asar', 'no-exist' - $.ajax - url: "file://#{p}" - error: (err) -> - assert.equal err.status, 404 - done() - - it 'sets __dirname correctly', (done) -> - after -> - w.destroy() - ipcMain.removeAllListeners 'dirname' - - w = new BrowserWindow(show: false, width: 400, height: 400) - p = path.resolve fixtures, 'asar', 'web.asar', 'index.html' - u = url.format protocol: 'file', slashed: true, pathname: p - ipcMain.once 'dirname', (event, dirname) -> - assert.equal dirname, path.dirname(p) - done() - w.loadURL u - - it 'loads script tag in html', (done) -> - after -> - w.destroy() - ipcMain.removeAllListeners 'ping' - - w = new BrowserWindow(show: false, width: 400, height: 400) - p = path.resolve fixtures, 'asar', 'script.asar', 'index.html' - u = url.format protocol: 'file', slashed: true, pathname: p - w.loadURL u - ipcMain.once 'ping', (event, message) -> - assert.equal message, 'pong' - done() - - describe 'original-fs module', -> - originalFs = require 'original-fs' - - it 'treats .asar as file', -> - file = path.join fixtures, 'asar', 'a.asar' - stats = originalFs.statSync file - assert stats.isFile() - - it 'is available in forked scripts', (done) -> - child = child_process.fork path.join(fixtures, 'module', 'original-fs.js') - child.on 'message', (msg) -> - assert.equal msg, 'object' - done() - child.send 'message' - - describe 'graceful-fs module', -> - gfs = require 'graceful-fs' - - it 'recognize asar archvies', -> - p = path.join fixtures, 'asar', 'a.asar', 'link1' - assert.equal gfs.readFileSync(p).toString().trim(), 'file1' - - it 'does not touch global fs object', -> - assert.notEqual fs.readdir, gfs.readdir - - describe 'mkdirp module', -> - mkdirp = require 'mkdirp' - - it 'throws error when calling inside asar archive', -> - p = path.join fixtures, 'asar', 'a.asar', 'not-exist' - assert.throws (-> mkdirp.sync p), new RegExp('ENOTDIR') - - describe 'native-image', -> - it 'reads image from asar archive', -> - p = path.join fixtures, 'asar', 'logo.asar', 'logo.png' - logo = nativeImage.createFromPath p - assert.deepEqual logo.getSize(), {width: 55, height: 55} - - it 'reads image from asar archive with unpacked files', -> - p = path.join fixtures, 'asar', 'unpack.asar', 'atom.png' - logo = nativeImage.createFromPath p - assert.deepEqual logo.getSize(), {width: 1024, height: 1024} diff --git a/spec/asar-spec.js b/spec/asar-spec.js new file mode 100644 index 000000000000..6ccc4b46a011 --- /dev/null +++ b/spec/asar-spec.js @@ -0,0 +1,805 @@ +var BrowserWindow, assert, child_process, fs, ipcMain, nativeImage, path, ref, ref1, remote; + +assert = require('assert'); + +child_process = require('child_process'); + +fs = require('fs'); + +path = require('path'); + +ref = require('electron'), nativeImage = ref.nativeImage, remote = ref.remote; + +ref1 = remote.require('electron'), ipcMain = ref1.ipcMain, BrowserWindow = ref1.BrowserWindow; + +describe('asar package', function() { + var fixtures; + fixtures = path.join(__dirname, 'fixtures'); + describe('node api', function() { + describe('fs.readFileSync', function() { + it('does not leak fd', function() { + var i, j, results; + results = []; + for (i = j = 1; j <= 10000; i = ++j) { + results.push(fs.readFileSync(path.join(process.resourcesPath, 'atom.asar', 'renderer', 'api', 'lib', 'ipc.js'))); + } + return results; + }); + it('reads a normal file', function() { + var file1, file2, file3; + file1 = path.join(fixtures, 'asar', 'a.asar', 'file1'); + assert.equal(fs.readFileSync(file1).toString().trim(), 'file1'); + file2 = path.join(fixtures, 'asar', 'a.asar', 'file2'); + assert.equal(fs.readFileSync(file2).toString().trim(), 'file2'); + file3 = path.join(fixtures, 'asar', 'a.asar', 'file3'); + return assert.equal(fs.readFileSync(file3).toString().trim(), 'file3'); + }); + it('reads from a empty file', function() { + var buffer, file; + file = path.join(fixtures, 'asar', 'empty.asar', 'file1'); + buffer = fs.readFileSync(file); + assert.equal(buffer.length, 0); + return assert.equal(buffer.toString(), ''); + }); + it('reads a linked file', function() { + var p; + p = path.join(fixtures, 'asar', 'a.asar', 'link1'); + return assert.equal(fs.readFileSync(p).toString().trim(), 'file1'); + }); + it('reads a file from linked directory', function() { + var p; + p = path.join(fixtures, 'asar', 'a.asar', 'link2', 'file1'); + assert.equal(fs.readFileSync(p).toString().trim(), 'file1'); + p = path.join(fixtures, 'asar', 'a.asar', 'link2', 'link2', 'file1'); + return assert.equal(fs.readFileSync(p).toString().trim(), 'file1'); + }); + it('throws ENOENT error when can not find file', function() { + var p, throws; + p = path.join(fixtures, 'asar', 'a.asar', 'not-exist'); + throws = function() { + return fs.readFileSync(p); + }; + return assert.throws(throws, /ENOENT/); + }); + it('passes ENOENT error to callback when can not find file', function() { + var async, p; + p = path.join(fixtures, 'asar', 'a.asar', 'not-exist'); + async = false; + fs.readFile(p, function(e) { + assert(async); + return assert(/ENOENT/.test(e)); + }); + return async = true; + }); + return it('reads a normal file with unpacked files', function() { + var p; + p = path.join(fixtures, 'asar', 'unpack.asar', 'a.txt'); + return assert.equal(fs.readFileSync(p).toString().trim(), 'a'); + }); + }); + describe('fs.readFile', function() { + it('reads a normal file', function(done) { + var p; + p = path.join(fixtures, 'asar', 'a.asar', 'file1'); + return fs.readFile(p, function(err, content) { + assert.equal(err, null); + assert.equal(String(content).trim(), 'file1'); + return done(); + }); + }); + it('reads from a empty file', function(done) { + var p; + p = path.join(fixtures, 'asar', 'empty.asar', 'file1'); + return fs.readFile(p, function(err, content) { + assert.equal(err, null); + assert.equal(String(content), ''); + return done(); + }); + }); + it('reads a linked file', function(done) { + var p; + p = path.join(fixtures, 'asar', 'a.asar', 'link1'); + return fs.readFile(p, function(err, content) { + assert.equal(err, null); + assert.equal(String(content).trim(), 'file1'); + return done(); + }); + }); + it('reads a file from linked directory', function(done) { + var p; + p = path.join(fixtures, 'asar', 'a.asar', 'link2', 'link2', 'file1'); + return fs.readFile(p, function(err, content) { + assert.equal(err, null); + assert.equal(String(content).trim(), 'file1'); + return done(); + }); + }); + return it('throws ENOENT error when can not find file', function(done) { + var p; + p = path.join(fixtures, 'asar', 'a.asar', 'not-exist'); + return fs.readFile(p, function(err, content) { + assert.equal(err.code, 'ENOENT'); + return done(); + }); + }); + }); + describe('fs.lstatSync', function() { + it('handles path with trailing slash correctly', function() { + var p; + p = path.join(fixtures, 'asar', 'a.asar', 'link2', 'link2', 'file1'); + fs.lstatSync(p); + return fs.lstatSync(p + '/'); + }); + it('returns information of root', function() { + var p, stats; + p = path.join(fixtures, 'asar', 'a.asar'); + stats = fs.lstatSync(p); + assert.equal(stats.isFile(), false); + assert.equal(stats.isDirectory(), true); + assert.equal(stats.isSymbolicLink(), false); + return assert.equal(stats.size, 0); + }); + it('returns information of a normal file', function() { + var file, j, len, p, ref2, results, stats; + ref2 = ['file1', 'file2', 'file3', path.join('dir1', 'file1'), path.join('link2', 'file1')]; + results = []; + for (j = 0, len = ref2.length; j < len; j++) { + file = ref2[j]; + p = path.join(fixtures, 'asar', 'a.asar', file); + stats = fs.lstatSync(p); + assert.equal(stats.isFile(), true); + assert.equal(stats.isDirectory(), false); + assert.equal(stats.isSymbolicLink(), false); + results.push(assert.equal(stats.size, 6)); + } + return results; + }); + it('returns information of a normal directory', function() { + var file, j, len, p, ref2, results, stats; + ref2 = ['dir1', 'dir2', 'dir3']; + results = []; + for (j = 0, len = ref2.length; j < len; j++) { + file = ref2[j]; + p = path.join(fixtures, 'asar', 'a.asar', file); + stats = fs.lstatSync(p); + assert.equal(stats.isFile(), false); + assert.equal(stats.isDirectory(), true); + assert.equal(stats.isSymbolicLink(), false); + results.push(assert.equal(stats.size, 0)); + } + return results; + }); + it('returns information of a linked file', function() { + var file, j, len, p, ref2, results, stats; + ref2 = ['link1', path.join('dir1', 'link1'), path.join('link2', 'link2')]; + results = []; + for (j = 0, len = ref2.length; j < len; j++) { + file = ref2[j]; + p = path.join(fixtures, 'asar', 'a.asar', file); + stats = fs.lstatSync(p); + assert.equal(stats.isFile(), false); + assert.equal(stats.isDirectory(), false); + assert.equal(stats.isSymbolicLink(), true); + results.push(assert.equal(stats.size, 0)); + } + return results; + }); + it('returns information of a linked directory', function() { + var file, j, len, p, ref2, results, stats; + ref2 = ['link2', path.join('dir1', 'link2'), path.join('link2', 'link2')]; + results = []; + for (j = 0, len = ref2.length; j < len; j++) { + file = ref2[j]; + p = path.join(fixtures, 'asar', 'a.asar', file); + stats = fs.lstatSync(p); + assert.equal(stats.isFile(), false); + assert.equal(stats.isDirectory(), false); + assert.equal(stats.isSymbolicLink(), true); + results.push(assert.equal(stats.size, 0)); + } + return results; + }); + return it('throws ENOENT error when can not find file', function() { + var file, j, len, p, ref2, results, throws; + ref2 = ['file4', 'file5', path.join('dir1', 'file4')]; + results = []; + for (j = 0, len = ref2.length; j < len; j++) { + file = ref2[j]; + p = path.join(fixtures, 'asar', 'a.asar', file); + throws = function() { + return fs.lstatSync(p); + }; + results.push(assert.throws(throws, /ENOENT/)); + } + return results; + }); + }); + describe('fs.lstat', function() { + it('handles path with trailing slash correctly', function(done) { + var p; + p = path.join(fixtures, 'asar', 'a.asar', 'link2', 'link2', 'file1'); + return fs.lstat(p + '/', done); + }); + it('returns information of root', function(done) { + var p, stats; + p = path.join(fixtures, 'asar', 'a.asar'); + return stats = fs.lstat(p, function(err, stats) { + assert.equal(err, null); + assert.equal(stats.isFile(), false); + assert.equal(stats.isDirectory(), true); + assert.equal(stats.isSymbolicLink(), false); + assert.equal(stats.size, 0); + return done(); + }); + }); + it('returns information of a normal file', function(done) { + var p, stats; + p = path.join(fixtures, 'asar', 'a.asar', 'link2', 'file1'); + return stats = fs.lstat(p, function(err, stats) { + assert.equal(err, null); + assert.equal(stats.isFile(), true); + assert.equal(stats.isDirectory(), false); + assert.equal(stats.isSymbolicLink(), false); + assert.equal(stats.size, 6); + return done(); + }); + }); + it('returns information of a normal directory', function(done) { + var p, stats; + p = path.join(fixtures, 'asar', 'a.asar', 'dir1'); + return stats = fs.lstat(p, function(err, stats) { + assert.equal(err, null); + assert.equal(stats.isFile(), false); + assert.equal(stats.isDirectory(), true); + assert.equal(stats.isSymbolicLink(), false); + assert.equal(stats.size, 0); + return done(); + }); + }); + it('returns information of a linked file', function(done) { + var p, stats; + p = path.join(fixtures, 'asar', 'a.asar', 'link2', 'link1'); + return stats = fs.lstat(p, function(err, stats) { + assert.equal(err, null); + assert.equal(stats.isFile(), false); + assert.equal(stats.isDirectory(), false); + assert.equal(stats.isSymbolicLink(), true); + assert.equal(stats.size, 0); + return done(); + }); + }); + it('returns information of a linked directory', function(done) { + var p, stats; + p = path.join(fixtures, 'asar', 'a.asar', 'link2', 'link2'); + return stats = fs.lstat(p, function(err, stats) { + assert.equal(err, null); + assert.equal(stats.isFile(), false); + assert.equal(stats.isDirectory(), false); + assert.equal(stats.isSymbolicLink(), true); + assert.equal(stats.size, 0); + return done(); + }); + }); + return it('throws ENOENT error when can not find file', function(done) { + var p, stats; + p = path.join(fixtures, 'asar', 'a.asar', 'file4'); + return stats = fs.lstat(p, function(err, stats) { + assert.equal(err.code, 'ENOENT'); + return done(); + }); + }); + }); + describe('fs.realpathSync', function() { + it('returns real path root', function() { + var p, parent, r; + parent = fs.realpathSync(path.join(fixtures, 'asar')); + p = 'a.asar'; + r = fs.realpathSync(path.join(parent, p)); + return assert.equal(r, path.join(parent, p)); + }); + it('returns real path of a normal file', function() { + var p, parent, r; + parent = fs.realpathSync(path.join(fixtures, 'asar')); + p = path.join('a.asar', 'file1'); + r = fs.realpathSync(path.join(parent, p)); + return assert.equal(r, path.join(parent, p)); + }); + it('returns real path of a normal directory', function() { + var p, parent, r; + parent = fs.realpathSync(path.join(fixtures, 'asar')); + p = path.join('a.asar', 'dir1'); + r = fs.realpathSync(path.join(parent, p)); + return assert.equal(r, path.join(parent, p)); + }); + it('returns real path of a linked file', function() { + var p, parent, r; + parent = fs.realpathSync(path.join(fixtures, 'asar')); + p = path.join('a.asar', 'link2', 'link1'); + r = fs.realpathSync(path.join(parent, p)); + return assert.equal(r, path.join(parent, 'a.asar', 'file1')); + }); + it('returns real path of a linked directory', function() { + var p, parent, r; + parent = fs.realpathSync(path.join(fixtures, 'asar')); + p = path.join('a.asar', 'link2', 'link2'); + r = fs.realpathSync(path.join(parent, p)); + return assert.equal(r, path.join(parent, 'a.asar', 'dir1')); + }); + return it('throws ENOENT error when can not find file', function() { + var p, parent, throws; + parent = fs.realpathSync(path.join(fixtures, 'asar')); + p = path.join('a.asar', 'not-exist'); + throws = function() { + return fs.realpathSync(path.join(parent, p)); + }; + return assert.throws(throws, /ENOENT/); + }); + }); + describe('fs.realpath', function() { + it('returns real path root', function(done) { + var p, parent; + parent = fs.realpathSync(path.join(fixtures, 'asar')); + p = 'a.asar'; + return fs.realpath(path.join(parent, p), function(err, r) { + assert.equal(err, null); + assert.equal(r, path.join(parent, p)); + return done(); + }); + }); + it('returns real path of a normal file', function(done) { + var p, parent; + parent = fs.realpathSync(path.join(fixtures, 'asar')); + p = path.join('a.asar', 'file1'); + return fs.realpath(path.join(parent, p), function(err, r) { + assert.equal(err, null); + assert.equal(r, path.join(parent, p)); + return done(); + }); + }); + it('returns real path of a normal directory', function(done) { + var p, parent; + parent = fs.realpathSync(path.join(fixtures, 'asar')); + p = path.join('a.asar', 'dir1'); + return fs.realpath(path.join(parent, p), function(err, r) { + assert.equal(err, null); + assert.equal(r, path.join(parent, p)); + return done(); + }); + }); + it('returns real path of a linked file', function(done) { + var p, parent; + parent = fs.realpathSync(path.join(fixtures, 'asar')); + p = path.join('a.asar', 'link2', 'link1'); + return fs.realpath(path.join(parent, p), function(err, r) { + assert.equal(err, null); + assert.equal(r, path.join(parent, 'a.asar', 'file1')); + return done(); + }); + }); + it('returns real path of a linked directory', function(done) { + var p, parent; + parent = fs.realpathSync(path.join(fixtures, 'asar')); + p = path.join('a.asar', 'link2', 'link2'); + return fs.realpath(path.join(parent, p), function(err, r) { + assert.equal(err, null); + assert.equal(r, path.join(parent, 'a.asar', 'dir1')); + return done(); + }); + }); + return it('throws ENOENT error when can not find file', function(done) { + var p, parent; + parent = fs.realpathSync(path.join(fixtures, 'asar')); + p = path.join('a.asar', 'not-exist'); + return fs.realpath(path.join(parent, p), function(err, stats) { + assert.equal(err.code, 'ENOENT'); + return done(); + }); + }); + }); + describe('fs.readdirSync', function() { + it('reads dirs from root', function() { + var dirs, p; + p = path.join(fixtures, 'asar', 'a.asar'); + dirs = fs.readdirSync(p); + return assert.deepEqual(dirs, ['dir1', 'dir2', 'dir3', 'file1', 'file2', 'file3', 'link1', 'link2', 'ping.js']); + }); + it('reads dirs from a normal dir', function() { + var dirs, p; + p = path.join(fixtures, 'asar', 'a.asar', 'dir1'); + dirs = fs.readdirSync(p); + return assert.deepEqual(dirs, ['file1', 'file2', 'file3', 'link1', 'link2']); + }); + it('reads dirs from a linked dir', function() { + var dirs, p; + p = path.join(fixtures, 'asar', 'a.asar', 'link2', 'link2'); + dirs = fs.readdirSync(p); + return assert.deepEqual(dirs, ['file1', 'file2', 'file3', 'link1', 'link2']); + }); + return it('throws ENOENT error when can not find file', function() { + var p, throws; + p = path.join(fixtures, 'asar', 'a.asar', 'not-exist'); + throws = function() { + return fs.readdirSync(p); + }; + return assert.throws(throws, /ENOENT/); + }); + }); + describe('fs.readdir', function() { + it('reads dirs from root', function(done) { + var dirs, p; + p = path.join(fixtures, 'asar', 'a.asar'); + return dirs = fs.readdir(p, function(err, dirs) { + assert.equal(err, null); + assert.deepEqual(dirs, ['dir1', 'dir2', 'dir3', 'file1', 'file2', 'file3', 'link1', 'link2', 'ping.js']); + return done(); + }); + }); + it('reads dirs from a normal dir', function(done) { + var dirs, p; + p = path.join(fixtures, 'asar', 'a.asar', 'dir1'); + return dirs = fs.readdir(p, function(err, dirs) { + assert.equal(err, null); + assert.deepEqual(dirs, ['file1', 'file2', 'file3', 'link1', 'link2']); + return done(); + }); + }); + it('reads dirs from a linked dir', function(done) { + var dirs, p; + p = path.join(fixtures, 'asar', 'a.asar', 'link2', 'link2'); + return dirs = fs.readdir(p, function(err, dirs) { + assert.equal(err, null); + assert.deepEqual(dirs, ['file1', 'file2', 'file3', 'link1', 'link2']); + return done(); + }); + }); + return it('throws ENOENT error when can not find file', function(done) { + var p; + p = path.join(fixtures, 'asar', 'a.asar', 'not-exist'); + return fs.readdir(p, function(err, stats) { + assert.equal(err.code, 'ENOENT'); + return done(); + }); + }); + }); + describe('fs.openSync', function() { + it('opens a normal/linked/under-linked-directory file', function() { + var buffer, fd, file, j, len, p, ref2, results; + ref2 = ['file1', 'link1', path.join('link2', 'file1')]; + results = []; + for (j = 0, len = ref2.length; j < len; j++) { + file = ref2[j]; + p = path.join(fixtures, 'asar', 'a.asar', file); + fd = fs.openSync(p, 'r'); + buffer = new Buffer(6); + fs.readSync(fd, buffer, 0, 6, 0); + assert.equal(String(buffer).trim(), 'file1'); + results.push(fs.closeSync(fd)); + } + return results; + }); + return it('throws ENOENT error when can not find file', function() { + var p, throws; + p = path.join(fixtures, 'asar', 'a.asar', 'not-exist'); + throws = function() { + return fs.openSync(p); + }; + return assert.throws(throws, /ENOENT/); + }); + }); + describe('fs.open', function() { + it('opens a normal file', function(done) { + var p; + p = path.join(fixtures, 'asar', 'a.asar', 'file1'); + return fs.open(p, 'r', function(err, fd) { + var buffer; + assert.equal(err, null); + buffer = new Buffer(6); + return fs.read(fd, buffer, 0, 6, 0, function(err) { + assert.equal(err, null); + assert.equal(String(buffer).trim(), 'file1'); + return fs.close(fd, done); + }); + }); + }); + return it('throws ENOENT error when can not find file', function(done) { + var p; + p = path.join(fixtures, 'asar', 'a.asar', 'not-exist'); + return fs.open(p, 'r', function(err, stats) { + assert.equal(err.code, 'ENOENT'); + return done(); + }); + }); + }); + describe('fs.mkdir', function() { + return it('throws error when calling inside asar archive', function(done) { + var p; + p = path.join(fixtures, 'asar', 'a.asar', 'not-exist'); + return fs.mkdir(p, function(err) { + assert.equal(err.code, 'ENOTDIR'); + return done(); + }); + }); + }); + describe('fs.mkdirSync', function() { + return it('throws error when calling inside asar archive', function() { + var p; + p = path.join(fixtures, 'asar', 'a.asar', 'not-exist'); + return assert.throws((function() { + return fs.mkdirSync(p); + }), new RegExp('ENOTDIR')); + }); + }); + describe('child_process.fork', function() { + child_process = require('child_process'); + it('opens a normal js file', function(done) { + var child; + child = child_process.fork(path.join(fixtures, 'asar', 'a.asar', 'ping.js')); + child.on('message', function(msg) { + assert.equal(msg, 'message'); + return done(); + }); + return child.send('message'); + }); + return it('supports asar in the forked js', function(done) { + var child, file; + file = path.join(fixtures, 'asar', 'a.asar', 'file1'); + child = child_process.fork(path.join(fixtures, 'module', 'asar.js')); + child.on('message', function(content) { + assert.equal(content, fs.readFileSync(file).toString()); + return done(); + }); + return child.send(file); + }); + }); + describe('child_process.execFile', function() { + var echo, execFile, execFileSync, ref2; + if (process.platform !== 'darwin') { + return; + } + ref2 = require('child_process'), execFile = ref2.execFile, execFileSync = ref2.execFileSync; + echo = path.join(fixtures, 'asar', 'echo.asar', 'echo'); + it('executes binaries', function(done) { + var child; + return child = execFile(echo, ['test'], function(error, stdout) { + assert.equal(error, null); + assert.equal(stdout, 'test\n'); + return done(); + }); + }); + return xit('execFileSync executes binaries', function() { + var output; + output = execFileSync(echo, ['test']); + return assert.equal(String(output), 'test\n'); + }); + }); + describe('internalModuleReadFile', function() { + var internalModuleReadFile; + internalModuleReadFile = process.binding('fs').internalModuleReadFile; + it('read a normal file', function() { + var file1, file2, file3; + file1 = path.join(fixtures, 'asar', 'a.asar', 'file1'); + assert.equal(internalModuleReadFile(file1).toString().trim(), 'file1'); + file2 = path.join(fixtures, 'asar', 'a.asar', 'file2'); + assert.equal(internalModuleReadFile(file2).toString().trim(), 'file2'); + file3 = path.join(fixtures, 'asar', 'a.asar', 'file3'); + return assert.equal(internalModuleReadFile(file3).toString().trim(), 'file3'); + }); + return it('reads a normal file with unpacked files', function() { + var p; + p = path.join(fixtures, 'asar', 'unpack.asar', 'a.txt'); + return assert.equal(internalModuleReadFile(p).toString().trim(), 'a'); + }); + }); + return describe('process.noAsar', function() { + var errorName; + errorName = process.platform === 'win32' ? 'ENOENT' : 'ENOTDIR'; + beforeEach(function() { + return process.noAsar = true; + }); + afterEach(function() { + return process.noAsar = false; + }); + it('disables asar support in sync API', function() { + var dir, file; + file = path.join(fixtures, 'asar', 'a.asar', 'file1'); + dir = path.join(fixtures, 'asar', 'a.asar', 'dir1'); + assert.throws((function() { + return fs.readFileSync(file); + }), new RegExp(errorName)); + assert.throws((function() { + return fs.lstatSync(file); + }), new RegExp(errorName)); + assert.throws((function() { + return fs.realpathSync(file); + }), new RegExp(errorName)); + return assert.throws((function() { + return fs.readdirSync(dir); + }), new RegExp(errorName)); + }); + it('disables asar support in async API', function(done) { + var dir, file; + file = path.join(fixtures, 'asar', 'a.asar', 'file1'); + dir = path.join(fixtures, 'asar', 'a.asar', 'dir1'); + return fs.readFile(file, function(error) { + assert.equal(error.code, errorName); + return fs.lstat(file, function(error) { + assert.equal(error.code, errorName); + return fs.realpath(file, function(error) { + assert.equal(error.code, errorName); + return fs.readdir(dir, function(error) { + assert.equal(error.code, errorName); + return done(); + }); + }); + }); + }); + }); + return it('treats *.asar as normal file', function() { + var asar, content1, content2, originalFs; + originalFs = require('original-fs'); + asar = path.join(fixtures, 'asar', 'a.asar'); + content1 = fs.readFileSync(asar); + content2 = originalFs.readFileSync(asar); + assert.equal(content1.compare(content2), 0); + return assert.throws((function() { + return fs.readdirSync(asar); + }), /ENOTDIR/); + }); + }); + }); + describe('asar protocol', function() { + var url; + url = require('url'); + it('can request a file in package', function(done) { + var p; + p = path.resolve(fixtures, 'asar', 'a.asar', 'file1'); + return $.get("file://" + p, function(data) { + assert.equal(data.trim(), 'file1'); + return done(); + }); + }); + it('can request a file in package with unpacked files', function(done) { + var p; + p = path.resolve(fixtures, 'asar', 'unpack.asar', 'a.txt'); + return $.get("file://" + p, function(data) { + assert.equal(data.trim(), 'a'); + return done(); + }); + }); + it('can request a linked file in package', function(done) { + var p; + p = path.resolve(fixtures, 'asar', 'a.asar', 'link2', 'link1'); + return $.get("file://" + p, function(data) { + assert.equal(data.trim(), 'file1'); + return done(); + }); + }); + it('can request a file in filesystem', function(done) { + var p; + p = path.resolve(fixtures, 'asar', 'file'); + return $.get("file://" + p, function(data) { + assert.equal(data.trim(), 'file'); + return done(); + }); + }); + it('gets 404 when file is not found', function(done) { + var p; + p = path.resolve(fixtures, 'asar', 'a.asar', 'no-exist'); + return $.ajax({ + url: "file://" + p, + error: function(err) { + assert.equal(err.status, 404); + return done(); + } + }); + }); + it('sets __dirname correctly', function(done) { + var p, u, w; + after(function() { + w.destroy(); + return ipcMain.removeAllListeners('dirname'); + }); + w = new BrowserWindow({ + show: false, + width: 400, + height: 400 + }); + p = path.resolve(fixtures, 'asar', 'web.asar', 'index.html'); + u = url.format({ + protocol: 'file', + slashed: true, + pathname: p + }); + ipcMain.once('dirname', function(event, dirname) { + assert.equal(dirname, path.dirname(p)); + return done(); + }); + return w.loadURL(u); + }); + return it('loads script tag in html', function(done) { + var p, u, w; + after(function() { + w.destroy(); + return ipcMain.removeAllListeners('ping'); + }); + w = new BrowserWindow({ + show: false, + width: 400, + height: 400 + }); + p = path.resolve(fixtures, 'asar', 'script.asar', 'index.html'); + u = url.format({ + protocol: 'file', + slashed: true, + pathname: p + }); + w.loadURL(u); + return ipcMain.once('ping', function(event, message) { + assert.equal(message, 'pong'); + return done(); + }); + }); + }); + describe('original-fs module', function() { + var originalFs; + originalFs = require('original-fs'); + it('treats .asar as file', function() { + var file, stats; + file = path.join(fixtures, 'asar', 'a.asar'); + stats = originalFs.statSync(file); + return assert(stats.isFile()); + }); + return it('is available in forked scripts', function(done) { + var child; + child = child_process.fork(path.join(fixtures, 'module', 'original-fs.js')); + child.on('message', function(msg) { + assert.equal(msg, 'object'); + return done(); + }); + return child.send('message'); + }); + }); + describe('graceful-fs module', function() { + var gfs; + gfs = require('graceful-fs'); + it('recognize asar archvies', function() { + var p; + p = path.join(fixtures, 'asar', 'a.asar', 'link1'); + return assert.equal(gfs.readFileSync(p).toString().trim(), 'file1'); + }); + return it('does not touch global fs object', function() { + return assert.notEqual(fs.readdir, gfs.readdir); + }); + }); + describe('mkdirp module', function() { + var mkdirp; + mkdirp = require('mkdirp'); + return it('throws error when calling inside asar archive', function() { + var p; + p = path.join(fixtures, 'asar', 'a.asar', 'not-exist'); + return assert.throws((function() { + return mkdirp.sync(p); + }), new RegExp('ENOTDIR')); + }); + }); + return describe('native-image', function() { + it('reads image from asar archive', function() { + var logo, p; + p = path.join(fixtures, 'asar', 'logo.asar', 'logo.png'); + logo = nativeImage.createFromPath(p); + return assert.deepEqual(logo.getSize(), { + width: 55, + height: 55 + }); + }); + return it('reads image from asar archive with unpacked files', function() { + var logo, p; + p = path.join(fixtures, 'asar', 'unpack.asar', 'atom.png'); + logo = nativeImage.createFromPath(p); + return assert.deepEqual(logo.getSize(), { + width: 1024, + height: 1024 + }); + }); + }); +}); diff --git a/spec/chromium-spec.coffee b/spec/chromium-spec.coffee deleted file mode 100644 index cc28f2f7ad47..000000000000 --- a/spec/chromium-spec.coffee +++ /dev/null @@ -1,275 +0,0 @@ -assert = require 'assert' -http = require 'http' -https = require 'https' -path = require 'path' -ws = require 'ws' - -{remote} = require 'electron' -{BrowserWindow, session} = remote.require 'electron' - -describe 'chromium feature', -> - fixtures = path.resolve __dirname, 'fixtures' - - listener = null - afterEach -> - if listener? - window.removeEventListener 'message', listener - listener = null - - xdescribe 'heap snapshot', -> - it 'does not crash', -> - process.atomBinding('v8_util').takeHeapSnapshot() - - describe 'sending request of http protocol urls', -> - it 'does not crash', (done) -> - @timeout 5000 - server = http.createServer (req, res) -> - res.end() - server.close() - done() - server.listen 0, '127.0.0.1', -> - {port} = server.address() - $.get "http://127.0.0.1:#{port}" - - describe 'document.hidden', -> - url = "file://#{fixtures}/pages/document-hidden.html" - w = null - - afterEach -> - w?.destroy() - - it 'is set correctly when window is not shown', (done) -> - w = new BrowserWindow(show:false) - w.webContents.on 'ipc-message', (event, args) -> - assert.deepEqual args, ['hidden', true] - done() - w.loadURL url - - it 'is set correctly when window is inactive', (done) -> - w = new BrowserWindow(show:false) - w.webContents.on 'ipc-message', (event, args) -> - assert.deepEqual args, ['hidden', false] - done() - w.showInactive() - w.loadURL url - - xdescribe 'navigator.webkitGetUserMedia', -> - it 'calls its callbacks', (done) -> - @timeout 5000 - navigator.webkitGetUserMedia audio: true, video: false, - -> done() - -> done() - - describe 'navigator.language', -> - it 'should not be empty', -> - assert.notEqual navigator.language, '' - - describe 'navigator.serviceWorker', -> - url = "file://#{fixtures}/pages/service-worker/index.html" - w = null - - afterEach -> - w?.destroy() - - it 'should register for file scheme', (done) -> - w = new BrowserWindow(show:false) - w.webContents.on 'ipc-message', (event, args) -> - if args[0] == 'reload' - w.webContents.reload() - else if args[0] == 'error' - done('unexpected error : ' + args[1]) - else if args[0] == 'response' - assert.equal args[1], 'Hello from serviceWorker!' - session.defaultSession.clearStorageData {storages: ['serviceworkers']}, -> - done() - w.loadURL url - - describe 'window.open', -> - @timeout 20000 - - it 'returns a BrowserWindowProxy object', -> - b = window.open 'about:blank', '', 'show=no' - assert.equal b.closed, false - assert.equal b.constructor.name, 'BrowserWindowProxy' - b.close() - - it 'accepts "node-integration" as feature', (done) -> - listener = (event) -> - assert.equal event.data, 'undefined' - b.close() - done() - window.addEventListener 'message', listener - b = window.open "file://#{fixtures}/pages/window-opener-node.html", '', 'nodeIntegration=no,show=no' - - it 'inherit options of parent window', (done) -> - listener = (event) -> - [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 - - url = "file://#{fixtures}/pages/window-opener.html" - w = null - - afterEach -> - w?.destroy() - - it 'is null for main window', (done) -> - w = new BrowserWindow(show: false) - w.webContents.on 'ipc-message', (event, args) -> - assert.deepEqual args, ['opener', null] - done() - w.loadURL url - - it 'is not null for window opened by window.open', (done) -> - listener = (event) -> - assert.equal event.data, 'object' - b.close() - done() - window.addEventListener 'message', listener - b = window.open url, '', 'show=no' - - describe 'window.postMessage', -> - it 'sets the source and origin correctly', (done) -> - sourceId = remote.getCurrentWindow().id - listener = (event) -> - window.removeEventListener 'message', listener - b.close() - message = JSON.parse(event.data) - assert.equal message.data, 'testing' - assert.equal message.origin, 'file://' - assert.equal message.sourceEqualsOpener, true - assert.equal message.sourceId, sourceId - assert.equal event.origin, 'file://' - done() - window.addEventListener 'message', listener - b = window.open "file://#{fixtures}/pages/window-open-postMessage.html", '', 'show=no' - BrowserWindow.fromId(b.guestId).webContents.once 'did-finish-load', -> - b.postMessage('testing', '*') - - describe 'window.opener.postMessage', -> - it 'sets source and origin correctly', (done) -> - listener = (event) -> - window.removeEventListener 'message', listener - b.close() - assert.equal event.source, b - assert.equal event.origin, 'file://' - done() - window.addEventListener 'message', listener - b = window.open "file://#{fixtures}/pages/window-opener-postMessage.html", '', 'show=no' - - describe 'creating a Uint8Array under browser side', -> - it 'does not crash', -> - RUint8Array = remote.getGlobal 'Uint8Array' - new RUint8Array - - describe 'webgl', -> - it 'can be get as context in canvas', -> - return if process.platform is 'linux' - webgl = document.createElement('canvas').getContext 'webgl' - assert.notEqual webgl, null - - describe 'web workers', -> - it 'Worker can work', (done) -> - worker = new Worker('../fixtures/workers/worker.js') - message = 'ping' - worker.onmessage = (event) -> - assert.equal event.data, message - worker.terminate() - done() - worker.postMessage message - - it 'SharedWorker can work', (done) -> - worker = new SharedWorker('../fixtures/workers/shared_worker.js') - message = 'ping' - worker.port.onmessage = (event) -> - assert.equal event.data, message - done() - worker.port.postMessage message - - describe 'iframe', -> - iframe = null - - beforeEach -> - iframe = document.createElement 'iframe' - - afterEach -> - document.body.removeChild iframe - - it 'does not have node integration', (done) -> - iframe.src = "file://#{fixtures}/pages/set-global.html" - document.body.appendChild iframe - iframe.onload = -> - assert.equal iframe.contentWindow.test, 'undefined undefined undefined' - done() - - describe 'storage', -> - it 'requesting persitent quota works', (done) -> - navigator.webkitPersistentStorage.requestQuota 1024 * 1024, (grantedBytes) -> - assert.equal grantedBytes, 1048576 - done() - - describe 'websockets', -> - wss = null - server = null - WebSocketServer = ws.Server - - afterEach -> - wss.close() - server.close() - - it 'has user agent', (done) -> - server = http.createServer() - server.listen 0, '127.0.0.1', -> - port = server.address().port - wss = new WebSocketServer(server: server) - wss.on 'error', done - wss.on 'connection', (ws) -> - if ws.upgradeReq.headers['user-agent'] - done() - else - done('user agent is empty') - websocket = new WebSocket("ws://127.0.0.1:#{port}") - - describe 'Promise', -> - it 'resolves correctly in Node.js calls', (done) -> - document.registerElement('x-element', { - prototype: Object.create(HTMLElement.prototype, { - createdCallback: { value: -> } - }) - }) - - setImmediate -> - called = false - Promise.resolve().then -> - done(if called then undefined else new Error('wrong sequence')) - document.createElement 'x-element' - called = true - - it 'resolves correctly in Electron calls', (done) -> - document.registerElement('y-element', { - prototype: Object.create(HTMLElement.prototype, { - createdCallback: { value: -> } - }) - }) - - remote.getGlobal('setImmediate') -> - called = false - Promise.resolve().then -> - done(if called then undefined else new Error('wrong sequence')) - document.createElement 'y-element' - called = true diff --git a/spec/chromium-spec.js b/spec/chromium-spec.js new file mode 100644 index 000000000000..563eea742ffd --- /dev/null +++ b/spec/chromium-spec.js @@ -0,0 +1,368 @@ +var BrowserWindow, assert, http, https, path, ref, remote, session, ws; + +assert = require('assert'); + +http = require('http'); + +https = require('https'); + +path = require('path'); + +ws = require('ws'); + +remote = require('electron').remote; + +ref = remote.require('electron'), BrowserWindow = ref.BrowserWindow, session = ref.session; + +describe('chromium feature', function() { + var fixtures, listener; + fixtures = path.resolve(__dirname, 'fixtures'); + listener = null; + afterEach(function() { + if (listener != null) { + window.removeEventListener('message', listener); + } + return listener = null; + }); + xdescribe('heap snapshot', function() { + return it('does not crash', function() { + return process.atomBinding('v8_util').takeHeapSnapshot(); + }); + }); + describe('sending request of http protocol urls', function() { + return it('does not crash', function(done) { + var server; + this.timeout(5000); + server = http.createServer(function(req, res) { + res.end(); + server.close(); + return done(); + }); + return server.listen(0, '127.0.0.1', function() { + var port; + port = server.address().port; + return $.get("http://127.0.0.1:" + port); + }); + }); + }); + describe('document.hidden', function() { + var url, w; + url = "file://" + fixtures + "/pages/document-hidden.html"; + w = null; + afterEach(function() { + return w != null ? w.destroy() : void 0; + }); + it('is set correctly when window is not shown', function(done) { + w = new BrowserWindow({ + show: false + }); + w.webContents.on('ipc-message', function(event, args) { + assert.deepEqual(args, ['hidden', true]); + return done(); + }); + return w.loadURL(url); + }); + return it('is set correctly when window is inactive', function(done) { + w = new BrowserWindow({ + show: false + }); + w.webContents.on('ipc-message', function(event, args) { + assert.deepEqual(args, ['hidden', false]); + return done(); + }); + w.showInactive(); + return w.loadURL(url); + }); + }); + xdescribe('navigator.webkitGetUserMedia', function() { + return it('calls its callbacks', function(done) { + this.timeout(5000); + return navigator.webkitGetUserMedia({ + audio: true, + video: false + }, function() { + return done(); + }, function() { + return done(); + }); + }); + }); + describe('navigator.language', function() { + return it('should not be empty', function() { + return assert.notEqual(navigator.language, ''); + }); + }); + describe('navigator.serviceWorker', function() { + var url, w; + url = "file://" + fixtures + "/pages/service-worker/index.html"; + w = null; + afterEach(function() { + return w != null ? w.destroy() : void 0; + }); + return it('should register for file scheme', function(done) { + w = new BrowserWindow({ + show: false + }); + w.webContents.on('ipc-message', function(event, args) { + if (args[0] === 'reload') { + return w.webContents.reload(); + } else if (args[0] === 'error') { + return done('unexpected error : ' + args[1]); + } else if (args[0] === 'response') { + assert.equal(args[1], 'Hello from serviceWorker!'); + return session.defaultSession.clearStorageData({ + storages: ['serviceworkers'] + }, function() { + return done(); + }); + } + }); + return w.loadURL(url); + }); + }); + describe('window.open', function() { + this.timeout(20000); + it('returns a BrowserWindowProxy object', function() { + var b; + b = window.open('about:blank', '', 'show=no'); + assert.equal(b.closed, false); + assert.equal(b.constructor.name, 'BrowserWindowProxy'); + return b.close(); + }); + it('accepts "node-integration" as feature', function(done) { + var b; + listener = function(event) { + assert.equal(event.data, 'undefined'); + b.close(); + return done(); + }; + window.addEventListener('message', listener); + return b = window.open("file://" + fixtures + "/pages/window-opener-node.html", '', 'nodeIntegration=no,show=no'); + }); + it('inherit options of parent window', function(done) { + var b; + listener = function(event) { + var height, ref1, width; + ref1 = remote.getCurrentWindow().getSize(), width = ref1[0], height = ref1[1]; + assert.equal(event.data, "size: " + width + " " + height); + b.close(); + return done(); + }; + window.addEventListener('message', listener); + return b = window.open("file://" + fixtures + "/pages/window-open-size.html", '', 'show=no'); + }); + return it('does not override child options', function(done) { + var b, size; + size = { + width: 350, + height: 450 + }; + listener = function(event) { + assert.equal(event.data, "size: " + size.width + " " + size.height); + b.close(); + return done(); + }; + window.addEventListener('message', listener); + return b = window.open("file://" + fixtures + "/pages/window-open-size.html", '', "show=no,width=" + size.width + ",height=" + size.height); + }); + }); + describe('window.opener', function() { + var url, w; + this.timeout(10000); + url = "file://" + fixtures + "/pages/window-opener.html"; + w = null; + afterEach(function() { + return w != null ? w.destroy() : void 0; + }); + it('is null for main window', function(done) { + w = new BrowserWindow({ + show: false + }); + w.webContents.on('ipc-message', function(event, args) { + assert.deepEqual(args, ['opener', null]); + return done(); + }); + return w.loadURL(url); + }); + return it('is not null for window opened by window.open', function(done) { + var b; + listener = function(event) { + assert.equal(event.data, 'object'); + b.close(); + return done(); + }; + window.addEventListener('message', listener); + return b = window.open(url, '', 'show=no'); + }); + }); + describe('window.postMessage', function() { + return it('sets the source and origin correctly', function(done) { + var b, sourceId; + sourceId = remote.getCurrentWindow().id; + listener = function(event) { + var message; + window.removeEventListener('message', listener); + b.close(); + message = JSON.parse(event.data); + assert.equal(message.data, 'testing'); + assert.equal(message.origin, 'file://'); + assert.equal(message.sourceEqualsOpener, true); + assert.equal(message.sourceId, sourceId); + assert.equal(event.origin, 'file://'); + return done(); + }; + window.addEventListener('message', listener); + b = window.open("file://" + fixtures + "/pages/window-open-postMessage.html", '', 'show=no'); + return BrowserWindow.fromId(b.guestId).webContents.once('did-finish-load', function() { + return b.postMessage('testing', '*'); + }); + }); + }); + describe('window.opener.postMessage', function() { + return it('sets source and origin correctly', function(done) { + var b; + listener = function(event) { + window.removeEventListener('message', listener); + b.close(); + assert.equal(event.source, b); + assert.equal(event.origin, 'file://'); + return done(); + }; + window.addEventListener('message', listener); + return b = window.open("file://" + fixtures + "/pages/window-opener-postMessage.html", '', 'show=no'); + }); + }); + describe('creating a Uint8Array under browser side', function() { + return it('does not crash', function() { + var RUint8Array; + RUint8Array = remote.getGlobal('Uint8Array'); + return new RUint8Array; + }); + }); + describe('webgl', function() { + return it('can be get as context in canvas', function() { + var webgl; + if (process.platform === 'linux') { + return; + } + webgl = document.createElement('canvas').getContext('webgl'); + return assert.notEqual(webgl, null); + }); + }); + describe('web workers', function() { + it('Worker can work', function(done) { + var message, worker; + worker = new Worker('../fixtures/workers/worker.js'); + message = 'ping'; + worker.onmessage = function(event) { + assert.equal(event.data, message); + worker.terminate(); + return done(); + }; + return worker.postMessage(message); + }); + return it('SharedWorker can work', function(done) { + var message, worker; + worker = new SharedWorker('../fixtures/workers/shared_worker.js'); + message = 'ping'; + worker.port.onmessage = function(event) { + assert.equal(event.data, message); + return done(); + }; + return worker.port.postMessage(message); + }); + }); + describe('iframe', function() { + var iframe; + iframe = null; + beforeEach(function() { + return iframe = document.createElement('iframe'); + }); + afterEach(function() { + return document.body.removeChild(iframe); + }); + return it('does not have node integration', function(done) { + iframe.src = "file://" + fixtures + "/pages/set-global.html"; + document.body.appendChild(iframe); + return iframe.onload = function() { + assert.equal(iframe.contentWindow.test, 'undefined undefined undefined'); + return done(); + }; + }); + }); + describe('storage', function() { + return it('requesting persitent quota works', function(done) { + return navigator.webkitPersistentStorage.requestQuota(1024 * 1024, function(grantedBytes) { + assert.equal(grantedBytes, 1048576); + return done(); + }); + }); + }); + describe('websockets', function() { + var WebSocketServer, server, wss; + wss = null; + server = null; + WebSocketServer = ws.Server; + afterEach(function() { + wss.close(); + return server.close(); + }); + return it('has user agent', function(done) { + server = http.createServer(); + return server.listen(0, '127.0.0.1', function() { + var port, websocket; + port = server.address().port; + wss = new WebSocketServer({ + server: server + }); + wss.on('error', done); + wss.on('connection', function(ws) { + if (ws.upgradeReq.headers['user-agent']) { + return done(); + } else { + return done('user agent is empty'); + } + }); + return websocket = new WebSocket("ws://127.0.0.1:" + port); + }); + }); + }); + return describe('Promise', function() { + it('resolves correctly in Node.js calls', function(done) { + document.registerElement('x-element', { + prototype: Object.create(HTMLElement.prototype, { + createdCallback: { + value: function() {} + } + }) + }); + return setImmediate(function() { + var called; + called = false; + Promise.resolve().then(function() { + return done(called ? void 0 : new Error('wrong sequence')); + }); + document.createElement('x-element'); + return called = true; + }); + }); + return it('resolves correctly in Electron calls', function(done) { + document.registerElement('y-element', { + prototype: Object.create(HTMLElement.prototype, { + createdCallback: { + value: function() {} + } + }) + }); + return remote.getGlobal('setImmediate')(function() { + var called; + called = false; + Promise.resolve().then(function() { + return done(called ? void 0 : new Error('wrong sequence')); + }); + document.createElement('y-element'); + return called = true; + }); + }); + }); +}); diff --git a/spec/modules-spec.coffee b/spec/modules-spec.coffee deleted file mode 100644 index 1cdc6cf0ea5c..000000000000 --- a/spec/modules-spec.coffee +++ /dev/null @@ -1,38 +0,0 @@ -assert = require 'assert' -fs = require 'fs' -path = require 'path' -temp = require 'temp' - -describe 'third-party module', -> - fixtures = path.join __dirname, 'fixtures' - temp.track() - - # If the test is executed with the debug build on Windows, we will skip it - # because native modules don't work with the debug build (see issue #2558). - if process.platform isnt 'win32' or - process.execPath.toLowerCase().indexOf('\\out\\d\\') is -1 - describe 'runas', -> - it 'can be required in renderer', -> - require 'runas' - - it 'can be required in node binary', (done) -> - runas = path.join fixtures, 'module', 'runas.js' - child = require('child_process').fork runas - child.on 'message', (msg) -> - 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' - - describe 'Q.when', -> - it 'emits the fullfil callback', (done) -> - Q(true).then (val) -> - assert.equal val, true - done() diff --git a/spec/modules-spec.js b/spec/modules-spec.js new file mode 100644 index 000000000000..809aa547b1d9 --- /dev/null +++ b/spec/modules-spec.js @@ -0,0 +1,53 @@ +var assert, fs, path, temp; + +assert = require('assert'); + +fs = require('fs'); + +path = require('path'); + +temp = require('temp'); + +describe('third-party module', function() { + var fixtures; + fixtures = path.join(__dirname, 'fixtures'); + temp.track(); + if (process.platform !== 'win32' || process.execPath.toLowerCase().indexOf('\\out\\d\\') === -1) { + describe('runas', function() { + it('can be required in renderer', function() { + return require('runas'); + }); + return it('can be required in node binary', function(done) { + var child, runas; + runas = path.join(fixtures, 'module', 'runas.js'); + child = require('child_process').fork(runas); + return child.on('message', function(msg) { + assert.equal(msg, 'ok'); + return done(); + }); + }); + }); + describe('ffi', function() { + return it('does not crash', function() { + var ffi, libm; + ffi = require('ffi'); + libm = ffi.Library('libm', { + ceil: ['double', ['double']] + }); + return assert.equal(libm.ceil(1.5), 2); + }); + }); + } + return describe('q', function() { + var Q; + Q = require('q'); + return describe('Q.when', function() { + return it('emits the fullfil callback', function(done) { + return Q(true).then(function(val) { + assert.equal(val, true); + return done(); + }); + }); + }); + }); +}); diff --git a/spec/node-spec.coffee b/spec/node-spec.coffee deleted file mode 100644 index e6b2aa15821c..000000000000 --- a/spec/node-spec.coffee +++ /dev/null @@ -1,156 +0,0 @@ -assert = require 'assert' -child_process = require 'child_process' -fs = require 'fs' -path = require 'path' -os = require 'os' - -{remote} = require 'electron' - -describe 'node feature', -> - fixtures = path.join __dirname, 'fixtures' - - describe 'child_process', -> - describe 'child_process.fork', -> - it 'works in current process', (done) -> - child = child_process.fork path.join(fixtures, 'module', 'ping.js') - child.on 'message', (msg) -> - assert.equal msg, 'message' - done() - child.send 'message' - - it 'preserves args', (done) -> - args = ['--expose_gc', '-test', '1'] - child = child_process.fork path.join(fixtures, 'module', 'process_args.js'), args - child.on 'message', (msg) -> - assert.deepEqual args, msg.slice(2) - done() - child.send 'message' - - it 'works in forked process', (done) -> - child = child_process.fork path.join(fixtures, 'module', 'fork_ping.js') - child.on 'message', (msg) -> - assert.equal msg, 'message' - done() - child.send 'message' - - it 'works in forked process when options.env is specifed', (done) -> - child = child_process.fork path.join(fixtures, 'module', 'fork_ping.js'), - [], - path: process.env['PATH'] - child.on 'message', (msg) -> - assert.equal msg, 'message' - done() - child.send 'message' - - it 'works in browser process', (done) -> - fork = remote.require('child_process').fork - child = fork path.join(fixtures, 'module', 'ping.js') - child.on 'message', (msg) -> - assert.equal msg, 'message' - done() - child.send 'message' - - it 'has String::localeCompare working in script', (done) -> - child = child_process.fork path.join(fixtures, 'module', 'locale-compare.js') - child.on 'message', (msg) -> - assert.deepEqual msg, [0, -1, 1] - done() - child.send 'message' - - it 'has setImmediate working in script', (done) -> - child = child_process.fork path.join(fixtures, 'module', 'set-immediate.js') - child.on 'message', (msg) -> - assert.equal msg, 'ok' - done() - child.send 'message' - - 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 - - describe 'throw error in node context', -> - it 'gets caught', (done) -> - error = new Error('boo!') - lsts = process.listeners 'uncaughtException' - process.removeAllListeners 'uncaughtException' - process.on 'uncaughtException', (err) -> - process.removeAllListeners 'uncaughtException' - for lst in lsts - process.on 'uncaughtException', lst - done() - fs.readFile __filename, -> - throw error - - describe 'setTimeout called under Chromium event loop in browser process', -> - it 'can be scheduled in time', (done) -> - remote.getGlobal('setTimeout')(done, 0) - - describe 'setInterval called under Chromium event loop in browser process', -> - it 'can be scheduled in time', (done) -> - clear = -> - remote.getGlobal('clearInterval')(interval) - done() - interval = remote.getGlobal('setInterval')(clear, 10) - - describe 'message loop', -> - describe 'process.nextTick', -> - it 'emits the callback', (done) -> - process.nextTick done - - it 'works in nested calls', (done) -> - process.nextTick -> - process.nextTick -> - process.nextTick done - - describe 'setImmediate', -> - it 'emits the callback', (done) -> - setImmediate done - - it 'works in nested calls', (done) -> - setImmediate -> - setImmediate -> - setImmediate done - - describe 'net.connect', -> - return unless process.platform is 'darwin' - - it 'emit error when connect to a socket path without listeners', (done) -> - socketPath = path.join os.tmpdir(), 'atom-shell-test.sock' - script = path.join(fixtures, 'module', 'create_socket.js') - child = child_process.fork script, [socketPath] - child.on 'exit', (code) -> - assert.equal code, 0 - client = require('net').connect socketPath - client.on 'error', (error) -> - assert.equal error.code, 'ECONNREFUSED' - done() - - describe 'Buffer', -> - it 'can be created from WebKit external string', -> - p = document.createElement 'p' - p.innerText = '闲云潭影日悠悠,物换星移几度秋' - b = new Buffer(p.innerText) - assert.equal b.toString(), '闲云潭影日悠悠,物换星移几度秋' - assert.equal Buffer.byteLength(p.innerText), 45 - - it 'correctly parses external one-byte UTF8 string', -> - p = document.createElement 'p' - p.innerText = 'Jøhänñéß' - b = new Buffer(p.innerText) - assert.equal b.toString(), 'Jøhänñéß' - assert.equal Buffer.byteLength(p.innerText), 13 - - describe 'process.stdout', -> - it 'should not throw exception', -> - process.stdout - - # Not reliable on some machines - xit 'should have isTTY defined', -> - assert.equal typeof(process.stdout.isTTY), 'boolean' - - describe 'vm.createContext', -> - it 'should not crash', -> - require('vm').runInNewContext('') diff --git a/spec/node-spec.js b/spec/node-spec.js new file mode 100644 index 000000000000..fb9a40ea8d42 --- /dev/null +++ b/spec/node-spec.js @@ -0,0 +1,213 @@ +var assert, child_process, fs, os, path, remote; + +assert = require('assert'); + +child_process = require('child_process'); + +fs = require('fs'); + +path = require('path'); + +os = require('os'); + +remote = require('electron').remote; + +describe('node feature', function() { + var fixtures; + fixtures = path.join(__dirname, 'fixtures'); + describe('child_process', function() { + return describe('child_process.fork', function() { + it('works in current process', function(done) { + var child; + child = child_process.fork(path.join(fixtures, 'module', 'ping.js')); + child.on('message', function(msg) { + assert.equal(msg, 'message'); + return done(); + }); + return child.send('message'); + }); + it('preserves args', function(done) { + var args, child; + args = ['--expose_gc', '-test', '1']; + child = child_process.fork(path.join(fixtures, 'module', 'process_args.js'), args); + child.on('message', function(msg) { + assert.deepEqual(args, msg.slice(2)); + return done(); + }); + return child.send('message'); + }); + it('works in forked process', function(done) { + var child; + child = child_process.fork(path.join(fixtures, 'module', 'fork_ping.js')); + child.on('message', function(msg) { + assert.equal(msg, 'message'); + return done(); + }); + return child.send('message'); + }); + it('works in forked process when options.env is specifed', function(done) { + var child; + child = child_process.fork(path.join(fixtures, 'module', 'fork_ping.js'), [], { + path: process.env['PATH'] + }); + child.on('message', function(msg) { + assert.equal(msg, 'message'); + return done(); + }); + return child.send('message'); + }); + it('works in browser process', function(done) { + var child, fork; + fork = remote.require('child_process').fork; + child = fork(path.join(fixtures, 'module', 'ping.js')); + child.on('message', function(msg) { + assert.equal(msg, 'message'); + return done(); + }); + return child.send('message'); + }); + it('has String::localeCompare working in script', function(done) { + var child; + child = child_process.fork(path.join(fixtures, 'module', 'locale-compare.js')); + child.on('message', function(msg) { + assert.deepEqual(msg, [0, -1, 1]); + return done(); + }); + return child.send('message'); + }); + return it('has setImmediate working in script', function(done) { + var child; + child = child_process.fork(path.join(fixtures, 'module', 'set-immediate.js')); + child.on('message', function(msg) { + assert.equal(msg, 'ok'); + return done(); + }); + return child.send('message'); + }); + }); + }); + describe('contexts', function() { + describe('setTimeout in fs callback', function() { + if (process.env.TRAVIS === 'true') { + return; + } + return it('does not crash', function(done) { + return fs.readFile(__filename, function() { + return setTimeout(done, 0); + }); + }); + }); + describe('throw error in node context', function() { + return it('gets caught', function(done) { + var error, lsts; + error = new Error('boo!'); + lsts = process.listeners('uncaughtException'); + process.removeAllListeners('uncaughtException'); + process.on('uncaughtException', function(err) { + var i, len, lst; + process.removeAllListeners('uncaughtException'); + for (i = 0, len = lsts.length; i < len; i++) { + lst = lsts[i]; + process.on('uncaughtException', lst); + } + return done(); + }); + return fs.readFile(__filename, function() { + throw error; + }); + }); + }); + describe('setTimeout called under Chromium event loop in browser process', function() { + return it('can be scheduled in time', function(done) { + return remote.getGlobal('setTimeout')(done, 0); + }); + }); + return describe('setInterval called under Chromium event loop in browser process', function() { + return it('can be scheduled in time', function(done) { + var clear, interval; + clear = function() { + remote.getGlobal('clearInterval')(interval); + return done(); + }; + return interval = remote.getGlobal('setInterval')(clear, 10); + }); + }); + }); + describe('message loop', function() { + describe('process.nextTick', function() { + it('emits the callback', function(done) { + return process.nextTick(done); + }); + return it('works in nested calls', function(done) { + return process.nextTick(function() { + return process.nextTick(function() { + return process.nextTick(done); + }); + }); + }); + }); + return describe('setImmediate', function() { + it('emits the callback', function(done) { + return setImmediate(done); + }); + return it('works in nested calls', function(done) { + return setImmediate(function() { + return setImmediate(function() { + return setImmediate(done); + }); + }); + }); + }); + }); + describe('net.connect', function() { + if (process.platform !== 'darwin') { + return; + } + return it('emit error when connect to a socket path without listeners', function(done) { + var child, script, socketPath; + socketPath = path.join(os.tmpdir(), 'atom-shell-test.sock'); + script = path.join(fixtures, 'module', 'create_socket.js'); + child = child_process.fork(script, [socketPath]); + return child.on('exit', function(code) { + var client; + assert.equal(code, 0); + client = require('net').connect(socketPath); + return client.on('error', function(error) { + assert.equal(error.code, 'ECONNREFUSED'); + return done(); + }); + }); + }); + }); + describe('Buffer', function() { + it('can be created from WebKit external string', function() { + var b, p; + p = document.createElement('p'); + p.innerText = '闲云潭影日悠悠,物换星移几度秋'; + b = new Buffer(p.innerText); + assert.equal(b.toString(), '闲云潭影日悠悠,物换星移几度秋'); + return assert.equal(Buffer.byteLength(p.innerText), 45); + }); + return it('correctly parses external one-byte UTF8 string', function() { + var b, p; + p = document.createElement('p'); + p.innerText = 'Jøhänñéß'; + b = new Buffer(p.innerText); + assert.equal(b.toString(), 'Jøhänñéß'); + return assert.equal(Buffer.byteLength(p.innerText), 13); + }); + }); + describe('process.stdout', function() { + it('should not throw exception', function() { + return process.stdout; + }); + return xit('should have isTTY defined', function() { + return assert.equal(typeof process.stdout.isTTY, 'boolean'); + }); + }); + return describe('vm.createContext', function() { + return it('should not crash', function() { + return require('vm').runInNewContext(''); + }); + }); +}); diff --git a/spec/webview-spec.coffee b/spec/webview-spec.coffee deleted file mode 100644 index 4754ea4348be..000000000000 --- a/spec/webview-spec.coffee +++ /dev/null @@ -1,517 +0,0 @@ -assert = require 'assert' -path = require 'path' -http = require 'http' -url = require 'url' - -describe ' tag', -> - @timeout 10000 - - fixtures = path.join __dirname, 'fixtures' - - webview = null - beforeEach -> - webview = new WebView - afterEach -> - document.body.removeChild(webview) if document.body.contains(webview) - - describe 'src attribute', -> - it 'specifies the page to load', (done) -> - webview.addEventListener 'console-message', (e) -> - assert.equal e.message, 'a' - done() - webview.src = "file://#{fixtures}/pages/a.html" - document.body.appendChild webview - - it 'navigates to new page when changed', (done) -> - listener = (e) -> - webview.src = "file://#{fixtures}/pages/b.html" - webview.addEventListener 'console-message', (e) -> - assert.equal e.message, 'b' - done() - webview.removeEventListener 'did-finish-load', listener - webview.addEventListener 'did-finish-load', listener - webview.src = "file://#{fixtures}/pages/a.html" - document.body.appendChild webview - - describe 'nodeintegration attribute', -> - it 'inserts no node symbols when not set', (done) -> - webview.addEventListener 'console-message', (e) -> - assert.equal e.message, 'undefined undefined undefined undefined' - done() - webview.src = "file://#{fixtures}/pages/c.html" - document.body.appendChild webview - - it 'inserts node symbols when set', (done) -> - webview.addEventListener 'console-message', (e) -> - assert.equal e.message, 'function object object' - done() - webview.setAttribute 'nodeintegration', 'on' - webview.src = "file://#{fixtures}/pages/d.html" - document.body.appendChild webview - - it 'loads node symbols after POST navigation when set', (done) -> - webview.addEventListener 'console-message', (e) -> - assert.equal e.message, 'function object object' - done() - webview.setAttribute 'nodeintegration', 'on' - webview.src = "file://#{fixtures}/pages/post.html" - document.body.appendChild webview - - # If the test is executed with the debug build on Windows, we will skip it - # because native modules don't work with the debug build (see issue #2558). - if process.platform isnt 'win32' or - process.execPath.toLowerCase().indexOf('\\out\\d\\') is -1 - it 'loads native modules when navigation happens', (done) -> - listener = (e) -> - webview.removeEventListener 'did-finish-load', listener - listener2 = (e) -> - assert.equal e.message, 'function' - done() - webview.addEventListener 'console-message', listener2 - webview.reload() - webview.addEventListener 'did-finish-load', listener - webview.setAttribute 'nodeintegration', 'on' - webview.src = "file://#{fixtures}/pages/native-module.html" - document.body.appendChild webview - - describe 'preload attribute', -> - it 'loads the script before other scripts in window', (done) -> - listener = (e) -> - assert.equal e.message, 'function object object' - webview.removeEventListener 'console-message', listener - done() - webview.addEventListener 'console-message', listener - webview.setAttribute 'preload', "#{fixtures}/module/preload.js" - webview.src = "file://#{fixtures}/pages/e.html" - document.body.appendChild webview - - 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 undefined object' - done() - webview.setAttribute 'preload', "#{fixtures}/module/preload-node-off.js" - webview.src = "file://#{fixtures}/api/blank.html" - document.body.appendChild webview - - it 'receives ipc message in preload script', (done) -> - message = 'boom!' - listener = (e) -> - assert.equal e.channel, 'pong' - assert.deepEqual e.args, [message] - webview.removeEventListener 'ipc-message', listener - done() - listener2 = (e) -> - webview.send 'ping', message - webview.removeEventListener 'did-finish-load', listener2 - webview.addEventListener 'ipc-message', listener - webview.addEventListener 'did-finish-load', listener2 - webview.setAttribute 'preload', "#{fixtures}/module/preload-ipc.js" - webview.src = "file://#{fixtures}/pages/e.html" - document.body.appendChild webview - - describe 'httpreferrer attribute', -> - it 'sets the referrer url', (done) -> - referrer = 'http://github.com/' - listener = (e) -> - assert.equal e.message, referrer - webview.removeEventListener 'console-message', listener - done() - webview.addEventListener 'console-message', listener - webview.setAttribute 'httpreferrer', referrer - webview.src = "file://#{fixtures}/pages/referrer.html" - document.body.appendChild webview - - describe 'useragent attribute', -> - it 'sets the user agent', (done) -> - referrer = 'Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; AS; rv:11.0) like Gecko' - listener = (e) -> - assert.equal e.message, referrer - webview.removeEventListener 'console-message', listener - done() - webview.addEventListener 'console-message', listener - webview.setAttribute 'useragent', referrer - webview.src = "file://#{fixtures}/pages/useragent.html" - document.body.appendChild webview - - describe 'disablewebsecurity attribute', -> - it 'does not disable web security when not set', (done) -> - src = " - - - " - encoded = btoa(unescape(encodeURIComponent(src))) - listener = (e) -> - assert /Not allowed to load local resource/.test(e.message) - webview.removeEventListener 'console-message', listener - done() - webview.addEventListener 'console-message', listener - webview.src = "data:text/html;base64,#{encoded}" - document.body.appendChild webview - - it 'disables web security when set', (done) -> - src = " - - - " - encoded = btoa(unescape(encodeURIComponent(src))) - listener = (e) -> - assert.equal e.message, 'ok' - webview.removeEventListener 'console-message', listener - done() - webview.addEventListener 'console-message', listener - webview.setAttribute 'disablewebsecurity', '' - webview.src = "data:text/html;base64,#{encoded}" - document.body.appendChild webview - - describe 'partition attribute', -> - it 'inserts no node symbols when not set', (done) -> - webview.addEventListener 'console-message', (e) -> - assert.equal e.message, 'undefined undefined undefined undefined' - done() - webview.src = "file://#{fixtures}/pages/c.html" - webview.partition = 'test1' - document.body.appendChild webview - - it 'inserts node symbols when set', (done) -> - webview.addEventListener 'console-message', (e) -> - assert.equal e.message, 'function object object' - done() - webview.setAttribute 'nodeintegration', 'on' - webview.src = "file://#{fixtures}/pages/d.html" - webview.partition = 'test2' - document.body.appendChild webview - - it 'isolates storage for different id', (done) -> - listener = (e) -> - assert.equal e.message, " 0" - webview.removeEventListener 'console-message', listener - done() - window.localStorage.setItem 'test', 'one' - webview.addEventListener 'console-message', listener - webview.src = "file://#{fixtures}/pages/partition/one.html" - webview.partition = 'test3' - document.body.appendChild webview - - it 'uses current session storage when no id is provided', (done) -> - listener = (e) -> - assert.equal e.message, "one 1" - webview.removeEventListener 'console-message', listener - done() - window.localStorage.setItem 'test', 'one' - webview.addEventListener 'console-message', listener - 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) -> - assert.equal e.url, 'http://host/' - assert.equal e.frameName, 'host' - done() - webview.src = "file://#{fixtures}/pages/window-open.html" - document.body.appendChild webview - - it 'emits when link with target is called', (done) -> - webview.addEventListener 'new-window', (e) -> - assert.equal e.url, 'http://host/' - assert.equal e.frameName, 'target' - done() - webview.src = "file://#{fixtures}/pages/target-name.html" - document.body.appendChild webview - - describe 'ipc-message event', -> - it 'emits when guest sends a ipc message to browser', (done) -> - webview.addEventListener 'ipc-message', (e) -> - assert.equal e.channel, 'channel' - assert.deepEqual e.args, ['arg1', 'arg2'] - done() - webview.src = "file://#{fixtures}/pages/ipc-message.html" - webview.setAttribute 'nodeintegration', 'on' - document.body.appendChild webview - - describe 'page-title-set event', -> - it 'emits when title is set', (done) -> - webview.addEventListener 'page-title-set', (e) -> - assert.equal e.title, 'test' - assert e.explicitSet - done() - webview.src = "file://#{fixtures}/pages/a.html" - document.body.appendChild webview - - describe 'page-favicon-updated event', -> - it 'emits when favicon urls are received', (done) -> - webview.addEventListener 'page-favicon-updated', (e) -> - assert.equal e.favicons.length, 2 - pageUrl = - if process.platform is 'win32' - 'file:///C:/favicon.png' - else - 'file:///favicon.png' - assert.equal e.favicons[0], pageUrl - done() - webview.src = "file://#{fixtures}/pages/a.html" - document.body.appendChild webview - - describe 'will-navigate event', -> - it 'emits when a url that leads to oustide of the page is clicked', (done) -> - webview.addEventListener 'will-navigate', (e) -> - assert.equal e.url, "http://host/" - done() - - webview.src = "file://#{fixtures}/pages/webview-will-navigate.html" - document.body.appendChild webview - - describe 'did-navigate event', -> - p = path.join fixtures, 'pages', 'webview-will-navigate.html' - p = p.replace /\\/g, '/' - pageUrl = url.format protocol: 'file', slashes: true, pathname: p - - it 'emits when a url that leads to outside of the page is clicked', (done) -> - webview.addEventListener 'did-navigate', (e) -> - assert.equal e.url, pageUrl - done() - - webview.src = pageUrl - document.body.appendChild webview - - describe 'did-navigate-in-page event', -> - it 'emits when an anchor link is clicked', (done) -> - p = path.join fixtures, 'pages', 'webview-did-navigate-in-page.html' - p = p.replace /\\/g, '/' - pageUrl = url.format protocol: 'file', slashes: true, pathname: p - - webview.addEventListener 'did-navigate-in-page', (e) -> - assert.equal e.url, "#{pageUrl}#test_content" - done() - - webview.src = pageUrl - document.body.appendChild webview - - it 'emits when window.history.replaceState is called', (done) -> - webview.addEventListener 'did-navigate-in-page', (e) -> - assert.equal e.url, "http://host/" - done() - - webview.src = "file://#{fixtures}/pages/webview-did-navigate-in-page-with-history.html" - document.body.appendChild webview - - it 'emits when window.location.hash is changed', (done) -> - p = path.join fixtures, 'pages', 'webview-did-navigate-in-page-with-hash.html' - p = p.replace /\\/g, '/' - pageUrl = url.format protocol: 'file', slashes: true, pathname: p - - webview.addEventListener 'did-navigate-in-page', (e) -> - assert.equal e.url, "#{pageUrl}#test" - done() - - webview.src = pageUrl - document.body.appendChild webview - - describe 'close event', -> - it 'should fire when interior page calls window.close', (done) -> - webview.addEventListener 'close', -> - done() - - webview.src = "file://#{fixtures}/pages/close.html" - document.body.appendChild webview - - describe 'devtools-opened event', -> - it 'should fire when webview.openDevTools() is called', (done) -> - listener = -> - webview.removeEventListener 'devtools-opened', listener - webview.closeDevTools() - done() - - webview.addEventListener 'devtools-opened', listener - webview.addEventListener 'dom-ready', -> - webview.openDevTools() - - webview.src = "file://#{fixtures}/pages/base-page.html" - document.body.appendChild webview - - describe 'devtools-closed event', -> - it 'should fire when webview.closeDevTools() is called', (done) -> - listener2 = -> - webview.removeEventListener 'devtools-closed', listener2 - done() - - listener = -> - webview.removeEventListener 'devtools-opened', listener - webview.closeDevTools() - - webview.addEventListener 'devtools-opened', listener - webview.addEventListener 'devtools-closed', listener2 - webview.addEventListener 'dom-ready', -> - webview.openDevTools() - - webview.src = "file://#{fixtures}/pages/base-page.html" - document.body.appendChild webview - - describe 'devtools-focused event', -> - it 'should fire when webview.openDevTools() is called', (done) -> - listener = -> - webview.removeEventListener 'devtools-focused', listener - webview.closeDevTools() - done() - - webview.addEventListener 'devtools-focused', listener - webview.addEventListener 'dom-ready', -> - webview.openDevTools() - - webview.src = "file://#{fixtures}/pages/base-page.html" - document.body.appendChild webview - - describe '.reload()', -> - it 'should emit beforeunload handler', (done) -> - listener = (e) -> - assert.equal e.channel, 'onbeforeunload' - webview.removeEventListener 'ipc-message', listener - done() - listener2 = (e) -> - webview.reload() - webview.removeEventListener 'did-finish-load', listener2 - webview.addEventListener 'ipc-message', listener - webview.addEventListener 'did-finish-load', listener2 - webview.setAttribute 'nodeintegration', 'on' - webview.src = "file://#{fixtures}/pages/beforeunload-false.html" - document.body.appendChild webview - - describe '.clearHistory()', -> - it 'should clear the navigation history', (done) -> - listener = (e) -> - assert.equal e.channel, 'history' - assert.equal e.args[0], 2 - assert webview.canGoBack() - webview.clearHistory() - assert not webview.canGoBack() - webview.removeEventListener 'ipc-message', listener - done() - webview.addEventListener 'ipc-message', listener - webview.setAttribute 'nodeintegration', 'on' - webview.src = "file://#{fixtures}/pages/history.html" - document.body.appendChild webview - - describe 'basic auth', -> - auth = require 'basic-auth' - - it 'should authenticate with correct credentials', (done) -> - message = 'Authenticated' - server = http.createServer (req, res) -> - credentials = auth(req) - if credentials.name == 'test' and credentials.pass == 'test' - res.end(message) - else - res.end('failed') - server.close() - server.listen 0, '127.0.0.1', -> - {port} = server.address() - webview.addEventListener 'ipc-message', (e) -> - assert.equal e.channel, message - done() - webview.src = "file://#{fixtures}/pages/basic-auth.html?port=#{port}" - webview.setAttribute 'nodeintegration', 'on' - document.body.appendChild webview - - describe 'dom-ready event', -> - it 'emits when document is loaded', (done) -> - server = http.createServer (req) -> - # Never respond, so the page never finished loading. - server.listen 0, '127.0.0.1', -> - {port} = server.address() - webview.addEventListener 'dom-ready', -> - done() - webview.src = "file://#{fixtures}/pages/dom-ready.html?port=#{port}" - document.body.appendChild webview - - describe 'executeJavaScript', -> - return unless process.env.TRAVIS is 'true' - - it 'should support user gesture', (done) -> - listener = (e) -> - webview.removeEventListener 'enter-html-full-screen', listener - done() - listener2 = (e) -> - jsScript = 'document.getElementsByTagName("video")[0].webkitRequestFullScreen()' - webview.executeJavaScript jsScript, true - webview.removeEventListener 'did-finish-load', listener2 - webview.addEventListener 'enter-html-full-screen', listener - webview.addEventListener 'did-finish-load', listener2 - webview.src = "file://#{fixtures}/pages/fullscreen.html" - document.body.appendChild webview - - describe 'sendInputEvent', -> - it 'can send keyboard event', (done) -> - webview.addEventListener 'ipc-message', (e) -> - assert.equal e.channel, 'keyup' - assert.deepEqual e.args, [67, true, false] - done() - webview.addEventListener 'dom-ready', -> - webview.sendInputEvent type: 'keyup', keyCode: 'c', modifiers: ['shift'] - webview.src = "file://#{fixtures}/pages/onkeyup.html" - webview.setAttribute 'nodeintegration', 'on' - document.body.appendChild webview - - it 'can send mouse event', (done) -> - webview.addEventListener 'ipc-message', (e) -> - assert.equal e.channel, 'mouseup' - assert.deepEqual e.args, [10, 20, false, true] - done() - webview.addEventListener 'dom-ready', -> - webview.sendInputEvent type: 'mouseup', modifiers: ['ctrl'], x: 10, y: 20 - webview.src = "file://#{fixtures}/pages/onmouseup.html" - webview.setAttribute 'nodeintegration', 'on' - document.body.appendChild webview - - describe 'media-started-playing media-paused events', -> - it 'emits when audio starts and stops playing', (done) -> - audioPlayed = false - webview.addEventListener 'media-started-playing', -> - audioPlayed = true - webview.addEventListener 'media-paused', -> - assert audioPlayed - done() - webview.src = "file://#{fixtures}/pages/audio.html" - document.body.appendChild webview - - describe 'found-in-page event', -> - it 'emits when a request is made', (done) -> - requestId = null - listener = (e) -> - assert.equal e.result.requestId, requestId - if e.result.finalUpdate - assert.equal e.result.matches, 3 - webview.stopFindInPage "clearSelection" - done() - listener2 = (e) -> - requestId = webview.findInPage "virtual" - webview.addEventListener 'found-in-page', listener - webview.addEventListener 'did-finish-load', listener2 - webview.src = "file://#{fixtures}/pages/content.html" - document.body.appendChild webview - - xdescribe 'did-change-theme-color event', -> - it 'emits when theme color changes', (done) -> - webview.addEventListener 'did-change-theme-color', (e) -> - done() - webview.src = "file://#{fixtures}/pages/theme-color.html" - document.body.appendChild webview diff --git a/spec/webview-spec.js b/spec/webview-spec.js new file mode 100644 index 000000000000..660a960cf946 --- /dev/null +++ b/spec/webview-spec.js @@ -0,0 +1,639 @@ +var assert, http, path, url; + +assert = require('assert'); + +path = require('path'); + +http = require('http'); + +url = require('url'); + +describe(' tag', function() { + var fixtures, webview; + this.timeout(10000); + fixtures = path.join(__dirname, 'fixtures'); + webview = null; + beforeEach(function() { + return webview = new WebView; + }); + afterEach(function() { + if (document.body.contains(webview)) { + return document.body.removeChild(webview); + } + }); + describe('src attribute', function() { + it('specifies the page to load', function(done) { + webview.addEventListener('console-message', function(e) { + assert.equal(e.message, 'a'); + return done(); + }); + webview.src = "file://" + fixtures + "/pages/a.html"; + return document.body.appendChild(webview); + }); + return it('navigates to new page when changed', function(done) { + var listener; + listener = function(e) { + webview.src = "file://" + fixtures + "/pages/b.html"; + webview.addEventListener('console-message', function(e) { + assert.equal(e.message, 'b'); + return done(); + }); + return webview.removeEventListener('did-finish-load', listener); + }; + webview.addEventListener('did-finish-load', listener); + webview.src = "file://" + fixtures + "/pages/a.html"; + return document.body.appendChild(webview); + }); + }); + describe('nodeintegration attribute', function() { + it('inserts no node symbols when not set', function(done) { + webview.addEventListener('console-message', function(e) { + assert.equal(e.message, 'undefined undefined undefined undefined'); + return done(); + }); + webview.src = "file://" + fixtures + "/pages/c.html"; + return document.body.appendChild(webview); + }); + it('inserts node symbols when set', function(done) { + webview.addEventListener('console-message', function(e) { + assert.equal(e.message, 'function object object'); + return done(); + }); + webview.setAttribute('nodeintegration', 'on'); + webview.src = "file://" + fixtures + "/pages/d.html"; + return document.body.appendChild(webview); + }); + it('loads node symbols after POST navigation when set', function(done) { + webview.addEventListener('console-message', function(e) { + assert.equal(e.message, 'function object object'); + return done(); + }); + webview.setAttribute('nodeintegration', 'on'); + webview.src = "file://" + fixtures + "/pages/post.html"; + return document.body.appendChild(webview); + }); + if (process.platform !== 'win32' || process.execPath.toLowerCase().indexOf('\\out\\d\\') === -1) { + return it('loads native modules when navigation happens', function(done) { + var listener; + listener = function(e) { + var listener2; + webview.removeEventListener('did-finish-load', listener); + listener2 = function(e) { + assert.equal(e.message, 'function'); + return done(); + }; + webview.addEventListener('console-message', listener2); + return webview.reload(); + }; + webview.addEventListener('did-finish-load', listener); + webview.setAttribute('nodeintegration', 'on'); + webview.src = "file://" + fixtures + "/pages/native-module.html"; + return document.body.appendChild(webview); + }); + } + }); + describe('preload attribute', function() { + it('loads the script before other scripts in window', function(done) { + var listener; + listener = function(e) { + assert.equal(e.message, 'function object object'); + webview.removeEventListener('console-message', listener); + return done(); + }; + webview.addEventListener('console-message', listener); + webview.setAttribute('preload', fixtures + "/module/preload.js"); + webview.src = "file://" + fixtures + "/pages/e.html"; + return document.body.appendChild(webview); + }); + it('preload script can still use "process" in required modules when nodeintegration is off', function(done) { + webview.addEventListener('console-message', function(e) { + assert.equal(e.message, 'object undefined object'); + return done(); + }); + webview.setAttribute('preload', fixtures + "/module/preload-node-off.js"); + webview.src = "file://" + fixtures + "/api/blank.html"; + return document.body.appendChild(webview); + }); + return it('receives ipc message in preload script', function(done) { + var listener, listener2, message; + message = 'boom!'; + listener = function(e) { + assert.equal(e.channel, 'pong'); + assert.deepEqual(e.args, [message]); + webview.removeEventListener('ipc-message', listener); + return done(); + }; + listener2 = function(e) { + webview.send('ping', message); + return webview.removeEventListener('did-finish-load', listener2); + }; + webview.addEventListener('ipc-message', listener); + webview.addEventListener('did-finish-load', listener2); + webview.setAttribute('preload', fixtures + "/module/preload-ipc.js"); + webview.src = "file://" + fixtures + "/pages/e.html"; + return document.body.appendChild(webview); + }); + }); + describe('httpreferrer attribute', function() { + return it('sets the referrer url', function(done) { + var listener, referrer; + referrer = 'http://github.com/'; + listener = function(e) { + assert.equal(e.message, referrer); + webview.removeEventListener('console-message', listener); + return done(); + }; + webview.addEventListener('console-message', listener); + webview.setAttribute('httpreferrer', referrer); + webview.src = "file://" + fixtures + "/pages/referrer.html"; + return document.body.appendChild(webview); + }); + }); + describe('useragent attribute', function() { + return it('sets the user agent', function(done) { + var listener, referrer; + referrer = 'Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; AS; rv:11.0) like Gecko'; + listener = function(e) { + assert.equal(e.message, referrer); + webview.removeEventListener('console-message', listener); + return done(); + }; + webview.addEventListener('console-message', listener); + webview.setAttribute('useragent', referrer); + webview.src = "file://" + fixtures + "/pages/useragent.html"; + return document.body.appendChild(webview); + }); + }); + describe('disablewebsecurity attribute', function() { + it('does not disable web security when not set', function(done) { + var encoded, listener, src; + src = " "; + encoded = btoa(unescape(encodeURIComponent(src))); + listener = function(e) { + assert(/Not allowed to load local resource/.test(e.message)); + webview.removeEventListener('console-message', listener); + return done(); + }; + webview.addEventListener('console-message', listener); + webview.src = "data:text/html;base64," + encoded; + return document.body.appendChild(webview); + }); + return it('disables web security when set', function(done) { + var encoded, listener, src; + src = " "; + encoded = btoa(unescape(encodeURIComponent(src))); + listener = function(e) { + assert.equal(e.message, 'ok'); + webview.removeEventListener('console-message', listener); + return done(); + }; + webview.addEventListener('console-message', listener); + webview.setAttribute('disablewebsecurity', ''); + webview.src = "data:text/html;base64," + encoded; + return document.body.appendChild(webview); + }); + }); + describe('partition attribute', function() { + it('inserts no node symbols when not set', function(done) { + webview.addEventListener('console-message', function(e) { + assert.equal(e.message, 'undefined undefined undefined undefined'); + return done(); + }); + webview.src = "file://" + fixtures + "/pages/c.html"; + webview.partition = 'test1'; + return document.body.appendChild(webview); + }); + it('inserts node symbols when set', function(done) { + webview.addEventListener('console-message', function(e) { + assert.equal(e.message, 'function object object'); + return done(); + }); + webview.setAttribute('nodeintegration', 'on'); + webview.src = "file://" + fixtures + "/pages/d.html"; + webview.partition = 'test2'; + return document.body.appendChild(webview); + }); + it('isolates storage for different id', function(done) { + var listener; + listener = function(e) { + assert.equal(e.message, " 0"); + webview.removeEventListener('console-message', listener); + return done(); + }; + window.localStorage.setItem('test', 'one'); + webview.addEventListener('console-message', listener); + webview.src = "file://" + fixtures + "/pages/partition/one.html"; + webview.partition = 'test3'; + return document.body.appendChild(webview); + }); + return it('uses current session storage when no id is provided', function(done) { + var listener; + listener = function(e) { + assert.equal(e.message, "one 1"); + webview.removeEventListener('console-message', listener); + return done(); + }; + window.localStorage.setItem('test', 'one'); + webview.addEventListener('console-message', listener); + webview.src = "file://" + fixtures + "/pages/partition/one.html"; + return document.body.appendChild(webview); + }); + }); + describe('allowpopups attribute', function() { + it('can not open new window when not set', function(done) { + var listener; + listener = function(e) { + assert.equal(e.message, 'null'); + webview.removeEventListener('console-message', listener); + return done(); + }; + webview.addEventListener('console-message', listener); + webview.src = "file://" + fixtures + "/pages/window-open-hide.html"; + return document.body.appendChild(webview); + }); + return it('can open new window when set', function(done) { + var listener; + listener = function(e) { + assert.equal(e.message, 'window'); + webview.removeEventListener('console-message', listener); + return done(); + }; + webview.addEventListener('console-message', listener); + webview.setAttribute('allowpopups', 'on'); + webview.src = "file://" + fixtures + "/pages/window-open-hide.html"; + return document.body.appendChild(webview); + }); + }); + describe('new-window event', function() { + it('emits when window.open is called', function(done) { + webview.addEventListener('new-window', function(e) { + assert.equal(e.url, 'http://host/'); + assert.equal(e.frameName, 'host'); + return done(); + }); + webview.src = "file://" + fixtures + "/pages/window-open.html"; + return document.body.appendChild(webview); + }); + return it('emits when link with target is called', function(done) { + webview.addEventListener('new-window', function(e) { + assert.equal(e.url, 'http://host/'); + assert.equal(e.frameName, 'target'); + return done(); + }); + webview.src = "file://" + fixtures + "/pages/target-name.html"; + return document.body.appendChild(webview); + }); + }); + describe('ipc-message event', function() { + return it('emits when guest sends a ipc message to browser', function(done) { + webview.addEventListener('ipc-message', function(e) { + assert.equal(e.channel, 'channel'); + assert.deepEqual(e.args, ['arg1', 'arg2']); + return done(); + }); + webview.src = "file://" + fixtures + "/pages/ipc-message.html"; + webview.setAttribute('nodeintegration', 'on'); + return document.body.appendChild(webview); + }); + }); + describe('page-title-set event', function() { + return it('emits when title is set', function(done) { + webview.addEventListener('page-title-set', function(e) { + assert.equal(e.title, 'test'); + assert(e.explicitSet); + return done(); + }); + webview.src = "file://" + fixtures + "/pages/a.html"; + return document.body.appendChild(webview); + }); + }); + describe('page-favicon-updated event', function() { + return it('emits when favicon urls are received', function(done) { + webview.addEventListener('page-favicon-updated', function(e) { + var pageUrl; + assert.equal(e.favicons.length, 2); + pageUrl = process.platform === 'win32' ? 'file:///C:/favicon.png' : 'file:///favicon.png'; + assert.equal(e.favicons[0], pageUrl); + return done(); + }); + webview.src = "file://" + fixtures + "/pages/a.html"; + return document.body.appendChild(webview); + }); + }); + describe('will-navigate event', function() { + return it('emits when a url that leads to oustide of the page is clicked', function(done) { + webview.addEventListener('will-navigate', function(e) { + assert.equal(e.url, "http://host/"); + return done(); + }); + webview.src = "file://" + fixtures + "/pages/webview-will-navigate.html"; + return document.body.appendChild(webview); + }); + }); + describe('did-navigate event', function() { + var p, pageUrl; + p = path.join(fixtures, 'pages', 'webview-will-navigate.html'); + p = p.replace(/\\/g, '/'); + pageUrl = url.format({ + protocol: 'file', + slashes: true, + pathname: p + }); + return it('emits when a url that leads to outside of the page is clicked', function(done) { + webview.addEventListener('did-navigate', function(e) { + assert.equal(e.url, pageUrl); + return done(); + }); + webview.src = pageUrl; + return document.body.appendChild(webview); + }); + }); + describe('did-navigate-in-page event', function() { + it('emits when an anchor link is clicked', function(done) { + var p, pageUrl; + p = path.join(fixtures, 'pages', 'webview-did-navigate-in-page.html'); + p = p.replace(/\\/g, '/'); + pageUrl = url.format({ + protocol: 'file', + slashes: true, + pathname: p + }); + webview.addEventListener('did-navigate-in-page', function(e) { + assert.equal(e.url, pageUrl + "#test_content"); + return done(); + }); + webview.src = pageUrl; + return document.body.appendChild(webview); + }); + it('emits when window.history.replaceState is called', function(done) { + webview.addEventListener('did-navigate-in-page', function(e) { + assert.equal(e.url, "http://host/"); + return done(); + }); + webview.src = "file://" + fixtures + "/pages/webview-did-navigate-in-page-with-history.html"; + return document.body.appendChild(webview); + }); + return it('emits when window.location.hash is changed', function(done) { + var p, pageUrl; + p = path.join(fixtures, 'pages', 'webview-did-navigate-in-page-with-hash.html'); + p = p.replace(/\\/g, '/'); + pageUrl = url.format({ + protocol: 'file', + slashes: true, + pathname: p + }); + webview.addEventListener('did-navigate-in-page', function(e) { + assert.equal(e.url, pageUrl + "#test"); + return done(); + }); + webview.src = pageUrl; + return document.body.appendChild(webview); + }); + }); + describe('close event', function() { + return it('should fire when interior page calls window.close', function(done) { + webview.addEventListener('close', function() { + return done(); + }); + webview.src = "file://" + fixtures + "/pages/close.html"; + return document.body.appendChild(webview); + }); + }); + describe('devtools-opened event', function() { + return it('should fire when webview.openDevTools() is called', function(done) { + var listener; + listener = function() { + webview.removeEventListener('devtools-opened', listener); + webview.closeDevTools(); + return done(); + }; + webview.addEventListener('devtools-opened', listener); + webview.addEventListener('dom-ready', function() { + return webview.openDevTools(); + }); + webview.src = "file://" + fixtures + "/pages/base-page.html"; + return document.body.appendChild(webview); + }); + }); + describe('devtools-closed event', function() { + return it('should fire when webview.closeDevTools() is called', function(done) { + var listener, listener2; + listener2 = function() { + webview.removeEventListener('devtools-closed', listener2); + return done(); + }; + listener = function() { + webview.removeEventListener('devtools-opened', listener); + return webview.closeDevTools(); + }; + webview.addEventListener('devtools-opened', listener); + webview.addEventListener('devtools-closed', listener2); + webview.addEventListener('dom-ready', function() { + return webview.openDevTools(); + }); + webview.src = "file://" + fixtures + "/pages/base-page.html"; + return document.body.appendChild(webview); + }); + }); + describe('devtools-focused event', function() { + return it('should fire when webview.openDevTools() is called', function(done) { + var listener; + listener = function() { + webview.removeEventListener('devtools-focused', listener); + webview.closeDevTools(); + return done(); + }; + webview.addEventListener('devtools-focused', listener); + webview.addEventListener('dom-ready', function() { + return webview.openDevTools(); + }); + webview.src = "file://" + fixtures + "/pages/base-page.html"; + return document.body.appendChild(webview); + }); + }); + describe('.reload()', function() { + return it('should emit beforeunload handler', function(done) { + var listener, listener2; + listener = function(e) { + assert.equal(e.channel, 'onbeforeunload'); + webview.removeEventListener('ipc-message', listener); + return done(); + }; + listener2 = function(e) { + webview.reload(); + return webview.removeEventListener('did-finish-load', listener2); + }; + webview.addEventListener('ipc-message', listener); + webview.addEventListener('did-finish-load', listener2); + webview.setAttribute('nodeintegration', 'on'); + webview.src = "file://" + fixtures + "/pages/beforeunload-false.html"; + return document.body.appendChild(webview); + }); + }); + describe('.clearHistory()', function() { + return it('should clear the navigation history', function(done) { + var listener; + listener = function(e) { + assert.equal(e.channel, 'history'); + assert.equal(e.args[0], 2); + assert(webview.canGoBack()); + webview.clearHistory(); + assert(!webview.canGoBack()); + webview.removeEventListener('ipc-message', listener); + return done(); + }; + webview.addEventListener('ipc-message', listener); + webview.setAttribute('nodeintegration', 'on'); + webview.src = "file://" + fixtures + "/pages/history.html"; + return document.body.appendChild(webview); + }); + }); + describe('basic auth', function() { + var auth; + auth = require('basic-auth'); + return it('should authenticate with correct credentials', function(done) { + var message, server; + message = 'Authenticated'; + server = http.createServer(function(req, res) { + var credentials; + credentials = auth(req); + if (credentials.name === 'test' && credentials.pass === 'test') { + res.end(message); + } else { + res.end('failed'); + } + return server.close(); + }); + return server.listen(0, '127.0.0.1', function() { + var port; + port = server.address().port; + webview.addEventListener('ipc-message', function(e) { + assert.equal(e.channel, message); + return done(); + }); + webview.src = "file://" + fixtures + "/pages/basic-auth.html?port=" + port; + webview.setAttribute('nodeintegration', 'on'); + return document.body.appendChild(webview); + }); + }); + }); + describe('dom-ready event', function() { + return it('emits when document is loaded', function(done) { + var server; + server = http.createServer(function(req) {}); + return server.listen(0, '127.0.0.1', function() { + var port; + port = server.address().port; + webview.addEventListener('dom-ready', function() { + return done(); + }); + webview.src = "file://" + fixtures + "/pages/dom-ready.html?port=" + port; + return document.body.appendChild(webview); + }); + }); + }); + describe('executeJavaScript', function() { + if (process.env.TRAVIS !== 'true') { + return; + } + return it('should support user gesture', function(done) { + var listener, listener2; + listener = function(e) { + webview.removeEventListener('enter-html-full-screen', listener); + return done(); + }; + listener2 = function(e) { + var jsScript; + jsScript = 'document.getElementsByTagName("video")[0].webkitRequestFullScreen()'; + webview.executeJavaScript(jsScript, true); + return webview.removeEventListener('did-finish-load', listener2); + }; + webview.addEventListener('enter-html-full-screen', listener); + webview.addEventListener('did-finish-load', listener2); + webview.src = "file://" + fixtures + "/pages/fullscreen.html"; + return document.body.appendChild(webview); + }); + }); + describe('sendInputEvent', function() { + it('can send keyboard event', function(done) { + webview.addEventListener('ipc-message', function(e) { + assert.equal(e.channel, 'keyup'); + assert.deepEqual(e.args, [67, true, false]); + return done(); + }); + webview.addEventListener('dom-ready', function() { + return webview.sendInputEvent({ + type: 'keyup', + keyCode: 'c', + modifiers: ['shift'] + }); + }); + webview.src = "file://" + fixtures + "/pages/onkeyup.html"; + webview.setAttribute('nodeintegration', 'on'); + return document.body.appendChild(webview); + }); + return it('can send mouse event', function(done) { + webview.addEventListener('ipc-message', function(e) { + assert.equal(e.channel, 'mouseup'); + assert.deepEqual(e.args, [10, 20, false, true]); + return done(); + }); + webview.addEventListener('dom-ready', function() { + return webview.sendInputEvent({ + type: 'mouseup', + modifiers: ['ctrl'], + x: 10, + y: 20 + }); + }); + webview.src = "file://" + fixtures + "/pages/onmouseup.html"; + webview.setAttribute('nodeintegration', 'on'); + return document.body.appendChild(webview); + }); + }); + describe('media-started-playing media-paused events', function() { + return it('emits when audio starts and stops playing', function(done) { + var audioPlayed; + audioPlayed = false; + webview.addEventListener('media-started-playing', function() { + return audioPlayed = true; + }); + webview.addEventListener('media-paused', function() { + assert(audioPlayed); + return done(); + }); + webview.src = "file://" + fixtures + "/pages/audio.html"; + return document.body.appendChild(webview); + }); + }); + describe('found-in-page event', function() { + return it('emits when a request is made', function(done) { + var listener, listener2, requestId; + requestId = null; + listener = function(e) { + assert.equal(e.result.requestId, requestId); + if (e.result.finalUpdate) { + assert.equal(e.result.matches, 3); + webview.stopFindInPage("clearSelection"); + return done(); + } + }; + listener2 = function(e) { + return requestId = webview.findInPage("virtual"); + }; + webview.addEventListener('found-in-page', listener); + webview.addEventListener('did-finish-load', listener2); + webview.src = "file://" + fixtures + "/pages/content.html"; + return document.body.appendChild(webview); + }); + }); + return xdescribe('did-change-theme-color event', function() { + return it('emits when theme color changes', function(done) { + webview.addEventListener('did-change-theme-color', function(e) { + return done(); + }); + webview.src = "file://" + fixtures + "/pages/theme-color.html"; + return document.body.appendChild(webview); + }); + }); +}); From 714e544b514618fd3289f17e82da81231f58a28f Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 11 Jan 2016 16:44:01 -0800 Subject: [PATCH 45/95] Remove coffeelint usage --- script/cibuild | 1 - script/coffeelint.json | 6 ------ script/coffeelint.py | 28 ---------------------------- 3 files changed, 35 deletions(-) delete mode 100644 script/coffeelint.json delete mode 100755 script/coffeelint.py diff --git a/script/cibuild b/script/cibuild index c0798dc7e2c3..1273945409e4 100755 --- a/script/cibuild +++ b/script/cibuild @@ -65,7 +65,6 @@ def main(): run_script('cpplint.py') if PLATFORM != 'win32': run_script('pylint.py') - run_script('coffeelint.py') if is_release: run_script('build.py', ['-c', 'R']) run_script('create-dist.py') diff --git a/script/coffeelint.json b/script/coffeelint.json deleted file mode 100644 index cc06d0d3c8ed..000000000000 --- a/script/coffeelint.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "max_line_length": { - "value": 80, - "level": "ignore" - } -} diff --git a/script/coffeelint.py b/script/coffeelint.py deleted file mode 100755 index 29f60f93d6fa..000000000000 --- a/script/coffeelint.py +++ /dev/null @@ -1,28 +0,0 @@ -#!/usr/bin/env python - -import glob -import os -import sys - -from lib.util import execute - - -SOURCE_ROOT = os.path.abspath(os.path.dirname(os.path.dirname(__file__))) - - -def main(): - os.chdir(SOURCE_ROOT) - - coffeelint = os.path.join(SOURCE_ROOT, 'node_modules', '.bin', 'coffeelint') - if sys.platform in ['win32', 'cygwin']: - coffeelint += '.cmd' - settings = ['--quiet', '-f', os.path.join('script', 'coffeelint.json')] - files = glob.glob('atom/browser/api/lib/*.coffee') + \ - glob.glob('atom/renderer/api/lib/*.coffee') + \ - glob.glob('atom/common/api/lib/*.coffee') + \ - glob.glob('atom/browser/atom/*.coffee') - - execute([coffeelint] + settings + files) - -if __name__ == '__main__': - sys.exit(main()) From ddfe4809e7be436008ffcf963f7dbd2d72973216 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 11 Jan 2016 16:44:11 -0800 Subject: [PATCH 46/95] Remove unused dependencies --- package.json | 2 -- 1 file changed, 2 deletions(-) diff --git a/package.json b/package.json index 546be7dd52b1..d082e861cd83 100644 --- a/package.json +++ b/package.json @@ -3,8 +3,6 @@ "version": "0.36.3", "devDependencies": { "asar": "^0.9.0", - "coffee-script": "^1.9.2", - "coffeelint": "^1.9.4", "request": "*" }, "optionalDependencies": { From 088a39ea9d837c2a4c74801cc655569da4f21293 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 11 Jan 2016 17:00:59 -0800 Subject: [PATCH 47/95] Convert gyp targets to use JavaScript --- atom.gyp | 24 +++--- filenames.gypi | 114 +++++++++++++-------------- tools/{coffee2asar.py => js2asar.py} | 15 ---- tools/{coffee2c.py => js2c.py} | 20 +---- 4 files changed, 70 insertions(+), 103 deletions(-) rename tools/{coffee2asar.py => js2asar.py} (60%) rename tools/{coffee2c.py => js2c.py} (50%) diff --git a/atom.gyp b/atom.gyp index ca2d6bf91a1f..1ea973681bfb 100644 --- a/atom.gyp +++ b/atom.gyp @@ -28,7 +28,7 @@ 'target_name': '<(project_name)', 'type': 'executable', 'dependencies': [ - 'compile_coffee', + 'js2asar', '<(project_name)_lib', ], 'sources': [ @@ -221,7 +221,7 @@ 'target_name': '<(project_name)_lib', 'type': 'static_library', 'dependencies': [ - 'atom_coffee2c', + 'atom_js2c', 'vendor/brightray/brightray.gyp:brightray', 'vendor/node/node.gyp:node', ], @@ -351,11 +351,11 @@ ], }, # target <(product_name)_lib { - 'target_name': 'compile_coffee', + 'target_name': 'js2asar', 'type': 'none', 'actions': [ { - 'action_name': 'compile_coffee', + 'action_name': 'js2asar', 'variables': { 'conditions': [ ['OS=="mac"', { @@ -366,41 +366,41 @@ ], }, 'inputs': [ - '<@(coffee_sources)', + '<@(js_sources)', ], 'outputs': [ '<(resources_path)/atom.asar', ], 'action': [ 'python', - 'tools/coffee2asar.py', + 'tools/js2asar.py', '<@(_outputs)', '<@(_inputs)', ], } ], - }, # target compile_coffee + }, # target js2asar { - 'target_name': 'atom_coffee2c', + 'target_name': 'atom_js2c', 'type': 'none', 'actions': [ { - 'action_name': 'atom_coffee2c', + 'action_name': 'atom_js2c', 'inputs': [ - '<@(coffee2c_sources)', + '<@(js2c_sources)', ], 'outputs': [ '<(SHARED_INTERMEDIATE_DIR)/atom_natives.h', ], 'action': [ 'python', - 'tools/coffee2c.py', + 'tools/js2c.py', '<@(_outputs)', '<@(_inputs)', ], } ], - }, # target atom_coffee2c + }, # target atom_js2c ], 'conditions': [ ['OS=="mac"', { diff --git a/filenames.gypi b/filenames.gypi index 61791604ecc5..61aa3d43d4aa 100644 --- a/filenames.gypi +++ b/filenames.gypi @@ -7,64 +7,64 @@ 'bundle_sources': [ 'atom/browser/resources/mac/atom.icns', ], - 'coffee_sources': [ - 'atom/browser/api/lib/app.coffee', - 'atom/browser/api/lib/auto-updater.coffee', - 'atom/browser/api/lib/auto-updater/auto-updater-native.coffee', - 'atom/browser/api/lib/auto-updater/auto-updater-win.coffee', - 'atom/browser/api/lib/auto-updater/squirrel-update-win.coffee', - 'atom/browser/api/lib/browser-window.coffee', - 'atom/browser/api/lib/content-tracing.coffee', - 'atom/browser/api/lib/dialog.coffee', - 'atom/browser/api/lib/exports/electron.coffee', - 'atom/browser/api/lib/global-shortcut.coffee', - 'atom/browser/api/lib/ipc.coffee', - 'atom/browser/api/lib/ipc-main.coffee', - 'atom/browser/api/lib/menu.coffee', - 'atom/browser/api/lib/menu-item.coffee', - 'atom/browser/api/lib/navigation-controller.coffee', - 'atom/browser/api/lib/power-monitor.coffee', - 'atom/browser/api/lib/power-save-blocker.coffee', - 'atom/browser/api/lib/protocol.coffee', - 'atom/browser/api/lib/session.coffee', - 'atom/browser/api/lib/screen.coffee', - 'atom/browser/api/lib/tray.coffee', - 'atom/browser/api/lib/web-contents.coffee', - 'atom/browser/lib/chrome-extension.coffee', - 'atom/browser/lib/desktop-capturer.coffee', - 'atom/browser/lib/guest-view-manager.coffee', - 'atom/browser/lib/guest-window-manager.coffee', - 'atom/browser/lib/init.coffee', - 'atom/browser/lib/objects-registry.coffee', - 'atom/browser/lib/rpc-server.coffee', - 'atom/common/api/lib/callbacks-registry.coffee', - 'atom/common/api/lib/clipboard.coffee', - 'atom/common/api/lib/crash-reporter.coffee', - 'atom/common/api/lib/deprecate.coffee', - 'atom/common/api/lib/exports/electron.coffee', - 'atom/common/api/lib/native-image.coffee', - 'atom/common/api/lib/shell.coffee', - 'atom/common/lib/init.coffee', - 'atom/common/lib/reset-search-paths.coffee', - 'atom/renderer/lib/chrome-api.coffee', - 'atom/renderer/lib/init.coffee', - 'atom/renderer/lib/inspector.coffee', - 'atom/renderer/lib/override.coffee', - 'atom/renderer/lib/web-view/guest-view-internal.coffee', - 'atom/renderer/lib/web-view/web-view.coffee', - 'atom/renderer/lib/web-view/web-view-attributes.coffee', - 'atom/renderer/lib/web-view/web-view-constants.coffee', - 'atom/renderer/api/lib/desktop-capturer.coffee', - 'atom/renderer/api/lib/exports/electron.coffee', - 'atom/renderer/api/lib/ipc.coffee', - 'atom/renderer/api/lib/ipc-renderer.coffee', - 'atom/renderer/api/lib/remote.coffee', - 'atom/renderer/api/lib/screen.coffee', - 'atom/renderer/api/lib/web-frame.coffee', + 'js_sources': [ + 'atom/browser/api/lib/app.js', + 'atom/browser/api/lib/auto-updater.js', + 'atom/browser/api/lib/auto-updater/auto-updater-native.js', + 'atom/browser/api/lib/auto-updater/auto-updater-win.js', + 'atom/browser/api/lib/auto-updater/squirrel-update-win.js', + 'atom/browser/api/lib/browser-window.js', + 'atom/browser/api/lib/content-tracing.js', + 'atom/browser/api/lib/dialog.js', + 'atom/browser/api/lib/exports/electron.js', + 'atom/browser/api/lib/global-shortcut.js', + 'atom/browser/api/lib/ipc.js', + 'atom/browser/api/lib/ipc-main.js', + 'atom/browser/api/lib/menu.js', + 'atom/browser/api/lib/menu-item.js', + 'atom/browser/api/lib/navigation-controller.js', + 'atom/browser/api/lib/power-monitor.js', + 'atom/browser/api/lib/power-save-blocker.js', + 'atom/browser/api/lib/protocol.js', + 'atom/browser/api/lib/session.js', + 'atom/browser/api/lib/screen.js', + 'atom/browser/api/lib/tray.js', + 'atom/browser/api/lib/web-contents.js', + 'atom/browser/lib/chrome-extension.js', + 'atom/browser/lib/desktop-capturer.js', + 'atom/browser/lib/guest-view-manager.js', + 'atom/browser/lib/guest-window-manager.js', + 'atom/browser/lib/init.js', + 'atom/browser/lib/objects-registry.js', + 'atom/browser/lib/rpc-server.js', + 'atom/common/api/lib/callbacks-registry.js', + 'atom/common/api/lib/clipboard.js', + 'atom/common/api/lib/crash-reporter.js', + 'atom/common/api/lib/deprecate.js', + 'atom/common/api/lib/exports/electron.js', + 'atom/common/api/lib/native-image.js', + 'atom/common/api/lib/shell.js', + 'atom/common/lib/init.js', + 'atom/common/lib/reset-search-paths.js', + 'atom/renderer/lib/chrome-api.js', + 'atom/renderer/lib/init.js', + 'atom/renderer/lib/inspector.js', + 'atom/renderer/lib/override.js', + 'atom/renderer/lib/web-view/guest-view-internal.js', + 'atom/renderer/lib/web-view/web-view.js', + 'atom/renderer/lib/web-view/web-view-attributes.js', + 'atom/renderer/lib/web-view/web-view-constants.js', + 'atom/renderer/api/lib/desktop-capturer.js', + 'atom/renderer/api/lib/exports/electron.js', + 'atom/renderer/api/lib/ipc.js', + 'atom/renderer/api/lib/ipc-renderer.js', + 'atom/renderer/api/lib/remote.js', + 'atom/renderer/api/lib/screen.js', + 'atom/renderer/api/lib/web-frame.js', ], - 'coffee2c_sources': [ - 'atom/common/lib/asar.coffee', - 'atom/common/lib/asar_init.coffee', + 'js2c_sources': [ + 'atom/common/lib/asar.js', + 'atom/common/lib/asar_init.js', ], 'lib_sources': [ 'atom/app/atom_content_client.cc', diff --git a/tools/coffee2asar.py b/tools/js2asar.py similarity index 60% rename from tools/coffee2asar.py rename to tools/js2asar.py index 9581715f0070..50291f12a1f7 100755 --- a/tools/coffee2asar.py +++ b/tools/js2asar.py @@ -12,27 +12,12 @@ SOURCE_ROOT = os.path.dirname(os.path.dirname(__file__)) def main(): archive = sys.argv[1] - coffee_source_files = sys.argv[2:] output_dir = tempfile.mkdtemp() - compile_coffee(coffee_source_files, output_dir) call_asar(archive, output_dir) shutil.rmtree(output_dir) -def compile_coffee(coffee_source_files, output_dir): - for source_file in coffee_source_files: - output_filename = os.path.splitext(source_file)[0] + '.js' - output_path = os.path.join(output_dir, output_filename) - call_compile_coffee(source_file, output_path) - - -def call_compile_coffee(source_file, output_filename): - compile_coffee = os.path.join(SOURCE_ROOT, 'tools', 'compile-coffee.py') - subprocess.check_call([sys.executable, compile_coffee, source_file, - output_filename]) - - def call_asar(archive, output_dir): js_dir = os.path.join(output_dir, 'atom') asar = os.path.join(SOURCE_ROOT, 'node_modules', 'asar', 'bin', 'asar') diff --git a/tools/coffee2c.py b/tools/js2c.py similarity index 50% rename from tools/coffee2c.py rename to tools/js2c.py index 1ca9a19334c6..394aa557e522 100755 --- a/tools/coffee2c.py +++ b/tools/js2c.py @@ -11,29 +11,11 @@ SOURCE_ROOT = os.path.abspath(os.path.dirname(os.path.dirname(__file__))) def main(): natives = os.path.abspath(sys.argv[1]) - coffee_source_files = sys.argv[2:] + js_source_files = sys.argv[2:] - output_dir = os.path.dirname(natives) - js_source_files = compile_coffee(coffee_source_files, output_dir) call_js2c(natives, js_source_files) -def compile_coffee(coffee_source_files, output_dir): - js_source_files = [] - for source_file in coffee_source_files: - output_filename = os.path.splitext(source_file)[0] + '.js' - output_path = os.path.join(output_dir, output_filename) - js_source_files.append(output_path) - call_compile_coffee(source_file, output_path) - return js_source_files - - -def call_compile_coffee(source_file, output_filename): - compile_coffee = os.path.join(SOURCE_ROOT, 'tools', 'compile-coffee.py') - subprocess.check_call([sys.executable, compile_coffee, source_file, - output_filename]) - - def call_js2c(natives, js_source_files): js2c = os.path.join(SOURCE_ROOT, 'vendor', 'node', 'tools', 'js2c.py') src_dir = os.path.dirname(js_source_files[0]) From dd902c61fa717490d3ef659811e204408268a9f0 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 11 Jan 2016 17:01:14 -0800 Subject: [PATCH 48/95] Expect .js specs --- spec/static/index.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/static/index.html b/spec/static/index.html index f958e1b7ed01..c909a88a8b79 100644 --- a/spec/static/index.html +++ b/spec/static/index.html @@ -64,7 +64,7 @@ }); walker.on('file', function(file) { - if (/-spec.coffee$/.test(file)) + if (/-spec\.js$/.test(file)) mocha.addFile(file); }); From 61af98cf947a0f6ab1586f87d91529ed0738e52f Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 11 Jan 2016 17:01:35 -0800 Subject: [PATCH 49/95] Remove CoffeeScript register in specs --- spec/static/index.html | 2 -- 1 file changed, 2 deletions(-) diff --git a/spec/static/index.html b/spec/static/index.html index c909a88a8b79..e31fcffebb89 100644 --- a/spec/static/index.html +++ b/spec/static/index.html @@ -31,8 +31,6 @@ remote.getCurrentWindow().inspectElement(e.clientX, e.clientY); } - require('coffee-script/register'); // Supports .coffee tests. - // Rediret all output to browser. if (isCi) { global.__defineGetter__('console', function() { From ed634416887a16bd4901983086014d67b7f775eb Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 11 Jan 2016 17:02:08 -0800 Subject: [PATCH 50/95] Remove coffee compile script --- tools/compile-coffee.py | 49 ----------------------------------------- 1 file changed, 49 deletions(-) delete mode 100755 tools/compile-coffee.py diff --git a/tools/compile-coffee.py b/tools/compile-coffee.py deleted file mode 100755 index d7423428f489..000000000000 --- a/tools/compile-coffee.py +++ /dev/null @@ -1,49 +0,0 @@ -#!/usr/bin/env python - -import os -import subprocess -import sys - - -SOURCE_ROOT = os.path.dirname(os.path.dirname(__file__)) -WINDOWS_NODE_PATHs = os.environ['PATH'].split(os.pathsep) + [ - 'C:/Program Files (x86)/nodejs', - 'C:/Program Files/nodejs', -] -NIX_NODE_PATHs = os.environ['PATH'].split(os.pathsep) + [ - '/usr/local/bin', - '/usr/bin', - '/bin', -] - -def main(): - input_file = sys.argv[1] - output_dir = os.path.dirname(sys.argv[2]) - - coffee = os.path.join(SOURCE_ROOT, 'node_modules', 'coffee-script', 'bin', - 'coffee') - - node = 'node' - if sys.platform in ['win32', 'cygwin']: - node = find_node(WINDOWS_NODE_PATHs, 'node.exe') - else: - node = find_node(NIX_NODE_PATHs, 'node') - - if not node: - print 'Node.js not found in PATH for building electron' - return 1 - - subprocess.check_call(['node', coffee, '-c', '-o', output_dir, input_file], - executable=node) - - -def find_node(paths, target): - for path in paths: - full_path = os.path.join(path, target) - if os.path.exists(full_path): - return full_path - return None - - -if __name__ == '__main__': - sys.exit(main()) From ab73f4c94aeb4d0f9b87e5776820a89e8217a5d1 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 11 Jan 2016 17:29:40 -0800 Subject: [PATCH 51/95] Copy JS files to tempdir before packing asar --- atom/browser/api/lib/auto-updater.js | 2 ++ tools/js2asar.py | 18 +++++++++++++++++- 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/atom/browser/api/lib/auto-updater.js b/atom/browser/api/lib/auto-updater.js index d666ba8eed6c..5a7d2472f612 100644 --- a/atom/browser/api/lib/auto-updater.js +++ b/atom/browser/api/lib/auto-updater.js @@ -9,4 +9,6 @@ autoUpdater = process.platform === 'win32' ? require('./auto-updater/auto-update deprecate.rename(autoUpdater, 'setFeedUrl', 'setFeedURL'); + + module.exports = autoUpdater; diff --git a/tools/js2asar.py b/tools/js2asar.py index 50291f12a1f7..9d501be69bc5 100755 --- a/tools/js2asar.py +++ b/tools/js2asar.py @@ -1,22 +1,30 @@ #!/usr/bin/env python +import errno import os import shutil import subprocess import sys import tempfile - SOURCE_ROOT = os.path.dirname(os.path.dirname(__file__)) def main(): archive = sys.argv[1] + js_source_files = sys.argv[2:] output_dir = tempfile.mkdtemp() + copy_js(js_source_files, output_dir) call_asar(archive, output_dir) shutil.rmtree(output_dir) +def copy_js(js_source_files, output_dir): + for source_file in js_source_files: + output_filename = os.path.splitext(source_file)[0] + '.js' + output_path = os.path.join(output_dir, output_filename) + safe_mkdir(os.path.dirname(output_path)) + shutil.copy2(source_file, output_path) def call_asar(archive, output_dir): js_dir = os.path.join(output_dir, 'atom') @@ -37,5 +45,13 @@ def find_node(): return full_path return 'node' +def safe_mkdir(path): + try: + os.makedirs(path) + except OSError as e: + if e.errno != errno.EEXIST: + raise + + if __name__ == '__main__': sys.exit(main()) From 78aff6a39fe2bdeac07db88cfc81253e5b067576 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 11 Jan 2016 17:30:10 -0800 Subject: [PATCH 52/95] :art: --- tools/js2asar.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tools/js2asar.py b/tools/js2asar.py index 9d501be69bc5..a17212419e1d 100755 --- a/tools/js2asar.py +++ b/tools/js2asar.py @@ -19,6 +19,7 @@ def main(): call_asar(archive, output_dir) shutil.rmtree(output_dir) + def copy_js(js_source_files, output_dir): for source_file in js_source_files: output_filename = os.path.splitext(source_file)[0] + '.js' @@ -26,6 +27,7 @@ def copy_js(js_source_files, output_dir): safe_mkdir(os.path.dirname(output_path)) shutil.copy2(source_file, output_path) + def call_asar(archive, output_dir): js_dir = os.path.join(output_dir, 'atom') asar = os.path.join(SOURCE_ROOT, 'node_modules', 'asar', 'bin', 'asar') @@ -45,6 +47,7 @@ def find_node(): return full_path return 'node' + def safe_mkdir(path): try: os.makedirs(path) From b547a38b3f4500432e38741dae1db4dc98f7dcb0 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 11 Jan 2016 17:39:11 -0800 Subject: [PATCH 53/95] Add wrapper functions to mirror old CoffeeScript --- atom/common/lib/asar.js | 2 ++ atom/common/lib/asar_init.js | 2 ++ 2 files changed, 4 insertions(+) diff --git a/atom/common/lib/asar.js b/atom/common/lib/asar.js index 60e4c5c69f8c..158d50da18be 100644 --- a/atom/common/lib/asar.js +++ b/atom/common/lib/asar.js @@ -1,3 +1,4 @@ +(function () { var asar, asarStatsToFsStats, cachedArchives, child_process, fakeTime, getOrCreateArchive, gid, invalidArchiveError, nextInode, notDirError, notFoundError, overrideAPI, overrideAPISync, path, splitPath, uid, util, hasProp = {}.hasOwnProperty; @@ -606,3 +607,4 @@ exports.wrapFsWithAsar = function(fs) { overrideAPISync(fs, 'openSync'); return overrideAPISync(child_process, 'execFileSync'); }; +})() diff --git a/atom/common/lib/asar_init.js b/atom/common/lib/asar_init.js index 51d438c2c001..0379865acf33 100644 --- a/atom/common/lib/asar_init.js +++ b/atom/common/lib/asar_init.js @@ -1,3 +1,4 @@ +(function () { return function(process, require, asarSource) { var createArchive, source; createArchive = process.binding('atom_common_asar').createArchive; @@ -13,3 +14,4 @@ return function(process, require, asarSource) { source['original-fs'] = source.fs; return source['fs'] = "var src = '(function (exports, require, module, __filename, __dirname) { ' +\n process.binding('natives')['original-fs'] +\n ' });';\nvar vm = require('vm');\nvar fn = vm.runInThisContext(src, { filename: 'fs.js' });\nfn(exports, require, module);\nvar asar = require('ATOM_SHELL_ASAR');\nasar.wrapFsWithAsar(exports);"; }; +})() From 5567baf33500b5cd7d4026553dc7b26dc1800146 Mon Sep 17 00:00:00 2001 From: Cheng Zhao Date: Wed, 13 Jan 2016 11:21:16 +0800 Subject: [PATCH 54/95] Add webFrame.insertText API --- atom/renderer/api/atom_api_web_frame.cc | 7 ++++++- atom/renderer/api/atom_api_web_frame.h | 3 +++ docs/api/web-frame.md | 6 ++++++ 3 files changed, 15 insertions(+), 1 deletion(-) diff --git a/atom/renderer/api/atom_api_web_frame.cc b/atom/renderer/api/atom_api_web_frame.cc index 83d67a8b6635..276f833c5a0c 100644 --- a/atom/renderer/api/atom_api_web_frame.cc +++ b/atom/renderer/api/atom_api_web_frame.cc @@ -116,6 +116,10 @@ void WebFrame::RegisterURLSchemeAsPrivileged(const std::string& scheme) { privileged_scheme); } +void WebFrame::InsertText(const std::string& text) { + web_frame_->insertText(blink::WebString::fromUTF8(text)); +} + mate::ObjectTemplateBuilder WebFrame::GetObjectTemplateBuilder( v8::Isolate* isolate) { return mate::ObjectTemplateBuilder(isolate) @@ -136,7 +140,8 @@ mate::ObjectTemplateBuilder WebFrame::GetObjectTemplateBuilder( .SetMethod("registerURLSchemeAsBypassingCSP", &WebFrame::RegisterURLSchemeAsBypassingCSP) .SetMethod("registerURLSchemeAsPrivileged", - &WebFrame::RegisterURLSchemeAsPrivileged); + &WebFrame::RegisterURLSchemeAsPrivileged) + .SetMethod("insertText", &WebFrame::InsertText); } // static diff --git a/atom/renderer/api/atom_api_web_frame.h b/atom/renderer/api/atom_api_web_frame.h index 95a5a82a313d..42175e12db35 100644 --- a/atom/renderer/api/atom_api_web_frame.h +++ b/atom/renderer/api/atom_api_web_frame.h @@ -60,6 +60,9 @@ class WebFrame : public mate::Wrappable { void RegisterURLSchemeAsBypassingCSP(const std::string& scheme); void RegisterURLSchemeAsPrivileged(const std::string& scheme); + // Editing. + void InsertText(const std::string& text); + // mate::Wrappable: virtual mate::ObjectTemplateBuilder GetObjectTemplateBuilder( v8::Isolate* isolate); diff --git a/docs/api/web-frame.md b/docs/api/web-frame.md index 114afd041cd0..6c4c9d864078 100644 --- a/docs/api/web-frame.md +++ b/docs/api/web-frame.md @@ -90,4 +90,10 @@ Content Security Policy. Registers the `scheme` as secure, bypasses content security policy for resources, allows registering ServiceWorker and supports fetch API. +### `webFrame.insertText(text)` + +* `text` String + +* Inserts `text` to the focused element. + [spellchecker]: https://github.com/atom/node-spellchecker From 8433d94cacfe251f6351deae893250cbbf4fea9e Mon Sep 17 00:00:00 2001 From: Robo Date: Tue, 12 Jan 2016 20:58:12 +0530 Subject: [PATCH 55/95] session: api to flush DOMStorage data --- atom/browser/api/atom_api_session.cc | 7 +++++++ atom/browser/api/atom_api_session.h | 1 + docs/api/session.md | 4 ++++ 3 files changed, 12 insertions(+) diff --git a/atom/browser/api/atom_api_session.cc b/atom/browser/api/atom_api_session.cc index f71b28c1cb70..f9e714880275 100644 --- a/atom/browser/api/atom_api_session.cc +++ b/atom/browser/api/atom_api_session.cc @@ -312,6 +312,12 @@ void Session::ClearStorageData(mate::Arguments* args) { base::Time(), base::Time::Max(), callback); } +void Session::FlushStorageData() { + auto storage_partition = + content::BrowserContext::GetStoragePartition(browser_context(), nullptr); + storage_partition->Flush(); +} + void Session::SetProxy(const net::ProxyConfig& config, const base::Closure& callback) { auto getter = browser_context_->GetRequestContext(); @@ -416,6 +422,7 @@ void Session::BuildPrototype(v8::Isolate* isolate, .SetMethod("resolveProxy", &Session::ResolveProxy) .SetMethod("clearCache", &Session::ClearCache) .SetMethod("clearStorageData", &Session::ClearStorageData) + .SetMethod("flushStorageData", &Session::FlushStorageData) .SetMethod("setProxy", &Session::SetProxy) .SetMethod("setDownloadPath", &Session::SetDownloadPath) .SetMethod("enableNetworkEmulation", &Session::EnableNetworkEmulation) diff --git a/atom/browser/api/atom_api_session.h b/atom/browser/api/atom_api_session.h index 0034b1480632..c631670831e0 100644 --- a/atom/browser/api/atom_api_session.h +++ b/atom/browser/api/atom_api_session.h @@ -64,6 +64,7 @@ class Session: public mate::TrackableObject, void ResolveProxy(const GURL& url, ResolveProxyCallback callback); void ClearCache(const net::CompletionCallback& callback); void ClearStorageData(mate::Arguments* args); + void FlushStorageData(); void SetProxy(const net::ProxyConfig& config, const base::Closure& callback); void SetDownloadPath(const base::FilePath& path); void EnableNetworkEmulation(const mate::Dictionary& options); diff --git a/docs/api/session.md b/docs/api/session.md index a8a55b593f27..9dd2bca0ed7b 100644 --- a/docs/api/session.md +++ b/docs/api/session.md @@ -179,6 +179,10 @@ Clears the session’s HTTP cache. Clears the data of web storages. +#### `ses.flushStorageData()` + +Writes any unwritten DOMStorage data to disk. + #### `ses.setProxy(config, callback)` * `config` Object From 5b7d1a9890d386f32713eda8646a896905c4790d Mon Sep 17 00:00:00 2001 From: Cheng Zhao Date: Wed, 13 Jan 2016 11:55:49 +0800 Subject: [PATCH 56/95] Add insertText to WebContents --- atom/browser/api/lib/web-contents.js | 15 +++++++++++++++ atom/renderer/lib/init.js | 9 +++++++++ atom/renderer/lib/web-view/web-view.js | 8 +++++++- docs/api/web-contents.md | 6 ++++++ docs/api/web-frame.md | 2 +- docs/api/web-view-tag.md | 6 ++++++ 6 files changed, 44 insertions(+), 2 deletions(-) diff --git a/atom/browser/api/lib/web-contents.js b/atom/browser/api/lib/web-contents.js index 0d1b8b24bdd0..d0abae7e65c4 100644 --- a/atom/browser/api/lib/web-contents.js +++ b/atom/browser/api/lib/web-contents.js @@ -1,3 +1,5 @@ +'use strict'; + var EventEmitter, Menu, NavigationController, PDFPageSize, binding, deprecate, getNextId, ipcMain, nextId, ref, session, wrapWebContents, slice = [].slice; @@ -53,6 +55,11 @@ PDFPageSize = { } }; +// Following methods are mapped to webFrame. +const webFrameMethods = [ + 'insertText', +]; + wrapWebContents = function(webContents) { /* webContents is an EventEmitter. */ @@ -95,6 +102,14 @@ wrapWebContents = function(webContents) { } } + // Mapping webFrame methods. + for (let method of webFrameMethods) { + webContents[method] = function() { + let args = Array.prototype.slice.call(arguments); + this.send('ELECTRON_INTERNAL_RENDERER_WEB_FRAME_METHOD', method, args); + }; + } + /* Dispatch IPC messages to the ipc module. */ webContents.on('ipc-message', function(event, packed) { var args, channel; diff --git a/atom/renderer/lib/init.js b/atom/renderer/lib/init.js index 3d3026b595ef..344c7f2b1d26 100644 --- a/atom/renderer/lib/init.js +++ b/atom/renderer/lib/init.js @@ -1,3 +1,5 @@ +'user strict'; + var Module, arg, error, error1, events, globalPaths, i, len, nodeIntegration, path, pathname, preloadScript, ref, url, v8Util; events = require('events'); @@ -44,6 +46,13 @@ v8Util = process.atomBinding('v8_util'); v8Util.setHiddenValue(global, 'ipc', new events.EventEmitter); +// Use electron module after everything is ready. +const electron = require('electron'); + +// Call webFrame method. +electron.ipcRenderer.on('ELECTRON_INTERNAL_RENDERER_WEB_FRAME_METHOD', (event, method, args) => { + electron.webFrame[method].apply(electron.webFrame, args); +}); /* Process command line arguments. */ diff --git a/atom/renderer/lib/web-view/web-view.js b/atom/renderer/lib/web-view/web-view.js index fcdfad1877ed..7f3c000dd7f0 100644 --- a/atom/renderer/lib/web-view/web-view.js +++ b/atom/renderer/lib/web-view/web-view.js @@ -376,7 +376,13 @@ registerWebViewElement = function() { /* Public-facing API methods. */ methods = ['getURL', 'getTitle', 'isLoading', 'isWaitingForResponse', 'stop', 'reload', 'reloadIgnoringCache', 'canGoBack', 'canGoForward', 'canGoToOffset', 'clearHistory', 'goBack', 'goForward', 'goToIndex', 'goToOffset', 'isCrashed', 'setUserAgent', 'getUserAgent', 'openDevTools', 'closeDevTools', 'isDevToolsOpened', 'isDevToolsFocused', 'inspectElement', 'setAudioMuted', 'isAudioMuted', 'undo', 'redo', 'cut', 'copy', 'paste', 'pasteAndMatchStyle', 'delete', 'selectAll', 'unselect', 'replace', 'replaceMisspelling', 'findInPage', 'stopFindInPage', 'getId', 'downloadURL', 'inspectServiceWorker', 'print', 'printToPDF']; - nonblockMethods = ['send', 'sendInputEvent', 'executeJavaScript', 'insertCSS']; + nonblockMethods = [ + 'executeJavaScript', + 'insertCSS', + 'insertText', + 'send', + 'sendInputEvent', + ]; /* Forward proto.foo* method calls to WebViewImpl.foo*. */ createBlockHandler = function(m) { diff --git a/docs/api/web-contents.md b/docs/api/web-contents.md index b399e143aacc..48658a294595 100644 --- a/docs/api/web-contents.md +++ b/docs/api/web-contents.md @@ -472,6 +472,12 @@ Executes the editing command `replace` in web page. Executes the editing command `replaceMisspelling` in web page. +### `webContents.insertText(text)` + +* `text` String + +Inserts `text` to the focused element. + ### `webContents.findInPage(text[, options])` * `text` String - Content to be searched, must not be empty. diff --git a/docs/api/web-frame.md b/docs/api/web-frame.md index 6c4c9d864078..e5dfa0b4eb95 100644 --- a/docs/api/web-frame.md +++ b/docs/api/web-frame.md @@ -94,6 +94,6 @@ allows registering ServiceWorker and supports fetch API. * `text` String -* Inserts `text` to the focused element. +Inserts `text` to the focused element. [spellchecker]: https://github.com/atom/node-spellchecker diff --git a/docs/api/web-view-tag.md b/docs/api/web-view-tag.md index 8b8f5ffd49ad..b3d94b85f715 100644 --- a/docs/api/web-view-tag.md +++ b/docs/api/web-view-tag.md @@ -352,6 +352,12 @@ Executes editing command `replace` in page. Executes editing command `replaceMisspelling` in page. +### `.insertText(text)` + +* `text` String + +Inserts `text` to the focused element. + ### `.findInPage(text[, options])` * `text` String - Content to be searched, must not be empty. From 55dfddba774963fde915cbf427d4ee577b1adf61 Mon Sep 17 00:00:00 2001 From: Cheng Zhao Date: Wed, 13 Jan 2016 12:11:46 +0800 Subject: [PATCH 57/95] Handle executeJavaScript in JavaScript --- atom/browser/api/atom_api_web_contents.cc | 6 ----- atom/browser/api/atom_api_web_contents.h | 2 -- atom/browser/api/lib/web-contents.js | 30 +++++++++++----------- atom/common/api/api_messages.h | 4 --- atom/renderer/api/atom_api_web_frame.cc | 11 +++++++- atom/renderer/api/atom_api_web_frame.h | 3 +++ atom/renderer/atom_render_view_observer.cc | 22 ---------------- atom/renderer/atom_render_view_observer.h | 2 -- 8 files changed, 28 insertions(+), 52 deletions(-) diff --git a/atom/browser/api/atom_api_web_contents.cc b/atom/browser/api/atom_api_web_contents.cc index 4d449ed9c39b..614148f5067e 100644 --- a/atom/browser/api/atom_api_web_contents.cc +++ b/atom/browser/api/atom_api_web_contents.cc @@ -756,11 +756,6 @@ bool WebContents::SavePage(const base::FilePath& full_file_path, return handler->Handle(full_file_path, save_type); } -void WebContents::ExecuteJavaScript(const base::string16& code, - bool has_user_gesture) { - Send(new AtomViewMsg_ExecuteJavaScript(routing_id(), code, has_user_gesture)); -} - void WebContents::OpenDevTools(mate::Arguments* args) { if (type_ == REMOTE) return; @@ -1093,7 +1088,6 @@ void WebContents::BuildPrototype(v8::Isolate* isolate, .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) diff --git a/atom/browser/api/atom_api_web_contents.h b/atom/browser/api/atom_api_web_contents.h index bd7149e38a93..59e16dcab85f 100644 --- a/atom/browser/api/atom_api_web_contents.h +++ b/atom/browser/api/atom_api_web_contents.h @@ -74,8 +74,6 @@ class WebContents : public mate::TrackableObject, bool SavePage(const base::FilePath& full_file_path, const content::SavePageType& save_type, const SavePageHandler::SavePageCallback& callback); - void ExecuteJavaScript(const base::string16& code, - bool has_user_gesture); void OpenDevTools(mate::Arguments* args); void CloseDevTools(); bool IsDevToolsOpened(); diff --git a/atom/browser/api/lib/web-contents.js b/atom/browser/api/lib/web-contents.js index d0abae7e65c4..4055901a3f18 100644 --- a/atom/browser/api/lib/web-contents.js +++ b/atom/browser/api/lib/web-contents.js @@ -57,6 +57,7 @@ PDFPageSize = { // Following methods are mapped to webFrame. const webFrameMethods = [ + 'executeJavaScript', 'insertText', ]; @@ -73,21 +74,6 @@ wrapWebContents = function(webContents) { return this._send(channel, slice.call(args)); }; - /* - Make sure webContents.executeJavaScript would run the code only when the - web contents has been loaded. - */ - webContents.executeJavaScript = function(code, hasUserGesture) { - if (hasUserGesture == null) { - hasUserGesture = false; - } - if (this.getURL() && !this.isLoading()) { - return this._executeJavaScript(code, hasUserGesture); - } else { - return webContents.once('did-finish-load', this._executeJavaScript.bind(this, code, hasUserGesture)); - } - }; - /* The navigation controller. */ controller = new NavigationController(webContents); ref1 = NavigationController.prototype; @@ -110,6 +96,20 @@ wrapWebContents = function(webContents) { }; } + // Make sure webContents.executeJavaScript would run the code only when the + // webContents has been loaded. + const executeJavaScript = webContents.executeJavaScript; + webContents.executeJavaScript = function(code, hasUserGesture) { + // TODO(zcbenz): Use default parameter after Chrome 49. + if (hasUserGesture === undefined) + hasUserGesture = false; + + if (this.getURL() && !this.isLoading()) + return executeJavaScript.call(this, code, hasUserGesture); + else + return this.once('did-finish-load', executeJavaScript.bind(this, code, hasUserGesture)); + }; + /* Dispatch IPC messages to the ipc module. */ webContents.on('ipc-message', function(event, packed) { var args, channel; diff --git a/atom/common/api/api_messages.h b/atom/common/api/api_messages.h index 274e1f533eb3..2c9bb3b2f3e4 100644 --- a/atom/common/api/api_messages.h +++ b/atom/common/api/api_messages.h @@ -40,10 +40,6 @@ IPC_MESSAGE_ROUTED2(AtomViewMsg_Message, base::string16 /* channel */, base::ListValue /* arguments */) -IPC_MESSAGE_ROUTED2(AtomViewMsg_ExecuteJavaScript, - base::string16 /* code */, - bool /* has user gesture */) - // Sent by the renderer when the draggable regions are updated. IPC_MESSAGE_ROUTED1(AtomViewHostMsg_UpdateDraggableRegions, std::vector /* regions */) diff --git a/atom/renderer/api/atom_api_web_frame.cc b/atom/renderer/api/atom_api_web_frame.cc index 276f833c5a0c..fe11253bb56b 100644 --- a/atom/renderer/api/atom_api_web_frame.cc +++ b/atom/renderer/api/atom_api_web_frame.cc @@ -15,6 +15,8 @@ #include "native_mate/object_template_builder.h" #include "third_party/WebKit/public/web/WebDocument.h" #include "third_party/WebKit/public/web/WebLocalFrame.h" +#include "third_party/WebKit/public/web/WebScopedUserGesture.h" +#include "third_party/WebKit/public/web/WebScriptSource.h" #include "third_party/WebKit/public/web/WebSecurityPolicy.h" #include "third_party/WebKit/public/web/WebView.h" @@ -120,6 +122,12 @@ void WebFrame::InsertText(const std::string& text) { web_frame_->insertText(blink::WebString::fromUTF8(text)); } +void WebFrame::ExecuteJavaScript(const base::string16& code, bool by_user) { + scoped_ptr gesture( + by_user ? new blink::WebScopedUserGesture : nullptr); + web_frame_->executeScriptAndReturnValue(blink::WebScriptSource(code)); +} + mate::ObjectTemplateBuilder WebFrame::GetObjectTemplateBuilder( v8::Isolate* isolate) { return mate::ObjectTemplateBuilder(isolate) @@ -141,7 +149,8 @@ mate::ObjectTemplateBuilder WebFrame::GetObjectTemplateBuilder( &WebFrame::RegisterURLSchemeAsBypassingCSP) .SetMethod("registerURLSchemeAsPrivileged", &WebFrame::RegisterURLSchemeAsPrivileged) - .SetMethod("insertText", &WebFrame::InsertText); + .SetMethod("insertText", &WebFrame::InsertText) + .SetMethod("executeJavaScript", &WebFrame::ExecuteJavaScript); } // static diff --git a/atom/renderer/api/atom_api_web_frame.h b/atom/renderer/api/atom_api_web_frame.h index 42175e12db35..632f6a517392 100644 --- a/atom/renderer/api/atom_api_web_frame.h +++ b/atom/renderer/api/atom_api_web_frame.h @@ -63,6 +63,9 @@ class WebFrame : public mate::Wrappable { // Editing. void InsertText(const std::string& text); + // Excecuting scripts. + void ExecuteJavaScript(const base::string16& code, bool by_user); + // mate::Wrappable: virtual mate::ObjectTemplateBuilder GetObjectTemplateBuilder( v8::Isolate* isolate); diff --git a/atom/renderer/atom_render_view_observer.cc b/atom/renderer/atom_render_view_observer.cc index bf2e1a70b788..cdbdb3d7c3ce 100644 --- a/atom/renderer/atom_render_view_observer.cc +++ b/atom/renderer/atom_render_view_observer.cc @@ -27,8 +27,6 @@ #include "third_party/WebKit/public/web/WebFrame.h" #include "third_party/WebKit/public/web/WebLocalFrame.h" #include "third_party/WebKit/public/web/WebKit.h" -#include "third_party/WebKit/public/web/WebScopedUserGesture.h" -#include "third_party/WebKit/public/web/WebScriptSource.h" #include "third_party/WebKit/public/web/WebView.h" #include "ui/base/resource/resource_bundle.h" #include "native_mate/dictionary.h" @@ -115,8 +113,6 @@ bool AtomRenderViewObserver::OnMessageReceived(const IPC::Message& message) { bool handled = true; IPC_BEGIN_MESSAGE_MAP(AtomRenderViewObserver, message) IPC_MESSAGE_HANDLER(AtomViewMsg_Message, OnBrowserMessage) - IPC_MESSAGE_HANDLER(AtomViewMsg_ExecuteJavaScript, - OnJavaScriptExecuteRequest) IPC_MESSAGE_UNHANDLED(handled = false) IPC_END_MESSAGE_MAP() @@ -152,22 +148,4 @@ void AtomRenderViewObserver::OnBrowserMessage(const base::string16& channel, } } -void AtomRenderViewObserver::OnJavaScriptExecuteRequest( - const base::string16& code, bool has_user_gesture) { - if (!document_created_) - return; - - if (!render_view()->GetWebView()) - return; - - scoped_ptr gesture( - has_user_gesture ? new blink::WebScopedUserGesture : nullptr); - - v8::Isolate* isolate = blink::mainThreadIsolate(); - v8::HandleScope handle_scope(isolate); - - blink::WebFrame* frame = render_view()->GetWebView()->mainFrame(); - frame->executeScriptAndReturnValue(blink::WebScriptSource(code)); -} - } // namespace atom diff --git a/atom/renderer/atom_render_view_observer.h b/atom/renderer/atom_render_view_observer.h index 85a8c159d97e..4b9d59f3fa08 100644 --- a/atom/renderer/atom_render_view_observer.h +++ b/atom/renderer/atom_render_view_observer.h @@ -32,8 +32,6 @@ class AtomRenderViewObserver : public content::RenderViewObserver { void OnBrowserMessage(const base::string16& channel, const base::ListValue& args); - void OnJavaScriptExecuteRequest(const base::string16& code, - bool has_user_gesture); // Weak reference to renderer client. AtomRendererClient* renderer_client_; From 350c572a8c8b6f035d3cb583dc01fe159137ca63 Mon Sep 17 00:00:00 2001 From: Cheng Zhao Date: Wed, 13 Jan 2016 12:17:56 +0800 Subject: [PATCH 58/95] Handle default parameter of executeJavaScript in C++ --- atom/browser/api/lib/web-contents.js | 4 ---- atom/renderer/api/atom_api_web_frame.cc | 7 +++++-- atom/renderer/api/atom_api_web_frame.h | 2 +- 3 files changed, 6 insertions(+), 7 deletions(-) diff --git a/atom/browser/api/lib/web-contents.js b/atom/browser/api/lib/web-contents.js index 4055901a3f18..a670850f5372 100644 --- a/atom/browser/api/lib/web-contents.js +++ b/atom/browser/api/lib/web-contents.js @@ -100,10 +100,6 @@ wrapWebContents = function(webContents) { // webContents has been loaded. const executeJavaScript = webContents.executeJavaScript; webContents.executeJavaScript = function(code, hasUserGesture) { - // TODO(zcbenz): Use default parameter after Chrome 49. - if (hasUserGesture === undefined) - hasUserGesture = false; - if (this.getURL() && !this.isLoading()) return executeJavaScript.call(this, code, hasUserGesture); else diff --git a/atom/renderer/api/atom_api_web_frame.cc b/atom/renderer/api/atom_api_web_frame.cc index fe11253bb56b..ca4732ff3651 100644 --- a/atom/renderer/api/atom_api_web_frame.cc +++ b/atom/renderer/api/atom_api_web_frame.cc @@ -122,9 +122,12 @@ void WebFrame::InsertText(const std::string& text) { web_frame_->insertText(blink::WebString::fromUTF8(text)); } -void WebFrame::ExecuteJavaScript(const base::string16& code, bool by_user) { +void WebFrame::ExecuteJavaScript(const base::string16& code, + mate::Arguments* args) { + bool has_user_gesture = false; + args->GetNext(&has_user_gesture); scoped_ptr gesture( - by_user ? new blink::WebScopedUserGesture : nullptr); + has_user_gesture ? new blink::WebScopedUserGesture : nullptr); web_frame_->executeScriptAndReturnValue(blink::WebScriptSource(code)); } diff --git a/atom/renderer/api/atom_api_web_frame.h b/atom/renderer/api/atom_api_web_frame.h index 632f6a517392..d55b24fd25ea 100644 --- a/atom/renderer/api/atom_api_web_frame.h +++ b/atom/renderer/api/atom_api_web_frame.h @@ -64,7 +64,7 @@ class WebFrame : public mate::Wrappable { void InsertText(const std::string& text); // Excecuting scripts. - void ExecuteJavaScript(const base::string16& code, bool by_user); + void ExecuteJavaScript(const base::string16& code, mate::Arguments* args); // mate::Wrappable: virtual mate::ObjectTemplateBuilder GetObjectTemplateBuilder( From 118924ba7a6b1fd41b8fc84909d090691260dd44 Mon Sep 17 00:00:00 2001 From: Cheng Zhao Date: Wed, 13 Jan 2016 12:20:49 +0800 Subject: [PATCH 59/95] docs: webFrame.executeJavaScript --- docs/api/web-frame.md | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/docs/api/web-frame.md b/docs/api/web-frame.md index e5dfa0b4eb95..d9e02ac097e7 100644 --- a/docs/api/web-frame.md +++ b/docs/api/web-frame.md @@ -96,4 +96,15 @@ allows registering ServiceWorker and supports fetch API. Inserts `text` to the focused element. +### `webFrame.executeJavaScript(code[, userGesture])` + +* `code` String +* `userGesture` Boolean (optional) - Default is `false`. + +Evaluates `code` in page. + +In the browser window some HTML APIs like `requestFullScreen` can only be +invoked by a gesture from the user. Setting `userGesture` to `true` will remove +this limitation. + [spellchecker]: https://github.com/atom/node-spellchecker From af02739c4e1aea0a115e1bb0c3610d71c0ddf5ab Mon Sep 17 00:00:00 2001 From: Cheng Zhao Date: Wed, 13 Jan 2016 12:46:13 +0800 Subject: [PATCH 60/95] Change webview's zoom level on JavaScript side --- atom/browser/api/atom_api_web_contents.cc | 20 -------------------- atom/browser/api/atom_api_web_contents.h | 4 ---- atom/browser/api/lib/web-contents.js | 3 +++ atom/common/api/api_messages.h | 6 ------ atom/renderer/api/atom_api_web_frame.cc | 10 ++++------ atom/renderer/api/lib/web-frame.js | 15 +++++++++------ atom/renderer/atom_renderer_client.cc | 16 ---------------- atom/renderer/lib/web-view/web-view.js | 10 ++++++++++ 8 files changed, 26 insertions(+), 58 deletions(-) diff --git a/atom/browser/api/atom_api_web_contents.cc b/atom/browser/api/atom_api_web_contents.cc index 614148f5067e..c4de932d37cc 100644 --- a/atom/browser/api/atom_api_web_contents.cc +++ b/atom/browser/api/atom_api_web_contents.cc @@ -33,7 +33,6 @@ #include "chrome/browser/printing/print_view_manager_basic.h" #include "chrome/browser/printing/print_preview_message_handler.h" #include "content/common/view_messages.h" -#include "content/public/browser/browser_plugin_guest_manager.h" #include "content/public/browser/favicon_status.h" #include "content/public/browser/native_web_keyboard_event.h" #include "content/public/browser/navigation_details.h" @@ -75,15 +74,6 @@ void SetUserAgentInIO(scoped_refptr getter, user_agent)); } -bool NotifyZoomLevelChanged( - double level, content::WebContents* guest_web_contents) { - guest_web_contents->SendToAllFrames( - new AtomViewMsg_SetZoomLevel(MSG_ROUTING_NONE, level)); - - // Return false to iterate over all guests. - return false; -} - } // namespace namespace mate { @@ -625,7 +615,6 @@ bool WebContents::OnMessageReceived(const IPC::Message& message) { IPC_MESSAGE_HANDLER(AtomViewHostMsg_Message, OnRendererMessage) IPC_MESSAGE_HANDLER_DELAY_REPLY(AtomViewHostMsg_Message_Sync, OnRendererMessageSync) - IPC_MESSAGE_HANDLER(AtomViewHostMsg_ZoomLevelChanged, OnZoomLevelChanged) IPC_MESSAGE_UNHANDLED(handled = false) IPC_END_MESSAGE_MAP() @@ -1154,15 +1143,6 @@ void WebContents::OnRendererMessageSync(const base::string16& channel, EmitWithSender(base::UTF16ToUTF8(channel), web_contents(), message, args); } -void WebContents::OnZoomLevelChanged(double level) { - auto manager = web_contents()->GetBrowserContext()->GetGuestManager(); - if (!manager) - return; - manager->ForEachGuest(web_contents(), - base::Bind(&NotifyZoomLevelChanged, - level)); -} - // static mate::Handle WebContents::CreateFrom( v8::Isolate* isolate, content::WebContents* web_contents) { diff --git a/atom/browser/api/atom_api_web_contents.h b/atom/browser/api/atom_api_web_contents.h index 59e16dcab85f..bcef57b9a4aa 100644 --- a/atom/browser/api/atom_api_web_contents.h +++ b/atom/browser/api/atom_api_web_contents.h @@ -263,10 +263,6 @@ class WebContents : public mate::TrackableObject, const base::ListValue& args, IPC::Message* message); - // Called when guests need to be notified of - // embedders' zoom level change. - void OnZoomLevelChanged(double level); - v8::Global session_; v8::Global devtools_web_contents_; diff --git a/atom/browser/api/lib/web-contents.js b/atom/browser/api/lib/web-contents.js index a670850f5372..f502076755f0 100644 --- a/atom/browser/api/lib/web-contents.js +++ b/atom/browser/api/lib/web-contents.js @@ -59,6 +59,9 @@ PDFPageSize = { const webFrameMethods = [ 'executeJavaScript', 'insertText', + 'setZoomFactor', + 'setZoomLevel', + 'setZoomLevelLimits', ]; wrapWebContents = function(webContents) { diff --git a/atom/common/api/api_messages.h b/atom/common/api/api_messages.h index 2c9bb3b2f3e4..eeb26614847b 100644 --- a/atom/common/api/api_messages.h +++ b/atom/common/api/api_messages.h @@ -30,12 +30,6 @@ IPC_SYNC_MESSAGE_ROUTED2_1(AtomViewHostMsg_Message_Sync, base::ListValue /* arguments */, base::string16 /* result (in JSON) */) -IPC_MESSAGE_ROUTED1(AtomViewHostMsg_ZoomLevelChanged, - double /* level */) - -IPC_MESSAGE_ROUTED1(AtomViewMsg_SetZoomLevel, - double /* level */) - IPC_MESSAGE_ROUTED2(AtomViewMsg_Message, base::string16 /* channel */, base::ListValue /* arguments */) diff --git a/atom/renderer/api/atom_api_web_frame.cc b/atom/renderer/api/atom_api_web_frame.cc index ca4732ff3651..c72882886b91 100644 --- a/atom/renderer/api/atom_api_web_frame.cc +++ b/atom/renderer/api/atom_api_web_frame.cc @@ -4,7 +4,7 @@ #include "atom/renderer/api/atom_api_web_frame.h" -#include "atom/common/api/api_messages.h" +#include "atom/common/api/event_emitter_caller.h" #include "atom/common/native_mate_converters/callback.h" #include "atom/common/native_mate_converters/gfx_converter.h" #include "atom/common/native_mate_converters/string16_converter.h" @@ -38,11 +38,9 @@ void WebFrame::SetName(const std::string& name) { } double WebFrame::SetZoomLevel(double level) { - auto render_view = content::RenderView::FromWebView(web_frame_->view()); - // Notify guests if any for zoom level change. - render_view->Send( - new AtomViewHostMsg_ZoomLevelChanged(MSG_ROUTING_NONE, level)); - return web_frame_->view()->setZoomLevel(level); + double ret = web_frame_->view()->setZoomLevel(level); + mate::EmitEvent(isolate(), GetWrapper(isolate()), "zoom-level-changed", ret); + return ret; } double WebFrame::GetZoomLevel() const { diff --git a/atom/renderer/api/lib/web-frame.js b/atom/renderer/api/lib/web-frame.js index 90d1c5a87bd2..8ae35d7b8ac6 100644 --- a/atom/renderer/api/lib/web-frame.js +++ b/atom/renderer/api/lib/web-frame.js @@ -1,16 +1,19 @@ -var deprecate, webFrame; +'use strict'; -deprecate = require('electron').deprecate; +const deprecate = require('electron').deprecate; +const EventEmitter = require('events').EventEmitter; -webFrame = process.atomBinding('web_frame').webFrame; +const webFrame = process.atomBinding('web_frame').webFrame; +// webFrame is an EventEmitter. +webFrame.__proto__ = EventEmitter.prototype; -/* Deprecated. */ +// Lots of webview would subscribe to webFrame's events. +webFrame.setMaxListeners(0); +// Deprecated. deprecate.rename(webFrame, 'registerUrlSchemeAsSecure', 'registerURLSchemeAsSecure'); - deprecate.rename(webFrame, 'registerUrlSchemeAsBypassingCSP', 'registerURLSchemeAsBypassingCSP'); - deprecate.rename(webFrame, 'registerUrlSchemeAsPrivileged', 'registerURLSchemeAsPrivileged'); module.exports = webFrame; diff --git a/atom/renderer/atom_renderer_client.cc b/atom/renderer/atom_renderer_client.cc index d9c364c3733f..15165efa330a 100644 --- a/atom/renderer/atom_renderer_client.cc +++ b/atom/renderer/atom_renderer_client.cc @@ -57,22 +57,6 @@ class AtomRenderFrameObserver : public content::RenderFrameObserver { render_frame()->GetWebFrame(), context); } - bool OnMessageReceived(const IPC::Message& message) { - bool handled = true; - IPC_BEGIN_MESSAGE_MAP(AtomRenderFrameObserver, message) - IPC_MESSAGE_HANDLER(AtomViewMsg_SetZoomLevel, OnSetZoomLevel) - IPC_MESSAGE_UNHANDLED(handled = false) - IPC_END_MESSAGE_MAP() - - return handled; - } - - void OnSetZoomLevel(double level) { - auto view = render_frame()->GetWebFrame()->view(); - if (view) - view->setZoomLevel(level); - } - private: AtomRendererClient* renderer_client_; diff --git a/atom/renderer/lib/web-view/web-view.js b/atom/renderer/lib/web-view/web-view.js index 7f3c000dd7f0..458e79a84224 100644 --- a/atom/renderer/lib/web-view/web-view.js +++ b/atom/renderer/lib/web-view/web-view.js @@ -1,3 +1,5 @@ +'user strict'; + var WebViewImpl, deprecate, getNextId, guestViewInternal, ipcRenderer, listener, nextId, ref, registerBrowserPluginElement, registerWebViewElement, remote, useCapture, v8Util, webFrame, webViewConstants, hasProp = {}.hasOwnProperty, slice = [].slice; @@ -39,6 +41,11 @@ WebViewImpl = (function() { this.setupFocusPropagation(); this.viewInstanceId = getNextId(); shadowRoot.appendChild(this.browserPluginNode); + + // Subscribe to host's zoom level changes. + webFrame.on('zoom-level-changed', (zoomLevel) => { + this.webviewNode.setZoomLevel(zoomLevel); + }); } WebViewImpl.prototype.createBrowserPluginNode = function() { @@ -382,6 +389,9 @@ registerWebViewElement = function() { 'insertText', 'send', 'sendInputEvent', + 'setZoomFactor', + 'setZoomLevel', + 'setZoomLevelLimits', ]; /* Forward proto.foo* method calls to WebViewImpl.foo*. */ From 44b8343585ff321bd6f5d88ac82ba55d5d40736d Mon Sep 17 00:00:00 2001 From: Cheng Zhao Date: Wed, 13 Jan 2016 14:47:39 +0800 Subject: [PATCH 61/95] Fix crash when closing page with webview --- atom/browser/api/atom_api_web_contents.cc | 20 ++++++++++++-------- atom/browser/lib/guest-view-manager.js | 2 +- 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/atom/browser/api/atom_api_web_contents.cc b/atom/browser/api/atom_api_web_contents.cc index c4de932d37cc..77e445efae35 100644 --- a/atom/browser/api/atom_api_web_contents.cc +++ b/atom/browser/api/atom_api_web_contents.cc @@ -280,15 +280,11 @@ WebContents::WebContents(v8::Isolate* isolate, } WebContents::~WebContents() { - if (type_ == WEB_VIEW && managed_web_contents()) { - // When force destroying the "destroyed" event is not emitted. + // The webview's lifetime is completely controlled by GuestViewManager, so + // it is always destroyed by calling webview.destroy(), we need to make + // sure the "destroyed" event is emitted manually. + if (type_ == WEB_VIEW && managed_web_contents()) WebContentsDestroyed(); - - guest_delegate_->Destroy(); - - Observe(nullptr); - DestroyWebContents(); - } } bool WebContents::AddMessageToConsole(content::WebContents* source, @@ -624,7 +620,15 @@ bool WebContents::OnMessageReceived(const IPC::Message& message) { void WebContents::WebContentsDestroyed() { // The RenderViewDeleted was not called when the WebContents is destroyed. RenderViewDeleted(web_contents()->GetRenderViewHost()); + + // This event is only for internal use, which is emitted when WebContents is + // being destroyed. + Emit("will-destroy"); + + // Cleanup relationships with other parts. RemoveFromWeakMap(); + if (type_ == WEB_VIEW) + guest_delegate_->Destroy(); // 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. diff --git a/atom/browser/lib/guest-view-manager.js b/atom/browser/lib/guest-view-manager.js index a1d82483a954..83f1f6ac2e18 100644 --- a/atom/browser/lib/guest-view-manager.js +++ b/atom/browser/lib/guest-view-manager.js @@ -52,7 +52,7 @@ createGuest = function(embedder, params) { }; /* Destroy guest when the embedder is gone or navigated. */ - destroyEvents = ['destroyed', 'crashed', 'did-navigate']; + destroyEvents = ['will-destroy', 'crashed', 'did-navigate']; destroy = function() { if (guestInstances[id] != null) { return destroyGuest(embedder, id); From 8ae836d82da74a20c53c0749d90da3556a20ee65 Mon Sep 17 00:00:00 2001 From: Cheng Zhao Date: Wed, 13 Jan 2016 14:58:16 +0800 Subject: [PATCH 62/95] Unlisten the zoom-level-changed event when webview is detached --- atom/renderer/lib/web-view/web-view.js | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/atom/renderer/lib/web-view/web-view.js b/atom/renderer/lib/web-view/web-view.js index 458e79a84224..cb0a5ddf118c 100644 --- a/atom/renderer/lib/web-view/web-view.js +++ b/atom/renderer/lib/web-view/web-view.js @@ -43,9 +43,10 @@ WebViewImpl = (function() { shadowRoot.appendChild(this.browserPluginNode); // Subscribe to host's zoom level changes. - webFrame.on('zoom-level-changed', (zoomLevel) => { + this.onZoomLevelChanged = (zoomLevel) => { this.webviewNode.setZoomLevel(zoomLevel); - }); + } + webFrame.on('zoom-level-changed', this.onZoomLevelChanged); } WebViewImpl.prototype.createBrowserPluginNode = function() { @@ -64,6 +65,8 @@ WebViewImpl = (function() { /* Resets some state upon reattaching element to the DOM. */ WebViewImpl.prototype.reset = function() { + // Unlisten the zoom-level-changed event. + webFrame.removeListener('zoom-level-changed', this.onZoomLevelChanged); /* If guestInstanceId is defined then the has navigated and has From a82ecfda06aaeb9d2861f7b1ed7bb0198159a4ca Mon Sep 17 00:00:00 2001 From: Ming Luo Date: Wed, 13 Jan 2016 10:18:12 -0500 Subject: [PATCH 63/95] Detail ipc.removeListener & ipc.removeAllListeners --- docs/api/ipc-main.md | 30 +++++++++++++++++++++++++++--- docs/api/ipc-renderer.md | 31 ++++++++++++++++++++++++++++--- 2 files changed, 55 insertions(+), 6 deletions(-) diff --git a/docs/api/ipc-main.md b/docs/api/ipc-main.md index bbaa3c0043f6..87430e7e9966 100644 --- a/docs/api/ipc-main.md +++ b/docs/api/ipc-main.md @@ -1,8 +1,10 @@ # ipcMain -The `ipcMain` module, when used in the main process, handles asynchronous and -synchronous messages sent from a renderer process (web page). Messages sent from -a renderer will be emitted to this module. +The `ipcMain` module is an instance of the +[EventEmitter](https://nodejs.org/api/events.html) class. When used in the main +process, it handles asynchronous and synchronous messages sent from a renderer +process (web page). Messages sent from a renderer will be emitted to this +module. ## Sending Messages @@ -54,6 +56,28 @@ The `ipcMain` module has the following method to listen for events: When the event occurs the `callback` is called with an `event` object and a message, `arg`. +Once done listening for messages, if you longer want to activate this callback +and for whatever reason can't merely stop sending messages on the channel, you +can use: + +### `ipcMain.removeListener(channel, callback)` + +* `channel` String - The event name. +* `callback` Function - The reference to the same function that you used for + `ipcMain.on(channel, callback)` + +Alternatively, if you don't have access to the same callback, you can use: + +### `ipcMain.removeAllListeners(channel)` + +* `channel` String - The event name. + +This has the expected effect of removing *all* handlers to this ipc channel. + +Because of this class' inheritance from the `EventEmitter` node class, you can +also use `ipcMain.once(channel, callback)` to fire handlers meant to occur only +once, as in, they won't be activated after one call of `callback` + ## IPC Event The `event` object passed to the `callback` has the following methods: diff --git a/docs/api/ipc-renderer.md b/docs/api/ipc-renderer.md index 01f0bb3a83dd..d88b477ea714 100644 --- a/docs/api/ipc-renderer.md +++ b/docs/api/ipc-renderer.md @@ -1,8 +1,10 @@ # ipcRenderer -The `ipcRenderer` module provides a few methods so you can send synchronous and -asynchronous messages from the render process (web page) to the main process. -You can also receive replies from the main process. +The `ipcRenderer` module is an instance of the +[EventEmitter](https://nodejs.org/api/events.html) class. It provides a few +methods so you can send synchronous and asynchronous messages from the render +process (web page) to the main process. You can also receive replies from the +main process. See [ipcMain](ipc-main.md) for code examples. @@ -18,6 +20,29 @@ The `ipcRenderer` module has the following method to listen for events: When the event occurs the `callback` is called with an `event` object and arbitrary arguments. +Once done listening for messages, if you longer want to activate this callback +and for whatever reason can't merely stop sending messages on the channel, you +can use: + +### `ipcRenderer.removeListener(channel, callback)` + +* `channel` String - The event name. +* `callback` Function - The reference to the same function that you used for + `ipcRenderer.on(channel, callback)` + +Alternatively, if you don't have access to the same callback, you can use: + +### `ipcRenderer.removeAllListeners(channel)` + +* `channel` String - The event name. + +This has the expected effect of removing *all* handlers to this ipc channel. + +Because of this class' inheritance from the `EventEmitter` node class, you can +also use `ipcRenderer.once(channel, callback)` to fire handlers meant to occur only +once, as in, they won't be activated after one call of `callback` + + ## Sending Messages The `ipcRenderer` module has the following methods for sending messages: From b373fbc552964f708ff43c259c501029828f391a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=A4=A7=E5=92=8C=E5=B1=8B=20=E8=B2=B4=E4=BB=81?= Date: Thu, 14 Jan 2016 01:33:06 +0900 Subject: [PATCH 64/95] Add Japanese translated docs. --- docs-translations/jp/api/accelerator.md | 43 +++ docs-translations/jp/api/app.md | 410 +++++++++++++++++++++++ docs-translations/jp/api/auto-updater.md | 85 +++++ 3 files changed, 538 insertions(+) create mode 100644 docs-translations/jp/api/accelerator.md create mode 100644 docs-translations/jp/api/app.md create mode 100644 docs-translations/jp/api/auto-updater.md diff --git a/docs-translations/jp/api/accelerator.md b/docs-translations/jp/api/accelerator.md new file mode 100644 index 000000000000..83a66447ed5f --- /dev/null +++ b/docs-translations/jp/api/accelerator.md @@ -0,0 +1,43 @@ +# Accelerator + +acceleratorは、キーボードショートカットを示す文字列です。複数の修飾語句とキーコードを `+` 文字で結合します。 + +例: + +* `Command+A` +* `Ctrl+Shift+Z` + +## プラットフォームの留意点 + + +OS Xでは`Command` キー、LinuxとWindowsでは`Control` キーを意味する`CommandOrControl`はいくつかのacceleratorを定義しますが、LinuxとWindowsでは、`Command` キーは何の効果もありません。 + + `Super` キーは、WindowsとLinuxでは `Windows` キーに、OS Xでは、`Cmd` キーに関連付けられます。 + +## 提供されている修飾語句 + +* `Command` (または、短く `Cmd`) +* `Control` (または、短く `Ctrl`) +* `CommandOrControl` (または、短く `CmdOrCtrl`) +* `Alt` +* `Shift` +* `Super` + +## 提供されているキーコード + +* `0` to `9` +* `A` to `Z` +* `F1` to `F24` +* `~`, `!`, `@`, `#`, `$`などの記号 +* `Plus` +* `Space` +* `Backspace` +* `Delete` +* `Insert` +* `Return` (またはエイリアスで `Enter`) +* `Up`と `Down`,`Left`、 `Right` +* `Home` と `End` +* `PageUp` と `PageDown` +* `Escape` (または、短く `Esc`) +* `VolumeUp`と `VolumeDown` 、 `VolumeMute` +* `MediaNextTrack`と `MediaPreviousTrack`、 `MediaStop` 、 `MediaPlayPause` diff --git a/docs-translations/jp/api/app.md b/docs-translations/jp/api/app.md new file mode 100644 index 000000000000..6e18f91d73c4 --- /dev/null +++ b/docs-translations/jp/api/app.md @@ -0,0 +1,410 @@ +# app + + `app` モジュールは、アプリケーションのライフサイクルコントロールを担います。 + +次の例は、最後のウィンドウが閉じたときにアプリケーションを終了させる方法を示しています。 + +```javascript +const app = require('electron').app; +app.on('window-all-closed', function() { + app.quit(); +}); +``` + +## イベント + +`app` オブジェクトは次のイベントを出力します。 + +### イベント: 'will-finish-launching' + +アプリケーションの基礎起動が終わったときに出力されます。Windows と Linuxでは、 `will-finish-launching` イベントと`ready`イベントは同じです。OS Xでは、`NSApplication`の `applicationWillFinishLaunching` 通知をに相当します。通常、`open-file`と`open-url` 用のリスナーの設定、クラッシュレポートの開始、自動アップデートをします。 + +ほとんどの場合、 `ready` イベントハンドラーですべてをするべきです。 + +### イベント: 'ready' + +Electronの初期化が終わった時に出力します。 + +### イベント: 'window-all-closed' + +全てのウィンドウを閉じたときに出力します。 + +このイベントは、アプリケーションが終了する予定ではないときのみ出力します。ユーザーが `Cmd + Q`を押したり、開発者が`app.quit()`をコールすると、Electronは最初にすべてのウィンドウをクローズしようとし、`will-quit`イベントを出力します。この場合、`window-all-closed`イベントは出力されません。 + +### イベント: 'before-quit' + +戻り値: + +* `event` Event + +アプリケーションがウィンドウをクローズし始める前に出力します。`event.preventDefault()`をコールすると、アプリケーションを終了させる既定の挙動を止めることができます。 + +### イベント: 'will-quit' + +戻り値: + +* `event` Event + +全てのウィンドウが閉じて、アプリケーションを終了するときに出力します。`event.preventDefault()`をコールすると、アプリケーションを終了させる既定の挙動を止めることができます。 + +詳細は、`will-quit`イベント と `window-all-closed` イベントの違いは、`window-all-closed` イベントの説明を見てください。 + +### イベント: 'quit' + +戻り値: + +* `event` Event +* `exitCode` Integer + +アプリケーションが終了したときに出力されます。 + +### イベント: 'open-file' _OS X_ + +戻り値: + +* `event` Event +* `path` String + +アプリケーションでファイルを開こうとしたときに出力します。アプリケーションがすでに起動し、OSがファイルを開くアプリケーションを再使用したいとき、`open-file`イベントは出力します。ファイルがdockにドロップアウトされ、アプリケーションがまだ起動していないときにも`open-file` は出力します。このケースを処理するために、アプリケーションの起動のかなり早い段階で、`open-file` イベントをリッスンして確認します(まだ `ready` イベントが出力する前に)。 + +このイベントをハンドルしたいときには `event.preventDefault()` をコールすべきです。 + +Windowsでは、ファイルパスを取得するために、 `process.argv` をパースする必要があります。 + +### イベント: 'open-url' _OS X_ + +戻り値: + +* `event` Event +* `url` String + +アプリケーションでURLを開こうとしたときに出力されます。URLスキーマーは、アプリケーションが開くように登録しなければなりません。 + +このイベントをハンドルしたい場合は、`event.preventDefault()`をコールすべきです。 + +### イベント: 'activate' _OS X_ + +戻り値: + +* `event` Event +* `hasVisibleWindows` Boolean + +アプリケーションがアクティブになったときに出力されます。通常は、アプリケーションのドックアイコンをクリックしたときに発生します。 + +### イベント: 'browser-window-blur' + +戻り値: + +* `event` Event +* `window` BrowserWindow + +[browserWindow](browser-window.md) からフォーカスが外れたときに出力されます。 + +### イベント: 'browser-window-focus' + +戻り値: + +* `event` Event +* `window` BrowserWindow + +[browserWindow](browser-window.md) にフォーカスが当たったとき出力されます。 + +### イベント: 'browser-window-created' + +戻り値: + +* `event` Event +* `window` BrowserWindow + +新しい [browserWindow](browser-window.md) が作成されたときに出力されます。 + +### イベント: 'certificate-error' + +戻り値: + +* `event` Event +* `webContents` [WebContents](web-contents.md) +* `url` URL +* `error` String - The error code +* `certificate` Object + * `data` Buffer - PEM encoded data + * `issuerName` String +* `callback` Function + + `url` の `certificate` 検証に失敗したときに発生します。証明書を信頼するために`event.preventDefault()` と `callback(true)`をコールして既定の動作を止める必要があります。 + +```javascript +session.on('certificate-error', function(event, webContents, url, error, certificate, callback) { + if (url == "https://github.com") { + // Verification logic. + event.preventDefault(); + callback(true); + } else { + callback(false); + } +}); +``` + +### イベント: 'select-client-certificate' + +戻り値: + +* `event` Event +* `webContents` [WebContents](web-contents.md) +* `url` URL +* `certificateList` [Objects] + * `data` Buffer - PEM encoded data + * `issuerName` String - Issuer's Common Name +* `callback` Function + +クライアント証明書が要求されたときに出力されます。 + +`url` は、クライアント証明書を要求するナビゲーションエントリーに対応し、`callback` リストからエントリをフィルターしてコールするのに必要です。`event.preventDefault()` を使用して、アプリケーションの証明書ストアから最初の証明書を使用するのを止めることができます。 + +```javascript +app.on('select-client-certificate', function(event, webContents, url, list, callback) { + event.preventDefault(); + callback(list[0]); +}) +``` + +### イベント: 'login' + +Returns: + +* `event` Event +* `webContents` [WebContents](web-contents.md) +* `request` Object + * `method` String + * `url` URL + * `referrer` URL +* `authInfo` Object + * `isProxy` Boolean + * `scheme` String + * `host` String + * `port` Integer + * `realm` String +* `callback` Function + +`webContents` がベーシック認証をしようとしたときに出力されます。 + +既定の動作ではすべての認証をキャンセルしたり、`event.preventDefault()` と `callback(username, password)` とを証明書でコールし既定の動作をとめてオーバーライドします。 + +```javascript +app.on('login', function(event, webContents, request, authInfo, callback) { + event.preventDefault(); + callback('username', 'secret'); +}) +``` + +### イベント: 'gpu-process-crashed' + +gpu プロセスがクラッシュしたときに出力されます。 + +## メソッド + +`app` オブジェクトは次のメソッドを持ちます。 + +**Note:** いくつかのメソッドは、特定のオペレーティングシステム向けに提供され、そのようにラベルで表示します。 + +### `app.quit()` + +全てのウィンドウを閉じようとします。`before-quit`イベントは、最初に出力されます。すべてのウィンドウを閉じることに成功したら、`will-quit`イベントが出力され、既定では、アプリケーションが終了します。 + +このメソッドは、全ての`beforeunload`と`unload`イベントハンドラは正確に発生することを保証されます。`beforeunload` イベントハンドラで、`false`を返すことでウィンドウの終了をキャンセルすることができます。 + +### `app.exit(exitCode)` + +* `exitCode` Integer + +`exitCode`で今すぐ終了します。 + +全てのウィンドウは、ユーザーに確認することなく、すぐに閉じ、`before-quit`と`will-quit` イベントは出力されません。 + +### `app.getAppPath()` + +減殺のアプリケーションディレクトリを戻します。 + +### `app.getPath(name)` + +* `name` String + +`name`に関連した特定のディレクトリやファイルへのパスを返します。失敗したら、`Error`をスローします。 + +`name`で次のパスをリクエストできます。 + +* `home` ユーザーのホームディレクトリ +* `appData` 既定で示すユーザーごとのアプリケーションディレクトリ + * `%APPDATA%` Windows上 + * `$XDG_CONFIG_HOME` or `~/.config` Linux上 + * `~/Library/Application Support` OS X上 +* `userData` アプリの設定ファイルを格納するディレクトリで、既定では`appData` ディレクトリ配下のアプリ名ディレクトリです +* `temp` 一時ディレクトリ +* `exe` 現在の実行ファイル +* `module` `libchromiumcontent` ライブラリ +* `desktop` 現在のユーザーのデスクトップディレクトリ +* `documents` ユーザーの "My Documents"用ディレクトリ +* `downloads` ユーザーのダウンロード用ディレクトリ +* `music` ユーザーのミュージック用ディレクトリ +* `pictures` ユーザーのピクチャー用ディレクトリ +* `videos` ユーザーのビデオ用ディレクトリ + +### `app.setPath(name, path)` + +* `name` String +* `path` String + +`name`に関連した特定のディレクトリやファイルへの`path` を上書きします。存在しないパスを指定した場合、このメソッドがディレクトリを作成します。失敗したら、`Error`をスローします。 + +`app.getPath`で、`name` で定義されたパスを上書きできます。 + +既定では、webページのクッキーとキャッシュは`userData`ディレクトリ配下に格納できます。ロケーションを変更したい場合、 `app` モジュールの `ready` イベントが出力される前に`userData`パスを上書きする必要があります。 + +### `app.getVersion()` + +ロードしたアプリケーションのバージョンを戻します。アプリケーションの `package.json`ファイルにversionが無ければ、現在のバンドルまたは実行ファイルのバージョンになります。 + +### `app.getName()` + +現在のアプリケーション名を戻し、`package.json` ファイルのnameです。 + +通常、 `package.json`の`name` フィールドは、短い小文字名で、npm module spec と一致します。通常、`productName`で、アプリケーションの大文字正式名を指定し、Electronでは`name`をそれで上書きます。 + +### `app.getLocale()` + +現在のアプリケーションのロケールを戻します。 + +### `app.addRecentDocument(path)` _OS X_ _Windows_ + +* `path` String + +最近のドキュメント一覧に`path`を追加します。 + +この一覧はOSが管理しています。Windowsではタスクバーからこの一覧を見れ、OS Xではdockメニューから見れます。 + +### `app.clearRecentDocuments()` _OS X_ _Windows_ + +最近のドキュメント一覧をクリアします。 + +### `app.setUserTasks(tasks)` _Windows_ + +* `tasks` Array - `Task` オブジェクトの配列 + +Windowsのジャンプリストの[Tasks][tasks]カテゴリに`tasks`を追加します。 + +`tasks` は`Task`オブジェクトの配列で、次のフォーマットになります。 + +`Task` Object: + +* `program` String - 実行するプログラムのパスで、通常はプログラムが開く`process.execPath`を指定します +* `arguments` String - `program` を実行するときのコマンドライン引数です +* `title` String - ジャンプリストに表示される文字列です +* `description` String - タスクの説明 +* `iconPath` String - ジャンプリストに表示するアイコンの絶対パスで、アイコンを含む任意のリソースファイルです。通常、プログラムのアイコンを表示する`process.execPath`を指定します。 +* `iconIndex` Integer - アイコンファイルのアイコンインデックスです。アイコンファイルに2つ以上のアイコンが含まれている場合、この値でアイコンを指定します。1つしかアイコンファイルに含まれていない場合は、この値は0です。 + +### `app.allowNTLMCredentialsForAllDomains(allow)` + +* `allow` Boolean + +HTTP NTLMまたはNegotiate認証用の照明を常に送信するかどうかを動的に設定できます。通常、Electronはローカルインターネットサイト(例えば、あなたと同じドメイン名のとき)に該当するURL用のNTLM/Kerberos証明書のみ送信します。しかし、この検知はコーポレートネットワークの設定が悪いときには、頻繁に失敗するので、この挙動を共通に行うことを選べば、全てのURLで有効にできます。 + +### `app.makeSingleInstance(callback)` + +* `callback` Function + +このメソッドは、アプリケーションをシングルインスタンスアプリケーションにします。アプリの実行を複数のインスタンスで実行することを許可せず、アプリケーション実行をシングルインスタンスのみにすることを保証し、ほかのインスタンスにはこのインスタンスの存在を知らせ終了さえます。 + +2つ目のインスタンスが起動したとき、`callback` は、`callback(argv, workingDirectory)` でコールします。`argv` は、2つ目のインスタンスのコマンドライン引数の配列で、`workingDirectory` は現在のワーキングディレクトリです。通常、アプリケーションはメインのウィンドウにフォーカスをあて最小化させないことで対応します。 + +The `callback` は、 `app`の`ready` イベントの出力後に実行することを保証します。 + +プロセスがアプリケーションのプライマリインスタンスでアプリがロードし続けるなら、このメソッドは `false`を戻します。プロセスがほかのインスタンスにパラメーターを送信し、`true`を戻すと、直ちに終了します。 + +OS Xは、ユーザーがFinderで2つ目のアプリインスタンスを開いたり、`open-file` 、 `open-url`イベントが出力しようとすると、システムが自動的にシングルインスタンスを強制します。しかし、コマンドラインでアプリを開始するとシステムのシングルインスタンスメカニズムは無視されるので、シングルインスタンスを強制するためには、このメソッドを使う必要があります。 + +2つ目のインスタンスを起動するとき、メインのインスタンスのウィンドウをアクティブにする例 + +```js +var myWindow = null; + +var shouldQuit = app.makeSingleInstance(function(commandLine, workingDirectory) { + // Someone tried to run a second instance, we should focus our window + if (myWindow) { + if (myWindow.isMinimized()) myWindow.restore(); + myWindow.focus(); + } + return true; +}); + +if (shouldQuit) { + app.quit(); + return; +} + +// Create myWindow, load the rest of the app, etc... +app.on('ready', function() { +}); +``` + +### `app.setAppUserModelId(id)` _Windows_ + +* `id` String + +[Application User Model ID][app-user-model-id] を `id`に変更します。 + +### `app.commandLine.appendSwitch(switch[, value])` + +Chromiumのコマンドラインにスイッチ( `value`をオプションにし)を追加します。 + +**Note:** これは、`process.argv`に影響せず、開発者が、Chromiumのローレベルな挙動をコントロールするのに使用します。 + +### `app.commandLine.appendArgument(value)` + +Chromiumのコマンドダインに引数を追加します。引数は正しく引用符で囲まれます。 + +**Note:** `process.argv`に影響しません。 + +### `app.dock.bounce([type])` _OS X_ + +* `type` String (optional) - `critical` または `informational`を指定できます。既定では、 `informational`です。 + +`critical`を渡すと、アプリケーションがアクティブ、もしくはリクエストがキャンセルされるまでは、dockアイコンは、バウンスします。 + +`informational` を渡すと、1秒dockアイコンはバウンスします。しかし、アプリケーションがアクティブ、もしくはリクエストがキャンセルされるまでは、リクエストは残ります。 + +リクエストを示すIDを戻します。 + +### `app.dock.cancelBounce(id)` _OS X_ + +* `id` Integer + +`id`のバウンスをキャンセルします。 + +### `app.dock.setBadge(text)` _OS X_ + +* `text` String + +dockのバッジエリアで表示する文字列を設定します。 + +### `app.dock.getBadge()` _OS X_ + +dockのバッジ文字列を戻します。 + +### `app.dock.hide()` _OS X_ + +dock アイコンを隠します。 + +### `app.dock.show()` _OS X_ + +dock アイコンを表示します。 + +### `app.dock.setMenu(menu)` _OS X_ + +* `menu` Menu + +アプリケーションの[dock menu][dock-menu]を設定します。 + +[dock-menu]:https://developer.apple.com/library/mac/documentation/Carbon/Conceptual/customizing_docktile/concepts/dockconcepts.html#//apple_ref/doc/uid/TP30000986-CH2-TPXREF103 +[tasks]:http://msdn.microsoft.com/en-us/library/windows/desktop/dd378460(v=vs.85).aspx#tasks +[app-user-model-id]: https://msdn.microsoft.com/en-us/library/windows/desktop/dd378459(v=vs.85).aspx diff --git a/docs-translations/jp/api/auto-updater.md b/docs-translations/jp/api/auto-updater.md new file mode 100644 index 000000000000..818a75e019a0 --- /dev/null +++ b/docs-translations/jp/api/auto-updater.md @@ -0,0 +1,85 @@ +# autoUpdater + +このモジュールは、`Squirrel`オートアップデートフレームワークのインターフェイスを提供します。 + +## プラットフォーム留意点 + +`autoUpdater`は、異なるプラットフォーム用に統一したAPIを提供していますが、それぞれのプラットフォーム上で、まだ多少の差があります。 + +### OS X + +OS Xでは、 `autoUpdater` モジュールは、[Squirrel.Mac][squirrel-mac]上に構築されていて、動作させるのに特別な設定が不要であることを意味します。サーバーサイドの要件は、[Server Support][server-support]を読んでください。 + +### Windows + +Windowsでは、auto-updaterを使う前に、ユーザーのPCにアプリをインストールする必要があるので、Windows インストーラーを生成するために[grunt-electron-installer][installer]モジュールを使用することをお勧めします。 + +Squirrelで生成されたインストーラーは、`com.squirrel.PACKAGE_ID.YOUR_EXE_WITHOUT_DOT_EXE`のフォーマット(例えば、`com.squirrel.slack.Slack` と `com.squirrel.code.Code`)で[Application User Model ID][app-user-model-id]とショートカットアイコンを作成します。`app.setAppUserModelId`APIで同じIDを使う必要があります。同じIDでないと、Windowsはタスクバーに適切にピン止めすることができません。 + +サーバーサイドのセットアップは、OS Xと異なります。詳細は、[Squirrel.Windows][squirrel-windows] を参照してください。 + +### Linux + +Linuxでは、auot-updater用のサポートがビルトインされていないので、アプリをアップデートするためにディストリビューションのパッケージマネジャーを使用することをお勧めします。 + +## イベント + +`autoUpdater` オブジェクトは次のイベントを出力します。 + +### イベント: 'error' + +戻り値: + +* `error` Error + +アップデート中にエラーがあった場合に出力されます。 + +### イベント: 'checking-for-update' + +アップデートを開始したかチェックしたときに出力されます。 + +### イベント: 'update-available' + +アップデートが提供されているときに出力されます。アップデートは自動的にダウンロードされます。 + +### イベント: 'update-not-available' + +アップデートが提供されていないときに出力されます。 + +### イベント: 'update-downloaded' + +戻り値: + +* `event` Event +* `releaseNotes` String +* `releaseName` String +* `releaseDate` Date +* `updateURL` String + +アップデートをダウンロードしたときに出力されます。 + +Windowsでは、`releaseName` のみ提供されます。 + +## メソッド + +`autoUpdater` オブジェクトは次のメソッドを持っています。 + +### `autoUpdater.setFeedURL(url)` + +* `url` String + + `url`を設定し、自動アップデートを初期化します。 `url`は一度設定すると変更できません。 + +### `autoUpdater.checkForUpdates()` + +アップデートがあるかどうかサーバーに問い合わせます。APIを使う前に、`setFeedURL`をコールしなければなりません。 + +### `autoUpdater.quitAndInstall()` + +ダウンロード後、アプリを再起動して、アップデートをインストールします。`update-downloaded`が出力された後のみ、コールすべきです。 + +[squirrel-mac]: https://github.com/Squirrel/Squirrel.Mac +[server-support]: https://github.com/Squirrel/Squirrel.Mac#server-support +[squirrel-windows]: https://github.com/Squirrel/Squirrel.Windows +[installer]: https://github.com/atom/grunt-electron-installer +[app-user-model-id]: https://msdn.microsoft.com/en-us/library/windows/desktop/dd378459(v=vs.85).aspx From edbf1994dd6a00899ec8488ef8f76f6c7f5f007f Mon Sep 17 00:00:00 2001 From: Luke Page Date: Wed, 13 Jan 2016 16:52:07 +0000 Subject: [PATCH 65/95] docs - fix typo leading to bad link --- docs/tutorial/desktop-environment-integration.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/tutorial/desktop-environment-integration.md b/docs/tutorial/desktop-environment-integration.md index 906f77ffa6b8..7d7eb44ecb6e 100644 --- a/docs/tutorial/desktop-environment-integration.md +++ b/docs/tutorial/desktop-environment-integration.md @@ -35,7 +35,7 @@ are fine differences. Model ID][app-user-model-id], must be installed to the Start screen. Note, however, that it does not need to be pinned to the Start screen. * On Windows 7 and below, notifications are not supported. You can however send -"balloon notifications" using the [Tray API](tray-balloon). +"balloon notifications" using the [Tray API][tray-balloon]. Furthermore, the maximum length for the notification body is 250 characters, with the Windows team recommending that notifications should be kept to 200 From 8b38bbcf1825ab37548ebc8b47684f823ad7d9fc Mon Sep 17 00:00:00 2001 From: Robo Date: Wed, 13 Jan 2016 22:32:41 +0530 Subject: [PATCH 66/95] webview: respect properties provided during webview creation --- atom/renderer/lib/web-view/web-view-attributes.js | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/atom/renderer/lib/web-view/web-view-attributes.js b/atom/renderer/lib/web-view/web-view-attributes.js index fd5dad21c58e..b02cd755e82a 100644 --- a/atom/renderer/lib/web-view/web-view-attributes.js +++ b/atom/renderer/lib/web-view/web-view-attributes.js @@ -29,6 +29,7 @@ resolveURL = function(url) { WebViewAttribute = (function() { function WebViewAttribute(name, webViewImpl) { this.name = name; + this.value = webViewImpl.webviewNode[name] || ''; this.webViewImpl = webViewImpl; this.ignoreMutation = false; this.defineProperty(); @@ -38,7 +39,7 @@ WebViewAttribute = (function() { /* Retrieves and returns the attribute's value. */ WebViewAttribute.prototype.getValue = function() { - return this.webViewImpl.webviewNode.getAttribute(this.name) || ''; + return this.webViewImpl.webviewNode.getAttribute(this.name) || this.value; }; @@ -228,7 +229,7 @@ SrcAttribute = (function(superClass) { if (this.webViewImpl.webviewNode.hasAttribute(this.name)) { return resolveURL(this.webViewImpl.webviewNode.getAttribute(this.name)); } else { - return ''; + return this.value; } }; @@ -368,7 +369,7 @@ PreloadAttribute = (function(superClass) { PreloadAttribute.prototype.getValue = function() { var preload, protocol; if (!this.webViewImpl.webviewNode.hasAttribute(this.name)) { - return ''; + return this.value; } preload = resolveURL(this.webViewImpl.webviewNode.getAttribute(this.name)); protocol = preload.substr(0, 5); From 918825cb58678352b558b9db55c1a8dc870e3952 Mon Sep 17 00:00:00 2001 From: Plusb Preco Date: Mon, 11 Jan 2016 13:11:10 +0900 Subject: [PATCH 67/95] :memo: Update as upstream [ci skip] --- docs-translations/ko-KR/api/browser-window.md | 31 ++++++--- docs-translations/ko-KR/api/dialog.md | 5 +- .../ko-KR/api/frameless-window.md | 4 +- docs-translations/ko-KR/api/menu.md | 2 +- docs-translations/ko-KR/api/remote.md | 3 + docs-translations/ko-KR/api/session.md | 65 ++++++++++--------- docs-translations/ko-KR/api/web-frame.md | 16 +++++ docs-translations/ko-KR/api/web-view-tag.md | 6 ++ .../development/build-instructions-windows.md | 2 +- .../desktop-environment-integration.md | 17 +---- 10 files changed, 91 insertions(+), 60 deletions(-) diff --git a/docs-translations/ko-KR/api/browser-window.md b/docs-translations/ko-KR/api/browser-window.md index 9086f8374241..43bcd4a19cfc 100644 --- a/docs-translations/ko-KR/api/browser-window.md +++ b/docs-translations/ko-KR/api/browser-window.md @@ -64,7 +64,7 @@ win.show(); 형태로 생성합니다. 기본값은 `true`입니다. * `acceptFirstMouse` Boolean - 윈도우가 비활성화 상태일 때 내부 컨텐츠 클릭 시 활성화 되는 동시에 단일 mouse-down 이벤트를 발생시킬지 여부. 기본값은 `false`입니다. -* `disableAutoHideCursor` Boolean - 파이핑중 자동으로 커서를 숨길지 여부. 기본값은 +* `disableAutoHideCursor` Boolean - 타이핑중 자동으로 커서를 숨길지 여부. 기본값은 `false`입니다. * `autoHideMenuBar` Boolean - `Alt`를 누르지 않는 한 어플리케이션 메뉴바를 숨길지 여부. 기본값은 `false`입니다. @@ -115,12 +115,16 @@ win.show(); 합니다. node 통합이 비활성화되어있을 경우, preload 스크립트는 node의 global 심볼들을 다시 global 스코프로 다시 포함 시킬 수 있습니다. [여기](process.md#event-loaded)의 예제를 참고하세요. -* `partition` String - 페이지에서 사용할 세션을 지정합니다. 만약 `partition`이 - `persist:`로 시작하면 페이지는 지속성 세션을 사용하며 다른 모든 앱 내의 - 페이지에서 같은 `partition`을 사용할 수 있습니다. 만약 `persist:` 접두어로 - 시작하지 않으면 페이지는 인-메모리 세션을 사용합니다. 여러 페이지에서 같은 - `partition`을 지정하면 같은 세션을 공유할 수 있습니다. `partition`을 지정하지 - 않으면 어플리케이션의 기본 세션이 사용됩니다. +* `session` [Session](session.md#class-session) - 페이지에서 사용할 세션을 + 지정합니다. Session 객체를 직접적으로 전달하는 대신, 파티션 문자열을 받는 + `partition` 옵션을 사용할 수도 있습니다. `session`과 `partition`이 같이 + 제공되었을 경우 `session`이 사용됩니다. 기본값은 기본 세션입니다. + * `partition` String - 페이지에서 사용할 세션을 지정합니다. 만약 `partition`이 + `persist:`로 시작하면 페이지는 지속성 세션을 사용하며 다른 모든 앱 내의 + 페이지에서 같은 `partition`을 사용할 수 있습니다. 만약 `persist:` 접두어로 + 시작하지 않으면 페이지는 인-메모리 세션을 사용합니다. 여러 페이지에서 같은 + `partition`을 지정하면 같은 세션을 공유할 수 있습니다. `partition`을 지정하지 + 않으면 어플리케이션의 기본 세션이 사용됩니다. * `zoomFactor` Number - 페이지의 기본 줌 값을 지정합니다. 예를 들어 `300%`를 표현하려면 `3.0`으로 지정합니다. 기본값은 `1.0`입니다. * `javascript` Boolean - 자바스크립트를 활성화합니다. 기본값은 `false`입니다. @@ -287,7 +291,8 @@ someWindow.on('app-command', function(e, cmd) { ### `BrowserWindow.getFocusedWindow()` -어플리케이션에서 포커스된 윈도우를 반환합니다. +어플리케이션에서 포커스된 윈도우를 반환합니다. 포커스된 윈도우가 없을 경우 `null`을 +반환합니다. ### `BrowserWindow.fromWebContents(webContents)` @@ -564,12 +569,20 @@ Kiosk(키오스크) 모드를 설정합니다. 현재 윈도우가 kiosk 모드인지 여부를 반환합니다. +### `win.getNativeWindowHandle()` + +`Buffer` 상의 플랫폼에 따른 윈도우 핸들을 반환합니다. + +핸들의 타입에 따라 적절히 캐스팅됩니다. Windows의 `HWND`, OS X의 `NSView*`, Linux의 +`Window` (`unsigned long`)를 예로 들 수 있습니다. + ### `win.hookWindowMessage(message, callback)` _Windows_ * `message` Integer * `callback` Function -Windows 메시지 훅을 등록합니다. `callback`은 WndProc에서 메시지를 받았을 때 호출됩니다. +Windows 메시지 훅을 등록합니다. `callback`은 WndProc에서 메시지를 받았을 때 +호출됩니다. ### `win.isWindowMessageHooked(message)` _Windows_ diff --git a/docs-translations/ko-KR/api/dialog.md b/docs-translations/ko-KR/api/dialog.md index 3fff8683cd6d..9147f1c5bdca 100644 --- a/docs-translations/ko-KR/api/dialog.md +++ b/docs-translations/ko-KR/api/dialog.md @@ -78,7 +78,8 @@ console.log(dialog.showOpenDialog({ properties: [ 'openFile', 'openDirectory', ' `filters`를 지정하면 유저가 저장 가능한 파일 형식을 지정할 수 있습니다. 사용 방법은 `dialog.showOpenDialog`의 `filters` 속성과 같습니다. -`callback`이 전달되면 메서드가 비동기로 작동되며 결과는 `callback(filename)`을 통해 전달됩니다. +`callback`이 전달되면 메서드가 비동기로 작동되며 결과는 `callback(filename)`을 통해 +전달됩니다. ### `dialog.showMessageBox([browserWindow, ]options[, callback])` @@ -88,6 +89,8 @@ console.log(dialog.showOpenDialog({ properties: [ 'openFile', 'openDirectory', ' 하나를 사용할 수 있습니다. Windows에선 따로 `icon`을 설정하지 않은 이상 "question"과 "info"는 같은 아이콘으로 표시됩니다. * `buttons` Array - 버튼들의 라벨을 포함한 배열입니다. + * `defaultId` Integer - 메시지 박스가 열렸을 때 기본적으로 선택될 버튼 배열의 + 버튼 인덱스입니다. * `title` String - 대화 상자의 제목입니다. 몇몇 플랫폼에선 보이지 않을 수 있습니다. * `message` String - 대화 상자의 본문 내용입니다. * `detail` String - 메시지의 추가 정보입니다. diff --git a/docs-translations/ko-KR/api/frameless-window.md b/docs-translations/ko-KR/api/frameless-window.md index e13794e0fdfd..9fa8fafc4c4f 100644 --- a/docs-translations/ko-KR/api/frameless-window.md +++ b/docs-translations/ko-KR/api/frameless-window.md @@ -38,8 +38,8 @@ var win = new BrowserWindow({ transparent: true, frame: false }); ### API의 한계 * 투명한 영역을 통과하여 클릭할 수 없습니다. 우리는 이 문제를 해결하기 위해 API를 - 제공할 예정이었지만 현재로써는 [upstream 버그](https://code.google.com/p/chromium/issues/detail?id=387234)로 - 인해 중단된 상태입니다. + 제공할 예정이며 자세한 내용은 + [이슈](https://github.com/atom/electron/issues/1335)를 참고하세요. * 투명한 창은 크기를 조절할 수 없습니다. `resizable` 속성을 `true`로 할 경우 몇몇 플랫폼에선 크래시가 일어납니다. * `blur` 필터는 웹 페이지에서만 적용됩니다. 윈도우 아래 컨텐츠에는 블러 효과를 적용할 diff --git a/docs-translations/ko-KR/api/menu.md b/docs-translations/ko-KR/api/menu.md index f01021ae1082..61bf92bf76d5 100644 --- a/docs-translations/ko-KR/api/menu.md +++ b/docs-translations/ko-KR/api/menu.md @@ -195,7 +195,7 @@ if (process.platform == 'darwin') { ); } -menu = Menu.buildFromTemplate(template); +var menu = Menu.buildFromTemplate(template); Menu.setApplicationMenu(menu); ``` diff --git a/docs-translations/ko-KR/api/remote.md b/docs-translations/ko-KR/api/remote.md index 935b09865130..3a09084acdef 100644 --- a/docs-translations/ko-KR/api/remote.md +++ b/docs-translations/ko-KR/api/remote.md @@ -34,6 +34,9 @@ win.loadURL('https://github.com'); 않습니다. 대신에 이 `BrowserWindow` 객체는 메인 프로세스에서 생성되며 랜더러 프로세스에 `win` 객체와 같이 이에 대응하는 remote 객체를 반환합니다. +참고로 remote를 통해선 [enumerable 속성](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Enumerability_and_ownership_of_properties)을 +가진 프로퍼티에만 접근할 수 있습니다. + ## Remote 객체의 생명 주기 Electron은 랜더러 프로세스의 remote 객체가 살아있는 한(다시 말해서 GC(garbage diff --git a/docs-translations/ko-KR/api/session.md b/docs-translations/ko-KR/api/session.md index c857e111571f..5da0dd01276b 100644 --- a/docs-translations/ko-KR/api/session.md +++ b/docs-translations/ko-KR/api/session.md @@ -178,47 +178,48 @@ session.defaultSession.cookies.set(cookie, function(error) { 웹 스토리지의 데이터를 비웁니다. +#### `ses.flushStorageData()` + +디스크에 사용되지 않은 DOMStorage 데이터를 모두 덮어씌웁니다. + #### `ses.setProxy(config, callback)` -* `config` String +* `config` Object + * `pacScript` String - PAC 파일과 관련된 URL입니다. + * `proxyRules` String - 사용할 프록시의 규칙을 나타냅니다. * `callback` Function - 작업이 완료되면 호출됩니다. -세션에 사용할 프록시 `config`를 분석하고 프록시를 적용합니다. +프록시 설정을 적용합니다. -세션에 사용할 프록시는 `config`가 PAC 주소일 경우 그대로 적용하고, 다른 형식일 경우 -다음 규칙에 따라 적용합니다. +`pacScript`와 `proxyRules`이 같이 제공되면 `proxyRules` 옵션은 무시되며 `pacScript` +컨픽만 적용됩니다. + +`proxyRules`는 다음과 같은 규칙을 따릅니다: ``` -config = scheme-proxies[";"] -scheme-proxies = ["="] -url-scheme = "http" | "https" | "ftp" | "socks" -proxy-uri-list = [","] -proxy-uri = ["://"][":"] - - 예시: - "http=foopy:80;ftp=foopy2" -- http:// URL에 "foopy:80" HTTP 프록시를 - 사용합니다. "foopy2:80" 는 ftp:// URL에 - 사용됩니다. - "foopy:80" -- 모든 URL에 "foopy:80" 프록시를 사용합니다. - "foopy:80,bar,direct://" -- 모든 URL에 "foopy:80" HTTP 프록시를 - 사용합니다. 문제가 발생하여 "foopy:80"를 - 사용할 수 없는 경우 "bar"를 대신 사용하여 - 장애를 복구하며 그 다음 문제가 생긴 경우 - 프록시를 사용하지 않습니다. - "socks4://foopy" -- 모든 URL에 "foopy:1000" SOCKS v4 프록시를 - 사용합니다. - "http=foopy,socks5://bar.com -- http:// URL에 "foopy" HTTP 프록시를 - 사용합니다. 문제가 발생하여 "foopy"를 - 사용할 수 없는 경우 SOCKS5 "bar.com" - 프록시를 대신 사용합니다. - "http=foopy,direct:// -- http:// URL에 "foopy" HTTP 프록시를 - 사용합니다. 그리고 문제가 발생하여 "foopy"를 - 사용할 수 없는 경우 프록시를 사용하지 않습니다. - "http=foopy;socks=foopy2 -- http:// URL에 "foopy" HTTP 프록시를 - 사용합니다. 그리고 "socks4://foopy2" - 프록시를 다른 모든 URL에 사용합니다. +proxyRules = schemeProxies[";"] +schemeProxies = ["="] +urlScheme = "http" | "https" | "ftp" | "socks" +proxyURIList = [","] +proxyURL = ["://"][":"] ``` +예시: +* `http=foopy:80;ftp=foopy2` - http:// URL에 `foopy:80` HTTP 프록시를 사용합니다. + `foopy2:80` 는 ftp:// URL에 사용됩니다. +* `foopy:80` - 모든 URL에 `foopy:80` 프록시를 사용합니다. +* `foopy:80,bar,direct://` - 모든 URL에 `foopy:80` HTTP 프록시를 사용합니다. + 문제가 발생하여 `foopy:80`를 사용할 수 없는 경우 `bar`를 대신 사용하여 장애를 + 복구하며 그 다음 문제가 생긴 경우 프록시를 사용하지 않습니다. +* `socks4://foopy` - 모든 URL에 `foopy:1000` SOCKS v4 프록시를 사용합니다. +* `http=foopy,socks5://bar.com` - http:// URL에 `foopy` HTTP 프록시를 사용합니다. + 문제가 발생하여 `foopy`를 사용할 수 없는 경우 SOCKS5 `bar.com` 프록시를 대신 + 사용합니다. +* `http=foopy,direct://` - http:// URL에 `foopy` HTTP 프록시를 사용합니다. 그리고 + 문제가 발생하여 `foopy`를 사용할 수 없는 경우 프록시를 사용하지 않습니다. +* `http=foopy;socks=foopy2` - http:// URL에 `foopy` HTTP 프록시를 사용합니다. + 그리고 `socks4://foopy2` 프록시를 다른 모든 URL에 사용합니다. + ### `app.resolveProxy(url, callback)` * `url` URL diff --git a/docs-translations/ko-KR/api/web-frame.md b/docs-translations/ko-KR/api/web-frame.md index 8181c0f3bf21..f77ed68f9073 100644 --- a/docs-translations/ko-KR/api/web-frame.md +++ b/docs-translations/ko-KR/api/web-frame.md @@ -88,4 +88,20 @@ webFrame.setSpellCheckProvider("en-US", true, { `scheme`를 보안된 스킴으로 등록합니다. 리소스에 대해 보안 정책을 우회하며, ServiceWorker의 등록과 fetch API를 사용할 수 있도록 지원합니다. +### `webFrame.insertText(text)` + +* `text` String + +포커스된 요소에 `text`를 삽입합니다. + +### `webFrame.executeJavaScript(code[, userGesture])` + +* `code` String +* `userGesture` Boolean (optional) - 기본값은 `false` 입니다. + +페이지에서 `code`를 실행합니다. + +브라우저 윈도우에서 어떤 `requestFullScreen` 같은 HTML API는 사용자의 승인이 +필요합니다. `userGesture`를 `true`로 설정하면 이러한 제약을 제거할 수 있습니다. + [spellchecker]: https://github.com/atom/node-spellchecker diff --git a/docs-translations/ko-KR/api/web-view-tag.md b/docs-translations/ko-KR/api/web-view-tag.md index 591721752f30..a6a84a1ceeee 100644 --- a/docs-translations/ko-KR/api/web-view-tag.md +++ b/docs-translations/ko-KR/api/web-view-tag.md @@ -340,6 +340,12 @@ Service worker에 대한 개발자 도구를 엽니다. 페이지에서 `replaceMisspelling` 커맨드를 실행합니다. +### `.insertText(text)` + +* `text` String + +포커스된 요소에 `text`를 삽입합니다. + ### `webContents.findInPage(text[, options])` * `text` String - 찾을 컨텐츠, 반드시 공백이 아니여야 합니다. diff --git a/docs-translations/ko-KR/development/build-instructions-windows.md b/docs-translations/ko-KR/development/build-instructions-windows.md index a5b0de78bdfb..3c7932479ecd 100644 --- a/docs-translations/ko-KR/development/build-instructions-windows.md +++ b/docs-translations/ko-KR/development/build-instructions-windows.md @@ -5,7 +5,7 @@ ## 빌드전 요구 사항 * Windows 7 / Server 2008 R2 또는 최신 버전 -* Visual Studio 2013 Update 5 - [VS 2013 커뮤니티 에디션 무료 다운로드](http://www.visualstudio.com/products/visual-studio-community-vs) +* Visual Studio 2013 Update 4 - [VS 2013 커뮤니티 에디션 무료 다운로드](https://www.visualstudio.com/news/vs2013-community-vs) * [Python 2.7](http://www.python.org/download/releases/2.7/) * [Node.js](http://nodejs.org/download/) * [Git](http://git-scm.com) diff --git a/docs-translations/ko-KR/tutorial/desktop-environment-integration.md b/docs-translations/ko-KR/tutorial/desktop-environment-integration.md index d2e50beb6c18..91fc59a8f2ef 100644 --- a/docs-translations/ko-KR/tutorial/desktop-environment-integration.md +++ b/docs-translations/ko-KR/tutorial/desktop-environment-integration.md @@ -34,21 +34,10 @@ myNotification.onclick = function () { 만들어 놔야 합니다. 이 바로가기는 반드시 시작 화면에 설치되어 있어야 합니다. 참고로 반드시 시작 화면에 고정 할 필요는 없습니다. * Windows 7과 그 이하 버전은 데스크톱 알림을 지원하지 않습니다. - 혹시 "풍선 팝업 알림" 기능을 찾는다면 [Tray API](tray-balloon)를 사용하세요. + 혹시 "풍선 팝업 알림" 기능을 찾는다면 [Tray API][tray-balloon]를 사용하세요. -이미지를 데스크톱 알림에 사용하려면 알림 옵션의 `icon` 속성에 로컬 이미지 파일 -(`png` 권장)을 지정하면 됩니다. 데스크톱 알림은 잘못된 경로를 지정하거나 `http/https` -기반의 URL을 지정해도 이미지가 보이지 않을 뿐 정상 작동합니다. - -```javascript -new Notification('Title', { - body: 'Notification with icon', - icon: 'file:///C:/Users/feriese/Desktop/icon.png' -}); -``` - -또한 본문의 최대 길이는 250자 입니다. Windows 개발팀에선 알림 문자열을 200자 이하로 -유지하는 것을 권장합니다. +또한 알림 본문의 최대 길이는 250자 입니다. Windows 개발팀에선 알림 문자열을 200자 +이하로 유지하는 것을 권장합니다. ### Linux From 10e4698baa94ddb0c1a1537385279875c2cccbe8 Mon Sep 17 00:00:00 2001 From: Robo Date: Thu, 14 Jan 2016 15:01:54 +0530 Subject: [PATCH 68/95] session: api to get current cache size --- atom/browser/api/atom_api_session.cc | 34 ++++++++++++++++++++++------ atom/browser/api/atom_api_session.h | 8 ++++++- docs/api/session.md | 7 ++++++ 3 files changed, 41 insertions(+), 8 deletions(-) diff --git a/atom/browser/api/atom_api_session.cc b/atom/browser/api/atom_api_session.cc index f9e714880275..5f227fb82f2c 100644 --- a/atom/browser/api/atom_api_session.cc +++ b/atom/browser/api/atom_api_session.cc @@ -22,6 +22,7 @@ #include "atom/common/node_includes.h" #include "base/files/file_path.h" #include "base/prefs/pref_service.h" +#include "base/strings/string_number_conversions.h" #include "base/strings/string_util.h" #include "base/thread_task_runner_handle.h" #include "brightray/browser/net/devtools_network_conditions.h" @@ -204,7 +205,7 @@ class ResolveProxyHelper { }; // Runs the callback in UI thread. -template +template void RunCallbackInUI(const base::Callback& callback, T... result) { BrowserThread::PostTask( BrowserThread::UI, FROM_HERE, base::Bind(callback, result...)); @@ -212,19 +213,35 @@ void RunCallbackInUI(const base::Callback& callback, T... result) { // Callback of HttpCache::GetBackend. void OnGetBackend(disk_cache::Backend** backend_ptr, + Session::CacheAction action, const net::CompletionCallback& callback, int result) { if (result != net::OK) { RunCallbackInUI(callback, result); } else if (backend_ptr && *backend_ptr) { - (*backend_ptr)->DoomAllEntries(base::Bind(&RunCallbackInUI, callback)); + if (action == Session::CacheAction::CLEAR) { + (*backend_ptr)->DoomAllEntries(base::Bind(&RunCallbackInUI, + callback)); + } else if (action == Session::CacheAction::STATS) { + base::StringPairs stats; + (*backend_ptr)->GetStats(&stats); + for (size_t i = 0; i < stats.size(); ++i) { + if (stats[i].first == "Current size") { + int current_size; + base::StringToInt(stats[i].second, ¤t_size); + RunCallbackInUI(callback, current_size); + break; + } + } + } } else { RunCallbackInUI(callback, net::ERR_FAILED); } } -void ClearHttpCacheInIO( +void GetHttpCacheInIO( const scoped_refptr& context_getter, + Session::CacheAction action, const net::CompletionCallback& callback) { auto request_context = context_getter->GetURLRequestContext(); auto http_cache = request_context->http_transaction_factory()->GetCache(); @@ -235,7 +252,7 @@ void ClearHttpCacheInIO( using BackendPtr = disk_cache::Backend*; BackendPtr* backend_ptr = new BackendPtr(nullptr); net::CompletionCallback on_get_backend = - base::Bind(&OnGetBackend, base::Owned(backend_ptr), callback); + base::Bind(&OnGetBackend, base::Owned(backend_ptr), action, callback); int rv = http_cache->GetBackend(backend_ptr, on_get_backend); if (rv != net::ERR_IO_PENDING) on_get_backend.Run(net::OK); @@ -287,10 +304,12 @@ void Session::ResolveProxy(const GURL& url, ResolveProxyCallback callback) { new ResolveProxyHelper(browser_context(), url, callback); } -void Session::ClearCache(const net::CompletionCallback& callback) { +template +void Session::DoCacheAction(const net::CompletionCallback& callback) { BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, - base::Bind(&ClearHttpCacheInIO, + base::Bind(&GetHttpCacheInIO, make_scoped_refptr(browser_context_->GetRequestContext()), + action, callback)); } @@ -420,7 +439,8 @@ void Session::BuildPrototype(v8::Isolate* isolate, mate::ObjectTemplateBuilder(isolate, prototype) .MakeDestroyable() .SetMethod("resolveProxy", &Session::ResolveProxy) - .SetMethod("clearCache", &Session::ClearCache) + .SetMethod("getCacheSize", &Session::DoCacheAction) + .SetMethod("clearCache", &Session::DoCacheAction) .SetMethod("clearStorageData", &Session::ClearStorageData) .SetMethod("flushStorageData", &Session::FlushStorageData) .SetMethod("setProxy", &Session::SetProxy) diff --git a/atom/browser/api/atom_api_session.h b/atom/browser/api/atom_api_session.h index c631670831e0..37a5a45a6c95 100644 --- a/atom/browser/api/atom_api_session.h +++ b/atom/browser/api/atom_api_session.h @@ -38,6 +38,11 @@ class Session: public mate::TrackableObject, public: using ResolveProxyCallback = base::Callback; + enum class CacheAction { + CLEAR, + STATS, + }; + // Gets or creates Session from the |browser_context|. static mate::Handle CreateFrom( v8::Isolate* isolate, AtomBrowserContext* browser_context); @@ -62,7 +67,8 @@ class Session: public mate::TrackableObject, private: void ResolveProxy(const GURL& url, ResolveProxyCallback callback); - void ClearCache(const net::CompletionCallback& callback); + template + void DoCacheAction(const net::CompletionCallback& callback); void ClearStorageData(mate::Arguments* args); void FlushStorageData(); void SetProxy(const net::ProxyConfig& config, const base::Closure& callback); diff --git a/docs/api/session.md b/docs/api/session.md index 9dd2bca0ed7b..ffed58797c43 100644 --- a/docs/api/session.md +++ b/docs/api/session.md @@ -159,6 +159,13 @@ on complete. Removes the cookies matching `url` and `name`, `callback` will called with `callback()` on complete. +#### `ses.getCacheSize(callback)` + +* `callback` Function + * `size` Integer - Cache size used in bytes. + +Returns the session's current cache size. + #### `ses.clearCache(callback)` * `callback` Function - Called when operation is done From 26350f4ccb7783e3ec5d6f6ff3328c5ba56677e8 Mon Sep 17 00:00:00 2001 From: Cheng Zhao Date: Thu, 14 Jan 2016 20:48:14 +0800 Subject: [PATCH 69/95] GetHttpCacheInIO => DoCacheActionInIO --- atom/browser/api/atom_api_session.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/atom/browser/api/atom_api_session.cc b/atom/browser/api/atom_api_session.cc index 5f227fb82f2c..1cc76ebfa23d 100644 --- a/atom/browser/api/atom_api_session.cc +++ b/atom/browser/api/atom_api_session.cc @@ -239,7 +239,7 @@ void OnGetBackend(disk_cache::Backend** backend_ptr, } } -void GetHttpCacheInIO( +void DoCacheActionInIO( const scoped_refptr& context_getter, Session::CacheAction action, const net::CompletionCallback& callback) { @@ -307,7 +307,7 @@ void Session::ResolveProxy(const GURL& url, ResolveProxyCallback callback) { template void Session::DoCacheAction(const net::CompletionCallback& callback) { BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, - base::Bind(&GetHttpCacheInIO, + base::Bind(&DoCacheActionInIO, make_scoped_refptr(browser_context_->GetRequestContext()), action, callback)); From ad9c2547309b765a9810184eec9c29edced6267f Mon Sep 17 00:00:00 2001 From: Ming Luo Date: Thu, 14 Jan 2016 09:27:24 -0500 Subject: [PATCH 70/95] Styled the removeListener & removeAllListeners They were previously not written with the same style as other parts of the doc. Also there was a couple grammar errors --- docs/api/ipc-main.md | 22 +++++++++++----------- docs/api/ipc-renderer.md | 17 ++++++++--------- 2 files changed, 19 insertions(+), 20 deletions(-) diff --git a/docs/api/ipc-main.md b/docs/api/ipc-main.md index 87430e7e9966..337d86be217b 100644 --- a/docs/api/ipc-main.md +++ b/docs/api/ipc-main.md @@ -53,12 +53,8 @@ The `ipcMain` module has the following method to listen for events: * `channel` String - The event name. * `callback` Function -When the event occurs the `callback` is called with an `event` object and a -message, `arg`. - -Once done listening for messages, if you longer want to activate this callback -and for whatever reason can't merely stop sending messages on the channel, you -can use: +When the event occurs the `callback` is called with an `event` object and +arbitrary arguments. ### `ipcMain.removeListener(channel, callback)` @@ -66,17 +62,21 @@ can use: * `callback` Function - The reference to the same function that you used for `ipcMain.on(channel, callback)` -Alternatively, if you don't have access to the same callback, you can use: +Once done listening for messages, if you no longer want to activate this +callback and for whatever reason can't merely stop sending messages on the +channel, this function will remove the callback handler for the specified +channel. ### `ipcMain.removeAllListeners(channel)` * `channel` String - The event name. -This has the expected effect of removing *all* handlers to this ipc channel. +This removes *all* handlers to this ipc channel. -Because of this class' inheritance from the `EventEmitter` node class, you can -also use `ipcMain.once(channel, callback)` to fire handlers meant to occur only -once, as in, they won't be activated after one call of `callback` +### `ipcMain.once(channel, callback)` + +Use this in place of `ipcMain.on()` to fire handlers meant to occur only once, +as in, they won't be activated after one call of `callback` ## IPC Event diff --git a/docs/api/ipc-renderer.md b/docs/api/ipc-renderer.md index d88b477ea714..090fd1a9119d 100644 --- a/docs/api/ipc-renderer.md +++ b/docs/api/ipc-renderer.md @@ -20,28 +20,27 @@ The `ipcRenderer` module has the following method to listen for events: When the event occurs the `callback` is called with an `event` object and arbitrary arguments. -Once done listening for messages, if you longer want to activate this callback -and for whatever reason can't merely stop sending messages on the channel, you -can use: - ### `ipcRenderer.removeListener(channel, callback)` * `channel` String - The event name. * `callback` Function - The reference to the same function that you used for `ipcRenderer.on(channel, callback)` -Alternatively, if you don't have access to the same callback, you can use: +Once done listening for messages, if you no longer want to activate this +callback and for whatever reason can't merely stop sending messages on the +channel, this function will remove the callback handler for the specified +channel. ### `ipcRenderer.removeAllListeners(channel)` * `channel` String - The event name. -This has the expected effect of removing *all* handlers to this ipc channel. +This removes *all* handlers to this ipc channel. -Because of this class' inheritance from the `EventEmitter` node class, you can -also use `ipcRenderer.once(channel, callback)` to fire handlers meant to occur only -once, as in, they won't be activated after one call of `callback` +### `ipcMain.once(channel, callback)` +Use this in place of `ipcMain.on()` to fire handlers meant to occur only once, +as in, they won't be activated after one call of `callback` ## Sending Messages From f4af744519561952c8fb2c95b1eb5773e9d669f3 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Thu, 14 Jan 2016 10:35:29 -0800 Subject: [PATCH 71/95] Use // for single line comments --- atom/browser/api/lib/app.js | 14 ++--- atom/browser/api/lib/auto-updater.js | 2 +- .../api/lib/auto-updater/auto-updater-win.js | 2 +- .../lib/auto-updater/squirrel-update-win.js | 22 ++++---- atom/browser/api/lib/browser-window.js | 22 ++++---- atom/browser/api/lib/dialog.js | 8 +-- atom/browser/api/lib/exports/electron.js | 6 +-- atom/browser/api/lib/ipc.js | 2 +- atom/browser/api/lib/menu-item.js | 6 +-- atom/browser/api/lib/menu.js | 32 ++++++------ atom/browser/api/lib/navigation-controller.js | 14 ++--- atom/browser/api/lib/protocol.js | 2 +- atom/browser/api/lib/session.js | 6 +-- atom/browser/api/lib/tray.js | 4 +- atom/browser/api/lib/web-contents.js | 16 +++--- atom/browser/lib/chrome-extension.js | 18 +++---- atom/browser/lib/desktop-capturer.js | 6 +-- atom/browser/lib/guest-view-manager.js | 30 +++++------ atom/browser/lib/guest-window-manager.js | 14 ++--- atom/browser/lib/init.js | 46 ++++++++--------- atom/browser/lib/objects-registry.js | 16 +++--- atom/browser/lib/rpc-server.js | 20 ++++---- atom/common/api/lib/callbacks-registry.js | 2 +- atom/common/api/lib/clipboard.js | 2 +- atom/common/api/lib/crash-reporter.js | 2 +- atom/common/api/lib/deprecate.js | 16 +++--- atom/common/api/lib/exports/electron.js | 12 ++--- atom/common/api/lib/native-image.js | 2 +- atom/common/lib/asar.js | 30 +++++------ atom/common/lib/asar_init.js | 6 +-- atom/common/lib/init.js | 2 +- atom/common/lib/reset-search-paths.js | 10 ++-- atom/renderer/api/lib/desktop-capturer.js | 2 +- atom/renderer/api/lib/exports/electron.js | 4 +- atom/renderer/api/lib/ipc-renderer.js | 2 +- atom/renderer/api/lib/ipc.js | 6 +-- atom/renderer/api/lib/remote.js | 50 +++++++++--------- atom/renderer/lib/init.js | 38 +++++++------- atom/renderer/lib/inspector.js | 6 +-- atom/renderer/lib/override.js | 28 +++++----- .../lib/web-view/web-view-attributes.js | 36 ++++++------- .../lib/web-view/web-view-constants.js | 6 +-- atom/renderer/lib/web-view/web-view.js | 51 ++++++++++--------- 43 files changed, 311 insertions(+), 310 deletions(-) diff --git a/atom/browser/api/lib/app.js b/atom/browser/api/lib/app.js index 84b0c3c77e89..7d0d0694147d 100644 --- a/atom/browser/api/lib/app.js +++ b/atom/browser/api/lib/app.js @@ -54,7 +54,7 @@ app.getAppPath = function() { }; -/* Routes the events to webContents. */ +// Routes the events to webContents. ref1 = ['login', 'certificate-error', 'select-client-certificate']; fn = function(name) { @@ -70,7 +70,7 @@ for (i = 0, len = ref1.length; i < len; i++) { } -/* Deprecated. */ +// Deprecated. app.getHomeDir = deprecate('app.getHomeDir', 'app.getPath', function() { return this.getPath('home'); @@ -92,7 +92,7 @@ deprecate.rename(app, 'terminate', 'quit'); deprecate.event(app, 'finish-launching', 'ready', function() { - /* give default app a chance to setup default menu. */ + // give default app a chance to setup default menu. return setImmediate((function(_this) { return function() { return _this.emit('finish-launching'); @@ -109,14 +109,14 @@ deprecate.event(app, 'activate-with-no-open-windows', 'activate', function(event deprecate.event(app, 'select-certificate', 'select-client-certificate'); -/* Wrappers for native classes. */ +// Wrappers for native classes. wrapDownloadItem = function(downloadItem) { - /* downloadItem is an EventEmitter. */ + // downloadItem is an EventEmitter. downloadItem.__proto__ = EventEmitter.prototype; - /* Deprecated. */ + // Deprecated. deprecate.property(downloadItem, 'url', 'getURL'); deprecate.property(downloadItem, 'filename', 'getFilename'); deprecate.property(downloadItem, 'mimeType', 'getMimeType'); @@ -126,6 +126,6 @@ wrapDownloadItem = function(downloadItem) { downloadItemBindings._setWrapDownloadItem(wrapDownloadItem); -/* Only one App object pemitted. */ +// Only one App object pemitted. module.exports = app; diff --git a/atom/browser/api/lib/auto-updater.js b/atom/browser/api/lib/auto-updater.js index 5a7d2472f612..e8e447ab1802 100644 --- a/atom/browser/api/lib/auto-updater.js +++ b/atom/browser/api/lib/auto-updater.js @@ -5,7 +5,7 @@ deprecate = require('electron').deprecate; autoUpdater = process.platform === 'win32' ? require('./auto-updater/auto-updater-win') : require('./auto-updater/auto-updater-native'); -/* Deprecated. */ +// Deprecated. deprecate.rename(autoUpdater, 'setFeedUrl', 'setFeedURL'); diff --git a/atom/browser/api/lib/auto-updater/auto-updater-win.js b/atom/browser/api/lib/auto-updater/auto-updater-win.js index b2ef7361d2d3..7d62809a56ce 100644 --- a/atom/browser/api/lib/auto-updater/auto-updater-win.js +++ b/atom/browser/api/lib/auto-updater/auto-updater-win.js @@ -50,7 +50,7 @@ AutoUpdater = (function(superClass) { } releaseNotes = update.releaseNotes, version = update.version; - /* Following information is not available on Windows, so fake them. */ + // Following information is not available on Windows, so fake them. date = new Date; url = _this.updateURL; return _this.emit('update-downloaded', {}, releaseNotes, version, date, url, function() { diff --git a/atom/browser/api/lib/auto-updater/squirrel-update-win.js b/atom/browser/api/lib/auto-updater/squirrel-update-win.js index 205f08ce34f9..78c127eae46b 100644 --- a/atom/browser/api/lib/auto-updater/squirrel-update-win.js +++ b/atom/browser/api/lib/auto-updater/squirrel-update-win.js @@ -7,12 +7,12 @@ path = require('path'); spawn = require('child_process').spawn; -/* i.e. my-app/app-0.1.13/ */ +// i.e. my-app/app-0.1.13/ appFolder = path.dirname(process.execPath); -/* i.e. my-app/Update.exe */ +// i.e. my-app/Update.exe updateExe = path.resolve(appFolder, '..', 'Update.exe'); @@ -33,7 +33,7 @@ spawnUpdate = function(args, detached, callback) { } catch (error1) { error = error1; - /* Shouldn't happen, but still guard it. */ + // Shouldn't happen, but still guard it. process.nextTick(function() { return callback(error); }); @@ -54,30 +54,30 @@ spawnUpdate = function(args, detached, callback) { }); return spawnedProcess.on('exit', function(code, signal) { - /* We may have already emitted an error. */ + // We may have already emitted an error. if (errorEmitted) { return; } - /* Process terminated with error. */ + // Process terminated with error. if (code !== 0) { return callback("Command failed: " + (signal != null ? signal : code) + "\n" + stderr); } - /* Success. */ + // Success. return callback(null, stdout); }); }; -/* Start an instance of the installed app. */ +// Start an instance of the installed app. exports.processStart = function(callback) { return spawnUpdate(['--processStart', exeName], true, function() {}); }; -/* Download the releases specified by the URL and write new results to stdout. */ +// Download the releases specified by the URL and write new results to stdout. exports.download = function(updateURL, callback) { return spawnUpdate(['--download', updateURL], false, function(error, stdout) { @@ -87,7 +87,7 @@ exports.download = function(updateURL, callback) { } try { - /* Last line of output is the JSON details about the releases */ + // Last line of output is the JSON details about the releases json = stdout.trim().split('\n').pop(); update = (ref = JSON.parse(json)) != null ? (ref1 = ref.releasesToApply) != null ? typeof ref1.pop === "function" ? ref1.pop() : void 0 : void 0 : void 0; } catch (error1) { @@ -98,14 +98,14 @@ exports.download = function(updateURL, callback) { }; -/* Update the application to the latest remote version specified by URL. */ +// Update the application to the latest remote version specified by URL. exports.update = function(updateURL, callback) { return spawnUpdate(['--update', updateURL], false, callback); }; -/* Is the Update.exe installed with the current application? */ +// Is the Update.exe installed with the current application? exports.supported = function() { var error1; diff --git a/atom/browser/api/lib/browser-window.js b/atom/browser/api/lib/browser-window.js index 694c7c25e237..f3b297ebbaf2 100644 --- a/atom/browser/api/lib/browser-window.js +++ b/atom/browser/api/lib/browser-window.js @@ -10,11 +10,11 @@ BrowserWindow.prototype.__proto__ = EventEmitter.prototype; BrowserWindow.prototype._init = function() { - /* avoid recursive require. */ + // avoid recursive require. var app, menu; app = require('electron').app; - /* Simulate the application menu on platforms other than OS X. */ + // Simulate the application menu on platforms other than OS X. if (process.platform !== 'darwin') { menu = app.getApplicationMenu(); if (menu != null) { @@ -22,7 +22,7 @@ BrowserWindow.prototype._init = function() { } } - /* Make new windows requested by links behave like "window.open" */ + // Make new windows requested by links behave like "window.open" this.webContents.on('-new-window', function(event, url, frameName) { var options; options = { @@ -43,7 +43,7 @@ BrowserWindow.prototype._init = function() { }; })(this)); - /* Hide the auto-hide menu when webContents is focused. */ + // Hide the auto-hide menu when webContents is focused. this.webContents.on('activate', (function(_this) { return function() { if (process.platform !== 'darwin' && _this.isMenuBarAutoHide() && _this.isMenuBarVisible()) { @@ -52,14 +52,14 @@ BrowserWindow.prototype._init = function() { }; })(this)); - /* Forward the crashed event. */ + // Forward the crashed event. this.webContents.on('crashed', (function(_this) { return function() { return _this.emit('crashed'); }; })(this)); - /* Change window title to page title. */ + // Change window title to page title. this.webContents.on('page-title-updated', (function(_this) { return function(event, title, explicitSet) { _this.emit('page-title-updated', event, title); @@ -81,7 +81,7 @@ BrowserWindow.prototype._init = function() { return this.focus(); }); - /* Redirect focus/blur event to app instance too. */ + // Redirect focus/blur event to app instance too. this.on('blur', (function(_this) { return function(event) { return app.emit('browser-window-blur', event, _this); @@ -93,10 +93,10 @@ BrowserWindow.prototype._init = function() { }; })(this)); - /* Notify the creation of the window. */ + // Notify the creation of the window. app.emit('browser-window-created', {}, this); - /* Be compatible with old APIs. */ + // Be compatible with old APIs. this.webContents.on('devtools-focused', (function(_this) { return function() { return _this.emit('devtools-focused'); @@ -156,7 +156,7 @@ BrowserWindow.fromDevToolsWebContents = function(webContents) { }; -/* Helpers. */ +// Helpers. BrowserWindow.prototype.loadURL = function() { return this.webContents.loadURL.apply(this.webContents, arguments); @@ -203,7 +203,7 @@ BrowserWindow.prototype.inspectServiceWorker = function() { }; -/* Deprecated. */ +// Deprecated. deprecate.member(BrowserWindow, 'undo', 'webContents'); diff --git a/atom/browser/api/lib/dialog.js b/atom/browser/api/lib/dialog.js index 5210e5d20a25..9932988216ad 100644 --- a/atom/browser/api/lib/dialog.js +++ b/atom/browser/api/lib/dialog.js @@ -24,14 +24,14 @@ messageBoxOptions = { parseArgs = function(window, options, callback) { if (!(window === null || (window != null ? window.constructor : void 0) === BrowserWindow)) { - /* Shift. */ + // Shift. callback = options; options = window; window = null; } if ((callback == null) && typeof options === 'function') { - /* Shift. */ + // Shift. callback = options; options = null; } @@ -143,7 +143,7 @@ module.exports = { options.defaultId = -1; } - /* Choose a default button to get selected when dialog is cancelled. */ + // Choose a default button to get selected when dialog is cancelled. if (options.cancelId == null) { options.cancelId = 0; ref2 = options.buttons; @@ -166,7 +166,7 @@ module.exports = { }; -/* Mark standard asynchronous functions. */ +// Mark standard asynchronous functions. ref1 = ['showMessageBox', 'showOpenDialog', 'showSaveDialog']; for (j = 0, len = ref1.length; j < len; j++) { diff --git a/atom/browser/api/lib/exports/electron.js b/atom/browser/api/lib/exports/electron.js index 5ded35a401fb..2ec917d16eba 100644 --- a/atom/browser/api/lib/exports/electron.js +++ b/atom/browser/api/lib/exports/electron.js @@ -3,13 +3,13 @@ var common; common = require('../../../../common/api/lib/exports/electron'); -/* Import common modules. */ +// Import common modules. common.defineProperties(exports); Object.defineProperties(exports, { - /* Browser side modules, please sort with alphabet order. */ + // Browser side modules, please sort with alphabet order. app: { enumerable: true, get: function() { @@ -101,7 +101,7 @@ Object.defineProperties(exports, { } }, - /* The internal modules, invisible unless you know their names. */ + // The internal modules, invisible unless you know their names. NavigationController: { get: function() { return require('../navigation-controller'); diff --git a/atom/browser/api/lib/ipc.js b/atom/browser/api/lib/ipc.js index 162e56bea2c1..e314f9360178 100644 --- a/atom/browser/api/lib/ipc.js +++ b/atom/browser/api/lib/ipc.js @@ -3,7 +3,7 @@ var deprecate, ipcMain, ref; ref = require('electron'), deprecate = ref.deprecate, ipcMain = ref.ipcMain; -/* This module is deprecated, we mirror everything from ipcMain. */ +// This module is deprecated, we mirror everything from ipcMain. deprecate.warn('ipc module', 'require("electron").ipcMain'); diff --git a/atom/browser/api/lib/menu-item.js b/atom/browser/api/lib/menu-item.js index 22d6c251f5e9..2e0980983c50 100644 --- a/atom/browser/api/lib/menu-item.js +++ b/atom/browser/api/lib/menu-item.js @@ -5,7 +5,7 @@ v8Util = process.atomBinding('v8_util'); nextCommandId = 0; -/* Maps role to methods of webContents */ +// Maps role to methods of webContents rolesMap = { undo: 'undo', @@ -19,7 +19,7 @@ rolesMap = { }; -/* Maps methods that should be called directly on the BrowserWindow instance */ +// Maps methods that should be called directly on the BrowserWindow instance methodInBrowserWindow = { minimize: true, @@ -59,7 +59,7 @@ MenuItem = (function() { this.click = (function(_this) { return function(focusedWindow) { - /* Manually flip the checked flags when clicked. */ + // Manually flip the checked flags when clicked. var methodName, ref1, ref2; if ((ref1 = _this.type) === 'checkbox' || ref1 === 'radio') { _this.checked = !_this.checked; diff --git a/atom/browser/api/lib/menu.js b/atom/browser/api/lib/menu.js index 6ca5c9adde43..69b3b3a80b73 100644 --- a/atom/browser/api/lib/menu.js +++ b/atom/browser/api/lib/menu.js @@ -9,15 +9,15 @@ v8Util = process.atomBinding('v8_util'); bindings = process.atomBinding('menu'); -/* Automatically generated radio menu item's group id. */ +// Automatically generated radio menu item's group id. nextGroupId = 0; -/* Search between seperators to find a radio menu item and return its group id, */ +// Search between seperators to find a radio menu item and return its group id, -/* otherwise generate a group id. */ +// otherwise generate a group id. generateGroupId = function(items, pos) { var i, item, j, k, ref1, ref2, ref3; @@ -46,7 +46,7 @@ generateGroupId = function(items, pos) { }; -/* Returns the index of item according to |id|. */ +// Returns the index of item according to |id|. indexOfItemById = function(items, id) { var i, item, j, len; @@ -60,7 +60,7 @@ indexOfItemById = function(items, id) { }; -/* Returns the index of where to insert the item according to |position|. */ +// Returns the index of where to insert the item according to |position|. indexToInsertByPosition = function(items, position) { var id, insertIndex, query, ref1; @@ -79,7 +79,7 @@ indexToInsertByPosition = function(items, position) { break; case 'endof': - /* If the |id| doesn't exist, then create a new group with the |id|. */ + // If the |id| doesn't exist, then create a new group with the |id|. if (insertIndex === -1) { items.push({ id: id, @@ -88,7 +88,7 @@ indexToInsertByPosition = function(items, position) { insertIndex = items.length - 1; } - /* Find the end of the group. */ + // Find the end of the group. insertIndex++; while (insertIndex < items.length && items[insertIndex].type !== 'separator') { insertIndex++; @@ -145,7 +145,7 @@ Menu.prototype._init = function() { menuWillShow: (function(_this) { return function() { - /* Make sure radio groups have at least one menu item seleted. */ + // Make sure radio groups have at least one menu item seleted. var checked, group, id, j, len, radioItem, ref1, results; ref1 = _this.groupsMap; results = []; @@ -175,7 +175,7 @@ Menu.prototype._init = function() { Menu.prototype.popup = function(window, x, y) { if ((window != null ? window.constructor : void 0) !== BrowserWindow) { - /* Shift. */ + // Shift. y = x; x = window; window = BrowserWindow.getFocusedWindow(); @@ -211,14 +211,14 @@ Menu.prototype.insert = function(pos, item) { break; case 'radio': - /* Grouping radio menu items. */ + // Grouping radio menu items. item.overrideReadOnlyProperty('groupId', generateGroupId(this.items, pos)); if ((base = this.groupsMap)[name = item.groupId] == null) { base[name] = []; } this.groupsMap[item.groupId].push(item); - /* Setting a radio menu item should flip other items in the group. */ + // Setting a radio menu item should flip other items in the group. v8Util.setHiddenValue(item, 'checked', item.checked); Object.defineProperty(item, 'checked', { enumerable: true, @@ -251,16 +251,16 @@ Menu.prototype.insert = function(pos, item) { this.setRole(pos, item.role); } - /* Make menu accessable to items. */ + // Make menu accessable to items. item.overrideReadOnlyProperty('menu', this); - /* Remember the items. */ + // Remember the items. this.items.splice(pos, 0, item); return this.commandsMap[item.commandId] = item; }; -/* Force menuWillShow to be called */ +// Force menuWillShow to be called Menu.prototype._callMenuWillShow = function() { var item, j, len, ref1, ref2, results; @@ -286,7 +286,7 @@ Menu.setApplicationMenu = function(menu) { throw new TypeError('Invalid menu'); } - /* Keep a reference. */ + // Keep a reference. applicationMenu = menu; if (process.platform === 'darwin') { if (menu === null) { @@ -324,7 +324,7 @@ Menu.buildFromTemplate = function(template) { insertIndex = indexToInsertByPosition(positionedTemplate, item.position); } else { - /* If no |position| is specified, insert after last item. */ + // If no |position| is specified, insert after last item. insertIndex++; } positionedTemplate.splice(insertIndex, 0, item); diff --git a/atom/browser/api/lib/navigation-controller.js b/atom/browser/api/lib/navigation-controller.js index 8e7753de5e3b..ff9b440a9164 100644 --- a/atom/browser/api/lib/navigation-controller.js +++ b/atom/browser/api/lib/navigation-controller.js @@ -4,7 +4,7 @@ var NavigationController, ipcMain, ipcMain = require('electron').ipcMain; -/* The history operation in renderer is redirected to browser. */ +// The history operation in renderer is redirected to browser. ipcMain.on('ATOM_SHELL_NAVIGATION_CONTROLLER', function() { var args, event, method, ref; @@ -32,7 +32,7 @@ NavigationController = (function() { this.webContents = webContents; this.clearHistory(); - /* webContents may have already navigated to a page. */ + // webContents may have already navigated to a page. if (this.webContents._getURL()) { this.currentIndex++; this.history.push(this.webContents._getURL()); @@ -42,26 +42,26 @@ NavigationController = (function() { var currentEntry; if (_this.inPageIndex > -1 && !inPage) { - /* Navigated to a new page, clear in-page mark. */ + // Navigated to a new page, clear in-page mark. _this.inPageIndex = -1; } else if (_this.inPageIndex === -1 && inPage) { - /* Started in-page navigations. */ + // Started in-page navigations. _this.inPageIndex = _this.currentIndex; } if (_this.pendingIndex >= 0) { - /* Go to index. */ + // Go to index. _this.currentIndex = _this.pendingIndex; _this.pendingIndex = -1; return _this.history[_this.currentIndex] = url; } else if (replaceEntry) { - /* Non-user initialized navigation. */ + // Non-user initialized navigation. return _this.history[_this.currentIndex] = url; } else { - /* Normal navigation. Clear history. */ + // Normal navigation. Clear history. _this.history = _this.history.slice(0, _this.currentIndex + 1); currentEntry = _this.history[_this.currentIndex]; if ((currentEntry != null ? currentEntry.url : void 0) !== url) { diff --git a/atom/browser/api/lib/protocol.js b/atom/browser/api/lib/protocol.js index d601e588cf32..dc92c676485f 100644 --- a/atom/browser/api/lib/protocol.js +++ b/atom/browser/api/lib/protocol.js @@ -9,7 +9,7 @@ if (!app.isReady()) { protocol = process.atomBinding('protocol').protocol; -/* Warn about removed APIs. */ +// Warn about removed APIs. logAndThrow = function(callback, message) { console.error(message); diff --git a/atom/browser/api/lib/session.js b/atom/browser/api/lib/session.js index fa43a2ae219d..d3b889cc09d3 100644 --- a/atom/browser/api/lib/session.js +++ b/atom/browser/api/lib/session.js @@ -7,7 +7,7 @@ bindings = process.atomBinding('session'); PERSIST_PERFIX = 'persist:'; -/* Returns the Session from |partition| string. */ +// Returns the Session from |partition| string. exports.fromPartition = function(partition) { if (partition == null) { @@ -24,7 +24,7 @@ exports.fromPartition = function(partition) { }; -/* Returns the default session. */ +// Returns the default session. Object.defineProperty(exports, 'defaultSession', { enumerable: true, @@ -35,7 +35,7 @@ Object.defineProperty(exports, 'defaultSession', { wrapSession = function(session) { - /* session is an EventEmitter. */ + // session is an EventEmitter. return session.__proto__ = EventEmitter.prototype; }; diff --git a/atom/browser/api/lib/tray.js b/atom/browser/api/lib/tray.js index 822bf31eb3af..db692a089372 100644 --- a/atom/browser/api/lib/tray.js +++ b/atom/browser/api/lib/tray.js @@ -10,7 +10,7 @@ Tray.prototype.__proto__ = EventEmitter.prototype; Tray.prototype._init = function() { - /* Deprecated. */ + // Deprecated. deprecate.rename(this, 'popContextMenu', 'popUpContextMenu'); deprecate.event(this, 'clicked', 'click'); deprecate.event(this, 'double-clicked', 'double-click'); @@ -21,7 +21,7 @@ Tray.prototype._init = function() { Tray.prototype.setContextMenu = function(menu) { this._setContextMenu(menu); - /* Keep a strong reference of menu. */ + // Keep a strong reference of menu. return this.menu = menu; }; diff --git a/atom/browser/api/lib/web-contents.js b/atom/browser/api/lib/web-contents.js index f502076755f0..c7d6786b17b2 100644 --- a/atom/browser/api/lib/web-contents.js +++ b/atom/browser/api/lib/web-contents.js @@ -66,18 +66,18 @@ const webFrameMethods = [ wrapWebContents = function(webContents) { - /* webContents is an EventEmitter. */ + // webContents is an EventEmitter. var controller, method, name, ref1; webContents.__proto__ = EventEmitter.prototype; - /* WebContents::send(channel, args..) */ + // WebContents::send(channel, args..) webContents.send = function() { var args, channel; channel = arguments[0], args = 2 <= arguments.length ? slice.call(arguments, 1) : []; return this._send(channel, slice.call(args)); }; - /* The navigation controller. */ + // The navigation controller. controller = new NavigationController(webContents); ref1 = NavigationController.prototype; for (name in ref1) { @@ -109,7 +109,7 @@ wrapWebContents = function(webContents) { return this.once('did-finish-load', executeJavaScript.bind(this, code, hasUserGesture)); }; - /* Dispatch IPC messages to the ipc module. */ + // Dispatch IPC messages to the ipc module. webContents.on('ipc-message', function(event, packed) { var args, channel; channel = packed[0], args = 2 <= packed.length ? slice.call(packed, 1) : []; @@ -126,14 +126,14 @@ wrapWebContents = function(webContents) { return ipcMain.emit.apply(ipcMain, [channel, event].concat(slice.call(args))); }); - /* Handle context menu action request from pepper plugin. */ + // Handle context menu action request from pepper plugin. webContents.on('pepper-context-menu', function(event, params) { var menu; menu = Menu.buildFromTemplate(params.menu); return menu.popup(params.x, params.y); }); - /* This error occurs when host could not be found. */ + // This error occurs when host could not be found. webContents.on('did-fail-provisional-load', function() { var args; args = 1 <= arguments.length ? slice.call(arguments, 0) : []; @@ -149,7 +149,7 @@ wrapWebContents = function(webContents) { })(this)); }); - /* Delays the page-title-updated event to next tick. */ + // Delays the page-title-updated event to next tick. webContents.on('-page-title-updated', function() { var args; args = 1 <= arguments.length ? slice.call(arguments, 0) : []; @@ -160,7 +160,7 @@ wrapWebContents = function(webContents) { })(this)); }); - /* Deprecated. */ + // Deprecated. deprecate.rename(webContents, 'loadUrl', 'loadURL'); deprecate.rename(webContents, 'getUrl', 'getURL'); deprecate.event(webContents, 'page-title-set', 'page-title-updated', function() { diff --git a/atom/browser/lib/chrome-extension.js b/atom/browser/lib/chrome-extension.js index e4de0b6779b3..80b3e0e644dd 100644 --- a/atom/browser/lib/chrome-extension.js +++ b/atom/browser/lib/chrome-extension.js @@ -9,7 +9,7 @@ path = require('path'); url = require('url'); -/* Mapping between hostname and file path. */ +// Mapping between hostname and file path. hostPathMap = {}; @@ -27,7 +27,7 @@ getPathForHost = function(host) { }; -/* Cache extensionInfo. */ +// Cache extensionInfo. extensionInfoMap = {}; @@ -57,14 +57,14 @@ getExtensionInfoFromPath = function(srcDirectory) { }; -/* The loaded extensions cache and its persistent path. */ +// The loaded extensions cache and its persistent path. loadedExtensions = null; loadedExtensionsPath = null; -/* Persistent loaded extensions. */ +// Persistent loaded extensions. app = electron.app; @@ -86,13 +86,13 @@ app.on('will-quit', function() { }); -/* We can not use protocol or BrowserWindow until app is ready. */ +// We can not use protocol or BrowserWindow until app is ready. app.once('ready', function() { var BrowserWindow, chromeExtensionHandler, e, error1, i, init, len, protocol, srcDirectory; protocol = electron.protocol, BrowserWindow = electron.BrowserWindow; - /* Load persistented extensions. */ + // Load persistented extensions. loadedExtensionsPath = path.join(app.getPath('userData'), 'DevTools Extensions'); try { loadedExtensions = JSON.parse(fs.readFileSync(loadedExtensionsPath)); @@ -100,7 +100,7 @@ app.once('ready', function() { loadedExtensions = []; } - /* Preheat the extensionInfo cache. */ + // Preheat the extensionInfo cache. for (i = 0, len = loadedExtensions.length; i < len; i++) { srcDirectory = loadedExtensions[i]; getExtensionInfoFromPath(srcDirectory); @@ -109,7 +109,7 @@ app.once('ready', function() { e = error1; } - /* The chrome-extension: can map a extension URL request to real file path. */ + // The chrome-extension: can map a extension URL request to real file path. chromeExtensionHandler = function(request, callback) { var directory, parsed; parsed = url.parse(request.url); @@ -150,7 +150,7 @@ app.once('ready', function() { return delete extensionInfoMap[name]; }; - /* Load persistented extensions when devtools is opened. */ + // Load persistented extensions when devtools is opened. init = BrowserWindow.prototype._init; return BrowserWindow.prototype._init = function() { init.call(this); diff --git a/atom/browser/lib/desktop-capturer.js b/atom/browser/lib/desktop-capturer.js index 789aa37ebc8d..2ebb3d2fa227 100644 --- a/atom/browser/lib/desktop-capturer.js +++ b/atom/browser/lib/desktop-capturer.js @@ -9,7 +9,7 @@ deepEqual = function(opt1, opt2) { }; -/* A queue for holding all requests from renderer process. */ +// A queue for holding all requests from renderer process. requestsQueue = []; @@ -40,7 +40,7 @@ ipcMain.on('ATOM_BROWSER_DESKTOP_CAPTURER_GET_SOURCES', function(event, captureW desktopCapturer.emit = function(event, name, sources) { - /* Receiving sources result from main process, now send them back to renderer. */ + // Receiving sources result from main process, now send them back to renderer. var captureScreen, captureWindow, handledRequest, i, len, ref, ref1, ref2, request, result, source, thumbnailSize, unhandledRequestsQueue; handledRequest = requestsQueue.shift(0); result = (function() { @@ -77,7 +77,7 @@ desktopCapturer.emit = function(event, name, sources) { } requestsQueue = unhandledRequestsQueue; - /* If the requestsQueue is not empty, start a new request handling. */ + // If the requestsQueue is not empty, start a new request handling. if (requestsQueue.length > 0) { ref2 = requestsQueue[0].options, captureWindow = ref2.captureWindow, captureScreen = ref2.captureScreen, thumbnailSize = ref2.thumbnailSize; return desktopCapturer.startHandling(captureWindow, captureScreen, thumbnailSize); diff --git a/atom/browser/lib/guest-view-manager.js b/atom/browser/lib/guest-view-manager.js index 83f1f6ac2e18..2560c8e0a641 100644 --- a/atom/browser/lib/guest-view-manager.js +++ b/atom/browser/lib/guest-view-manager.js @@ -4,7 +4,7 @@ var attachGuest, createGuest, destroyGuest, embedderElementsMap, getNextInstance ref = require('electron'), ipcMain = ref.ipcMain, webContents = ref.webContents; -/* Doesn't exist in early initialization. */ +// Doesn't exist in early initialization. webViewManager = null; @@ -19,21 +19,21 @@ embedderElementsMap = {}; reverseEmbedderElementsMap = {}; -/* Moves the last element of array to the first one. */ +// Moves the last element of array to the first one. moveLastToFirst = function(list) { return list.unshift(list.pop()); }; -/* Generate guestInstanceId. */ +// Generate guestInstanceId. getNextInstanceId = function(webContents) { return ++nextInstanceId; }; -/* Create a new guest instance. */ +// Create a new guest instance. createGuest = function(embedder, params) { var destroy, destroyEvents, event, fn, guest, i, id, j, len, len1, listeners; @@ -51,7 +51,7 @@ createGuest = function(embedder, params) { embedder: embedder }; - /* Destroy guest when the embedder is gone or navigated. */ + // Destroy guest when the embedder is gone or navigated. destroyEvents = ['will-destroy', 'crashed', 'did-navigate']; destroy = function() { if (guestInstances[id] != null) { @@ -82,7 +82,7 @@ createGuest = function(embedder, params) { return results; }); - /* Init guest web view after attached. */ + // Init guest web view after attached. guest.once('did-attach', function() { var opts; params = this.attachParams; @@ -119,7 +119,7 @@ createGuest = function(embedder, params) { return guest.allowPopups = params.allowpopups; }); - /* Dispatch events to embedder. */ + // Dispatch events to embedder. fn = function(event) { return guest.on(event, function() { var _, args; @@ -132,14 +132,14 @@ createGuest = function(embedder, params) { fn(event); } - /* Dispatch guest's IPC messages to embedder. */ + // Dispatch guest's IPC messages to embedder. guest.on('ipc-message-host', function(_, packed) { var args, channel; channel = packed[0], args = 2 <= packed.length ? slice.call(packed, 1) : []; return embedder.send.apply(embedder, ["ATOM_SHELL_GUEST_VIEW_INTERNAL_IPC_MESSAGE-" + guest.viewInstanceId, channel].concat(slice.call(args))); }); - /* Autosize. */ + // Autosize. guest.on('size-changed', function() { var _, args; _ = arguments[0], args = 2 <= arguments.length ? slice.call(arguments, 1) : []; @@ -149,18 +149,18 @@ createGuest = function(embedder, params) { }; -/* Attach the guest to an element of embedder. */ +// Attach the guest to an element of embedder. attachGuest = function(embedder, elementInstanceId, guestInstanceId, params) { var guest, key, oldGuestInstanceId, ref1, webPreferences; guest = guestInstances[guestInstanceId].guest; - /* Destroy the old guest when attaching. */ + // Destroy the old guest when attaching. key = (embedder.getId()) + "-" + elementInstanceId; oldGuestInstanceId = embedderElementsMap[key]; if (oldGuestInstanceId != null) { - /* Reattachment to the same guest is not currently supported. */ + // Reattachment to the same guest is not currently supported. if (oldGuestInstanceId === guestInstanceId) { return; } @@ -185,7 +185,7 @@ attachGuest = function(embedder, elementInstanceId, guestInstanceId, params) { }; -/* Destroy an existing guest instance. */ +// Destroy an existing guest instance. destroyGuest = function(embedder, id) { var key; @@ -222,7 +222,7 @@ ipcMain.on('ATOM_SHELL_GUEST_VIEW_MANAGER_SET_ALLOW_TRANSPARENCY', function(even }); -/* Returns WebContents from its guest id. */ +// Returns WebContents from its guest id. exports.getGuest = function(id) { var ref1; @@ -230,7 +230,7 @@ exports.getGuest = function(id) { }; -/* Returns the embedder of the guest. */ +// Returns the embedder of the guest. exports.getEmbedder = function(id) { var ref1; diff --git a/atom/browser/lib/guest-window-manager.js b/atom/browser/lib/guest-window-manager.js index 5b1290c282ec..302a6530df01 100644 --- a/atom/browser/lib/guest-window-manager.js +++ b/atom/browser/lib/guest-window-manager.js @@ -9,7 +9,7 @@ v8Util = process.atomBinding('v8_util'); frameToGuest = {}; -/* Copy attribute of |parent| to |child| if it is not defined in |child|. */ +// Copy attribute of |parent| to |child| if it is not defined in |child|. mergeOptions = function(child, parent) { var key, value; @@ -28,16 +28,16 @@ mergeOptions = function(child, parent) { }; -/* Merge |options| with the |embedder|'s window's options. */ +// Merge |options| with the |embedder|'s window's options. mergeBrowserWindowOptions = function(embedder, options) { if (embedder.browserWindowOptions != null) { - /* Inherit the original options if it is a BrowserWindow. */ + // Inherit the original options if it is a BrowserWindow. mergeOptions(options, embedder.browserWindowOptions); } else { - /* Or only inherit web-preferences if it is a webview. */ + // Or only inherit web-preferences if it is a webview. if (options.webPreferences == null) { options.webPreferences = {}; } @@ -47,7 +47,7 @@ mergeBrowserWindowOptions = function(embedder, options) { }; -/* Create a new guest created by |embedder| with |options|. */ +// Create a new guest created by |embedder| with |options|. createGuest = function(embedder, url, frameName, options) { var closedByEmbedder, closedByUser, guest, guestId, ref1; @@ -57,7 +57,7 @@ createGuest = function(embedder, url, frameName, options) { return guest.id; } - /* Remember the embedder window's id. */ + // Remember the embedder window's id. if (options.webPreferences == null) { options.webPreferences = {}; } @@ -92,7 +92,7 @@ createGuest = function(embedder, url, frameName, options) { }; -/* Routed window.open messages. */ +// Routed window.open messages. ipcMain.on('ATOM_SHELL_GUEST_WINDOW_MANAGER_WINDOW_OPEN', function() { var args, event, frameName, options, url; diff --git a/atom/browser/lib/init.js b/atom/browser/lib/init.js index ea44e2c9b04e..34f780852f59 100644 --- a/atom/browser/lib/init.js +++ b/atom/browser/lib/init.js @@ -10,20 +10,20 @@ util = require('util'); Module = require('module'); -/* We modified the original process.argv to let node.js load the atom.js, */ +// We modified the original process.argv to let node.js load the atom.js, -/* we need to restore it here. */ +// we need to restore it here. process.argv.splice(1, 1); -/* Clear search paths. */ +// Clear search paths. require(path.resolve(__dirname, '..', '..', 'common', 'lib', 'reset-search-paths')); -/* Import common settings. */ +// Import common settings. require(path.resolve(__dirname, '..', '..', 'common', 'lib', 'init')); @@ -34,7 +34,7 @@ if (!process.env.ELECTRON_HIDE_INTERNAL_MODULES) { } -/* Expose public APIs. */ +// Expose public APIs. globalPaths.push(path.resolve(__dirname, '..', 'api', 'lib', 'exports')); @@ -62,7 +62,7 @@ if (process.platform === 'win32') { console.log = console.error = console.warn = consoleLog; process.stdout.write = process.stderr.write = streamWrite; - /* Always returns EOF for stdin stream. */ + // Always returns EOF for stdin stream. Readable = require('stream').Readable; stdin = new Readable; stdin.push(null); @@ -72,17 +72,17 @@ if (process.platform === 'win32') { } -/* Don't quit on fatal error. */ +// Don't quit on fatal error. process.on('uncaughtException', function(error) { - /* Do nothing if the user has a custom uncaught exception handler. */ + // Do nothing if the user has a custom uncaught exception handler. var dialog, message, ref, stack; if (process.listeners('uncaughtException').length > 1) { return; } - /* Show error in GUI. */ + // Show error in GUI. dialog = require('electron').dialog; stack = (ref = error.stack) != null ? ref : error.name + ": " + error.message; message = "Uncaught Exception:\n" + stack; @@ -90,7 +90,7 @@ process.on('uncaughtException', function(error) { }); -/* Emit 'exit' event on quit. */ +// Emit 'exit' event on quit. app = require('electron').app; @@ -99,24 +99,24 @@ app.on('quit', function(event, exitCode) { }); -/* Map process.exit to app.exit, which quits gracefully. */ +// Map process.exit to app.exit, which quits gracefully. process.exit = app.exit; -/* Load the RPC server. */ +// Load the RPC server. require('./rpc-server'); -/* Load the guest view manager. */ +// Load the guest view manager. require('./guest-view-manager'); require('./guest-window-manager'); -/* Now we try to load app's package.json. */ +// Now we try to load app's package.json. packageJson = null; @@ -142,14 +142,14 @@ if (packageJson == null) { } -/* Set application's version. */ +// Set application's version. if (packageJson.version != null) { app.setVersion(packageJson.version); } -/* Set application's name. */ +// Set application's name. if (packageJson.productName != null) { app.setName(packageJson.productName); @@ -158,7 +158,7 @@ if (packageJson.productName != null) { } -/* Set application's desktop name. */ +// Set application's desktop name. if (packageJson.desktopName != null) { app.setDesktopName(packageJson.desktopName); @@ -167,12 +167,12 @@ if (packageJson.desktopName != null) { } -/* Chrome 42 disables NPAPI plugins by default, reenable them here */ +// Chrome 42 disables NPAPI plugins by default, reenable them here app.commandLine.appendSwitch('enable-npapi'); -/* Set the user path according to application's name. */ +// Set the user path according to application's name. app.setPath('userData', path.join(app.getPath('appData'), app.getName())); @@ -181,21 +181,21 @@ app.setPath('userCache', path.join(app.getPath('cache'), app.getName())); app.setAppPath(packagePath); -/* Load the chrome extension support. */ +// Load the chrome extension support. require('./chrome-extension'); -/* Load internal desktop-capturer module. */ +// Load internal desktop-capturer module. require('./desktop-capturer'); -/* Set main startup script of the app. */ +// Set main startup script of the app. mainStartupScript = packageJson.main || 'index.js'; -/* Finally load app's main.js and transfer control to C++. */ +// Finally load app's main.js and transfer control to C++. Module._load(path.join(packagePath, mainStartupScript), Module, true); diff --git a/atom/browser/lib/objects-registry.js b/atom/browser/lib/objects-registry.js index 81fe1c2398f1..5f134e8e9ef3 100644 --- a/atom/browser/lib/objects-registry.js +++ b/atom/browser/lib/objects-registry.js @@ -36,7 +36,7 @@ ObjectsRegistry = (function(superClass) { var base, base1, id; id = this.saveToStorage(obj); - /* Remember the owner. */ + // Remember the owner. if ((base = this.owners)[webContentsId] == null) { base[webContentsId] = {}; } @@ -45,12 +45,12 @@ ObjectsRegistry = (function(superClass) { } this.owners[webContentsId][id]++; - /* Returns object's id */ + // Returns object's id return id; }; - /* Get an object according to its ID. */ + // Get an object according to its ID. ObjectsRegistry.prototype.get = function(id) { var ref; @@ -58,13 +58,13 @@ ObjectsRegistry = (function(superClass) { }; - /* Dereference an object according to its ID. */ + // Dereference an object according to its ID. ObjectsRegistry.prototype.remove = function(webContentsId, id) { var pointer; this.dereference(id, 1); - /* Also reduce the count in owner. */ + // Also reduce the count in owner. pointer = this.owners[webContentsId]; if (pointer == null) { return; @@ -76,7 +76,7 @@ ObjectsRegistry = (function(superClass) { }; - /* Clear all references to objects refrenced by the WebContents. */ + // Clear all references to objects refrenced by the WebContents. ObjectsRegistry.prototype.clear = function(webContentsId) { var count, id, ref; @@ -93,7 +93,7 @@ ObjectsRegistry = (function(superClass) { }; - /* Private: Saves the object into storage and assigns an ID for it. */ + // Private: Saves the object into storage and assigns an ID for it. ObjectsRegistry.prototype.saveToStorage = function(object) { var id; @@ -111,7 +111,7 @@ ObjectsRegistry = (function(superClass) { }; - /* Private: Dereference the object from store. */ + // Private: Dereference the object from store. ObjectsRegistry.prototype.dereference = function(id, count) { var pointer; diff --git a/atom/browser/lib/rpc-server.js b/atom/browser/lib/rpc-server.js index 426ebe4a3906..ab7dee85f6ee 100644 --- a/atom/browser/lib/rpc-server.js +++ b/atom/browser/lib/rpc-server.js @@ -14,7 +14,7 @@ v8Util = process.atomBinding('v8_util'); IDWeakMap = process.atomBinding('id_weak_map').IDWeakMap; -/* Convert a real value into meta data. */ +// Convert a real value into meta data. valueToMeta = function(sender, value, optimizeSimpleObject) { var el, field, i, len, meta, name; @@ -43,12 +43,12 @@ valueToMeta = function(sender, value, optimizeSimpleObject) { meta.type = 'promise'; } - /* Treat simple objects as value. */ + // Treat simple objects as value. if (optimizeSimpleObject && meta.type === 'object' && v8Util.getHiddenValue(value, 'simple')) { meta.type = 'value'; } - /* Treat the arguments object as array. */ + // Treat the arguments object as array. if (meta.type === 'object' && (value.callee != null) && (value.length != null)) { meta.type = 'array'; } @@ -86,7 +86,7 @@ valueToMeta = function(sender, value, optimizeSimpleObject) { } else if (meta.type === 'error') { meta.members = plainObjectToMeta(value); - /* Error.name is not part of own properties. */ + // Error.name is not part of own properties. meta.members.push({ name: 'name', value: value.name @@ -101,7 +101,7 @@ valueToMeta = function(sender, value, optimizeSimpleObject) { }; -/* Convert object to meta by value. */ +// Convert object to meta by value. plainObjectToMeta = function(obj) { return Object.getOwnPropertyNames(obj).map(function(name) { @@ -113,7 +113,7 @@ plainObjectToMeta = function(obj) { }; -/* Convert Error into meta data. */ +// Convert Error into meta data. exceptionToMeta = function(error) { return { @@ -124,7 +124,7 @@ exceptionToMeta = function(error) { }; -/* Convert array of meta data from renderer into array of real values. */ +// Convert array of meta data from renderer into array of real values. unwrapArgs = function(sender, args) { var metaToValue; @@ -160,7 +160,7 @@ unwrapArgs = function(sender, args) { }; case 'function': - /* Cache the callbacks in renderer. */ + // Cache the callbacks in renderer. if (!sender.callbacks) { sender.callbacks = new IDWeakMap; sender.on('render-view-deleted', function() { @@ -230,7 +230,7 @@ callFunction = function(event, func, caller, args) { }; -/* Send by BrowserWindow when its render view is deleted. */ +// Send by BrowserWindow when its render view is deleted. process.on('ATOM_BROWSER_RELEASE_RENDER_VIEW', function(id) { return objectsRegistry.clear(id); @@ -316,7 +316,7 @@ ipcMain.on('ATOM_BROWSER_MEMBER_CONSTRUCTOR', function(event, id, method, args) args = unwrapArgs(event.sender, args); constructor = objectsRegistry.get(id)[method]; - /* Call new with array of arguments. */ + // Call new with array of arguments. obj = new (Function.prototype.bind.apply(constructor, [null].concat(args))); return event.returnValue = valueToMeta(event.sender, obj); } catch (error1) { diff --git a/atom/common/api/lib/callbacks-registry.js b/atom/common/api/lib/callbacks-registry.js index 1b93bf128e1f..018301825302 100644 --- a/atom/common/api/lib/callbacks-registry.js +++ b/atom/common/api/lib/callbacks-registry.js @@ -11,7 +11,7 @@ module.exports = CallbacksRegistry = (function() { CallbacksRegistry.prototype.add = function(callback) { - /* The callback is already added. */ + // The callback is already added. var filenameAndLine, id, location, match, ref, regexp, stackString, x; id = v8Util.getHiddenValue(callback, 'callbackId'); if (id != null) { diff --git a/atom/common/api/lib/clipboard.js b/atom/common/api/lib/clipboard.js index 4e7a668167e8..02b3de2e0623 100644 --- a/atom/common/api/lib/clipboard.js +++ b/atom/common/api/lib/clipboard.js @@ -1,6 +1,6 @@ if (process.platform === 'linux' && process.type === 'renderer') { - /* On Linux we could not access clipboard in renderer process. */ + // On Linux we could not access clipboard in renderer process. module.exports = require('electron').remote.clipboard; } else { module.exports = process.atomBinding('clipboard'); diff --git a/atom/common/api/lib/crash-reporter.js b/atom/common/api/lib/crash-reporter.js index 75a60a1a998a..57cde40f8507 100644 --- a/atom/common/api/lib/crash-reporter.js +++ b/atom/common/api/lib/crash-reporter.js @@ -22,7 +22,7 @@ CrashReporter = (function() { } this.productName = options.productName, companyName = options.companyName, submitURL = options.submitURL, autoSubmit = options.autoSubmit, ignoreSystemCrashHandler = options.ignoreSystemCrashHandler, extra = options.extra; - /* Deprecated. */ + // Deprecated. deprecate = electron.deprecate; if (options.submitUrl) { if (submitURL == null) { diff --git a/atom/common/api/lib/deprecate.js b/atom/common/api/lib/deprecate.js index be04b1fe18a0..b588bb1af41e 100644 --- a/atom/common/api/lib/deprecate.js +++ b/atom/common/api/lib/deprecate.js @@ -1,5 +1,5 @@ -/* Deprecate a method. */ +// Deprecate a method. var deprecate, slice = [].slice; @@ -16,7 +16,7 @@ deprecate = function(oldName, newName, fn) { }; -/* The method is renamed. */ +// The method is renamed. deprecate.rename = function(object, oldName, newName) { var newMethod, warned; @@ -36,7 +36,7 @@ deprecate.rename = function(object, oldName, newName) { }; -/* Forward the method to member. */ +// Forward the method to member. deprecate.member = function(object, method, member) { var warned; @@ -51,7 +51,7 @@ deprecate.member = function(object, method, member) { }; -/* Deprecate a property. */ +// Deprecate a property. deprecate.property = function(object, property, method) { return Object.defineProperty(object, property, { @@ -68,7 +68,7 @@ deprecate.property = function(object, property, method) { }; -/* Deprecate an event. */ +// Deprecate an event. deprecate.event = function(emitter, oldName, newName, fn) { var warned; @@ -77,7 +77,7 @@ deprecate.event = function(emitter, oldName, newName, fn) { var args; args = 1 <= arguments.length ? slice.call(arguments, 0) : []; - /* there is listeners for old API. */ + // there is listeners for old API. if (this.listenerCount(oldName) > 0) { if (!(warned || process.noDeprecation)) { warned = true; @@ -93,14 +93,14 @@ deprecate.event = function(emitter, oldName, newName, fn) { }; -/* Print deprecation warning. */ +// Print deprecation warning. deprecate.warn = function(oldName, newName) { return deprecate.log(oldName + " is deprecated. Use " + newName + " instead."); }; -/* Print deprecation message. */ +// Print deprecation message. deprecate.log = function(message) { if (process.throwDeprecation) { diff --git a/atom/common/api/lib/exports/electron.js b/atom/common/api/lib/exports/electron.js index 56443d376062..f818fb4cac80 100644 --- a/atom/common/api/lib/exports/electron.js +++ b/atom/common/api/lib/exports/electron.js @@ -1,25 +1,25 @@ -/* Do not expose the internal modules to `require`. */ +// Do not expose the internal modules to `require`. exports.hideInternalModules = function() { var globalPaths; globalPaths = require('module').globalPaths; if (globalPaths.length === 3) { - /* Remove the "common/api/lib" and "browser-or-renderer/api/lib". */ + // Remove the "common/api/lib" and "browser-or-renderer/api/lib". return globalPaths.splice(0, 2); } }; -/* Attaches properties to |exports|. */ +// Attaches properties to |exports|. exports.defineProperties = function(exports) { return Object.defineProperties(exports, { - /* Common modules, please sort with alphabet order. */ + // Common modules, please sort with alphabet order. clipboard: { - /* Must be enumerable, otherwise it woulde be invisible to remote module. */ + // Must be enumerable, otherwise it woulde be invisible to remote module. enumerable: true, get: function() { return require('../clipboard'); @@ -44,7 +44,7 @@ exports.defineProperties = function(exports) { } }, - /* The internal modules, invisible unless you know their names. */ + // The internal modules, invisible unless you know their names. CallbacksRegistry: { get: function() { return require('../callbacks-registry'); diff --git a/atom/common/api/lib/native-image.js b/atom/common/api/lib/native-image.js index b1e1b2610ff4..44a4330fa894 100644 --- a/atom/common/api/lib/native-image.js +++ b/atom/common/api/lib/native-image.js @@ -5,7 +5,7 @@ deprecate = require('electron').deprecate; nativeImage = process.atomBinding('native_image'); -/* Deprecated. */ +// Deprecated. deprecate.rename(nativeImage, 'createFromDataUrl', 'createFromDataURL'); diff --git a/atom/common/lib/asar.js b/atom/common/lib/asar.js index 158d50da18be..c90b59ddb764 100644 --- a/atom/common/lib/asar.js +++ b/atom/common/lib/asar.js @@ -11,7 +11,7 @@ path = require('path'); util = require('util'); -/* Cache asar archive objects. */ +// Cache asar archive objects. cachedArchives = {}; @@ -29,7 +29,7 @@ getOrCreateArchive = function(p) { }; -/* Clean cache on quit. */ +// Clean cache on quit. process.on('exit', function() { var archive, p, results; @@ -43,11 +43,11 @@ process.on('exit', function() { }); -/* Separate asar package's path from full path. */ +// Separate asar package's path from full path. splitPath = function(p) { - /* shortcut to disable asar. */ + // shortcut to disable asar. var index; if (process.noAsar) { return [false]; @@ -67,7 +67,7 @@ splitPath = function(p) { }; -/* Convert asar archive's Stats object to fs's Stats object. */ +// Convert asar archive's Stats object to fs's Stats object. nextInode = 0; @@ -116,7 +116,7 @@ asarStatsToFsStats = function(stats) { }; -/* Create a ENOENT error. */ +// Create a ENOENT error. notFoundError = function(asarPath, filePath, callback) { var error; @@ -132,7 +132,7 @@ notFoundError = function(asarPath, filePath, callback) { }; -/* Create a ENOTDIR error. */ +// Create a ENOTDIR error. notDirError = function(callback) { var error; @@ -148,7 +148,7 @@ notDirError = function(callback) { }; -/* Create invalid archive error. */ +// Create invalid archive error. invalidArchiveError = function(asarPath, callback) { var error; @@ -162,7 +162,7 @@ invalidArchiveError = function(asarPath, callback) { }; -/* Override APIs that rely on passing file path instead of content to C++. */ +// Override APIs that rely on passing file path instead of content to C++. overrideAPISync = function(module, name, arg) { var old; @@ -221,7 +221,7 @@ overrideAPI = function(module, name, arg) { }; -/* Override fs APIs. */ +// Override fs APIs. exports.wrapFsWithAsar = function(fs) { var exists, existsSync, internalModuleReadFile, internalModuleStat, lstat, lstatSync, mkdir, mkdirSync, open, openSync, readFile, readFileSync, readdir, readdirSync, realpath, realpathSync, stat, statSync, statSyncNoException; @@ -269,7 +269,7 @@ exports.wrapFsWithAsar = function(fs) { return statSync(p); } - /* Do not distinguish links for now. */ + // Do not distinguish links for now. return fs.lstatSync(p); }; stat = fs.stat; @@ -280,7 +280,7 @@ exports.wrapFsWithAsar = function(fs) { return stat(p, callback); } - /* Do not distinguish links for now. */ + // Do not distinguish links for now. return process.nextTick(function() { return fs.lstat(p, callback); }); @@ -427,7 +427,7 @@ exports.wrapFsWithAsar = function(fs) { readFileSync = fs.readFileSync; fs.readFileSync = function(p, opts) { - /* this allows v8 to optimize this function */ + // this allows v8 to optimize this function var archive, asarPath, buffer, encoding, fd, filePath, info, isAsar, options, realPath, ref; options = opts; ref = splitPath(p), isAsar = ref[0], asarPath = ref[1], filePath = ref[2]; @@ -554,13 +554,13 @@ exports.wrapFsWithAsar = function(fs) { } archive = getOrCreateArchive(asarPath); - /* -ENOENT */ + // -ENOENT if (!archive) { return -34; } stats = archive.stat(filePath); - /* -ENOENT */ + // -ENOENT if (!stats) { return -34; } diff --git a/atom/common/lib/asar_init.js b/atom/common/lib/asar_init.js index 0379865acf33..52d93af86691 100644 --- a/atom/common/lib/asar_init.js +++ b/atom/common/lib/asar_init.js @@ -3,13 +3,13 @@ return function(process, require, asarSource) { var createArchive, source; createArchive = process.binding('atom_common_asar').createArchive; - /* Make asar.coffee accessible via "require". */ + // Make asar.coffee accessible via "require". process.binding('natives').ATOM_SHELL_ASAR = asarSource; - /* Monkey-patch the fs module. */ + // Monkey-patch the fs module. require('ATOM_SHELL_ASAR').wrapFsWithAsar(require('fs')); - /* Make graceful-fs work with asar. */ + // Make graceful-fs work with asar. source = process.binding('natives'); source['original-fs'] = source.fs; return source['fs'] = "var src = '(function (exports, require, module, __filename, __dirname) { ' +\n process.binding('natives')['original-fs'] +\n ' });';\nvar vm = require('vm');\nvar fn = vm.runInThisContext(src, { filename: 'fs.js' });\nfn(exports, require, module);\nvar asar = require('ATOM_SHELL_ASAR');\nasar.wrapFsWithAsar(exports);"; diff --git a/atom/common/lib/init.js b/atom/common/lib/init.js index c1c21d4e819b..44291ff45262 100644 --- a/atom/common/lib/init.js +++ b/atom/common/lib/init.js @@ -22,7 +22,7 @@ process.atomBinding = function(name) { if (!process.env.ELECTRON_HIDE_INTERNAL_MODULES) { - /* Add common/api/lib to module search paths. */ + // Add common/api/lib to module search paths. Module.globalPaths.push(path.resolve(__dirname, '..', 'api', 'lib')); } diff --git a/atom/common/lib/reset-search-paths.js b/atom/common/lib/reset-search-paths.js index 61486b570e2c..ef7a5913c205 100644 --- a/atom/common/lib/reset-search-paths.js +++ b/atom/common/lib/reset-search-paths.js @@ -5,28 +5,28 @@ path = require('path'); Module = require('module'); -/* Clear Node's global search paths. */ +// Clear Node's global search paths. Module.globalPaths.length = 0; -/* Clear current and parent(init.coffee)'s search paths. */ +// Clear current and parent(init.coffee)'s search paths. module.paths = []; module.parent.paths = []; -/* Prevent Node from adding paths outside this app to search paths. */ +// Prevent Node from adding paths outside this app to search paths. Module._nodeModulePaths = function(from) { var dir, i, part, parts, paths, skipOutsidePaths, splitRe, tip; from = path.resolve(from); - /* If "from" is outside the app then we do nothing. */ + // If "from" is outside the app then we do nothing. skipOutsidePaths = from.startsWith(process.resourcesPath); - /* Following logoic is copied from module.js. */ + // Following logoic is copied from module.js. splitRe = process.platform === 'win32' ? /[\/\\]/ : /\//; paths = []; parts = from.split(splitRe); diff --git a/atom/renderer/api/lib/desktop-capturer.js b/atom/renderer/api/lib/desktop-capturer.js index 4cc5362fbb73..ce9443c1ed8a 100644 --- a/atom/renderer/api/lib/desktop-capturer.js +++ b/atom/renderer/api/lib/desktop-capturer.js @@ -10,7 +10,7 @@ getNextId = function() { }; -/* |options.type| can not be empty and has to include 'window' or 'screen'. */ +// |options.type| can not be empty and has to include 'window' or 'screen'. isValid = function(options) { return ((options != null ? options.types : void 0) != null) && Array.isArray(options.types); diff --git a/atom/renderer/api/lib/exports/electron.js b/atom/renderer/api/lib/exports/electron.js index e1c960c4b365..a740d88bd0a4 100644 --- a/atom/renderer/api/lib/exports/electron.js +++ b/atom/renderer/api/lib/exports/electron.js @@ -3,13 +3,13 @@ var common; common = require('../../../../common/api/lib/exports/electron'); -/* Import common modules. */ +// Import common modules. common.defineProperties(exports); Object.defineProperties(exports, { - /* Renderer side modules, please sort with alphabet order. */ + // Renderer side modules, please sort with alphabet order. desktopCapturer: { enumerable: true, get: function() { diff --git a/atom/renderer/api/lib/ipc-renderer.js b/atom/renderer/api/lib/ipc-renderer.js index b5f23030117f..95e9b097d1e8 100644 --- a/atom/renderer/api/lib/ipc-renderer.js +++ b/atom/renderer/api/lib/ipc-renderer.js @@ -8,7 +8,7 @@ binding = process.atomBinding('ipc'); v8Util = process.atomBinding('v8_util'); -/* Created by init.coffee. */ +// Created by init.coffee. ipcRenderer = v8Util.getHiddenValue(global, 'ipc'); diff --git a/atom/renderer/api/lib/ipc.js b/atom/renderer/api/lib/ipc.js index 7758ce5d5188..3578c56d3da9 100644 --- a/atom/renderer/api/lib/ipc.js +++ b/atom/renderer/api/lib/ipc.js @@ -6,12 +6,12 @@ ref = require('electron'), ipcRenderer = ref.ipcRenderer, deprecate = ref.deprec EventEmitter = require('events').EventEmitter; -/* This module is deprecated, we mirror everything from ipcRenderer. */ +// This module is deprecated, we mirror everything from ipcRenderer. deprecate.warn('ipc module', 'require("electron").ipcRenderer'); -/* Routes events of ipcRenderer. */ +// Routes events of ipcRenderer. ipc = new EventEmitter; @@ -23,7 +23,7 @@ ipcRenderer.emit = function() { }; -/* Deprecated. */ +// Deprecated. for (method in ipcRenderer) { if (method.startsWith('send')) { diff --git a/atom/renderer/api/lib/remote.js b/atom/renderer/api/lib/remote.js index 3c0324c0ba27..8eb7bc21c24e 100644 --- a/atom/renderer/api/lib/remote.js +++ b/atom/renderer/api/lib/remote.js @@ -8,7 +8,7 @@ v8Util = process.atomBinding('v8_util'); callbacksRegistry = new CallbacksRegistry; -/* Check for circular reference. */ +// Check for circular reference. isCircular = function(field, visited) { if (typeof field === 'object') { @@ -21,7 +21,7 @@ isCircular = function(field, visited) { }; -/* Convert the arguments object into an array of meta data. */ +// Convert the arguments object into an array of meta data. wrapArgs = function(args, visited) { var valueToMeta; @@ -91,7 +91,7 @@ wrapArgs = function(args, visited) { }; -/* Convert meta data from browser into real value. */ +// Convert meta data from browser into real value. metaToValue = function(meta) { var RemoteFunction, el, i, j, len, len1, member, ref1, ref2, results, ret; @@ -122,13 +122,13 @@ metaToValue = function(meta) { default: if (meta.type === 'function') { - /* A shadow class to represent the remote function object. */ + // A shadow class to represent the remote function object. ret = RemoteFunction = (function() { function RemoteFunction() { var obj; if (this.constructor === RemoteFunction) { - /* Constructor call. */ + // Constructor call. obj = ipcRenderer.sendSync('ATOM_BROWSER_CONSTRUCTOR', meta.id, wrapArgs(arguments)); /* @@ -139,7 +139,7 @@ metaToValue = function(meta) { return metaToValue(obj); } else { - /* Function call. */ + // Function call. obj = ipcRenderer.sendSync('ATOM_BROWSER_FUNCTION_CALL', meta.id, wrapArgs(arguments)); return metaToValue(obj); } @@ -152,7 +152,7 @@ metaToValue = function(meta) { ret = v8Util.createObjectWithName(meta.name); } - /* Polulate delegate members. */ + // Polulate delegate members. ref2 = meta.members; for (j = 0, len1 = ref2.length; j < len1; j++) { member = ref2[j]; @@ -171,14 +171,14 @@ metaToValue = function(meta) { return ipcRenderer.send('ATOM_BROWSER_DEREFERENCE', meta.id); }); - /* Remember object's id. */ + // Remember object's id. v8Util.setHiddenValue(ret, 'atomId', meta.id); return ret; } }; -/* Construct a plain object from the meta. */ +// Construct a plain object from the meta. metaToPlainObject = function(meta) { var i, len, name, obj, ref1, ref2, value; @@ -212,12 +212,12 @@ createRemoteMemberFunction = function(metaId, name) { var ret; if (this.constructor === RemoteMemberFunction) { - /* Constructor call. */ + // Constructor call. ret = ipcRenderer.sendSync('ATOM_BROWSER_MEMBER_CONSTRUCTOR', metaId, name, wrapArgs(arguments)); return metaToValue(ret); } else { - /* Call member function. */ + // Call member function. ret = ipcRenderer.sendSync('ATOM_BROWSER_MEMBER_CALL', metaId, name, wrapArgs(arguments)); return metaToValue(ret); } @@ -241,39 +241,39 @@ createRemoteMemberProperty = function(metaId, name) { configurable: false, set: function(value) { - /* Set member data. */ + // Set member data. ipcRenderer.sendSync('ATOM_BROWSER_MEMBER_SET', metaId, name, value); return value; }, get: function() { - /* Get member data. */ + // Get member data. return metaToValue(ipcRenderer.sendSync('ATOM_BROWSER_MEMBER_GET', metaId, name)); } }; }; -/* Browser calls a callback in renderer. */ +// Browser calls a callback in renderer. ipcRenderer.on('ATOM_RENDERER_CALLBACK', function(event, id, args) { return callbacksRegistry.apply(id, metaToValue(args)); }); -/* A callback in browser is released. */ +// A callback in browser is released. ipcRenderer.on('ATOM_RENDERER_RELEASE_CALLBACK', function(event, id) { return callbacksRegistry.remove(id); }); -/* List all built-in modules in browser process. */ +// List all built-in modules in browser process. browserModules = require('../../../browser/api/lib/exports/electron'); -/* And add a helper receiver for each one. */ +// And add a helper receiver for each one. fn = function(name) { return Object.defineProperty(exports, name, { @@ -305,12 +305,12 @@ exports.require = function(module) { }; -/* Optimize require('electron'). */ +// Optimize require('electron'). moduleCache.electron = exports; -/* Alias to remote.require('electron').xxx. */ +// Alias to remote.require('electron').xxx. builtinCache = {}; @@ -324,7 +324,7 @@ exports.getBuiltin = function(module) { }; -/* Get current BrowserWindow object. */ +// Get current BrowserWindow object. windowCache = null; @@ -338,7 +338,7 @@ exports.getCurrentWindow = function() { }; -/* Get current WebContents object. */ +// Get current WebContents object. webContentsCache = null; @@ -352,7 +352,7 @@ exports.getCurrentWebContents = function() { }; -/* Get a global object in browser. */ +// Get a global object in browser. exports.getGlobal = function(name) { var meta; @@ -361,7 +361,7 @@ exports.getGlobal = function(name) { }; -/* Get the process object in browser. */ +// Get the process object in browser. processCache = null; @@ -373,7 +373,7 @@ exports.__defineGetter__('process', function() { }); -/* Create a funtion that will return the specifed value when called in browser. */ +// Create a funtion that will return the specifed value when called in browser. exports.createFunctionWithReturnValue = function(returnValue) { var func; @@ -385,7 +385,7 @@ exports.createFunctionWithReturnValue = function(returnValue) { }; -/* Get the guest WebContents from guestInstanceId. */ +// Get the guest WebContents from guestInstanceId. exports.getGuestWebContents = function(guestInstanceId) { var meta; diff --git a/atom/renderer/lib/init.js b/atom/renderer/lib/init.js index 344c7f2b1d26..0f651218ecdb 100644 --- a/atom/renderer/lib/init.js +++ b/atom/renderer/lib/init.js @@ -19,12 +19,12 @@ Module = require('module'); process.argv.splice(1, 1); -/* Clear search paths. */ +// Clear search paths. require(path.resolve(__dirname, '..', '..', 'common', 'lib', 'reset-search-paths')); -/* Import common settings. */ +// Import common settings. require(path.resolve(__dirname, '..', '..', 'common', 'lib', 'init')); @@ -35,12 +35,12 @@ if (!process.env.ELECTRON_HIDE_INTERNAL_MODULES) { } -/* Expose public APIs. */ +// Expose public APIs. globalPaths.push(path.resolve(__dirname, '..', 'api', 'lib', 'exports')); -/* The global variable will be used by ipc for event dispatching */ +// The global variable will be used by ipc for event dispatching v8Util = process.atomBinding('v8_util'); @@ -54,7 +54,7 @@ electron.ipcRenderer.on('ELECTRON_INTERNAL_RENDERER_WEB_FRAME_METHOD', (event, m electron.webFrame[method].apply(electron.webFrame, args); }); -/* Process command line arguments. */ +// Process command line arguments. nodeIntegration = 'false'; @@ -63,11 +63,11 @@ for (i = 0, len = ref.length; i < len; i++) { arg = ref[i]; if (arg.indexOf('--guest-instance-id=') === 0) { - /* This is a guest web view. */ + // This is a guest web view. process.guestInstanceId = parseInt(arg.substr(arg.indexOf('=') + 1)); } else if (arg.indexOf('--opener-id=') === 0) { - /* This is a guest BrowserWindow. */ + // This is a guest BrowserWindow. process.openerId = parseInt(arg.substr(arg.indexOf('=') + 1)); } else if (arg.indexOf('--node-integration=') === 0) { nodeIntegration = arg.substr(arg.indexOf('=') + 1); @@ -78,20 +78,20 @@ for (i = 0, len = ref.length; i < len; i++) { if (location.protocol === 'chrome-devtools:') { - /* Override some inspector APIs. */ + // Override some inspector APIs. require('./inspector'); nodeIntegration = 'true'; } else if (location.protocol === 'chrome-extension:') { - /* Add implementations of chrome API. */ + // Add implementations of chrome API. require('./chrome-api'); nodeIntegration = 'true'; } else { - /* Override default web functions. */ + // Override default web functions. require('./override'); - /* Load webview tag implementation. */ + // Load webview tag implementation. if (process.guestInstanceId == null) { require('./web-view/web-view'); require('./web-view/web-view-attributes'); @@ -100,27 +100,27 @@ if (location.protocol === 'chrome-devtools:') { if (nodeIntegration === 'true' || nodeIntegration === 'all' || nodeIntegration === 'except-iframe' || nodeIntegration === 'manual-enable-iframe') { - /* Export node bindings to global. */ + // Export node bindings to global. global.require = require; global.module = module; - /* Set the __filename to the path of html file if it is file: protocol. */ + // Set the __filename to the path of html file if it is file: protocol. if (window.location.protocol === 'file:') { pathname = process.platform === 'win32' && window.location.pathname[0] === '/' ? window.location.pathname.substr(1) : window.location.pathname; global.__filename = path.normalize(decodeURIComponent(pathname)); global.__dirname = path.dirname(global.__filename); - /* Set module's filename so relative require can work as expected. */ + // Set module's filename so relative require can work as expected. module.filename = global.__filename; - /* Also search for module under the html file. */ + // Also search for module under the html file. module.paths = module.paths.concat(Module._nodeModulePaths(global.__dirname)); } else { global.__filename = __filename; global.__dirname = __dirname; } - /* Redirect window.onerror to uncaughtException. */ + // Redirect window.onerror to uncaughtException. window.onerror = function(message, filename, lineno, colno, error) { if (global.process.listeners('uncaughtException').length > 0) { global.process.emit('uncaughtException', error); @@ -130,13 +130,13 @@ if (nodeIntegration === 'true' || nodeIntegration === 'all' || nodeIntegration = } }; - /* Emit the 'exit' event when page is unloading. */ + // Emit the 'exit' event when page is unloading. window.addEventListener('unload', function() { return process.emit('exit'); }); } else { - /* Delete Node's symbols after the Environment has been loaded. */ + // Delete Node's symbols after the Environment has been loaded. process.once('loaded', function() { delete global.process; delete global.setImmediate; @@ -146,7 +146,7 @@ if (nodeIntegration === 'true' || nodeIntegration === 'all' || nodeIntegration = } -/* Load the script specfied by the "preload" attribute. */ +// Load the script specfied by the "preload" attribute. if (preloadScript) { try { diff --git a/atom/renderer/lib/inspector.js b/atom/renderer/lib/inspector.js index ee578aefcfa2..54c02f011dc7 100644 --- a/atom/renderer/lib/inspector.js +++ b/atom/renderer/lib/inspector.js @@ -2,10 +2,10 @@ var convertToMenuTemplate, createFileSelectorElement, createMenu, pathToHtml5Fil window.onload = function() { - /* Use menu API to show context menu. */ + // Use menu API to show context menu. InspectorFrontendHost.showContextMenuAtPoint = createMenu; - /* Use dialog API to override file chooser dialog. */ + // Use dialog API to override file chooser dialog. return WebInspector.createFileSelectorElement = createFileSelectorElement; }; @@ -52,7 +52,7 @@ createMenu = function(x, y, items, document) { Menu = remote.Menu; menu = Menu.buildFromTemplate(convertToMenuTemplate(items)); - /* The menu is expected to show asynchronously. */ + // The menu is expected to show asynchronously. return setTimeout(function() { return menu.popup(remote.getCurrentWindow()); }); diff --git a/atom/renderer/lib/override.js b/atom/renderer/lib/override.js index 1a5791feb3fc..27d8fdc3f210 100644 --- a/atom/renderer/lib/override.js +++ b/atom/renderer/lib/override.js @@ -4,7 +4,7 @@ var BrowserWindowProxy, a, getHistoryOperation, ipcRenderer, ref, remote, resolv ref = require('electron'), ipcRenderer = ref.ipcRenderer, remote = ref.remote; -/* Helper function to resolve relative url. */ +// Helper function to resolve relative url. a = window.top.document.createElement('a'); @@ -14,7 +14,7 @@ resolveURL = function(url) { }; -/* Window object returned by "window.open". */ +// Window object returned by "window.open". BrowserWindowProxy = (function() { BrowserWindowProxy.proxies = {}; @@ -70,14 +70,14 @@ BrowserWindowProxy = (function() { if (process.guestInstanceId == null) { - /* Override default window.close. */ + // Override default window.close. window.close = function() { return remote.getCurrentWindow().close(); }; } -/* Make the browser window or guest view emit "new-window" event. */ +// Make the browser window or guest view emit "new-window" event. window.open = function(url, frameName, features) { var feature, guestId, i, ints, j, len, len1, name, options, ref1, ref2, value; @@ -90,7 +90,7 @@ window.open = function(url, frameName, features) { options = {}; ints = ['x', 'y', 'width', 'height', 'min-width', 'max-width', 'min-height', 'max-height', 'zoom-factor']; - /* Make sure to get rid of excessive whitespace in the property name */ + // Make sure to get rid of excessive whitespace in the property name ref1 = features.split(/,\s*/); for (i = 0, len = ref1.length; i < len; i++) { feature = ref1[i]; @@ -117,7 +117,7 @@ window.open = function(url, frameName, features) { options.height = 600; } - /* Resolve relative urls. */ + // Resolve relative urls. url = resolveURL(url); for (j = 0, len1 = ints.length; j < len1; j++) { name = ints[j]; @@ -134,7 +134,7 @@ window.open = function(url, frameName, features) { }; -/* Use the dialog API to implement alert(). */ +// Use the dialog API to implement alert(). window.alert = function(message, title) { var buttons; @@ -149,11 +149,11 @@ window.alert = function(message, title) { buttons: buttons }); - /* Alert should always return undefined. */ + // Alert should always return undefined. }; -/* And the confirm(). */ +// And the confirm(). window.confirm = function(message, title) { var buttons, cancelId; @@ -171,7 +171,7 @@ window.confirm = function(message, title) { }; -/* But we do not support prompt(). */ +// But we do not support prompt(). window.prompt = function() { throw new Error('prompt() is and will not be supported.'); @@ -183,9 +183,9 @@ if (process.openerId != null) { ipcRenderer.on('ATOM_SHELL_GUEST_WINDOW_POSTMESSAGE', function(event, sourceId, message, sourceOrigin) { - /* Manually dispatch event instead of using postMessage because we also need to */ + // Manually dispatch event instead of using postMessage because we also need to - /* set event.source. */ + // set event.source. event = document.createEvent('Event'); event.initEvent('message', false, false); event.data = message; @@ -195,7 +195,7 @@ ipcRenderer.on('ATOM_SHELL_GUEST_WINDOW_POSTMESSAGE', function(event, sourceId, }); -/* Forward history operations to browser. */ +// Forward history operations to browser. sendHistoryOperation = function() { var args; @@ -228,7 +228,7 @@ Object.defineProperty(window.history, 'length', { }); -/* Make document.hidden and document.visibilityState return the correct value. */ +// Make document.hidden and document.visibilityState return the correct value. Object.defineProperty(document, 'hidden', { get: function() { diff --git a/atom/renderer/lib/web-view/web-view-attributes.js b/atom/renderer/lib/web-view/web-view-attributes.js index b02cd755e82a..ddf17b9f9ed7 100644 --- a/atom/renderer/lib/web-view/web-view-attributes.js +++ b/atom/renderer/lib/web-view/web-view-attributes.js @@ -11,7 +11,7 @@ webViewConstants = require('./web-view-constants'); remote = require('electron').remote; -/* Helper function to resolve url set in attribute. */ +// Helper function to resolve url set in attribute. a = document.createElement('a'); @@ -36,21 +36,21 @@ WebViewAttribute = (function() { } - /* Retrieves and returns the attribute's value. */ + // Retrieves and returns the attribute's value. WebViewAttribute.prototype.getValue = function() { return this.webViewImpl.webviewNode.getAttribute(this.name) || this.value; }; - /* Sets the attribute's value. */ + // Sets the attribute's value. WebViewAttribute.prototype.setValue = function(value) { return this.webViewImpl.webviewNode.setAttribute(this.name, value || ''); }; - /* Changes the attribute's value without triggering its mutation handler. */ + // Changes the attribute's value without triggering its mutation handler. WebViewAttribute.prototype.setValueIgnoreMutation = function(value) { this.ignoreMutation = true; @@ -59,7 +59,7 @@ WebViewAttribute = (function() { }; - /* Defines this attribute as a property on the webview node. */ + // Defines this attribute as a property on the webview node. WebViewAttribute.prototype.defineProperty = function() { return Object.defineProperty(this.webViewImpl.webviewNode, this.name, { @@ -78,7 +78,7 @@ WebViewAttribute = (function() { }; - /* Called when the attribute's value changes. */ + // Called when the attribute's value changes. WebViewAttribute.prototype.handleMutation = function() {}; @@ -87,7 +87,7 @@ WebViewAttribute = (function() { })(); -/* An attribute that is treated as a Boolean. */ +// An attribute that is treated as a Boolean. BooleanAttribute = (function(superClass) { extend(BooleanAttribute, superClass); @@ -113,7 +113,7 @@ BooleanAttribute = (function(superClass) { })(WebViewAttribute); -/* Attribute that specifies whether transparency is allowed in the webview. */ +// Attribute that specifies whether transparency is allowed in the webview. AllowTransparencyAttribute = (function(superClass) { extend(AllowTransparencyAttribute, superClass); @@ -134,7 +134,7 @@ AllowTransparencyAttribute = (function(superClass) { })(BooleanAttribute); -/* Attribute used to define the demension limits of autosizing. */ +// Attribute used to define the demension limits of autosizing. AutosizeDimensionAttribute = (function(superClass) { extend(AutosizeDimensionAttribute, superClass); @@ -169,7 +169,7 @@ AutosizeDimensionAttribute = (function(superClass) { })(WebViewAttribute); -/* Attribute that specifies whether the webview should be autosized. */ +// Attribute that specifies whether the webview should be autosized. AutosizeAttribute = (function(superClass) { extend(AutosizeAttribute, superClass); @@ -185,7 +185,7 @@ AutosizeAttribute = (function(superClass) { })(BooleanAttribute); -/* Attribute representing the state of the storage partition. */ +// Attribute representing the state of the storage partition. PartitionAttribute = (function(superClass) { extend(PartitionAttribute, superClass); @@ -198,7 +198,7 @@ PartitionAttribute = (function(superClass) { PartitionAttribute.prototype.handleMutation = function(oldValue, newValue) { newValue = newValue || ''; - /* The partition cannot change if the webview has already navigated. */ + // The partition cannot change if the webview has already navigated. if (!this.webViewImpl.beforeFirstNavigation) { window.console.error(webViewConstants.ERROR_MSG_ALREADY_NAVIGATED); this.setValueIgnoreMutation(oldValue); @@ -215,7 +215,7 @@ PartitionAttribute = (function(superClass) { })(WebViewAttribute); -/* Attribute that handles the location and navigation of the webview. */ +// Attribute that handles the location and navigation of the webview. SrcAttribute = (function(superClass) { extend(SrcAttribute, superClass); @@ -310,7 +310,7 @@ SrcAttribute = (function(superClass) { return; } - /* Navigate to |this.src|. */ + // Navigate to |this.src|. opts = {}; httpreferrer = this.webViewImpl.attributes[webViewConstants.ATTRIBUTE_HTTPREFERRER].getValue(); if (httpreferrer) { @@ -329,7 +329,7 @@ SrcAttribute = (function(superClass) { })(WebViewAttribute); -/* Attribute specifies HTTP referrer. */ +// Attribute specifies HTTP referrer. HttpReferrerAttribute = (function(superClass) { extend(HttpReferrerAttribute, superClass); @@ -343,7 +343,7 @@ HttpReferrerAttribute = (function(superClass) { })(WebViewAttribute); -/* Attribute specifies user agent */ +// Attribute specifies user agent UserAgentAttribute = (function(superClass) { extend(UserAgentAttribute, superClass); @@ -357,7 +357,7 @@ UserAgentAttribute = (function(superClass) { })(WebViewAttribute); -/* Attribute that set preload script. */ +// Attribute that set preload script. PreloadAttribute = (function(superClass) { extend(PreloadAttribute, superClass); @@ -385,7 +385,7 @@ PreloadAttribute = (function(superClass) { })(WebViewAttribute); -/* Sets up all of the webview attributes. */ +// Sets up all of the webview attributes. WebViewImpl.prototype.setupWebViewAttributes = function() { var attribute, autosizeAttributes, i, len, results; diff --git a/atom/renderer/lib/web-view/web-view-constants.js b/atom/renderer/lib/web-view/web-view-constants.js index 098e02eb8875..9ca98340ced5 100644 --- a/atom/renderer/lib/web-view/web-view-constants.js +++ b/atom/renderer/lib/web-view/web-view-constants.js @@ -1,6 +1,6 @@ module.exports = { - /* Attributes. */ + // Attributes. ATTRIBUTE_ALLOWTRANSPARENCY: 'allowtransparency', ATTRIBUTE_AUTOSIZE: 'autosize', ATTRIBUTE_MAXHEIGHT: 'maxheight', @@ -18,10 +18,10 @@ module.exports = { ATTRIBUTE_PRELOAD: 'preload', ATTRIBUTE_USERAGENT: 'useragent', - /* Internal attribute. */ + // Internal attribute. ATTRIBUTE_INTERNALINSTANCEID: 'internalinstanceid', - /* Error messages. */ + // Error messages. ERROR_MSG_ALREADY_NAVIGATED: 'The object has already navigated, so its partition cannot be changed.', ERROR_MSG_CANNOT_INJECT_SCRIPT: ': ' + 'Script cannot be injected into content until the page has loaded.', ERROR_MSG_INVALID_PARTITION_ATTRIBUTE: 'Invalid partition attribute.', diff --git a/atom/renderer/lib/web-view/web-view.js b/atom/renderer/lib/web-view/web-view.js index cb0a5ddf118c..549c3d4d4795 100644 --- a/atom/renderer/lib/web-view/web-view.js +++ b/atom/renderer/lib/web-view/web-view.js @@ -13,7 +13,7 @@ guestViewInternal = require('./guest-view-internal'); webViewConstants = require('./web-view-constants'); -/* ID generator. */ +// ID generator. nextId = 0; @@ -22,7 +22,7 @@ getNextId = function() { }; -/* Represents the internal state of the WebView node. */ +// Represents the internal state of the WebView node. WebViewImpl = (function() { function WebViewImpl(webviewNode) { @@ -33,7 +33,7 @@ WebViewImpl = (function() { this.elementAttached = false; this.beforeFirstNavigation = true; - /* on* Event handlers. */ + // on* Event handlers. this.on = {}; this.browserPluginNode = this.createBrowserPluginNode(); shadowRoot = this.webviewNode.createShadowRoot(); @@ -62,7 +62,7 @@ WebViewImpl = (function() { }; - /* Resets some state upon reattaching element to the DOM. */ + // Resets some state upon reattaching element to the DOM. WebViewImpl.prototype.reset = function() { // Unlisten the zoom-level-changed event. @@ -87,7 +87,7 @@ WebViewImpl = (function() { }; - /* Sets the .request property. */ + // Sets the .request property. WebViewImpl.prototype.setRequestPropertyOnWebViewNode = function(request) { return Object.defineProperty(this.webviewNode, 'request', { @@ -110,14 +110,14 @@ WebViewImpl = (function() { this.webviewNode.addEventListener('focus', (function(_this) { return function(e) { - /* Focus the BrowserPlugin when the takes focus. */ + // Focus the BrowserPlugin when the takes focus. return _this.browserPluginNode.focus(); }; })(this)); return this.webviewNode.addEventListener('blur', (function(_this) { return function(e) { - /* Blur the BrowserPlugin when the loses focus. */ + // Blur the BrowserPlugin when the loses focus. return _this.browserPluginNode.blur(); }; })(this)); @@ -137,7 +137,7 @@ WebViewImpl = (function() { return; } - /* Let the changed attribute handle its own mutation; */ + // Let the changed attribute handle its own mutation; return this.attributes[attributeName].handleMutation(oldValue, newValue); }; @@ -146,7 +146,7 @@ WebViewImpl = (function() { this.browserPluginNode.removeAttribute(webViewConstants.ATTRIBUTE_INTERNALINSTANCEID); this.internalInstanceId = parseInt(newValue); - /* Track when the element resizes using the element resize callback. */ + // Track when the element resizes using the element resize callback. webFrame.registerElementResizeCallback(this.internalInstanceId, this.onElementResize.bind(this)); if (!this.guestInstanceId) { return; @@ -163,9 +163,9 @@ WebViewImpl = (function() { width = node.offsetWidth; height = node.offsetHeight; - /* Check the current bounds to make sure we do not resize */ + // Check the current bounds to make sure we do not resize - /* outside of current constraints. */ + // outside of current constraints. maxWidth = this.attributes[webViewConstants.ATTRIBUTE_MAXWIDTH].getValue() | width; maxHeight = this.attributes[webViewConstants.ATTRIBUTE_MAXHEIGHT].getValue() | width; minWidth = this.attributes[webViewConstants.ATTRIBUTE_MINWIDTH].getValue() | width; @@ -186,7 +186,7 @@ WebViewImpl = (function() { WebViewImpl.prototype.onElementResize = function(newSize) { - /* Dispatch the 'resize' event. */ + // Dispatch the 'resize' event. var resizeEvent; resizeEvent = new Event('resize', { bubbles: true @@ -214,10 +214,10 @@ WebViewImpl = (function() { }; - /* Adds an 'on' property on the webview, which can be used to set/unset */ + // Adds an 'on' property on the webview, which can be used to set/unset - /* an event handler. */ + // an event handler. WebViewImpl.prototype.setupEventProperty = function(eventName) { var propertyName; @@ -244,7 +244,7 @@ WebViewImpl = (function() { }; - /* Updates state upon loadcommit. */ + // Updates state upon loadcommit. WebViewImpl.prototype.onLoadCommit = function(webViewEvent) { var newValue, oldValue; @@ -306,7 +306,7 @@ WebViewImpl = (function() { })(); -/* Registers browser plugin custom element. */ +// Registers browser plugin custom element. registerBrowserPluginElement = function() { var proto; @@ -315,7 +315,7 @@ registerBrowserPluginElement = function() { this.setAttribute('type', 'application/browser-plugin'); this.setAttribute('id', 'browser-plugin-' + getNextId()); - /* The node fills in the container. */ + // The node fills in the container. this.style.display = 'block'; this.style.width = '100%'; return this.style.height = '100%'; @@ -330,7 +330,7 @@ registerBrowserPluginElement = function() { }; proto.attachedCallback = function() { - /* Load the plugin immediately. */ + // Load the plugin immediately. var unused; return unused = this.nonExistentAttribute; }; @@ -345,7 +345,7 @@ registerBrowserPluginElement = function() { }; -/* Registers custom element. */ +// Registers custom element. registerWebViewElement = function() { var createBlockHandler, createNonBlockHandler, i, j, len, len1, m, methods, nonblockMethods, proto; @@ -384,7 +384,7 @@ registerWebViewElement = function() { } }; - /* Public-facing API methods. */ + // Public-facing API methods. methods = ['getURL', 'getTitle', 'isLoading', 'isWaitingForResponse', 'stop', 'reload', 'reloadIgnoringCache', 'canGoBack', 'canGoForward', 'canGoToOffset', 'clearHistory', 'goBack', 'goForward', 'goToIndex', 'goToOffset', 'isCrashed', 'setUserAgent', 'getUserAgent', 'openDevTools', 'closeDevTools', 'isDevToolsOpened', 'isDevToolsFocused', 'inspectElement', 'setAudioMuted', 'isAudioMuted', 'undo', 'redo', 'cut', 'copy', 'paste', 'pasteAndMatchStyle', 'delete', 'selectAll', 'unselect', 'replace', 'replaceMisspelling', 'findInPage', 'stopFindInPage', 'getId', 'downloadURL', 'inspectServiceWorker', 'print', 'printToPDF']; nonblockMethods = [ 'executeJavaScript', @@ -397,7 +397,7 @@ registerWebViewElement = function() { 'setZoomLevelLimits', ]; - /* Forward proto.foo* method calls to WebViewImpl.foo*. */ + // Forward proto.foo* method calls to WebViewImpl.foo*. createBlockHandler = function(m) { return function() { var args, internal, ref1; @@ -423,15 +423,16 @@ registerWebViewElement = function() { proto[m] = createNonBlockHandler(m); } - /* Deprecated. */ + // Deprecated. deprecate.rename(proto, 'getUrl', 'getURL'); window.WebView = webFrame.registerEmbedderCustomElement('webview', { prototype: proto }); - /* Delete the callbacks so developers cannot call them and produce unexpected */ - - /* behavior. */ + /* + Delete the callbacks so developers cannot call them and produce unexpected + behavior. + */ delete proto.createdCallback; delete proto.attachedCallback; delete proto.detachedCallback; From 990dc30e8d57ba5629bc628595a11c57c6ccd851 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Thu, 14 Jan 2016 10:44:21 -0800 Subject: [PATCH 72/95] Use // for multi-line comments --- .../api/lib/auto-updater/auto-updater-win.js | 7 ++--- .../lib/auto-updater/squirrel-update-win.js | 12 ++----- atom/browser/api/lib/browser-window.js | 20 +++++------- atom/browser/api/lib/navigation-controller.js | 14 +++------ atom/browser/api/lib/web-contents.js | 6 ++-- atom/browser/lib/chrome-extension.js | 6 ++-- atom/browser/lib/desktop-capturer.js | 12 +++---- atom/browser/lib/guest-view-manager.js | 8 ++--- atom/browser/lib/guest-window-manager.js | 8 ++--- atom/browser/lib/init.js | 13 ++------ atom/browser/lib/objects-registry.js | 25 ++++----------- atom/browser/lib/rpc-server.js | 31 ++++++------------- atom/common/api/lib/callbacks-registry.js | 6 ++-- atom/common/lib/asar.js | 10 +++--- atom/common/lib/init.js | 25 ++++++--------- 15 files changed, 65 insertions(+), 138 deletions(-) diff --git a/atom/browser/api/lib/auto-updater/auto-updater-win.js b/atom/browser/api/lib/auto-updater/auto-updater-win.js index 7d62809a56ce..61b1911e232e 100644 --- a/atom/browser/api/lib/auto-updater/auto-updater-win.js +++ b/atom/browser/api/lib/auto-updater/auto-updater-win.js @@ -62,11 +62,8 @@ AutoUpdater = (function(superClass) { }; - /* - Private: Emit both error object and message, this is to keep compatibility - with Old APIs. - */ - + // Private: Emit both error object and message, this is to keep compatibility + // with Old APIs. AutoUpdater.prototype.emitError = function(message) { return this.emit('error', new Error(message), message); }; diff --git a/atom/browser/api/lib/auto-updater/squirrel-update-win.js b/atom/browser/api/lib/auto-updater/squirrel-update-win.js index 78c127eae46b..2f68c1dace46 100644 --- a/atom/browser/api/lib/auto-updater/squirrel-update-win.js +++ b/atom/browser/api/lib/auto-updater/squirrel-update-win.js @@ -6,24 +6,16 @@ path = require('path'); spawn = require('child_process').spawn; - // i.e. my-app/app-0.1.13/ - appFolder = path.dirname(process.execPath); - // i.e. my-app/Update.exe - updateExe = path.resolve(appFolder, '..', 'Update.exe'); exeName = path.basename(process.execPath); - -/* - Spawn a command and invoke the callback when it completes with an error - and the output from standard out. - */ - +// Spawn a command and invoke the callback when it completes with an error +// and the output from standard out. spawnUpdate = function(args, detached, callback) { var error, error1, errorEmitted, spawnedProcess, stderr, stdout; try { diff --git a/atom/browser/api/lib/browser-window.js b/atom/browser/api/lib/browser-window.js index f3b297ebbaf2..79395250f823 100644 --- a/atom/browser/api/lib/browser-window.js +++ b/atom/browser/api/lib/browser-window.js @@ -33,10 +33,8 @@ BrowserWindow.prototype._init = function() { return ipcMain.emit('ATOM_SHELL_GUEST_WINDOW_MANAGER_WINDOW_OPEN', event, url, frameName, options); }); - /* - window.resizeTo(...) - window.moveTo(...) - */ + // window.resizeTo(...) + // window.moveTo(...) this.webContents.on('move', (function(_this) { return function(event, size) { return _this.setBounds(size); @@ -69,14 +67,12 @@ BrowserWindow.prototype._init = function() { }; })(this)); - /* - Sometimes the webContents doesn't get focus when window is shown, so we have - to force focusing on webContents in this case. The safest way is to focus it - when we first start to load URL, if we do it earlier it won't have effect, - if we do it later we might move focus in the page. - Though this hack is only needed on OS X when the app is launched from - Finder, we still do it on all platforms in case of other bugs we don't know. - */ + // Sometimes the webContents doesn't get focus when window is shown, so we have + // to force focusing on webContents in this case. The safest way is to focus it + // when we first start to load URL, if we do it earlier it won't have effect, + // if we do it later we might move focus in the page. + // Though this hack is only needed on OS X when the app is launched from + // Finder, we still do it on all platforms in case of other bugs we don't know. this.webContents.once('load-url', function() { return this.focus(); }); diff --git a/atom/browser/api/lib/navigation-controller.js b/atom/browser/api/lib/navigation-controller.js index ff9b440a9164..5e613f416f4e 100644 --- a/atom/browser/api/lib/navigation-controller.js +++ b/atom/browser/api/lib/navigation-controller.js @@ -18,15 +18,11 @@ ipcMain.on('ATOM_SHELL_SYNC_NAVIGATION_CONTROLLER', function() { return event.returnValue = (ref = event.sender)[method].apply(ref, args); }); - -/* - JavaScript implementation of Chromium's NavigationController. - Instead of relying on Chromium for history control, we compeletely do history - control on user land, and only rely on WebContents.loadURL for navigation. - This helps us avoid Chromium's various optimizations so we can ensure renderer - process is restarted everytime. - */ - +// JavaScript implementation of Chromium's NavigationController. +// Instead of relying on Chromium for history control, we compeletely do history +// control on user land, and only rely on WebContents.loadURL for navigation. +// This helps us avoid Chromium's various optimizations so we can ensure renderer +// process is restarted everytime. NavigationController = (function() { function NavigationController(webContents) { this.webContents = webContents; diff --git a/atom/browser/api/lib/web-contents.js b/atom/browser/api/lib/web-contents.js index c7d6786b17b2..b1d7ee4febd9 100644 --- a/atom/browser/api/lib/web-contents.js +++ b/atom/browser/api/lib/web-contents.js @@ -138,10 +138,8 @@ wrapWebContents = function(webContents) { var args; args = 1 <= arguments.length ? slice.call(arguments, 0) : []; - /* - Calling loadURL during this event might cause crash, so delay the event - until next tick. - */ + // Calling loadURL during this event might cause crash, so delay the event + // until next tick. return setImmediate((function(_this) { return function() { return _this.emit.apply(_this, ['did-fail-load'].concat(slice.call(args))); diff --git a/atom/browser/lib/chrome-extension.js b/atom/browser/lib/chrome-extension.js index 80b3e0e644dd..a6bb44e33823 100644 --- a/atom/browser/lib/chrome-extension.js +++ b/atom/browser/lib/chrome-extension.js @@ -36,10 +36,8 @@ getExtensionInfoFromPath = function(srcDirectory) { manifest = JSON.parse(fs.readFileSync(path.join(srcDirectory, 'manifest.json'))); if (extensionInfoMap[manifest.name] == null) { - /* - We can not use 'file://' directly because all resources in the extension - will be treated as relative to the root in Chrome. - */ + // We can not use 'file://' directly because all resources in the extension + // will be treated as relative to the root in Chrome. page = url.format({ protocol: 'chrome-extension', slashes: true, diff --git a/atom/browser/lib/desktop-capturer.js b/atom/browser/lib/desktop-capturer.js index 2ebb3d2fa227..68da4e27f1e4 100644 --- a/atom/browser/lib/desktop-capturer.js +++ b/atom/browser/lib/desktop-capturer.js @@ -29,10 +29,8 @@ ipcMain.on('ATOM_BROWSER_DESKTOP_CAPTURER_GET_SOURCES', function(event, captureW desktopCapturer.startHandling(captureWindow, captureScreen, thumbnailSize); } - /* - If the WebContents is destroyed before receiving result, just remove the - reference from requestsQueue to make the module not send the result to it. - */ + // If the WebContents is destroyed before receiving result, just remove the + // reference from requestsQueue to make the module not send the result to it. return event.sender.once('destroyed', function() { return request.webContents = null; }); @@ -60,10 +58,8 @@ desktopCapturer.emit = function(event, name, sources) { ref.send("ATOM_RENDERER_DESKTOP_CAPTURER_RESULT_" + handledRequest.id, result); } - /* - Check the queue to see whether there is other same request. If has, handle - it for reducing redunplicated `desktopCaptuer.startHandling` calls. - */ + // Check the queue to see whether there is other same request. If has, handle + // it for reducing redunplicated `desktopCaptuer.startHandling` calls. unhandledRequestsQueue = []; for (i = 0, len = requestsQueue.length; i < len; i++) { request = requestsQueue[i]; diff --git a/atom/browser/lib/guest-view-manager.js b/atom/browser/lib/guest-view-manager.js index 2560c8e0a641..fa409f89c41b 100644 --- a/atom/browser/lib/guest-view-manager.js +++ b/atom/browser/lib/guest-view-manager.js @@ -62,11 +62,9 @@ createGuest = function(embedder, params) { event = destroyEvents[i]; embedder.once(event, destroy); - /* - Users might also listen to the crashed event, so We must ensure the guest - is destroyed before users' listener gets called. It is done by moving our - listener to the first one in queue. - */ + // Users might also listen to the crashed event, so We must ensure the guest + // is destroyed before users' listener gets called. It is done by moving our + // listener to the first one in queue. listeners = embedder._events[event]; if (Array.isArray(listeners)) { moveLastToFirst(listeners); diff --git a/atom/browser/lib/guest-window-manager.js b/atom/browser/lib/guest-window-manager.js index 302a6530df01..df129b4a0928 100644 --- a/atom/browser/lib/guest-window-manager.js +++ b/atom/browser/lib/guest-window-manager.js @@ -65,11 +65,9 @@ createGuest = function(embedder, url, frameName, options) { guest = new BrowserWindow(options); guest.loadURL(url); - /* - 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. - */ + // 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 = function() { guest.removeListener('closed', closedByUser); diff --git a/atom/browser/lib/init.js b/atom/browser/lib/init.js index 34f780852f59..9ce4e55ee3be 100644 --- a/atom/browser/lib/init.js +++ b/atom/browser/lib/init.js @@ -17,14 +17,10 @@ Module = require('module'); process.argv.splice(1, 1); - // Clear search paths. - require(path.resolve(__dirname, '..', '..', 'common', 'lib', 'reset-search-paths')); - // Import common settings. - require(path.resolve(__dirname, '..', '..', 'common', 'lib', 'init')); globalPaths = Module.globalPaths; @@ -33,17 +29,12 @@ if (!process.env.ELECTRON_HIDE_INTERNAL_MODULES) { globalPaths.push(path.resolve(__dirname, '..', 'api', 'lib')); } - // Expose public APIs. - globalPaths.push(path.resolve(__dirname, '..', 'api', 'lib', 'exports')); if (process.platform === 'win32') { - - /* - Redirect node's console to use our own implementations, since node can not - handle console output when running as GUI program. - */ + // Redirect node's console to use our own implementations, since node can not + // handle console output when running as GUI program. consoleLog = function() { var args; args = 1 <= arguments.length ? slice.call(arguments, 0) : []; diff --git a/atom/browser/lib/objects-registry.js b/atom/browser/lib/objects-registry.js index 5f134e8e9ef3..082f1ef3441d 100644 --- a/atom/browser/lib/objects-registry.js +++ b/atom/browser/lib/objects-registry.js @@ -13,25 +13,17 @@ ObjectsRegistry = (function(superClass) { this.setMaxListeners(Number.MAX_VALUE); this.nextId = 0; - /* - Stores all objects by ref-counting. - (id) => {object, count} - */ + // Stores all objects by ref-counting. + // (id) => {object, count} this.storage = {}; - /* - Stores the IDs of objects referenced by WebContents. - (webContentsId) => {(id) => (count)} - */ + // Stores the IDs of objects referenced by WebContents. + // (webContentsId) => {(id) => (count)} this.owners = {}; } - - /* - Register a new object, the object would be kept referenced until you release - it explicitly. - */ - + // Register a new object, the object would be kept referenced until you release + // it explicitly. ObjectsRegistry.prototype.add = function(webContentsId, obj) { var base, base1, id; id = this.saveToStorage(obj); @@ -51,7 +43,6 @@ ObjectsRegistry = (function(superClass) { // Get an object according to its ID. - ObjectsRegistry.prototype.get = function(id) { var ref; return (ref = this.storage[id]) != null ? ref.object : void 0; @@ -59,7 +50,6 @@ ObjectsRegistry = (function(superClass) { // Dereference an object according to its ID. - ObjectsRegistry.prototype.remove = function(webContentsId, id) { var pointer; this.dereference(id, 1); @@ -77,7 +67,6 @@ ObjectsRegistry = (function(superClass) { // Clear all references to objects refrenced by the WebContents. - ObjectsRegistry.prototype.clear = function(webContentsId) { var count, id, ref; this.emit("clear-" + webContentsId); @@ -94,7 +83,6 @@ ObjectsRegistry = (function(superClass) { // Private: Saves the object into storage and assigns an ID for it. - ObjectsRegistry.prototype.saveToStorage = function(object) { var id; id = v8Util.getHiddenValue(object, 'atomId'); @@ -112,7 +100,6 @@ ObjectsRegistry = (function(superClass) { // Private: Dereference the object from store. - ObjectsRegistry.prototype.dereference = function(id, count) { var pointer; pointer = this.storage[id]; diff --git a/atom/browser/lib/rpc-server.js b/atom/browser/lib/rpc-server.js index ab7dee85f6ee..13405b8ed96d 100644 --- a/atom/browser/lib/rpc-server.js +++ b/atom/browser/lib/rpc-server.js @@ -61,11 +61,9 @@ valueToMeta = function(sender, value, optimizeSimpleObject) { } else if (meta.type === 'object' || meta.type === 'function') { meta.name = value.constructor.name; - /* - Reference the original value if it's an object, because when it's - passed to renderer we would assume the renderer keeps a reference of - it. - */ + // Reference the original value if it's an object, because when it's + // passed to renderer we would assume the renderer keeps a reference of + // it. meta.id = objectsRegistry.add(sender.getId(), value); meta.members = (function() { var results; @@ -196,12 +194,8 @@ unwrapArgs = function(sender, args) { return args.map(metaToValue); }; - -/* - Call a function and send reply asynchronously if it's a an asynchronous - style function and the caller didn't pass a callback. - */ - +// Call a function and send reply asynchronously if it's a an asynchronous +// style function and the caller didn't pass a callback. callFunction = function(event, func, caller, args) { var e, error1, funcMarkedAsync, funcName, funcPassedCallback, ref, ret; funcMarkedAsync = v8Util.getHiddenValue(func, 'asynchronous'); @@ -219,11 +213,9 @@ callFunction = function(event, func, caller, args) { } catch (error1) { e = error1; - /* - Catch functions thrown further down in function invocation and wrap - them with the function name so it's easier to trace things like - `Error processing argument -1.` - */ + // Catch functions thrown further down in function invocation and wrap + // them with the function name so it's easier to trace things like + // `Error processing argument -1.` funcName = (ref = func.name) != null ? ref : "anonymous"; throw new Error("Could not call remote function `" + funcName + "`. Check that the function signature is correct. Underlying error: " + e.message); } @@ -231,7 +223,6 @@ callFunction = function(event, func, caller, args) { // Send by BrowserWindow when its render view is deleted. - process.on('ATOM_BROWSER_RELEASE_RENDER_VIEW', function(id) { return objectsRegistry.clear(id); }); @@ -286,10 +277,8 @@ ipcMain.on('ATOM_BROWSER_CONSTRUCTOR', function(event, id, args) { args = unwrapArgs(event.sender, args); constructor = objectsRegistry.get(id); - /* - Call new with array of arguments. - http://stackoverflow.com/questions/1606797/use-of-apply-with-new-operator-is-this-possible - */ + // Call new with array of arguments. + // http://stackoverflow.com/questions/1606797/use-of-apply-with-new-operator-is-this-possible obj = new (Function.prototype.bind.apply(constructor, [null].concat(args))); return event.returnValue = valueToMeta(event.sender, obj); } catch (error1) { diff --git a/atom/common/api/lib/callbacks-registry.js b/atom/common/api/lib/callbacks-registry.js index 018301825302..5c74388ec409 100644 --- a/atom/common/api/lib/callbacks-registry.js +++ b/atom/common/api/lib/callbacks-registry.js @@ -19,10 +19,8 @@ module.exports = CallbacksRegistry = (function() { } id = ++this.nextId; - /* - Capture the location of the function and put it in the ID string, - so that release errors can be tracked down easily. - */ + // Capture the location of the function and put it in the ID string, + // so that release errors can be tracked down easily. regexp = /at (.*)/gi; stackString = (new Error).stack; while ((match = regexp.exec(stackString)) !== null) { diff --git a/atom/common/lib/asar.js b/atom/common/lib/asar.js index c90b59ddb764..843b6d75aa7f 100644 --- a/atom/common/lib/asar.js +++ b/atom/common/lib/asar.js @@ -571,12 +571,10 @@ exports.wrapFsWithAsar = function(fs) { } }; - /* - Calling mkdir for directory inside asar archive should throw ENOTDIR - error, but on Windows it throws ENOENT. - This is to work around the recursive looping bug of mkdirp since it is - widely used. - */ + // Calling mkdir for directory inside asar archive should throw ENOTDIR + // error, but on Windows it throws ENOENT. + // This is to work around the recursive looping bug of mkdirp since it is + // widely used. if (process.platform === 'win32') { mkdir = fs.mkdir; fs.mkdir = function(p, mode, callback) { diff --git a/atom/common/lib/init.js b/atom/common/lib/init.js index 44291ff45262..dca836c7db81 100644 --- a/atom/common/lib/init.js +++ b/atom/common/lib/init.js @@ -27,15 +27,12 @@ if (!process.env.ELECTRON_HIDE_INTERNAL_MODULES) { } -/* - setImmediate and process.nextTick makes use of uv_check and uv_prepare to - run the callbacks, however since we only run uv loop on requests, the - callbacks wouldn't be called until something else activated the uv loop, - which would delay the callbacks for arbitrary long time. So we should - initiatively activate the uv loop once setImmediate and process.nextTick is - called. - */ - +// setImmediate and process.nextTick makes use of uv_check and uv_prepare to +// run the callbacks, however since we only run uv loop on requests, the +// callbacks wouldn't be called until something else activated the uv loop, +// which would delay the callbacks for arbitrary long time. So we should +// initiatively activate the uv loop once setImmediate and process.nextTick is +// called. wrapWithActivateUvLoop = function(func) { return function() { process.activateUvLoop(); @@ -51,12 +48,10 @@ global.clearImmediate = timers.clearImmediate; if (process.type === 'browser') { - /* - setTimeout needs to update the polling timeout of the event loop, when - called under Chromium's event loop the node's event loop won't get a chance - to update the timeout, so we have to force the node's event loop to - recalculate the timeout in browser process. - */ + // setTimeout needs to update the polling timeout of the event loop, when + // called under Chromium's event loop the node's event loop won't get a chance + // to update the timeout, so we have to force the node's event loop to + // recalculate the timeout in browser process. global.setTimeout = wrapWithActivateUvLoop(timers.setTimeout); global.setInterval = wrapWithActivateUvLoop(timers.setInterval); } From 030d2a843c486122d49b63210b1bffa1916d8f77 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Thu, 14 Jan 2016 11:10:12 -0800 Subject: [PATCH 73/95] Remove extra newlines around comments --- atom/browser/api/lib/app.js | 7 - atom/browser/api/lib/auto-updater.js | 4 - .../lib/auto-updater/squirrel-update-win.js | 6 - atom/browser/api/lib/browser-window.js | 2 - atom/browser/api/lib/dialog.js | 4 - atom/browser/api/lib/exports/electron.js | 1 - atom/browser/api/lib/ipc.js | 2 - atom/browser/api/lib/menu-item.js | 4 - atom/browser/api/lib/menu.js | 14 -- atom/browser/api/lib/navigation-controller.js | 2 - atom/browser/api/lib/protocol.js | 2 - atom/browser/api/lib/session.js | 5 - atom/browser/api/lib/tray.js | 1 - atom/browser/api/lib/web-contents.js | 1 - atom/browser/lib/chrome-extension.js | 11 -- atom/browser/lib/desktop-capturer.js | 3 - atom/browser/lib/guest-view-manager.js | 16 -- atom/browser/lib/guest-window-manager.js | 8 - atom/browser/lib/init.js | 33 ---- atom/browser/lib/objects-registry.js | 3 - atom/browser/lib/rpc-server.js | 10 -- atom/common/api/lib/callbacks-registry.js | 1 - atom/common/api/lib/clipboard.js | 1 - atom/common/api/lib/deprecate.js | 13 -- atom/common/api/lib/exports/electron.js | 3 - atom/common/api/lib/native-image.js | 2 - atom/common/lib/asar.js | 18 --- atom/common/lib/init.js | 2 - atom/common/lib/reset-search-paths.js | 6 - atom/renderer/api/lib/desktop-capturer.js | 2 - atom/renderer/api/lib/exports/electron.js | 3 - atom/renderer/api/lib/ipc-renderer.js | 2 - atom/renderer/api/lib/ipc.js | 6 - atom/renderer/api/lib/remote.js | 66 ++------ atom/renderer/lib/init.js | 23 +-- atom/renderer/lib/inspector.js | 1 - atom/renderer/lib/override.js | 19 --- .../lib/web-view/web-view-attributes.js | 77 ++-------- .../lib/web-view/web-view-constants.js | 1 - atom/renderer/lib/web-view/web-view.js | 143 +++++++++--------- 40 files changed, 103 insertions(+), 425 deletions(-) diff --git a/atom/browser/api/lib/app.js b/atom/browser/api/lib/app.js index 7d0d0694147d..560fcb8630ee 100644 --- a/atom/browser/api/lib/app.js +++ b/atom/browser/api/lib/app.js @@ -53,9 +53,7 @@ app.getAppPath = function() { return appPath; }; - // Routes the events to webContents. - ref1 = ['login', 'certificate-error', 'select-client-certificate']; fn = function(name) { return app.on(name, function() { @@ -69,7 +67,6 @@ for (i = 0, len = ref1.length; i < len; i++) { fn(name); } - // Deprecated. app.getHomeDir = deprecate('app.getHomeDir', 'app.getPath', function() { @@ -108,9 +105,7 @@ deprecate.event(app, 'activate-with-no-open-windows', 'activate', function(event deprecate.event(app, 'select-certificate', 'select-client-certificate'); - // Wrappers for native classes. - wrapDownloadItem = function(downloadItem) { // downloadItem is an EventEmitter. @@ -125,7 +120,5 @@ wrapDownloadItem = function(downloadItem) { downloadItemBindings._setWrapDownloadItem(wrapDownloadItem); - // Only one App object pemitted. - module.exports = app; diff --git a/atom/browser/api/lib/auto-updater.js b/atom/browser/api/lib/auto-updater.js index e8e447ab1802..a3ffc12e9f2d 100644 --- a/atom/browser/api/lib/auto-updater.js +++ b/atom/browser/api/lib/auto-updater.js @@ -4,11 +4,7 @@ deprecate = require('electron').deprecate; autoUpdater = process.platform === 'win32' ? require('./auto-updater/auto-updater-win') : require('./auto-updater/auto-updater-native'); - // Deprecated. - deprecate.rename(autoUpdater, 'setFeedUrl', 'setFeedURL'); - - module.exports = autoUpdater; diff --git a/atom/browser/api/lib/auto-updater/squirrel-update-win.js b/atom/browser/api/lib/auto-updater/squirrel-update-win.js index 2f68c1dace46..49d525f4a684 100644 --- a/atom/browser/api/lib/auto-updater/squirrel-update-win.js +++ b/atom/browser/api/lib/auto-updater/squirrel-update-win.js @@ -61,16 +61,12 @@ spawnUpdate = function(args, detached, callback) { }); }; - // Start an instance of the installed app. - exports.processStart = function(callback) { return spawnUpdate(['--processStart', exeName], true, function() {}); }; - // Download the releases specified by the URL and write new results to stdout. - exports.download = function(updateURL, callback) { return spawnUpdate(['--download', updateURL], false, function(error, stdout) { var error1, json, ref, ref1, update; @@ -91,14 +87,12 @@ exports.download = function(updateURL, callback) { // Update the application to the latest remote version specified by URL. - exports.update = function(updateURL, callback) { return spawnUpdate(['--update', updateURL], false, callback); }; // Is the Update.exe installed with the current application? - exports.supported = function() { var error1; try { diff --git a/atom/browser/api/lib/browser-window.js b/atom/browser/api/lib/browser-window.js index 79395250f823..df9ae1647383 100644 --- a/atom/browser/api/lib/browser-window.js +++ b/atom/browser/api/lib/browser-window.js @@ -151,7 +151,6 @@ BrowserWindow.fromDevToolsWebContents = function(webContents) { } }; - // Helpers. BrowserWindow.prototype.loadURL = function() { @@ -198,7 +197,6 @@ BrowserWindow.prototype.inspectServiceWorker = function() { return this.webContents.inspectServiceWorker(); }; - // Deprecated. deprecate.member(BrowserWindow, 'undo', 'webContents'); diff --git a/atom/browser/api/lib/dialog.js b/atom/browser/api/lib/dialog.js index 9932988216ad..9ed49738a55b 100644 --- a/atom/browser/api/lib/dialog.js +++ b/atom/browser/api/lib/dialog.js @@ -23,14 +23,12 @@ messageBoxOptions = { parseArgs = function(window, options, callback) { if (!(window === null || (window != null ? window.constructor : void 0) === BrowserWindow)) { - // Shift. callback = options; options = window; window = null; } if ((callback == null) && typeof options === 'function') { - // Shift. callback = options; options = null; @@ -165,9 +163,7 @@ module.exports = { } }; - // Mark standard asynchronous functions. - ref1 = ['showMessageBox', 'showOpenDialog', 'showSaveDialog']; for (j = 0, len = ref1.length; j < len; j++) { api = ref1[j]; diff --git a/atom/browser/api/lib/exports/electron.js b/atom/browser/api/lib/exports/electron.js index 2ec917d16eba..74ae751e0834 100644 --- a/atom/browser/api/lib/exports/electron.js +++ b/atom/browser/api/lib/exports/electron.js @@ -4,7 +4,6 @@ common = require('../../../../common/api/lib/exports/electron'); // Import common modules. - common.defineProperties(exports); Object.defineProperties(exports, { diff --git a/atom/browser/api/lib/ipc.js b/atom/browser/api/lib/ipc.js index e314f9360178..ed20e976173f 100644 --- a/atom/browser/api/lib/ipc.js +++ b/atom/browser/api/lib/ipc.js @@ -2,9 +2,7 @@ var deprecate, ipcMain, ref; ref = require('electron'), deprecate = ref.deprecate, ipcMain = ref.ipcMain; - // This module is deprecated, we mirror everything from ipcMain. - deprecate.warn('ipc module', 'require("electron").ipcMain'); module.exports = ipcMain; diff --git a/atom/browser/api/lib/menu-item.js b/atom/browser/api/lib/menu-item.js index 2e0980983c50..b8357dd34918 100644 --- a/atom/browser/api/lib/menu-item.js +++ b/atom/browser/api/lib/menu-item.js @@ -4,9 +4,7 @@ v8Util = process.atomBinding('v8_util'); nextCommandId = 0; - // Maps role to methods of webContents - rolesMap = { undo: 'undo', redo: 'redo', @@ -18,9 +16,7 @@ rolesMap = { close: 'close' }; - // Maps methods that should be called directly on the BrowserWindow instance - methodInBrowserWindow = { minimize: true, close: true diff --git a/atom/browser/api/lib/menu.js b/atom/browser/api/lib/menu.js index 69b3b3a80b73..5af39e18af32 100644 --- a/atom/browser/api/lib/menu.js +++ b/atom/browser/api/lib/menu.js @@ -8,17 +8,11 @@ v8Util = process.atomBinding('v8_util'); bindings = process.atomBinding('menu'); - // Automatically generated radio menu item's group id. - nextGroupId = 0; - // Search between seperators to find a radio menu item and return its group id, - - // otherwise generate a group id. - generateGroupId = function(items, pos) { var i, item, j, k, ref1, ref2, ref3; if (pos > 0) { @@ -45,9 +39,7 @@ generateGroupId = function(items, pos) { return ++nextGroupId; }; - // Returns the index of item according to |id|. - indexOfItemById = function(items, id) { var i, item, j, len; for (i = j = 0, len = items.length; j < len; i = ++j) { @@ -59,9 +51,7 @@ indexOfItemById = function(items, id) { return -1; }; - // Returns the index of where to insert the item according to |position|. - indexToInsertByPosition = function(items, position) { var id, insertIndex, query, ref1; if (!position) { @@ -174,7 +164,6 @@ Menu.prototype._init = function() { Menu.prototype.popup = function(window, x, y) { if ((window != null ? window.constructor : void 0) !== BrowserWindow) { - // Shift. y = x; x = window; @@ -210,7 +199,6 @@ Menu.prototype.insert = function(pos, item) { this.insertSubMenu(pos, item.commandId, item.label, item.submenu); break; case 'radio': - // Grouping radio menu items. item.overrideReadOnlyProperty('groupId', generateGroupId(this.items, pos)); if ((base = this.groupsMap)[name = item.groupId] == null) { @@ -261,7 +249,6 @@ Menu.prototype.insert = function(pos, item) { // Force menuWillShow to be called - Menu.prototype._callMenuWillShow = function() { var item, j, len, ref1, ref2, results; if ((ref1 = this.delegate) != null) { @@ -323,7 +310,6 @@ Menu.buildFromTemplate = function(template) { if (item.position) { insertIndex = indexToInsertByPosition(positionedTemplate, item.position); } else { - // If no |position| is specified, insert after last item. insertIndex++; } diff --git a/atom/browser/api/lib/navigation-controller.js b/atom/browser/api/lib/navigation-controller.js index 5e613f416f4e..5478b6dd3264 100644 --- a/atom/browser/api/lib/navigation-controller.js +++ b/atom/browser/api/lib/navigation-controller.js @@ -3,9 +3,7 @@ var NavigationController, ipcMain, ipcMain = require('electron').ipcMain; - // The history operation in renderer is redirected to browser. - ipcMain.on('ATOM_SHELL_NAVIGATION_CONTROLLER', function() { var args, event, method, ref; event = arguments[0], method = arguments[1], args = 3 <= arguments.length ? slice.call(arguments, 2) : []; diff --git a/atom/browser/api/lib/protocol.js b/atom/browser/api/lib/protocol.js index dc92c676485f..f04eab121f15 100644 --- a/atom/browser/api/lib/protocol.js +++ b/atom/browser/api/lib/protocol.js @@ -8,9 +8,7 @@ if (!app.isReady()) { protocol = process.atomBinding('protocol').protocol; - // Warn about removed APIs. - logAndThrow = function(callback, message) { console.error(message); if (callback) { diff --git a/atom/browser/api/lib/session.js b/atom/browser/api/lib/session.js index d3b889cc09d3..8ba9e61be45a 100644 --- a/atom/browser/api/lib/session.js +++ b/atom/browser/api/lib/session.js @@ -6,9 +6,7 @@ bindings = process.atomBinding('session'); PERSIST_PERFIX = 'persist:'; - // Returns the Session from |partition| string. - exports.fromPartition = function(partition) { if (partition == null) { partition = ''; @@ -23,9 +21,7 @@ exports.fromPartition = function(partition) { } }; - // Returns the default session. - Object.defineProperty(exports, 'defaultSession', { enumerable: true, get: function() { @@ -34,7 +30,6 @@ Object.defineProperty(exports, 'defaultSession', { }); wrapSession = function(session) { - // session is an EventEmitter. return session.__proto__ = EventEmitter.prototype; }; diff --git a/atom/browser/api/lib/tray.js b/atom/browser/api/lib/tray.js index db692a089372..a2b732964ea4 100644 --- a/atom/browser/api/lib/tray.js +++ b/atom/browser/api/lib/tray.js @@ -9,7 +9,6 @@ Tray = process.atomBinding('tray').Tray; Tray.prototype.__proto__ = EventEmitter.prototype; Tray.prototype._init = function() { - // Deprecated. deprecate.rename(this, 'popContextMenu', 'popUpContextMenu'); deprecate.event(this, 'clicked', 'click'); diff --git a/atom/browser/api/lib/web-contents.js b/atom/browser/api/lib/web-contents.js index b1d7ee4febd9..c507daab077e 100644 --- a/atom/browser/api/lib/web-contents.js +++ b/atom/browser/api/lib/web-contents.js @@ -65,7 +65,6 @@ const webFrameMethods = [ ]; wrapWebContents = function(webContents) { - // webContents is an EventEmitter. var controller, method, name, ref1; webContents.__proto__ = EventEmitter.prototype; diff --git a/atom/browser/lib/chrome-extension.js b/atom/browser/lib/chrome-extension.js index a6bb44e33823..44e7f947e391 100644 --- a/atom/browser/lib/chrome-extension.js +++ b/atom/browser/lib/chrome-extension.js @@ -8,9 +8,7 @@ path = require('path'); url = require('url'); - // Mapping between hostname and file path. - hostPathMap = {}; hostPathMapNextKey = 0; @@ -26,9 +24,7 @@ getPathForHost = function(host) { return hostPathMap[host]; }; - // Cache extensionInfo. - extensionInfoMap = {}; getExtensionInfoFromPath = function(srcDirectory) { @@ -54,16 +50,11 @@ getExtensionInfoFromPath = function(srcDirectory) { } }; - // The loaded extensions cache and its persistent path. - loadedExtensions = null; - loadedExtensionsPath = null; - // Persistent loaded extensions. - app = electron.app; app.on('will-quit', function() { @@ -83,9 +74,7 @@ app.on('will-quit', function() { } }); - // We can not use protocol or BrowserWindow until app is ready. - app.once('ready', function() { var BrowserWindow, chromeExtensionHandler, e, error1, i, init, len, protocol, srcDirectory; protocol = electron.protocol, BrowserWindow = electron.BrowserWindow; diff --git a/atom/browser/lib/desktop-capturer.js b/atom/browser/lib/desktop-capturer.js index 68da4e27f1e4..638d87c3af32 100644 --- a/atom/browser/lib/desktop-capturer.js +++ b/atom/browser/lib/desktop-capturer.js @@ -8,9 +8,7 @@ deepEqual = function(opt1, opt2) { return JSON.stringify(opt1) === JSON.stringify(opt2); }; - // A queue for holding all requests from renderer process. - requestsQueue = []; ipcMain.on('ATOM_BROWSER_DESKTOP_CAPTURER_GET_SOURCES', function(event, captureWindow, captureScreen, thumbnailSize, id) { @@ -37,7 +35,6 @@ ipcMain.on('ATOM_BROWSER_DESKTOP_CAPTURER_GET_SOURCES', function(event, captureW }); desktopCapturer.emit = function(event, name, sources) { - // Receiving sources result from main process, now send them back to renderer. var captureScreen, captureWindow, handledRequest, i, len, ref, ref1, ref2, request, result, source, thumbnailSize, unhandledRequestsQueue; handledRequest = requestsQueue.shift(0); diff --git a/atom/browser/lib/guest-view-manager.js b/atom/browser/lib/guest-view-manager.js index fa409f89c41b..a07803069966 100644 --- a/atom/browser/lib/guest-view-manager.js +++ b/atom/browser/lib/guest-view-manager.js @@ -3,9 +3,7 @@ var attachGuest, createGuest, destroyGuest, embedderElementsMap, getNextInstance ref = require('electron'), ipcMain = ref.ipcMain, webContents = ref.webContents; - // Doesn't exist in early initialization. - webViewManager = null; supportedWebViewEvents = ['load-commit', 'did-finish-load', 'did-fail-load', 'did-frame-finish-load', 'did-start-loading', 'did-stop-loading', 'did-get-response-details', 'did-get-redirect-request', 'dom-ready', 'console-message', 'devtools-opened', 'devtools-closed', 'devtools-focused', 'new-window', 'will-navigate', 'did-navigate', 'did-navigate-in-page', 'close', 'crashed', 'gpu-crashed', 'plugin-crashed', 'destroyed', 'page-title-updated', 'page-favicon-updated', 'enter-html-full-screen', 'leave-html-full-screen', 'media-started-playing', 'media-paused', 'found-in-page', 'did-change-theme-color']; @@ -18,23 +16,17 @@ embedderElementsMap = {}; reverseEmbedderElementsMap = {}; - // Moves the last element of array to the first one. - moveLastToFirst = function(list) { return list.unshift(list.pop()); }; - // Generate guestInstanceId. - getNextInstanceId = function(webContents) { return ++nextInstanceId; }; - // Create a new guest instance. - createGuest = function(embedder, params) { var destroy, destroyEvents, event, fn, guest, i, id, j, len, len1, listeners; if (webViewManager == null) { @@ -146,9 +138,7 @@ createGuest = function(embedder, params) { return id; }; - // Attach the guest to an element of embedder. - attachGuest = function(embedder, elementInstanceId, guestInstanceId, params) { var guest, key, oldGuestInstanceId, ref1, webPreferences; guest = guestInstances[guestInstanceId].guest; @@ -182,9 +172,7 @@ attachGuest = function(embedder, elementInstanceId, guestInstanceId, params) { return reverseEmbedderElementsMap[guestInstanceId] = key; }; - // Destroy an existing guest instance. - destroyGuest = function(embedder, id) { var key; webViewManager.removeGuest(embedder, id); @@ -219,17 +207,13 @@ ipcMain.on('ATOM_SHELL_GUEST_VIEW_MANAGER_SET_ALLOW_TRANSPARENCY', function(even return (ref1 = guestInstances[id]) != null ? ref1.guest.setAllowTransparency(allowtransparency) : void 0; }); - // Returns WebContents from its guest id. - exports.getGuest = function(id) { var ref1; return (ref1 = guestInstances[id]) != null ? ref1.guest : void 0; }; - // Returns the embedder of the guest. - exports.getEmbedder = function(id) { var ref1; return (ref1 = guestInstances[id]) != null ? ref1.embedder : void 0; diff --git a/atom/browser/lib/guest-window-manager.js b/atom/browser/lib/guest-window-manager.js index df129b4a0928..f57b8eb1327e 100644 --- a/atom/browser/lib/guest-window-manager.js +++ b/atom/browser/lib/guest-window-manager.js @@ -8,9 +8,7 @@ v8Util = process.atomBinding('v8_util'); frameToGuest = {}; - // Copy attribute of |parent| to |child| if it is not defined in |child|. - mergeOptions = function(child, parent) { var key, value; for (key in parent) { @@ -27,9 +25,7 @@ mergeOptions = function(child, parent) { return child; }; - // Merge |options| with the |embedder|'s window's options. - mergeBrowserWindowOptions = function(embedder, options) { if (embedder.browserWindowOptions != null) { @@ -46,9 +42,7 @@ mergeBrowserWindowOptions = function(embedder, options) { return options; }; - // Create a new guest created by |embedder| with |options|. - createGuest = function(embedder, url, frameName, options) { var closedByEmbedder, closedByUser, guest, guestId, ref1; guest = frameToGuest[frameName]; @@ -89,9 +83,7 @@ createGuest = function(embedder, url, frameName, options) { return guest.id; }; - // Routed window.open messages. - ipcMain.on('ATOM_SHELL_GUEST_WINDOW_MANAGER_WINDOW_OPEN', function() { var args, event, frameName, options, url; event = arguments[0], args = 2 <= arguments.length ? slice.call(arguments, 1) : []; diff --git a/atom/browser/lib/init.js b/atom/browser/lib/init.js index 9ce4e55ee3be..03e4c9c18718 100644 --- a/atom/browser/lib/init.js +++ b/atom/browser/lib/init.js @@ -9,12 +9,8 @@ util = require('util'); Module = require('module'); - // We modified the original process.argv to let node.js load the atom.js, - - // we need to restore it here. - process.argv.splice(1, 1); // Clear search paths. @@ -62,9 +58,7 @@ if (process.platform === 'win32') { }); } - // Don't quit on fatal error. - process.on('uncaughtException', function(error) { // Do nothing if the user has a custom uncaught exception handler. @@ -80,35 +74,26 @@ process.on('uncaughtException', function(error) { return dialog.showErrorBox('A JavaScript error occurred in the main process', message); }); - // Emit 'exit' event on quit. - app = require('electron').app; app.on('quit', function(event, exitCode) { return process.emit('exit', exitCode); }); - // Map process.exit to app.exit, which quits gracefully. - process.exit = app.exit; - // Load the RPC server. - require('./rpc-server'); - // Load the guest view manager. - require('./guest-view-manager'); require('./guest-window-manager'); // Now we try to load app's package.json. - packageJson = null; searchPaths = ['app', 'app.asar', 'default_app']; @@ -132,61 +117,43 @@ if (packageJson == null) { throw new Error("Unable to find a valid app"); } - // Set application's version. - if (packageJson.version != null) { app.setVersion(packageJson.version); } - // Set application's name. - if (packageJson.productName != null) { app.setName(packageJson.productName); } else if (packageJson.name != null) { app.setName(packageJson.name); } - // Set application's desktop name. - if (packageJson.desktopName != null) { app.setDesktopName(packageJson.desktopName); } else { app.setDesktopName((app.getName()) + ".desktop"); } - // Chrome 42 disables NPAPI plugins by default, reenable them here - app.commandLine.appendSwitch('enable-npapi'); - // Set the user path according to application's name. - app.setPath('userData', path.join(app.getPath('appData'), app.getName())); app.setPath('userCache', path.join(app.getPath('cache'), app.getName())); app.setAppPath(packagePath); - // Load the chrome extension support. - require('./chrome-extension'); - // Load internal desktop-capturer module. - require('./desktop-capturer'); - // Set main startup script of the app. - mainStartupScript = packageJson.main || 'index.js'; - // Finally load app's main.js and transfer control to C++. - Module._load(path.join(packagePath, mainStartupScript), Module, true); diff --git a/atom/browser/lib/objects-registry.js b/atom/browser/lib/objects-registry.js index 082f1ef3441d..a468c89219cc 100644 --- a/atom/browser/lib/objects-registry.js +++ b/atom/browser/lib/objects-registry.js @@ -65,7 +65,6 @@ ObjectsRegistry = (function(superClass) { } }; - // Clear all references to objects refrenced by the WebContents. ObjectsRegistry.prototype.clear = function(webContentsId) { var count, id, ref; @@ -81,7 +80,6 @@ ObjectsRegistry = (function(superClass) { return delete this.owners[webContentsId]; }; - // Private: Saves the object into storage and assigns an ID for it. ObjectsRegistry.prototype.saveToStorage = function(object) { var id; @@ -98,7 +96,6 @@ ObjectsRegistry = (function(superClass) { return id; }; - // Private: Dereference the object from store. ObjectsRegistry.prototype.dereference = function(id, count) { var pointer; diff --git a/atom/browser/lib/rpc-server.js b/atom/browser/lib/rpc-server.js index 13405b8ed96d..a8add74e0321 100644 --- a/atom/browser/lib/rpc-server.js +++ b/atom/browser/lib/rpc-server.js @@ -13,9 +13,7 @@ v8Util = process.atomBinding('v8_util'); IDWeakMap = process.atomBinding('id_weak_map').IDWeakMap; - // Convert a real value into meta data. - valueToMeta = function(sender, value, optimizeSimpleObject) { var el, field, i, len, meta, name; if (optimizeSimpleObject == null) { @@ -98,9 +96,7 @@ valueToMeta = function(sender, value, optimizeSimpleObject) { return meta; }; - // Convert object to meta by value. - plainObjectToMeta = function(obj) { return Object.getOwnPropertyNames(obj).map(function(name) { return { @@ -110,9 +106,7 @@ plainObjectToMeta = function(obj) { }); }; - // Convert Error into meta data. - exceptionToMeta = function(error) { return { type: 'exception', @@ -121,9 +115,7 @@ exceptionToMeta = function(error) { }; }; - // Convert array of meta data from renderer into array of real values. - unwrapArgs = function(sender, args) { var metaToValue; metaToValue = function(meta) { @@ -157,7 +149,6 @@ unwrapArgs = function(sender, args) { return returnValue; }; case 'function': - // Cache the callbacks in renderer. if (!sender.callbacks) { sender.callbacks = new IDWeakMap; @@ -221,7 +212,6 @@ callFunction = function(event, func, caller, args) { } }; - // Send by BrowserWindow when its render view is deleted. process.on('ATOM_BROWSER_RELEASE_RENDER_VIEW', function(id) { return objectsRegistry.clear(id); diff --git a/atom/common/api/lib/callbacks-registry.js b/atom/common/api/lib/callbacks-registry.js index 5c74388ec409..e4cfe8161236 100644 --- a/atom/common/api/lib/callbacks-registry.js +++ b/atom/common/api/lib/callbacks-registry.js @@ -10,7 +10,6 @@ module.exports = CallbacksRegistry = (function() { } CallbacksRegistry.prototype.add = function(callback) { - // The callback is already added. var filenameAndLine, id, location, match, ref, regexp, stackString, x; id = v8Util.getHiddenValue(callback, 'callbackId'); diff --git a/atom/common/api/lib/clipboard.js b/atom/common/api/lib/clipboard.js index 02b3de2e0623..cd1cb53e4001 100644 --- a/atom/common/api/lib/clipboard.js +++ b/atom/common/api/lib/clipboard.js @@ -1,5 +1,4 @@ if (process.platform === 'linux' && process.type === 'renderer') { - // On Linux we could not access clipboard in renderer process. module.exports = require('electron').remote.clipboard; } else { diff --git a/atom/common/api/lib/deprecate.js b/atom/common/api/lib/deprecate.js index b588bb1af41e..dcaf5f6cf6f9 100644 --- a/atom/common/api/lib/deprecate.js +++ b/atom/common/api/lib/deprecate.js @@ -1,4 +1,3 @@ - // Deprecate a method. var deprecate, slice = [].slice; @@ -15,9 +14,7 @@ deprecate = function(oldName, newName, fn) { }; }; - // The method is renamed. - deprecate.rename = function(object, oldName, newName) { var newMethod, warned; warned = false; @@ -35,9 +32,7 @@ deprecate.rename = function(object, oldName, newName) { } }; - // Forward the method to member. - deprecate.member = function(object, method, member) { var warned; warned = false; @@ -50,9 +45,7 @@ deprecate.member = function(object, method, member) { }; }; - // Deprecate a property. - deprecate.property = function(object, property, method) { return Object.defineProperty(object, property, { get: function() { @@ -67,9 +60,7 @@ deprecate.property = function(object, property, method) { }); }; - // Deprecate an event. - deprecate.event = function(emitter, oldName, newName, fn) { var warned; warned = false; @@ -92,16 +83,12 @@ deprecate.event = function(emitter, oldName, newName, fn) { }); }; - // Print deprecation warning. - deprecate.warn = function(oldName, newName) { return deprecate.log(oldName + " is deprecated. Use " + newName + " instead."); }; - // Print deprecation message. - deprecate.log = function(message) { if (process.throwDeprecation) { throw new Error(message); diff --git a/atom/common/api/lib/exports/electron.js b/atom/common/api/lib/exports/electron.js index f818fb4cac80..178b2d1046bc 100644 --- a/atom/common/api/lib/exports/electron.js +++ b/atom/common/api/lib/exports/electron.js @@ -1,4 +1,3 @@ - // Do not expose the internal modules to `require`. exports.hideInternalModules = function() { var globalPaths; @@ -10,9 +9,7 @@ exports.hideInternalModules = function() { } }; - // Attaches properties to |exports|. - exports.defineProperties = function(exports) { return Object.defineProperties(exports, { diff --git a/atom/common/api/lib/native-image.js b/atom/common/api/lib/native-image.js index 44a4330fa894..1546cfaa7e6d 100644 --- a/atom/common/api/lib/native-image.js +++ b/atom/common/api/lib/native-image.js @@ -4,9 +4,7 @@ deprecate = require('electron').deprecate; nativeImage = process.atomBinding('native_image'); - // Deprecated. - deprecate.rename(nativeImage, 'createFromDataUrl', 'createFromDataURL'); module.exports = nativeImage; diff --git a/atom/common/lib/asar.js b/atom/common/lib/asar.js index 843b6d75aa7f..82a5139ee67e 100644 --- a/atom/common/lib/asar.js +++ b/atom/common/lib/asar.js @@ -10,9 +10,7 @@ path = require('path'); util = require('util'); - // Cache asar archive objects. - cachedArchives = {}; getOrCreateArchive = function(p) { @@ -28,9 +26,7 @@ getOrCreateArchive = function(p) { return cachedArchives[p] = archive; }; - // Clean cache on quit. - process.on('exit', function() { var archive, p, results; results = []; @@ -42,9 +38,7 @@ process.on('exit', function() { return results; }); - // Separate asar package's path from full path. - splitPath = function(p) { // shortcut to disable asar. @@ -66,9 +60,7 @@ splitPath = function(p) { return [true, p.substr(0, index + 5), p.substr(index + 6)]; }; - // Convert asar archive's Stats object to fs's Stats object. - nextInode = 0; uid = process.getuid != null ? process.getuid() : 0; @@ -115,9 +107,7 @@ asarStatsToFsStats = function(stats) { }; }; - // Create a ENOENT error. - notFoundError = function(asarPath, filePath, callback) { var error; error = new Error("ENOENT, " + filePath + " not found in " + asarPath); @@ -131,9 +121,7 @@ notFoundError = function(asarPath, filePath, callback) { }); }; - // Create a ENOTDIR error. - notDirError = function(callback) { var error; error = new Error('ENOTDIR, not a directory'); @@ -147,9 +135,7 @@ notDirError = function(callback) { }); }; - // Create invalid archive error. - invalidArchiveError = function(asarPath, callback) { var error; error = new Error("Invalid package " + asarPath); @@ -161,9 +147,7 @@ invalidArchiveError = function(asarPath, callback) { }); }; - // Override APIs that rely on passing file path instead of content to C++. - overrideAPISync = function(module, name, arg) { var old; if (arg == null) { @@ -220,9 +204,7 @@ overrideAPI = function(module, name, arg) { }; }; - // Override fs APIs. - exports.wrapFsWithAsar = function(fs) { var exists, existsSync, internalModuleReadFile, internalModuleStat, lstat, lstatSync, mkdir, mkdirSync, open, openSync, readFile, readFileSync, readdir, readdirSync, realpath, realpathSync, stat, statSync, statSyncNoException; lstatSync = fs.lstatSync; diff --git a/atom/common/lib/init.js b/atom/common/lib/init.js index dca836c7db81..2165603e87e6 100644 --- a/atom/common/lib/init.js +++ b/atom/common/lib/init.js @@ -21,7 +21,6 @@ process.atomBinding = function(name) { }; if (!process.env.ELECTRON_HIDE_INTERNAL_MODULES) { - // Add common/api/lib to module search paths. Module.globalPaths.push(path.resolve(__dirname, '..', 'api', 'lib')); } @@ -47,7 +46,6 @@ global.setImmediate = wrapWithActivateUvLoop(timers.setImmediate); global.clearImmediate = timers.clearImmediate; if (process.type === 'browser') { - // setTimeout needs to update the polling timeout of the event loop, when // called under Chromium's event loop the node's event loop won't get a chance // to update the timeout, so we have to force the node's event loop to diff --git a/atom/common/lib/reset-search-paths.js b/atom/common/lib/reset-search-paths.js index ef7a5913c205..a996cd4ceca8 100644 --- a/atom/common/lib/reset-search-paths.js +++ b/atom/common/lib/reset-search-paths.js @@ -4,21 +4,15 @@ path = require('path'); Module = require('module'); - // Clear Node's global search paths. - Module.globalPaths.length = 0; - // Clear current and parent(init.coffee)'s search paths. - module.paths = []; module.parent.paths = []; - // Prevent Node from adding paths outside this app to search paths. - Module._nodeModulePaths = function(from) { var dir, i, part, parts, paths, skipOutsidePaths, splitRe, tip; from = path.resolve(from); diff --git a/atom/renderer/api/lib/desktop-capturer.js b/atom/renderer/api/lib/desktop-capturer.js index ce9443c1ed8a..5b44bdf5f23e 100644 --- a/atom/renderer/api/lib/desktop-capturer.js +++ b/atom/renderer/api/lib/desktop-capturer.js @@ -9,9 +9,7 @@ getNextId = function() { return ++nextId; }; - // |options.type| can not be empty and has to include 'window' or 'screen'. - isValid = function(options) { return ((options != null ? options.types : void 0) != null) && Array.isArray(options.types); }; diff --git a/atom/renderer/api/lib/exports/electron.js b/atom/renderer/api/lib/exports/electron.js index a740d88bd0a4..e3fe7b335317 100644 --- a/atom/renderer/api/lib/exports/electron.js +++ b/atom/renderer/api/lib/exports/electron.js @@ -2,13 +2,10 @@ var common; common = require('../../../../common/api/lib/exports/electron'); - // Import common modules. - common.defineProperties(exports); Object.defineProperties(exports, { - // Renderer side modules, please sort with alphabet order. desktopCapturer: { enumerable: true, diff --git a/atom/renderer/api/lib/ipc-renderer.js b/atom/renderer/api/lib/ipc-renderer.js index 95e9b097d1e8..cd6b37c3db45 100644 --- a/atom/renderer/api/lib/ipc-renderer.js +++ b/atom/renderer/api/lib/ipc-renderer.js @@ -7,9 +7,7 @@ binding = process.atomBinding('ipc'); v8Util = process.atomBinding('v8_util'); - // Created by init.coffee. - ipcRenderer = v8Util.getHiddenValue(global, 'ipc'); ipcRenderer.send = function() { diff --git a/atom/renderer/api/lib/ipc.js b/atom/renderer/api/lib/ipc.js index 3578c56d3da9..1e0e703e6a84 100644 --- a/atom/renderer/api/lib/ipc.js +++ b/atom/renderer/api/lib/ipc.js @@ -5,14 +5,10 @@ ref = require('electron'), ipcRenderer = ref.ipcRenderer, deprecate = ref.deprec EventEmitter = require('events').EventEmitter; - // This module is deprecated, we mirror everything from ipcRenderer. - deprecate.warn('ipc module', 'require("electron").ipcRenderer'); - // Routes events of ipcRenderer. - ipc = new EventEmitter; ipcRenderer.emit = function() { @@ -22,9 +18,7 @@ ipcRenderer.emit = function() { return EventEmitter.prototype.emit.apply(ipcRenderer, arguments); }; - // Deprecated. - for (method in ipcRenderer) { if (method.startsWith('send')) { ipc[method] = ipcRenderer[method]; diff --git a/atom/renderer/api/lib/remote.js b/atom/renderer/api/lib/remote.js index 8eb7bc21c24e..f50fca7a2d4a 100644 --- a/atom/renderer/api/lib/remote.js +++ b/atom/renderer/api/lib/remote.js @@ -7,9 +7,7 @@ v8Util = process.atomBinding('v8_util'); callbacksRegistry = new CallbacksRegistry; - // Check for circular reference. - isCircular = function(field, visited) { if (typeof field === 'object') { if (indexOf.call(visited, field) >= 0) { @@ -20,9 +18,7 @@ isCircular = function(field, visited) { return false; }; - // Convert the arguments object into an array of meta data. - wrapArgs = function(args, visited) { var valueToMeta; if (visited == null) { @@ -90,9 +86,7 @@ wrapArgs = function(args, visited) { return Array.prototype.slice.call(args).map(valueToMeta); }; - // Convert meta data from browser into real value. - metaToValue = function(meta) { var RemoteFunction, el, i, j, len, len1, member, ref1, ref2, results, ret; switch (meta.type) { @@ -121,7 +115,6 @@ metaToValue = function(meta) { break; default: if (meta.type === 'function') { - // A shadow class to represent the remote function object. ret = RemoteFunction = (function() { function RemoteFunction() { @@ -163,10 +156,8 @@ metaToValue = function(meta) { } } - /* - Track delegate object's life time, and tell the browser to clean up - when the object is GCed. - */ + // Track delegate object's life time, and tell the browser to clean up + // when the object is GCed. v8Util.setDestructor(ret, function() { return ipcRenderer.send('ATOM_BROWSER_DEREFERENCE', meta.id); }); @@ -177,9 +168,7 @@ metaToValue = function(meta) { } }; - // Construct a plain object from the meta. - metaToPlainObject = function(meta) { var i, len, name, obj, ref1, ref2, value; obj = (function() { @@ -198,13 +187,9 @@ metaToPlainObject = function(meta) { return obj; }; - -/* - Create a RemoteMemberFunction instance. - This function's content should not be inlined into metaToValue, otherwise V8 - may consider it circular reference. - */ - +// Create a RemoteMemberFunction instance. +// This function's content should not be inlined into metaToValue, otherwise V8 +// may consider it circular reference. createRemoteMemberFunction = function(metaId, name) { var RemoteMemberFunction; return RemoteMemberFunction = (function() { @@ -228,13 +213,9 @@ createRemoteMemberFunction = function(metaId, name) { })(); }; - -/* - Create configuration for defineProperty. - This function's content should not be inlined into metaToValue, otherwise V8 - may consider it circular reference. - */ - +// Create configuration for defineProperty. +// This function's content should not be inlined into metaToValue, otherwise V8 +// may consider it circular reference. createRemoteMemberProperty = function(metaId, name) { return { enumerable: true, @@ -253,28 +234,20 @@ createRemoteMemberProperty = function(metaId, name) { }; }; - // Browser calls a callback in renderer. - ipcRenderer.on('ATOM_RENDERER_CALLBACK', function(event, id, args) { return callbacksRegistry.apply(id, metaToValue(args)); }); - // A callback in browser is released. - ipcRenderer.on('ATOM_RENDERER_RELEASE_CALLBACK', function(event, id) { return callbacksRegistry.remove(id); }); - // List all built-in modules in browser process. - browserModules = require('../../../browser/api/lib/exports/electron'); - // And add a helper receiver for each one. - fn = function(name) { return Object.defineProperty(exports, name, { get: function() { @@ -287,12 +260,9 @@ for (name in browserModules) { } -/* - Get remote module. - (Just like node's require, the modules are cached permanently, note that this - is safe leak since the object is not expected to get freed in browser) - */ - +// Get remote module. +// (Just like node's require, the modules are cached permanently, note that this +// is safe leak since the object is not expected to get freed in browser) moduleCache = {}; exports.require = function(module) { @@ -306,12 +276,10 @@ exports.require = function(module) { // Optimize require('electron'). - moduleCache.electron = exports; // Alias to remote.require('electron').xxx. - builtinCache = {}; exports.getBuiltin = function(module) { @@ -323,9 +291,7 @@ exports.getBuiltin = function(module) { return builtinCache[module] = metaToValue(meta); }; - // Get current BrowserWindow object. - windowCache = null; exports.getCurrentWindow = function() { @@ -337,9 +303,7 @@ exports.getCurrentWindow = function() { return windowCache = metaToValue(meta); }; - // Get current WebContents object. - webContentsCache = null; exports.getCurrentWebContents = function() { @@ -351,18 +315,14 @@ exports.getCurrentWebContents = function() { return webContentsCache = metaToValue(meta); }; - // Get a global object in browser. - exports.getGlobal = function(name) { var meta; meta = ipcRenderer.sendSync('ATOM_BROWSER_GLOBAL', name); return metaToValue(meta); }; - // Get the process object in browser. - processCache = null; exports.__defineGetter__('process', function() { @@ -372,9 +332,7 @@ exports.__defineGetter__('process', function() { return processCache; }); - // Create a funtion that will return the specifed value when called in browser. - exports.createFunctionWithReturnValue = function(returnValue) { var func; func = function() { @@ -384,9 +342,7 @@ exports.createFunctionWithReturnValue = function(returnValue) { return func; }; - // Get the guest WebContents from guestInstanceId. - exports.getGuestWebContents = function(guestInstanceId) { var meta; meta = ipcRenderer.sendSync('ATOM_BROWSER_GUEST_WEB_CONTENTS', guestInstanceId); diff --git a/atom/renderer/lib/init.js b/atom/renderer/lib/init.js index 0f651218ecdb..8fd0d2e25e71 100644 --- a/atom/renderer/lib/init.js +++ b/atom/renderer/lib/init.js @@ -11,21 +11,16 @@ 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. - */ - +// We modified the original process.argv to let node.js load the +// atom-renderer.js, we need to restore it here. process.argv.splice(1, 1); // Clear search paths. - require(path.resolve(__dirname, '..', '..', 'common', 'lib', 'reset-search-paths')); // Import common settings. - require(path.resolve(__dirname, '..', '..', 'common', 'lib', 'init')); globalPaths = Module.globalPaths; @@ -34,14 +29,10 @@ if (!process.env.ELECTRON_HIDE_INTERNAL_MODULES) { globalPaths.push(path.resolve(__dirname, '..', 'api', 'lib')); } - // Expose public APIs. - globalPaths.push(path.resolve(__dirname, '..', 'api', 'lib', 'exports')); - // The global variable will be used by ipc for event dispatching - v8Util = process.atomBinding('v8_util'); v8Util.setHiddenValue(global, 'ipc', new events.EventEmitter); @@ -55,18 +46,15 @@ electron.ipcRenderer.on('ELECTRON_INTERNAL_RENDERER_WEB_FRAME_METHOD', (event, m }); // Process command line arguments. - nodeIntegration = 'false'; ref = process.argv; for (i = 0, len = ref.length; i < len; i++) { arg = ref[i]; if (arg.indexOf('--guest-instance-id=') === 0) { - // This is a guest web view. process.guestInstanceId = parseInt(arg.substr(arg.indexOf('=') + 1)); } else if (arg.indexOf('--opener-id=') === 0) { - // This is a guest BrowserWindow. process.openerId = parseInt(arg.substr(arg.indexOf('=') + 1)); } else if (arg.indexOf('--node-integration=') === 0) { @@ -77,17 +65,14 @@ for (i = 0, len = ref.length; i < len; i++) { } if (location.protocol === 'chrome-devtools:') { - // Override some inspector APIs. require('./inspector'); nodeIntegration = 'true'; } else if (location.protocol === 'chrome-extension:') { - // Add implementations of chrome API. require('./chrome-api'); nodeIntegration = 'true'; } else { - // Override default web functions. require('./override'); @@ -99,7 +84,6 @@ if (location.protocol === 'chrome-devtools:') { } if (nodeIntegration === 'true' || nodeIntegration === 'all' || nodeIntegration === 'except-iframe' || nodeIntegration === 'manual-enable-iframe') { - // Export node bindings to global. global.require = require; global.module = module; @@ -135,7 +119,6 @@ if (nodeIntegration === 'true' || nodeIntegration === 'all' || nodeIntegration = return process.emit('exit'); }); } else { - // Delete Node's symbols after the Environment has been loaded. process.once('loaded', function() { delete global.process; @@ -145,9 +128,7 @@ if (nodeIntegration === 'true' || nodeIntegration === 'all' || nodeIntegration = }); } - // Load the script specfied by the "preload" attribute. - if (preloadScript) { try { require(preloadScript); diff --git a/atom/renderer/lib/inspector.js b/atom/renderer/lib/inspector.js index 54c02f011dc7..b37e1d3de905 100644 --- a/atom/renderer/lib/inspector.js +++ b/atom/renderer/lib/inspector.js @@ -1,7 +1,6 @@ var convertToMenuTemplate, createFileSelectorElement, createMenu, pathToHtml5FileObject, showFileChooserDialog; window.onload = function() { - // Use menu API to show context menu. InspectorFrontendHost.showContextMenuAtPoint = createMenu; diff --git a/atom/renderer/lib/override.js b/atom/renderer/lib/override.js index 27d8fdc3f210..c240281363b9 100644 --- a/atom/renderer/lib/override.js +++ b/atom/renderer/lib/override.js @@ -3,9 +3,7 @@ var BrowserWindowProxy, a, getHistoryOperation, ipcRenderer, ref, remote, resolv ref = require('electron'), ipcRenderer = ref.ipcRenderer, remote = ref.remote; - // Helper function to resolve relative url. - a = window.top.document.createElement('a'); resolveURL = function(url) { @@ -13,9 +11,7 @@ resolveURL = function(url) { return a.href; }; - // Window object returned by "window.open". - BrowserWindowProxy = (function() { BrowserWindowProxy.proxies = {}; @@ -69,16 +65,13 @@ BrowserWindowProxy = (function() { })(); if (process.guestInstanceId == null) { - // Override default window.close. window.close = function() { return remote.getCurrentWindow().close(); }; } - // Make the browser window or guest view emit "new-window" event. - window.open = function(url, frameName, features) { var feature, guestId, i, ints, j, len, len1, name, options, ref1, ref2, value; if (frameName == null) { @@ -133,9 +126,7 @@ window.open = function(url, frameName, features) { } }; - // Use the dialog API to implement alert(). - window.alert = function(message, title) { var buttons; if (title == null) { @@ -152,9 +143,7 @@ window.alert = function(message, title) { // Alert should always return undefined. }; - // And the confirm(). - window.confirm = function(message, title) { var buttons, cancelId; if (title == null) { @@ -170,9 +159,7 @@ window.confirm = function(message, title) { }); }; - // But we do not support prompt(). - window.prompt = function() { throw new Error('prompt() is and will not be supported.'); }; @@ -182,9 +169,7 @@ if (process.openerId != null) { } ipcRenderer.on('ATOM_SHELL_GUEST_WINDOW_POSTMESSAGE', function(event, sourceId, message, sourceOrigin) { - // Manually dispatch event instead of using postMessage because we also need to - // set event.source. event = document.createEvent('Event'); event.initEvent('message', false, false); @@ -194,9 +179,7 @@ ipcRenderer.on('ATOM_SHELL_GUEST_WINDOW_POSTMESSAGE', function(event, sourceId, return window.dispatchEvent(event); }); - // Forward history operations to browser. - sendHistoryOperation = function() { var args; args = 1 <= arguments.length ? slice.call(arguments, 0) : []; @@ -227,9 +210,7 @@ Object.defineProperty(window.history, 'length', { } }); - // Make document.hidden and document.visibilityState return the correct value. - Object.defineProperty(document, 'hidden', { get: function() { var currentWindow; diff --git a/atom/renderer/lib/web-view/web-view-attributes.js b/atom/renderer/lib/web-view/web-view-attributes.js index ddf17b9f9ed7..0352dc5e821d 100644 --- a/atom/renderer/lib/web-view/web-view-attributes.js +++ b/atom/renderer/lib/web-view/web-view-attributes.js @@ -10,9 +10,7 @@ webViewConstants = require('./web-view-constants'); remote = require('electron').remote; - // Helper function to resolve url set in attribute. - a = document.createElement('a'); resolveURL = function(url) { @@ -20,12 +18,8 @@ resolveURL = function(url) { return a.href; }; - -/* - Attribute objects. - Default implementation of a WebView attribute. - */ - +// Attribute objects. +// Default implementation of a WebView attribute. WebViewAttribute = (function() { function WebViewAttribute(name, webViewImpl) { this.name = name; @@ -35,32 +29,24 @@ WebViewAttribute = (function() { this.defineProperty(); } - // Retrieves and returns the attribute's value. - WebViewAttribute.prototype.getValue = function() { return this.webViewImpl.webviewNode.getAttribute(this.name) || this.value; }; - // Sets the attribute's value. - WebViewAttribute.prototype.setValue = function(value) { return this.webViewImpl.webviewNode.setAttribute(this.name, value || ''); }; - // Changes the attribute's value without triggering its mutation handler. - WebViewAttribute.prototype.setValueIgnoreMutation = function(value) { this.ignoreMutation = true; this.setValue(value); return this.ignoreMutation = false; }; - // Defines this attribute as a property on the webview node. - WebViewAttribute.prototype.defineProperty = function() { return Object.defineProperty(this.webViewImpl.webviewNode, this.name, { get: (function(_this) { @@ -77,18 +63,14 @@ WebViewAttribute = (function() { }); }; - // Called when the attribute's value changes. - WebViewAttribute.prototype.handleMutation = function() {}; return WebViewAttribute; })(); - // An attribute that is treated as a Boolean. - BooleanAttribute = (function(superClass) { extend(BooleanAttribute, superClass); @@ -112,9 +94,7 @@ BooleanAttribute = (function(superClass) { })(WebViewAttribute); - // Attribute that specifies whether transparency is allowed in the webview. - AllowTransparencyAttribute = (function(superClass) { extend(AllowTransparencyAttribute, superClass); @@ -133,9 +113,7 @@ AllowTransparencyAttribute = (function(superClass) { })(BooleanAttribute); - // Attribute used to define the demension limits of autosizing. - AutosizeDimensionAttribute = (function(superClass) { extend(AutosizeDimensionAttribute, superClass); @@ -168,9 +146,7 @@ AutosizeDimensionAttribute = (function(superClass) { })(WebViewAttribute); - // Attribute that specifies whether the webview should be autosized. - AutosizeAttribute = (function(superClass) { extend(AutosizeAttribute, superClass); @@ -184,9 +160,7 @@ AutosizeAttribute = (function(superClass) { })(BooleanAttribute); - // Attribute representing the state of the storage partition. - PartitionAttribute = (function(superClass) { extend(PartitionAttribute, superClass); @@ -214,9 +188,7 @@ PartitionAttribute = (function(superClass) { })(WebViewAttribute); - // Attribute that handles the location and navigation of the webview. - SrcAttribute = (function(superClass) { extend(SrcAttribute, superClass); @@ -236,29 +208,23 @@ SrcAttribute = (function(superClass) { SrcAttribute.prototype.setValueIgnoreMutation = function(value) { WebViewAttribute.prototype.setValueIgnoreMutation.call(this, value); - /* - takeRecords() is needed to clear queued up src mutations. Without it, it - is possible for this change to get picked up asyncronously by src's - mutation observer |observer|, and then get handled even though we do not - want to handle this mutation. - */ + // takeRecords() is needed to clear queued up src mutations. Without it, it + // is possible for this change to get picked up asyncronously by src's + // mutation observer |observer|, and then get handled even though we do not + // want to handle this mutation. return this.observer.takeRecords(); }; SrcAttribute.prototype.handleMutation = function(oldValue, newValue) { - /* - Once we have navigated, we don't allow clearing the src attribute. - Once enters a navigated state, it cannot return to a - placeholder state. - */ + // Once we have navigated, we don't allow clearing the src attribute. + // Once enters a navigated state, it cannot return to a + // placeholder state. if (!newValue && oldValue) { - /* - src attribute changes normally initiate a navigation. We suppress - the next src attribute handler call to avoid reloading the page - on every guest-initiated navigation. - */ + // src attribute changes normally initiate a navigation. We suppress + // the next src attribute handler call to avoid reloading the page + // on every guest-initiated navigation. this.setValueIgnoreMutation(oldValue); return; } @@ -266,13 +232,10 @@ SrcAttribute = (function(superClass) { }; - /* - The purpose of this mutation observer is to catch assignment to the src - attribute without any changes to its value. This is useful in the case - where the webview guest has crashed and navigating to the same address - spawns off a new process. - */ - + // The purpose of this mutation observer is to catch assignment to the src + // attribute without any changes to its value. This is useful in the case + // where the webview guest has crashed and navigating to the same address + // spawns off a new process. SrcAttribute.prototype.setupMutationObserver = function() { var params; this.observer = new MutationObserver((function(_this) { @@ -328,9 +291,7 @@ SrcAttribute = (function(superClass) { })(WebViewAttribute); - // Attribute specifies HTTP referrer. - HttpReferrerAttribute = (function(superClass) { extend(HttpReferrerAttribute, superClass); @@ -342,9 +303,7 @@ HttpReferrerAttribute = (function(superClass) { })(WebViewAttribute); - // Attribute specifies user agent - UserAgentAttribute = (function(superClass) { extend(UserAgentAttribute, superClass); @@ -356,9 +315,7 @@ UserAgentAttribute = (function(superClass) { })(WebViewAttribute); - // Attribute that set preload script. - PreloadAttribute = (function(superClass) { extend(PreloadAttribute, superClass); @@ -384,9 +341,7 @@ PreloadAttribute = (function(superClass) { })(WebViewAttribute); - // Sets up all of the webview attributes. - WebViewImpl.prototype.setupWebViewAttributes = function() { var attribute, autosizeAttributes, i, len, results; this.attributes = {}; diff --git a/atom/renderer/lib/web-view/web-view-constants.js b/atom/renderer/lib/web-view/web-view-constants.js index 9ca98340ced5..418083061a26 100644 --- a/atom/renderer/lib/web-view/web-view-constants.js +++ b/atom/renderer/lib/web-view/web-view-constants.js @@ -1,5 +1,4 @@ module.exports = { - // Attributes. ATTRIBUTE_ALLOWTRANSPARENCY: 'allowtransparency', ATTRIBUTE_AUTOSIZE: 'autosize', diff --git a/atom/renderer/lib/web-view/web-view.js b/atom/renderer/lib/web-view/web-view.js index 549c3d4d4795..07624b79b67a 100644 --- a/atom/renderer/lib/web-view/web-view.js +++ b/atom/renderer/lib/web-view/web-view.js @@ -12,18 +12,14 @@ guestViewInternal = require('./guest-view-internal'); webViewConstants = require('./web-view-constants'); - // ID generator. - nextId = 0; getNextId = function() { return ++nextId; }; - // Represents the internal state of the WebView node. - WebViewImpl = (function() { function WebViewImpl(webviewNode) { var shadowRoot; @@ -50,32 +46,25 @@ WebViewImpl = (function() { } WebViewImpl.prototype.createBrowserPluginNode = function() { - - /* - We create BrowserPlugin as a custom element in order to observe changes - to attributes synchronously. - */ + // We create BrowserPlugin as a custom element in order to observe changes + // to attributes synchronously. var browserPluginNode; browserPluginNode = new WebViewImpl.BrowserPlugin(); v8Util.setHiddenValue(browserPluginNode, 'internal', this); return browserPluginNode; }; - // Resets some state upon reattaching element to the DOM. - WebViewImpl.prototype.reset = function() { // Unlisten the zoom-level-changed event. webFrame.removeListener('zoom-level-changed', this.onZoomLevelChanged); - /* - If guestInstanceId is defined then the has navigated and has - already picked up a partition ID. Thus, we need to reset the initialization - state. However, it may be the case that beforeFirstNavigation is false BUT - guestInstanceId has yet to be initialized. This means that we have not - heard back from createGuest yet. We will not reset the flag in this case so - that we don't end up allocating a second guest. - */ + // If guestInstanceId is defined then the has navigated and has + // already picked up a partition ID. Thus, we need to reset the initialization + // state. However, it may be the case that beforeFirstNavigation is false BUT + // guestInstanceId has yet to be initialized. This means that we have not + // heard back from createGuest yet. We will not reset the flag in this case so + // that we don't end up allocating a second guest. if (this.guestInstanceId) { guestViewInternal.destroyGuest(this.guestInstanceId); this.webContents = null; @@ -86,9 +75,7 @@ WebViewImpl = (function() { return this.internalInstanceId = 0; }; - // Sets the .request property. - WebViewImpl.prototype.setRequestPropertyOnWebViewNode = function(request) { return Object.defineProperty(this.webviewNode, 'request', { value: request, @@ -99,12 +86,10 @@ WebViewImpl = (function() { WebViewImpl.prototype.setupFocusPropagation = function() { if (!this.webviewNode.hasAttribute('tabIndex')) { - /* - needs a tabIndex in order to be focusable. - TODO(fsamuel): It would be nice to avoid exposing a tabIndex attribute - to allow to be focusable. - See http://crbug.com/231664. - */ + // needs a tabIndex in order to be focusable. + // TODO(fsamuel): It would be nice to avoid exposing a tabIndex attribute + // to allow to be focusable. + // See http://crbug.com/231664. this.webviewNode.setAttribute('tabIndex', -1); } this.webviewNode.addEventListener('focus', (function(_this) { @@ -124,14 +109,11 @@ WebViewImpl = (function() { }; - /* - This observer monitors mutations to attributes of the and - updates the BrowserPlugin properties accordingly. In turn, updating - a BrowserPlugin property will update the corresponding BrowserPlugin - attribute, if necessary. See BrowserPlugin::UpdateDOMAttribute for more - details. - */ - + // This observer monitors mutations to attributes of the and + // updates the BrowserPlugin properties accordingly. In turn, updating + // a BrowserPlugin property will update the corresponding BrowserPlugin + // attribute, if necessary. See BrowserPlugin::UpdateDOMAttribute for more + // details. WebViewImpl.prototype.handleWebviewAttributeMutation = function(attributeName, oldValue, newValue) { if (!this.attributes[attributeName] || this.attributes[attributeName].ignoreMutation) { return; @@ -164,7 +146,6 @@ WebViewImpl = (function() { height = node.offsetHeight; // Check the current bounds to make sure we do not resize - // outside of current constraints. maxWidth = this.attributes[webViewConstants.ATTRIBUTE_MAXWIDTH].getValue() | width; maxHeight = this.attributes[webViewConstants.ATTRIBUTE_MAXHEIGHT].getValue() | width; @@ -176,16 +157,13 @@ WebViewImpl = (function() { node.style.width = newWidth + 'px'; node.style.height = newHeight + 'px'; - /* - Only fire the DOM event if the size of the has actually - changed. - */ + // Only fire the DOM event if the size of the has actually + // changed. return this.dispatchEvent(webViewEvent); } }; WebViewImpl.prototype.onElementResize = function(newSize) { - // Dispatch the 'resize' event. var resizeEvent; resizeEvent = new Event('resize', { @@ -213,12 +191,8 @@ WebViewImpl = (function() { return this.webviewNode.dispatchEvent(webViewEvent); }; - // Adds an 'on' property on the webview, which can be used to set/unset - - // an event handler. - WebViewImpl.prototype.setupEventProperty = function(eventName) { var propertyName; propertyName = 'on' + eventName.toLowerCase(); @@ -243,20 +217,16 @@ WebViewImpl = (function() { }); }; - // Updates state upon loadcommit. - WebViewImpl.prototype.onLoadCommit = function(webViewEvent) { var newValue, oldValue; oldValue = this.webviewNode.getAttribute(webViewConstants.ATTRIBUTE_SRC); newValue = webViewEvent.url; if (webViewEvent.isMainFrame && (oldValue !== newValue)) { - /* - Touching the src attribute triggers a navigation. To avoid - triggering a page reload on every guest-initiated navigation, - we do not handle this mutation. - */ + // Touching the src attribute triggers a navigation. To avoid + // triggering a page reload on every guest-initiated navigation, + // we do not handle this mutation. return this.attributes[webViewConstants.ATTRIBUTE_SRC].setValueIgnoreMutation(newValue); } }; @@ -278,13 +248,11 @@ WebViewImpl = (function() { params[attributeName] = attribute.getValue(); } - /* - When the WebView is not participating in layout (display:none) - then getBoundingClientRect() would report a width and height of 0. - However, in the case where the WebView has a fixed size we can - use that value to initially size the guest so as to avoid a relayout of - the on display:block. - */ + // When the WebView is not participating in layout (display:none) + // then getBoundingClientRect() would report a width and height of 0. + // However, in the case where the WebView has a fixed size we can + // use that value to initially size the guest so as to avoid a relayout of + // the on display:block. css = window.getComputedStyle(this.webviewNode, null); elementRect = this.webviewNode.getBoundingClientRect(); params.elementWidth = parseInt(elementRect.width) || parseInt(css.getPropertyValue('width')); @@ -305,9 +273,7 @@ WebViewImpl = (function() { })(); - // Registers browser plugin custom element. - registerBrowserPluginElement = function() { var proto; proto = Object.create(HTMLObjectElement.prototype); @@ -329,7 +295,6 @@ registerBrowserPluginElement = function() { return internal.handleBrowserPluginAttributeMutation(name, oldValue, newValue); }; proto.attachedCallback = function() { - // Load the plugin immediately. var unused; return unused = this.nonExistentAttribute; @@ -344,9 +309,7 @@ registerBrowserPluginElement = function() { return delete proto.attributeChangedCallback; }; - // Registers custom element. - registerWebViewElement = function() { var createBlockHandler, createNonBlockHandler, i, j, len, len1, m, methods, nonblockMethods, proto; proto = Object.create(HTMLObjectElement.prototype); @@ -385,7 +348,51 @@ registerWebViewElement = function() { }; // Public-facing API methods. - methods = ['getURL', 'getTitle', 'isLoading', 'isWaitingForResponse', 'stop', 'reload', 'reloadIgnoringCache', 'canGoBack', 'canGoForward', 'canGoToOffset', 'clearHistory', 'goBack', 'goForward', 'goToIndex', 'goToOffset', 'isCrashed', 'setUserAgent', 'getUserAgent', 'openDevTools', 'closeDevTools', 'isDevToolsOpened', 'isDevToolsFocused', 'inspectElement', 'setAudioMuted', 'isAudioMuted', 'undo', 'redo', 'cut', 'copy', 'paste', 'pasteAndMatchStyle', 'delete', 'selectAll', 'unselect', 'replace', 'replaceMisspelling', 'findInPage', 'stopFindInPage', 'getId', 'downloadURL', 'inspectServiceWorker', 'print', 'printToPDF']; + methods = [ + 'getURL', + 'getTitle', + 'isLoading', + 'isWaitingForResponse', + 'stop', + 'reload', + 'reloadIgnoringCache', + 'canGoBack', + 'canGoForward', + 'canGoToOffset', + 'clearHistory', + 'goBack', + 'goForward', + 'goToIndex', + 'goToOffset', + 'isCrashed', + 'setUserAgent', + 'getUserAgent', + 'openDevTools', + 'closeDevTools', + 'isDevToolsOpened', + 'isDevToolsFocused', + 'inspectElement', + 'setAudioMuted', + 'isAudioMuted', + 'undo', + 'redo', + 'cut', + 'copy', + 'paste', + 'pasteAndMatchStyle', + 'delete', + 'selectAll', + 'unselect', + 'replace', + 'replaceMisspelling', + 'findInPage', + 'stopFindInPage', + 'getId', + 'downloadURL', + 'inspectServiceWorker', + 'print', + 'printToPDF' + ]; nonblockMethods = [ 'executeJavaScript', 'insertCSS', @@ -429,10 +436,8 @@ registerWebViewElement = function() { prototype: proto }); - /* - Delete the callbacks so developers cannot call them and produce unexpected - behavior. - */ + // Delete the callbacks so developers cannot call them and produce unexpected + // behavior. delete proto.createdCallback; delete proto.attachedCallback; delete proto.detachedCallback; From 9103253f62208f52d556a4738ec9d9c47a1830e6 Mon Sep 17 00:00:00 2001 From: Jessica Lord Date: Thu, 14 Jan 2016 13:16:42 -0800 Subject: [PATCH 74/95] Use `const` --- atom/browser/api/lib/app.js | 24 +++++++++------ atom/browser/api/lib/auto-updater.js | 7 ++--- .../lib/auto-updater/auto-updater-native.js | 7 ++--- .../api/lib/auto-updater/auto-updater-win.js | 18 +++++------- .../lib/auto-updater/squirrel-update-win.js | 18 +++++------- atom/browser/api/lib/browser-window.js | 11 +++---- atom/browser/api/lib/dialog.js | 29 +++++++++---------- atom/browser/api/lib/exports/electron.js | 4 +-- atom/browser/api/lib/ipc-main.js | 4 +-- atom/browser/api/lib/ipc.js | 5 ++-- 10 files changed, 55 insertions(+), 72 deletions(-) diff --git a/atom/browser/api/lib/app.js b/atom/browser/api/lib/app.js index 560fcb8630ee..bd820127cd9a 100644 --- a/atom/browser/api/lib/app.js +++ b/atom/browser/api/lib/app.js @@ -1,15 +1,21 @@ -var EventEmitter, Menu, app, appPath, bindings, deprecate, downloadItemBindings, fn, i, len, name, ref, ref1, session, wrapDownloadItem, - slice = [].slice; +const deprecate = require('electron').deprecate; +const session = require('electron').session; +const Menu = require('electron').Menu; +const EventEmitter = require('events').EventEmitter; -ref = require('electron'), deprecate = ref.deprecate, session = ref.session, Menu = ref.Menu; +const bindings = process.atomBinding('app'); +const downloadItemBindings = process.atomBinding('download_item'); +const app = bindings.app; -EventEmitter = require('events').EventEmitter; +var slice = [].slice; -bindings = process.atomBinding('app'); - -downloadItemBindings = process.atomBinding('download_item'); - -app = bindings.app; +var appPath; +var fn; +var i; +var len; +var name; +var ref1; +var wrapDownloadItem; app.__proto__ = EventEmitter.prototype; diff --git a/atom/browser/api/lib/auto-updater.js b/atom/browser/api/lib/auto-updater.js index a3ffc12e9f2d..9cc1fada0675 100644 --- a/atom/browser/api/lib/auto-updater.js +++ b/atom/browser/api/lib/auto-updater.js @@ -1,8 +1,5 @@ -var autoUpdater, deprecate; - -deprecate = require('electron').deprecate; - -autoUpdater = process.platform === 'win32' ? require('./auto-updater/auto-updater-win') : require('./auto-updater/auto-updater-native'); +const deprecate = require('electron').deprecate; +const autoUpdater = process.platform === 'win32' ? require('./auto-updater/auto-updater-win') : require('./auto-updater/auto-updater-native'); // Deprecated. deprecate.rename(autoUpdater, 'setFeedUrl', 'setFeedURL'); diff --git a/atom/browser/api/lib/auto-updater/auto-updater-native.js b/atom/browser/api/lib/auto-updater/auto-updater-native.js index 9f22b33feb1d..20c69cdb5a2b 100644 --- a/atom/browser/api/lib/auto-updater/auto-updater-native.js +++ b/atom/browser/api/lib/auto-updater/auto-updater-native.js @@ -1,8 +1,5 @@ -var EventEmitter, autoUpdater; - -EventEmitter = require('events').EventEmitter; - -autoUpdater = process.atomBinding('auto_updater').autoUpdater; +const EventEmitter = require('events').EventEmitter; +const autoUpdater = process.atomBinding('auto_updater').autoUpdater; autoUpdater.__proto__ = EventEmitter.prototype; diff --git a/atom/browser/api/lib/auto-updater/auto-updater-win.js b/atom/browser/api/lib/auto-updater/auto-updater-win.js index 61b1911e232e..bbe02555a0b8 100644 --- a/atom/browser/api/lib/auto-updater/auto-updater-win.js +++ b/atom/browser/api/lib/auto-updater/auto-updater-win.js @@ -1,16 +1,12 @@ -var AutoUpdater, EventEmitter, app, squirrelUpdate, url, - extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }, - hasProp = {}.hasOwnProperty; +const app = require('electron').app; +const EventEmitter = require('events').EventEmitter; +const url = require('url'); +const squirrelUpdate = require('./squirrel-update-win'); -app = require('electron').app; +var extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }, +hasProp = {}.hasOwnProperty; -EventEmitter = require('events').EventEmitter; - -url = require('url'); - -squirrelUpdate = require('./squirrel-update-win'); - -AutoUpdater = (function(superClass) { +var AutoUpdater = (function(superClass) { extend(AutoUpdater, superClass); function AutoUpdater() { diff --git a/atom/browser/api/lib/auto-updater/squirrel-update-win.js b/atom/browser/api/lib/auto-updater/squirrel-update-win.js index 49d525f4a684..8fe8a3786db9 100644 --- a/atom/browser/api/lib/auto-updater/squirrel-update-win.js +++ b/atom/browser/api/lib/auto-updater/squirrel-update-win.js @@ -1,22 +1,18 @@ -var appFolder, exeName, fs, path, spawn, spawnUpdate, updateExe; - -fs = require('fs'); - -path = require('path'); - -spawn = require('child_process').spawn; +const fs = require('fs'); +const path = require('path'); +const spawn = require('child_process').spawn; // i.e. my-app/app-0.1.13/ -appFolder = path.dirname(process.execPath); +const appFolder = path.dirname(process.execPath); // i.e. my-app/Update.exe -updateExe = path.resolve(appFolder, '..', 'Update.exe'); +const updateExe = path.resolve(appFolder, '..', 'Update.exe'); -exeName = path.basename(process.execPath); +const exeName = path.basename(process.execPath); // Spawn a command and invoke the callback when it completes with an error // and the output from standard out. -spawnUpdate = function(args, detached, callback) { +var spawnUpdate = function(args, detached, callback) { var error, error1, errorEmitted, spawnedProcess, stderr, stdout; try { spawnedProcess = spawn(updateExe, args, { diff --git a/atom/browser/api/lib/browser-window.js b/atom/browser/api/lib/browser-window.js index df9ae1647383..1268b0f80127 100644 --- a/atom/browser/api/lib/browser-window.js +++ b/atom/browser/api/lib/browser-window.js @@ -1,10 +1,7 @@ -var BrowserWindow, EventEmitter, deprecate, ipcMain, ref; - -ref = require('electron'), ipcMain = ref.ipcMain, deprecate = ref.deprecate; - -EventEmitter = require('events').EventEmitter; - -BrowserWindow = process.atomBinding('window').BrowserWindow; +const ipcMain = require('electron').ipcMain; +const deprecate = require('electron').deprecate; +const EventEmitter = require('events').EventEmitter; +const BrowserWindow = process.atomBinding('window').BrowserWindow; BrowserWindow.prototype.__proto__ = EventEmitter.prototype; diff --git a/atom/browser/api/lib/dialog.js b/atom/browser/api/lib/dialog.js index 9ed49738a55b..302fa7bf07fe 100644 --- a/atom/browser/api/lib/dialog.js +++ b/atom/browser/api/lib/dialog.js @@ -1,27 +1,25 @@ -var BrowserWindow, api, app, binding, checkAppInitialized, fileDialogProperties, j, len, messageBoxOptions, messageBoxTypes, parseArgs, ref, ref1, v8Util, - slice = [].slice, - indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; }; +const app = require('electron').app; +const BrowserWindow = require('electron').BrowserWindow; +const binding = process.atomBinding('dialog'); +const v8Util = process.atomBinding('v8_util'); -ref = require('electron'), app = ref.app, BrowserWindow = ref.BrowserWindow; +var slice = [].slice; +var indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; }; -binding = process.atomBinding('dialog'); - -v8Util = process.atomBinding('v8_util'); - -fileDialogProperties = { +var fileDialogProperties = { openFile: 1 << 0, openDirectory: 1 << 1, multiSelections: 1 << 2, createDirectory: 1 << 3 }; -messageBoxTypes = ['none', 'info', 'warning', 'error', 'question']; +var messageBoxTypes = ['none', 'info', 'warning', 'error', 'question']; -messageBoxOptions = { +var messageBoxOptions = { noLink: 1 << 0 }; -parseArgs = function(window, options, callback) { +var parseArgs = function(window, options, callback) { if (!(window === null || (window != null ? window.constructor : void 0) === BrowserWindow)) { // Shift. callback = options; @@ -36,7 +34,7 @@ parseArgs = function(window, options, callback) { return [window, options, callback]; }; -checkAppInitialized = function() { +var checkAppInitialized = function() { if (!app.isReady()) { throw new Error('dialog module can only be used after app is ready'); } @@ -164,8 +162,9 @@ module.exports = { }; // Mark standard asynchronous functions. -ref1 = ['showMessageBox', 'showOpenDialog', 'showSaveDialog']; +var ref1 = ['showMessageBox', 'showOpenDialog', 'showSaveDialog']; +var j, len for (j = 0, len = ref1.length; j < len; j++) { - api = ref1[j]; + var api = ref1[j]; v8Util.setHiddenValue(module.exports[api], 'asynchronous', true); } diff --git a/atom/browser/api/lib/exports/electron.js b/atom/browser/api/lib/exports/electron.js index 74ae751e0834..7f97fcdbc4cf 100644 --- a/atom/browser/api/lib/exports/electron.js +++ b/atom/browser/api/lib/exports/electron.js @@ -1,6 +1,4 @@ -var common; - -common = require('../../../../common/api/lib/exports/electron'); +const common = require('../../../../common/api/lib/exports/electron'); // Import common modules. diff --git a/atom/browser/api/lib/ipc-main.js b/atom/browser/api/lib/ipc-main.js index bd4300d2c244..e253e03eaabe 100644 --- a/atom/browser/api/lib/ipc-main.js +++ b/atom/browser/api/lib/ipc-main.js @@ -1,5 +1,3 @@ -var EventEmitter; - -EventEmitter = require('events').EventEmitter; +const EventEmitter = require('events').EventEmitter; module.exports = new EventEmitter; diff --git a/atom/browser/api/lib/ipc.js b/atom/browser/api/lib/ipc.js index ed20e976173f..6e9715154234 100644 --- a/atom/browser/api/lib/ipc.js +++ b/atom/browser/api/lib/ipc.js @@ -1,6 +1,5 @@ -var deprecate, ipcMain, ref; - -ref = require('electron'), deprecate = ref.deprecate, ipcMain = ref.ipcMain; +const deprecate = require('electron').deprecate; +const ipcMain = require('electron').ipcMain; // This module is deprecated, we mirror everything from ipcMain. deprecate.warn('ipc module', 'require("electron").ipcMain'); From 3a0fb42737080bfe411d2dcd3adff41cdef7ca60 Mon Sep 17 00:00:00 2001 From: Jessica Lord Date: Thu, 14 Jan 2016 13:18:52 -0800 Subject: [PATCH 75/95] Use `const` --- atom/browser/api/lib/menu-item.js | 4 +-- atom/browser/api/lib/menu.js | 26 ++++++-------- atom/browser/api/lib/navigation-controller.js | 7 ++-- atom/browser/api/lib/power-monitor.js | 7 ++-- atom/browser/api/lib/protocol.js | 8 ++--- atom/browser/api/lib/screen.js | 7 ++-- atom/browser/api/lib/session.js | 12 +++---- atom/browser/api/lib/tray.js | 10 ++---- atom/browser/api/lib/web-contents.js | 23 +++++++------ atom/browser/lib/chrome-extension.js | 34 +++++++------------ 10 files changed, 55 insertions(+), 83 deletions(-) diff --git a/atom/browser/api/lib/menu-item.js b/atom/browser/api/lib/menu-item.js index b8357dd34918..80fdd46fd89b 100644 --- a/atom/browser/api/lib/menu-item.js +++ b/atom/browser/api/lib/menu-item.js @@ -26,8 +26,8 @@ MenuItem = (function() { MenuItem.types = ['normal', 'separator', 'submenu', 'checkbox', 'radio']; function MenuItem(options) { - var Menu, click, ref; - Menu = require('electron').Menu; + var click, ref; + const Menu = require('electron').Menu; click = options.click, this.selector = options.selector, this.type = options.type, this.role = options.role, this.label = options.label, this.sublabel = options.sublabel, this.accelerator = options.accelerator, this.icon = options.icon, this.enabled = options.enabled, this.visible = options.visible, this.checked = options.checked, this.submenu = options.submenu; if ((this.submenu != null) && this.submenu.constructor !== Menu) { this.submenu = Menu.buildFromTemplate(this.submenu); diff --git a/atom/browser/api/lib/menu.js b/atom/browser/api/lib/menu.js index 5af39e18af32..69ad4fec051d 100644 --- a/atom/browser/api/lib/menu.js +++ b/atom/browser/api/lib/menu.js @@ -1,19 +1,15 @@ -var BrowserWindow, EventEmitter, Menu, MenuItem, applicationMenu, bindings, generateGroupId, indexOfItemById, indexToInsertByPosition, nextGroupId, ref, v8Util; - -ref = require('electron'), BrowserWindow = ref.BrowserWindow, MenuItem = ref.MenuItem; - -EventEmitter = require('events').EventEmitter; - -v8Util = process.atomBinding('v8_util'); - -bindings = process.atomBinding('menu'); +const BrowserWindow = require('electron').BrowserWindow; +const MenuItem = require('electron').MenuItem; +const EventEmitter = require('events').EventEmitter; +const v8Util = process.atomBinding('v8_util'); +const bindings = process.atomBinding('menu'); // Automatically generated radio menu item's group id. -nextGroupId = 0; +var nextGroupId = 0; // Search between seperators to find a radio menu item and return its group id, // otherwise generate a group id. -generateGroupId = function(items, pos) { +var generateGroupId = function(items, pos) { var i, item, j, k, ref1, ref2, ref3; if (pos > 0) { for (i = j = ref1 = pos - 1; ref1 <= 0 ? j <= 0 : j >= 0; i = ref1 <= 0 ? ++j : --j) { @@ -40,7 +36,7 @@ generateGroupId = function(items, pos) { }; // Returns the index of item according to |id|. -indexOfItemById = function(items, id) { +var indexOfItemById = function(items, id) { var i, item, j, len; for (i = j = 0, len = items.length; j < len; i = ++j) { item = items[i]; @@ -52,7 +48,7 @@ indexOfItemById = function(items, id) { }; // Returns the index of where to insert the item according to |position|. -indexToInsertByPosition = function(items, position) { +var indexToInsertByPosition = function(items, position) { var id, insertIndex, query, ref1; if (!position) { return items.length; @@ -87,7 +83,7 @@ indexToInsertByPosition = function(items, position) { return insertIndex; }; -Menu = bindings.Menu; +const Menu = bindings.Menu; Menu.prototype.__proto__ = EventEmitter.prototype; @@ -265,7 +261,7 @@ Menu.prototype._callMenuWillShow = function() { return results; }; -applicationMenu = null; +var applicationMenu = null; Menu.setApplicationMenu = function(menu) { var j, len, results, w, windows; diff --git a/atom/browser/api/lib/navigation-controller.js b/atom/browser/api/lib/navigation-controller.js index 5478b6dd3264..80756eb13e49 100644 --- a/atom/browser/api/lib/navigation-controller.js +++ b/atom/browser/api/lib/navigation-controller.js @@ -1,7 +1,6 @@ -var NavigationController, ipcMain, - slice = [].slice; +const ipcMain = require('electron').ipcMain; -ipcMain = require('electron').ipcMain; +var slice = [].slice; // The history operation in renderer is redirected to browser. ipcMain.on('ATOM_SHELL_NAVIGATION_CONTROLLER', function() { @@ -21,7 +20,7 @@ ipcMain.on('ATOM_SHELL_SYNC_NAVIGATION_CONTROLLER', function() { // control on user land, and only rely on WebContents.loadURL for navigation. // This helps us avoid Chromium's various optimizations so we can ensure renderer // process is restarted everytime. -NavigationController = (function() { +var NavigationController = (function() { function NavigationController(webContents) { this.webContents = webContents; this.clearHistory(); diff --git a/atom/browser/api/lib/power-monitor.js b/atom/browser/api/lib/power-monitor.js index df4b28c6eb66..239eb3b4d47a 100644 --- a/atom/browser/api/lib/power-monitor.js +++ b/atom/browser/api/lib/power-monitor.js @@ -1,8 +1,5 @@ -var EventEmitter, powerMonitor; - -EventEmitter = require('events').EventEmitter; - -powerMonitor = process.atomBinding('power_monitor').powerMonitor; +const EventEmitter = require('events').EventEmitter; +const powerMonitor = process.atomBinding('power_monitor').powerMonitor; powerMonitor.__proto__ = EventEmitter.prototype; diff --git a/atom/browser/api/lib/protocol.js b/atom/browser/api/lib/protocol.js index f04eab121f15..41cb48db09b9 100644 --- a/atom/browser/api/lib/protocol.js +++ b/atom/browser/api/lib/protocol.js @@ -1,15 +1,13 @@ -var app, logAndThrow, protocol; - -app = require('electron').app; +const app = require('electron').app; if (!app.isReady()) { throw new Error('Can not initialize protocol module before app is ready'); } -protocol = process.atomBinding('protocol').protocol; +const protocol = process.atomBinding('protocol').protocol; // Warn about removed APIs. -logAndThrow = function(callback, message) { +var logAndThrow = function(callback, message) { console.error(message); if (callback) { return callback(new Error(message)); diff --git a/atom/browser/api/lib/screen.js b/atom/browser/api/lib/screen.js index 3dca49e99d90..04965278a3c8 100644 --- a/atom/browser/api/lib/screen.js +++ b/atom/browser/api/lib/screen.js @@ -1,8 +1,5 @@ -var EventEmitter, screen; - -EventEmitter = require('events').EventEmitter; - -screen = process.atomBinding('screen').screen; +const EventEmitter = require('events').EventEmitter; +const screen = process.atomBinding('screen').screen; screen.__proto__ = EventEmitter.prototype; diff --git a/atom/browser/api/lib/session.js b/atom/browser/api/lib/session.js index 8ba9e61be45a..dc65264349fa 100644 --- a/atom/browser/api/lib/session.js +++ b/atom/browser/api/lib/session.js @@ -1,10 +1,6 @@ -var EventEmitter, PERSIST_PERFIX, bindings, wrapSession; - -EventEmitter = require('events').EventEmitter; - -bindings = process.atomBinding('session'); - -PERSIST_PERFIX = 'persist:'; +const EventEmitter = require('events').EventEmitter; +const bindings = process.atomBinding('session'); +const PERSIST_PERFIX = 'persist:'; // Returns the Session from |partition| string. exports.fromPartition = function(partition) { @@ -29,7 +25,7 @@ Object.defineProperty(exports, 'defaultSession', { } }); -wrapSession = function(session) { +var wrapSession = function(session) { // session is an EventEmitter. return session.__proto__ = EventEmitter.prototype; }; diff --git a/atom/browser/api/lib/tray.js b/atom/browser/api/lib/tray.js index a2b732964ea4..342683552f62 100644 --- a/atom/browser/api/lib/tray.js +++ b/atom/browser/api/lib/tray.js @@ -1,10 +1,6 @@ -var EventEmitter, Tray, deprecate; - -deprecate = require('electron').deprecate; - -EventEmitter = require('events').EventEmitter; - -Tray = process.atomBinding('tray').Tray; +const deprecate = require('electron').deprecate; +const EventEmitter = require('events').EventEmitter; +const Tray = process.atomBinding('tray').Tray; Tray.prototype.__proto__ = EventEmitter.prototype; diff --git a/atom/browser/api/lib/web-contents.js b/atom/browser/api/lib/web-contents.js index c507daab077e..47f5eb4639b9 100644 --- a/atom/browser/api/lib/web-contents.js +++ b/atom/browser/api/lib/web-contents.js @@ -1,21 +1,22 @@ 'use strict'; -var EventEmitter, Menu, NavigationController, PDFPageSize, binding, deprecate, getNextId, ipcMain, nextId, ref, session, wrapWebContents, - slice = [].slice; +const EventEmitter = require('events').EventEmitter; +const deprecate = require('electron').deprecate; +const ipcMain = require('electron').ipcMain; +const session = require('electron').session; +const NavigationController = require('electron').NavigationController; +const Menu = require('electron').Menu; -EventEmitter = require('events').EventEmitter; +const binding = process.atomBinding('web_contents'); -ref = require('electron'), deprecate = ref.deprecate, ipcMain = ref.ipcMain, session = ref.session, NavigationController = ref.NavigationController, Menu = ref.Menu; +let slice = [].slice; +let nextId = 0; -binding = process.atomBinding('web_contents'); - -nextId = 0; - -getNextId = function() { +let getNextId = function() { return ++nextId; }; -PDFPageSize = { +let PDFPageSize = { A5: { custom_display_name: "A5", height_microns: 210000, @@ -64,7 +65,7 @@ const webFrameMethods = [ 'setZoomLevelLimits', ]; -wrapWebContents = function(webContents) { +let wrapWebContents = function(webContents) { // webContents is an EventEmitter. var controller, method, name, ref1; webContents.__proto__ = EventEmitter.prototype; diff --git a/atom/browser/lib/chrome-extension.js b/atom/browser/lib/chrome-extension.js index 44e7f947e391..32459c3a20e2 100644 --- a/atom/browser/lib/chrome-extension.js +++ b/atom/browser/lib/chrome-extension.js @@ -1,33 +1,28 @@ -var app, electron, extensionInfoMap, fs, getExtensionInfoFromPath, getHostForPath, getPathForHost, hostPathMap, hostPathMapNextKey, loadedExtensions, loadedExtensionsPath, path, url; - -electron = require('electron'); - -fs = require('fs'); - -path = require('path'); - -url = require('url'); +const electron = require('electron'); +const app = electron.app; +const fs = require('fs'); +const path = require('path'); +const url = require('url'); // Mapping between hostname and file path. -hostPathMap = {}; +var hostPathMap = {}; +var hostPathMapNextKey = 0; -hostPathMapNextKey = 0; - -getHostForPath = function(path) { +var getHostForPath = function(path) { var key; key = "extension-" + (++hostPathMapNextKey); hostPathMap[key] = path; return key; }; -getPathForHost = function(host) { +var getPathForHost = function(host) { return hostPathMap[host]; }; // Cache extensionInfo. -extensionInfoMap = {}; +var extensionInfoMap = {}; -getExtensionInfoFromPath = function(srcDirectory) { +var getExtensionInfoFromPath = function(srcDirectory) { var manifest, page; manifest = JSON.parse(fs.readFileSync(path.join(srcDirectory, 'manifest.json'))); if (extensionInfoMap[manifest.name] == null) { @@ -51,11 +46,8 @@ getExtensionInfoFromPath = function(srcDirectory) { }; // The loaded extensions cache and its persistent path. -loadedExtensions = null; -loadedExtensionsPath = null; - -// Persistent loaded extensions. -app = electron.app; +var loadedExtensions = null; +var loadedExtensionsPath = null; app.on('will-quit', function() { var e, error1, error2; From 177970144522f2be863c3839627beafe5ec28090 Mon Sep 17 00:00:00 2001 From: Jessica Lord Date: Thu, 14 Jan 2016 13:21:11 -0800 Subject: [PATCH 76/95] Use `const` --- atom/browser/lib/desktop-capturer.js | 11 +++--- atom/browser/lib/guest-view-manager.js | 31 ++++++++--------- atom/browser/lib/guest-window-manager.js | 19 +++++------ atom/browser/lib/init.js | 41 ++++++++++------------ atom/browser/lib/objects-registry.js | 12 +++---- atom/browser/lib/rpc-server.js | 30 +++++++---------- atom/common/api/lib/crash-reporter.js | 25 +++++--------- atom/common/api/lib/exports/electron.js | 3 +- atom/common/api/lib/native-image.js | 7 ++-- atom/common/lib/asar.js | 43 +++++++++++------------- 10 files changed, 92 insertions(+), 130 deletions(-) diff --git a/atom/browser/lib/desktop-capturer.js b/atom/browser/lib/desktop-capturer.js index 638d87c3af32..da649df1ce0c 100644 --- a/atom/browser/lib/desktop-capturer.js +++ b/atom/browser/lib/desktop-capturer.js @@ -1,15 +1,12 @@ -var deepEqual, desktopCapturer, ipcMain, requestsQueue; +const ipcMain = require('electron').ipcMain; +const desktopCapturer = process.atomBinding('desktop_capturer').desktopCapturer; -ipcMain = require('electron').ipcMain; - -desktopCapturer = process.atomBinding('desktop_capturer').desktopCapturer; - -deepEqual = function(opt1, opt2) { +var deepEqual = function(opt1, opt2) { return JSON.stringify(opt1) === JSON.stringify(opt2); }; // A queue for holding all requests from renderer process. -requestsQueue = []; +var requestsQueue = []; ipcMain.on('ATOM_BROWSER_DESKTOP_CAPTURER_GET_SOURCES', function(event, captureWindow, captureScreen, thumbnailSize, id) { var request; diff --git a/atom/browser/lib/guest-view-manager.js b/atom/browser/lib/guest-view-manager.js index a07803069966..bf92cf80706c 100644 --- a/atom/browser/lib/guest-view-manager.js +++ b/atom/browser/lib/guest-view-manager.js @@ -1,33 +1,30 @@ -var attachGuest, createGuest, destroyGuest, embedderElementsMap, getNextInstanceId, guestInstances, ipcMain, moveLastToFirst, nextInstanceId, ref, reverseEmbedderElementsMap, supportedWebViewEvents, webContents, webViewManager, - slice = [].slice; +const ipcMain = require('electron').ipcMain; +const webContents = require('electron').webContents; -ref = require('electron'), ipcMain = ref.ipcMain, webContents = ref.webContents; +var slice = [].slice; // Doesn't exist in early initialization. -webViewManager = null; +var webViewManager = null; -supportedWebViewEvents = ['load-commit', 'did-finish-load', 'did-fail-load', 'did-frame-finish-load', 'did-start-loading', 'did-stop-loading', 'did-get-response-details', 'did-get-redirect-request', 'dom-ready', 'console-message', 'devtools-opened', 'devtools-closed', 'devtools-focused', 'new-window', 'will-navigate', 'did-navigate', 'did-navigate-in-page', 'close', 'crashed', 'gpu-crashed', 'plugin-crashed', 'destroyed', 'page-title-updated', 'page-favicon-updated', 'enter-html-full-screen', 'leave-html-full-screen', 'media-started-playing', 'media-paused', 'found-in-page', 'did-change-theme-color']; +var supportedWebViewEvents = ['load-commit', 'did-finish-load', 'did-fail-load', 'did-frame-finish-load', 'did-start-loading', 'did-stop-loading', 'did-get-response-details', 'did-get-redirect-request', 'dom-ready', 'console-message', 'devtools-opened', 'devtools-closed', 'devtools-focused', 'new-window', 'will-navigate', 'did-navigate', 'did-navigate-in-page', 'close', 'crashed', 'gpu-crashed', 'plugin-crashed', 'destroyed', 'page-title-updated', 'page-favicon-updated', 'enter-html-full-screen', 'leave-html-full-screen', 'media-started-playing', 'media-paused', 'found-in-page', 'did-change-theme-color']; -nextInstanceId = 0; - -guestInstances = {}; - -embedderElementsMap = {}; - -reverseEmbedderElementsMap = {}; +var nextInstanceId = 0; +var guestInstances = {}; +var embedderElementsMap = {}; +var reverseEmbedderElementsMap = {}; // Moves the last element of array to the first one. -moveLastToFirst = function(list) { +var moveLastToFirst = function(list) { return list.unshift(list.pop()); }; // Generate guestInstanceId. -getNextInstanceId = function(webContents) { +var getNextInstanceId = function(webContents) { return ++nextInstanceId; }; // Create a new guest instance. -createGuest = function(embedder, params) { +var createGuest = function(embedder, params) { var destroy, destroyEvents, event, fn, guest, i, id, j, len, len1, listeners; if (webViewManager == null) { webViewManager = process.atomBinding('web_view_manager'); @@ -139,7 +136,7 @@ createGuest = function(embedder, params) { }; // Attach the guest to an element of embedder. -attachGuest = function(embedder, elementInstanceId, guestInstanceId, params) { +var attachGuest = function(embedder, elementInstanceId, guestInstanceId, params) { var guest, key, oldGuestInstanceId, ref1, webPreferences; guest = guestInstances[guestInstanceId].guest; @@ -173,7 +170,7 @@ attachGuest = function(embedder, elementInstanceId, guestInstanceId, params) { }; // Destroy an existing guest instance. -destroyGuest = function(embedder, id) { +var destroyGuest = function(embedder, id) { var key; webViewManager.removeGuest(embedder, id); guestInstances[id].guest.destroy(); diff --git a/atom/browser/lib/guest-window-manager.js b/atom/browser/lib/guest-window-manager.js index f57b8eb1327e..152167cccc0c 100644 --- a/atom/browser/lib/guest-window-manager.js +++ b/atom/browser/lib/guest-window-manager.js @@ -1,15 +1,14 @@ -var BrowserWindow, createGuest, frameToGuest, ipcMain, mergeBrowserWindowOptions, mergeOptions, ref, v8Util, - hasProp = {}.hasOwnProperty, - slice = [].slice; +const ipcMain = require('electron').ipcMain; +const BrowserWindow = require('electron').BrowserWindow; -ref = require('electron'), ipcMain = ref.ipcMain, BrowserWindow = ref.BrowserWindow; +const v8Util = process.atomBinding('v8_util'); -v8Util = process.atomBinding('v8_util'); - -frameToGuest = {}; +var hasProp = {}.hasOwnProperty; +var slice = [].slice; +var frameToGuest = {}; // Copy attribute of |parent| to |child| if it is not defined in |child|. -mergeOptions = function(child, parent) { +var mergeOptions = function(child, parent) { var key, value; for (key in parent) { if (!hasProp.call(parent, key)) continue; @@ -26,7 +25,7 @@ mergeOptions = function(child, parent) { }; // Merge |options| with the |embedder|'s window's options. -mergeBrowserWindowOptions = function(embedder, options) { +var mergeBrowserWindowOptions = function(embedder, options) { if (embedder.browserWindowOptions != null) { // Inherit the original options if it is a BrowserWindow. @@ -43,7 +42,7 @@ mergeBrowserWindowOptions = function(embedder, options) { }; // Create a new guest created by |embedder| with |options|. -createGuest = function(embedder, url, frameName, options) { +var createGuest = function(embedder, url, frameName, options) { var closedByEmbedder, closedByUser, guest, guestId, ref1; guest = frameToGuest[frameName]; if (frameName && (guest != null)) { diff --git a/atom/browser/lib/init.js b/atom/browser/lib/init.js index 03e4c9c18718..a38cd6f9e41f 100644 --- a/atom/browser/lib/init.js +++ b/atom/browser/lib/init.js @@ -1,13 +1,9 @@ -var Module, Readable, app, consoleLog, e, error1, fs, globalPaths, i, len, mainStartupScript, packageJson, packagePath, path, searchPaths, stdin, streamWrite, util, - slice = [].slice; +const fs = require('fs'); +const path = require('path'); +const util = require('util'); +const Module = require('module'); -fs = require('fs'); - -path = require('path'); - -util = require('util'); - -Module = require('module'); +var slice = [].slice; // We modified the original process.argv to let node.js load the atom.js, // we need to restore it here. @@ -19,7 +15,7 @@ require(path.resolve(__dirname, '..', '..', 'common', 'lib', 'reset-search-paths // Import common settings. require(path.resolve(__dirname, '..', '..', 'common', 'lib', 'init')); -globalPaths = Module.globalPaths; +var globalPaths = Module.globalPaths; if (!process.env.ELECTRON_HIDE_INTERNAL_MODULES) { globalPaths.push(path.resolve(__dirname, '..', 'api', 'lib')); @@ -31,12 +27,12 @@ globalPaths.push(path.resolve(__dirname, '..', 'api', 'lib', 'exports')); if (process.platform === 'win32') { // Redirect node's console to use our own implementations, since node can not // handle console output when running as GUI program. - consoleLog = function() { + var consoleLog = function() { var args; args = 1 <= arguments.length ? slice.call(arguments, 0) : []; return process.log(util.format.apply(util, args) + "\n"); }; - streamWrite = function(chunk, encoding, callback) { + var streamWrite = function(chunk, encoding, callback) { if (Buffer.isBuffer(chunk)) { chunk = chunk.toString(encoding); } @@ -50,8 +46,8 @@ if (process.platform === 'win32') { process.stdout.write = process.stderr.write = streamWrite; // Always returns EOF for stdin stream. - Readable = require('stream').Readable; - stdin = new Readable; + var Readable = require('stream').Readable; + var stdin = new Readable; stdin.push(null); process.__defineGetter__('stdin', function() { return stdin; @@ -75,7 +71,7 @@ process.on('uncaughtException', function(error) { }); // Emit 'exit' event on quit. -app = require('electron').app; +var app = require('electron').app; app.on('quit', function(event, exitCode) { return process.emit('exit', exitCode); @@ -92,20 +88,17 @@ require('./guest-view-manager'); require('./guest-window-manager'); - // Now we try to load app's package.json. -packageJson = null; - -searchPaths = ['app', 'app.asar', 'default_app']; - +var packageJson = null; +var searchPaths = ['app', 'app.asar', 'default_app']; +var i, len; for (i = 0, len = searchPaths.length; i < len; i++) { - packagePath = searchPaths[i]; + var packagePath = searchPaths[i]; try { packagePath = path.join(process.resourcesPath, packagePath); packageJson = JSON.parse(fs.readFileSync(path.join(packagePath, 'package.json'))); break; - } catch (error1) { - e = error1; + } catch (error) { continue; } } @@ -153,7 +146,7 @@ require('./chrome-extension'); require('./desktop-capturer'); // Set main startup script of the app. -mainStartupScript = packageJson.main || 'index.js'; +var mainStartupScript = packageJson.main || 'index.js'; // Finally load app's main.js and transfer control to C++. Module._load(path.join(packagePath, mainStartupScript), Module, true); diff --git a/atom/browser/lib/objects-registry.js b/atom/browser/lib/objects-registry.js index a468c89219cc..953b2f47c9fd 100644 --- a/atom/browser/lib/objects-registry.js +++ b/atom/browser/lib/objects-registry.js @@ -1,12 +1,10 @@ -var EventEmitter, ObjectsRegistry, v8Util, - extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }, - hasProp = {}.hasOwnProperty; +const EventEmitter = require('events').EventEmitter; +const v8Util = process.atomBinding('v8_util'); -EventEmitter = require('events').EventEmitter; +var extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }; +var hasProp = {}.hasOwnProperty; -v8Util = process.atomBinding('v8_util'); - -ObjectsRegistry = (function(superClass) { +var ObjectsRegistry = (function(superClass) { extend(ObjectsRegistry, superClass); function ObjectsRegistry() { diff --git a/atom/browser/lib/rpc-server.js b/atom/browser/lib/rpc-server.js index a8add74e0321..346db74f6ecd 100644 --- a/atom/browser/lib/rpc-server.js +++ b/atom/browser/lib/rpc-server.js @@ -1,20 +1,14 @@ -var IDWeakMap, callFunction, electron, exceptionToMeta, ipcMain, objectsRegistry, path, plainObjectToMeta, unwrapArgs, v8Util, valueToMeta, - slice = [].slice; +const path = require('path'); +const electron = require('electron'); +const ipcMain = electron.ipcMain; +const objectsRegistry = require('./objects-registry'); +const v8Util = process.atomBinding('v8_util'); +const IDWeakMap = process.atomBinding('id_weak_map').IDWeakMap; -path = require('path'); - -electron = require('electron'); - -ipcMain = electron.ipcMain; - -objectsRegistry = require('./objects-registry'); - -v8Util = process.atomBinding('v8_util'); - -IDWeakMap = process.atomBinding('id_weak_map').IDWeakMap; +var slice = [].slice; // Convert a real value into meta data. -valueToMeta = function(sender, value, optimizeSimpleObject) { +var valueToMeta = function(sender, value, optimizeSimpleObject) { var el, field, i, len, meta, name; if (optimizeSimpleObject == null) { optimizeSimpleObject = false; @@ -97,7 +91,7 @@ valueToMeta = function(sender, value, optimizeSimpleObject) { }; // Convert object to meta by value. -plainObjectToMeta = function(obj) { +var plainObjectToMeta = function(obj) { return Object.getOwnPropertyNames(obj).map(function(name) { return { name: name, @@ -107,7 +101,7 @@ plainObjectToMeta = function(obj) { }; // Convert Error into meta data. -exceptionToMeta = function(error) { +var exceptionToMeta = function(error) { return { type: 'exception', message: error.message, @@ -116,7 +110,7 @@ exceptionToMeta = function(error) { }; // Convert array of meta data from renderer into array of real values. -unwrapArgs = function(sender, args) { +var unwrapArgs = function(sender, args) { var metaToValue; metaToValue = function(meta) { var i, len, member, ref, rendererReleased, ret, returnValue; @@ -187,7 +181,7 @@ unwrapArgs = function(sender, args) { // Call a function and send reply asynchronously if it's a an asynchronous // style function and the caller didn't pass a callback. -callFunction = function(event, func, caller, args) { +var callFunction = function(event, func, caller, args) { var e, error1, funcMarkedAsync, funcName, funcPassedCallback, ref, ret; funcMarkedAsync = v8Util.getHiddenValue(func, 'asynchronous'); funcPassedCallback = typeof args[args.length - 1] === 'function'; diff --git a/atom/common/api/lib/crash-reporter.js b/atom/common/api/lib/crash-reporter.js index 57cde40f8507..8a3de9eaa14d 100644 --- a/atom/common/api/lib/crash-reporter.js +++ b/atom/common/api/lib/crash-reporter.js @@ -1,18 +1,11 @@ -var CrashReporter, binding, crashRepoter, electron, fs, os, path, spawn; +const fs = require('fs'); +const os = require('os'); +const path = require('path'); +const spawn = require('child_process').spawn; +const electron = require('electron'); +const binding = process.atomBinding('crash_reporter'); -fs = require('fs'); - -os = require('os'); - -path = require('path'); - -spawn = require('child_process').spawn; - -electron = require('electron'); - -binding = process.atomBinding('crash_reporter'); - -CrashReporter = (function() { +var CrashReporter = (function() { function CrashReporter() {} CrashReporter.prototype.start = function(options) { @@ -99,6 +92,4 @@ CrashReporter = (function() { })(); -crashRepoter = new CrashReporter; - -module.exports = crashRepoter; +module.exports = new CrashReporter; diff --git a/atom/common/api/lib/exports/electron.js b/atom/common/api/lib/exports/electron.js index 178b2d1046bc..5b93d286da61 100644 --- a/atom/common/api/lib/exports/electron.js +++ b/atom/common/api/lib/exports/electron.js @@ -1,7 +1,6 @@ // Do not expose the internal modules to `require`. exports.hideInternalModules = function() { - var globalPaths; - globalPaths = require('module').globalPaths; + var globalPaths = require('module').globalPaths; if (globalPaths.length === 3) { // Remove the "common/api/lib" and "browser-or-renderer/api/lib". diff --git a/atom/common/api/lib/native-image.js b/atom/common/api/lib/native-image.js index 1546cfaa7e6d..6f9a9bd7d542 100644 --- a/atom/common/api/lib/native-image.js +++ b/atom/common/api/lib/native-image.js @@ -1,8 +1,5 @@ -var deprecate, nativeImage; - -deprecate = require('electron').deprecate; - -nativeImage = process.atomBinding('native_image'); +const deprecate = require('electron').deprecate; +const nativeImage = process.atomBinding('native_image'); // Deprecated. deprecate.rename(nativeImage, 'createFromDataUrl', 'createFromDataURL'); diff --git a/atom/common/lib/asar.js b/atom/common/lib/asar.js index 82a5139ee67e..6c8aa64e024a 100644 --- a/atom/common/lib/asar.js +++ b/atom/common/lib/asar.js @@ -1,19 +1,15 @@ (function () { -var asar, asarStatsToFsStats, cachedArchives, child_process, fakeTime, getOrCreateArchive, gid, invalidArchiveError, nextInode, notDirError, notFoundError, overrideAPI, overrideAPISync, path, splitPath, uid, util, - hasProp = {}.hasOwnProperty; +const asar = process.binding('atom_common_asar'); +const child_process = require('child_process'); +const path = require('path'); +const util = require('util'); -asar = process.binding('atom_common_asar'); - -child_process = require('child_process'); - -path = require('path'); - -util = require('util'); +var hasProp = {}.hasOwnProperty; // Cache asar archive objects. -cachedArchives = {}; +var cachedArchives = {}; -getOrCreateArchive = function(p) { +var getOrCreateArchive = function(p) { var archive; archive = cachedArchives[p]; if (archive != null) { @@ -39,13 +35,14 @@ process.on('exit', function() { }); // Separate asar package's path from full path. -splitPath = function(p) { +var splitPath = function(p) { + var index; // shortcut to disable asar. - var index; if (process.noAsar) { return [false]; } + if (typeof p !== 'string') { return [false]; } @@ -61,15 +58,15 @@ splitPath = function(p) { }; // Convert asar archive's Stats object to fs's Stats object. -nextInode = 0; +var nextInode = 0; -uid = process.getuid != null ? process.getuid() : 0; +var uid = process.getuid != null ? process.getuid() : 0; -gid = process.getgid != null ? process.getgid() : 0; +var gid = process.getgid != null ? process.getgid() : 0; -fakeTime = new Date(); +var fakeTime = new Date(); -asarStatsToFsStats = function(stats) { +var asarStatsToFsStats = function(stats) { return { dev: 1, ino: ++nextInode, @@ -108,7 +105,7 @@ asarStatsToFsStats = function(stats) { }; // Create a ENOENT error. -notFoundError = function(asarPath, filePath, callback) { +var notFoundError = function(asarPath, filePath, callback) { var error; error = new Error("ENOENT, " + filePath + " not found in " + asarPath); error.code = "ENOENT"; @@ -122,7 +119,7 @@ notFoundError = function(asarPath, filePath, callback) { }; // Create a ENOTDIR error. -notDirError = function(callback) { +var notDirError = function(callback) { var error; error = new Error('ENOTDIR, not a directory'); error.code = 'ENOTDIR'; @@ -136,7 +133,7 @@ notDirError = function(callback) { }; // Create invalid archive error. -invalidArchiveError = function(asarPath, callback) { +var invalidArchiveError = function(asarPath, callback) { var error; error = new Error("Invalid package " + asarPath); if (typeof callback !== 'function') { @@ -148,7 +145,7 @@ invalidArchiveError = function(asarPath, callback) { }; // Override APIs that rely on passing file path instead of content to C++. -overrideAPISync = function(module, name, arg) { +var overrideAPISync = function(module, name, arg) { var old; if (arg == null) { arg = 0; @@ -174,7 +171,7 @@ overrideAPISync = function(module, name, arg) { }; }; -overrideAPI = function(module, name, arg) { +var overrideAPI = function(module, name, arg) { var old; if (arg == null) { arg = 0; From ab8908a4afb0655913a244b915f7316852d16fdc Mon Sep 17 00:00:00 2001 From: Jessica Lord Date: Thu, 14 Jan 2016 14:11:50 -0800 Subject: [PATCH 77/95] Use `const` --- atom/common/lib/init.js | 15 +++++---------- atom/common/lib/reset-search-paths.js | 7 ++----- atom/renderer/api/lib/desktop-capturer.js | 13 ++++++------- atom/renderer/api/lib/exports/electron.js | 4 +--- atom/renderer/api/lib/ipc-renderer.js | 13 +++++-------- atom/renderer/lib/chrome-api.js | 7 ++----- atom/renderer/lib/inspector.js | 19 ++++++++----------- 7 files changed, 29 insertions(+), 49 deletions(-) diff --git a/atom/common/lib/init.js b/atom/common/lib/init.js index 2165603e87e6..76fe1b45820a 100644 --- a/atom/common/lib/init.js +++ b/atom/common/lib/init.js @@ -1,12 +1,7 @@ -var Module, fs, path, timers, wrapWithActivateUvLoop; - -fs = require('fs'); - -path = require('path'); - -timers = require('timers'); - -Module = require('module'); +const fs = require('fs'); +const path = require('path'); +const timers = require('timers'); +const Module = require('module'); process.atomBinding = function(name) { var e, error; @@ -32,7 +27,7 @@ if (!process.env.ELECTRON_HIDE_INTERNAL_MODULES) { // which would delay the callbacks for arbitrary long time. So we should // initiatively activate the uv loop once setImmediate and process.nextTick is // called. -wrapWithActivateUvLoop = function(func) { +var wrapWithActivateUvLoop = function(func) { return function() { process.activateUvLoop(); return func.apply(this, arguments); diff --git a/atom/common/lib/reset-search-paths.js b/atom/common/lib/reset-search-paths.js index a996cd4ceca8..abf671196735 100644 --- a/atom/common/lib/reset-search-paths.js +++ b/atom/common/lib/reset-search-paths.js @@ -1,8 +1,5 @@ -var Module, path; - -path = require('path'); - -Module = require('module'); +const path = require('path'); +const Module = require('module'); // Clear Node's global search paths. Module.globalPaths.length = 0; diff --git a/atom/renderer/api/lib/desktop-capturer.js b/atom/renderer/api/lib/desktop-capturer.js index 5b44bdf5f23e..f9b7ca393d86 100644 --- a/atom/renderer/api/lib/desktop-capturer.js +++ b/atom/renderer/api/lib/desktop-capturer.js @@ -1,16 +1,15 @@ -var getNextId, ipcRenderer, isValid, nativeImage, nextId, ref, - indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; }; +const ipcRenderer = require('electron').ipcRenderer; +const nativeImage = require('electron').ref.nativeImage; -ref = require('electron'), ipcRenderer = ref.ipcRenderer, nativeImage = ref.nativeImage; +var nextId = 0; +var indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; }; -nextId = 0; - -getNextId = function() { +var getNextId = function() { return ++nextId; }; // |options.type| can not be empty and has to include 'window' or 'screen'. -isValid = function(options) { +var isValid = function(options) { return ((options != null ? options.types : void 0) != null) && Array.isArray(options.types); }; diff --git a/atom/renderer/api/lib/exports/electron.js b/atom/renderer/api/lib/exports/electron.js index e3fe7b335317..3f0d3254cb8b 100644 --- a/atom/renderer/api/lib/exports/electron.js +++ b/atom/renderer/api/lib/exports/electron.js @@ -1,6 +1,4 @@ -var common; - -common = require('../../../../common/api/lib/exports/electron'); +const common = require('../../../../common/api/lib/exports/electron'); // Import common modules. common.defineProperties(exports); diff --git a/atom/renderer/api/lib/ipc-renderer.js b/atom/renderer/api/lib/ipc-renderer.js index cd6b37c3db45..5b3c0a4eb788 100644 --- a/atom/renderer/api/lib/ipc-renderer.js +++ b/atom/renderer/api/lib/ipc-renderer.js @@ -1,14 +1,11 @@ -var EventEmitter, binding, ipcRenderer, v8Util, - slice = [].slice; +const EventEmitter = require('events').EventEmitter; +const binding = process.atomBinding('ipc'); +const v8Util = process.atomBinding('v8_util'); -EventEmitter = require('events').EventEmitter; - -binding = process.atomBinding('ipc'); - -v8Util = process.atomBinding('v8_util'); +var slice = [].slice; // Created by init.coffee. -ipcRenderer = v8Util.getHiddenValue(global, 'ipc'); +const ipcRenderer = v8Util.getHiddenValue(global, 'ipc'); ipcRenderer.send = function() { var args; diff --git a/atom/renderer/lib/chrome-api.js b/atom/renderer/lib/chrome-api.js index 535f7f2103b5..7ff7d2e87b99 100644 --- a/atom/renderer/lib/chrome-api.js +++ b/atom/renderer/lib/chrome-api.js @@ -1,8 +1,5 @@ -var chrome, url; - -url = require('url'); - -chrome = window.chrome = window.chrome || {}; +const url = require('url'); +const chrome = window.chrome = window.chrome || {}; chrome.extension = { getURL: function(path) { diff --git a/atom/renderer/lib/inspector.js b/atom/renderer/lib/inspector.js index b37e1d3de905..9ef6440720ff 100644 --- a/atom/renderer/lib/inspector.js +++ b/atom/renderer/lib/inspector.js @@ -1,5 +1,3 @@ -var convertToMenuTemplate, createFileSelectorElement, createMenu, pathToHtml5FileObject, showFileChooserDialog; - window.onload = function() { // Use menu API to show context menu. InspectorFrontendHost.showContextMenuAtPoint = createMenu; @@ -8,7 +6,7 @@ window.onload = function() { return WebInspector.createFileSelectorElement = createFileSelectorElement; }; -convertToMenuTemplate = function(items) { +var convertToMenuTemplate = function(items) { var fn, i, item, len, template; template = []; fn = function(item) { @@ -45,11 +43,10 @@ convertToMenuTemplate = function(items) { return template; }; -createMenu = function(x, y, items, document) { - var Menu, menu, remote; - remote = require('electron').remote; - Menu = remote.Menu; - menu = Menu.buildFromTemplate(convertToMenuTemplate(items)); +var createMenu = function(x, y, items, document) { + const remote = require('electron').remote; + const Menu = remote.Menu; + const menu = Menu.buildFromTemplate(convertToMenuTemplate(items)); // The menu is expected to show asynchronously. return setTimeout(function() { @@ -57,7 +54,7 @@ createMenu = function(x, y, items, document) { }); }; -showFileChooserDialog = function(callback) { +var showFileChooserDialog = function(callback) { var dialog, files, remote; remote = require('electron').remote; dialog = remote.dialog; @@ -67,7 +64,7 @@ showFileChooserDialog = function(callback) { } }; -pathToHtml5FileObject = function(path) { +var pathToHtml5FileObject = function(path) { var blob, fs; fs = require('fs'); blob = new Blob([fs.readFileSync(path)]); @@ -75,7 +72,7 @@ pathToHtml5FileObject = function(path) { return blob; }; -createFileSelectorElement = function(callback) { +var createFileSelectorElement = function(callback) { var fileSelectorElement; fileSelectorElement = document.createElement('span'); fileSelectorElement.style.display = 'none'; From 5412ecdcc18d2f42bf55465fde7fcea01ab32671 Mon Sep 17 00:00:00 2001 From: Jessica Lord Date: Thu, 14 Jan 2016 14:20:06 -0800 Subject: [PATCH 78/95] Use `const` --- atom/renderer/api/lib/ipc.js | 13 +++--- atom/renderer/api/lib/remote.js | 42 +++++++++---------- atom/renderer/lib/init.js | 30 ++++++------- atom/renderer/lib/override.js | 16 +++---- .../lib/web-view/guest-view-internal.js | 15 ++++--- .../lib/web-view/web-view-attributes.js | 39 ++++++++--------- atom/renderer/lib/web-view/web-view.js | 32 +++++++------- 7 files changed, 87 insertions(+), 100 deletions(-) diff --git a/atom/renderer/api/lib/ipc.js b/atom/renderer/api/lib/ipc.js index 1e0e703e6a84..e58cd0273c2b 100644 --- a/atom/renderer/api/lib/ipc.js +++ b/atom/renderer/api/lib/ipc.js @@ -1,15 +1,14 @@ -var EventEmitter, deprecate, ipc, ipcRenderer, method, ref, - slice = [].slice; +const ipcRenderer = require('electron').ipcRenderer; +const deprecate = require('electron').deprecate; +const EventEmitter = require('events').EventEmitter; -ref = require('electron'), ipcRenderer = ref.ipcRenderer, deprecate = ref.deprecate; - -EventEmitter = require('events').EventEmitter; +var slice = [].slice; // This module is deprecated, we mirror everything from ipcRenderer. deprecate.warn('ipc module', 'require("electron").ipcRenderer'); // Routes events of ipcRenderer. -ipc = new EventEmitter; +var ipc = new EventEmitter; ipcRenderer.emit = function() { var args, channel, event; @@ -19,7 +18,7 @@ ipcRenderer.emit = function() { }; // Deprecated. -for (method in ipcRenderer) { +for (var method in ipcRenderer) { if (method.startsWith('send')) { ipc[method] = ipcRenderer[method]; } diff --git a/atom/renderer/api/lib/remote.js b/atom/renderer/api/lib/remote.js index f50fca7a2d4a..c9b823b3b397 100644 --- a/atom/renderer/api/lib/remote.js +++ b/atom/renderer/api/lib/remote.js @@ -1,14 +1,13 @@ -var CallbacksRegistry, browserModules, builtinCache, callbacksRegistry, createRemoteMemberFunction, createRemoteMemberProperty, fn, ipcRenderer, isCircular, metaToPlainObject, metaToValue, moduleCache, name, processCache, ref, v8Util, webContentsCache, windowCache, wrapArgs, - indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; }; +const ipcRenderer = require('electron').ipcRenderer; +const CallbacksRegistry = require('electron').CallbacksRegistry; +const v8Util = process.atomBinding('v8_util'); -ref = require('electron'), ipcRenderer = ref.ipcRenderer, CallbacksRegistry = ref.CallbacksRegistry; +const callbacksRegistry = new CallbacksRegistry; -v8Util = process.atomBinding('v8_util'); - -callbacksRegistry = new CallbacksRegistry; +var indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; }; // Check for circular reference. -isCircular = function(field, visited) { +var isCircular = function(field, visited) { if (typeof field === 'object') { if (indexOf.call(visited, field) >= 0) { return true; @@ -19,7 +18,7 @@ isCircular = function(field, visited) { }; // Convert the arguments object into an array of meta data. -wrapArgs = function(args, visited) { +var wrapArgs = function(args, visited) { var valueToMeta; if (visited == null) { visited = []; @@ -87,7 +86,7 @@ wrapArgs = function(args, visited) { }; // Convert meta data from browser into real value. -metaToValue = function(meta) { +var metaToValue = function(meta) { var RemoteFunction, el, i, j, len, len1, member, ref1, ref2, results, ret; switch (meta.type) { case 'value': @@ -169,7 +168,7 @@ metaToValue = function(meta) { }; // Construct a plain object from the meta. -metaToPlainObject = function(meta) { +var metaToPlainObject = function(meta) { var i, len, name, obj, ref1, ref2, value; obj = (function() { switch (meta.type) { @@ -190,7 +189,7 @@ metaToPlainObject = function(meta) { // Create a RemoteMemberFunction instance. // This function's content should not be inlined into metaToValue, otherwise V8 // may consider it circular reference. -createRemoteMemberFunction = function(metaId, name) { +var createRemoteMemberFunction = function(metaId, name) { var RemoteMemberFunction; return RemoteMemberFunction = (function() { function RemoteMemberFunction() { @@ -216,7 +215,7 @@ createRemoteMemberFunction = function(metaId, name) { // Create configuration for defineProperty. // This function's content should not be inlined into metaToValue, otherwise V8 // may consider it circular reference. -createRemoteMemberProperty = function(metaId, name) { +var createRemoteMemberProperty = function(metaId, name) { return { enumerable: true, configurable: false, @@ -245,25 +244,24 @@ ipcRenderer.on('ATOM_RENDERER_RELEASE_CALLBACK', function(event, id) { }); // List all built-in modules in browser process. -browserModules = require('../../../browser/api/lib/exports/electron'); +const browserModules = require('../../../browser/api/lib/exports/electron'); // And add a helper receiver for each one. -fn = function(name) { +var fn = function(name) { return Object.defineProperty(exports, name, { get: function() { return exports.getBuiltin(name); } }); }; -for (name in browserModules) { +for (var name in browserModules) { fn(name); } - // Get remote module. // (Just like node's require, the modules are cached permanently, note that this // is safe leak since the object is not expected to get freed in browser) -moduleCache = {}; +var moduleCache = {}; exports.require = function(module) { var meta; @@ -274,13 +272,11 @@ exports.require = function(module) { return moduleCache[module] = metaToValue(meta); }; - // Optimize require('electron'). moduleCache.electron = exports; - // Alias to remote.require('electron').xxx. -builtinCache = {}; +var builtinCache = {}; exports.getBuiltin = function(module) { var meta; @@ -292,7 +288,7 @@ exports.getBuiltin = function(module) { }; // Get current BrowserWindow object. -windowCache = null; +var windowCache = null; exports.getCurrentWindow = function() { var meta; @@ -304,7 +300,7 @@ exports.getCurrentWindow = function() { }; // Get current WebContents object. -webContentsCache = null; +var webContentsCache = null; exports.getCurrentWebContents = function() { var meta; @@ -323,7 +319,7 @@ exports.getGlobal = function(name) { }; // Get the process object in browser. -processCache = null; +var processCache = null; exports.__defineGetter__('process', function() { if (processCache == null) { diff --git a/atom/renderer/lib/init.js b/atom/renderer/lib/init.js index 8fd0d2e25e71..297ee61fcff2 100644 --- a/atom/renderer/lib/init.js +++ b/atom/renderer/lib/init.js @@ -1,14 +1,9 @@ 'user strict'; -var Module, arg, error, error1, events, globalPaths, i, len, nodeIntegration, path, pathname, preloadScript, ref, url, v8Util; - -events = require('events'); - -path = require('path'); - -url = require('url'); - -Module = require('module'); +const events = require('events'); +const path = require('path'); +const url = require('url'); +const Module = require('module'); // We modified the original process.argv to let node.js load the @@ -23,7 +18,7 @@ require(path.resolve(__dirname, '..', '..', 'common', 'lib', 'reset-search-paths // Import common settings. require(path.resolve(__dirname, '..', '..', 'common', 'lib', 'init')); -globalPaths = Module.globalPaths; +var globalPaths = Module.globalPaths; if (!process.env.ELECTRON_HIDE_INTERNAL_MODULES) { globalPaths.push(path.resolve(__dirname, '..', 'api', 'lib')); @@ -33,7 +28,7 @@ if (!process.env.ELECTRON_HIDE_INTERNAL_MODULES) { globalPaths.push(path.resolve(__dirname, '..', 'api', 'lib', 'exports')); // The global variable will be used by ipc for event dispatching -v8Util = process.atomBinding('v8_util'); +var v8Util = process.atomBinding('v8_util'); v8Util.setHiddenValue(global, 'ipc', new events.EventEmitter); @@ -46,11 +41,13 @@ electron.ipcRenderer.on('ELECTRON_INTERNAL_RENDERER_WEB_FRAME_METHOD', (event, m }); // Process command line arguments. -nodeIntegration = 'false'; +var nodeIntegration = 'false'; +var preloadScript = null; -ref = process.argv; +var ref = process.argv; +var i, len; for (i = 0, len = ref.length; i < len; i++) { - arg = ref[i]; + var arg = ref[i]; if (arg.indexOf('--guest-instance-id=') === 0) { // This is a guest web view. process.guestInstanceId = parseInt(arg.substr(arg.indexOf('=') + 1)); @@ -90,7 +87,7 @@ if (nodeIntegration === 'true' || nodeIntegration === 'all' || nodeIntegration = // Set the __filename to the path of html file if it is file: protocol. if (window.location.protocol === 'file:') { - pathname = process.platform === 'win32' && window.location.pathname[0] === '/' ? window.location.pathname.substr(1) : window.location.pathname; + var pathname = process.platform === 'win32' && window.location.pathname[0] === '/' ? window.location.pathname.substr(1) : window.location.pathname; global.__filename = path.normalize(decodeURIComponent(pathname)); global.__dirname = path.dirname(global.__filename); @@ -132,8 +129,7 @@ if (nodeIntegration === 'true' || nodeIntegration === 'all' || nodeIntegration = if (preloadScript) { try { require(preloadScript); - } catch (error1) { - error = error1; + } catch (error) { if (error.code === 'MODULE_NOT_FOUND') { console.error("Unable to load preload script " + preloadScript); } else { diff --git a/atom/renderer/lib/override.js b/atom/renderer/lib/override.js index c240281363b9..6ff1e80785d8 100644 --- a/atom/renderer/lib/override.js +++ b/atom/renderer/lib/override.js @@ -1,18 +1,18 @@ -var BrowserWindowProxy, a, getHistoryOperation, ipcRenderer, ref, remote, resolveURL, sendHistoryOperation, - slice = [].slice; +const ipcRenderer = require('electron').ipcRenderer; +const remote = require('electron').remote; -ref = require('electron'), ipcRenderer = ref.ipcRenderer, remote = ref.remote; +var slice = [].slice; // Helper function to resolve relative url. -a = window.top.document.createElement('a'); +var a = window.top.document.createElement('a'); -resolveURL = function(url) { +var resolveURL = function(url) { a.href = url; return a.href; }; // Window object returned by "window.open". -BrowserWindowProxy = (function() { +var BrowserWindowProxy = (function() { BrowserWindowProxy.proxies = {}; BrowserWindowProxy.getOrCreate = function(guestId) { @@ -180,13 +180,13 @@ ipcRenderer.on('ATOM_SHELL_GUEST_WINDOW_POSTMESSAGE', function(event, sourceId, }); // Forward history operations to browser. -sendHistoryOperation = function() { +var sendHistoryOperation = function() { var args; args = 1 <= arguments.length ? slice.call(arguments, 0) : []; return ipcRenderer.send.apply(ipcRenderer, ['ATOM_SHELL_NAVIGATION_CONTROLLER'].concat(slice.call(args))); }; -getHistoryOperation = function() { +var getHistoryOperation = function() { var args; args = 1 <= arguments.length ? slice.call(arguments, 0) : []; return ipcRenderer.sendSync.apply(ipcRenderer, ['ATOM_SHELL_SYNC_NAVIGATION_CONTROLLER'].concat(slice.call(args))); diff --git a/atom/renderer/lib/web-view/guest-view-internal.js b/atom/renderer/lib/web-view/guest-view-internal.js index 5dd86aff6613..046c9643eadd 100644 --- a/atom/renderer/lib/web-view/guest-view-internal.js +++ b/atom/renderer/lib/web-view/guest-view-internal.js @@ -1,11 +1,10 @@ -var DEPRECATED_EVENTS, WEB_VIEW_EVENTS, dispatchEvent, ipcRenderer, ref, requestId, webFrame, - slice = [].slice; +const ipcRenderer = require('electron').ipcRenderer; +const webFrame = require('electron').webFrame; -ref = require('electron'), ipcRenderer = ref.ipcRenderer, webFrame = ref.webFrame; +var slice = [].slice; +var requestId = 0; -requestId = 0; - -WEB_VIEW_EVENTS = { +var WEB_VIEW_EVENTS = { 'load-commit': ['url', 'isMainFrame'], 'did-finish-load': [], 'did-fail-load': ['errorCode', 'errorDescription', 'validatedURL'], @@ -38,11 +37,11 @@ WEB_VIEW_EVENTS = { 'found-in-page': ['result'] }; -DEPRECATED_EVENTS = { +var DEPRECATED_EVENTS = { 'page-title-updated': 'page-title-set' }; -dispatchEvent = function() { +var dispatchEvent = function() { var args, domEvent, eventKey, eventName, f, i, j, len, ref1, webView; webView = arguments[0], eventName = arguments[1], eventKey = arguments[2], args = 4 <= arguments.length ? slice.call(arguments, 3) : []; if (DEPRECATED_EVENTS[eventName] != null) { diff --git a/atom/renderer/lib/web-view/web-view-attributes.js b/atom/renderer/lib/web-view/web-view-attributes.js index 0352dc5e821d..90ce9f1290fc 100644 --- a/atom/renderer/lib/web-view/web-view-attributes.js +++ b/atom/renderer/lib/web-view/web-view-attributes.js @@ -1,26 +1,23 @@ -var AllowTransparencyAttribute, AutosizeAttribute, AutosizeDimensionAttribute, BooleanAttribute, HttpReferrerAttribute, PartitionAttribute, PreloadAttribute, SrcAttribute, UserAgentAttribute, WebViewAttribute, WebViewImpl, a, guestViewInternal, remote, resolveURL, webViewConstants, - extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }, - hasProp = {}.hasOwnProperty; +const WebViewImpl = require('./web-view'); +const guestViewInternal = require('./guest-view-internal'); +const webViewConstants = require('./web-view-constants'); +const remote = require('electron').remote; -WebViewImpl = require('./web-view'); +var extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }; -guestViewInternal = require('./guest-view-internal'); - -webViewConstants = require('./web-view-constants'); - -remote = require('electron').remote; +var hasProp = {}.hasOwnProperty; // Helper function to resolve url set in attribute. -a = document.createElement('a'); +var a = document.createElement('a'); -resolveURL = function(url) { +var resolveURL = function(url) { a.href = url; return a.href; }; // Attribute objects. // Default implementation of a WebView attribute. -WebViewAttribute = (function() { +var WebViewAttribute = (function() { function WebViewAttribute(name, webViewImpl) { this.name = name; this.value = webViewImpl.webviewNode[name] || ''; @@ -71,7 +68,7 @@ WebViewAttribute = (function() { })(); // An attribute that is treated as a Boolean. -BooleanAttribute = (function(superClass) { +var BooleanAttribute = (function(superClass) { extend(BooleanAttribute, superClass); function BooleanAttribute(name, webViewImpl) { @@ -95,7 +92,7 @@ BooleanAttribute = (function(superClass) { })(WebViewAttribute); // Attribute that specifies whether transparency is allowed in the webview. -AllowTransparencyAttribute = (function(superClass) { +var AllowTransparencyAttribute = (function(superClass) { extend(AllowTransparencyAttribute, superClass); function AllowTransparencyAttribute(webViewImpl) { @@ -114,7 +111,7 @@ AllowTransparencyAttribute = (function(superClass) { })(BooleanAttribute); // Attribute used to define the demension limits of autosizing. -AutosizeDimensionAttribute = (function(superClass) { +var AutosizeDimensionAttribute = (function(superClass) { extend(AutosizeDimensionAttribute, superClass); function AutosizeDimensionAttribute(name, webViewImpl) { @@ -147,7 +144,7 @@ AutosizeDimensionAttribute = (function(superClass) { })(WebViewAttribute); // Attribute that specifies whether the webview should be autosized. -AutosizeAttribute = (function(superClass) { +var AutosizeAttribute = (function(superClass) { extend(AutosizeAttribute, superClass); function AutosizeAttribute(webViewImpl) { @@ -161,7 +158,7 @@ AutosizeAttribute = (function(superClass) { })(BooleanAttribute); // Attribute representing the state of the storage partition. -PartitionAttribute = (function(superClass) { +var PartitionAttribute = (function(superClass) { extend(PartitionAttribute, superClass); function PartitionAttribute(webViewImpl) { @@ -189,7 +186,7 @@ PartitionAttribute = (function(superClass) { })(WebViewAttribute); // Attribute that handles the location and navigation of the webview. -SrcAttribute = (function(superClass) { +var SrcAttribute = (function(superClass) { extend(SrcAttribute, superClass); function SrcAttribute(webViewImpl) { @@ -292,7 +289,7 @@ SrcAttribute = (function(superClass) { })(WebViewAttribute); // Attribute specifies HTTP referrer. -HttpReferrerAttribute = (function(superClass) { +var HttpReferrerAttribute = (function(superClass) { extend(HttpReferrerAttribute, superClass); function HttpReferrerAttribute(webViewImpl) { @@ -304,7 +301,7 @@ HttpReferrerAttribute = (function(superClass) { })(WebViewAttribute); // Attribute specifies user agent -UserAgentAttribute = (function(superClass) { +var UserAgentAttribute = (function(superClass) { extend(UserAgentAttribute, superClass); function UserAgentAttribute(webViewImpl) { @@ -316,7 +313,7 @@ UserAgentAttribute = (function(superClass) { })(WebViewAttribute); // Attribute that set preload script. -PreloadAttribute = (function(superClass) { +var PreloadAttribute = (function(superClass) { extend(PreloadAttribute, superClass); function PreloadAttribute(webViewImpl) { diff --git a/atom/renderer/lib/web-view/web-view.js b/atom/renderer/lib/web-view/web-view.js index 07624b79b67a..1daf66e55aa3 100644 --- a/atom/renderer/lib/web-view/web-view.js +++ b/atom/renderer/lib/web-view/web-view.js @@ -1,26 +1,26 @@ 'user strict'; -var WebViewImpl, deprecate, getNextId, guestViewInternal, ipcRenderer, listener, nextId, ref, registerBrowserPluginElement, registerWebViewElement, remote, useCapture, v8Util, webFrame, webViewConstants, - hasProp = {}.hasOwnProperty, - slice = [].slice; +const deprecate = require('electron').deprecate; +const webFrame = require('electron').webFrame; +const remote = require('electron').remote; +const ipcRenderer = require('electron').ipcRenderer; -ref = require('electron'), deprecate = ref.deprecate, webFrame = ref.webFrame, remote = ref.remote, ipcRenderer = ref.ipcRenderer; +const v8Util = process.atomBinding('v8_util'); +const guestViewInternal = require('./guest-view-internal'); +const webViewConstants = require('./web-view-constants'); -v8Util = process.atomBinding('v8_util'); - -guestViewInternal = require('./guest-view-internal'); - -webViewConstants = require('./web-view-constants'); +var hasProp = {}.hasOwnProperty; +var slice = [].slice; // ID generator. -nextId = 0; +var nextId = 0; -getNextId = function() { +var getNextId = function() { return ++nextId; }; // Represents the internal state of the WebView node. -WebViewImpl = (function() { +var WebViewImpl = (function() { function WebViewImpl(webviewNode) { var shadowRoot; this.webviewNode = webviewNode; @@ -274,7 +274,7 @@ WebViewImpl = (function() { })(); // Registers browser plugin custom element. -registerBrowserPluginElement = function() { +var registerBrowserPluginElement = function() { var proto; proto = Object.create(HTMLObjectElement.prototype); proto.createdCallback = function() { @@ -310,7 +310,7 @@ registerBrowserPluginElement = function() { }; // Registers custom element. -registerWebViewElement = function() { +var registerWebViewElement = function() { var createBlockHandler, createNonBlockHandler, i, j, len, len1, m, methods, nonblockMethods, proto; proto = Object.create(HTMLObjectElement.prototype); proto.createdCallback = function() { @@ -444,9 +444,9 @@ registerWebViewElement = function() { return delete proto.attributeChangedCallback; }; -useCapture = true; +var useCapture = true; -listener = function(event) { +var listener = function(event) { if (document.readyState === 'loading') { return; } From ae2893ceaaac64b720bea0dd799524452b918ac8 Mon Sep 17 00:00:00 2001 From: Jessica Lord Date: Thu, 14 Jan 2016 15:44:33 -0800 Subject: [PATCH 79/95] Inline `var` --- atom/browser/api/lib/app.js | 19 ++++++------------- 1 file changed, 6 insertions(+), 13 deletions(-) diff --git a/atom/browser/api/lib/app.js b/atom/browser/api/lib/app.js index bd820127cd9a..bb194be62a01 100644 --- a/atom/browser/api/lib/app.js +++ b/atom/browser/api/lib/app.js @@ -9,14 +9,6 @@ const app = bindings.app; var slice = [].slice; -var appPath; -var fn; -var i; -var len; -var name; -var ref1; -var wrapDownloadItem; - app.__proto__ = EventEmitter.prototype; app.setApplicationMenu = function(menu) { @@ -49,7 +41,7 @@ if (process.platform === 'darwin') { }; } -appPath = null; +var appPath = null; app.setAppPath = function(path) { return appPath = path; @@ -60,16 +52,17 @@ app.getAppPath = function() { }; // Routes the events to webContents. -ref1 = ['login', 'certificate-error', 'select-client-certificate']; -fn = function(name) { +var ref1 = ['login', 'certificate-error', 'select-client-certificate']; +var fn = function(name) { return app.on(name, function() { var args, event, webContents; event = arguments[0], webContents = arguments[1], args = 3 <= arguments.length ? slice.call(arguments, 2) : []; return webContents.emit.apply(webContents, [name, event].concat(slice.call(args))); }); }; +var i, len; for (i = 0, len = ref1.length; i < len; i++) { - name = ref1[i]; + var name = ref1[i]; fn(name); } @@ -112,7 +105,7 @@ deprecate.event(app, 'activate-with-no-open-windows', 'activate', function(event deprecate.event(app, 'select-certificate', 'select-client-certificate'); // Wrappers for native classes. -wrapDownloadItem = function(downloadItem) { +var wrapDownloadItem = function(downloadItem) { // downloadItem is an EventEmitter. downloadItem.__proto__ = EventEmitter.prototype; From 047975609d24065528ed56ff8afc976ba057950c Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Thu, 14 Jan 2016 17:03:51 -0800 Subject: [PATCH 80/95] Add missing -spec suffix to desktop capturer spec --- spec/{api-desktop-capturer.js => api-desktop-capturer-spec.js} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename spec/{api-desktop-capturer.js => api-desktop-capturer-spec.js} (100%) diff --git a/spec/api-desktop-capturer.js b/spec/api-desktop-capturer-spec.js similarity index 100% rename from spec/api-desktop-capturer.js rename to spec/api-desktop-capturer-spec.js From 5a4a8e1fa75c23246bd91e36bab0f5e378bfaeb6 Mon Sep 17 00:00:00 2001 From: Jessica Lord Date: Thu, 14 Jan 2016 17:03:55 -0800 Subject: [PATCH 81/95] :fire: stray `ref` --- atom/renderer/api/lib/desktop-capturer.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/atom/renderer/api/lib/desktop-capturer.js b/atom/renderer/api/lib/desktop-capturer.js index f9b7ca393d86..c445bfecbe1b 100644 --- a/atom/renderer/api/lib/desktop-capturer.js +++ b/atom/renderer/api/lib/desktop-capturer.js @@ -1,5 +1,5 @@ const ipcRenderer = require('electron').ipcRenderer; -const nativeImage = require('electron').ref.nativeImage; +const nativeImage = require('electron').nativeImage; var nextId = 0; var indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; }; From 572f53dc5eb5a27a634065c8292ab9790b72f4a6 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Thu, 14 Jan 2016 17:04:38 -0800 Subject: [PATCH 82/95] Expand spec description --- spec/api-desktop-capturer-spec.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/api-desktop-capturer-spec.js b/spec/api-desktop-capturer-spec.js index 288e57ee4489..3a03366d4545 100644 --- a/spec/api-desktop-capturer-spec.js +++ b/spec/api-desktop-capturer-spec.js @@ -5,7 +5,7 @@ assert = require('assert'); desktopCapturer = require('electron').desktopCapturer; describe('desktopCapturer', function() { - return it('should returns something', function(done) { + return it('should return a non-empty array of sources', function(done) { return desktopCapturer.getSources({ types: ['window', 'screen'] }, function(error, sources) { From 003de0debe1046caf1d4ec41464ec25b53be1dbe Mon Sep 17 00:00:00 2001 From: Jessica Lord Date: Thu, 14 Jan 2016 18:07:29 -0800 Subject: [PATCH 83/95] Clean up variable declarations --- atom/browser/api/lib/app.js | 6 +++--- atom/browser/api/lib/dialog.js | 4 ++-- atom/browser/lib/init.js | 4 ++-- atom/renderer/lib/init.js | 4 ++-- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/atom/browser/api/lib/app.js b/atom/browser/api/lib/app.js index bb194be62a01..c4cdb5124651 100644 --- a/atom/browser/api/lib/app.js +++ b/atom/browser/api/lib/app.js @@ -60,10 +60,10 @@ var fn = function(name) { return webContents.emit.apply(webContents, [name, event].concat(slice.call(args))); }); }; -var i, len; +var i, len, name; for (i = 0, len = ref1.length; i < len; i++) { - var name = ref1[i]; - fn(name); + name = ref1[i]; + fn(ref1[i]); } // Deprecated. diff --git a/atom/browser/api/lib/dialog.js b/atom/browser/api/lib/dialog.js index 302fa7bf07fe..b77773be2096 100644 --- a/atom/browser/api/lib/dialog.js +++ b/atom/browser/api/lib/dialog.js @@ -163,8 +163,8 @@ module.exports = { // Mark standard asynchronous functions. var ref1 = ['showMessageBox', 'showOpenDialog', 'showSaveDialog']; -var j, len +var j, len, api; for (j = 0, len = ref1.length; j < len; j++) { - var api = ref1[j]; + api = ref1[j]; v8Util.setHiddenValue(module.exports[api], 'asynchronous', true); } diff --git a/atom/browser/lib/init.js b/atom/browser/lib/init.js index a38cd6f9e41f..272cebbf875b 100644 --- a/atom/browser/lib/init.js +++ b/atom/browser/lib/init.js @@ -91,9 +91,9 @@ require('./guest-window-manager'); // Now we try to load app's package.json. var packageJson = null; var searchPaths = ['app', 'app.asar', 'default_app']; -var i, len; +var i, len, packagePath; for (i = 0, len = searchPaths.length; i < len; i++) { - var packagePath = searchPaths[i]; + packagePath = searchPaths[i]; try { packagePath = path.join(process.resourcesPath, packagePath); packageJson = JSON.parse(fs.readFileSync(path.join(packagePath, 'package.json'))); diff --git a/atom/renderer/lib/init.js b/atom/renderer/lib/init.js index 297ee61fcff2..556e9d617bdb 100644 --- a/atom/renderer/lib/init.js +++ b/atom/renderer/lib/init.js @@ -45,9 +45,9 @@ var nodeIntegration = 'false'; var preloadScript = null; var ref = process.argv; -var i, len; +var i, len, arg; for (i = 0, len = ref.length; i < len; i++) { - var arg = ref[i]; + arg = ref[i]; if (arg.indexOf('--guest-instance-id=') === 0) { // This is a guest web view. process.guestInstanceId = parseInt(arg.substr(arg.indexOf('=') + 1)); From cda88db77ce59e5d4f56a9be3d773cdb35406191 Mon Sep 17 00:00:00 2001 From: evgenyzinoviev Date: Fri, 15 Jan 2016 03:45:19 +0100 Subject: [PATCH 84/95] Added option to prevent a window from being moved on OS X --- atom/browser/native_window_mac.mm | 5 +++++ atom/common/options_switches.cc | 1 + atom/common/options_switches.h | 1 + docs/api/browser-window.md | 1 + 4 files changed, 8 insertions(+) diff --git a/atom/browser/native_window_mac.mm b/atom/browser/native_window_mac.mm index 2d75a682c653..8f7699140474 100644 --- a/atom/browser/native_window_mac.mm +++ b/atom/browser/native_window_mac.mm @@ -452,6 +452,11 @@ NativeWindowMac::NativeWindowMac( set_force_using_draggable_region(true); } + bool movable; + if (options.Get(options::kMovable, &movable)) { + [window_ setMovable:movable]; + } + // On OS X the initial window size doesn't include window frame. bool use_content_size = false; options.Get(options::kUseContentSize, &use_content_size); diff --git a/atom/common/options_switches.cc b/atom/common/options_switches.cc index 6c4e8477cc4a..477fe6755faf 100644 --- a/atom/common/options_switches.cc +++ b/atom/common/options_switches.cc @@ -22,6 +22,7 @@ const char kMinHeight[] = "minHeight"; const char kMaxWidth[] = "maxWidth"; const char kMaxHeight[] = "maxHeight"; const char kResizable[] = "resizable"; +const char kMovable[] = "movable"; const char kFullscreen[] = "fullscreen"; // Whether the window should show in taskbar. diff --git a/atom/common/options_switches.h b/atom/common/options_switches.h index f038521673a0..78de53b825f9 100644 --- a/atom/common/options_switches.h +++ b/atom/common/options_switches.h @@ -23,6 +23,7 @@ extern const char kMinHeight[]; extern const char kMaxWidth[]; extern const char kMaxHeight[]; extern const char kResizable[]; +extern const char kMovable[]; extern const char kFullscreen[]; extern const char kSkipTaskbar[]; extern const char kKiosk[]; diff --git a/docs/api/browser-window.md b/docs/api/browser-window.md index 61180d5b89a9..211b23a5eb9e 100644 --- a/docs/api/browser-window.md +++ b/docs/api/browser-window.md @@ -47,6 +47,7 @@ It creates a new `BrowserWindow` with native properties as set by the `options`. * `maxWidth` Integer - Window's maximum width. Default is no limit. * `maxHeight` Integer - Window's maximum height. Default is no limit. * `resizable` Boolean - Whether window is resizable. Default is `true`. + * `movable` Boolean - Whether window is movable. Default is `true`. * `alwaysOnTop` Boolean - Whether the window should always stay on top of other windows. Default is `false`. * `fullscreen` Boolean - Whether the window should show in fullscreen. When From 39225ac5ec5b7d5a779011a6e3638389cb256540 Mon Sep 17 00:00:00 2001 From: Cheng Zhao Date: Fri, 15 Jan 2016 14:27:19 +0800 Subject: [PATCH 85/95] Bump v0.36.4 --- atom.gyp | 2 +- atom/browser/resources/mac/Info.plist | 4 ++-- atom/browser/resources/win/atom.rc | 8 ++++---- atom/common/atom_version.h | 2 +- package.json | 2 +- 5 files changed, 9 insertions(+), 9 deletions(-) diff --git a/atom.gyp b/atom.gyp index 1ea973681bfb..0960572dac2c 100644 --- a/atom.gyp +++ b/atom.gyp @@ -4,7 +4,7 @@ 'product_name%': 'Electron', 'company_name%': 'GitHub, Inc', 'company_abbr%': 'github', - 'version%': '0.36.3', + 'version%': '0.36.4', }, 'includes': [ 'filenames.gypi', diff --git a/atom/browser/resources/mac/Info.plist b/atom/browser/resources/mac/Info.plist index 105c034d250f..f1de499afeda 100644 --- a/atom/browser/resources/mac/Info.plist +++ b/atom/browser/resources/mac/Info.plist @@ -17,9 +17,9 @@ CFBundleIconFile atom.icns CFBundleVersion - 0.36.3 + 0.36.4 CFBundleShortVersionString - 0.36.3 + 0.36.4 LSApplicationCategoryType public.app-category.developer-tools LSMinimumSystemVersion diff --git a/atom/browser/resources/win/atom.rc b/atom/browser/resources/win/atom.rc index 676b503fd3f9..5763cb7ba3c6 100644 --- a/atom/browser/resources/win/atom.rc +++ b/atom/browser/resources/win/atom.rc @@ -56,8 +56,8 @@ END // VS_VERSION_INFO VERSIONINFO - FILEVERSION 0,36,3,0 - PRODUCTVERSION 0,36,3,0 + FILEVERSION 0,36,4,0 + PRODUCTVERSION 0,36,4,0 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -74,12 +74,12 @@ BEGIN BEGIN VALUE "CompanyName", "GitHub, Inc." VALUE "FileDescription", "Electron" - VALUE "FileVersion", "0.36.3" + VALUE "FileVersion", "0.36.4" VALUE "InternalName", "electron.exe" VALUE "LegalCopyright", "Copyright (C) 2015 GitHub, Inc. All rights reserved." VALUE "OriginalFilename", "electron.exe" VALUE "ProductName", "Electron" - VALUE "ProductVersion", "0.36.3" + VALUE "ProductVersion", "0.36.4" VALUE "SquirrelAwareVersion", "1" END END diff --git a/atom/common/atom_version.h b/atom/common/atom_version.h index 55b5a3a402d9..838eca35dbc4 100644 --- a/atom/common/atom_version.h +++ b/atom/common/atom_version.h @@ -7,7 +7,7 @@ #define ATOM_MAJOR_VERSION 0 #define ATOM_MINOR_VERSION 36 -#define ATOM_PATCH_VERSION 3 +#define ATOM_PATCH_VERSION 4 #define ATOM_VERSION_IS_RELEASE 1 diff --git a/package.json b/package.json index d082e861cd83..7f1bde090eb4 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "electron", - "version": "0.36.3", + "version": "0.36.4", "devDependencies": { "asar": "^0.9.0", "request": "*" From a5cc1053113e5b500519e5cde982271757bb05d5 Mon Sep 17 00:00:00 2001 From: Importcjj Date: Fri, 15 Jan 2016 15:26:16 +0800 Subject: [PATCH 86/95] fix incorrect markdown tag --- .../zh-CN/tutorial/desktop-environment-integration.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs-translations/zh-CN/tutorial/desktop-environment-integration.md b/docs-translations/zh-CN/tutorial/desktop-environment-integration.md index 6ded331627e9..614aeed708f6 100644 --- a/docs-translations/zh-CN/tutorial/desktop-environment-integration.md +++ b/docs-translations/zh-CN/tutorial/desktop-environment-integration.md @@ -31,7 +31,7 @@ app.clearRecentDocuments(); ## 自定义的鱼眼菜单(OS X) OS X 可以让开发者定制自己的菜单,通常会包含一些常用特性的快捷方式。 ### 菜单中的终端 -[Dock menu of Terminal.app][6] +![Dock menu of Terminal.app][6] 使用 `app.dock.setMenu` API 来设置你的菜单,这仅在 OS X 上可行: ```javascript From c10c419f1da07184254d4210215a3d256ec4ae7a Mon Sep 17 00:00:00 2001 From: Cheng Zhao Date: Wed, 13 Jan 2016 17:07:18 +0800 Subject: [PATCH 87/95] No need to call sender.callbacks.remove The IDWeakMap automatically removes the key when object is garbage collected. --- atom/browser/api/lib/web-contents.js | 4 +++ atom/browser/lib/rpc-server.js | 43 ++++++++++++++-------------- 2 files changed, 26 insertions(+), 21 deletions(-) diff --git a/atom/browser/api/lib/web-contents.js b/atom/browser/api/lib/web-contents.js index 47f5eb4639b9..2cce6e6cb9dc 100644 --- a/atom/browser/api/lib/web-contents.js +++ b/atom/browser/api/lib/web-contents.js @@ -70,6 +70,10 @@ let wrapWebContents = function(webContents) { var controller, method, name, ref1; webContents.__proto__ = EventEmitter.prototype; + // Every remote callback from renderer process would add a listenter to the + // render-view-deleted event, so ignore the listenters warning. + webContents.setMaxListeners(0); + // WebContents::send(channel, args..) webContents.send = function() { var args, channel; diff --git a/atom/browser/lib/rpc-server.js b/atom/browser/lib/rpc-server.js index 346db74f6ecd..e7fa56b9e41a 100644 --- a/atom/browser/lib/rpc-server.js +++ b/atom/browser/lib/rpc-server.js @@ -1,3 +1,5 @@ +'use strict'; + const path = require('path'); const electron = require('electron'); const ipcMain = electron.ipcMain; @@ -41,7 +43,7 @@ var valueToMeta = function(sender, value, optimizeSimpleObject) { } // Treat the arguments object as array. - if (meta.type === 'object' && (value.callee != null) && (value.length != null)) { + if (meta.type === 'object' && (value.hasOwnProperty('callee')) && (value.length != null)) { meta.type = 'array'; } if (meta.type === 'array') { @@ -113,7 +115,7 @@ var exceptionToMeta = function(error) { var unwrapArgs = function(sender, args) { var metaToValue; metaToValue = function(meta) { - var i, len, member, ref, rendererReleased, ret, returnValue; + var i, len, member, ref, rendererReleased, returnValue; switch (meta.type) { case 'value': return meta.value; @@ -130,7 +132,7 @@ var unwrapArgs = function(sender, args) { then: metaToValue(meta.then) }); case 'object': - ret = v8Util.createObjectWithName(meta.name); + let ret = v8Util.createObjectWithName(meta.name); ref = meta.members; for (i = 0, len = ref.length; i < len; i++) { member = ref[i]; @@ -147,31 +149,30 @@ var unwrapArgs = function(sender, args) { if (!sender.callbacks) { sender.callbacks = new IDWeakMap; sender.on('render-view-deleted', function() { - return sender.callbacks.clear(); + return this.callbacks.clear(); }); } - if (sender.callbacks.has(meta.id)) { + + if (sender.callbacks.has(meta.id)) return sender.callbacks.get(meta.id); - } + + // Prevent the callback from being called when its page is gone. rendererReleased = false; - objectsRegistry.once("clear-" + (sender.getId()), function() { - return rendererReleased = true; + sender.once('render-view-deleted', function() { + rendererReleased = true; }); - ret = function() { - if (rendererReleased) { - throw new Error("Attempting to call a function in a renderer window that has been closed or released. Function provided here: " + meta.location + "."); - } - return sender.send('ATOM_RENDERER_CALLBACK', meta.id, valueToMeta(sender, arguments)); + + let callIntoRenderer = function(...args) { + if (rendererReleased) + throw new Error(`Attempting to call a function in a renderer window that has been closed or released. Function provided here: ${meta.location}.`); + sender.send('ATOM_RENDERER_CALLBACK', meta.id, valueToMeta(sender, args)); }; - v8Util.setDestructor(ret, function() { - if (rendererReleased) { - return; - } - sender.callbacks.remove(meta.id); - return sender.send('ATOM_RENDERER_RELEASE_CALLBACK', meta.id); + v8Util.setDestructor(callIntoRenderer, function() { + if (!rendererReleased) + sender.send('ATOM_RENDERER_RELEASE_CALLBACK', meta.id); }); - sender.callbacks.set(meta.id, ret); - return ret; + sender.callbacks.set(meta.id, callIntoRenderer); + return callIntoRenderer; default: throw new TypeError("Unknown type: " + meta.type); } From 60d44b3b045902aa66237af5730e94f09c91ae28 Mon Sep 17 00:00:00 2001 From: Cheng Zhao Date: Wed, 13 Jan 2016 17:12:47 +0800 Subject: [PATCH 88/95] spec: Remove annoying outputs from savePage test --- spec/api-browser-window-spec.js | 40 ++++++++++++++---------- spec/fixtures/pages/save_page/index.html | 2 +- spec/fixtures/pages/save_page/test.js | 2 +- 3 files changed, 26 insertions(+), 18 deletions(-) diff --git a/spec/api-browser-window-spec.js b/spec/api-browser-window-spec.js index 432c9a739cde..50a98ed38ce6 100644 --- a/spec/api-browser-window-spec.js +++ b/spec/api-browser-window-spec.js @@ -455,31 +455,39 @@ describe('browser-window module', function() { }); }); }); - describe('save page', function() { - var savePageCssPath, savePageDir, savePageHtmlPath, savePageJsPath; - savePageDir = path.join(fixtures, 'save_page'); - savePageHtmlPath = path.join(savePageDir, 'save_page.html'); - savePageJsPath = path.join(savePageDir, 'save_page_files', 'test.js'); - savePageCssPath = path.join(savePageDir, 'save_page_files', 'test.css'); - return it('should save page', function(done) { + + describe('savePage method', function() { + const savePageDir = path.join(fixtures, 'save_page'); + const savePageHtmlPath = path.join(savePageDir, 'save_page.html'); + const savePageJsPath = path.join(savePageDir, 'save_page_files', 'test.js'); + const savePageCssPath = path.join(savePageDir, 'save_page_files', 'test.css'); + + after(function() { + try { + fs.unlinkSync(savePageCssPath); + fs.unlinkSync(savePageJsPath); + fs.unlinkSync(savePageHtmlPath); + fs.rmdirSync(path.join(savePageDir, 'save_page_files')); + fs.rmdirSync(savePageDir); + } catch (e) { + } + }); + + it('should save page to disk', function(done) { w.webContents.on('did-finish-load', function() { - return w.webContents.savePage(savePageHtmlPath, 'HTMLComplete', function(error) { + w.webContents.savePage(savePageHtmlPath, 'HTMLComplete', function(error) { assert.equal(error, null); assert(fs.existsSync(savePageHtmlPath)); assert(fs.existsSync(savePageJsPath)); assert(fs.existsSync(savePageCssPath)); - fs.unlinkSync(savePageCssPath); - fs.unlinkSync(savePageJsPath); - fs.unlinkSync(savePageHtmlPath); - fs.rmdirSync(path.join(savePageDir, 'save_page_files')); - fs.rmdirSync(savePageDir); - return done(); + done(); }); }); - return w.loadURL("file://" + fixtures + "/pages/save_page/index.html"); + w.loadURL("file://" + fixtures + "/pages/save_page/index.html"); }); }); - return describe('BrowserWindow options argument is optional', function() { + + describe('BrowserWindow options argument is optional', function() { return it('should create a window with default size (800x600)', function() { var size; w.destroy(); diff --git a/spec/fixtures/pages/save_page/index.html b/spec/fixtures/pages/save_page/index.html index 829233bb86fb..61445bce23d1 100644 --- a/spec/fixtures/pages/save_page/index.html +++ b/spec/fixtures/pages/save_page/index.html @@ -1,6 +1,6 @@ - + diff --git a/spec/fixtures/pages/save_page/test.js b/spec/fixtures/pages/save_page/test.js index 3d79457383f5..c6035e5e3f33 100644 --- a/spec/fixtures/pages/save_page/test.js +++ b/spec/fixtures/pages/save_page/test.js @@ -1 +1 @@ -console.log('save_page'); +// do nothing From 63c646242a68e30dcfc38dfec714f7c146cf7e70 Mon Sep 17 00:00:00 2001 From: Cheng Zhao Date: Wed, 13 Jan 2016 17:19:53 +0800 Subject: [PATCH 89/95] spec: Group session.cookies tests --- spec/api-session-spec.js | 142 ++++++++++++++++++++------------------- 1 file changed, 73 insertions(+), 69 deletions(-) diff --git a/spec/api-session-spec.js b/spec/api-session-spec.js index 403e715cf5c6..4045d9e6fdac 100644 --- a/spec/api-session-spec.js +++ b/spec/api-session-spec.js @@ -28,80 +28,51 @@ describe('session module', function() { afterEach(function() { return w.destroy(); }); - it('should get cookies', function(done) { - var server; - server = http.createServer(function(req, res) { - res.setHeader('Set-Cookie', ['0=0']); - res.end('finished'); - return server.close(); - }); - return server.listen(0, '127.0.0.1', function() { - var port; - port = server.address().port; - w.loadURL(url + ":" + port); - return w.webContents.on('did-finish-load', function() { - return w.webContents.session.cookies.get({ - url: url - }, function(error, list) { - var cookie, i, len; - if (error) { - return done(error); - } - for (i = 0, len = list.length; i < len; i++) { - cookie = list[i]; - if (cookie.name === '0') { - if (cookie.value === '0') { - return done(); - } else { - return done("cookie value is " + cookie.value + " while expecting 0"); + + describe('session.cookies', function() { + it('should get cookies', function(done) { + var server; + server = http.createServer(function(req, res) { + res.setHeader('Set-Cookie', ['0=0']); + res.end('finished'); + return server.close(); + }); + return server.listen(0, '127.0.0.1', function() { + var port; + port = server.address().port; + w.loadURL(url + ":" + port); + return w.webContents.on('did-finish-load', function() { + return w.webContents.session.cookies.get({ + url: url + }, function(error, list) { + var cookie, i, len; + if (error) { + return done(error); + } + for (i = 0, len = list.length; i < len; i++) { + cookie = list[i]; + if (cookie.name === '0') { + if (cookie.value === '0') { + return done(); + } else { + return done("cookie value is " + cookie.value + " while expecting 0"); + } } } - } - return done('Can not find cookie'); + return done('Can not find cookie'); + }); }); }); }); - }); - it('should over-write the existent cookie', function(done) { - return session.defaultSession.cookies.set({ - url: url, - name: '1', - value: '1' - }, function(error) { - if (error) { - return done(error); - } - return session.defaultSession.cookies.get({ - url: url - }, function(error, list) { - var cookie, i, len; + it('should over-write the existent cookie', function(done) { + return session.defaultSession.cookies.set({ + url: url, + name: '1', + value: '1' + }, function(error) { if (error) { return done(error); } - for (i = 0, len = list.length; i < len; i++) { - cookie = list[i]; - if (cookie.name === '1') { - if (cookie.value === '1') { - return done(); - } else { - return done("cookie value is " + cookie.value + " while expecting 1"); - } - } - } - return done('Can not find cookie'); - }); - }); - }); - it('should remove cookies', function(done) { - return session.defaultSession.cookies.set({ - url: url, - name: '2', - value: '2' - }, function(error) { - if (error) { - return done(error); - } - return session.defaultSession.cookies.remove(url, '2', function() { return session.defaultSession.cookies.get({ url: url }, function(error, list) { @@ -111,15 +82,48 @@ describe('session module', function() { } for (i = 0, len = list.length; i < len; i++) { cookie = list[i]; - if (cookie.name === '2') { - return done('Cookie not deleted'); + if (cookie.name === '1') { + if (cookie.value === '1') { + return done(); + } else { + return done("cookie value is " + cookie.value + " while expecting 1"); + } } } - return done(); + return done('Can not find cookie'); + }); + }); + }); + it('should remove cookies', function(done) { + return session.defaultSession.cookies.set({ + url: url, + name: '2', + value: '2' + }, function(error) { + if (error) { + return done(error); + } + return session.defaultSession.cookies.remove(url, '2', function() { + return session.defaultSession.cookies.get({ + url: url + }, function(error, list) { + var cookie, i, len; + if (error) { + return done(error); + } + for (i = 0, len = list.length; i < len; i++) { + cookie = list[i]; + if (cookie.name === '2') { + return done('Cookie not deleted'); + } + } + return done(); + }); }); }); }); }); + describe('session.clearStorageData(options)', function() { fixtures = path.resolve(__dirname, 'fixtures'); return it('clears localstorage data', function(done) { From 9ccc7ee30d0d1adf606ca53f25a38c14a3247d0a Mon Sep 17 00:00:00 2001 From: Cheng Zhao Date: Wed, 13 Jan 2016 17:59:59 +0800 Subject: [PATCH 90/95] Small ajustments on lifetime of webContents --- atom/browser/api/atom_api_web_contents.cc | 29 ++++++++++++++++++----- 1 file changed, 23 insertions(+), 6 deletions(-) diff --git a/atom/browser/api/atom_api_web_contents.cc b/atom/browser/api/atom_api_web_contents.cc index 77e445efae35..0173abf4eef0 100644 --- a/atom/browser/api/atom_api_web_contents.cc +++ b/atom/browser/api/atom_api_web_contents.cc @@ -280,11 +280,18 @@ WebContents::WebContents(v8::Isolate* isolate, } WebContents::~WebContents() { - // The webview's lifetime is completely controlled by GuestViewManager, so - // it is always destroyed by calling webview.destroy(), we need to make - // sure the "destroyed" event is emitted manually. - if (type_ == WEB_VIEW && managed_web_contents()) + // The destroy() is called. + if (managed_web_contents()) { + // For webview we need to tell content module to do some cleanup work before + // destroying it. + if (type_ == WEB_VIEW) + guest_delegate_->Destroy(); + + // The WebContentsDestroyed will not be called automatically because we + // unsubscribe from webContents before destroying it. So we have to manually + // call it here to make sure "destroyed" event is emitted. WebContentsDestroyed(); + } } bool WebContents::AddMessageToConsole(content::WebContents* source, @@ -617,6 +624,18 @@ bool WebContents::OnMessageReceived(const IPC::Message& message) { return handled; } +// There are three ways of destroying a webContents: +// 1. call webContents.destory(); +// 2. garbage collection; +// 3. user closes the window of webContents; +// For webview only #1 will happen, for BrowserWindow both #1 and #3 may +// happen. The #2 should never happen for webContents, because webview is +// managed by GuestViewManager, and BrowserWindow's webContents is managed +// by api::Window. +// For #1, the destructor will do the cleanup work and we only need to make +// sure "destroyed" event is emitted. For #3, the content::WebContents will +// be destroyed on close, and WebContentsDestroyed would be called for it, so +// we need to make sure the api::WebContents is also deleted. void WebContents::WebContentsDestroyed() { // The RenderViewDeleted was not called when the WebContents is destroyed. RenderViewDeleted(web_contents()->GetRenderViewHost()); @@ -627,8 +646,6 @@ void WebContents::WebContentsDestroyed() { // Cleanup relationships with other parts. RemoveFromWeakMap(); - if (type_ == WEB_VIEW) - guest_delegate_->Destroy(); // 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. From 187cb54c25be635b2026c28d9500cfccf1c2cd2a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20H=C3=A4mmerle?= Date: Fri, 15 Jan 2016 13:43:44 +0100 Subject: [PATCH 91/95] spelling: bellow -> below --- docs/api/browser-window.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/api/browser-window.md b/docs/api/browser-window.md index 61180d5b89a9..97ec0b28a8cd 100644 --- a/docs/api/browser-window.md +++ b/docs/api/browser-window.md @@ -79,11 +79,11 @@ It creates a new `BrowserWindow` with native properties as set by the `options`. * `transparent` Boolean - Makes the window [transparent](frameless-window.md). Default is `false`. * `type` String - The type of window, default is normal window. See more about - this bellow. + this below. * `titleBarStyle` String - The style of window title bar. See more about this - bellow. + below. * `webPreferences` Object - Settings of web page's features. See more about - this bellow. + this below. The possible values and behaviors of `type` option are platform dependent, supported values are: From 7586078d0ac416245a063ff06219d3548cb3b1b5 Mon Sep 17 00:00:00 2001 From: Ivo Georgiev Date: Fri, 15 Jan 2016 16:54:29 +0200 Subject: [PATCH 92/95] Ensure we close FD on Windows --- atom/common/asar/archive.cc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/atom/common/asar/archive.cc b/atom/common/asar/archive.cc index ebb80cc2c485..b444377dd3a0 100644 --- a/atom/common/asar/archive.cc +++ b/atom/common/asar/archive.cc @@ -129,6 +129,9 @@ Archive::Archive(const base::FilePath& path) } Archive::~Archive() { +#if defined(OS_WIN) + _close(fd_) +#endif } bool Archive::Init() { From 4b0119f9962657aa170cee832b23cccdb46ca29f Mon Sep 17 00:00:00 2001 From: evgenyzinoviev Date: Fri, 15 Jan 2016 16:02:23 +0100 Subject: [PATCH 93/95] added a note that this option is only implemented on osx --- docs/api/browser-window.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/api/browser-window.md b/docs/api/browser-window.md index 211b23a5eb9e..422b3cfddeb2 100644 --- a/docs/api/browser-window.md +++ b/docs/api/browser-window.md @@ -47,7 +47,8 @@ It creates a new `BrowserWindow` with native properties as set by the `options`. * `maxWidth` Integer - Window's maximum width. Default is no limit. * `maxHeight` Integer - Window's maximum height. Default is no limit. * `resizable` Boolean - Whether window is resizable. Default is `true`. - * `movable` Boolean - Whether window is movable. Default is `true`. + * `movable` Boolean - Whether window is movable. This is only implemented + on OS X. Default is `true`. * `alwaysOnTop` Boolean - Whether the window should always stay on top of other windows. Default is `false`. * `fullscreen` Boolean - Whether the window should show in fullscreen. When From b119704ea963e5749a869226562e52a2cef761a4 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Fri, 15 Jan 2016 10:05:35 -0800 Subject: [PATCH 94/95] Use 2 space indent instead of 3 --- atom/common/asar/archive.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/atom/common/asar/archive.cc b/atom/common/asar/archive.cc index b444377dd3a0..05cedc75cfe0 100644 --- a/atom/common/asar/archive.cc +++ b/atom/common/asar/archive.cc @@ -130,7 +130,7 @@ Archive::Archive(const base::FilePath& path) Archive::~Archive() { #if defined(OS_WIN) - _close(fd_) + _close(fd_) #endif } From 741d1487765a9f22ae5379310b7de3ccd27b357c Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Fri, 15 Jan 2016 10:09:19 -0800 Subject: [PATCH 95/95] Add missing semicolon --- atom/common/asar/archive.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/atom/common/asar/archive.cc b/atom/common/asar/archive.cc index 05cedc75cfe0..1e986719ac6e 100644 --- a/atom/common/asar/archive.cc +++ b/atom/common/asar/archive.cc @@ -130,7 +130,7 @@ Archive::Archive(const base::FilePath& path) Archive::~Archive() { #if defined(OS_WIN) - _close(fd_) + _close(fd_); #endif }