diff --git a/atom/browser/api/atom_api_web_contents.cc b/atom/browser/api/atom_api_web_contents.cc index 4d449ed9c39b..77e445efae35 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 { @@ -290,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, @@ -625,7 +611,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() @@ -635,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. @@ -756,11 +749,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 +1081,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) @@ -1160,15 +1147,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 bd7149e38a93..bcef57b9a4aa 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(); @@ -265,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 0d1b8b24bdd0..f502076755f0 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,15 @@ PDFPageSize = { } }; +// Following methods are mapped to webFrame. +const webFrameMethods = [ + 'executeJavaScript', + 'insertText', + 'setZoomFactor', + 'setZoomLevel', + 'setZoomLevelLimits', +]; + wrapWebContents = function(webContents) { /* webContents is an EventEmitter. */ @@ -66,21 +77,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; @@ -95,6 +91,24 @@ 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); + }; + } + + // Make sure webContents.executeJavaScript would run the code only when the + // webContents has been loaded. + const executeJavaScript = webContents.executeJavaScript; + webContents.executeJavaScript = function(code, hasUserGesture) { + 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/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); diff --git a/atom/common/api/api_messages.h b/atom/common/api/api_messages.h index 274e1f533eb3..eeb26614847b 100644 --- a/atom/common/api/api_messages.h +++ b/atom/common/api/api_messages.h @@ -30,20 +30,10 @@ 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 */) -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 83d67a8b6635..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" @@ -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" @@ -36,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 { @@ -116,6 +116,19 @@ void WebFrame::RegisterURLSchemeAsPrivileged(const std::string& scheme) { privileged_scheme); } +void WebFrame::InsertText(const std::string& text) { + web_frame_->insertText(blink::WebString::fromUTF8(text)); +} + +void WebFrame::ExecuteJavaScript(const base::string16& code, + mate::Arguments* args) { + bool has_user_gesture = false; + args->GetNext(&has_user_gesture); + scoped_ptr gesture( + has_user_gesture ? new blink::WebScopedUserGesture : nullptr); + web_frame_->executeScriptAndReturnValue(blink::WebScriptSource(code)); +} + mate::ObjectTemplateBuilder WebFrame::GetObjectTemplateBuilder( v8::Isolate* isolate) { return mate::ObjectTemplateBuilder(isolate) @@ -136,7 +149,9 @@ mate::ObjectTemplateBuilder WebFrame::GetObjectTemplateBuilder( .SetMethod("registerURLSchemeAsBypassingCSP", &WebFrame::RegisterURLSchemeAsBypassingCSP) .SetMethod("registerURLSchemeAsPrivileged", - &WebFrame::RegisterURLSchemeAsPrivileged); + &WebFrame::RegisterURLSchemeAsPrivileged) + .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 95a5a82a313d..d55b24fd25ea 100644 --- a/atom/renderer/api/atom_api_web_frame.h +++ b/atom/renderer/api/atom_api_web_frame.h @@ -60,6 +60,12 @@ class WebFrame : public mate::Wrappable { void RegisterURLSchemeAsBypassingCSP(const std::string& scheme); void RegisterURLSchemeAsPrivileged(const std::string& scheme); + // Editing. + void InsertText(const std::string& text); + + // Excecuting scripts. + void ExecuteJavaScript(const base::string16& code, mate::Arguments* args); + // mate::Wrappable: virtual mate::ObjectTemplateBuilder GetObjectTemplateBuilder( v8::Isolate* isolate); 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_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_; 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/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..cb0a5ddf118c 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,12 @@ WebViewImpl = (function() { this.setupFocusPropagation(); this.viewInstanceId = getNextId(); shadowRoot.appendChild(this.browserPluginNode); + + // Subscribe to host's zoom level changes. + this.onZoomLevelChanged = (zoomLevel) => { + this.webviewNode.setZoomLevel(zoomLevel); + } + webFrame.on('zoom-level-changed', this.onZoomLevelChanged); } WebViewImpl.prototype.createBrowserPluginNode = function() { @@ -57,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 @@ -376,7 +386,16 @@ 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', + 'setZoomFactor', + 'setZoomLevel', + 'setZoomLevelLimits', + ]; /* 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 114afd041cd0..d9e02ac097e7 100644 --- a/docs/api/web-frame.md +++ b/docs/api/web-frame.md @@ -90,4 +90,21 @@ 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. + +### `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 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.