forked from distok/asarfuckery
Changes of Linux canary v0.0.70
This commit is contained in:
parent
f77ae11327
commit
42e7e8d8e4
38 changed files with 1136 additions and 642 deletions
|
@ -212,7 +212,10 @@ function launchSplashWindow(startMinimized) {
|
|||
frame: false,
|
||||
resizable: false,
|
||||
center: true,
|
||||
show: false
|
||||
show: false,
|
||||
webPreferences: {
|
||||
nodeIntegration: true
|
||||
}
|
||||
};
|
||||
|
||||
splashWindow = new _electron.BrowserWindow(windowConfig);
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
'use strict'
|
||||
|
||||
const bindings = process.atomBinding('app')
|
||||
const commandLine = process.atomBinding('command_line')
|
||||
const path = require('path')
|
||||
const { app, App } = bindings
|
||||
|
||||
|
@ -25,24 +26,21 @@ Object.assign(app, {
|
|||
return Menu.getApplicationMenu()
|
||||
},
|
||||
commandLine: {
|
||||
appendSwitch (...args) {
|
||||
const castedArgs = args.map((arg) => {
|
||||
return typeof arg !== 'string' ? `${arg}` : arg
|
||||
})
|
||||
return bindings.appendSwitch(...castedArgs)
|
||||
},
|
||||
appendArgument (...args) {
|
||||
const castedArgs = args.map((arg) => {
|
||||
return typeof arg !== 'string' ? `${arg}` : arg
|
||||
})
|
||||
return bindings.appendArgument(...castedArgs)
|
||||
}
|
||||
hasSwitch: (...args) => commandLine.hasSwitch(...args.map(String)),
|
||||
getSwitchValue: (...args) => commandLine.getSwitchValue(...args.map(String)),
|
||||
appendSwitch: (...args) => commandLine.appendSwitch(...args.map(String)),
|
||||
appendArgument: (...args) => commandLine.appendArgument(...args.map(String))
|
||||
},
|
||||
enableMixedSandbox () {
|
||||
deprecate.log(`'enableMixedSandbox' is deprecated. Mixed-sandbox mode is now enabled by default. You can safely remove the call to enableMixedSandbox().`)
|
||||
}
|
||||
})
|
||||
|
||||
const nativeFn = app.getAppMetrics
|
||||
app.getFileIcon = deprecate.promisify(app.getFileIcon)
|
||||
|
||||
const nativeAppMetrics = app.getAppMetrics
|
||||
app.getAppMetrics = () => {
|
||||
const metrics = nativeFn.call(app)
|
||||
const metrics = nativeAppMetrics.call(app)
|
||||
for (const metric of metrics) {
|
||||
if ('memory' in metric) {
|
||||
deprecate.removeProperty(metric, 'memory')
|
||||
|
@ -93,9 +91,7 @@ if (process.platform === 'linux') {
|
|||
}
|
||||
|
||||
app.allowNTLMCredentialsForAllDomains = function (allow) {
|
||||
if (!process.noDeprecations) {
|
||||
deprecate.warn('app.allowNTLMCredentialsForAllDomains', 'session.allowNTLMCredentialsForDomains')
|
||||
}
|
||||
deprecate.warn('app.allowNTLMCredentialsForAllDomains', 'session.allowNTLMCredentialsForDomains')
|
||||
const domains = allow ? '*' : ''
|
||||
if (!this.isReady()) {
|
||||
this.commandLine.appendSwitch('auth-server-whitelist', domains)
|
||||
|
|
|
@ -3,8 +3,6 @@
|
|||
const electron = require('electron')
|
||||
const { WebContentsView, TopLevelWindow } = electron
|
||||
const { BrowserWindow } = process.atomBinding('window')
|
||||
const v8Util = process.atomBinding('v8_util')
|
||||
const ipcMain = require('@electron/internal/browser/ipc-main-internal')
|
||||
|
||||
Object.setPrototypeOf(BrowserWindow.prototype, TopLevelWindow.prototype)
|
||||
|
||||
|
@ -27,69 +25,6 @@ BrowserWindow.prototype._init = function () {
|
|||
nativeSetBounds.call(this, bounds, ...opts)
|
||||
}
|
||||
|
||||
// Make new windows requested by links behave like "window.open"
|
||||
this.webContents.on('-new-window', (event, url, frameName, disposition,
|
||||
additionalFeatures, postData,
|
||||
referrer) => {
|
||||
const options = {
|
||||
show: true,
|
||||
width: 800,
|
||||
height: 600
|
||||
}
|
||||
ipcMain.emit('ELECTRON_GUEST_WINDOW_MANAGER_INTERNAL_WINDOW_OPEN',
|
||||
event, url, referrer, frameName, disposition,
|
||||
options, additionalFeatures, postData)
|
||||
})
|
||||
|
||||
this.webContents.on('-web-contents-created', (event, webContents, url,
|
||||
frameName) => {
|
||||
v8Util.setHiddenValue(webContents, 'url-framename', { url, frameName })
|
||||
})
|
||||
|
||||
// Create a new browser window for the native implementation of
|
||||
// "window.open", used in sandbox and nativeWindowOpen mode
|
||||
this.webContents.on('-add-new-contents', (event, webContents, disposition,
|
||||
userGesture, left, top, width,
|
||||
height) => {
|
||||
const urlFrameName = v8Util.getHiddenValue(webContents, 'url-framename')
|
||||
if ((disposition !== 'foreground-tab' && disposition !== 'new-window' &&
|
||||
disposition !== 'background-tab') || !urlFrameName) {
|
||||
event.preventDefault()
|
||||
return
|
||||
}
|
||||
|
||||
if (webContents.getLastWebPreferences().nodeIntegration === true) {
|
||||
const message =
|
||||
'Enabling Node.js integration in child windows opened with the ' +
|
||||
'"nativeWindowOpen" option will cause memory leaks, please turn off ' +
|
||||
'the "nodeIntegration" option.\\n' +
|
||||
'From 5.x child windows opened with the "nativeWindowOpen" option ' +
|
||||
'will always have Node.js integration disabled.\\n' +
|
||||
'See https://github.com/electron/electron/pull/15076 for more.'
|
||||
// console is only available after DOM is created.
|
||||
const printWarning = () => this.webContents.executeJavaScript(`console.warn('${message}')`)
|
||||
if (this.webContents.isDomReady()) {
|
||||
printWarning()
|
||||
} else {
|
||||
this.webContents.once('dom-ready', printWarning)
|
||||
}
|
||||
}
|
||||
|
||||
const { url, frameName } = urlFrameName
|
||||
v8Util.deleteHiddenValue(webContents, 'url-framename')
|
||||
const options = {
|
||||
show: true,
|
||||
x: left,
|
||||
y: top,
|
||||
width: width || 800,
|
||||
height: height || 600,
|
||||
webContents: webContents
|
||||
}
|
||||
const referrer = { url: '', policy: 'default' }
|
||||
ipcMain.emit('ELECTRON_GUEST_WINDOW_MANAGER_INTERNAL_WINDOW_OPEN',
|
||||
event, url, referrer, frameName, disposition, options)
|
||||
})
|
||||
|
||||
// window.resizeTo(...)
|
||||
// window.moveTo(...)
|
||||
this.webContents.on('move', (event, size) => {
|
||||
|
|
|
@ -1,3 +1,9 @@
|
|||
'use strict'
|
||||
const { deprecate } = require('electron')
|
||||
const contentTracing = process.atomBinding('content_tracing')
|
||||
|
||||
module.exports = process.atomBinding('content_tracing')
|
||||
contentTracing.startRecording = deprecate.promisify(contentTracing.startRecording)
|
||||
contentTracing.stopRecording = deprecate.promisify(contentTracing.stopRecording)
|
||||
contentTracing.getCategories = deprecate.promisify(contentTracing.getCategories)
|
||||
|
||||
module.exports = contentTracing
|
||||
|
|
|
@ -2,14 +2,18 @@
|
|||
|
||||
const { app } = require('electron')
|
||||
|
||||
const isMac = process.platform === 'darwin'
|
||||
const isWindows = process.platform === 'win32'
|
||||
const isLinux = process.platform === 'linux'
|
||||
|
||||
const roles = {
|
||||
about: {
|
||||
get label () {
|
||||
return process.platform === 'linux' ? 'About' : `About ${app.getName()}`
|
||||
return isLinux ? 'About' : `About ${app.getName()}`
|
||||
}
|
||||
},
|
||||
close: {
|
||||
label: process.platform === 'darwin' ? 'Close Window' : 'Close',
|
||||
label: isMac ? 'Close Window' : 'Close',
|
||||
accelerator: 'CommandOrControl+W',
|
||||
windowMethod: 'close'
|
||||
},
|
||||
|
@ -78,12 +82,12 @@ const roles = {
|
|||
default: return 'Quit'
|
||||
}
|
||||
},
|
||||
accelerator: process.platform === 'win32' ? null : 'CommandOrControl+Q',
|
||||
accelerator: isWindows ? null : 'CommandOrControl+Q',
|
||||
appMethod: 'quit'
|
||||
},
|
||||
redo: {
|
||||
label: 'Redo',
|
||||
accelerator: process.platform === 'win32' ? 'Control+Y' : 'Shift+CommandOrControl+Z',
|
||||
accelerator: isWindows ? 'Control+Y' : 'Shift+CommandOrControl+Z',
|
||||
webContentsMethod: 'redo'
|
||||
},
|
||||
reload: {
|
||||
|
@ -122,13 +126,13 @@ const roles = {
|
|||
},
|
||||
toggledevtools: {
|
||||
label: 'Toggle Developer Tools',
|
||||
accelerator: process.platform === 'darwin' ? 'Alt+Command+I' : 'Ctrl+Shift+I',
|
||||
accelerator: isMac ? 'Alt+Command+I' : 'Ctrl+Shift+I',
|
||||
nonNativeMacOSRole: true,
|
||||
windowMethod: 'toggleDevTools'
|
||||
},
|
||||
togglefullscreen: {
|
||||
label: 'Toggle Full Screen',
|
||||
accelerator: process.platform === 'darwin' ? 'Control+Command+F' : 'F11',
|
||||
accelerator: isMac ? 'Control+Command+F' : 'F11',
|
||||
windowMethod: (window) => {
|
||||
window.setFullScreen(!window.isFullScreen())
|
||||
}
|
||||
|
@ -152,9 +156,8 @@ const roles = {
|
|||
accelerator: 'CommandOrControl+Plus',
|
||||
nonNativeMacOSRole: true,
|
||||
webContentsMethod: (webContents) => {
|
||||
webContents.getZoomLevel((zoomLevel) => {
|
||||
webContents.setZoomLevel(zoomLevel + 0.5)
|
||||
})
|
||||
const zoomLevel = webContents.getZoomLevel()
|
||||
webContents.setZoomLevel(zoomLevel + 0.5)
|
||||
}
|
||||
},
|
||||
zoomout: {
|
||||
|
@ -162,78 +165,97 @@ const roles = {
|
|||
accelerator: 'CommandOrControl+-',
|
||||
nonNativeMacOSRole: true,
|
||||
webContentsMethod: (webContents) => {
|
||||
webContents.getZoomLevel((zoomLevel) => {
|
||||
webContents.setZoomLevel(zoomLevel - 0.5)
|
||||
})
|
||||
const zoomLevel = webContents.getZoomLevel()
|
||||
webContents.setZoomLevel(zoomLevel - 0.5)
|
||||
}
|
||||
},
|
||||
// Edit submenu (should fit both Mac & Windows)
|
||||
// App submenu should be used for Mac only
|
||||
appmenu: {
|
||||
get label () {
|
||||
return app.getName()
|
||||
},
|
||||
submenu: [
|
||||
{ role: 'about' },
|
||||
{ type: 'separator' },
|
||||
{ role: 'services' },
|
||||
{ type: 'separator' },
|
||||
{ role: 'hide' },
|
||||
{ role: 'hideothers' },
|
||||
{ role: 'unhide' },
|
||||
{ type: 'separator' },
|
||||
{ role: 'quit' }
|
||||
]
|
||||
},
|
||||
// File submenu
|
||||
filemenu: {
|
||||
label: 'File',
|
||||
submenu: [
|
||||
isMac ? { role: 'close' } : { role: 'quit' }
|
||||
]
|
||||
},
|
||||
// Edit submenu
|
||||
editmenu: {
|
||||
label: 'Edit',
|
||||
submenu: [
|
||||
{
|
||||
role: 'undo'
|
||||
},
|
||||
{
|
||||
role: 'redo'
|
||||
},
|
||||
{
|
||||
type: 'separator'
|
||||
},
|
||||
{
|
||||
role: 'cut'
|
||||
},
|
||||
{
|
||||
role: 'copy'
|
||||
},
|
||||
{
|
||||
role: 'paste'
|
||||
},
|
||||
|
||||
process.platform === 'darwin' ? {
|
||||
role: 'pasteAndMatchStyle'
|
||||
} : null,
|
||||
|
||||
{
|
||||
role: 'delete'
|
||||
},
|
||||
|
||||
process.platform === 'win32' ? {
|
||||
type: 'separator'
|
||||
} : null,
|
||||
|
||||
{
|
||||
role: 'selectAll'
|
||||
}
|
||||
{ role: 'undo' },
|
||||
{ role: 'redo' },
|
||||
{ type: 'separator' },
|
||||
{ role: 'cut' },
|
||||
{ role: 'copy' },
|
||||
{ role: 'paste' },
|
||||
...(isMac ? [
|
||||
{ role: 'pasteAndMatchStyle' },
|
||||
{ role: 'delete' },
|
||||
{ role: 'selectAll' },
|
||||
{ type: 'separator' },
|
||||
{
|
||||
label: 'Speech',
|
||||
submenu: [
|
||||
{ role: 'startspeaking' },
|
||||
{ role: 'stopspeaking' }
|
||||
]
|
||||
}
|
||||
] : [
|
||||
{ role: 'delete' },
|
||||
{ type: 'separator' },
|
||||
{ role: 'selectAll' }
|
||||
])
|
||||
]
|
||||
},
|
||||
|
||||
// Window submenu should be used for Mac only
|
||||
// View submenu
|
||||
viewmenu: {
|
||||
label: 'View',
|
||||
submenu: [
|
||||
{ role: 'reload' },
|
||||
{ role: 'forcereload' },
|
||||
{ role: 'toggledevtools' },
|
||||
{ type: 'separator' },
|
||||
{ role: 'resetzoom' },
|
||||
{ role: 'zoomin' },
|
||||
{ role: 'zoomout' },
|
||||
{ type: 'separator' },
|
||||
{ role: 'togglefullscreen' }
|
||||
]
|
||||
},
|
||||
// Window submenu
|
||||
windowmenu: {
|
||||
label: 'Window',
|
||||
submenu: [
|
||||
{
|
||||
role: 'minimize'
|
||||
},
|
||||
{
|
||||
role: 'close'
|
||||
},
|
||||
|
||||
process.platform === 'darwin' ? {
|
||||
type: 'separator'
|
||||
} : null,
|
||||
|
||||
process.platform === 'darwin' ? {
|
||||
role: 'front'
|
||||
} : null
|
||||
|
||||
{ role: 'minimize' },
|
||||
{ role: 'zoom' },
|
||||
...(isMac ? [
|
||||
{ type: 'separator' },
|
||||
{ role: 'front' }
|
||||
] : [
|
||||
{ role: 'close' }
|
||||
])
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
const canExecuteRole = (role) => {
|
||||
if (!roles.hasOwnProperty(role)) return false
|
||||
if (process.platform !== 'darwin') return true
|
||||
if (!isMac) return true
|
||||
|
||||
// macOS handles all roles natively except for a few
|
||||
return roles[role].nonNativeMacOSRole
|
||||
|
@ -248,7 +270,8 @@ exports.getDefaultAccelerator = (role) => {
|
|||
}
|
||||
|
||||
exports.shouldRegisterAccelerator = (role) => {
|
||||
return roles.hasOwnProperty(role) ? roles[role].registerAccelerator : true
|
||||
const hasRoleRegister = roles.hasOwnProperty(role) && roles[role].registerAccelerator !== undefined
|
||||
return hasRoleRegister ? roles[role].registerAccelerator : true
|
||||
}
|
||||
|
||||
exports.getDefaultSubmenu = (role) => {
|
||||
|
|
|
@ -145,6 +145,8 @@ Menu.setApplicationMenu = function (menu) {
|
|||
}
|
||||
|
||||
applicationMenu = menu
|
||||
v8Util.setHiddenValue(global, 'applicationMenuSet', true)
|
||||
|
||||
if (process.platform === 'darwin') {
|
||||
if (!menu) return
|
||||
menu._callMenuWillShow()
|
||||
|
@ -159,13 +161,13 @@ Menu.buildFromTemplate = function (template) {
|
|||
if (!Array.isArray(template)) {
|
||||
throw new TypeError('Invalid template for Menu: Menu template must be an array')
|
||||
}
|
||||
const menu = new Menu()
|
||||
if (!areValidTemplateItems(template)) {
|
||||
throw new TypeError('Invalid template for MenuItem: must have at least one of label, role or type')
|
||||
}
|
||||
const filtered = removeExtraSeparators(template)
|
||||
const sorted = sortTemplate(filtered)
|
||||
|
||||
const menu = new Menu()
|
||||
sorted.forEach((item) => menu.append(new MenuItem(item)))
|
||||
|
||||
return menu
|
||||
|
|
|
@ -30,9 +30,7 @@ module.exports = [
|
|||
{ name: 'Tray', file: 'tray' },
|
||||
{ name: 'View', file: 'view' },
|
||||
{ name: 'webContents', file: 'web-contents' },
|
||||
{ name: 'WebContentsView', file: 'web-contents-view' },
|
||||
// The internal modules, invisible unless you know their names.
|
||||
{ name: 'NavigationController', file: 'navigation-controller', private: true }
|
||||
{ name: 'WebContentsView', file: 'web-contents-view' }
|
||||
]
|
||||
|
||||
if (features.isViewApiEnabled()) {
|
||||
|
@ -41,6 +39,8 @@ if (features.isViewApiEnabled()) {
|
|||
{ name: 'Button', file: 'views/button' },
|
||||
{ name: 'LabelButton', file: 'views/label-button' },
|
||||
{ name: 'LayoutManager', file: 'views/layout-manager' },
|
||||
{ name: 'MdTextButton', file: 'views/md-text-button' },
|
||||
{ name: 'ResizeArea', file: 'views/resize-area' },
|
||||
{ name: 'TextField', file: 'views/text-field' }
|
||||
)
|
||||
}
|
||||
|
|
|
@ -1,8 +1,23 @@
|
|||
'use strict'
|
||||
|
||||
const { EventEmitter } = require('events')
|
||||
const { app } = require('electron')
|
||||
const { fromPartition, Session, Cookies } = process.atomBinding('session')
|
||||
const { app, deprecate } = require('electron')
|
||||
const { Session, Cookies } = process.atomBinding('session')
|
||||
const realFromPartition = process.atomBinding('session').fromPartition
|
||||
|
||||
const wrappedSymbol = Symbol('wrapped-deprecate')
|
||||
const fromPartition = (partition) => {
|
||||
const session = realFromPartition(partition)
|
||||
if (!session[wrappedSymbol]) {
|
||||
session[wrappedSymbol] = true
|
||||
const { cookies } = session
|
||||
cookies.flushStore = deprecate.promisify(cookies.flushStore)
|
||||
cookies.get = deprecate.promisify(cookies.get)
|
||||
cookies.remove = deprecate.promisify(cookies.remove)
|
||||
cookies.set = deprecate.promisify(cookies.set)
|
||||
}
|
||||
return session
|
||||
}
|
||||
|
||||
// Public API.
|
||||
Object.defineProperties(exports, {
|
||||
|
@ -20,5 +35,6 @@ Object.setPrototypeOf(Session.prototype, EventEmitter.prototype)
|
|||
Object.setPrototypeOf(Cookies.prototype, EventEmitter.prototype)
|
||||
|
||||
Session.prototype._init = function () {
|
||||
this.protocol.isProtocolHandled = deprecate.promisify(this.protocol.isProtocolHandled)
|
||||
app.emit('session-created', this)
|
||||
}
|
||||
|
|
|
@ -31,12 +31,6 @@ class TouchBar extends EventEmitter {
|
|||
|
||||
let { items, escapeItem } = options
|
||||
|
||||
// FIXME Support array as first argument, remove in 2.0
|
||||
if (Array.isArray(options)) {
|
||||
items = options
|
||||
escapeItem = null
|
||||
}
|
||||
|
||||
if (!Array.isArray(items)) {
|
||||
items = []
|
||||
}
|
||||
|
|
|
@ -5,8 +5,9 @@ const { EventEmitter } = require('events')
|
|||
const electron = require('electron')
|
||||
const path = require('path')
|
||||
const url = require('url')
|
||||
const { app, ipcMain, session, NavigationController, deprecate } = electron
|
||||
const { app, ipcMain, session, deprecate } = electron
|
||||
|
||||
const NavigationController = require('@electron/internal/browser/navigation-controller')
|
||||
const ipcMainInternal = require('@electron/internal/browser/ipc-main-internal')
|
||||
const errorUtils = require('@electron/internal/common/error-utils')
|
||||
|
||||
|
@ -110,6 +111,7 @@ WebContents.prototype.send = function (channel, ...args) {
|
|||
|
||||
return this._send(internal, sendToAll, channel, args)
|
||||
}
|
||||
|
||||
WebContents.prototype.sendToAll = function (channel, ...args) {
|
||||
if (typeof channel !== 'string') {
|
||||
throw new Error('Missing required channel argument')
|
||||
|
@ -141,6 +143,30 @@ WebContents.prototype._sendInternalToAll = function (channel, ...args) {
|
|||
|
||||
return this._send(internal, sendToAll, channel, args)
|
||||
}
|
||||
WebContents.prototype.sendToFrame = function (frameId, channel, ...args) {
|
||||
if (typeof channel !== 'string') {
|
||||
throw new Error('Missing required channel argument')
|
||||
} else if (typeof frameId !== 'number') {
|
||||
throw new Error('Missing required frameId argument')
|
||||
}
|
||||
|
||||
const internal = false
|
||||
const sendToAll = false
|
||||
|
||||
return this._sendToFrame(internal, sendToAll, frameId, channel, args)
|
||||
}
|
||||
WebContents.prototype._sendToFrameInternal = function (frameId, channel, ...args) {
|
||||
if (typeof channel !== 'string') {
|
||||
throw new Error('Missing required channel argument')
|
||||
} else if (typeof frameId !== 'number') {
|
||||
throw new Error('Missing required frameId argument')
|
||||
}
|
||||
|
||||
const internal = true
|
||||
const sendToAll = false
|
||||
|
||||
return this._sendToFrame(internal, sendToAll, frameId, channel, args)
|
||||
}
|
||||
|
||||
// Following methods are mapped to webFrame.
|
||||
const webFrameMethods = [
|
||||
|
@ -196,10 +222,34 @@ WebContents.prototype.executeJavaScript = function (code, hasUserGesture, callba
|
|||
}
|
||||
}
|
||||
|
||||
// TODO(codebytere): remove when promisifications is complete
|
||||
const nativeZoomLevel = WebContents.prototype.getZoomLevel
|
||||
WebContents.prototype.getZoomLevel = function (callback) {
|
||||
if (callback == null) {
|
||||
return nativeZoomLevel.call(this)
|
||||
} else {
|
||||
process.nextTick(() => {
|
||||
callback(nativeZoomLevel.call(this))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// TODO(codebytere): remove when promisifications is complete
|
||||
const nativeZoomFactor = WebContents.prototype.getZoomFactor
|
||||
WebContents.prototype.getZoomFactor = function (callback) {
|
||||
if (callback == null) {
|
||||
return nativeZoomFactor.call(this)
|
||||
} else {
|
||||
process.nextTick(() => {
|
||||
callback(nativeZoomFactor.call(this))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
WebContents.prototype.takeHeapSnapshot = function (filePath) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const channel = `ELECTRON_TAKE_HEAP_SNAPSHOT_RESULT_${getNextId()}`
|
||||
ipcMain.once(channel, (event, success) => {
|
||||
ipcMainInternal.once(channel, (event, success) => {
|
||||
if (success) {
|
||||
resolve()
|
||||
} else {
|
||||
|
@ -207,7 +257,7 @@ WebContents.prototype.takeHeapSnapshot = function (filePath) {
|
|||
}
|
||||
})
|
||||
if (!this._takeHeapSnapshot(filePath, channel)) {
|
||||
ipcMain.emit(channel, false)
|
||||
ipcMainInternal.emit(channel, false)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
@ -276,16 +326,6 @@ WebContents.prototype.getPrinters = function () {
|
|||
}
|
||||
}
|
||||
|
||||
WebContents.prototype.getZoomLevel = function (callback) {
|
||||
if (typeof callback !== 'function') {
|
||||
throw new Error('Must pass function as an argument')
|
||||
}
|
||||
process.nextTick(() => {
|
||||
const zoomLevel = this._getZoomLevel()
|
||||
callback(zoomLevel)
|
||||
})
|
||||
}
|
||||
|
||||
WebContents.prototype.loadFile = function (filePath, options = {}) {
|
||||
if (typeof filePath !== 'string') {
|
||||
throw new Error('Must pass filePath as a string')
|
||||
|
@ -302,22 +342,31 @@ WebContents.prototype.loadFile = function (filePath, options = {}) {
|
|||
}))
|
||||
}
|
||||
|
||||
WebContents.prototype.getZoomFactor = function (callback) {
|
||||
if (typeof callback !== 'function') {
|
||||
throw new Error('Must pass function as an argument')
|
||||
const addReplyToEvent = (event) => {
|
||||
event.reply = (...args) => {
|
||||
event.sender.sendToFrame(event.frameId, ...args)
|
||||
}
|
||||
process.nextTick(() => {
|
||||
const zoomFactor = this._getZoomFactor()
|
||||
callback(zoomFactor)
|
||||
}
|
||||
|
||||
const addReplyInternalToEvent = (event) => {
|
||||
Object.defineProperty(event, '_replyInternal', {
|
||||
configurable: false,
|
||||
enumerable: false,
|
||||
value: (...args) => {
|
||||
event.sender._sendToFrameInternal(event.frameId, ...args)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
WebContents.prototype.findInPage = function (text, options = {}) {
|
||||
// TODO (nitsakh): Remove in 5.0
|
||||
if (options.wordStart != null || options.medialCapitalAtWordStart != null) {
|
||||
deprecate.log('wordStart and medialCapitalAtWordStart options are deprecated')
|
||||
}
|
||||
return this._findInPage(text, options)
|
||||
const safeProtocols = new Set([
|
||||
'chrome-devtools:',
|
||||
'chrome-extension:'
|
||||
])
|
||||
|
||||
const isWebContentsTrusted = function (contents) {
|
||||
const pageURL = contents._getURL()
|
||||
const { protocol } = url.parse(pageURL)
|
||||
return safeProtocols.has(protocol)
|
||||
}
|
||||
|
||||
// Add JavaScript wrappers for WebContents class.
|
||||
|
@ -325,27 +374,38 @@ WebContents.prototype._init = function () {
|
|||
// The navigation controller.
|
||||
NavigationController.call(this, this)
|
||||
|
||||
// Every remote callback from renderer process would add a listenter to the
|
||||
// render-view-deleted event, so ignore the listenters warning.
|
||||
// Every remote callback from renderer process would add a listener to the
|
||||
// render-view-deleted event, so ignore the listeners warning.
|
||||
this.setMaxListeners(0)
|
||||
|
||||
this.capturePage = deprecate.promisify(this.capturePage)
|
||||
this.hasServiceWorker = deprecate.function(this.hasServiceWorker)
|
||||
this.unregisterServiceWorker = deprecate.function(this.unregisterServiceWorker)
|
||||
|
||||
// Dispatch IPC messages to the ipc module.
|
||||
this.on('ipc-message', function (event, [channel, ...args]) {
|
||||
this.on('-ipc-message', function (event, [channel, ...args]) {
|
||||
addReplyToEvent(event)
|
||||
this.emit('ipc-message', event, channel, ...args)
|
||||
ipcMain.emit(channel, event, ...args)
|
||||
})
|
||||
this.on('ipc-message-sync', function (event, [channel, ...args]) {
|
||||
|
||||
this.on('-ipc-message-sync', function (event, [channel, ...args]) {
|
||||
Object.defineProperty(event, 'returnValue', {
|
||||
set: function (value) {
|
||||
return event.sendReply([value])
|
||||
},
|
||||
get: function () {}
|
||||
})
|
||||
addReplyToEvent(event)
|
||||
this.emit('ipc-message-sync', event, channel, ...args)
|
||||
ipcMain.emit(channel, event, ...args)
|
||||
})
|
||||
|
||||
this.on('ipc-internal-message', function (event, [channel, ...args]) {
|
||||
addReplyInternalToEvent(event)
|
||||
ipcMainInternal.emit(channel, event, ...args)
|
||||
})
|
||||
|
||||
this.on('ipc-internal-message-sync', function (event, [channel, ...args]) {
|
||||
Object.defineProperty(event, 'returnValue', {
|
||||
set: function (value) {
|
||||
|
@ -353,6 +413,7 @@ WebContents.prototype._init = function () {
|
|||
},
|
||||
get: function () {}
|
||||
})
|
||||
addReplyInternalToEvent(event)
|
||||
ipcMainInternal.emit(channel, event, ...args)
|
||||
})
|
||||
|
||||
|
@ -368,13 +429,23 @@ WebContents.prototype._init = function () {
|
|||
})
|
||||
})
|
||||
|
||||
this.on('remote-require', (event, ...args) => {
|
||||
app.emit('remote-require', event, this, ...args)
|
||||
})
|
||||
const forwardedEvents = [
|
||||
'desktop-capturer-get-sources',
|
||||
'remote-require',
|
||||
'remote-get-global',
|
||||
'remote-get-builtin',
|
||||
'remote-get-current-window',
|
||||
'remote-get-current-web-contents',
|
||||
'remote-get-guest-web-contents'
|
||||
]
|
||||
|
||||
this.on('remote-get-global', (event, ...args) => {
|
||||
app.emit('remote-get-global', event, this, ...args)
|
||||
})
|
||||
for (const eventName of forwardedEvents) {
|
||||
this.on(eventName, (event, ...args) => {
|
||||
if (!isWebContentsTrusted(event.sender)) {
|
||||
app.emit(eventName, event, this, ...args)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
deprecate.event(this, 'did-get-response-details', '-did-get-response-details')
|
||||
deprecate.event(this, 'did-get-redirect-request', '-did-get-redirect-request')
|
||||
|
@ -384,6 +455,46 @@ WebContents.prototype._init = function () {
|
|||
this.reload()
|
||||
})
|
||||
|
||||
// Handle window.open for BrowserWindow and BrowserView.
|
||||
if (['browserView', 'window'].includes(this.getType())) {
|
||||
// Make new windows requested by links behave like "window.open".
|
||||
this.on('-new-window', (event, url, frameName, disposition,
|
||||
additionalFeatures, postData,
|
||||
referrer) => {
|
||||
const options = {
|
||||
show: true,
|
||||
width: 800,
|
||||
height: 600
|
||||
}
|
||||
ipcMainInternal.emit('ELECTRON_GUEST_WINDOW_MANAGER_INTERNAL_WINDOW_OPEN',
|
||||
event, url, referrer, frameName, disposition,
|
||||
options, additionalFeatures, postData)
|
||||
})
|
||||
|
||||
// Create a new browser window for the native implementation of
|
||||
// "window.open", used in sandbox and nativeWindowOpen mode.
|
||||
this.on('-add-new-contents', (event, webContents, disposition,
|
||||
userGesture, left, top, width, height, url, frameName) => {
|
||||
if ((disposition !== 'foreground-tab' && disposition !== 'new-window' &&
|
||||
disposition !== 'background-tab')) {
|
||||
event.preventDefault()
|
||||
return
|
||||
}
|
||||
|
||||
const options = {
|
||||
show: true,
|
||||
x: left,
|
||||
y: top,
|
||||
width: width || 800,
|
||||
height: height || 600,
|
||||
webContents
|
||||
}
|
||||
const referrer = { url: '', policy: 'default' }
|
||||
ipcMainInternal.emit('ELECTRON_GUEST_WINDOW_MANAGER_INTERNAL_WINDOW_OPEN',
|
||||
event, url, referrer, frameName, disposition, options)
|
||||
})
|
||||
}
|
||||
|
||||
app.emit('web-contents-created', {}, this)
|
||||
}
|
||||
|
||||
|
|
|
@ -180,7 +180,7 @@ ipcMain.on('CHROME_RUNTIME_SENDMESSAGE', function (event, extensionId, message,
|
|||
|
||||
page.webContents._sendInternalToAll(`CHROME_RUNTIME_ONMESSAGE_${extensionId}`, event.sender.id, message, resultID)
|
||||
ipcMain.once(`CHROME_RUNTIME_ONMESSAGE_RESULT_${resultID}`, (event, result) => {
|
||||
event.sender._sendInternal(`CHROME_RUNTIME_SENDMESSAGE_RESULT_${originResultID}`, result)
|
||||
event._replyInternal(`CHROME_RUNTIME_SENDMESSAGE_RESULT_${originResultID}`, result)
|
||||
})
|
||||
resultID++
|
||||
})
|
||||
|
@ -196,12 +196,23 @@ ipcMain.on('CHROME_TABS_SEND_MESSAGE', function (event, tabId, extensionId, isBa
|
|||
|
||||
contents._sendInternalToAll(`CHROME_RUNTIME_ONMESSAGE_${extensionId}`, senderTabId, message, resultID)
|
||||
ipcMain.once(`CHROME_RUNTIME_ONMESSAGE_RESULT_${resultID}`, (event, result) => {
|
||||
event.sender._sendInternal(`CHROME_TABS_SEND_MESSAGE_RESULT_${originResultID}`, result)
|
||||
event._replyInternal(`CHROME_TABS_SEND_MESSAGE_RESULT_${originResultID}`, result)
|
||||
})
|
||||
resultID++
|
||||
})
|
||||
|
||||
const isChromeExtension = function (pageURL) {
|
||||
const { protocol } = url.parse(pageURL)
|
||||
return protocol === 'chrome-extension:'
|
||||
}
|
||||
|
||||
ipcMain.on('CHROME_TABS_EXECUTESCRIPT', function (event, requestId, tabId, extensionId, details) {
|
||||
const pageURL = event.sender._getURL()
|
||||
if (!isChromeExtension(pageURL)) {
|
||||
console.error(`Blocked ${pageURL} from calling chrome.tabs.executeScript()`)
|
||||
return
|
||||
}
|
||||
|
||||
const contents = webContents.fromId(tabId)
|
||||
if (!contents) {
|
||||
console.error(`Sending message to unknown tab ${tabId}`)
|
||||
|
|
58
electronasar/canary/browser/default-menu.js
Normal file
58
electronasar/canary/browser/default-menu.js
Normal file
|
@ -0,0 +1,58 @@
|
|||
'use strict'
|
||||
|
||||
const { shell, Menu } = require('electron')
|
||||
const v8Util = process.atomBinding('v8_util')
|
||||
|
||||
const isMac = process.platform === 'darwin'
|
||||
|
||||
const setDefaultApplicationMenu = () => {
|
||||
if (v8Util.getHiddenValue(global, 'applicationMenuSet')) return
|
||||
|
||||
const helpMenu = {
|
||||
role: 'help',
|
||||
submenu: [
|
||||
{
|
||||
label: 'Learn More',
|
||||
click () {
|
||||
shell.openExternalSync('https://electronjs.org')
|
||||
}
|
||||
},
|
||||
{
|
||||
label: 'Documentation',
|
||||
click () {
|
||||
shell.openExternalSync(
|
||||
`https://github.com/electron/electron/tree/v${process.versions.electron}/docs#readme`
|
||||
)
|
||||
}
|
||||
},
|
||||
{
|
||||
label: 'Community Discussions',
|
||||
click () {
|
||||
shell.openExternalSync('https://discuss.atom.io/c/electron')
|
||||
}
|
||||
},
|
||||
{
|
||||
label: 'Search Issues',
|
||||
click () {
|
||||
shell.openExternalSync('https://github.com/electron/electron/issues')
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
const template = [
|
||||
...(isMac ? [{ role: 'appMenu' }] : []),
|
||||
{ role: 'fileMenu' },
|
||||
{ role: 'editMenu' },
|
||||
{ role: 'viewMenu' },
|
||||
{ role: 'windowMenu' },
|
||||
helpMenu
|
||||
]
|
||||
|
||||
const menu = Menu.buildFromTemplate(template)
|
||||
Menu.setApplicationMenu(menu)
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
setDefaultApplicationMenu
|
||||
}
|
|
@ -1,7 +1,9 @@
|
|||
'use strict'
|
||||
|
||||
const ipcMain = require('@electron/internal/browser/ipc-main-internal')
|
||||
|
||||
const { desktopCapturer } = process.atomBinding('desktop_capturer')
|
||||
const eventBinding = process.atomBinding('event')
|
||||
|
||||
const deepEqual = (a, b) => JSON.stringify(a) === JSON.stringify(b)
|
||||
|
||||
|
@ -11,32 +13,40 @@ let requestsQueue = []
|
|||
const electronSources = 'ELECTRON_BROWSER_DESKTOP_CAPTURER_GET_SOURCES'
|
||||
const capturerResult = (id) => `ELECTRON_RENDERER_DESKTOP_CAPTURER_RESULT_${id}`
|
||||
|
||||
ipcMain.on(electronSources, (event, captureWindow, captureScreen, thumbnailSize, id) => {
|
||||
ipcMain.on(electronSources, (event, captureWindow, captureScreen, thumbnailSize, fetchWindowIcons, id) => {
|
||||
const customEvent = eventBinding.createWithSender(event.sender)
|
||||
event.sender.emit('desktop-capturer-get-sources', customEvent)
|
||||
|
||||
if (customEvent.defaultPrevented) {
|
||||
event._replyInternal(capturerResult(id), [])
|
||||
return
|
||||
}
|
||||
|
||||
const request = {
|
||||
id,
|
||||
options: {
|
||||
captureWindow,
|
||||
captureScreen,
|
||||
thumbnailSize
|
||||
thumbnailSize,
|
||||
fetchWindowIcons
|
||||
},
|
||||
webContents: event.sender
|
||||
event
|
||||
}
|
||||
requestsQueue.push(request)
|
||||
if (requestsQueue.length === 1) {
|
||||
desktopCapturer.startHandling(captureWindow, captureScreen, thumbnailSize)
|
||||
desktopCapturer.startHandling(captureWindow, captureScreen, thumbnailSize, fetchWindowIcons)
|
||||
}
|
||||
|
||||
// If the WebContents is destroyed before receiving result, just remove the
|
||||
// reference from requestsQueue to make the module not send the result to it.
|
||||
event.sender.once('destroyed', () => {
|
||||
request.webContents = null
|
||||
request.event = null
|
||||
})
|
||||
})
|
||||
|
||||
desktopCapturer.emit = (event, name, sources) => {
|
||||
desktopCapturer.emit = (event, name, sources, fetchWindowIcons) => {
|
||||
// Receiving sources result from main process, now send them back to renderer.
|
||||
const handledRequest = requestsQueue.shift()
|
||||
const handledWebContents = handledRequest.webContents
|
||||
const unhandledRequestsQueue = []
|
||||
|
||||
const result = sources.map(source => {
|
||||
|
@ -44,20 +54,21 @@ desktopCapturer.emit = (event, name, sources) => {
|
|||
id: source.id,
|
||||
name: source.name,
|
||||
thumbnail: source.thumbnail.toDataURL(),
|
||||
display_id: source.display_id
|
||||
display_id: source.display_id,
|
||||
appIcon: (fetchWindowIcons && source.appIcon) ? source.appIcon.toDataURL() : null
|
||||
}
|
||||
})
|
||||
|
||||
if (handledWebContents) {
|
||||
handledWebContents._sendInternal(capturerResult(handledRequest.id), result)
|
||||
if (handledRequest.event) {
|
||||
handledRequest.event._replyInternal(capturerResult(handledRequest.id), result)
|
||||
}
|
||||
|
||||
// Check the queue to see whether there is another identical request & handle
|
||||
requestsQueue.forEach(request => {
|
||||
const webContents = request.webContents
|
||||
const event = request.event
|
||||
if (deepEqual(handledRequest.options, request.options)) {
|
||||
if (webContents) {
|
||||
webContents._sendInternal(capturerResult(request.id), result)
|
||||
if (event) {
|
||||
event._replyInternal(capturerResult(request.id), result)
|
||||
}
|
||||
} else {
|
||||
unhandledRequestsQueue.push(request)
|
||||
|
@ -67,7 +78,7 @@ desktopCapturer.emit = (event, name, sources) => {
|
|||
|
||||
// If the requestsQueue is not empty, start a new request handling.
|
||||
if (requestsQueue.length > 0) {
|
||||
const { captureWindow, captureScreen, thumbnailSize } = requestsQueue[0].options
|
||||
return desktopCapturer.startHandling(captureWindow, captureScreen, thumbnailSize)
|
||||
const { captureWindow, captureScreen, thumbnailSize, fetchWindowIcons } = requestsQueue[0].options
|
||||
return desktopCapturer.startHandling(captureWindow, captureScreen, thumbnailSize, fetchWindowIcons)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,6 +4,11 @@ const { webContents } = require('electron')
|
|||
const ipcMain = require('@electron/internal/browser/ipc-main-internal')
|
||||
const parseFeaturesString = require('@electron/internal/common/parse-features-string')
|
||||
const errorUtils = require('@electron/internal/common/error-utils')
|
||||
const {
|
||||
syncMethods,
|
||||
asyncCallbackMethods,
|
||||
asyncPromiseMethods
|
||||
} = require('@electron/internal/common/web-view-methods')
|
||||
|
||||
// Doesn't exist in early initialization.
|
||||
let webViewManager = null
|
||||
|
@ -158,14 +163,6 @@ const createGuest = function (embedder, params) {
|
|||
}
|
||||
}
|
||||
})
|
||||
guest.on('-web-contents-created', (...args) => {
|
||||
if (guest.getLastWebPreferences().nativeWindowOpen === true) {
|
||||
const embedder = getEmbedder(guestInstanceId)
|
||||
if (embedder != null) {
|
||||
embedder.emit('-web-contents-created', ...args)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
return guestInstanceId
|
||||
}
|
||||
|
@ -184,16 +181,19 @@ const attachGuest = function (event, embedderFrameId, elementInstanceId, guestIn
|
|||
|
||||
const oldGuestInstance = guestInstances[oldGuestInstanceId]
|
||||
if (oldGuestInstance) {
|
||||
oldGuestInstance.guest.destroy()
|
||||
oldGuestInstance.guest.detachFromOuterFrame()
|
||||
}
|
||||
}
|
||||
|
||||
const guestInstance = guestInstances[guestInstanceId]
|
||||
// If this isn't a valid guest instance then do nothing.
|
||||
if (!guestInstance) {
|
||||
return
|
||||
throw new Error(`Invalid guestInstanceId: ${guestInstanceId}`)
|
||||
}
|
||||
const { guest } = guestInstance
|
||||
if (guest.hostWebContents !== event.sender) {
|
||||
throw new Error(`Access denied to guestInstanceId: ${guestInstanceId}`)
|
||||
}
|
||||
|
||||
// If this guest is already attached to an element then remove it
|
||||
if (guestInstance.elementInstanceId) {
|
||||
|
@ -212,7 +212,7 @@ const attachGuest = function (event, embedderFrameId, elementInstanceId, guestIn
|
|||
nodeIntegration: params.nodeintegration != null ? params.nodeintegration : false,
|
||||
enableRemoteModule: params.enableremotemodule,
|
||||
plugins: params.plugins,
|
||||
zoomFactor: embedder._getZoomFactor(),
|
||||
zoomFactor: embedder.getZoomFactor(),
|
||||
webSecurity: !params.disablewebsecurity,
|
||||
enableBlinkFeatures: params.blinkfeatures,
|
||||
disableBlinkFeatures: params.disableblinkfeatures
|
||||
|
@ -246,7 +246,8 @@ const attachGuest = function (event, embedderFrameId, elementInstanceId, guestIn
|
|||
['nativeWindowOpen', true],
|
||||
['nodeIntegration', false],
|
||||
['enableRemoteModule', false],
|
||||
['sandbox', true]
|
||||
['sandbox', true],
|
||||
['nodeIntegrationInSubFrames', false]
|
||||
])
|
||||
|
||||
// Inherit certain option values from embedder
|
||||
|
@ -332,8 +333,8 @@ const isWebViewTagEnabledCache = new WeakMap()
|
|||
|
||||
const isWebViewTagEnabled = function (contents) {
|
||||
if (!isWebViewTagEnabledCache.has(contents)) {
|
||||
const value = contents.getLastWebPreferences().webviewTag
|
||||
isWebViewTagEnabledCache.set(contents, value)
|
||||
const webPreferences = contents.getLastWebPreferences() || {}
|
||||
isWebViewTagEnabledCache.set(contents, !!webPreferences.webviewTag)
|
||||
}
|
||||
|
||||
return isWebViewTagEnabledCache.get(contents)
|
||||
|
@ -350,7 +351,7 @@ const handleMessage = function (channel, handler) {
|
|||
}
|
||||
|
||||
handleMessage('ELECTRON_GUEST_VIEW_MANAGER_CREATE_GUEST', function (event, params, requestId) {
|
||||
event.sender._sendInternal(`ELECTRON_RESPONSE_${requestId}`, createGuest(event.sender, params))
|
||||
event._replyInternal(`ELECTRON_RESPONSE_${requestId}`, createGuest(event.sender, params))
|
||||
})
|
||||
|
||||
handleMessage('ELECTRON_GUEST_VIEW_MANAGER_CREATE_GUEST_SYNC', function (event, params) {
|
||||
|
@ -358,25 +359,37 @@ handleMessage('ELECTRON_GUEST_VIEW_MANAGER_CREATE_GUEST_SYNC', function (event,
|
|||
})
|
||||
|
||||
handleMessage('ELECTRON_GUEST_VIEW_MANAGER_DESTROY_GUEST', function (event, guestInstanceId) {
|
||||
const guest = getGuest(guestInstanceId)
|
||||
if (guest) {
|
||||
guest.destroy()
|
||||
try {
|
||||
const guest = getGuestForWebContents(guestInstanceId, event.sender)
|
||||
guest.detachFromOuterFrame()
|
||||
} catch (error) {
|
||||
console.error(`Guest destroy failed: ${error}`)
|
||||
}
|
||||
})
|
||||
|
||||
handleMessage('ELECTRON_GUEST_VIEW_MANAGER_ATTACH_GUEST', function (event, embedderFrameId, elementInstanceId, guestInstanceId, params) {
|
||||
attachGuest(event, embedderFrameId, elementInstanceId, guestInstanceId, params)
|
||||
try {
|
||||
attachGuest(event, embedderFrameId, elementInstanceId, guestInstanceId, params)
|
||||
} catch (error) {
|
||||
console.error(`Guest attach failed: ${error}`)
|
||||
}
|
||||
})
|
||||
|
||||
handleMessage('ELECTRON_GUEST_VIEW_MANAGER_FOCUS_CHANGE', function (event, focus, guestInstanceId) {
|
||||
event.sender.emit('focus-change', {}, focus, guestInstanceId)
|
||||
// this message is sent by the actual <webview>
|
||||
ipcMain.on('ELECTRON_GUEST_VIEW_MANAGER_FOCUS_CHANGE', function (event, focus, guestInstanceId) {
|
||||
const guest = getGuest(guestInstanceId)
|
||||
if (guest === event.sender) {
|
||||
event.sender.emit('focus-change', {}, focus, guestInstanceId)
|
||||
} else {
|
||||
console.error(`focus-change for guestInstanceId: ${guestInstanceId}`)
|
||||
}
|
||||
})
|
||||
|
||||
handleMessage('ELECTRON_GUEST_VIEW_MANAGER_ASYNC_CALL', function (event, requestId, guestInstanceId, method, args, hasCallback) {
|
||||
new Promise(resolve => {
|
||||
const guest = getGuest(guestInstanceId)
|
||||
if (guest.hostWebContents !== event.sender) {
|
||||
throw new Error('Access denied')
|
||||
const guest = getGuestForWebContents(guestInstanceId, event.sender)
|
||||
if (!asyncCallbackMethods.has(method) && !asyncPromiseMethods.has(method)) {
|
||||
throw new Error(`Invalid method: ${method}`)
|
||||
}
|
||||
if (hasCallback) {
|
||||
guest[method](...args, resolve)
|
||||
|
@ -388,22 +401,34 @@ handleMessage('ELECTRON_GUEST_VIEW_MANAGER_ASYNC_CALL', function (event, request
|
|||
}, error => {
|
||||
return [errorUtils.serialize(error)]
|
||||
}).then(responseArgs => {
|
||||
event.sender._sendInternal(`ELECTRON_GUEST_VIEW_MANAGER_ASYNC_CALL_RESPONSE_${requestId}`, ...responseArgs)
|
||||
event._replyInternal(`ELECTRON_GUEST_VIEW_MANAGER_ASYNC_CALL_RESPONSE_${requestId}`, ...responseArgs)
|
||||
})
|
||||
})
|
||||
|
||||
handleMessage('ELECTRON_GUEST_VIEW_MANAGER_SYNC_CALL', function (event, guestInstanceId, method, args) {
|
||||
try {
|
||||
const guest = getGuest(guestInstanceId)
|
||||
if (guest.hostWebContents !== event.sender) {
|
||||
throw new Error('Access denied')
|
||||
const guest = getGuestForWebContents(guestInstanceId, event.sender)
|
||||
if (!syncMethods.has(method)) {
|
||||
throw new Error(`Invalid method: ${method}`)
|
||||
}
|
||||
event.returnValue = [null, guest[method].apply(guest, args)]
|
||||
event.returnValue = [null, guest[method](...args)]
|
||||
} catch (error) {
|
||||
event.returnValue = [errorUtils.serialize(error)]
|
||||
}
|
||||
})
|
||||
|
||||
// Returns WebContents from its guest id hosted in given webContents.
|
||||
const getGuestForWebContents = function (guestInstanceId, contents) {
|
||||
const guest = getGuest(guestInstanceId)
|
||||
if (!guest) {
|
||||
throw new Error(`Invalid guestInstanceId: ${guestInstanceId}`)
|
||||
}
|
||||
if (guest.hostWebContents !== contents) {
|
||||
throw new Error(`Access denied to guestInstanceId: ${guestInstanceId}`)
|
||||
}
|
||||
return guest
|
||||
}
|
||||
|
||||
// Returns WebContents from its guest id.
|
||||
const getGuest = function (guestInstanceId) {
|
||||
const guestInstance = guestInstances[guestInstanceId]
|
||||
|
@ -416,5 +441,5 @@ const getEmbedder = function (guestInstanceId) {
|
|||
if (guestInstance != null) return guestInstance.embedder
|
||||
}
|
||||
|
||||
exports.getGuest = getGuest
|
||||
exports.getEmbedder = getEmbedder
|
||||
exports.getGuestForWebContents = getGuestForWebContents
|
||||
exports.isWebViewTagEnabled = isWebViewTagEnabled
|
||||
|
|
|
@ -16,7 +16,8 @@ const inheritedWebPreferences = new Map([
|
|||
['nodeIntegration', false],
|
||||
['enableRemoteModule', false],
|
||||
['sandbox', true],
|
||||
['webviewTag', false]
|
||||
['webviewTag', false],
|
||||
['nodeIntegrationInSubFrames', false]
|
||||
])
|
||||
|
||||
// Copy attribute of |parent| to |child| if it is not defined in |child|.
|
||||
|
@ -90,9 +91,9 @@ const setupGuest = function (embedder, frameName, guest, options) {
|
|||
}
|
||||
const closedByUser = function () {
|
||||
embedder._sendInternal('ELECTRON_GUEST_WINDOW_MANAGER_WINDOW_CLOSED_' + guestId)
|
||||
embedder.removeListener('render-view-deleted', closedByEmbedder)
|
||||
embedder.removeListener('current-render-view-deleted', closedByEmbedder)
|
||||
}
|
||||
embedder.once('render-view-deleted', closedByEmbedder)
|
||||
embedder.once('current-render-view-deleted', closedByEmbedder)
|
||||
guest.once('closed', closedByUser)
|
||||
if (frameName) {
|
||||
frameToGuest.set(frameName, guest)
|
||||
|
@ -118,28 +119,12 @@ const createGuest = function (embedder, url, referrer, frameName, options, postD
|
|||
}
|
||||
|
||||
guest = new BrowserWindow(options)
|
||||
if (!options.webContents || url !== 'about:blank') {
|
||||
if (!options.webContents) {
|
||||
// We should not call `loadURL` if the window was constructed from an
|
||||
// existing webContents(window.open in a sandboxed renderer) and if the url
|
||||
// is not 'about:blank'.
|
||||
// existing webContents (window.open in a sandboxed renderer).
|
||||
//
|
||||
// Navigating to the url when creating the window from an existing
|
||||
// webContents would not be necessary(it will navigate there anyway), but
|
||||
// apparently there's a bug that allows the child window to be scripted by
|
||||
// the opener, even when the child window is from another origin.
|
||||
//
|
||||
// That's why the second condition(url !== "about:blank") is required: to
|
||||
// force `OverrideSiteInstanceForNavigation` to be called and consequently
|
||||
// spawn a new renderer if the new window is targeting a different origin.
|
||||
//
|
||||
// If the URL is "about:blank", then it is very likely that the opener just
|
||||
// wants to synchronously script the popup, for example:
|
||||
//
|
||||
// let popup = window.open()
|
||||
// popup.document.body.write('<h1>hello</h1>')
|
||||
//
|
||||
// The above code would not work if a navigation to "about:blank" is done
|
||||
// here, since the window would be cleared of all changes in the next tick.
|
||||
// webContents is not necessary (it will navigate there anyway).
|
||||
const loadOptions = {
|
||||
httpReferrer: referrer
|
||||
}
|
||||
|
@ -288,6 +273,11 @@ ipcMain.on('ELECTRON_GUEST_WINDOW_MANAGER_WINDOW_CLOSE', function (event, guestI
|
|||
if (guestWindow != null) guestWindow.destroy()
|
||||
})
|
||||
|
||||
const windowMethods = new Set([
|
||||
'focus',
|
||||
'blur'
|
||||
])
|
||||
|
||||
ipcMain.on('ELECTRON_GUEST_WINDOW_MANAGER_WINDOW_METHOD', function (event, guestId, method, ...args) {
|
||||
const guestContents = webContents.fromId(guestId)
|
||||
if (guestContents == null) {
|
||||
|
@ -295,7 +285,7 @@ ipcMain.on('ELECTRON_GUEST_WINDOW_MANAGER_WINDOW_METHOD', function (event, guest
|
|||
return
|
||||
}
|
||||
|
||||
if (!canAccessWindow(event.sender, guestContents)) {
|
||||
if (!canAccessWindow(event.sender, guestContents) || !windowMethods.has(method)) {
|
||||
console.error(`Blocked ${event.sender.getURL()} from calling ${method} on its opener.`)
|
||||
event.returnValue = null
|
||||
return
|
||||
|
@ -326,17 +316,27 @@ ipcMain.on('ELECTRON_GUEST_WINDOW_MANAGER_WINDOW_POSTMESSAGE', function (event,
|
|||
}
|
||||
})
|
||||
|
||||
const webContentsMethods = new Set([
|
||||
'print',
|
||||
'executeJavaScript'
|
||||
])
|
||||
|
||||
ipcMain.on('ELECTRON_GUEST_WINDOW_MANAGER_WEB_CONTENTS_METHOD', function (event, guestId, method, ...args) {
|
||||
const guestContents = webContents.fromId(guestId)
|
||||
if (guestContents == null) return
|
||||
|
||||
if (canAccessWindow(event.sender, guestContents)) {
|
||||
if (canAccessWindow(event.sender, guestContents) && webContentsMethods.has(method)) {
|
||||
guestContents[method](...args)
|
||||
} else {
|
||||
console.error(`Blocked ${event.sender.getURL()} from calling ${method} on its opener.`)
|
||||
}
|
||||
})
|
||||
|
||||
const webContentsSyncMethods = new Set([
|
||||
'getURL',
|
||||
'loadURL'
|
||||
])
|
||||
|
||||
ipcMain.on('ELECTRON_GUEST_WINDOW_MANAGER_WEB_CONTENTS_METHOD_SYNC', function (event, guestId, method, ...args) {
|
||||
const guestContents = webContents.fromId(guestId)
|
||||
if (guestContents == null) {
|
||||
|
@ -344,7 +344,7 @@ ipcMain.on('ELECTRON_GUEST_WINDOW_MANAGER_WEB_CONTENTS_METHOD_SYNC', function (e
|
|||
return
|
||||
}
|
||||
|
||||
if (canAccessWindow(event.sender, guestContents)) {
|
||||
if (canAccessWindow(event.sender, guestContents) && webContentsSyncMethods.has(method)) {
|
||||
event.returnValue = guestContents[method](...args)
|
||||
} else {
|
||||
console.error(`Blocked ${event.sender.getURL()} from calling ${method} on its opener.`)
|
||||
|
|
|
@ -184,5 +184,17 @@ if (currentPlatformSupportsAppIndicator()) {
|
|||
process.env.XDG_CURRENT_DESKTOP = 'Unity'
|
||||
}
|
||||
|
||||
// Quit when all windows are closed and no other one is listening to this.
|
||||
app.on('window-all-closed', () => {
|
||||
if (app.listenerCount('window-all-closed') === 1) {
|
||||
app.quit()
|
||||
}
|
||||
})
|
||||
|
||||
const { setDefaultApplicationMenu } = require('@electron/internal/browser/default-menu')
|
||||
|
||||
// Create default menu.
|
||||
app.once('ready', setDefaultApplicationMenu)
|
||||
|
||||
// Finally load app's main.js and transfer control to C++.
|
||||
Module._load(path.join(packagePath, mainStartupScript), Module, true)
|
||||
|
|
|
@ -3,12 +3,20 @@
|
|||
const ipcMain = require('@electron/internal/browser/ipc-main-internal')
|
||||
|
||||
// The history operation in renderer is redirected to browser.
|
||||
ipcMain.on('ELECTRON_NAVIGATION_CONTROLLER', function (event, method, ...args) {
|
||||
event.sender[method](...args)
|
||||
ipcMain.on('ELECTRON_NAVIGATION_CONTROLLER_GO_BACK', function (event) {
|
||||
event.sender.goBack()
|
||||
})
|
||||
|
||||
ipcMain.on('ELECTRON_SYNC_NAVIGATION_CONTROLLER', function (event, method, ...args) {
|
||||
event.returnValue = event.sender[method](...args)
|
||||
ipcMain.on('ELECTRON_NAVIGATION_CONTROLLER_GO_FORWARD', function (event) {
|
||||
event.sender.goForward()
|
||||
})
|
||||
|
||||
ipcMain.on('ELECTRON_NAVIGATION_CONTROLLER_GO_TO_OFFSET', function (event, offset) {
|
||||
event.sender.goToOffset(offset)
|
||||
})
|
||||
|
||||
ipcMain.on('ELECTRON_NAVIGATION_CONTROLLER_LENGTH', function (event) {
|
||||
event.returnValue = event.sender.length()
|
||||
})
|
||||
|
||||
// JavaScript implementation of Chromium's NavigationController.
|
||||
|
@ -55,9 +63,66 @@ const NavigationController = (function () {
|
|||
if (options == null) {
|
||||
options = {}
|
||||
}
|
||||
const p = new Promise((resolve, reject) => {
|
||||
const resolveAndCleanup = () => {
|
||||
removeListeners()
|
||||
resolve()
|
||||
}
|
||||
const rejectAndCleanup = (errorCode, errorDescription, url) => {
|
||||
const err = new Error(`${errorDescription} (${errorCode}) loading '${url}'`)
|
||||
Object.assign(err, { errno: errorCode, code: errorDescription, url })
|
||||
removeListeners()
|
||||
reject(err)
|
||||
}
|
||||
const finishListener = () => {
|
||||
resolveAndCleanup()
|
||||
}
|
||||
const failListener = (event, errorCode, errorDescription, validatedURL, isMainFrame, frameProcessId, frameRoutingId) => {
|
||||
if (isMainFrame) {
|
||||
rejectAndCleanup(errorCode, errorDescription, validatedURL)
|
||||
}
|
||||
}
|
||||
|
||||
let navigationStarted = false
|
||||
const navigationListener = (event, url, isSameDocument, isMainFrame, frameProcessId, frameRoutingId, navigationId) => {
|
||||
if (isMainFrame) {
|
||||
if (navigationStarted) {
|
||||
// the webcontents has started another unrelated navigation in the
|
||||
// main frame (probably from the app calling `loadURL` again); reject
|
||||
// the promise
|
||||
return rejectAndCleanup(-3, 'ERR_ABORTED', url)
|
||||
}
|
||||
navigationStarted = true
|
||||
}
|
||||
}
|
||||
const stopLoadingListener = () => {
|
||||
// By the time we get here, either 'finish' or 'fail' should have fired
|
||||
// if the navigation occurred. However, in some situations (e.g. when
|
||||
// attempting to load a page with a bad scheme), loading will stop
|
||||
// without emitting finish or fail. In this case, we reject the promise
|
||||
// with a generic failure.
|
||||
// TODO(jeremy): enumerate all the cases in which this can happen. If
|
||||
// the only one is with a bad scheme, perhaps ERR_INVALID_ARGUMENT
|
||||
// would be more appropriate.
|
||||
rejectAndCleanup(-2, 'ERR_FAILED', url)
|
||||
}
|
||||
const removeListeners = () => {
|
||||
this.webContents.removeListener('did-finish-load', finishListener)
|
||||
this.webContents.removeListener('did-fail-load', failListener)
|
||||
this.webContents.removeListener('did-start-navigation', navigationListener)
|
||||
this.webContents.removeListener('did-stop-loading', stopLoadingListener)
|
||||
}
|
||||
this.webContents.on('did-finish-load', finishListener)
|
||||
this.webContents.on('did-fail-load', failListener)
|
||||
this.webContents.on('did-start-navigation', navigationListener)
|
||||
this.webContents.on('did-stop-loading', stopLoadingListener)
|
||||
})
|
||||
// Add a no-op rejection handler to silence the unhandled rejection error.
|
||||
p.catch(() => {})
|
||||
this.pendingIndex = -1
|
||||
this.webContents._loadURL(url, options)
|
||||
return this.webContents.emit('load-url', url, options)
|
||||
this.webContents.emit('load-url', url, options)
|
||||
return p
|
||||
}
|
||||
|
||||
NavigationController.prototype.getURL = function () {
|
|
@ -13,6 +13,7 @@ const { isPromise } = electron
|
|||
|
||||
const ipcMain = require('@electron/internal/browser/ipc-main-internal')
|
||||
const objectsRegistry = require('@electron/internal/browser/objects-registry')
|
||||
const guestViewManager = require('@electron/internal/browser/guest-view-manager')
|
||||
const bufferUtils = require('@electron/internal/common/buffer-utils')
|
||||
const errorUtils = require('@electron/internal/common/error-utils')
|
||||
|
||||
|
@ -138,7 +139,7 @@ const plainObjectToMeta = function (obj) {
|
|||
}
|
||||
|
||||
// Convert Error into meta data.
|
||||
const exceptionToMeta = function (sender, contextId, error) {
|
||||
const exceptionToMeta = function (error) {
|
||||
return {
|
||||
type: 'exception',
|
||||
value: errorUtils.serialize(error)
|
||||
|
@ -174,7 +175,7 @@ const removeRemoteListenersAndLogWarning = (sender, callIntoRenderer) => {
|
|||
}
|
||||
|
||||
// Convert array of meta data from renderer into array of real values.
|
||||
const unwrapArgs = function (sender, contextId, args) {
|
||||
const unwrapArgs = function (sender, frameId, contextId, args) {
|
||||
const metaToValue = function (meta) {
|
||||
switch (meta.type) {
|
||||
case 'value':
|
||||
|
@ -182,7 +183,7 @@ const unwrapArgs = function (sender, contextId, args) {
|
|||
case 'remote-object':
|
||||
return objectsRegistry.get(meta.id)
|
||||
case 'array':
|
||||
return unwrapArgs(sender, contextId, meta.value)
|
||||
return unwrapArgs(sender, frameId, contextId, meta.value)
|
||||
case 'buffer':
|
||||
return bufferUtils.metaToBuffer(meta.value)
|
||||
case 'date':
|
||||
|
@ -216,9 +217,11 @@ const unwrapArgs = function (sender, contextId, args) {
|
|||
}
|
||||
|
||||
const callIntoRenderer = function (...args) {
|
||||
let succeed = false
|
||||
if (!sender.isDestroyed()) {
|
||||
sender._sendInternal('ELECTRON_RENDERER_CALLBACK', contextId, meta.id, valueToMeta(sender, contextId, args))
|
||||
} else {
|
||||
succeed = sender._sendToFrameInternal(frameId, 'ELECTRON_RENDERER_CALLBACK', contextId, meta.id, valueToMeta(sender, contextId, args))
|
||||
}
|
||||
if (!succeed) {
|
||||
removeRemoteListenersAndLogWarning(this, callIntoRenderer)
|
||||
}
|
||||
}
|
||||
|
@ -273,7 +276,7 @@ const handleRemoteCommand = function (channel, handler) {
|
|||
try {
|
||||
returnValue = handler(event, contextId, ...args)
|
||||
} catch (error) {
|
||||
returnValue = exceptionToMeta(event.sender, contextId, error)
|
||||
returnValue = exceptionToMeta(error)
|
||||
}
|
||||
|
||||
if (returnValue !== undefined) {
|
||||
|
@ -295,46 +298,79 @@ handleRemoteCommand('ELECTRON_BROWSER_REQUIRE', function (event, contextId, modu
|
|||
const customEvent = eventBinding.createWithSender(event.sender)
|
||||
event.sender.emit('remote-require', customEvent, moduleName)
|
||||
|
||||
if (customEvent.defaultPrevented) {
|
||||
if (typeof customEvent.returnValue === 'undefined') {
|
||||
throw new Error(`Invalid module: ${moduleName}`)
|
||||
if (customEvent.returnValue === undefined) {
|
||||
if (customEvent.defaultPrevented) {
|
||||
throw new Error(`Blocked remote.require('${moduleName}')`)
|
||||
} else {
|
||||
customEvent.returnValue = process.mainModule.require(moduleName)
|
||||
}
|
||||
} else {
|
||||
customEvent.returnValue = process.mainModule.require(moduleName)
|
||||
}
|
||||
|
||||
return valueToMeta(event.sender, contextId, customEvent.returnValue)
|
||||
})
|
||||
|
||||
handleRemoteCommand('ELECTRON_BROWSER_GET_BUILTIN', function (event, contextId, module) {
|
||||
return valueToMeta(event.sender, contextId, electron[module])
|
||||
handleRemoteCommand('ELECTRON_BROWSER_GET_BUILTIN', function (event, contextId, moduleName) {
|
||||
const customEvent = eventBinding.createWithSender(event.sender)
|
||||
event.sender.emit('remote-get-builtin', customEvent, moduleName)
|
||||
|
||||
if (customEvent.returnValue === undefined) {
|
||||
if (customEvent.defaultPrevented) {
|
||||
throw new Error(`Blocked remote.getBuiltin('${moduleName}')`)
|
||||
} else {
|
||||
customEvent.returnValue = electron[moduleName]
|
||||
}
|
||||
}
|
||||
|
||||
return valueToMeta(event.sender, contextId, customEvent.returnValue)
|
||||
})
|
||||
|
||||
handleRemoteCommand('ELECTRON_BROWSER_GLOBAL', function (event, contextId, globalName) {
|
||||
const customEvent = eventBinding.createWithSender(event.sender)
|
||||
event.sender.emit('remote-get-global', customEvent, globalName)
|
||||
|
||||
if (customEvent.defaultPrevented) {
|
||||
if (typeof customEvent.returnValue === 'undefined') {
|
||||
throw new Error(`Invalid global: ${globalName}`)
|
||||
if (customEvent.returnValue === undefined) {
|
||||
if (customEvent.defaultPrevented) {
|
||||
throw new Error(`Blocked remote.getGlobal('${globalName}')`)
|
||||
} else {
|
||||
customEvent.returnValue = global[globalName]
|
||||
}
|
||||
} else {
|
||||
customEvent.returnValue = global[globalName]
|
||||
}
|
||||
|
||||
return valueToMeta(event.sender, contextId, customEvent.returnValue)
|
||||
})
|
||||
|
||||
handleRemoteCommand('ELECTRON_BROWSER_CURRENT_WINDOW', function (event, contextId) {
|
||||
return valueToMeta(event.sender, contextId, event.sender.getOwnerBrowserWindow())
|
||||
const customEvent = eventBinding.createWithSender(event.sender)
|
||||
event.sender.emit('remote-get-current-window', customEvent)
|
||||
|
||||
if (customEvent.returnValue === undefined) {
|
||||
if (customEvent.defaultPrevented) {
|
||||
throw new Error('Blocked remote.getCurrentWindow()')
|
||||
} else {
|
||||
customEvent.returnValue = event.sender.getOwnerBrowserWindow()
|
||||
}
|
||||
}
|
||||
|
||||
return valueToMeta(event.sender, contextId, customEvent.returnValue)
|
||||
})
|
||||
|
||||
handleRemoteCommand('ELECTRON_BROWSER_CURRENT_WEB_CONTENTS', function (event, contextId) {
|
||||
return valueToMeta(event.sender, contextId, event.sender)
|
||||
const customEvent = eventBinding.createWithSender(event.sender)
|
||||
event.sender.emit('remote-get-current-web-contents', customEvent)
|
||||
|
||||
if (customEvent.returnValue === undefined) {
|
||||
if (customEvent.defaultPrevented) {
|
||||
throw new Error('Blocked remote.getCurrentWebContents()')
|
||||
} else {
|
||||
customEvent.returnValue = event.sender
|
||||
}
|
||||
}
|
||||
|
||||
return valueToMeta(event.sender, contextId, customEvent.returnValue)
|
||||
})
|
||||
|
||||
handleRemoteCommand('ELECTRON_BROWSER_CONSTRUCTOR', function (event, contextId, id, args) {
|
||||
args = unwrapArgs(event.sender, contextId, args)
|
||||
args = unwrapArgs(event.sender, event.frameId, contextId, args)
|
||||
const constructor = objectsRegistry.get(id)
|
||||
|
||||
if (constructor == null) {
|
||||
|
@ -345,7 +381,7 @@ handleRemoteCommand('ELECTRON_BROWSER_CONSTRUCTOR', function (event, contextId,
|
|||
})
|
||||
|
||||
handleRemoteCommand('ELECTRON_BROWSER_FUNCTION_CALL', function (event, contextId, id, args) {
|
||||
args = unwrapArgs(event.sender, contextId, args)
|
||||
args = unwrapArgs(event.sender, event.frameId, contextId, args)
|
||||
const func = objectsRegistry.get(id)
|
||||
|
||||
if (func == null) {
|
||||
|
@ -356,7 +392,7 @@ handleRemoteCommand('ELECTRON_BROWSER_FUNCTION_CALL', function (event, contextId
|
|||
})
|
||||
|
||||
handleRemoteCommand('ELECTRON_BROWSER_MEMBER_CONSTRUCTOR', function (event, contextId, id, method, args) {
|
||||
args = unwrapArgs(event.sender, contextId, args)
|
||||
args = unwrapArgs(event.sender, event.frameId, contextId, args)
|
||||
const object = objectsRegistry.get(id)
|
||||
|
||||
if (object == null) {
|
||||
|
@ -367,7 +403,7 @@ handleRemoteCommand('ELECTRON_BROWSER_MEMBER_CONSTRUCTOR', function (event, cont
|
|||
})
|
||||
|
||||
handleRemoteCommand('ELECTRON_BROWSER_MEMBER_CALL', function (event, contextId, id, method, args) {
|
||||
args = unwrapArgs(event.sender, contextId, args)
|
||||
args = unwrapArgs(event.sender, event.frameId, contextId, args)
|
||||
const obj = objectsRegistry.get(id)
|
||||
|
||||
if (obj == null) {
|
||||
|
@ -378,7 +414,7 @@ handleRemoteCommand('ELECTRON_BROWSER_MEMBER_CALL', function (event, contextId,
|
|||
})
|
||||
|
||||
handleRemoteCommand('ELECTRON_BROWSER_MEMBER_SET', function (event, contextId, id, name, args) {
|
||||
args = unwrapArgs(event.sender, contextId, args)
|
||||
args = unwrapArgs(event.sender, event.frameId, contextId, args)
|
||||
const obj = objectsRegistry.get(id)
|
||||
|
||||
if (obj == null) {
|
||||
|
@ -409,8 +445,20 @@ handleRemoteCommand('ELECTRON_BROWSER_CONTEXT_RELEASE', (event, contextId) => {
|
|||
})
|
||||
|
||||
handleRemoteCommand('ELECTRON_BROWSER_GUEST_WEB_CONTENTS', function (event, contextId, guestInstanceId) {
|
||||
const guestViewManager = require('@electron/internal/browser/guest-view-manager')
|
||||
return valueToMeta(event.sender, contextId, guestViewManager.getGuest(guestInstanceId))
|
||||
const guest = guestViewManager.getGuestForWebContents(guestInstanceId, event.sender)
|
||||
|
||||
const customEvent = eventBinding.createWithSender(event.sender)
|
||||
event.sender.emit('remote-get-guest-web-contents', customEvent, guest)
|
||||
|
||||
if (customEvent.returnValue === undefined) {
|
||||
if (customEvent.defaultPrevented) {
|
||||
throw new Error(`Blocked remote.getGuestForWebContents()`)
|
||||
} else {
|
||||
customEvent.returnValue = guest
|
||||
}
|
||||
}
|
||||
|
||||
return valueToMeta(event.sender, contextId, customEvent.returnValue)
|
||||
})
|
||||
|
||||
// Implements window.close()
|
||||
|
@ -486,27 +534,40 @@ ipcMain.on('ELECTRON_BROWSER_CLIPBOARD_WRITE_FIND_TEXT', function (event, text)
|
|||
setReturnValue(event, () => electron.clipboard.writeFindText(text))
|
||||
})
|
||||
|
||||
ipcMain.on('ELECTRON_BROWSER_SANDBOX_LOAD', function (event) {
|
||||
const preloadPath = event.sender._getPreloadPath()
|
||||
const getPreloadScript = function (preloadPath) {
|
||||
let preloadSrc = null
|
||||
let preloadError = null
|
||||
if (preloadPath) {
|
||||
try {
|
||||
preloadSrc = fs.readFileSync(preloadPath).toString()
|
||||
} catch (err) {
|
||||
preloadError = { stack: err ? err.stack : (new Error(`Failed to load "${preloadPath}"`)).stack }
|
||||
preloadError = errorUtils.serialize(err)
|
||||
}
|
||||
}
|
||||
return { preloadPath, preloadSrc, preloadError }
|
||||
}
|
||||
|
||||
ipcMain.on('ELECTRON_BROWSER_SANDBOX_LOAD', function (event) {
|
||||
const preloadPaths = [
|
||||
...(event.sender.session ? event.sender.session.getPreloads() : []),
|
||||
event.sender._getPreloadPath()
|
||||
]
|
||||
|
||||
event.returnValue = {
|
||||
preloadSrc,
|
||||
preloadError,
|
||||
preloadScripts: preloadPaths.map(path => getPreloadScript(path)),
|
||||
isRemoteModuleEnabled: event.sender._isRemoteModuleEnabled(),
|
||||
isWebViewTagEnabled: guestViewManager.isWebViewTagEnabled(event.sender),
|
||||
process: {
|
||||
arch: process.arch,
|
||||
platform: process.platform,
|
||||
env: process.env,
|
||||
version: process.version,
|
||||
versions: process.versions
|
||||
versions: process.versions,
|
||||
execPath: process.helperExecPath
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
ipcMain.on('ELECTRON_BROWSER_PRELOAD_ERROR', function (event, preloadPath, error) {
|
||||
event.sender.emit('preload-error', event, preloadPath, errorUtils.deserialize(error))
|
||||
})
|
||||
|
|
|
@ -2,8 +2,8 @@
|
|||
|
||||
if (process.platform === 'linux' && process.type === 'renderer') {
|
||||
// On Linux we could not access clipboard in renderer process.
|
||||
const { getRemoteForUsage } = require('@electron/internal/renderer/remote')
|
||||
module.exports = getRemoteForUsage('clipboard').clipboard
|
||||
const { getRemote } = require('@electron/internal/renderer/remote')
|
||||
module.exports = getRemote('clipboard')
|
||||
} else {
|
||||
const clipboard = process.atomBinding('clipboard')
|
||||
|
||||
|
|
|
@ -19,7 +19,9 @@ const deprecate = {
|
|||
setHandler: (handler) => { deprecationHandler = handler },
|
||||
getHandler: () => deprecationHandler,
|
||||
warn: (oldName, newName) => {
|
||||
return deprecate.log(`'${oldName}' is deprecated. Use '${newName}' instead.`)
|
||||
if (!process.noDeprecation) {
|
||||
deprecate.log(`'${oldName}' is deprecated. Use '${newName}' instead.`)
|
||||
}
|
||||
},
|
||||
log: (message) => {
|
||||
if (typeof deprecationHandler === 'function') {
|
||||
|
@ -67,6 +69,41 @@ const deprecate = {
|
|||
})
|
||||
},
|
||||
|
||||
function: (fn, newName) => {
|
||||
// if newName is left blank, a removal warning will be displayed
|
||||
const warn = warnOnce(fn.name, newName)
|
||||
|
||||
return function () {
|
||||
if (!process.noDeprecation) warn()
|
||||
return fn.apply(this, arguments)
|
||||
}
|
||||
},
|
||||
|
||||
promisify: (fn) => {
|
||||
const fnName = fn.name || 'function'
|
||||
const oldName = `${fnName} with callbacks`
|
||||
const newName = `${fnName} with Promises`
|
||||
const warn = warnOnce(oldName, newName)
|
||||
|
||||
return function (...params) {
|
||||
let cb
|
||||
if (params.length > 0 && typeof params[params.length - 1] === 'function') {
|
||||
cb = params.pop()
|
||||
}
|
||||
const promise = fn.apply(this, params)
|
||||
if (!cb) return promise
|
||||
if (process.enablePromiseAPIs) warn()
|
||||
return promise
|
||||
.then(res => {
|
||||
process.nextTick(() => {
|
||||
cb.length === 2 ? cb(null, res) : cb(res)
|
||||
})
|
||||
}, err => {
|
||||
process.nextTick(() => cb(err))
|
||||
})
|
||||
}
|
||||
},
|
||||
|
||||
renameProperty: (o, oldName, newName) => {
|
||||
const warn = warnOnce(oldName, newName)
|
||||
|
||||
|
|
|
@ -4,12 +4,12 @@
|
|||
// - `features` input string
|
||||
// - `emit` function(key, value) - called for each parsed KV
|
||||
module.exports = function parseFeaturesString (features, emit) {
|
||||
features = `${features}`
|
||||
features = `${features}`.trim()
|
||||
// split the string by ','
|
||||
features.split(/,\s*/).forEach((feature) => {
|
||||
features.split(/\s*,\s*/).forEach((feature) => {
|
||||
// expected form is either a key by itself or a key/value pair in the form of
|
||||
// 'key=value'
|
||||
let [key, value] = feature.split(/\s*=/)
|
||||
let [key, value] = feature.split(/\s*=\s*/)
|
||||
if (!key) return
|
||||
|
||||
// interpret the value as a boolean, if possible
|
||||
|
|
70
electronasar/canary/common/web-view-methods.js
Normal file
70
electronasar/canary/common/web-view-methods.js
Normal file
|
@ -0,0 +1,70 @@
|
|||
'use strict'
|
||||
|
||||
// Public-facing API methods.
|
||||
exports.syncMethods = new Set([
|
||||
'getURL',
|
||||
'loadURL',
|
||||
'getTitle',
|
||||
'isLoading',
|
||||
'isLoadingMainFrame',
|
||||
'isWaitingForResponse',
|
||||
'stop',
|
||||
'reload',
|
||||
'reloadIgnoringCache',
|
||||
'canGoBack',
|
||||
'canGoForward',
|
||||
'canGoToOffset',
|
||||
'clearHistory',
|
||||
'goBack',
|
||||
'goForward',
|
||||
'goToIndex',
|
||||
'goToOffset',
|
||||
'isCrashed',
|
||||
'setUserAgent',
|
||||
'getUserAgent',
|
||||
'openDevTools',
|
||||
'closeDevTools',
|
||||
'isDevToolsOpened',
|
||||
'isDevToolsFocused',
|
||||
'inspectElement',
|
||||
'setAudioMuted',
|
||||
'isAudioMuted',
|
||||
'isCurrentlyAudible',
|
||||
'undo',
|
||||
'redo',
|
||||
'cut',
|
||||
'copy',
|
||||
'paste',
|
||||
'pasteAndMatchStyle',
|
||||
'delete',
|
||||
'selectAll',
|
||||
'unselect',
|
||||
'replace',
|
||||
'replaceMisspelling',
|
||||
'findInPage',
|
||||
'stopFindInPage',
|
||||
'downloadURL',
|
||||
'inspectServiceWorker',
|
||||
'showDefinitionForSelection',
|
||||
'getZoomFactor',
|
||||
'getZoomLevel',
|
||||
'setZoomFactor',
|
||||
'setZoomLevel',
|
||||
'sendImeEvent'
|
||||
])
|
||||
|
||||
exports.asyncCallbackMethods = new Set([
|
||||
'insertCSS',
|
||||
'insertText',
|
||||
'send',
|
||||
'sendInputEvent',
|
||||
'setLayoutZoomLevelLimits',
|
||||
'setVisualZoomLevelLimits',
|
||||
'print',
|
||||
'printToPDF'
|
||||
])
|
||||
|
||||
exports.asyncPromiseMethods = new Set([
|
||||
'capturePage',
|
||||
'executeJavaScript'
|
||||
])
|
|
@ -1,6 +1,6 @@
|
|||
'use strict'
|
||||
|
||||
const { nativeImage } = require('electron')
|
||||
const { nativeImage, deprecate } = require('electron')
|
||||
const ipcRenderer = require('@electron/internal/renderer/ipc-renderer-internal')
|
||||
|
||||
const includes = [].includes
|
||||
|
@ -17,32 +17,43 @@ function isValid (options) {
|
|||
return Array.isArray(types)
|
||||
}
|
||||
|
||||
exports.getSources = function (options, callback) {
|
||||
if (!isValid(options)) return callback(new Error('Invalid options'))
|
||||
const captureWindow = includes.call(options.types, 'window')
|
||||
const captureScreen = includes.call(options.types, 'screen')
|
||||
function mapSources (sources) {
|
||||
return sources.map(source => ({
|
||||
id: source.id,
|
||||
name: source.name,
|
||||
thumbnail: nativeImage.createFromDataURL(source.thumbnail),
|
||||
display_id: source.display_id,
|
||||
appIcon: source.appIcon ? nativeImage.createFromDataURL(source.appIcon) : null
|
||||
}))
|
||||
}
|
||||
|
||||
if (options.thumbnailSize == null) {
|
||||
options.thumbnailSize = {
|
||||
width: 150,
|
||||
height: 150
|
||||
const getSources = (options) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
if (!isValid(options)) throw new Error('Invalid options')
|
||||
|
||||
const captureWindow = includes.call(options.types, 'window')
|
||||
const captureScreen = includes.call(options.types, 'screen')
|
||||
|
||||
if (options.thumbnailSize == null) {
|
||||
options.thumbnailSize = {
|
||||
width: 150,
|
||||
height: 150
|
||||
}
|
||||
}
|
||||
if (options.fetchWindowIcons == null) {
|
||||
options.fetchWindowIcons = false
|
||||
}
|
||||
}
|
||||
|
||||
const id = incrementId()
|
||||
ipcRenderer.send('ELECTRON_BROWSER_DESKTOP_CAPTURER_GET_SOURCES', captureWindow, captureScreen, options.thumbnailSize, id)
|
||||
return ipcRenderer.once(`ELECTRON_RENDERER_DESKTOP_CAPTURER_RESULT_${id}`, (event, sources) => {
|
||||
callback(null, (() => {
|
||||
const results = []
|
||||
sources.forEach(source => {
|
||||
results.push({
|
||||
id: source.id,
|
||||
name: source.name,
|
||||
thumbnail: nativeImage.createFromDataURL(source.thumbnail),
|
||||
display_id: source.display_id
|
||||
})
|
||||
})
|
||||
return results
|
||||
})())
|
||||
const id = incrementId()
|
||||
ipcRenderer.send('ELECTRON_BROWSER_DESKTOP_CAPTURER_GET_SOURCES', captureWindow, captureScreen, options.thumbnailSize, options.fetchWindowIcons, id)
|
||||
return ipcRenderer.once(`ELECTRON_RENDERER_DESKTOP_CAPTURER_RESULT_${id}`, (event, sources) => {
|
||||
try {
|
||||
resolve(mapSources(sources))
|
||||
} catch (error) {
|
||||
reject(error)
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
exports.getSources = deprecate.promisify(getSources)
|
||||
|
|
|
@ -8,11 +8,11 @@ const ipcRenderer = v8Util.getHiddenValue(global, 'ipc')
|
|||
const internal = false
|
||||
|
||||
ipcRenderer.send = function (...args) {
|
||||
return binding.send('ipc-message', args)
|
||||
return binding.send('-ipc-message', args)
|
||||
}
|
||||
|
||||
ipcRenderer.sendSync = function (...args) {
|
||||
return binding.sendSync('ipc-message-sync', args)[0]
|
||||
return binding.sendSync('-ipc-message-sync', args)[0]
|
||||
}
|
||||
|
||||
ipcRenderer.sendToHost = function (...args) {
|
||||
|
|
|
@ -311,7 +311,9 @@ exports.getCurrentWindow = () => {
|
|||
|
||||
// Get current WebContents object.
|
||||
exports.getCurrentWebContents = () => {
|
||||
return metaToValue(ipcRenderer.sendSync('ELECTRON_BROWSER_CURRENT_WEB_CONTENTS', contextId))
|
||||
const command = 'ELECTRON_BROWSER_CURRENT_WEB_CONTENTS'
|
||||
const meta = ipcRenderer.sendSync(command, contextId)
|
||||
return metaToValue(meta)
|
||||
}
|
||||
|
||||
// Get a global object in browser.
|
||||
|
|
|
@ -1,4 +1,8 @@
|
|||
'use strict'
|
||||
|
||||
const { getRemoteForUsage } = require('@electron/internal/renderer/remote')
|
||||
module.exports = getRemoteForUsage('screen').screen
|
||||
const { deprecate } = require('electron')
|
||||
|
||||
deprecate.warn(`electron.screen`, `electron.remote.screen`)
|
||||
|
||||
const { getRemote } = require('@electron/internal/renderer/remote')
|
||||
module.exports = getRemote('screen')
|
||||
|
|
|
@ -6,9 +6,10 @@
|
|||
// Does not implement predefined messages:
|
||||
// https://developer.chrome.com/extensions/i18n#overview-predefined
|
||||
|
||||
const { potentiallyRemoteRequire } = require('@electron/internal/renderer/remote')
|
||||
const ipcRenderer = require('@electron/internal/renderer/ipc-renderer-internal')
|
||||
const fs = require('fs')
|
||||
const path = require('path')
|
||||
const fs = potentiallyRemoteRequire('fs')
|
||||
const path = potentiallyRemoteRequire('path')
|
||||
|
||||
let metadata
|
||||
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
'use strict'
|
||||
|
||||
const fs = require('fs')
|
||||
const path = require('path')
|
||||
const { remote } = require('electron')
|
||||
const { app } = remote
|
||||
const { getRemote, potentiallyRemoteRequire } = require('@electron/internal/renderer/remote')
|
||||
const fs = potentiallyRemoteRequire('fs')
|
||||
const path = potentiallyRemoteRequire('path')
|
||||
const app = getRemote('app')
|
||||
|
||||
const getChromeStoragePath = (storageType, extensionId) => {
|
||||
return path.join(
|
||||
|
|
|
@ -31,68 +31,67 @@ const ipcRenderer = require('@electron/internal/renderer/ipc-renderer-internal')
|
|||
require('@electron/internal/renderer/web-frame-init')()
|
||||
|
||||
// Process command line arguments.
|
||||
let nodeIntegration = false
|
||||
let webviewTag = false
|
||||
let preloadScript = null
|
||||
let preloadScripts = []
|
||||
let isBackgroundPage = false
|
||||
let appPath = null
|
||||
for (const arg of process.argv) {
|
||||
if (arg.indexOf('--guest-instance-id=') === 0) {
|
||||
// This is a guest web view.
|
||||
process.guestInstanceId = parseInt(arg.substr(arg.indexOf('=') + 1))
|
||||
} else if (arg.indexOf('--opener-id=') === 0) {
|
||||
// This is a guest BrowserWindow.
|
||||
process.openerId = parseInt(arg.substr(arg.indexOf('=') + 1))
|
||||
} else if (arg.indexOf('--node-integration=') === 0) {
|
||||
nodeIntegration = arg.substr(arg.indexOf('=') + 1) === 'true'
|
||||
} else if (arg.indexOf('--preload=') === 0) {
|
||||
preloadScript = arg.substr(arg.indexOf('=') + 1)
|
||||
} else if (arg === '--background-page') {
|
||||
isBackgroundPage = true
|
||||
} else if (arg.indexOf('--app-path=') === 0) {
|
||||
appPath = arg.substr(arg.indexOf('=') + 1)
|
||||
} else if (arg.indexOf('--webview-tag=') === 0) {
|
||||
webviewTag = arg.substr(arg.indexOf('=') + 1) === 'true'
|
||||
} else if (arg.indexOf('--preload-scripts') === 0) {
|
||||
preloadScripts = arg.substr(arg.indexOf('=') + 1).split(path.delimiter)
|
||||
}
|
||||
const { hasSwitch, getSwitchValue } = process.atomBinding('command_line')
|
||||
|
||||
const parseOption = function (name, defaultValue, converter = value => value) {
|
||||
return hasSwitch(name) ? converter(getSwitchValue(name)) : defaultValue
|
||||
}
|
||||
|
||||
const contextIsolation = hasSwitch('context-isolation')
|
||||
const nodeIntegration = hasSwitch('node-integration')
|
||||
const webviewTag = hasSwitch('webview-tag')
|
||||
const isHiddenPage = hasSwitch('hidden-page')
|
||||
const isBackgroundPage = hasSwitch('background-page')
|
||||
const usesNativeWindowOpen = hasSwitch('native-window-open')
|
||||
|
||||
const preloadScript = parseOption('preload', null)
|
||||
const preloadScripts = parseOption('preload-scripts', [], value => value.split(path.delimiter))
|
||||
const appPath = parseOption('app-path', null)
|
||||
const guestInstanceId = parseOption('guest-instance-id', null, value => parseInt(value))
|
||||
const openerId = parseOption('opener-id', null, value => parseInt(value))
|
||||
|
||||
// The arguments to be passed to isolated world.
|
||||
const isolatedWorldArgs = { ipcRenderer, guestInstanceId, isHiddenPage, openerId, usesNativeWindowOpen }
|
||||
|
||||
// The webContents preload script is loaded after the session preload scripts.
|
||||
if (preloadScript) {
|
||||
preloadScripts.push(preloadScript)
|
||||
}
|
||||
|
||||
if (window.location.protocol === 'chrome-devtools:') {
|
||||
// Override some inspector APIs.
|
||||
require('@electron/internal/renderer/inspector')
|
||||
nodeIntegration = false
|
||||
} else if (window.location.protocol === 'chrome-extension:') {
|
||||
// Add implementations of chrome API.
|
||||
require('@electron/internal/renderer/chrome-api').injectTo(window.location.hostname, isBackgroundPage, window)
|
||||
nodeIntegration = false
|
||||
} else if (window.location.protocol === 'chrome:') {
|
||||
// Disable node integration for chrome UI scheme.
|
||||
nodeIntegration = false
|
||||
} else {
|
||||
// Override default web functions.
|
||||
require('@electron/internal/renderer/override')
|
||||
switch (window.location.protocol) {
|
||||
case 'chrome-devtools:': {
|
||||
// Override some inspector APIs.
|
||||
require('@electron/internal/renderer/inspector')
|
||||
break
|
||||
}
|
||||
case 'chrome-extension:': {
|
||||
// Inject the chrome.* APIs that chrome extensions require
|
||||
require('@electron/internal/renderer/chrome-api').injectTo(window.location.hostname, isBackgroundPage, window)
|
||||
break
|
||||
}
|
||||
case 'chrome:':
|
||||
break
|
||||
default: {
|
||||
// Override default web functions.
|
||||
require('@electron/internal/renderer/window-setup')(ipcRenderer, guestInstanceId, openerId, isHiddenPage, usesNativeWindowOpen)
|
||||
|
||||
// Inject content scripts.
|
||||
require('@electron/internal/renderer/content-scripts-injector')
|
||||
|
||||
// Load webview tag implementation.
|
||||
if (webviewTag && process.guestInstanceId == null) {
|
||||
const { setupWebView } = require('@electron/internal/renderer/web-view/web-view')
|
||||
if (process.argv.includes('--context-isolation')) {
|
||||
v8Util.setHiddenValue(window, 'setup-webview', setupWebView)
|
||||
} else {
|
||||
setupWebView(window)
|
||||
// Inject content scripts.
|
||||
if (process.isMainFrame) {
|
||||
require('@electron/internal/renderer/content-scripts-injector')
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Load webview tag implementation.
|
||||
if (process.isMainFrame) {
|
||||
require('@electron/internal/renderer/web-view/web-view-init')(contextIsolation, webviewTag, guestInstanceId)
|
||||
}
|
||||
|
||||
// Pass the arguments to isolatedWorld.
|
||||
if (contextIsolation) {
|
||||
v8Util.setHiddenValue(global, 'isolated-world-args', isolatedWorldArgs)
|
||||
}
|
||||
|
||||
if (nodeIntegration) {
|
||||
// Export node bindings to global.
|
||||
global.require = require
|
||||
|
@ -150,27 +149,21 @@ if (nodeIntegration) {
|
|||
})
|
||||
}
|
||||
|
||||
const errorUtils = require('@electron/internal/common/error-utils')
|
||||
|
||||
// Load the preload scripts.
|
||||
for (const preloadScript of preloadScripts) {
|
||||
try {
|
||||
require(preloadScript)
|
||||
} catch (error) {
|
||||
console.error('Unable to load preload script: ' + preloadScript)
|
||||
console.error(error.stack || error.message)
|
||||
console.error(`Unable to load preload script: ${preloadScript}`)
|
||||
console.error(`${error}`)
|
||||
|
||||
ipcRenderer.send('ELECTRON_BROWSER_PRELOAD_ERROR', preloadScript, errorUtils.serialize(error))
|
||||
}
|
||||
}
|
||||
|
||||
// Warn about security issues
|
||||
require('@electron/internal/renderer/security-warnings')(nodeIntegration)
|
||||
|
||||
// Report focus/blur events of webview to browser.
|
||||
// Note that while Chromium content APIs have observer for focus/blur, they
|
||||
// unfortunately do not work for webview.
|
||||
if (process.guestInstanceId) {
|
||||
window.addEventListener('focus', () => {
|
||||
ipcRenderer.send('ELECTRON_GUEST_VIEW_MANAGER_FOCUS_CHANGE', true, process.guestInstanceId)
|
||||
})
|
||||
window.addEventListener('blur', () => {
|
||||
ipcRenderer.send('ELECTRON_GUEST_VIEW_MANAGER_FOCUS_CHANGE', false, process.guestInstanceId)
|
||||
})
|
||||
if (process.isMainFrame) {
|
||||
require('@electron/internal/renderer/security-warnings')(nodeIntegration)
|
||||
}
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
'use strict'
|
||||
|
||||
const { getRemote, potentiallyRemoteRequire } = require('@electron/internal/renderer/remote')
|
||||
|
||||
window.onload = function () {
|
||||
// Use menu API to show context menu.
|
||||
window.InspectorFrontendHost.showContextMenuAtPoint = createMenu
|
||||
|
@ -18,7 +20,7 @@ function completeURL (project, path) {
|
|||
}
|
||||
|
||||
window.confirm = function (message, title) {
|
||||
const { dialog } = require('electron').remote
|
||||
const dialog = getRemote('dialog')
|
||||
if (title == null) {
|
||||
title = ''
|
||||
}
|
||||
|
@ -62,8 +64,7 @@ const convertToMenuTemplate = function (items) {
|
|||
}
|
||||
|
||||
const createMenu = function (x, y, items) {
|
||||
const { remote } = require('electron')
|
||||
const { Menu } = remote
|
||||
const Menu = getRemote('Menu')
|
||||
|
||||
let template = convertToMenuTemplate(items)
|
||||
if (useEditMenuItems(x, y, template)) {
|
||||
|
@ -73,7 +74,8 @@ const createMenu = function (x, y, items) {
|
|||
|
||||
// The menu is expected to show asynchronously.
|
||||
setTimeout(function () {
|
||||
menu.popup({ window: remote.getCurrentWindow() })
|
||||
const getCurrentWindow = getRemote('getCurrentWindow')
|
||||
menu.popup({ window: getCurrentWindow() })
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -116,7 +118,7 @@ const getEditMenuItems = function () {
|
|||
}
|
||||
|
||||
const showFileChooserDialog = function (callback) {
|
||||
const { dialog } = require('electron').remote
|
||||
const dialog = getRemote('dialog')
|
||||
const files = dialog.showOpenDialog({})
|
||||
if (files != null) {
|
||||
callback(pathToHtml5FileObject(files[0]))
|
||||
|
@ -124,7 +126,7 @@ const showFileChooserDialog = function (callback) {
|
|||
}
|
||||
|
||||
const pathToHtml5FileObject = function (path) {
|
||||
const fs = require('fs')
|
||||
const fs = potentiallyRemoteRequire('fs')
|
||||
const blob = new Blob([fs.readFileSync(path)])
|
||||
blob.name = path
|
||||
return blob
|
||||
|
|
|
@ -1,18 +0,0 @@
|
|||
'use strict'
|
||||
|
||||
const ipcRenderer = require('@electron/internal/renderer/ipc-renderer-internal')
|
||||
|
||||
const v8Util = process.atomBinding('v8_util')
|
||||
|
||||
const { guestInstanceId, openerId } = process
|
||||
const hiddenPage = process.argv.includes('--hidden-page')
|
||||
const usesNativeWindowOpen = process.argv.includes('--native-window-open')
|
||||
const contextIsolation = process.argv.includes('--context-isolation')
|
||||
|
||||
// Pass the arguments to isolatedWorld.
|
||||
if (contextIsolation) {
|
||||
const isolatedWorldArgs = { ipcRenderer, guestInstanceId, hiddenPage, openerId, usesNativeWindowOpen }
|
||||
v8Util.setHiddenValue(global, 'isolated-world-args', isolatedWorldArgs)
|
||||
}
|
||||
|
||||
require('@electron/internal/renderer/window-setup')(ipcRenderer, guestInstanceId, openerId, hiddenPage, usesNativeWindowOpen)
|
|
@ -2,9 +2,24 @@
|
|||
|
||||
const { remote } = require('electron')
|
||||
|
||||
exports.getRemoteForUsage = function (usage) {
|
||||
exports.getRemote = function (name) {
|
||||
if (!remote) {
|
||||
throw new Error(`${usage} requires remote, which is not enabled`)
|
||||
throw new Error(`${name} requires remote, which is not enabled`)
|
||||
}
|
||||
return remote[name]
|
||||
}
|
||||
|
||||
exports.remoteRequire = function (name) {
|
||||
if (!remote) {
|
||||
throw new Error(`${name} requires remote, which is not enabled`)
|
||||
}
|
||||
return remote.require(name)
|
||||
}
|
||||
|
||||
exports.potentiallyRemoteRequire = function (name) {
|
||||
if (process.sandboxed) {
|
||||
return exports.remoteRequire(name)
|
||||
} else {
|
||||
return require(name)
|
||||
}
|
||||
return remote
|
||||
}
|
||||
|
|
|
@ -249,51 +249,6 @@ const warnAboutAllowedPopups = function () {
|
|||
}
|
||||
}
|
||||
|
||||
const warnAboutNodeIntegrationDefault = function (webPreferences) {
|
||||
if (webPreferences.nodeIntegration && !webPreferences.nodeIntegrationWasExplicitlyEnabled) {
|
||||
const warning = `This window has node integration enabled by default. In ` +
|
||||
`Electron 5.0.0, node integration will be disabled by default. To prepare ` +
|
||||
`for this change, set {nodeIntegration: true} in the webPreferences for ` +
|
||||
`this window, or ensure that this window does not rely on node integration ` +
|
||||
`and set {nodeIntegration: false}.`
|
||||
console.warn('%cElectron Deprecation Warning (nodeIntegration default change)', 'font-weight: bold;', warning)
|
||||
}
|
||||
}
|
||||
|
||||
const warnAboutContextIsolationDefault = function (webPreferences) {
|
||||
if (webPreferences.preload && !webPreferences.contextIsolation && !webPreferences.contextIsolationWasExplicitlyDisabled) {
|
||||
const url = 'https://electronjs.org/docs/tutorial/security#3-enable-context-isolation-for-remote-content'
|
||||
const warning = `This window has context isolation disabled by default. In ` +
|
||||
`Electron 5.0.0, context isolation will be enabled by default. To prepare ` +
|
||||
`for this change, set {contextIsolation: false} in the webPreferences for ` +
|
||||
`this window, or ensure that this window does not rely on context ` +
|
||||
`isolation being disabled, and set {contextIsolation: true}.\n\n` +
|
||||
`For more information, see ${url}`
|
||||
console.warn('%cElectron Deprecation Warning (contextIsolation default change)', 'font-weight: bold;', warning)
|
||||
}
|
||||
}
|
||||
|
||||
const warnAboutDeprecatedWebviewTagDefault = function (webPreferences) {
|
||||
if (webPreferences.webviewTagWasExplicitlyEnabled) {
|
||||
return
|
||||
}
|
||||
if (!document || !document.getElementsByTagName) {
|
||||
return
|
||||
}
|
||||
const webviews = document.getElementsByTagName('webview')
|
||||
if (webviews && webviews.length > 0) {
|
||||
const url = 'https://github.com/electron/electron/blob/master/docs/api/breaking-changes.md#new-browserwindow-webpreferences-'
|
||||
const warning = `This window has the <webview> tag enabled by default. In ` +
|
||||
`Electron 5.0.0, <webview> tags will be disabled by default. To prepare ` +
|
||||
`for this change, set {webviewTag: true} in the webPreferences for ` +
|
||||
`this window.\n\n` +
|
||||
`For more information, see ${url}`
|
||||
|
||||
console.warn('%cElectron Deprecation Warning (webviewTag default change)',
|
||||
'font-weight: bold;', warning)
|
||||
}
|
||||
}
|
||||
|
||||
// Currently missing since we can't easily programmatically check for it:
|
||||
// #12WebViews: Verify the options and params of all `<webview>` tags
|
||||
|
||||
|
@ -306,9 +261,6 @@ const logSecurityWarnings = function (webPreferences, nodeIntegration) {
|
|||
warnAboutEnableBlinkFeatures(webPreferences)
|
||||
warnAboutInsecureCSP()
|
||||
warnAboutAllowedPopups()
|
||||
warnAboutNodeIntegrationDefault(webPreferences)
|
||||
warnAboutContextIsolationDefault(webPreferences)
|
||||
warnAboutDeprecatedWebviewTagDefault(webPreferences)
|
||||
}
|
||||
|
||||
const getWebPreferences = function () {
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
'use strict'
|
||||
|
||||
const ipcRenderer = require('@electron/internal/renderer/ipc-renderer-internal')
|
||||
const { WebViewImpl } = require('@electron/internal/renderer/web-view/web-view')
|
||||
const { WebViewImpl } = require('@electron/internal/renderer/web-view/web-view-impl')
|
||||
const webViewConstants = require('@electron/internal/renderer/web-view/web-view-constants')
|
||||
const errorUtils = require('@electron/internal/common/error-utils')
|
||||
|
||||
|
|
110
electronasar/canary/renderer/web-view/web-view-element.js
Normal file
110
electronasar/canary/renderer/web-view/web-view-element.js
Normal file
|
@ -0,0 +1,110 @@
|
|||
'use strict'
|
||||
|
||||
// When using context isolation, the WebViewElement and the custom element
|
||||
// methods have to be defined in the main world to be able to be registered.
|
||||
//
|
||||
// Note: The hidden values can only be read/set inside the same context, all
|
||||
// methods that access the "internal" hidden value must be put in this file.
|
||||
//
|
||||
// Note: This file could be loaded in the main world of contextIsolation page,
|
||||
// which runs in browserify environment instead of Node environment, all native
|
||||
// modules must be passed from outside, all included files must be plain JS.
|
||||
|
||||
const webViewConstants = require('@electron/internal/renderer/web-view/web-view-constants')
|
||||
|
||||
// Return a WebViewElement class that is defined in this context.
|
||||
const defineWebViewElement = (v8Util, webViewImpl) => {
|
||||
const { guestViewInternal, WebViewImpl } = webViewImpl
|
||||
return class WebViewElement extends HTMLElement {
|
||||
static get observedAttributes () {
|
||||
return [
|
||||
webViewConstants.ATTRIBUTE_PARTITION,
|
||||
webViewConstants.ATTRIBUTE_SRC,
|
||||
webViewConstants.ATTRIBUTE_HTTPREFERRER,
|
||||
webViewConstants.ATTRIBUTE_USERAGENT,
|
||||
webViewConstants.ATTRIBUTE_NODEINTEGRATION,
|
||||
webViewConstants.ATTRIBUTE_PLUGINS,
|
||||
webViewConstants.ATTRIBUTE_DISABLEWEBSECURITY,
|
||||
webViewConstants.ATTRIBUTE_ALLOWPOPUPS,
|
||||
webViewConstants.ATTRIBUTE_ENABLEREMOTEMODULE,
|
||||
webViewConstants.ATTRIBUTE_PRELOAD,
|
||||
webViewConstants.ATTRIBUTE_BLINKFEATURES,
|
||||
webViewConstants.ATTRIBUTE_DISABLEBLINKFEATURES,
|
||||
webViewConstants.ATTRIBUTE_WEBPREFERENCES
|
||||
]
|
||||
}
|
||||
|
||||
constructor () {
|
||||
super()
|
||||
v8Util.setHiddenValue(this, 'internal', new WebViewImpl(this))
|
||||
}
|
||||
|
||||
connectedCallback () {
|
||||
const internal = v8Util.getHiddenValue(this, 'internal')
|
||||
if (!internal) {
|
||||
return
|
||||
}
|
||||
if (!internal.elementAttached) {
|
||||
guestViewInternal.registerEvents(internal, internal.viewInstanceId)
|
||||
internal.elementAttached = true
|
||||
internal.attributes[webViewConstants.ATTRIBUTE_SRC].parse()
|
||||
}
|
||||
}
|
||||
|
||||
attributeChangedCallback (name, oldValue, newValue) {
|
||||
const internal = v8Util.getHiddenValue(this, 'internal')
|
||||
if (internal) {
|
||||
internal.handleWebviewAttributeMutation(name, oldValue, newValue)
|
||||
}
|
||||
}
|
||||
|
||||
disconnectedCallback () {
|
||||
const internal = v8Util.getHiddenValue(this, 'internal')
|
||||
if (!internal) {
|
||||
return
|
||||
}
|
||||
guestViewInternal.deregisterEvents(internal.viewInstanceId)
|
||||
internal.elementAttached = false
|
||||
this.internalInstanceId = 0
|
||||
internal.reset()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Register <webview> custom element.
|
||||
const registerWebViewElement = (v8Util, webViewImpl) => {
|
||||
const WebViewElement = defineWebViewElement(v8Util, webViewImpl)
|
||||
|
||||
webViewImpl.setupMethods(WebViewElement)
|
||||
|
||||
// The customElements.define has to be called in a special scope.
|
||||
webViewImpl.webFrame.allowGuestViewElementDefinition(window, () => {
|
||||
window.customElements.define('webview', WebViewElement)
|
||||
window.WebView = WebViewElement
|
||||
|
||||
// Delete the callbacks so developers cannot call them and produce unexpected
|
||||
// behavior.
|
||||
delete WebViewElement.prototype.connectedCallback
|
||||
delete WebViewElement.prototype.disconnectedCallback
|
||||
delete WebViewElement.prototype.attributeChangedCallback
|
||||
|
||||
// Now that |observedAttributes| has been retrieved, we can hide it from
|
||||
// user code as well.
|
||||
delete WebViewElement.observedAttributes
|
||||
})
|
||||
}
|
||||
|
||||
// Prepare to register the <webview> element.
|
||||
const setupWebView = (v8Util, webViewImpl) => {
|
||||
const useCapture = true
|
||||
window.addEventListener('readystatechange', function listener (event) {
|
||||
if (document.readyState === 'loading') {
|
||||
return
|
||||
}
|
||||
webViewImpl.setupAttributes()
|
||||
registerWebViewElement(v8Util, webViewImpl)
|
||||
window.removeEventListener(event.type, listener, useCapture)
|
||||
}, useCapture)
|
||||
}
|
||||
|
||||
module.exports = { setupWebView }
|
|
@ -7,6 +7,11 @@ const ipcRenderer = require('@electron/internal/renderer/ipc-renderer-internal')
|
|||
const guestViewInternal = require('@electron/internal/renderer/web-view/guest-view-internal')
|
||||
const webViewConstants = require('@electron/internal/renderer/web-view/web-view-constants')
|
||||
const errorUtils = require('@electron/internal/common/error-utils')
|
||||
const {
|
||||
syncMethods,
|
||||
asyncCallbackMethods,
|
||||
asyncPromiseMethods
|
||||
} = require('@electron/internal/common/web-view-methods')
|
||||
|
||||
// ID generator.
|
||||
let nextId = 0
|
||||
|
@ -19,7 +24,6 @@ const getNextId = function () {
|
|||
class WebViewImpl {
|
||||
constructor (webviewNode) {
|
||||
this.webviewNode = webviewNode
|
||||
v8Util.setHiddenValue(this.webviewNode, 'internal', this)
|
||||
this.elementAttached = false
|
||||
this.beforeFirstNavigation = true
|
||||
this.hasFocus = false
|
||||
|
@ -196,105 +200,26 @@ class WebViewImpl {
|
|||
}
|
||||
}
|
||||
|
||||
// Registers <webview> custom element.
|
||||
const registerWebViewElement = (window) => {
|
||||
const proto = Object.create(window.HTMLObjectElement.prototype)
|
||||
proto.createdCallback = function () {
|
||||
return new WebViewImpl(this)
|
||||
}
|
||||
proto.attributeChangedCallback = function (name, oldValue, newValue) {
|
||||
const setupAttributes = () => {
|
||||
require('@electron/internal/renderer/web-view/web-view-attributes')
|
||||
}
|
||||
|
||||
const setupMethods = (WebViewElement) => {
|
||||
// WebContents associated with this webview.
|
||||
WebViewElement.prototype.getWebContents = function () {
|
||||
const { getRemote } = require('@electron/internal/renderer/remote')
|
||||
const getGuestWebContents = getRemote('getGuestWebContents')
|
||||
const internal = v8Util.getHiddenValue(this, 'internal')
|
||||
if (internal) {
|
||||
internal.handleWebviewAttributeMutation(name, oldValue, newValue)
|
||||
}
|
||||
}
|
||||
proto.detachedCallback = function () {
|
||||
const internal = v8Util.getHiddenValue(this, 'internal')
|
||||
if (!internal) {
|
||||
return
|
||||
}
|
||||
guestViewInternal.deregisterEvents(internal.viewInstanceId)
|
||||
internal.elementAttached = false
|
||||
this.internalInstanceId = 0
|
||||
internal.reset()
|
||||
}
|
||||
proto.attachedCallback = function () {
|
||||
const internal = v8Util.getHiddenValue(this, 'internal')
|
||||
if (!internal) {
|
||||
return
|
||||
}
|
||||
if (!internal.elementAttached) {
|
||||
guestViewInternal.registerEvents(internal, internal.viewInstanceId)
|
||||
internal.elementAttached = true
|
||||
internal.attributes[webViewConstants.ATTRIBUTE_SRC].parse()
|
||||
if (!internal.guestInstanceId) {
|
||||
internal.createGuestSync()
|
||||
}
|
||||
return getGuestWebContents(internal.guestInstanceId)
|
||||
}
|
||||
|
||||
// Public-facing API methods.
|
||||
const methods = [
|
||||
'getURL',
|
||||
'loadURL',
|
||||
'getTitle',
|
||||
'isLoading',
|
||||
'isLoadingMainFrame',
|
||||
'isWaitingForResponse',
|
||||
'stop',
|
||||
'reload',
|
||||
'reloadIgnoringCache',
|
||||
'canGoBack',
|
||||
'canGoForward',
|
||||
'canGoToOffset',
|
||||
'clearHistory',
|
||||
'goBack',
|
||||
'goForward',
|
||||
'goToIndex',
|
||||
'goToOffset',
|
||||
'isCrashed',
|
||||
'setUserAgent',
|
||||
'getUserAgent',
|
||||
'openDevTools',
|
||||
'closeDevTools',
|
||||
'isDevToolsOpened',
|
||||
'isDevToolsFocused',
|
||||
'inspectElement',
|
||||
'setAudioMuted',
|
||||
'isAudioMuted',
|
||||
'isCurrentlyAudible',
|
||||
'undo',
|
||||
'redo',
|
||||
'cut',
|
||||
'copy',
|
||||
'paste',
|
||||
'pasteAndMatchStyle',
|
||||
'delete',
|
||||
'selectAll',
|
||||
'unselect',
|
||||
'replace',
|
||||
'replaceMisspelling',
|
||||
'findInPage',
|
||||
'stopFindInPage',
|
||||
'downloadURL',
|
||||
'inspectServiceWorker',
|
||||
'showDefinitionForSelection',
|
||||
'setZoomFactor',
|
||||
'setZoomLevel',
|
||||
'sendImeEvent'
|
||||
]
|
||||
const nonblockMethods = [
|
||||
'insertCSS',
|
||||
'insertText',
|
||||
'send',
|
||||
'sendInputEvent',
|
||||
'setLayoutZoomLevelLimits',
|
||||
'setVisualZoomLevelLimits',
|
||||
// with callback
|
||||
'capturePage',
|
||||
'executeJavaScript',
|
||||
'getZoomFactor',
|
||||
'getZoomLevel',
|
||||
'print',
|
||||
'printToPDF'
|
||||
]
|
||||
// Focusing the webview should move page focus to the underlying iframe.
|
||||
WebViewElement.prototype.focus = function () {
|
||||
this.contentWindow.focus()
|
||||
}
|
||||
|
||||
const getGuestInstanceId = function (self) {
|
||||
const internal = v8Util.getHiddenValue(self, 'internal')
|
||||
|
@ -315,8 +240,8 @@ const registerWebViewElement = (window) => {
|
|||
}
|
||||
}
|
||||
}
|
||||
for (const method of methods) {
|
||||
proto[method] = createBlockHandler(method)
|
||||
for (const method of syncMethods) {
|
||||
WebViewElement.prototype[method] = createBlockHandler(method)
|
||||
}
|
||||
|
||||
const createNonBlockHandler = function (method) {
|
||||
|
@ -333,49 +258,35 @@ const registerWebViewElement = (window) => {
|
|||
ipcRenderer.send('ELECTRON_GUEST_VIEW_MANAGER_ASYNC_CALL', requestId, getGuestInstanceId(this), method, args, callback != null)
|
||||
}
|
||||
}
|
||||
for (const method of nonblockMethods) {
|
||||
proto[method] = createNonBlockHandler(method)
|
||||
|
||||
for (const method of asyncCallbackMethods) {
|
||||
WebViewElement.prototype[method] = createNonBlockHandler(method)
|
||||
}
|
||||
|
||||
// WebContents associated with this webview.
|
||||
proto.getWebContents = function () {
|
||||
const { getRemoteForUsage } = require('@electron/internal/renderer/remote')
|
||||
const remote = getRemoteForUsage('getWebContents()')
|
||||
const internal = v8Util.getHiddenValue(this, 'internal')
|
||||
if (!internal.guestInstanceId) {
|
||||
internal.createGuestSync()
|
||||
const createPromiseHandler = function (method) {
|
||||
return function (...args) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const callback = (typeof args[args.length - 1] === 'function') ? args.pop() : null
|
||||
const requestId = getNextId()
|
||||
|
||||
ipcRenderer.once(`ELECTRON_GUEST_VIEW_MANAGER_ASYNC_CALL_RESPONSE_${requestId}`, function (event, error, result) {
|
||||
if (error == null) {
|
||||
if (callback) {
|
||||
callback(result)
|
||||
}
|
||||
resolve(result)
|
||||
} else {
|
||||
reject(errorUtils.deserialize(error))
|
||||
}
|
||||
})
|
||||
ipcRenderer.send('ELECTRON_GUEST_VIEW_MANAGER_ASYNC_CALL', requestId, getGuestInstanceId(this), method, args, callback != null)
|
||||
})
|
||||
}
|
||||
return remote.getGuestWebContents(internal.guestInstanceId)
|
||||
}
|
||||
|
||||
// Focusing the webview should move page focus to the underlying iframe.
|
||||
proto.focus = function () {
|
||||
this.contentWindow.focus()
|
||||
for (const method of asyncPromiseMethods) {
|
||||
WebViewElement.prototype[method] = createPromiseHandler(method)
|
||||
}
|
||||
|
||||
window.WebView = webFrame.registerEmbedderCustomElement(window, 'webview', {
|
||||
prototype: proto
|
||||
})
|
||||
|
||||
// Delete the callbacks so developers cannot call them and produce unexpected
|
||||
// behavior.
|
||||
delete proto.createdCallback
|
||||
delete proto.attachedCallback
|
||||
delete proto.detachedCallback
|
||||
delete proto.attributeChangedCallback
|
||||
}
|
||||
|
||||
const setupWebView = (window) => {
|
||||
require('@electron/internal/renderer/web-view/web-view-attributes')
|
||||
|
||||
const useCapture = true
|
||||
window.addEventListener('readystatechange', function listener (event) {
|
||||
if (document.readyState === 'loading') {
|
||||
return
|
||||
}
|
||||
registerWebViewElement(window)
|
||||
window.removeEventListener(event.type, listener, useCapture)
|
||||
}, useCapture)
|
||||
}
|
||||
|
||||
module.exports = { setupWebView, WebViewImpl }
|
||||
module.exports = { setupAttributes, setupMethods, guestViewInternal, webFrame, WebViewImpl }
|
35
electronasar/canary/renderer/web-view/web-view-init.js
Normal file
35
electronasar/canary/renderer/web-view/web-view-init.js
Normal file
|
@ -0,0 +1,35 @@
|
|||
'use strict'
|
||||
|
||||
const ipcRenderer = require('@electron/internal/renderer/ipc-renderer-internal')
|
||||
const v8Util = process.atomBinding('v8_util')
|
||||
|
||||
function handleFocusBlur (guestInstanceId) {
|
||||
// Note that while Chromium content APIs have observer for focus/blur, they
|
||||
// unfortunately do not work for webview.
|
||||
|
||||
window.addEventListener('focus', () => {
|
||||
ipcRenderer.send('ELECTRON_GUEST_VIEW_MANAGER_FOCUS_CHANGE', true, guestInstanceId)
|
||||
})
|
||||
|
||||
window.addEventListener('blur', () => {
|
||||
ipcRenderer.send('ELECTRON_GUEST_VIEW_MANAGER_FOCUS_CHANGE', false, guestInstanceId)
|
||||
})
|
||||
}
|
||||
|
||||
module.exports = function (contextIsolation, webviewTag, guestInstanceId) {
|
||||
// Don't allow recursive `<webview>`.
|
||||
if (webviewTag && guestInstanceId == null) {
|
||||
const webViewImpl = require('@electron/internal/renderer/web-view/web-view-impl')
|
||||
if (contextIsolation) {
|
||||
v8Util.setHiddenValue(window, 'web-view-impl', webViewImpl)
|
||||
} else {
|
||||
const { setupWebView } = require('@electron/internal/renderer/web-view/web-view-element')
|
||||
setupWebView(v8Util, webViewImpl)
|
||||
}
|
||||
}
|
||||
|
||||
if (guestInstanceId) {
|
||||
// Report focus/blur events of webview to browser.
|
||||
handleFocusBlur(guestInstanceId)
|
||||
}
|
||||
}
|
|
@ -23,10 +23,10 @@
|
|||
// - document.hidden
|
||||
// - document.visibilityState
|
||||
|
||||
const { defineProperty } = Object
|
||||
const { defineProperty, defineProperties } = Object
|
||||
|
||||
// Helper function to resolve relative url.
|
||||
const a = window.top.document.createElement('a')
|
||||
const a = window.document.createElement('a')
|
||||
const resolveURL = function (url) {
|
||||
a.href = url
|
||||
return a.href
|
||||
|
@ -54,12 +54,61 @@ const removeProxy = (guestId) => {
|
|||
delete windowProxies[guestId]
|
||||
}
|
||||
|
||||
function LocationProxy (ipcRenderer, guestId) {
|
||||
const getGuestURL = function () {
|
||||
const urlString = ipcRenderer.sendSync('ELECTRON_GUEST_WINDOW_MANAGER_WEB_CONTENTS_METHOD_SYNC', guestId, 'getURL')
|
||||
try {
|
||||
return new URL(urlString)
|
||||
} catch (e) {
|
||||
console.error('LocationProxy: failed to parse string', urlString, e)
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
const propertyProxyFor = function (property) {
|
||||
return {
|
||||
get: function () {
|
||||
const guestURL = getGuestURL()
|
||||
const value = guestURL ? guestURL[property] : ''
|
||||
return value === undefined ? '' : value
|
||||
},
|
||||
set: function (newVal) {
|
||||
const guestURL = getGuestURL()
|
||||
if (guestURL) {
|
||||
guestURL[property] = newVal
|
||||
return ipcRenderer.sendSync(
|
||||
'ELECTRON_GUEST_WINDOW_MANAGER_WEB_CONTENTS_METHOD_SYNC',
|
||||
guestId, 'loadURL', guestURL.toString())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
defineProperties(this, {
|
||||
hash: propertyProxyFor('hash'),
|
||||
href: propertyProxyFor('href'),
|
||||
host: propertyProxyFor('host'),
|
||||
hostname: propertyProxyFor('hostname'),
|
||||
origin: propertyProxyFor('origin'),
|
||||
pathname: propertyProxyFor('pathname'),
|
||||
port: propertyProxyFor('port'),
|
||||
protocol: propertyProxyFor('protocol'),
|
||||
search: propertyProxyFor('search')
|
||||
})
|
||||
|
||||
this.toString = function () {
|
||||
return this.href
|
||||
}
|
||||
}
|
||||
|
||||
function BrowserWindowProxy (ipcRenderer, guestId) {
|
||||
this.closed = false
|
||||
|
||||
const location = new LocationProxy(ipcRenderer, guestId)
|
||||
defineProperty(this, 'location', {
|
||||
get: function () {
|
||||
return ipcRenderer.sendSync('ELECTRON_GUEST_WINDOW_MANAGER_WEB_CONTENTS_METHOD_SYNC', guestId, 'getURL')
|
||||
return location
|
||||
},
|
||||
set: function (url) {
|
||||
url = resolveURL(url)
|
||||
|
@ -97,15 +146,6 @@ function BrowserWindowProxy (ipcRenderer, guestId) {
|
|||
}
|
||||
}
|
||||
|
||||
// Forward history operations to browser.
|
||||
const sendHistoryOperation = function (ipcRenderer, ...args) {
|
||||
ipcRenderer.send('ELECTRON_NAVIGATION_CONTROLLER', ...args)
|
||||
}
|
||||
|
||||
const getHistoryOperation = function (ipcRenderer, ...args) {
|
||||
return ipcRenderer.sendSync('ELECTRON_SYNC_NAVIGATION_CONTROLLER', ...args)
|
||||
}
|
||||
|
||||
module.exports = (ipcRenderer, guestInstanceId, openerId, hiddenPage, usesNativeWindowOpen) => {
|
||||
if (guestInstanceId == null) {
|
||||
// Override default window.close.
|
||||
|
@ -150,20 +190,20 @@ module.exports = (ipcRenderer, guestInstanceId, openerId, hiddenPage, usesNative
|
|||
})
|
||||
|
||||
window.history.back = function () {
|
||||
sendHistoryOperation(ipcRenderer, 'goBack')
|
||||
ipcRenderer.send('ELECTRON_NAVIGATION_CONTROLLER_GO_BACK')
|
||||
}
|
||||
|
||||
window.history.forward = function () {
|
||||
sendHistoryOperation(ipcRenderer, 'goForward')
|
||||
ipcRenderer.send('ELECTRON_NAVIGATION_CONTROLLER_GO_FORWARD')
|
||||
}
|
||||
|
||||
window.history.go = function (offset) {
|
||||
sendHistoryOperation(ipcRenderer, 'goToOffset', +offset)
|
||||
ipcRenderer.send('ELECTRON_NAVIGATION_CONTROLLER_GO_TO_OFFSET', +offset)
|
||||
}
|
||||
|
||||
defineProperty(window.history, 'length', {
|
||||
get: function () {
|
||||
return getHistoryOperation(ipcRenderer, 'length')
|
||||
return ipcRenderer.sendSync('ELECTRON_NAVIGATION_CONTROLLER_LENGTH')
|
||||
}
|
||||
})
|
||||
|
||||
|
|
Loading…
Reference in a new issue