Merge pull request #5913 from electron/webview-devtools-extensions

Enable DevTools extensions in webviews
This commit is contained in:
Cheng Zhao 2016-06-09 01:45:55 +00:00 committed by GitHub
commit 20372f057e
8 changed files with 97 additions and 25 deletions

View file

@ -744,6 +744,15 @@ int WebContents::GetID() const {
return web_contents()->GetRenderProcessHost()->GetID();
}
std::string WebContents::GetType() const {
switch (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 {
return GetID() == web_contents->GetID();
}
@ -1287,6 +1296,7 @@ void WebContents::BuildPrototype(v8::Isolate* isolate,
.SetMethod("endFrameSubscription", &WebContents::EndFrameSubscription)
.SetMethod("setSize", &WebContents::SetSize)
.SetMethod("isGuest", &WebContents::IsGuest)
.SetMethod("getType", &WebContents::GetType)
.SetMethod("getWebPreferences", &WebContents::GetWebPreferences)
.SetMethod("getOwnerBrowserWindow", &WebContents::GetOwnerBrowserWindow)
.SetMethod("hasServiceWorker", &WebContents::HasServiceWorker)
@ -1365,6 +1375,8 @@ void Initialize(v8::Local<v8::Object> exports, v8::Local<v8::Value> unused,
dict.SetMethod("_setWrapWebContents", &atom::api::SetWrapWebContents);
dict.SetMethod("fromId",
&mate::TrackableObject<atom::api::WebContents>::FromWeakMapID);
dict.SetMethod("getAllWebContents",
&mate::TrackableObject<atom::api::WebContents>::GetAll);
}
} // namespace

View file

@ -59,6 +59,7 @@ class WebContents : public mate::TrackableObject<WebContents>,
v8::Local<v8::ObjectTemplate> prototype);
int GetID() const;
std::string GetType() const;
bool Equal(const WebContents* web_contents) const;
void LoadURL(const GURL& url, const mate::Dictionary& options);
void DownloadURL(const GURL& url);

View file

@ -10,6 +10,14 @@ session
const binding = process.atomBinding('web_contents')
const debuggerBinding = process.atomBinding('debugger')
const WebContents = new EventEmitter()
WebContents.create = (options = {}) => {
return binding.create(options)
}
WebContents.fromId = (id) => {
return binding.fromId(id)
}
let nextId = 0
const getNextId = function () {
return ++nextId
@ -223,6 +231,8 @@ const wrapWebContents = function (webContents) {
this._printToPDF(printingSetting, callback)
}
WebContents.emit('web-contents-created', webContents)
}
binding._setWrapWebContents(wrapWebContents)
@ -235,12 +245,4 @@ const wrapDebugger = function (webContentsDebugger) {
debuggerBinding._setWrapDebugger(wrapDebugger)
module.exports = {
create (options = {}) {
return binding.create(options)
},
fromId (id) {
return binding.fromId(id)
}
}
module.exports = WebContents

View file

@ -1,4 +1,5 @@
const {app, ipcMain, protocol, webContents, BrowserWindow} = require('electron')
const {getAllWebContents} = process.atomBinding('web_contents')
const renderProcessPreferences = process.atomBinding('render_process_preferences').forAllBrowserWindow()
const fs = require('fs')
@ -81,13 +82,13 @@ const removeBackgroundPages = function (manifest) {
}
// Dispatch tabs events.
const hookWindowForTabEvents = function (win) {
const tabId = win.webContents.id
const hookWebContentsForTabEvents = function (webContents) {
const tabId = webContents.id
for (const page of objectValues(backgroundPages)) {
page.webContents.sendToAll('CHROME_TABS_ONCREATED', tabId)
}
win.once('closed', () => {
webContents.once('destroyed', () => {
for (const page of objectValues(backgroundPages)) {
page.webContents.sendToAll('CHROME_TABS_ONREMOVED', tabId)
}
@ -221,6 +222,15 @@ const loadDevToolsExtensions = function (win, manifests) {
win.devToolsWebContents.executeJavaScript(`DevToolsAPI.addExtensions(${JSON.stringify(extensionInfoArray)})`)
}
webContents.on('web-contents-created', function (webContents) {
if (webContents.getType() === 'remote') return
hookWebContentsForTabEvents(webContents)
webContents.on('devtools-opened', function () {
loadDevToolsExtensions(webContents, objectValues(manifestMap))
})
})
// The persistent path of "DevTools Extensions" preference file.
let loadedExtensionsPath = null
@ -295,12 +305,15 @@ app.once('ready', function () {
BrowserWindow.addDevToolsExtension = function (srcDirectory) {
const manifest = getManifestFromPath(srcDirectory)
if (manifest) {
for (const win of BrowserWindow.getAllWindows()) {
loadDevToolsExtensions(win, [manifest])
for (const webContents of getAllWebContents()) {
if (webContents.getType() !== 'remote') {
loadDevToolsExtensions(webContents, [manifest])
}
}
return manifest.name
}
}
BrowserWindow.removeDevToolsExtension = function (name) {
const manifest = manifestNameMap[name]
if (!manifest) return
@ -310,14 +323,4 @@ app.once('ready', function () {
delete manifestMap[manifest.extensionId]
delete manifestNameMap[name]
}
// Load extensions automatically when devtools is opened.
const init = BrowserWindow.prototype._init
BrowserWindow.prototype._init = function () {
init.call(this)
hookWindowForTabEvents(this)
this.webContents.on('devtools-opened', () => {
loadDevToolsExtensions(this, objectValues(manifestMap))
})
}
})

View file

@ -864,6 +864,7 @@ describe('browser-window module', function () {
ipcMain.once('answer', function (event, message) {
assert.equal(message.runtimeId, 'foo')
assert.equal(message.tabId, w.webContents.id)
done()
})
})
@ -875,6 +876,7 @@ describe('browser-window module', function () {
ipcMain.once('answer', function (event, message, extensionId) {
assert.equal(message.runtimeId, 'foo')
assert.equal(message.tabId, w.webContents.id)
done()
})
})

View file

@ -5,7 +5,8 @@
<title></title>
<script>
var message = JSON.stringify({
runtimeId: chrome.runtime.id
runtimeId: chrome.runtime.id,
tabId: chrome.devtools.inspectedWindow.tabId
})
var sendMessage = `require('electron').ipcRenderer.send('answer', ${message})`
window.chrome.devtools.inspectedWindow.eval(sendMessage, function () {})

View file

@ -0,0 +1,30 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
</head>
<body>
<webview nodeintegration src="./a.html"></webview>
<script>
var wv = document.querySelector('webview')
wv.addEventListener('dom-ready', () => {
const webContents = wv.getWebContents()
webContents.on('devtools-opened', function () {
var showPanelIntevalId = setInterval(function () {
if (webContents.devToolsWebContents) {
webContents.devToolsWebContents.executeJavaScript('(' + (function () {
var lastPanelId = WebInspector.inspectorView._tabbedPane._tabs.peekLast().id
WebInspector.inspectorView.showPanel(lastPanelId)
}).toString() + ')()')
} else {
clearInterval(showPanelIntevalId)
}
}, 100)
})
wv.openDevTools()
})
</script>
</script>
</body>
</html>

View file

@ -912,4 +912,25 @@ describe('<webview> tag', function () {
w.loadURL('file://' + fixtures + '/pages/webview-visibilitychange.html')
})
it('loads devtools extensions registered on the parent window', function (done) {
this.timeout(10000)
w = new BrowserWindow({
show: false
})
BrowserWindow.removeDevToolsExtension('foo')
var extensionPath = path.join(__dirname, 'fixtures', 'devtools-extensions', 'foo')
BrowserWindow.addDevToolsExtension(extensionPath)
w.loadURL('file://' + fixtures + '/pages/webview-devtools.html')
ipcMain.once('answer', function (event, message) {
assert.equal(message.runtimeId, 'foo')
assert.notEqual(message.tabId, w.webContents.id)
done()
})
})
})