Merge pull request #750 from atom/fix-leaking-webcontents
Handle window.open and <a target="..."> correctly
This commit is contained in:
commit
41b6f682d8
24 changed files with 275 additions and 94 deletions
1
atom.gyp
1
atom.gyp
|
@ -30,6 +30,7 @@
|
||||||
'atom/browser/api/lib/web-contents.coffee',
|
'atom/browser/api/lib/web-contents.coffee',
|
||||||
'atom/browser/lib/chrome-extension.coffee',
|
'atom/browser/lib/chrome-extension.coffee',
|
||||||
'atom/browser/lib/guest-view-manager.coffee',
|
'atom/browser/lib/guest-view-manager.coffee',
|
||||||
|
'atom/browser/lib/guest-window-manager.coffee',
|
||||||
'atom/browser/lib/init.coffee',
|
'atom/browser/lib/init.coffee',
|
||||||
'atom/browser/lib/objects-registry.coffee',
|
'atom/browser/lib/objects-registry.coffee',
|
||||||
'atom/browser/lib/rpc-server.coffee',
|
'atom/browser/lib/rpc-server.coffee',
|
||||||
|
|
|
@ -88,7 +88,7 @@ bool WebContents::ShouldCreateWebContents(
|
||||||
content::SessionStorageNamespace* session_storage_namespace) {
|
content::SessionStorageNamespace* session_storage_namespace) {
|
||||||
base::ListValue args;
|
base::ListValue args;
|
||||||
args.AppendString(target_url.spec());
|
args.AppendString(target_url.spec());
|
||||||
args.AppendString(partition_id);
|
args.AppendString(frame_name);
|
||||||
Emit("new-window", args);
|
Emit("new-window", args);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -441,6 +441,7 @@ mate::ObjectTemplateBuilder WebContents::GetObjectTemplateBuilder(
|
||||||
.SetMethod("_send", &WebContents::SendIPCMessage)
|
.SetMethod("_send", &WebContents::SendIPCMessage)
|
||||||
.SetMethod("setAutoSize", &WebContents::SetAutoSize)
|
.SetMethod("setAutoSize", &WebContents::SetAutoSize)
|
||||||
.SetMethod("setAllowTransparency", &WebContents::SetAllowTransparency)
|
.SetMethod("setAllowTransparency", &WebContents::SetAllowTransparency)
|
||||||
|
.SetMethod("isGuest", &WebContents::is_guest)
|
||||||
.Build());
|
.Build());
|
||||||
|
|
||||||
return mate::ObjectTemplateBuilder(
|
return mate::ObjectTemplateBuilder(
|
||||||
|
|
|
@ -82,6 +82,15 @@ void Window::OnPageTitleUpdated(bool* prevent_default,
|
||||||
*prevent_default = Emit("page-title-updated", args);
|
*prevent_default = Emit("page-title-updated", args);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Window::WillCreatePopupWindow(const base::string16& frame_name,
|
||||||
|
const GURL& target_url,
|
||||||
|
const std::string& partition_id) {
|
||||||
|
base::ListValue args;
|
||||||
|
args.AppendString(target_url.spec());
|
||||||
|
args.AppendString(frame_name);
|
||||||
|
Emit("new-window", args);
|
||||||
|
}
|
||||||
|
|
||||||
void Window::WillCloseWindow(bool* prevent_default) {
|
void Window::WillCloseWindow(bool* prevent_default) {
|
||||||
*prevent_default = Emit("close");
|
*prevent_default = Emit("close");
|
||||||
}
|
}
|
||||||
|
@ -122,6 +131,10 @@ void Window::Close() {
|
||||||
window_->Close();
|
window_->Close();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Window::IsClosed() {
|
||||||
|
return window_->IsClosed();
|
||||||
|
}
|
||||||
|
|
||||||
void Window::Focus() {
|
void Window::Focus() {
|
||||||
window_->Focus(true);
|
window_->Focus(true);
|
||||||
}
|
}
|
||||||
|
@ -370,6 +383,7 @@ void Window::BuildPrototype(v8::Isolate* isolate,
|
||||||
mate::ObjectTemplateBuilder(isolate, prototype)
|
mate::ObjectTemplateBuilder(isolate, prototype)
|
||||||
.SetMethod("destroy", &Window::Destroy)
|
.SetMethod("destroy", &Window::Destroy)
|
||||||
.SetMethod("close", &Window::Close)
|
.SetMethod("close", &Window::Close)
|
||||||
|
.SetMethod("isClosed", &Window::IsClosed)
|
||||||
.SetMethod("focus", &Window::Focus)
|
.SetMethod("focus", &Window::Focus)
|
||||||
.SetMethod("isFocused", &Window::IsFocused)
|
.SetMethod("isFocused", &Window::IsFocused)
|
||||||
.SetMethod("show", &Window::Show)
|
.SetMethod("show", &Window::Show)
|
||||||
|
|
|
@ -43,19 +43,23 @@ class Window : public mate::EventEmitter,
|
||||||
virtual ~Window();
|
virtual ~Window();
|
||||||
|
|
||||||
// Implementations of NativeWindowObserver:
|
// Implementations of NativeWindowObserver:
|
||||||
virtual void OnPageTitleUpdated(bool* prevent_default,
|
void OnPageTitleUpdated(bool* prevent_default,
|
||||||
const std::string& title) OVERRIDE;
|
const std::string& title) override;
|
||||||
virtual void WillCloseWindow(bool* prevent_default) OVERRIDE;
|
void WillCreatePopupWindow(const base::string16& frame_name,
|
||||||
virtual void OnWindowClosed() OVERRIDE;
|
const GURL& target_url,
|
||||||
virtual void OnWindowBlur() OVERRIDE;
|
const std::string& partition_id) override;
|
||||||
virtual void OnWindowFocus() OVERRIDE;
|
void WillCloseWindow(bool* prevent_default) override;
|
||||||
virtual void OnRendererUnresponsive() OVERRIDE;
|
void OnWindowClosed() override;
|
||||||
virtual void OnRendererResponsive() OVERRIDE;
|
void OnWindowBlur() override;
|
||||||
|
void OnWindowFocus() override;
|
||||||
|
void OnRendererUnresponsive() override;
|
||||||
|
void OnRendererResponsive() override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// APIs for NativeWindow.
|
// APIs for NativeWindow.
|
||||||
void Destroy();
|
void Destroy();
|
||||||
void Close();
|
void Close();
|
||||||
|
bool IsClosed();
|
||||||
void Focus();
|
void Focus();
|
||||||
bool IsFocused();
|
bool IsFocused();
|
||||||
void Show();
|
void Show();
|
||||||
|
|
|
@ -19,8 +19,7 @@ v8::Persistent<v8::ObjectTemplate> template_;
|
||||||
|
|
||||||
Event::Event()
|
Event::Event()
|
||||||
: sender_(NULL),
|
: sender_(NULL),
|
||||||
message_(NULL),
|
message_(NULL) {
|
||||||
prevent_default_(false) {
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Event::~Event() {
|
Event::~Event() {
|
||||||
|
@ -52,8 +51,9 @@ void Event::WebContentsDestroyed() {
|
||||||
message_ = NULL;
|
message_ = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Event::PreventDefault() {
|
void Event::PreventDefault(v8::Isolate* isolate) {
|
||||||
prevent_default_ = true;
|
GetWrapper(isolate)->Set(StringToV8(isolate, "defaultPrevented"),
|
||||||
|
v8::True(isolate));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Event::SendReply(const base::string16& json) {
|
bool Event::SendReply(const base::string16& json) {
|
||||||
|
|
|
@ -24,14 +24,11 @@ class Event : public Wrappable,
|
||||||
void SetSenderAndMessage(content::WebContents* sender, IPC::Message* message);
|
void SetSenderAndMessage(content::WebContents* sender, IPC::Message* message);
|
||||||
|
|
||||||
// event.PreventDefault().
|
// event.PreventDefault().
|
||||||
void PreventDefault();
|
void PreventDefault(v8::Isolate* isolate);
|
||||||
|
|
||||||
// event.sendReply(json), used for replying synchronous message.
|
// event.sendReply(json), used for replying synchronous message.
|
||||||
bool SendReply(const base::string16& json);
|
bool SendReply(const base::string16& json);
|
||||||
|
|
||||||
// Whether event.preventDefault() is called.
|
|
||||||
bool prevent_default() const { return prevent_default_; }
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
Event();
|
Event();
|
||||||
virtual ~Event();
|
virtual ~Event();
|
||||||
|
@ -47,8 +44,6 @@ class Event : public Wrappable,
|
||||||
content::WebContents* sender_;
|
content::WebContents* sender_;
|
||||||
IPC::Message* message_;
|
IPC::Message* message_;
|
||||||
|
|
||||||
bool prevent_default_;
|
|
||||||
|
|
||||||
DISALLOW_COPY_AND_ASSIGN(Event);
|
DISALLOW_COPY_AND_ASSIGN(Event);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -98,17 +98,7 @@ bool EventEmitter::Emit(v8::Isolate* isolate,
|
||||||
node::MakeCallback(isolate, GetWrapper(isolate), "emit", args.size(),
|
node::MakeCallback(isolate, GetWrapper(isolate), "emit", args.size(),
|
||||||
&args[0]);
|
&args[0]);
|
||||||
|
|
||||||
if (use_native_event) {
|
return event->Get(StringToV8(isolate, "defaultPrevented"))->BooleanValue();
|
||||||
Handle<Event> native_event;
|
|
||||||
if (ConvertFromV8(isolate, event, &native_event))
|
|
||||||
return native_event->prevent_default();
|
|
||||||
}
|
|
||||||
|
|
||||||
v8::Handle<v8::Value> prevent_default =
|
|
||||||
event->GetHiddenValue(StringToSymbol(isolate, "prevent_default"));
|
|
||||||
if (prevent_default.IsEmpty())
|
|
||||||
return false;
|
|
||||||
return prevent_default->BooleanValue();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace mate
|
} // namespace mate
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
EventEmitter = require('events').EventEmitter
|
EventEmitter = require('events').EventEmitter
|
||||||
IDWeakMap = require 'id-weak-map'
|
IDWeakMap = require 'id-weak-map'
|
||||||
app = require 'app'
|
app = require 'app'
|
||||||
|
ipc = require 'ipc'
|
||||||
wrapWebContents = require('web-contents').wrap
|
wrapWebContents = require('web-contents').wrap
|
||||||
|
|
||||||
BrowserWindow = process.atomBinding('window').BrowserWindow
|
BrowserWindow = process.atomBinding('window').BrowserWindow
|
||||||
|
@ -23,6 +24,12 @@ BrowserWindow::_init = ->
|
||||||
value: BrowserWindow.windows.add(this)
|
value: BrowserWindow.windows.add(this)
|
||||||
enumerable: true
|
enumerable: true
|
||||||
|
|
||||||
|
# Make new windows requested by links behave like "window.open"
|
||||||
|
@on 'new-window', (event, url, frameName) =>
|
||||||
|
event.sender = @webContents
|
||||||
|
options = show: true, width: 800, height: 600
|
||||||
|
ipc.emit 'ATOM_SHELL_GUEST_WINDOW_MANAGER_WINDOW_OPEN', event, url, frameName, options
|
||||||
|
|
||||||
# Remove the window from weak map immediately when it's destroyed, since we
|
# Remove the window from weak map immediately when it's destroyed, since we
|
||||||
# could be iterating windows before GC happened.
|
# could be iterating windows before GC happened.
|
||||||
@once 'closed', =>
|
@once 'closed', =>
|
||||||
|
|
53
atom/browser/lib/guest-window-manager.coffee
Normal file
53
atom/browser/lib/guest-window-manager.coffee
Normal file
|
@ -0,0 +1,53 @@
|
||||||
|
ipc = require 'ipc'
|
||||||
|
BrowserWindow = require 'browser-window'
|
||||||
|
|
||||||
|
frameToGuest = {}
|
||||||
|
|
||||||
|
# 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
|
||||||
|
|
||||||
|
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.
|
||||||
|
closedByEmbedder = ->
|
||||||
|
guest.removeListener 'closed', closedByUser
|
||||||
|
guest.destroy() unless guest.isClosed()
|
||||||
|
closedByUser = ->
|
||||||
|
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.
|
||||||
|
ipc.on 'ATOM_SHELL_GUEST_WINDOW_MANAGER_WINDOW_OPEN', (event, args...) ->
|
||||||
|
event.sender.emit 'new-window', event, args...
|
||||||
|
if event.sender.isGuest() or event.defaultPrevented
|
||||||
|
event.returnValue = null
|
||||||
|
else
|
||||||
|
event.returnValue = createGuest event.sender, args...
|
||||||
|
|
||||||
|
ipc.on 'ATOM_SHELL_GUEST_WINDOW_MANAGER_WINDOW_CLOSE', (event, guestId) ->
|
||||||
|
return unless BrowserWindow.windows.has guestId
|
||||||
|
BrowserWindow.windows.get(guestId).destroy()
|
||||||
|
|
||||||
|
ipc.on 'ATOM_SHELL_GUEST_WINDOW_MANAGER_WINDOW_METHOD', (event, guestId, method, args...) ->
|
||||||
|
return unless BrowserWindow.windows.has guestId
|
||||||
|
BrowserWindow.windows.get(guestId)[method] args...
|
||||||
|
|
||||||
|
ipc.on 'ATOM_SHELL_GUEST_WINDOW_MANAGER_WEB_CONTENTS_METHOD', (event, guestId, method, args...) ->
|
||||||
|
return unless BrowserWindow.windows.has guestId
|
||||||
|
BrowserWindow.windows.get(guestId).webContents?[method] args...
|
|
@ -58,10 +58,11 @@ process.once 'BIND_DONE', ->
|
||||||
process.emit 'exit'
|
process.emit 'exit'
|
||||||
|
|
||||||
# Load the RPC server.
|
# Load the RPC server.
|
||||||
require './rpc-server.js'
|
require './rpc-server'
|
||||||
|
|
||||||
# Load the guest view manager.
|
# Load the guest view manager.
|
||||||
require './guest-view-manager.js'
|
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
|
packageJson = null
|
||||||
|
|
|
@ -423,6 +423,22 @@ void NativeWindow::NotifyWindowFocus() {
|
||||||
FOR_EACH_OBSERVER(NativeWindowObserver, observers_, OnWindowFocus());
|
FOR_EACH_OBSERVER(NativeWindowObserver, observers_, OnWindowFocus());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool NativeWindow::ShouldCreateWebContents(
|
||||||
|
content::WebContents* web_contents,
|
||||||
|
int route_id,
|
||||||
|
WindowContainerType window_container_type,
|
||||||
|
const base::string16& frame_name,
|
||||||
|
const GURL& target_url,
|
||||||
|
const std::string& partition_id,
|
||||||
|
content::SessionStorageNamespace* session_storage_namespace) {
|
||||||
|
FOR_EACH_OBSERVER(NativeWindowObserver,
|
||||||
|
observers_,
|
||||||
|
WillCreatePopupWindow(frame_name,
|
||||||
|
target_url,
|
||||||
|
partition_id));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
// In atom-shell all reloads and navigations started by renderer process would
|
// In atom-shell all reloads and navigations started by renderer process would
|
||||||
// be redirected to this method, so we can have precise control of how we
|
// be redirected to this method, so we can have precise control of how we
|
||||||
// would open the url (in our case, is to restart the renderer process). See
|
// would open the url (in our case, is to restart the renderer process). See
|
||||||
|
|
|
@ -214,43 +214,50 @@ class NativeWindow : public brightray::DefaultWebContentsDelegate,
|
||||||
const std::vector<DraggableRegion>& regions) = 0;
|
const std::vector<DraggableRegion>& regions) = 0;
|
||||||
|
|
||||||
// Implementations of content::WebContentsDelegate.
|
// Implementations of content::WebContentsDelegate.
|
||||||
virtual content::WebContents* OpenURLFromTab(
|
bool ShouldCreateWebContents(
|
||||||
|
content::WebContents* web_contents,
|
||||||
|
int route_id,
|
||||||
|
WindowContainerType window_container_type,
|
||||||
|
const base::string16& frame_name,
|
||||||
|
const GURL& target_url,
|
||||||
|
const std::string& partition_id,
|
||||||
|
content::SessionStorageNamespace* session_storage_namespace) override;
|
||||||
|
content::WebContents* OpenURLFromTab(
|
||||||
content::WebContents* source,
|
content::WebContents* source,
|
||||||
const content::OpenURLParams& params) OVERRIDE;
|
const content::OpenURLParams& params) override;
|
||||||
virtual content::JavaScriptDialogManager*
|
content::JavaScriptDialogManager* GetJavaScriptDialogManager() override;
|
||||||
GetJavaScriptDialogManager() OVERRIDE;
|
void BeforeUnloadFired(content::WebContents* tab,
|
||||||
virtual void BeforeUnloadFired(content::WebContents* tab,
|
bool proceed,
|
||||||
bool proceed,
|
bool* proceed_to_fire_unload) override;
|
||||||
bool* proceed_to_fire_unload) OVERRIDE;
|
void RequestToLockMouse(content::WebContents* web_contents,
|
||||||
virtual void RequestToLockMouse(content::WebContents* web_contents,
|
bool user_gesture,
|
||||||
bool user_gesture,
|
bool last_unlocked_by_target) override;
|
||||||
bool last_unlocked_by_target) OVERRIDE;
|
bool CanOverscrollContent() const override;
|
||||||
virtual bool CanOverscrollContent() const OVERRIDE;
|
void ActivateContents(content::WebContents* contents) override;
|
||||||
virtual void ActivateContents(content::WebContents* contents) OVERRIDE;
|
void DeactivateContents(content::WebContents* contents) override;
|
||||||
virtual void DeactivateContents(content::WebContents* contents) OVERRIDE;
|
void MoveContents(content::WebContents* source,
|
||||||
virtual void MoveContents(content::WebContents* source,
|
const gfx::Rect& pos) override;
|
||||||
const gfx::Rect& pos) OVERRIDE;
|
void CloseContents(content::WebContents* source) override;
|
||||||
virtual void CloseContents(content::WebContents* source) OVERRIDE;
|
bool IsPopupOrPanel(
|
||||||
virtual bool IsPopupOrPanel(
|
const content::WebContents* source) const override;
|
||||||
const content::WebContents* source) const OVERRIDE;
|
void RendererUnresponsive(content::WebContents* source) override;
|
||||||
virtual void RendererUnresponsive(content::WebContents* source) OVERRIDE;
|
void RendererResponsive(content::WebContents* source) override;
|
||||||
virtual void RendererResponsive(content::WebContents* source) OVERRIDE;
|
|
||||||
|
|
||||||
// Implementations of content::WebContentsObserver.
|
// Implementations of content::WebContentsObserver.
|
||||||
virtual void BeforeUnloadFired(const base::TimeTicks& proceed_time) OVERRIDE;
|
void BeforeUnloadFired(const base::TimeTicks& proceed_time) override;
|
||||||
virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE;
|
bool OnMessageReceived(const IPC::Message& message) override;
|
||||||
|
|
||||||
// Implementations of content::NotificationObserver.
|
// Implementations of content::NotificationObserver.
|
||||||
virtual void Observe(int type,
|
void Observe(int type,
|
||||||
const content::NotificationSource& source,
|
const content::NotificationSource& source,
|
||||||
const content::NotificationDetails& details) OVERRIDE;
|
const content::NotificationDetails& details) override;
|
||||||
|
|
||||||
// Implementations of brightray::InspectableWebContentsDelegate.
|
// Implementations of brightray::InspectableWebContentsDelegate.
|
||||||
virtual void DevToolsSaveToFile(const std::string& url,
|
void DevToolsSaveToFile(const std::string& url,
|
||||||
const std::string& content,
|
const std::string& content,
|
||||||
bool save_as) OVERRIDE;
|
bool save_as) override;
|
||||||
virtual void DevToolsAppendToFile(const std::string& url,
|
void DevToolsAppendToFile(const std::string& url,
|
||||||
const std::string& content) OVERRIDE;
|
const std::string& content) override;
|
||||||
|
|
||||||
// Whether window has standard frame.
|
// Whether window has standard frame.
|
||||||
bool has_frame_;
|
bool has_frame_;
|
||||||
|
|
|
@ -7,6 +7,9 @@
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
|
#include "base/strings/string16.h"
|
||||||
|
#include "url/gurl.h"
|
||||||
|
|
||||||
namespace atom {
|
namespace atom {
|
||||||
|
|
||||||
class NativeWindowObserver {
|
class NativeWindowObserver {
|
||||||
|
@ -17,6 +20,11 @@ class NativeWindowObserver {
|
||||||
virtual void OnPageTitleUpdated(bool* prevent_default,
|
virtual void OnPageTitleUpdated(bool* prevent_default,
|
||||||
const std::string& title) {}
|
const std::string& title) {}
|
||||||
|
|
||||||
|
// Called when the web page in window wants to create a popup window.
|
||||||
|
virtual void WillCreatePopupWindow(const base::string16& frame_name,
|
||||||
|
const GURL& target_url,
|
||||||
|
const std::string& partition_id) {}
|
||||||
|
|
||||||
// Called when the window is gonna closed.
|
// Called when the window is gonna closed.
|
||||||
virtual void WillCloseWindow(bool* prevent_default) {}
|
virtual void WillCloseWindow(bool* prevent_default) {}
|
||||||
|
|
||||||
|
|
|
@ -10,7 +10,7 @@ WEB_VIEW_EVENTS =
|
||||||
'did-stop-loading': []
|
'did-stop-loading': []
|
||||||
'did-get-redirect-request': ['oldUrl', 'newUrl', 'isMainFrame']
|
'did-get-redirect-request': ['oldUrl', 'newUrl', 'isMainFrame']
|
||||||
'console-message': ['level', 'message', 'line', 'sourceId']
|
'console-message': ['level', 'message', 'line', 'sourceId']
|
||||||
'new-window': ['url', 'partitionId']
|
'new-window': ['url', 'frameName']
|
||||||
'close': []
|
'close': []
|
||||||
'crashed': []
|
'crashed': []
|
||||||
'destroyed': []
|
'destroyed': []
|
||||||
|
|
|
@ -1,34 +1,48 @@
|
||||||
process = global.process
|
process = global.process
|
||||||
|
ipc = require 'ipc'
|
||||||
remote = require 'remote'
|
remote = require 'remote'
|
||||||
|
|
||||||
|
# Window object returned by "window.open".
|
||||||
|
class FakeWindow
|
||||||
|
constructor: (@guestId) ->
|
||||||
|
|
||||||
|
close: ->
|
||||||
|
ipc.send 'ATOM_SHELL_GUEST_WINDOW_MANAGER_WINDOW_CLOSE', @guestId
|
||||||
|
|
||||||
|
focus: ->
|
||||||
|
ipc.send 'ATOM_SHELL_GUEST_WINDOW_MANAGER_WINDOW_METHOD', @guestId, 'focus'
|
||||||
|
|
||||||
|
blur: ->
|
||||||
|
ipc.send 'ATOM_SHELL_GUEST_WINDOW_MANAGER_WINDOW_METHOD', @guestId, 'blur'
|
||||||
|
|
||||||
|
eval: (args...) ->
|
||||||
|
ipc.send 'ATOM_SHELL_GUEST_WINDOW_MANAGER_WEB_CONTENTS_METHOD', @guestId, 'executeJavaScript', args...
|
||||||
|
|
||||||
unless process.guestInstanceId?
|
unless process.guestInstanceId?
|
||||||
# Override default window.close, see:
|
# Override default window.close.
|
||||||
window.close = ->
|
window.close = ->
|
||||||
remote.getCurrentWindow().close()
|
remote.getCurrentWindow().close()
|
||||||
|
|
||||||
# Override default window.open.
|
# Make the browser window or guest view emit "new-window" event.
|
||||||
window.open = (url, name, features) ->
|
window.open = (url, frameName='', features='') ->
|
||||||
options = {}
|
options = {}
|
||||||
for feature in features.split ','
|
for feature in features.split ','
|
||||||
[name, value] = feature.split '='
|
[name, value] = feature.split '='
|
||||||
options[name] =
|
options[name] =
|
||||||
if value is 'yes'
|
if value is 'yes'
|
||||||
true
|
true
|
||||||
else if value is 'no'
|
else if value is 'no'
|
||||||
false
|
false
|
||||||
else
|
else
|
||||||
value
|
value
|
||||||
|
options.x ?= options.left
|
||||||
|
options.y ?= options.top
|
||||||
|
options.title ?= name
|
||||||
|
options.width ?= 800
|
||||||
|
options.height ?= 600
|
||||||
|
|
||||||
options.x ?= options.left
|
guestId = ipc.sendSync 'ATOM_SHELL_GUEST_WINDOW_MANAGER_WINDOW_OPEN', url, frameName, options
|
||||||
options.y ?= options.top
|
new FakeWindow(guestId)
|
||||||
options.title ?= name
|
|
||||||
options.width ?= 800
|
|
||||||
options.height ?= 600
|
|
||||||
|
|
||||||
BrowserWindow = require('remote').require 'browser-window'
|
|
||||||
browser = new BrowserWindow options
|
|
||||||
browser.loadUrl url
|
|
||||||
browser
|
|
||||||
|
|
||||||
# Use the dialog API to implement alert().
|
# Use the dialog API to implement alert().
|
||||||
window.alert = (message, title='') ->
|
window.alert = (message, title='') ->
|
||||||
|
|
|
@ -546,6 +546,21 @@ Corresponds to the points in time when the spinner of the tab stops spinning.
|
||||||
|
|
||||||
Emitted when a redirect was received while requesting a resource.
|
Emitted when a redirect was received while requesting a resource.
|
||||||
|
|
||||||
|
### Event: 'new-window'
|
||||||
|
|
||||||
|
* `event` Event
|
||||||
|
* `url` String
|
||||||
|
* `frameName` String
|
||||||
|
* `options` Object
|
||||||
|
|
||||||
|
Emitted when the page requested to open a new window for `url`. It could be
|
||||||
|
requested by `window.open` or a external link like `<a target='_blank'>`.
|
||||||
|
|
||||||
|
By default a new `BrowserWindow` will be created for `url` called, and a proxy
|
||||||
|
will be returned to `window.open` to let you have limited control of it.
|
||||||
|
|
||||||
|
Calling `event.preventDefault()` can prevent creating new windows.
|
||||||
|
|
||||||
### Event: 'crashed'
|
### Event: 'crashed'
|
||||||
|
|
||||||
Emitted when the renderer process is crashed.
|
Emitted when the renderer process is crashed.
|
||||||
|
|
|
@ -237,7 +237,7 @@ webview.addEventListener('console-message', function(e) {
|
||||||
### new-window
|
### new-window
|
||||||
|
|
||||||
* `url` String
|
* `url` String
|
||||||
* `partitionId` String
|
* `frameName` String
|
||||||
|
|
||||||
Fired when the guest page attempts to open a new browser window.
|
Fired when the guest page attempts to open a new browser window.
|
||||||
|
|
||||||
|
|
|
@ -156,3 +156,20 @@ describe 'browser-window module', ->
|
||||||
w.on 'onbeforeunload', ->
|
w.on 'onbeforeunload', ->
|
||||||
done()
|
done()
|
||||||
w.loadUrl 'file://' + path.join(fixtures, 'api', 'close-beforeunload-empty-string.html')
|
w.loadUrl 'file://' + path.join(fixtures, 'api', 'close-beforeunload-empty-string.html')
|
||||||
|
|
||||||
|
describe 'new-window event', ->
|
||||||
|
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) ->
|
||||||
|
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"
|
||||||
|
|
|
@ -32,10 +32,10 @@ describe 'chromium feature', ->
|
||||||
assert.notEqual navigator.language, ''
|
assert.notEqual navigator.language, ''
|
||||||
|
|
||||||
describe 'window.open', ->
|
describe 'window.open', ->
|
||||||
it 'returns a BrowserWindow object', ->
|
it 'returns a FakeWindow object', ->
|
||||||
b = window.open 'about:blank', 'test', 'show=no'
|
b = window.open 'about:blank', 'test', 'show=no'
|
||||||
assert.equal b.constructor.name, 'BrowserWindow'
|
assert.equal b.constructor.name, 'FakeWindow'
|
||||||
b.destroy()
|
b.close()
|
||||||
|
|
||||||
describe 'creating a Uint8Array under browser side', ->
|
describe 'creating a Uint8Array under browser side', ->
|
||||||
it 'does not crash', ->
|
it 'does not crash', ->
|
||||||
|
|
13
spec/fixtures/pages/target-name.html
vendored
Normal file
13
spec/fixtures/pages/target-name.html
vendored
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
<html>
|
||||||
|
<body>
|
||||||
|
<a id="a", href="http://host" target="target">link</a>
|
||||||
|
<script type="text/javascript" charset="utf-8">
|
||||||
|
var event = new MouseEvent('click', {
|
||||||
|
'view': window,
|
||||||
|
'bubbles': true,
|
||||||
|
'cancelable': true
|
||||||
|
});
|
||||||
|
document.getElementById('a').dispatchEvent(event);
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
7
spec/fixtures/pages/window-open.html
vendored
Normal file
7
spec/fixtures/pages/window-open.html
vendored
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
<html>
|
||||||
|
<body>
|
||||||
|
<script type="text/javascript" charset="utf-8">
|
||||||
|
window.open('http://host', 'host');
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -96,13 +96,14 @@ describe 'node feature', ->
|
||||||
setImmediate done
|
setImmediate done
|
||||||
|
|
||||||
describe 'net.connect', ->
|
describe 'net.connect', ->
|
||||||
it 'emit error when connect to a socket path without listeners', (done) ->
|
return unless process.platform is 'darwin'
|
||||||
return done() if process.platform is 'win32'
|
|
||||||
|
|
||||||
|
it 'emit error when connect to a socket path without listeners', (done) ->
|
||||||
socketPath = path.join os.tmpdir(), 'atom-shell-test.sock'
|
socketPath = path.join os.tmpdir(), 'atom-shell-test.sock'
|
||||||
script = path.join(fixtures, 'module', 'create_socket.js')
|
script = path.join(fixtures, 'module', 'create_socket.js')
|
||||||
child = child_process.fork script, [socketPath]
|
child = child_process.fork script, [socketPath]
|
||||||
child.on 'exit', ->
|
child.on 'exit', (code) ->
|
||||||
|
assert.equal code, 0
|
||||||
client = require('net').connect socketPath
|
client = require('net').connect socketPath
|
||||||
client.on 'error', (error) ->
|
client.on 'error', (error) ->
|
||||||
assert.equal error.code, 'ECONNREFUSED'
|
assert.equal error.code, 'ECONNREFUSED'
|
||||||
|
|
|
@ -46,3 +46,20 @@ describe '<webview> tag', ->
|
||||||
webview.setAttribute 'nodeintegration', 'on'
|
webview.setAttribute 'nodeintegration', 'on'
|
||||||
webview.src = "file://#{fixtures}/pages/d.html"
|
webview.src = "file://#{fixtures}/pages/d.html"
|
||||||
document.body.appendChild webview
|
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
|
||||||
|
|
2
vendor/brightray
vendored
2
vendor/brightray
vendored
|
@ -1 +1 @@
|
||||||
Subproject commit 319c63da618f5fdff38f6a65c452f3802b8756d1
|
Subproject commit ba89e08f8dcec06a65068c6c959431e7914fc00d
|
Loading…
Reference in a new issue