Merge pull request #6035 from electron/content-scripts-in-web-views

Load content scripts in webview devtools
This commit is contained in:
Cheng Zhao 2016-06-15 07:26:27 +00:00 committed by GitHub
commit efa667fa0a
6 changed files with 73 additions and 41 deletions

View file

@ -4,9 +4,8 @@
#include "atom/browser/api/atom_api_render_process_preferences.h" #include "atom/browser/api/atom_api_render_process_preferences.h"
#include "atom/browser/api/atom_api_web_contents.h"
#include "atom/browser/atom_browser_client.h" #include "atom/browser/atom_browser_client.h"
#include "atom/browser/native_window.h"
#include "atom/browser/window_list.h"
#include "atom/common/native_mate_converters/value_converter.h" #include "atom/common/native_mate_converters/value_converter.h"
#include "atom/common/node_includes.h" #include "atom/common/node_includes.h"
#include "content/public/browser/render_process_host.h" #include "content/public/browser/render_process_host.h"
@ -19,18 +18,17 @@ namespace api {
namespace { namespace {
bool IsBrowserWindow(content::RenderProcessHost* process) { bool IsWebContents(v8::Isolate* isolate, content::RenderProcessHost* process) {
content::WebContents* web_contents = content::WebContents* web_contents =
static_cast<AtomBrowserClient*>(AtomBrowserClient::Get())-> static_cast<AtomBrowserClient*>(AtomBrowserClient::Get())->
GetWebContentsFromProcessID(process->GetID()); GetWebContentsFromProcessID(process->GetID());
if (!web_contents) if (!web_contents)
return false; return false;
NativeWindow* window = NativeWindow::FromWebContents(web_contents); auto api_web_contents = WebContents::CreateFrom(isolate, web_contents);
if (!window) auto type = api_web_contents->GetType();
return false; return type == WebContents::Type::BROWSER_WINDOW ||
type == WebContents::Type::WEB_VIEW;
return true;
} }
} // namespace } // namespace
@ -63,10 +61,11 @@ void RenderProcessPreferences::BuildPrototype(
// static // static
mate::Handle<RenderProcessPreferences> mate::Handle<RenderProcessPreferences>
RenderProcessPreferences::ForAllBrowserWindow(v8::Isolate* isolate) { RenderProcessPreferences::ForAllWebContents(v8::Isolate* isolate) {
return mate::CreateHandle( return mate::CreateHandle(
isolate, isolate,
new RenderProcessPreferences(isolate, base::Bind(&IsBrowserWindow))); new RenderProcessPreferences(isolate,
base::Bind(&IsWebContents, isolate)));
} }
} // namespace api } // namespace api
@ -78,8 +77,8 @@ namespace {
void Initialize(v8::Local<v8::Object> exports, v8::Local<v8::Value> unused, void Initialize(v8::Local<v8::Object> exports, v8::Local<v8::Value> unused,
v8::Local<v8::Context> context, void* priv) { v8::Local<v8::Context> context, void* priv) {
mate::Dictionary dict(context->GetIsolate(), exports); mate::Dictionary dict(context->GetIsolate(), exports);
dict.SetMethod("forAllBrowserWindow", dict.SetMethod("forAllWebContents",
&atom::api::RenderProcessPreferences::ForAllBrowserWindow); &atom::api::RenderProcessPreferences::ForAllWebContents);
} }
} // namespace } // namespace

View file

@ -17,7 +17,7 @@ class RenderProcessPreferences
: public mate::Wrappable<RenderProcessPreferences> { : public mate::Wrappable<RenderProcessPreferences> {
public: public:
static mate::Handle<RenderProcessPreferences> static mate::Handle<RenderProcessPreferences>
ForAllBrowserWindow(v8::Isolate* isolate); ForAllWebContents(v8::Isolate* isolate);
static void BuildPrototype(v8::Isolate* isolate, static void BuildPrototype(v8::Isolate* isolate,
v8::Local<v8::ObjectTemplate> prototype); v8::Local<v8::ObjectTemplate> prototype);

View file

@ -187,6 +187,39 @@ struct Converter<content::SavePageType> {
} }
}; };
template<>
struct Converter<atom::api::WebContents::Type> {
static v8::Local<v8::Value> ToV8(v8::Isolate* isolate,
atom::api::WebContents::Type val) {
using Type = atom::api::WebContents::Type;
std::string type = "";
switch (val) {
case Type::BACKGROUND_PAGE: type = "backgroundPage"; break;
case Type::BROWSER_WINDOW: type = "window"; break;
case Type::REMOTE: type = "remote"; break;
case Type::WEB_VIEW: type = "webview"; break;
default: break;
}
return mate::ConvertToV8(isolate, type);
}
static bool FromV8(v8::Isolate* isolate, v8::Local<v8::Value> val,
atom::api::WebContents::Type* out) {
using Type = atom::api::WebContents::Type;
std::string type;
if (!ConvertFromV8(isolate, val, &type))
return false;
if (type == "webview") {
*out = Type::WEB_VIEW;
} else if (type == "backgroundPage") {
*out = Type::BACKGROUND_PAGE;
} else {
return false;
}
return true;
}
};
} // namespace mate } // namespace mate
@ -238,10 +271,8 @@ WebContents::WebContents(v8::Isolate* isolate,
// Read options. // Read options.
options.Get("backgroundThrottling", &background_throttling_); options.Get("backgroundThrottling", &background_throttling_);
// Whether it is a guest WebContents. type_ = BROWSER_WINDOW;
bool is_guest = false; options.Get("type", &type_);
options.Get("isGuest", &is_guest);
type_ = is_guest ? WEB_VIEW : BROWSER_WINDOW;
// Obtain the session. // Obtain the session.
std::string partition; std::string partition;
@ -261,7 +292,7 @@ WebContents::WebContents(v8::Isolate* isolate,
session_.Reset(isolate, session.ToV8()); session_.Reset(isolate, session.ToV8());
content::WebContents* web_contents; content::WebContents* web_contents;
if (is_guest) { if (IsGuest()) {
scoped_refptr<content::SiteInstance> site_instance = scoped_refptr<content::SiteInstance> site_instance =
content::SiteInstance::CreateForURL( content::SiteInstance::CreateForURL(
session->browser_context(), GURL("chrome-guest://fake-host")); session->browser_context(), GURL("chrome-guest://fake-host"));
@ -290,7 +321,7 @@ WebContents::WebContents(v8::Isolate* isolate,
web_contents->SetUserAgentOverride(GetBrowserContext()->GetUserAgent()); web_contents->SetUserAgentOverride(GetBrowserContext()->GetUserAgent());
if (is_guest) { if (IsGuest()) {
guest_delegate_->Initialize(this); guest_delegate_->Initialize(this);
NativeWindow* owner_window = nullptr; NativeWindow* owner_window = nullptr;
@ -744,13 +775,8 @@ int WebContents::GetID() const {
return web_contents()->GetRenderProcessHost()->GetID(); return web_contents()->GetRenderProcessHost()->GetID();
} }
std::string WebContents::GetType() const { WebContents::Type WebContents::GetType() const {
switch (type_) { return type_;
case BROWSER_WINDOW: return "window";
case WEB_VIEW: return "webview";
case REMOTE: return "remote";
default: return "";
}
} }
bool WebContents::Equal(const WebContents* web_contents) const { bool WebContents::Equal(const WebContents* web_contents) const {

View file

@ -43,6 +43,13 @@ class WebContents : public mate::TrackableObject<WebContents>,
public CommonWebContentsDelegate, public CommonWebContentsDelegate,
public content::WebContentsObserver { public content::WebContentsObserver {
public: public:
enum Type {
BACKGROUND_PAGE, // A DevTools extension background page.
BROWSER_WINDOW, // Used by BrowserWindow.
REMOTE, // Thin wrap around an existing WebContents.
WEB_VIEW, // Used by <webview>.
};
// For node.js callback function type: function(error, buffer) // For node.js callback function type: function(error, buffer)
using PrintToPDFCallback = using PrintToPDFCallback =
base::Callback<void(v8::Local<v8::Value>, v8::Local<v8::Value>)>; base::Callback<void(v8::Local<v8::Value>, v8::Local<v8::Value>)>;
@ -59,7 +66,7 @@ class WebContents : public mate::TrackableObject<WebContents>,
v8::Local<v8::ObjectTemplate> prototype); v8::Local<v8::ObjectTemplate> prototype);
int GetID() const; int GetID() const;
std::string GetType() const; Type GetType() const;
bool Equal(const WebContents* web_contents) const; bool Equal(const WebContents* web_contents) const;
void LoadURL(const GURL& url, const mate::Dictionary& options); void LoadURL(const GURL& url, const mate::Dictionary& options);
void DownloadURL(const GURL& url); void DownloadURL(const GURL& url);
@ -268,12 +275,6 @@ class WebContents : public mate::TrackableObject<WebContents>,
void DevToolsClosed() override; void DevToolsClosed() override;
private: private:
enum Type {
BROWSER_WINDOW, // Used by BrowserWindow.
WEB_VIEW, // Used by <webview>.
REMOTE, // Thin wrap around an existing WebContents.
};
AtomBrowserContext* GetBrowserContext() const; AtomBrowserContext* GetBrowserContext() const;
uint32_t GetNextRequestId() { uint32_t GetNextRequestId() {

View file

@ -1,6 +1,6 @@
const {app, ipcMain, session, webContents, BrowserWindow} = require('electron') const {app, ipcMain, session, webContents, BrowserWindow} = require('electron')
const {getAllWebContents} = process.atomBinding('web_contents') const {getAllWebContents} = process.atomBinding('web_contents')
const renderProcessPreferences = process.atomBinding('render_process_preferences').forAllBrowserWindow() const renderProcessPreferences = process.atomBinding('render_process_preferences').forAllWebContents()
const fs = require('fs') const fs = require('fs')
const path = require('path') const path = require('path')
@ -19,6 +19,11 @@ const generateExtensionIdFromName = function (name) {
return name.replace(/[\W_]+/g, '-').toLowerCase() return name.replace(/[\W_]+/g, '-').toLowerCase()
} }
const isWindowOrWebView = function (webContents) {
const type = webContents.getType()
return type === 'window' || type === 'webview'
}
// Create or get manifest object from |srcDirectory|. // Create or get manifest object from |srcDirectory|.
const getManifestFromPath = function (srcDirectory) { const getManifestFromPath = function (srcDirectory) {
let manifest let manifest
@ -73,6 +78,7 @@ const startBackgroundPages = function (manifest) {
const html = new Buffer(`<html><body>${scripts}</body></html>`) const html = new Buffer(`<html><body>${scripts}</body></html>`)
const contents = webContents.create({ const contents = webContents.create({
type: 'backgroundPage',
commandLineSwitches: ['--background-page'] commandLineSwitches: ['--background-page']
}) })
backgroundPages[manifest.extensionId] = { html: html, webContents: contents } backgroundPages[manifest.extensionId] = { html: html, webContents: contents }
@ -111,7 +117,7 @@ let nextId = 0
ipcMain.on('CHROME_RUNTIME_CONNECT', function (event, extensionId, connectInfo) { ipcMain.on('CHROME_RUNTIME_CONNECT', function (event, extensionId, connectInfo) {
const page = backgroundPages[extensionId] const page = backgroundPages[extensionId]
if (!page) { if (!page) {
console.error(`Connect to unkown extension ${extensionId}`) console.error(`Connect to unknown extension ${extensionId}`)
return return
} }
@ -132,7 +138,7 @@ ipcMain.on('CHROME_I18N_MANIFEST', function (event, extensionId) {
ipcMain.on('CHROME_RUNTIME_SENDMESSAGE', function (event, extensionId, message) { ipcMain.on('CHROME_RUNTIME_SENDMESSAGE', function (event, extensionId, message) {
const page = backgroundPages[extensionId] const page = backgroundPages[extensionId]
if (!page) { if (!page) {
console.error(`Connect to unkown extension ${extensionId}`) console.error(`Connect to unknown extension ${extensionId}`)
return return
} }
@ -142,7 +148,7 @@ ipcMain.on('CHROME_RUNTIME_SENDMESSAGE', function (event, extensionId, message)
ipcMain.on('CHROME_TABS_SEND_MESSAGE', function (event, tabId, extensionId, isBackgroundPage, message) { ipcMain.on('CHROME_TABS_SEND_MESSAGE', function (event, tabId, extensionId, isBackgroundPage, message) {
const contents = webContents.fromId(tabId) const contents = webContents.fromId(tabId)
if (!contents) { if (!contents) {
console.error(`Sending message to unkown tab ${tabId}`) console.error(`Sending message to unknown tab ${tabId}`)
return return
} }
@ -154,7 +160,7 @@ ipcMain.on('CHROME_TABS_SEND_MESSAGE', function (event, tabId, extensionId, isBa
ipcMain.on('CHROME_TABS_EXECUTESCRIPT', function (event, requestId, tabId, extensionId, details) { ipcMain.on('CHROME_TABS_EXECUTESCRIPT', function (event, requestId, tabId, extensionId, details) {
const contents = webContents.fromId(tabId) const contents = webContents.fromId(tabId)
if (!contents) { if (!contents) {
console.error(`Sending message to unkown tab ${tabId}`) console.error(`Sending message to unknown tab ${tabId}`)
return return
} }
@ -237,7 +243,7 @@ const loadDevToolsExtensions = function (win, manifests) {
} }
app.on('web-contents-created', function (event, webContents) { app.on('web-contents-created', function (event, webContents) {
if (webContents.getType() === 'remote') return if (!isWindowOrWebView(webContents)) return
hookWebContentsForTabEvents(webContents) hookWebContentsForTabEvents(webContents)
webContents.on('devtools-opened', function () { webContents.on('devtools-opened', function () {
@ -322,7 +328,7 @@ app.once('ready', function () {
const manifest = getManifestFromPath(srcDirectory) const manifest = getManifestFromPath(srcDirectory)
if (manifest) { if (manifest) {
for (const webContents of getAllWebContents()) { for (const webContents of getAllWebContents()) {
if (webContents.getType() !== 'remote') { if (isWindowOrWebView(webContents)) {
loadDevToolsExtensions(webContents, [manifest]) loadDevToolsExtensions(webContents, [manifest])
} }
} }

View file

@ -63,7 +63,7 @@ const createGuest = function (embedder, params) {
const id = getNextInstanceId(embedder) const id = getNextInstanceId(embedder)
const guest = webContents.create({ const guest = webContents.create({
isGuest: true, type: 'webview',
partition: params.partition, partition: params.partition,
embedder: embedder embedder: embedder
}) })