Merge pull request #5913 from electron/webview-devtools-extensions
Enable DevTools extensions in webviews
This commit is contained in:
commit
20372f057e
8 changed files with 97 additions and 25 deletions
|
@ -744,6 +744,15 @@ int WebContents::GetID() const {
|
||||||
return web_contents()->GetRenderProcessHost()->GetID();
|
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 {
|
bool WebContents::Equal(const WebContents* web_contents) const {
|
||||||
return GetID() == web_contents->GetID();
|
return GetID() == web_contents->GetID();
|
||||||
}
|
}
|
||||||
|
@ -1287,6 +1296,7 @@ void WebContents::BuildPrototype(v8::Isolate* isolate,
|
||||||
.SetMethod("endFrameSubscription", &WebContents::EndFrameSubscription)
|
.SetMethod("endFrameSubscription", &WebContents::EndFrameSubscription)
|
||||||
.SetMethod("setSize", &WebContents::SetSize)
|
.SetMethod("setSize", &WebContents::SetSize)
|
||||||
.SetMethod("isGuest", &WebContents::IsGuest)
|
.SetMethod("isGuest", &WebContents::IsGuest)
|
||||||
|
.SetMethod("getType", &WebContents::GetType)
|
||||||
.SetMethod("getWebPreferences", &WebContents::GetWebPreferences)
|
.SetMethod("getWebPreferences", &WebContents::GetWebPreferences)
|
||||||
.SetMethod("getOwnerBrowserWindow", &WebContents::GetOwnerBrowserWindow)
|
.SetMethod("getOwnerBrowserWindow", &WebContents::GetOwnerBrowserWindow)
|
||||||
.SetMethod("hasServiceWorker", &WebContents::HasServiceWorker)
|
.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("_setWrapWebContents", &atom::api::SetWrapWebContents);
|
||||||
dict.SetMethod("fromId",
|
dict.SetMethod("fromId",
|
||||||
&mate::TrackableObject<atom::api::WebContents>::FromWeakMapID);
|
&mate::TrackableObject<atom::api::WebContents>::FromWeakMapID);
|
||||||
|
dict.SetMethod("getAllWebContents",
|
||||||
|
&mate::TrackableObject<atom::api::WebContents>::GetAll);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
|
@ -59,6 +59,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;
|
||||||
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);
|
||||||
|
|
|
@ -10,6 +10,14 @@ session
|
||||||
const binding = process.atomBinding('web_contents')
|
const binding = process.atomBinding('web_contents')
|
||||||
const debuggerBinding = process.atomBinding('debugger')
|
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
|
let nextId = 0
|
||||||
const getNextId = function () {
|
const getNextId = function () {
|
||||||
return ++nextId
|
return ++nextId
|
||||||
|
@ -223,6 +231,8 @@ const wrapWebContents = function (webContents) {
|
||||||
|
|
||||||
this._printToPDF(printingSetting, callback)
|
this._printToPDF(printingSetting, callback)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
WebContents.emit('web-contents-created', webContents)
|
||||||
}
|
}
|
||||||
|
|
||||||
binding._setWrapWebContents(wrapWebContents)
|
binding._setWrapWebContents(wrapWebContents)
|
||||||
|
@ -235,12 +245,4 @@ const wrapDebugger = function (webContentsDebugger) {
|
||||||
|
|
||||||
debuggerBinding._setWrapDebugger(wrapDebugger)
|
debuggerBinding._setWrapDebugger(wrapDebugger)
|
||||||
|
|
||||||
module.exports = {
|
module.exports = WebContents
|
||||||
create (options = {}) {
|
|
||||||
return binding.create(options)
|
|
||||||
},
|
|
||||||
|
|
||||||
fromId (id) {
|
|
||||||
return binding.fromId(id)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
const {app, ipcMain, protocol, webContents, BrowserWindow} = require('electron')
|
const {app, ipcMain, protocol, webContents, BrowserWindow} = require('electron')
|
||||||
|
const {getAllWebContents} = process.atomBinding('web_contents')
|
||||||
const renderProcessPreferences = process.atomBinding('render_process_preferences').forAllBrowserWindow()
|
const renderProcessPreferences = process.atomBinding('render_process_preferences').forAllBrowserWindow()
|
||||||
|
|
||||||
const fs = require('fs')
|
const fs = require('fs')
|
||||||
|
@ -81,13 +82,13 @@ const removeBackgroundPages = function (manifest) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Dispatch tabs events.
|
// Dispatch tabs events.
|
||||||
const hookWindowForTabEvents = function (win) {
|
const hookWebContentsForTabEvents = function (webContents) {
|
||||||
const tabId = win.webContents.id
|
const tabId = webContents.id
|
||||||
for (const page of objectValues(backgroundPages)) {
|
for (const page of objectValues(backgroundPages)) {
|
||||||
page.webContents.sendToAll('CHROME_TABS_ONCREATED', tabId)
|
page.webContents.sendToAll('CHROME_TABS_ONCREATED', tabId)
|
||||||
}
|
}
|
||||||
|
|
||||||
win.once('closed', () => {
|
webContents.once('destroyed', () => {
|
||||||
for (const page of objectValues(backgroundPages)) {
|
for (const page of objectValues(backgroundPages)) {
|
||||||
page.webContents.sendToAll('CHROME_TABS_ONREMOVED', tabId)
|
page.webContents.sendToAll('CHROME_TABS_ONREMOVED', tabId)
|
||||||
}
|
}
|
||||||
|
@ -221,6 +222,15 @@ const loadDevToolsExtensions = function (win, manifests) {
|
||||||
win.devToolsWebContents.executeJavaScript(`DevToolsAPI.addExtensions(${JSON.stringify(extensionInfoArray)})`)
|
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.
|
// The persistent path of "DevTools Extensions" preference file.
|
||||||
let loadedExtensionsPath = null
|
let loadedExtensionsPath = null
|
||||||
|
|
||||||
|
@ -295,12 +305,15 @@ app.once('ready', function () {
|
||||||
BrowserWindow.addDevToolsExtension = function (srcDirectory) {
|
BrowserWindow.addDevToolsExtension = function (srcDirectory) {
|
||||||
const manifest = getManifestFromPath(srcDirectory)
|
const manifest = getManifestFromPath(srcDirectory)
|
||||||
if (manifest) {
|
if (manifest) {
|
||||||
for (const win of BrowserWindow.getAllWindows()) {
|
for (const webContents of getAllWebContents()) {
|
||||||
loadDevToolsExtensions(win, [manifest])
|
if (webContents.getType() !== 'remote') {
|
||||||
|
loadDevToolsExtensions(webContents, [manifest])
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return manifest.name
|
return manifest.name
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
BrowserWindow.removeDevToolsExtension = function (name) {
|
BrowserWindow.removeDevToolsExtension = function (name) {
|
||||||
const manifest = manifestNameMap[name]
|
const manifest = manifestNameMap[name]
|
||||||
if (!manifest) return
|
if (!manifest) return
|
||||||
|
@ -310,14 +323,4 @@ app.once('ready', function () {
|
||||||
delete manifestMap[manifest.extensionId]
|
delete manifestMap[manifest.extensionId]
|
||||||
delete manifestNameMap[name]
|
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))
|
|
||||||
})
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
|
|
|
@ -864,6 +864,7 @@ describe('browser-window module', function () {
|
||||||
|
|
||||||
ipcMain.once('answer', function (event, message) {
|
ipcMain.once('answer', function (event, message) {
|
||||||
assert.equal(message.runtimeId, 'foo')
|
assert.equal(message.runtimeId, 'foo')
|
||||||
|
assert.equal(message.tabId, w.webContents.id)
|
||||||
done()
|
done()
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
@ -875,6 +876,7 @@ describe('browser-window module', function () {
|
||||||
|
|
||||||
ipcMain.once('answer', function (event, message, extensionId) {
|
ipcMain.once('answer', function (event, message, extensionId) {
|
||||||
assert.equal(message.runtimeId, 'foo')
|
assert.equal(message.runtimeId, 'foo')
|
||||||
|
assert.equal(message.tabId, w.webContents.id)
|
||||||
done()
|
done()
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
|
@ -5,7 +5,8 @@
|
||||||
<title></title>
|
<title></title>
|
||||||
<script>
|
<script>
|
||||||
var message = JSON.stringify({
|
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})`
|
var sendMessage = `require('electron').ipcRenderer.send('answer', ${message})`
|
||||||
window.chrome.devtools.inspectedWindow.eval(sendMessage, function () {})
|
window.chrome.devtools.inspectedWindow.eval(sendMessage, function () {})
|
||||||
|
|
30
spec/fixtures/pages/webview-devtools.html
vendored
Normal file
30
spec/fixtures/pages/webview-devtools.html
vendored
Normal 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>
|
|
@ -912,4 +912,25 @@ describe('<webview> tag', function () {
|
||||||
|
|
||||||
w.loadURL('file://' + fixtures + '/pages/webview-visibilitychange.html')
|
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()
|
||||||
|
})
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue