Migrate to block comments
This commit is contained in:
parent
630cd091a0
commit
403870a27e
44 changed files with 538 additions and 437 deletions
|
@ -34,13 +34,13 @@ app.setAppPath = (path) ->
|
||||||
app.getAppPath = ->
|
app.getAppPath = ->
|
||||||
appPath
|
appPath
|
||||||
|
|
||||||
# Routes the events to webContents.
|
### Routes the events to webContents. ###
|
||||||
for name in ['login', 'certificate-error', 'select-client-certificate']
|
for name in ['login', 'certificate-error', 'select-client-certificate']
|
||||||
do (name) ->
|
do (name) ->
|
||||||
app.on name, (event, webContents, args...) ->
|
app.on name, (event, webContents, args...) ->
|
||||||
webContents.emit name, event, args...
|
webContents.emit name, event, args...
|
||||||
|
|
||||||
# Deprecated.
|
### Deprecated. ###
|
||||||
app.getHomeDir = deprecate 'app.getHomeDir', 'app.getPath', ->
|
app.getHomeDir = deprecate 'app.getHomeDir', 'app.getPath', ->
|
||||||
@getPath 'home'
|
@getPath 'home'
|
||||||
app.getDataPath = deprecate 'app.getDataPath', 'app.getPath', ->
|
app.getDataPath = deprecate 'app.getDataPath', 'app.getPath', ->
|
||||||
|
@ -51,22 +51,23 @@ app.resolveProxy = deprecate 'app.resolveProxy', 'session.defaultSession.resolve
|
||||||
session.defaultSession.resolveProxy url, callback
|
session.defaultSession.resolveProxy url, callback
|
||||||
deprecate.rename app, 'terminate', 'quit'
|
deprecate.rename app, 'terminate', 'quit'
|
||||||
deprecate.event app, 'finish-launching', 'ready', ->
|
deprecate.event app, 'finish-launching', 'ready', ->
|
||||||
setImmediate => # give default app a chance to setup default menu.
|
### give default app a chance to setup default menu. ###
|
||||||
|
setImmediate =>
|
||||||
@emit 'finish-launching'
|
@emit 'finish-launching'
|
||||||
deprecate.event app, 'activate-with-no-open-windows', 'activate', (event, hasVisibleWindows) ->
|
deprecate.event app, 'activate-with-no-open-windows', 'activate', (event, hasVisibleWindows) ->
|
||||||
@emit 'activate-with-no-open-windows', event if not hasVisibleWindows
|
@emit 'activate-with-no-open-windows', event if not hasVisibleWindows
|
||||||
deprecate.event app, 'select-certificate', 'select-client-certificate'
|
deprecate.event app, 'select-certificate', 'select-client-certificate'
|
||||||
|
|
||||||
# Wrappers for native classes.
|
### Wrappers for native classes. ###
|
||||||
wrapDownloadItem = (downloadItem) ->
|
wrapDownloadItem = (downloadItem) ->
|
||||||
# downloadItem is an EventEmitter.
|
### downloadItem is an EventEmitter. ###
|
||||||
downloadItem.__proto__ = EventEmitter.prototype
|
downloadItem.__proto__ = EventEmitter.prototype
|
||||||
# Deprecated.
|
### Deprecated. ###
|
||||||
deprecate.property downloadItem, 'url', 'getURL'
|
deprecate.property downloadItem, 'url', 'getURL'
|
||||||
deprecate.property downloadItem, 'filename', 'getFilename'
|
deprecate.property downloadItem, 'filename', 'getFilename'
|
||||||
deprecate.property downloadItem, 'mimeType', 'getMimeType'
|
deprecate.property downloadItem, 'mimeType', 'getMimeType'
|
||||||
deprecate.rename downloadItem, 'getUrl', 'getURL'
|
deprecate.rename downloadItem, 'getUrl', 'getURL'
|
||||||
downloadItemBindings._setWrapDownloadItem wrapDownloadItem
|
downloadItemBindings._setWrapDownloadItem wrapDownloadItem
|
||||||
|
|
||||||
# Only one App object pemitted.
|
### Only one App object pemitted. ###
|
||||||
module.exports = app
|
module.exports = app
|
||||||
|
|
|
@ -6,7 +6,7 @@ autoUpdater =
|
||||||
else
|
else
|
||||||
require './auto-updater/auto-updater-native'
|
require './auto-updater/auto-updater-native'
|
||||||
|
|
||||||
# Deprecated.
|
### Deprecated. ###
|
||||||
deprecate.rename autoUpdater, 'setFeedUrl', 'setFeedURL'
|
deprecate.rename autoUpdater, 'setFeedUrl', 'setFeedURL'
|
||||||
|
|
||||||
module.exports = autoUpdater
|
module.exports = autoUpdater
|
||||||
|
|
|
@ -28,14 +28,16 @@ class AutoUpdater extends EventEmitter
|
||||||
return @emitError error if error?
|
return @emitError error if error?
|
||||||
|
|
||||||
{releaseNotes, version} = update
|
{releaseNotes, version} = update
|
||||||
# Following information is not available on Windows, so fake them.
|
### Following information is not available on Windows, so fake them. ###
|
||||||
date = new Date
|
date = new Date
|
||||||
url = @updateURL
|
url = @updateURL
|
||||||
|
|
||||||
@emit 'update-downloaded', {}, releaseNotes, version, date, url, => @quitAndInstall()
|
@emit 'update-downloaded', {}, releaseNotes, version, date, url, => @quitAndInstall()
|
||||||
|
|
||||||
# Private: Emit both error object and message, this is to keep compatibility
|
###
|
||||||
# with Old APIs.
|
Private: Emit both error object and message, this is to keep compatibility
|
||||||
|
with Old APIs.
|
||||||
|
###
|
||||||
emitError: (message) ->
|
emitError: (message) ->
|
||||||
@emit 'error', new Error(message), message
|
@emit 'error', new Error(message), message
|
||||||
|
|
||||||
|
|
|
@ -2,17 +2,21 @@ fs = require 'fs'
|
||||||
path = require 'path'
|
path = require 'path'
|
||||||
{spawn} = require 'child_process'
|
{spawn} = require 'child_process'
|
||||||
|
|
||||||
appFolder = path.dirname process.execPath # i.e. my-app/app-0.1.13/
|
### i.e. my-app/app-0.1.13/ ###
|
||||||
updateExe = path.resolve appFolder, '..', 'Update.exe' # i.e. my-app/Update.exe
|
appFolder = path.dirname process.execPath
|
||||||
|
### i.e. my-app/Update.exe ###
|
||||||
|
updateExe = path.resolve appFolder, '..', 'Update.exe'
|
||||||
exeName = path.basename process.execPath
|
exeName = path.basename process.execPath
|
||||||
|
|
||||||
# Spawn a command and invoke the callback when it completes with an error
|
###
|
||||||
# and the output from standard out.
|
Spawn a command and invoke the callback when it completes with an error
|
||||||
|
and the output from standard out.
|
||||||
|
###
|
||||||
spawnUpdate = (args, detached, callback) ->
|
spawnUpdate = (args, detached, callback) ->
|
||||||
try
|
try
|
||||||
spawnedProcess = spawn updateExe, args, {detached}
|
spawnedProcess = spawn updateExe, args, {detached}
|
||||||
catch error
|
catch error
|
||||||
# Shouldn't happen, but still guard it.
|
### Shouldn't happen, but still guard it. ###
|
||||||
process.nextTick -> callback error
|
process.nextTick -> callback error
|
||||||
return
|
return
|
||||||
|
|
||||||
|
@ -26,27 +30,27 @@ spawnUpdate = (args, detached, callback) ->
|
||||||
errorEmitted = true
|
errorEmitted = true
|
||||||
callback error
|
callback error
|
||||||
spawnedProcess.on 'exit', (code, signal) ->
|
spawnedProcess.on 'exit', (code, signal) ->
|
||||||
# We may have already emitted an error.
|
### We may have already emitted an error. ###
|
||||||
return if errorEmitted
|
return if errorEmitted
|
||||||
|
|
||||||
# Process terminated with error.
|
### Process terminated with error. ###
|
||||||
if code isnt 0
|
if code isnt 0
|
||||||
return callback "Command failed: #{signal ? code}\n#{stderr}"
|
return callback "Command failed: #{signal ? code}\n#{stderr}"
|
||||||
|
|
||||||
# Success.
|
### Success. ###
|
||||||
callback null, stdout
|
callback null, stdout
|
||||||
|
|
||||||
# Start an instance of the installed app.
|
### Start an instance of the installed app. ###
|
||||||
exports.processStart = (callback) ->
|
exports.processStart = (callback) ->
|
||||||
spawnUpdate ['--processStart', exeName], true, ->
|
spawnUpdate ['--processStart', exeName], true, ->
|
||||||
|
|
||||||
# Download the releases specified by the URL and write new results to stdout.
|
### Download the releases specified by the URL and write new results to stdout. ###
|
||||||
exports.download = (updateURL, callback) ->
|
exports.download = (updateURL, callback) ->
|
||||||
spawnUpdate ['--download', updateURL], false, (error, stdout) ->
|
spawnUpdate ['--download', updateURL], false, (error, stdout) ->
|
||||||
return callback(error) if error?
|
return callback(error) if error?
|
||||||
|
|
||||||
try
|
try
|
||||||
# Last line of output is the JSON details about the releases
|
### Last line of output is the JSON details about the releases ###
|
||||||
json = stdout.trim().split('\n').pop()
|
json = stdout.trim().split('\n').pop()
|
||||||
update = JSON.parse(json)?.releasesToApply?.pop?()
|
update = JSON.parse(json)?.releasesToApply?.pop?()
|
||||||
catch
|
catch
|
||||||
|
@ -54,11 +58,11 @@ exports.download = (updateURL, callback) ->
|
||||||
|
|
||||||
callback null, update
|
callback null, update
|
||||||
|
|
||||||
# Update the application to the latest remote version specified by URL.
|
### Update the application to the latest remote version specified by URL. ###
|
||||||
exports.update = (updateURL, callback) ->
|
exports.update = (updateURL, callback) ->
|
||||||
spawnUpdate ['--update', updateURL], false, callback
|
spawnUpdate ['--update', updateURL], false, callback
|
||||||
|
|
||||||
# Is the Update.exe installed with the current application?
|
### Is the Update.exe installed with the current application? ###
|
||||||
exports.supported = ->
|
exports.supported = ->
|
||||||
try
|
try
|
||||||
fs.accessSync updateExe, fs.R_OK
|
fs.accessSync updateExe, fs.R_OK
|
||||||
|
|
|
@ -5,56 +5,61 @@
|
||||||
BrowserWindow::__proto__ = EventEmitter.prototype
|
BrowserWindow::__proto__ = EventEmitter.prototype
|
||||||
|
|
||||||
BrowserWindow::_init = ->
|
BrowserWindow::_init = ->
|
||||||
{app} = require 'electron' # avoid recursive require.
|
### avoid recursive require. ###
|
||||||
|
{app} = require 'electron'
|
||||||
|
|
||||||
# Simulate the application menu on platforms other than OS X.
|
### Simulate the application menu on platforms other than OS X. ###
|
||||||
if process.platform isnt 'darwin'
|
if process.platform isnt 'darwin'
|
||||||
menu = app.getApplicationMenu()
|
menu = app.getApplicationMenu()
|
||||||
@setMenu menu if menu?
|
@setMenu menu if menu?
|
||||||
|
|
||||||
# Make new windows requested by links behave like "window.open"
|
### Make new windows requested by links behave like "window.open" ###
|
||||||
@webContents.on '-new-window', (event, url, frameName) ->
|
@webContents.on '-new-window', (event, url, frameName) ->
|
||||||
options = show: true, width: 800, height: 600
|
options = show: true, width: 800, height: 600
|
||||||
ipcMain.emit 'ATOM_SHELL_GUEST_WINDOW_MANAGER_WINDOW_OPEN', event, url, frameName, options
|
ipcMain.emit 'ATOM_SHELL_GUEST_WINDOW_MANAGER_WINDOW_OPEN', event, url, frameName, options
|
||||||
|
|
||||||
# window.resizeTo(...)
|
###
|
||||||
# window.moveTo(...)
|
window.resizeTo(...)
|
||||||
|
window.moveTo(...)
|
||||||
|
###
|
||||||
@webContents.on 'move', (event, size) =>
|
@webContents.on 'move', (event, size) =>
|
||||||
@setBounds size
|
@setBounds size
|
||||||
|
|
||||||
# Hide the auto-hide menu when webContents is focused.
|
### Hide the auto-hide menu when webContents is focused. ###
|
||||||
@webContents.on 'activate', =>
|
@webContents.on 'activate', =>
|
||||||
if process.platform isnt 'darwin' and @isMenuBarAutoHide() and @isMenuBarVisible()
|
if process.platform isnt 'darwin' and @isMenuBarAutoHide() and @isMenuBarVisible()
|
||||||
@setMenuBarVisibility false
|
@setMenuBarVisibility false
|
||||||
|
|
||||||
# Forward the crashed event.
|
### Forward the crashed event. ###
|
||||||
@webContents.on 'crashed', =>
|
@webContents.on 'crashed', =>
|
||||||
@emit 'crashed'
|
@emit 'crashed'
|
||||||
|
|
||||||
# Change window title to page title.
|
### Change window title to page title. ###
|
||||||
@webContents.on 'page-title-updated', (event, title, explicitSet) =>
|
@webContents.on 'page-title-updated', (event, title, explicitSet) =>
|
||||||
@emit 'page-title-updated', event, title
|
@emit 'page-title-updated', event, title
|
||||||
@setTitle title unless event.defaultPrevented
|
@setTitle title unless event.defaultPrevented
|
||||||
|
|
||||||
# Sometimes the webContents doesn't get focus when window is shown, so we have
|
###
|
||||||
# to force focusing on webContents in this case. The safest way is to focus it
|
Sometimes the webContents doesn't get focus when window is shown, so we have
|
||||||
# when we first start to load URL, if we do it earlier it won't have effect,
|
to force focusing on webContents in this case. The safest way is to focus it
|
||||||
# if we do it later we might move focus in the page.
|
when we first start to load URL, if we do it earlier it won't have effect,
|
||||||
# Though this hack is only needed on OS X when the app is launched from
|
if we do it later we might move focus in the page.
|
||||||
# Finder, we still do it on all platforms in case of other bugs we don't know.
|
Though this hack is only needed on OS X when the app is launched from
|
||||||
|
Finder, we still do it on all platforms in case of other bugs we don't know.
|
||||||
|
###
|
||||||
@webContents.once 'load-url', ->
|
@webContents.once 'load-url', ->
|
||||||
@focus()
|
@focus()
|
||||||
|
|
||||||
# Redirect focus/blur event to app instance too.
|
### Redirect focus/blur event to app instance too. ###
|
||||||
@on 'blur', (event) =>
|
@on 'blur', (event) =>
|
||||||
app.emit 'browser-window-blur', event, this
|
app.emit 'browser-window-blur', event, this
|
||||||
@on 'focus', (event) =>
|
@on 'focus', (event) =>
|
||||||
app.emit 'browser-window-focus', event, this
|
app.emit 'browser-window-focus', event, this
|
||||||
|
|
||||||
# Notify the creation of the window.
|
### Notify the creation of the window. ###
|
||||||
app.emit 'browser-window-created', {}, this
|
app.emit 'browser-window-created', {}, this
|
||||||
|
|
||||||
# Be compatible with old APIs.
|
### Be compatible with old APIs. ###
|
||||||
@webContents.on 'devtools-focused', => @emit 'devtools-focused'
|
@webContents.on 'devtools-focused', => @emit 'devtools-focused'
|
||||||
@webContents.on 'devtools-opened', => @emit 'devtools-opened'
|
@webContents.on 'devtools-opened', => @emit 'devtools-opened'
|
||||||
@webContents.on 'devtools-closed', => @emit 'devtools-closed'
|
@webContents.on 'devtools-closed', => @emit 'devtools-closed'
|
||||||
|
@ -76,7 +81,7 @@ BrowserWindow.fromDevToolsWebContents = (webContents) ->
|
||||||
windows = BrowserWindow.getAllWindows()
|
windows = BrowserWindow.getAllWindows()
|
||||||
return window for window in windows when window.devToolsWebContents?.equal webContents
|
return window for window in windows when window.devToolsWebContents?.equal webContents
|
||||||
|
|
||||||
# Helpers.
|
### Helpers. ###
|
||||||
BrowserWindow::loadURL = -> @webContents.loadURL.apply @webContents, arguments
|
BrowserWindow::loadURL = -> @webContents.loadURL.apply @webContents, arguments
|
||||||
BrowserWindow::getURL = -> @webContents.getURL()
|
BrowserWindow::getURL = -> @webContents.getURL()
|
||||||
BrowserWindow::reload = -> @webContents.reload.apply @webContents, arguments
|
BrowserWindow::reload = -> @webContents.reload.apply @webContents, arguments
|
||||||
|
@ -89,7 +94,7 @@ BrowserWindow::toggleDevTools = -> @webContents.toggleDevTools()
|
||||||
BrowserWindow::inspectElement = -> @webContents.inspectElement.apply @webContents, arguments
|
BrowserWindow::inspectElement = -> @webContents.inspectElement.apply @webContents, arguments
|
||||||
BrowserWindow::inspectServiceWorker = -> @webContents.inspectServiceWorker()
|
BrowserWindow::inspectServiceWorker = -> @webContents.inspectServiceWorker()
|
||||||
|
|
||||||
# Deprecated.
|
### Deprecated. ###
|
||||||
deprecate.member BrowserWindow, 'undo', 'webContents'
|
deprecate.member BrowserWindow, 'undo', 'webContents'
|
||||||
deprecate.member BrowserWindow, 'redo', 'webContents'
|
deprecate.member BrowserWindow, 'redo', 'webContents'
|
||||||
deprecate.member BrowserWindow, 'cut', 'webContents'
|
deprecate.member BrowserWindow, 'cut', 'webContents'
|
||||||
|
|
|
@ -16,12 +16,12 @@ messageBoxOptions =
|
||||||
|
|
||||||
parseArgs = (window, options, callback) ->
|
parseArgs = (window, options, callback) ->
|
||||||
unless window is null or window?.constructor is BrowserWindow
|
unless window is null or window?.constructor is BrowserWindow
|
||||||
# Shift.
|
### Shift. ###
|
||||||
callback = options
|
callback = options
|
||||||
options = window
|
options = window
|
||||||
window = null
|
window = null
|
||||||
if not callback? and typeof options is 'function'
|
if not callback? and typeof options is 'function'
|
||||||
# Shift.
|
### Shift. ###
|
||||||
callback = options
|
callback = options
|
||||||
options = null
|
options = null
|
||||||
[window, options, callback]
|
[window, options, callback]
|
||||||
|
@ -97,7 +97,7 @@ module.exports =
|
||||||
options.icon ?= null
|
options.icon ?= null
|
||||||
options.defaultId ?= -1
|
options.defaultId ?= -1
|
||||||
|
|
||||||
# Choose a default button to get selected when dialog is cancelled.
|
### Choose a default button to get selected when dialog is cancelled. ###
|
||||||
unless options.cancelId?
|
unless options.cancelId?
|
||||||
options.cancelId = 0
|
options.cancelId = 0
|
||||||
for text, i in options.buttons
|
for text, i in options.buttons
|
||||||
|
@ -122,6 +122,6 @@ module.exports =
|
||||||
showErrorBox: (args...) ->
|
showErrorBox: (args...) ->
|
||||||
binding.showErrorBox args...
|
binding.showErrorBox args...
|
||||||
|
|
||||||
# Mark standard asynchronous functions.
|
### Mark standard asynchronous functions. ###
|
||||||
for api in ['showMessageBox', 'showOpenDialog', 'showSaveDialog']
|
for api in ['showMessageBox', 'showOpenDialog', 'showSaveDialog']
|
||||||
v8Util.setHiddenValue module.exports[api], 'asynchronous', true
|
v8Util.setHiddenValue module.exports[api], 'asynchronous', true
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
common = require '../../../../common/api/lib/exports/electron'
|
common = require '../../../../common/api/lib/exports/electron'
|
||||||
|
|
||||||
# Import common modules.
|
### Import common modules. ###
|
||||||
common.defineProperties exports
|
common.defineProperties exports
|
||||||
|
|
||||||
Object.defineProperties exports,
|
Object.defineProperties exports,
|
||||||
# Browser side modules, please sort with alphabet order.
|
### Browser side modules, please sort with alphabet order. ###
|
||||||
app:
|
app:
|
||||||
enumerable: true
|
enumerable: true
|
||||||
get: -> require '../app'
|
get: -> require '../app'
|
||||||
|
@ -50,7 +50,7 @@ Object.defineProperties exports,
|
||||||
Tray:
|
Tray:
|
||||||
enumerable: true
|
enumerable: true
|
||||||
get: -> require '../tray'
|
get: -> require '../tray'
|
||||||
# The internal modules, invisible unless you know their names.
|
### The internal modules, invisible unless you know their names. ###
|
||||||
NavigationController:
|
NavigationController:
|
||||||
get: -> require '../navigation-controller'
|
get: -> require '../navigation-controller'
|
||||||
webContents:
|
webContents:
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{deprecate, ipcMain} = require 'electron'
|
{deprecate, ipcMain} = require 'electron'
|
||||||
|
|
||||||
# This module is deprecated, we mirror everything from ipcMain.
|
### This module is deprecated, we mirror everything from ipcMain. ###
|
||||||
deprecate.warn 'ipc module', 'require("electron").ipcMain'
|
deprecate.warn 'ipc module', 'require("electron").ipcMain'
|
||||||
|
|
||||||
module.exports = ipcMain
|
module.exports = ipcMain
|
||||||
|
|
|
@ -2,7 +2,7 @@ v8Util = process.atomBinding 'v8_util'
|
||||||
|
|
||||||
nextCommandId = 0
|
nextCommandId = 0
|
||||||
|
|
||||||
# Maps role to methods of webContents
|
### Maps role to methods of webContents ###
|
||||||
rolesMap =
|
rolesMap =
|
||||||
undo: 'undo'
|
undo: 'undo'
|
||||||
redo: 'redo'
|
redo: 'redo'
|
||||||
|
@ -13,7 +13,7 @@ rolesMap =
|
||||||
minimize: 'minimize'
|
minimize: 'minimize'
|
||||||
close: 'close'
|
close: 'close'
|
||||||
|
|
||||||
# Maps methods that should be called directly on the BrowserWindow instance
|
### Maps methods that should be called directly on the BrowserWindow instance ###
|
||||||
methodInBrowserWindow =
|
methodInBrowserWindow =
|
||||||
minimize: true
|
minimize: true
|
||||||
close: true
|
close: true
|
||||||
|
@ -46,7 +46,7 @@ class MenuItem
|
||||||
|
|
||||||
@commandId = ++nextCommandId
|
@commandId = ++nextCommandId
|
||||||
@click = (focusedWindow) =>
|
@click = (focusedWindow) =>
|
||||||
# Manually flip the checked flags when clicked.
|
### Manually flip the checked flags when clicked. ###
|
||||||
@checked = !@checked if @type in ['checkbox', 'radio']
|
@checked = !@checked if @type in ['checkbox', 'radio']
|
||||||
|
|
||||||
if @role and rolesMap[@role] and process.platform isnt 'darwin' and focusedWindow?
|
if @role and rolesMap[@role] and process.platform isnt 'darwin' and focusedWindow?
|
||||||
|
|
|
@ -4,11 +4,11 @@
|
||||||
v8Util = process.atomBinding 'v8_util'
|
v8Util = process.atomBinding 'v8_util'
|
||||||
bindings = process.atomBinding 'menu'
|
bindings = process.atomBinding 'menu'
|
||||||
|
|
||||||
# Automatically generated radio menu item's group id.
|
### Automatically generated radio menu item's group id. ###
|
||||||
nextGroupId = 0
|
nextGroupId = 0
|
||||||
|
|
||||||
# Search between seperators to find a radio menu item and return its group id,
|
### Search between seperators to find a radio menu item and return its group id, ###
|
||||||
# otherwise generate a group id.
|
### otherwise generate a group id. ###
|
||||||
generateGroupId = (items, pos) ->
|
generateGroupId = (items, pos) ->
|
||||||
if pos > 0
|
if pos > 0
|
||||||
for i in [pos - 1..0]
|
for i in [pos - 1..0]
|
||||||
|
@ -22,12 +22,12 @@ generateGroupId = (items, pos) ->
|
||||||
break if item.type is 'separator'
|
break if item.type is 'separator'
|
||||||
++nextGroupId
|
++nextGroupId
|
||||||
|
|
||||||
# Returns the index of item according to |id|.
|
### Returns the index of item according to |id|. ###
|
||||||
indexOfItemById = (items, id) ->
|
indexOfItemById = (items, id) ->
|
||||||
return i for item, i in items when item.id is id
|
return i for item, i in items when item.id is id
|
||||||
-1
|
-1
|
||||||
|
|
||||||
# Returns the index of where to insert the item according to |position|.
|
### Returns the index of where to insert the item according to |position|. ###
|
||||||
indexToInsertByPosition = (items, position) ->
|
indexToInsertByPosition = (items, position) ->
|
||||||
return items.length unless position
|
return items.length unless position
|
||||||
|
|
||||||
|
@ -41,12 +41,12 @@ indexToInsertByPosition = (items, position) ->
|
||||||
when 'after'
|
when 'after'
|
||||||
insertIndex++
|
insertIndex++
|
||||||
when 'endof'
|
when 'endof'
|
||||||
# If the |id| doesn't exist, then create a new group with the |id|.
|
### If the |id| doesn't exist, then create a new group with the |id|. ###
|
||||||
if insertIndex is -1
|
if insertIndex is -1
|
||||||
items.push id: id, type: 'separator'
|
items.push id: id, type: 'separator'
|
||||||
insertIndex = items.length - 1
|
insertIndex = items.length - 1
|
||||||
|
|
||||||
# Find the end of the group.
|
### Find the end of the group. ###
|
||||||
insertIndex++
|
insertIndex++
|
||||||
while insertIndex < items.length and items[insertIndex].type isnt 'separator'
|
while insertIndex < items.length and items[insertIndex].type isnt 'separator'
|
||||||
insertIndex++
|
insertIndex++
|
||||||
|
@ -69,7 +69,7 @@ Menu::_init = ->
|
||||||
executeCommand: (commandId) =>
|
executeCommand: (commandId) =>
|
||||||
@commandsMap[commandId]?.click BrowserWindow.getFocusedWindow()
|
@commandsMap[commandId]?.click BrowserWindow.getFocusedWindow()
|
||||||
menuWillShow: =>
|
menuWillShow: =>
|
||||||
# Make sure radio groups have at least one menu item seleted.
|
### Make sure radio groups have at least one menu item seleted. ###
|
||||||
for id, group of @groupsMap
|
for id, group of @groupsMap
|
||||||
checked = false
|
checked = false
|
||||||
for radioItem in group when radioItem.checked
|
for radioItem in group when radioItem.checked
|
||||||
|
@ -79,7 +79,7 @@ Menu::_init = ->
|
||||||
|
|
||||||
Menu::popup = (window, x, y) ->
|
Menu::popup = (window, x, y) ->
|
||||||
unless window?.constructor is BrowserWindow
|
unless window?.constructor is BrowserWindow
|
||||||
# Shift.
|
### Shift. ###
|
||||||
y = x
|
y = x
|
||||||
x = window
|
x = window
|
||||||
window = BrowserWindow.getFocusedWindow()
|
window = BrowserWindow.getFocusedWindow()
|
||||||
|
@ -100,12 +100,12 @@ Menu::insert = (pos, item) ->
|
||||||
when 'separator' then @insertSeparator pos
|
when 'separator' then @insertSeparator pos
|
||||||
when 'submenu' then @insertSubMenu pos, item.commandId, item.label, item.submenu
|
when 'submenu' then @insertSubMenu pos, item.commandId, item.label, item.submenu
|
||||||
when 'radio'
|
when 'radio'
|
||||||
# Grouping radio menu items.
|
### Grouping radio menu items. ###
|
||||||
item.overrideReadOnlyProperty 'groupId', generateGroupId(@items, pos)
|
item.overrideReadOnlyProperty 'groupId', generateGroupId(@items, pos)
|
||||||
@groupsMap[item.groupId] ?= []
|
@groupsMap[item.groupId] ?= []
|
||||||
@groupsMap[item.groupId].push item
|
@groupsMap[item.groupId].push item
|
||||||
|
|
||||||
# Setting a radio menu item should flip other items in the group.
|
### Setting a radio menu item should flip other items in the group. ###
|
||||||
v8Util.setHiddenValue item, 'checked', item.checked
|
v8Util.setHiddenValue item, 'checked', item.checked
|
||||||
Object.defineProperty item, 'checked',
|
Object.defineProperty item, 'checked',
|
||||||
enumerable: true
|
enumerable: true
|
||||||
|
@ -121,14 +121,14 @@ Menu::insert = (pos, item) ->
|
||||||
@setIcon pos, item.icon if item.icon?
|
@setIcon pos, item.icon if item.icon?
|
||||||
@setRole pos, item.role if item.role?
|
@setRole pos, item.role if item.role?
|
||||||
|
|
||||||
# Make menu accessable to items.
|
### Make menu accessable to items. ###
|
||||||
item.overrideReadOnlyProperty 'menu', this
|
item.overrideReadOnlyProperty 'menu', this
|
||||||
|
|
||||||
# Remember the items.
|
### Remember the items. ###
|
||||||
@items.splice pos, 0, item
|
@items.splice pos, 0, item
|
||||||
@commandsMap[item.commandId] = item
|
@commandsMap[item.commandId] = item
|
||||||
|
|
||||||
# Force menuWillShow to be called
|
### Force menuWillShow to be called ###
|
||||||
Menu::_callMenuWillShow = ->
|
Menu::_callMenuWillShow = ->
|
||||||
@delegate?.menuWillShow()
|
@delegate?.menuWillShow()
|
||||||
item.submenu._callMenuWillShow() for item in @items when item.submenu?
|
item.submenu._callMenuWillShow() for item in @items when item.submenu?
|
||||||
|
@ -136,7 +136,8 @@ Menu::_callMenuWillShow = ->
|
||||||
applicationMenu = null
|
applicationMenu = null
|
||||||
Menu.setApplicationMenu = (menu) ->
|
Menu.setApplicationMenu = (menu) ->
|
||||||
throw new TypeError('Invalid menu') unless menu is null or menu.constructor is Menu
|
throw new TypeError('Invalid menu') unless menu is null or menu.constructor is Menu
|
||||||
applicationMenu = menu # Keep a reference.
|
### Keep a reference. ###
|
||||||
|
applicationMenu = menu
|
||||||
|
|
||||||
if process.platform is 'darwin'
|
if process.platform is 'darwin'
|
||||||
return if menu is null
|
return if menu is null
|
||||||
|
@ -160,7 +161,7 @@ Menu.buildFromTemplate = (template) ->
|
||||||
if item.position
|
if item.position
|
||||||
insertIndex = indexToInsertByPosition positionedTemplate, item.position
|
insertIndex = indexToInsertByPosition positionedTemplate, item.position
|
||||||
else
|
else
|
||||||
# If no |position| is specified, insert after last item.
|
### If no |position| is specified, insert after last item. ###
|
||||||
insertIndex++
|
insertIndex++
|
||||||
positionedTemplate.splice insertIndex, 0, item
|
positionedTemplate.splice insertIndex, 0, item
|
||||||
|
|
||||||
|
|
|
@ -1,42 +1,47 @@
|
||||||
{ipcMain} = require 'electron'
|
{ipcMain} = require 'electron'
|
||||||
|
|
||||||
# The history operation in renderer is redirected to browser.
|
### The history operation in renderer is redirected to browser. ###
|
||||||
ipcMain.on 'ATOM_SHELL_NAVIGATION_CONTROLLER', (event, method, args...) ->
|
ipcMain.on 'ATOM_SHELL_NAVIGATION_CONTROLLER', (event, method, args...) ->
|
||||||
event.sender[method] args...
|
event.sender[method] args...
|
||||||
|
|
||||||
ipcMain.on 'ATOM_SHELL_SYNC_NAVIGATION_CONTROLLER', (event, method, args...) ->
|
ipcMain.on 'ATOM_SHELL_SYNC_NAVIGATION_CONTROLLER', (event, method, args...) ->
|
||||||
event.returnValue = event.sender[method] args...
|
event.returnValue = event.sender[method] args...
|
||||||
|
|
||||||
# JavaScript implementation of Chromium's NavigationController.
|
###
|
||||||
# Instead of relying on Chromium for history control, we compeletely do history
|
JavaScript implementation of Chromium's NavigationController.
|
||||||
# control on user land, and only rely on WebContents.loadURL for navigation.
|
Instead of relying on Chromium for history control, we compeletely do history
|
||||||
# This helps us avoid Chromium's various optimizations so we can ensure renderer
|
control on user land, and only rely on WebContents.loadURL for navigation.
|
||||||
# process is restarted everytime.
|
This helps us avoid Chromium's various optimizations so we can ensure renderer
|
||||||
|
process is restarted everytime.
|
||||||
|
###
|
||||||
class NavigationController
|
class NavigationController
|
||||||
constructor: (@webContents) ->
|
constructor: (@webContents) ->
|
||||||
@clearHistory()
|
@clearHistory()
|
||||||
|
|
||||||
# webContents may have already navigated to a page.
|
### webContents may have already navigated to a page. ###
|
||||||
if @webContents._getURL()
|
if @webContents._getURL()
|
||||||
@currentIndex++
|
@currentIndex++
|
||||||
@history.push @webContents._getURL()
|
@history.push @webContents._getURL()
|
||||||
|
|
||||||
@webContents.on 'navigation-entry-commited', (event, url, inPage, replaceEntry) =>
|
@webContents.on 'navigation-entry-commited', (event, url, inPage, replaceEntry) =>
|
||||||
if @inPageIndex > -1 and not inPage
|
if @inPageIndex > -1 and not inPage
|
||||||
# Navigated to a new page, clear in-page mark.
|
### Navigated to a new page, clear in-page mark. ###
|
||||||
@inPageIndex = -1
|
@inPageIndex = -1
|
||||||
else if @inPageIndex is -1 and inPage
|
else if @inPageIndex is -1 and inPage
|
||||||
# Started in-page navigations.
|
### Started in-page navigations. ###
|
||||||
@inPageIndex = @currentIndex
|
@inPageIndex = @currentIndex
|
||||||
|
|
||||||
if @pendingIndex >= 0 # Go to index.
|
if @pendingIndex >= 0
|
||||||
|
### Go to index. ###
|
||||||
@currentIndex = @pendingIndex
|
@currentIndex = @pendingIndex
|
||||||
@pendingIndex = -1
|
@pendingIndex = -1
|
||||||
@history[@currentIndex] = url
|
@history[@currentIndex] = url
|
||||||
else if replaceEntry # Non-user initialized navigation.
|
else if replaceEntry
|
||||||
|
### Non-user initialized navigation. ###
|
||||||
@history[@currentIndex] = url
|
@history[@currentIndex] = url
|
||||||
else # Normal navigation.
|
else
|
||||||
@history = @history.slice 0, @currentIndex + 1 # Clear history.
|
### Normal navigation. Clear history. ###
|
||||||
|
@history = @history.slice 0, @currentIndex + 1
|
||||||
currentEntry = @history[@currentIndex]
|
currentEntry = @history[@currentIndex]
|
||||||
if currentEntry?.url isnt url
|
if currentEntry?.url isnt url
|
||||||
@currentIndex++
|
@currentIndex++
|
||||||
|
|
|
@ -4,7 +4,7 @@ throw new Error('Can not initialize protocol module before app is ready') unless
|
||||||
|
|
||||||
{protocol} = process.atomBinding 'protocol'
|
{protocol} = process.atomBinding 'protocol'
|
||||||
|
|
||||||
# Warn about removed APIs.
|
### Warn about removed APIs. ###
|
||||||
logAndThrow = (callback, message) ->
|
logAndThrow = (callback, message) ->
|
||||||
console.error message
|
console.error message
|
||||||
if callback then callback(new Error(message)) else throw new Error(message)
|
if callback then callback(new Error(message)) else throw new Error(message)
|
||||||
|
|
|
@ -4,7 +4,7 @@ bindings = process.atomBinding 'session'
|
||||||
|
|
||||||
PERSIST_PERFIX = 'persist:'
|
PERSIST_PERFIX = 'persist:'
|
||||||
|
|
||||||
# Returns the Session from |partition| string.
|
### Returns the Session from |partition| string. ###
|
||||||
exports.fromPartition = (partition='') ->
|
exports.fromPartition = (partition='') ->
|
||||||
return exports.defaultSession if partition is ''
|
return exports.defaultSession if partition is ''
|
||||||
if partition.startsWith PERSIST_PERFIX
|
if partition.startsWith PERSIST_PERFIX
|
||||||
|
@ -12,13 +12,13 @@ exports.fromPartition = (partition='') ->
|
||||||
else
|
else
|
||||||
bindings.fromPartition partition, true
|
bindings.fromPartition partition, true
|
||||||
|
|
||||||
# Returns the default session.
|
### Returns the default session. ###
|
||||||
Object.defineProperty exports, 'defaultSession',
|
Object.defineProperty exports, 'defaultSession',
|
||||||
enumerable: true
|
enumerable: true
|
||||||
get: -> bindings.fromPartition '', false
|
get: -> bindings.fromPartition '', false
|
||||||
|
|
||||||
wrapSession = (session) ->
|
wrapSession = (session) ->
|
||||||
# session is an EventEmitter.
|
### session is an EventEmitter. ###
|
||||||
session.__proto__ = EventEmitter.prototype
|
session.__proto__ = EventEmitter.prototype
|
||||||
|
|
||||||
bindings._setWrapSession wrapSession
|
bindings._setWrapSession wrapSession
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
Tray::__proto__ = EventEmitter.prototype
|
Tray::__proto__ = EventEmitter.prototype
|
||||||
|
|
||||||
Tray::_init = ->
|
Tray::_init = ->
|
||||||
# Deprecated.
|
### Deprecated. ###
|
||||||
deprecate.rename this, 'popContextMenu', 'popUpContextMenu'
|
deprecate.rename this, 'popContextMenu', 'popUpContextMenu'
|
||||||
deprecate.event this, 'clicked', 'click'
|
deprecate.event this, 'clicked', 'click'
|
||||||
deprecate.event this, 'double-clicked', 'double-click'
|
deprecate.event this, 'double-clicked', 'double-click'
|
||||||
|
@ -14,6 +14,7 @@ Tray::_init = ->
|
||||||
|
|
||||||
Tray::setContextMenu = (menu) ->
|
Tray::setContextMenu = (menu) ->
|
||||||
@_setContextMenu menu
|
@_setContextMenu menu
|
||||||
@menu = menu # Keep a strong reference of menu.
|
### Keep a strong reference of menu. ###
|
||||||
|
@menu = menu
|
||||||
|
|
||||||
module.exports = Tray
|
module.exports = Tray
|
||||||
|
|
|
@ -40,28 +40,30 @@ PDFPageSize =
|
||||||
custom_display_name: "Tabloid"
|
custom_display_name: "Tabloid"
|
||||||
|
|
||||||
wrapWebContents = (webContents) ->
|
wrapWebContents = (webContents) ->
|
||||||
# webContents is an EventEmitter.
|
### webContents is an EventEmitter. ###
|
||||||
webContents.__proto__ = EventEmitter.prototype
|
webContents.__proto__ = EventEmitter.prototype
|
||||||
|
|
||||||
# WebContents::send(channel, args..)
|
### WebContents::send(channel, args..) ###
|
||||||
webContents.send = (channel, args...) ->
|
webContents.send = (channel, args...) ->
|
||||||
@_send channel, [args...]
|
@_send channel, [args...]
|
||||||
|
|
||||||
# Make sure webContents.executeJavaScript would run the code only when the
|
###
|
||||||
# web contents has been loaded.
|
Make sure webContents.executeJavaScript would run the code only when the
|
||||||
|
web contents has been loaded.
|
||||||
|
###
|
||||||
webContents.executeJavaScript = (code, hasUserGesture=false) ->
|
webContents.executeJavaScript = (code, hasUserGesture=false) ->
|
||||||
if @getURL() and not @isLoading()
|
if @getURL() and not @isLoading()
|
||||||
@_executeJavaScript code, hasUserGesture
|
@_executeJavaScript code, hasUserGesture
|
||||||
else
|
else
|
||||||
webContents.once 'did-finish-load', @_executeJavaScript.bind(this, code, hasUserGesture)
|
webContents.once 'did-finish-load', @_executeJavaScript.bind(this, code, hasUserGesture)
|
||||||
|
|
||||||
# The navigation controller.
|
### The navigation controller. ###
|
||||||
controller = new NavigationController(webContents)
|
controller = new NavigationController(webContents)
|
||||||
for name, method of NavigationController.prototype when method instanceof Function
|
for name, method of NavigationController.prototype when method instanceof Function
|
||||||
do (name, method) ->
|
do (name, method) ->
|
||||||
webContents[name] = -> method.apply controller, arguments
|
webContents[name] = -> method.apply controller, arguments
|
||||||
|
|
||||||
# Dispatch IPC messages to the ipc module.
|
### Dispatch IPC messages to the ipc module. ###
|
||||||
webContents.on 'ipc-message', (event, packed) ->
|
webContents.on 'ipc-message', (event, packed) ->
|
||||||
[channel, args...] = packed
|
[channel, args...] = packed
|
||||||
ipcMain.emit channel, event, args...
|
ipcMain.emit channel, event, args...
|
||||||
|
@ -70,22 +72,24 @@ wrapWebContents = (webContents) ->
|
||||||
Object.defineProperty event, 'returnValue', set: (value) -> event.sendReply JSON.stringify(value)
|
Object.defineProperty event, 'returnValue', set: (value) -> event.sendReply JSON.stringify(value)
|
||||||
ipcMain.emit channel, event, args...
|
ipcMain.emit channel, event, args...
|
||||||
|
|
||||||
# Handle context menu action request from pepper plugin.
|
### Handle context menu action request from pepper plugin. ###
|
||||||
webContents.on 'pepper-context-menu', (event, params) ->
|
webContents.on 'pepper-context-menu', (event, params) ->
|
||||||
menu = Menu.buildFromTemplate params.menu
|
menu = Menu.buildFromTemplate params.menu
|
||||||
menu.popup params.x, params.y
|
menu.popup params.x, params.y
|
||||||
|
|
||||||
# This error occurs when host could not be found.
|
### This error occurs when host could not be found. ###
|
||||||
webContents.on 'did-fail-provisional-load', (args...) ->
|
webContents.on 'did-fail-provisional-load', (args...) ->
|
||||||
# Calling loadURL during this event might cause crash, so delay the event
|
###
|
||||||
# until next tick.
|
Calling loadURL during this event might cause crash, so delay the event
|
||||||
|
until next tick.
|
||||||
|
###
|
||||||
setImmediate => @emit 'did-fail-load', args...
|
setImmediate => @emit 'did-fail-load', args...
|
||||||
|
|
||||||
# Delays the page-title-updated event to next tick.
|
### Delays the page-title-updated event to next tick. ###
|
||||||
webContents.on '-page-title-updated', (args...) ->
|
webContents.on '-page-title-updated', (args...) ->
|
||||||
setImmediate => @emit 'page-title-updated', args...
|
setImmediate => @emit 'page-title-updated', args...
|
||||||
|
|
||||||
# Deprecated.
|
### Deprecated. ###
|
||||||
deprecate.rename webContents, 'loadUrl', 'loadURL'
|
deprecate.rename webContents, 'loadUrl', 'loadURL'
|
||||||
deprecate.rename webContents, 'getUrl', 'getURL'
|
deprecate.rename webContents, 'getUrl', 'getURL'
|
||||||
deprecate.event webContents, 'page-title-set', 'page-title-updated', (args...) ->
|
deprecate.event webContents, 'page-title-set', 'page-title-updated', (args...) ->
|
||||||
|
|
|
@ -3,7 +3,7 @@ fs = require 'fs'
|
||||||
path = require 'path'
|
path = require 'path'
|
||||||
url = require 'url'
|
url = require 'url'
|
||||||
|
|
||||||
# Mapping between hostname and file path.
|
### Mapping between hostname and file path. ###
|
||||||
hostPathMap = {}
|
hostPathMap = {}
|
||||||
hostPathMapNextKey = 0
|
hostPathMapNextKey = 0
|
||||||
|
|
||||||
|
@ -15,14 +15,16 @@ getHostForPath = (path) ->
|
||||||
getPathForHost = (host) ->
|
getPathForHost = (host) ->
|
||||||
hostPathMap[host]
|
hostPathMap[host]
|
||||||
|
|
||||||
# Cache extensionInfo.
|
### Cache extensionInfo. ###
|
||||||
extensionInfoMap = {}
|
extensionInfoMap = {}
|
||||||
|
|
||||||
getExtensionInfoFromPath = (srcDirectory) ->
|
getExtensionInfoFromPath = (srcDirectory) ->
|
||||||
manifest = JSON.parse fs.readFileSync(path.join(srcDirectory, 'manifest.json'))
|
manifest = JSON.parse fs.readFileSync(path.join(srcDirectory, 'manifest.json'))
|
||||||
unless extensionInfoMap[manifest.name]?
|
unless extensionInfoMap[manifest.name]?
|
||||||
# We can not use 'file://' directly because all resources in the extension
|
###
|
||||||
# will be treated as relative to the root in Chrome.
|
We can not use 'file://' directly because all resources in the extension
|
||||||
|
will be treated as relative to the root in Chrome.
|
||||||
|
###
|
||||||
page = url.format
|
page = url.format
|
||||||
protocol: 'chrome-extension'
|
protocol: 'chrome-extension'
|
||||||
slashes: true
|
slashes: true
|
||||||
|
@ -35,11 +37,11 @@ getExtensionInfoFromPath = (srcDirectory) ->
|
||||||
exposeExperimentalAPIs: true
|
exposeExperimentalAPIs: true
|
||||||
extensionInfoMap[manifest.name]
|
extensionInfoMap[manifest.name]
|
||||||
|
|
||||||
# The loaded extensions cache and its persistent path.
|
### The loaded extensions cache and its persistent path. ###
|
||||||
loadedExtensions = null
|
loadedExtensions = null
|
||||||
loadedExtensionsPath = null
|
loadedExtensionsPath = null
|
||||||
|
|
||||||
# Persistent loaded extensions.
|
### Persistent loaded extensions. ###
|
||||||
{app} = electron
|
{app} = electron
|
||||||
app.on 'will-quit', ->
|
app.on 'will-quit', ->
|
||||||
try
|
try
|
||||||
|
@ -50,21 +52,21 @@ app.on 'will-quit', ->
|
||||||
fs.writeFileSync loadedExtensionsPath, JSON.stringify(loadedExtensions)
|
fs.writeFileSync loadedExtensionsPath, JSON.stringify(loadedExtensions)
|
||||||
catch e
|
catch e
|
||||||
|
|
||||||
# We can not use protocol or BrowserWindow until app is ready.
|
### We can not use protocol or BrowserWindow until app is ready. ###
|
||||||
app.once 'ready', ->
|
app.once 'ready', ->
|
||||||
{protocol, BrowserWindow} = electron
|
{protocol, BrowserWindow} = electron
|
||||||
|
|
||||||
# Load persistented extensions.
|
### Load persistented extensions. ###
|
||||||
loadedExtensionsPath = path.join app.getPath('userData'), 'DevTools Extensions'
|
loadedExtensionsPath = path.join app.getPath('userData'), 'DevTools Extensions'
|
||||||
|
|
||||||
try
|
try
|
||||||
loadedExtensions = JSON.parse fs.readFileSync(loadedExtensionsPath)
|
loadedExtensions = JSON.parse fs.readFileSync(loadedExtensionsPath)
|
||||||
loadedExtensions = [] unless Array.isArray loadedExtensions
|
loadedExtensions = [] unless Array.isArray loadedExtensions
|
||||||
# Preheat the extensionInfo cache.
|
### Preheat the extensionInfo cache. ###
|
||||||
getExtensionInfoFromPath srcDirectory for srcDirectory in loadedExtensions
|
getExtensionInfoFromPath srcDirectory for srcDirectory in loadedExtensions
|
||||||
catch e
|
catch e
|
||||||
|
|
||||||
# The chrome-extension: can map a extension URL request to real file path.
|
### The chrome-extension: can map a extension URL request to real file path. ###
|
||||||
chromeExtensionHandler = (request, callback) ->
|
chromeExtensionHandler = (request, callback) ->
|
||||||
parsed = url.parse request.url
|
parsed = url.parse request.url
|
||||||
return callback() unless parsed.hostname and parsed.path?
|
return callback() unless parsed.hostname and parsed.path?
|
||||||
|
@ -88,7 +90,7 @@ app.once 'ready', ->
|
||||||
BrowserWindow.removeDevToolsExtension = (name) ->
|
BrowserWindow.removeDevToolsExtension = (name) ->
|
||||||
delete extensionInfoMap[name]
|
delete extensionInfoMap[name]
|
||||||
|
|
||||||
# Load persistented extensions when devtools is opened.
|
### Load persistented extensions when devtools is opened. ###
|
||||||
init = BrowserWindow::_init
|
init = BrowserWindow::_init
|
||||||
BrowserWindow::_init = ->
|
BrowserWindow::_init = ->
|
||||||
init.call this
|
init.call this
|
||||||
|
|
|
@ -4,26 +4,30 @@
|
||||||
deepEqual = (opt1, opt2) ->
|
deepEqual = (opt1, opt2) ->
|
||||||
return JSON.stringify(opt1) is JSON.stringify(opt2)
|
return JSON.stringify(opt1) is JSON.stringify(opt2)
|
||||||
|
|
||||||
# A queue for holding all requests from renderer process.
|
### A queue for holding all requests from renderer process. ###
|
||||||
requestsQueue = []
|
requestsQueue = []
|
||||||
|
|
||||||
ipcMain.on 'ATOM_BROWSER_DESKTOP_CAPTURER_GET_SOURCES', (event, captureWindow, captureScreen, thumbnailSize, id) ->
|
ipcMain.on 'ATOM_BROWSER_DESKTOP_CAPTURER_GET_SOURCES', (event, captureWindow, captureScreen, thumbnailSize, id) ->
|
||||||
request = id: id, options: {captureWindow, captureScreen, thumbnailSize}, webContents: event.sender
|
request = id: id, options: {captureWindow, captureScreen, thumbnailSize}, webContents: event.sender
|
||||||
requestsQueue.push request
|
requestsQueue.push request
|
||||||
desktopCapturer.startHandling captureWindow, captureScreen, thumbnailSize if requestsQueue.length is 1
|
desktopCapturer.startHandling captureWindow, captureScreen, thumbnailSize if requestsQueue.length is 1
|
||||||
# If the WebContents is destroyed before receiving result, just remove the
|
###
|
||||||
# reference from requestsQueue to make the module not send the result to it.
|
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', ->
|
event.sender.once 'destroyed', ->
|
||||||
request.webContents = null
|
request.webContents = null
|
||||||
|
|
||||||
desktopCapturer.emit = (event, name, sources) ->
|
desktopCapturer.emit = (event, name, sources) ->
|
||||||
# Receiving sources result from main process, now send them back to renderer.
|
### Receiving sources result from main process, now send them back to renderer. ###
|
||||||
handledRequest = requestsQueue.shift 0
|
handledRequest = requestsQueue.shift 0
|
||||||
result = ({ id: source.id, name: source.name, thumbnail: source.thumbnail.toDataUrl() } for source in sources)
|
result = ({ id: source.id, name: source.name, thumbnail: source.thumbnail.toDataUrl() } for source in sources)
|
||||||
handledRequest.webContents?.send "ATOM_RENDERER_DESKTOP_CAPTURER_RESULT_#{handledRequest.id}", result
|
handledRequest.webContents?.send "ATOM_RENDERER_DESKTOP_CAPTURER_RESULT_#{handledRequest.id}", result
|
||||||
|
|
||||||
# Check the queue to see whether there is other same request. If has, handle
|
###
|
||||||
# it for reducing redunplicated `desktopCaptuer.startHandling` calls.
|
Check the queue to see whether there is other same request. If has, handle
|
||||||
|
it for reducing redunplicated `desktopCaptuer.startHandling` calls.
|
||||||
|
###
|
||||||
unhandledRequestsQueue = []
|
unhandledRequestsQueue = []
|
||||||
for request in requestsQueue
|
for request in requestsQueue
|
||||||
if deepEqual handledRequest.options, request.options
|
if deepEqual handledRequest.options, request.options
|
||||||
|
@ -31,7 +35,7 @@ desktopCapturer.emit = (event, name, sources) ->
|
||||||
else
|
else
|
||||||
unhandledRequestsQueue.push request
|
unhandledRequestsQueue.push request
|
||||||
requestsQueue = unhandledRequestsQueue
|
requestsQueue = unhandledRequestsQueue
|
||||||
# If the requestsQueue is not empty, start a new request handling.
|
### If the requestsQueue is not empty, start a new request handling. ###
|
||||||
if requestsQueue.length > 0
|
if requestsQueue.length > 0
|
||||||
{captureWindow, captureScreen, thumbnailSize} = requestsQueue[0].options
|
{captureWindow, captureScreen, thumbnailSize} = requestsQueue[0].options
|
||||||
desktopCapturer.startHandling captureWindow, captureScreen, thumbnailSize
|
desktopCapturer.startHandling captureWindow, captureScreen, thumbnailSize
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
{ipcMain, webContents} = require 'electron'
|
{ipcMain, webContents} = require 'electron'
|
||||||
|
|
||||||
webViewManager = null # Doesn't exist in early initialization.
|
### Doesn't exist in early initialization. ###
|
||||||
|
webViewManager = null
|
||||||
|
|
||||||
supportedWebViewEvents = [
|
supportedWebViewEvents = [
|
||||||
'load-commit'
|
'load-commit'
|
||||||
|
@ -40,15 +41,15 @@ guestInstances = {}
|
||||||
embedderElementsMap = {}
|
embedderElementsMap = {}
|
||||||
reverseEmbedderElementsMap = {}
|
reverseEmbedderElementsMap = {}
|
||||||
|
|
||||||
# Moves the last element of array to the first one.
|
### Moves the last element of array to the first one. ###
|
||||||
moveLastToFirst = (list) ->
|
moveLastToFirst = (list) ->
|
||||||
list.unshift list.pop()
|
list.unshift list.pop()
|
||||||
|
|
||||||
# Generate guestInstanceId.
|
### Generate guestInstanceId. ###
|
||||||
getNextInstanceId = (webContents) ->
|
getNextInstanceId = (webContents) ->
|
||||||
++nextInstanceId
|
++nextInstanceId
|
||||||
|
|
||||||
# Create a new guest instance.
|
### Create a new guest instance. ###
|
||||||
createGuest = (embedder, params) ->
|
createGuest = (embedder, params) ->
|
||||||
webViewManager ?= process.atomBinding 'web_view_manager'
|
webViewManager ?= process.atomBinding 'web_view_manager'
|
||||||
|
|
||||||
|
@ -56,21 +57,23 @@ createGuest = (embedder, params) ->
|
||||||
guest = webContents.create {isGuest: true, partition: params.partition, embedder}
|
guest = webContents.create {isGuest: true, partition: params.partition, embedder}
|
||||||
guestInstances[id] = {guest, embedder}
|
guestInstances[id] = {guest, embedder}
|
||||||
|
|
||||||
# Destroy guest when the embedder is gone or navigated.
|
### Destroy guest when the embedder is gone or navigated. ###
|
||||||
destroyEvents = ['destroyed', 'crashed', 'did-navigate']
|
destroyEvents = ['destroyed', 'crashed', 'did-navigate']
|
||||||
destroy = ->
|
destroy = ->
|
||||||
destroyGuest embedder, id if guestInstances[id]?
|
destroyGuest embedder, id if guestInstances[id]?
|
||||||
for event in destroyEvents
|
for event in destroyEvents
|
||||||
embedder.once event, destroy
|
embedder.once event, destroy
|
||||||
# Users might also listen to the crashed event, so We must ensure the guest
|
###
|
||||||
# is destroyed before users' listener gets called. It is done by moving our
|
Users might also listen to the crashed event, so We must ensure the guest
|
||||||
# listener to the first one in queue.
|
is destroyed before users' listener gets called. It is done by moving our
|
||||||
|
listener to the first one in queue.
|
||||||
|
###
|
||||||
listeners = embedder._events[event]
|
listeners = embedder._events[event]
|
||||||
moveLastToFirst listeners if Array.isArray listeners
|
moveLastToFirst listeners if Array.isArray listeners
|
||||||
guest.once 'destroyed', ->
|
guest.once 'destroyed', ->
|
||||||
embedder.removeListener event, destroy for event in destroyEvents
|
embedder.removeListener event, destroy for event in destroyEvents
|
||||||
|
|
||||||
# Init guest web view after attached.
|
### Init guest web view after attached. ###
|
||||||
guest.once 'did-attach', ->
|
guest.once 'did-attach', ->
|
||||||
params = @attachParams
|
params = @attachParams
|
||||||
delete @attachParams
|
delete @attachParams
|
||||||
|
@ -96,32 +99,32 @@ createGuest = (embedder, params) ->
|
||||||
|
|
||||||
guest.allowPopups = params.allowpopups
|
guest.allowPopups = params.allowpopups
|
||||||
|
|
||||||
# Dispatch events to embedder.
|
### Dispatch events to embedder. ###
|
||||||
for event in supportedWebViewEvents
|
for event in supportedWebViewEvents
|
||||||
do (event) ->
|
do (event) ->
|
||||||
guest.on event, (_, args...) ->
|
guest.on event, (_, args...) ->
|
||||||
embedder.send "ATOM_SHELL_GUEST_VIEW_INTERNAL_DISPATCH_EVENT-#{guest.viewInstanceId}", event, args...
|
embedder.send "ATOM_SHELL_GUEST_VIEW_INTERNAL_DISPATCH_EVENT-#{guest.viewInstanceId}", event, args...
|
||||||
|
|
||||||
# Dispatch guest's IPC messages to embedder.
|
### Dispatch guest's IPC messages to embedder. ###
|
||||||
guest.on 'ipc-message-host', (_, packed) ->
|
guest.on 'ipc-message-host', (_, packed) ->
|
||||||
[channel, args...] = packed
|
[channel, args...] = packed
|
||||||
embedder.send "ATOM_SHELL_GUEST_VIEW_INTERNAL_IPC_MESSAGE-#{guest.viewInstanceId}", channel, args...
|
embedder.send "ATOM_SHELL_GUEST_VIEW_INTERNAL_IPC_MESSAGE-#{guest.viewInstanceId}", channel, args...
|
||||||
|
|
||||||
# Autosize.
|
### Autosize. ###
|
||||||
guest.on 'size-changed', (_, args...) ->
|
guest.on 'size-changed', (_, args...) ->
|
||||||
embedder.send "ATOM_SHELL_GUEST_VIEW_INTERNAL_SIZE_CHANGED-#{guest.viewInstanceId}", args...
|
embedder.send "ATOM_SHELL_GUEST_VIEW_INTERNAL_SIZE_CHANGED-#{guest.viewInstanceId}", args...
|
||||||
|
|
||||||
id
|
id
|
||||||
|
|
||||||
# Attach the guest to an element of embedder.
|
### Attach the guest to an element of embedder. ###
|
||||||
attachGuest = (embedder, elementInstanceId, guestInstanceId, params) ->
|
attachGuest = (embedder, elementInstanceId, guestInstanceId, params) ->
|
||||||
guest = guestInstances[guestInstanceId].guest
|
guest = guestInstances[guestInstanceId].guest
|
||||||
|
|
||||||
# Destroy the old guest when attaching.
|
### Destroy the old guest when attaching. ###
|
||||||
key = "#{embedder.getId()}-#{elementInstanceId}"
|
key = "#{embedder.getId()}-#{elementInstanceId}"
|
||||||
oldGuestInstanceId = embedderElementsMap[key]
|
oldGuestInstanceId = embedderElementsMap[key]
|
||||||
if oldGuestInstanceId?
|
if oldGuestInstanceId?
|
||||||
# Reattachment to the same guest is not currently supported.
|
### Reattachment to the same guest is not currently supported. ###
|
||||||
return unless oldGuestInstanceId != guestInstanceId
|
return unless oldGuestInstanceId != guestInstanceId
|
||||||
|
|
||||||
return unless guestInstances[oldGuestInstanceId]?
|
return unless guestInstances[oldGuestInstanceId]?
|
||||||
|
@ -139,7 +142,7 @@ attachGuest = (embedder, elementInstanceId, guestInstanceId, params) ->
|
||||||
embedderElementsMap[key] = guestInstanceId
|
embedderElementsMap[key] = guestInstanceId
|
||||||
reverseEmbedderElementsMap[guestInstanceId] = key
|
reverseEmbedderElementsMap[guestInstanceId] = key
|
||||||
|
|
||||||
# Destroy an existing guest instance.
|
### Destroy an existing guest instance. ###
|
||||||
destroyGuest = (embedder, id) ->
|
destroyGuest = (embedder, id) ->
|
||||||
webViewManager.removeGuest embedder, id
|
webViewManager.removeGuest embedder, id
|
||||||
guestInstances[id].guest.destroy()
|
guestInstances[id].guest.destroy()
|
||||||
|
@ -165,10 +168,10 @@ ipcMain.on 'ATOM_SHELL_GUEST_VIEW_MANAGER_SET_SIZE', (event, id, params) ->
|
||||||
ipcMain.on 'ATOM_SHELL_GUEST_VIEW_MANAGER_SET_ALLOW_TRANSPARENCY', (event, id, allowtransparency) ->
|
ipcMain.on 'ATOM_SHELL_GUEST_VIEW_MANAGER_SET_ALLOW_TRANSPARENCY', (event, id, allowtransparency) ->
|
||||||
guestInstances[id]?.guest.setAllowTransparency allowtransparency
|
guestInstances[id]?.guest.setAllowTransparency allowtransparency
|
||||||
|
|
||||||
# Returns WebContents from its guest id.
|
### Returns WebContents from its guest id. ###
|
||||||
exports.getGuest = (id) ->
|
exports.getGuest = (id) ->
|
||||||
guestInstances[id]?.guest
|
guestInstances[id]?.guest
|
||||||
|
|
||||||
# Returns the embedder of the guest.
|
### Returns the embedder of the guest. ###
|
||||||
exports.getEmbedder = (id) ->
|
exports.getEmbedder = (id) ->
|
||||||
guestInstances[id]?.embedder
|
guestInstances[id]?.embedder
|
||||||
|
|
|
@ -3,7 +3,7 @@ v8Util = process.atomBinding 'v8_util'
|
||||||
|
|
||||||
frameToGuest = {}
|
frameToGuest = {}
|
||||||
|
|
||||||
# Copy attribute of |parent| to |child| if it is not defined in |child|.
|
### Copy attribute of |parent| to |child| if it is not defined in |child|. ###
|
||||||
mergeOptions = (child, parent) ->
|
mergeOptions = (child, parent) ->
|
||||||
for own key, value of parent when key not of child
|
for own key, value of parent when key not of child
|
||||||
if typeof value is 'object'
|
if typeof value is 'object'
|
||||||
|
@ -12,34 +12,36 @@ mergeOptions = (child, parent) ->
|
||||||
child[key] = value
|
child[key] = value
|
||||||
child
|
child
|
||||||
|
|
||||||
# Merge |options| with the |embedder|'s window's options.
|
### Merge |options| with the |embedder|'s window's options. ###
|
||||||
mergeBrowserWindowOptions = (embedder, options) ->
|
mergeBrowserWindowOptions = (embedder, options) ->
|
||||||
if embedder.browserWindowOptions?
|
if embedder.browserWindowOptions?
|
||||||
# Inherit the original options if it is a BrowserWindow.
|
### Inherit the original options if it is a BrowserWindow. ###
|
||||||
mergeOptions options, embedder.browserWindowOptions
|
mergeOptions options, embedder.browserWindowOptions
|
||||||
else
|
else
|
||||||
# Or only inherit web-preferences if it is a webview.
|
### Or only inherit web-preferences if it is a webview. ###
|
||||||
options.webPreferences ?= {}
|
options.webPreferences ?= {}
|
||||||
mergeOptions options.webPreferences, embedder.getWebPreferences()
|
mergeOptions options.webPreferences, embedder.getWebPreferences()
|
||||||
options
|
options
|
||||||
|
|
||||||
# Create a new guest created by |embedder| with |options|.
|
### Create a new guest created by |embedder| with |options|. ###
|
||||||
createGuest = (embedder, url, frameName, options) ->
|
createGuest = (embedder, url, frameName, options) ->
|
||||||
guest = frameToGuest[frameName]
|
guest = frameToGuest[frameName]
|
||||||
if frameName and guest?
|
if frameName and guest?
|
||||||
guest.loadURL url
|
guest.loadURL url
|
||||||
return guest.id
|
return guest.id
|
||||||
|
|
||||||
# Remember the embedder window's id.
|
### Remember the embedder window's id. ###
|
||||||
options.webPreferences ?= {}
|
options.webPreferences ?= {}
|
||||||
options.webPreferences.openerId = BrowserWindow.fromWebContents(embedder)?.id
|
options.webPreferences.openerId = BrowserWindow.fromWebContents(embedder)?.id
|
||||||
|
|
||||||
guest = new BrowserWindow(options)
|
guest = new BrowserWindow(options)
|
||||||
guest.loadURL url
|
guest.loadURL url
|
||||||
|
|
||||||
# When |embedder| is destroyed we should also destroy attached guest, and if
|
###
|
||||||
# guest is closed by user then we should prevent |embedder| from double
|
When |embedder| is destroyed we should also destroy attached guest, and if
|
||||||
# closing guest.
|
guest is closed by user then we should prevent |embedder| from double
|
||||||
|
closing guest.
|
||||||
|
###
|
||||||
guestId = guest.id
|
guestId = guest.id
|
||||||
closedByEmbedder = ->
|
closedByEmbedder = ->
|
||||||
guest.removeListener 'closed', closedByUser
|
guest.removeListener 'closed', closedByUser
|
||||||
|
@ -58,7 +60,7 @@ createGuest = (embedder, url, frameName, options) ->
|
||||||
|
|
||||||
guest.id
|
guest.id
|
||||||
|
|
||||||
# Routed window.open messages.
|
### Routed window.open messages. ###
|
||||||
ipcMain.on 'ATOM_SHELL_GUEST_WINDOW_MANAGER_WINDOW_OPEN', (event, args...) ->
|
ipcMain.on 'ATOM_SHELL_GUEST_WINDOW_MANAGER_WINDOW_OPEN', (event, args...) ->
|
||||||
[url, frameName, options] = args
|
[url, frameName, options] = args
|
||||||
options = mergeBrowserWindowOptions event.sender, options
|
options = mergeBrowserWindowOptions event.sender, options
|
||||||
|
|
|
@ -3,26 +3,28 @@ path = require 'path'
|
||||||
util = require 'util'
|
util = require 'util'
|
||||||
Module = require 'module'
|
Module = require 'module'
|
||||||
|
|
||||||
# We modified the original process.argv to let node.js load the atom.js,
|
### We modified the original process.argv to let node.js load the atom.js, ###
|
||||||
# we need to restore it here.
|
### we need to restore it here. ###
|
||||||
process.argv.splice 1, 1
|
process.argv.splice 1, 1
|
||||||
|
|
||||||
# Clear search paths.
|
### Clear search paths. ###
|
||||||
require path.resolve(__dirname, '..', '..', 'common', 'lib', 'reset-search-paths')
|
require path.resolve(__dirname, '..', '..', 'common', 'lib', 'reset-search-paths')
|
||||||
|
|
||||||
# Import common settings.
|
### Import common settings. ###
|
||||||
require path.resolve(__dirname, '..', '..', 'common', 'lib', 'init')
|
require path.resolve(__dirname, '..', '..', 'common', 'lib', 'init')
|
||||||
|
|
||||||
globalPaths = Module.globalPaths
|
globalPaths = Module.globalPaths
|
||||||
unless process.env.ELECTRON_HIDE_INTERNAL_MODULES
|
unless process.env.ELECTRON_HIDE_INTERNAL_MODULES
|
||||||
globalPaths.push path.resolve(__dirname, '..', 'api', 'lib')
|
globalPaths.push path.resolve(__dirname, '..', 'api', 'lib')
|
||||||
|
|
||||||
# Expose public APIs.
|
### Expose public APIs. ###
|
||||||
globalPaths.push path.resolve(__dirname, '..', 'api', 'lib', 'exports')
|
globalPaths.push path.resolve(__dirname, '..', 'api', 'lib', 'exports')
|
||||||
|
|
||||||
if process.platform is 'win32'
|
if process.platform is 'win32'
|
||||||
# Redirect node's console to use our own implementations, since node can not
|
###
|
||||||
# handle console output when running as GUI program.
|
Redirect node's console to use our own implementations, since node can not
|
||||||
|
handle console output when running as GUI program.
|
||||||
|
###
|
||||||
consoleLog = (args...) ->
|
consoleLog = (args...) ->
|
||||||
process.log util.format(args...) + "\n"
|
process.log util.format(args...) + "\n"
|
||||||
streamWrite = (chunk, encoding, callback) ->
|
streamWrite = (chunk, encoding, callback) ->
|
||||||
|
@ -33,40 +35,40 @@ if process.platform is 'win32'
|
||||||
console.log = console.error = console.warn = consoleLog
|
console.log = console.error = console.warn = consoleLog
|
||||||
process.stdout.write = process.stderr.write = streamWrite
|
process.stdout.write = process.stderr.write = streamWrite
|
||||||
|
|
||||||
# Always returns EOF for stdin stream.
|
### Always returns EOF for stdin stream. ###
|
||||||
Readable = require('stream').Readable
|
Readable = require('stream').Readable
|
||||||
stdin = new Readable
|
stdin = new Readable
|
||||||
stdin.push null
|
stdin.push null
|
||||||
process.__defineGetter__ 'stdin', -> stdin
|
process.__defineGetter__ 'stdin', -> stdin
|
||||||
|
|
||||||
# Don't quit on fatal error.
|
### Don't quit on fatal error. ###
|
||||||
process.on 'uncaughtException', (error) ->
|
process.on 'uncaughtException', (error) ->
|
||||||
# Do nothing if the user has a custom uncaught exception handler.
|
### Do nothing if the user has a custom uncaught exception handler. ###
|
||||||
if process.listeners('uncaughtException').length > 1
|
if process.listeners('uncaughtException').length > 1
|
||||||
return
|
return
|
||||||
|
|
||||||
# Show error in GUI.
|
### Show error in GUI. ###
|
||||||
{dialog} = require 'electron'
|
{dialog} = require 'electron'
|
||||||
stack = error.stack ? "#{error.name}: #{error.message}"
|
stack = error.stack ? "#{error.name}: #{error.message}"
|
||||||
message = "Uncaught Exception:\n#{stack}"
|
message = "Uncaught Exception:\n#{stack}"
|
||||||
dialog.showErrorBox 'A JavaScript error occurred in the main process', message
|
dialog.showErrorBox 'A JavaScript error occurred in the main process', message
|
||||||
|
|
||||||
# Emit 'exit' event on quit.
|
### Emit 'exit' event on quit. ###
|
||||||
{app} = require 'electron'
|
{app} = require 'electron'
|
||||||
app.on 'quit', (event, exitCode) ->
|
app.on 'quit', (event, exitCode) ->
|
||||||
process.emit 'exit', exitCode
|
process.emit 'exit', exitCode
|
||||||
|
|
||||||
# Map process.exit to app.exit, which quits gracefully.
|
### Map process.exit to app.exit, which quits gracefully. ###
|
||||||
process.exit = app.exit
|
process.exit = app.exit
|
||||||
|
|
||||||
# Load the RPC server.
|
### Load the RPC server. ###
|
||||||
require './rpc-server'
|
require './rpc-server'
|
||||||
|
|
||||||
# Load the guest view manager.
|
### Load the guest view manager. ###
|
||||||
require './guest-view-manager'
|
require './guest-view-manager'
|
||||||
require './guest-window-manager'
|
require './guest-window-manager'
|
||||||
|
|
||||||
# Now we try to load app's package.json.
|
### Now we try to load app's package.json. ###
|
||||||
packageJson = null
|
packageJson = null
|
||||||
|
|
||||||
searchPaths = [ 'app', 'app.asar', 'default_app' ]
|
searchPaths = [ 'app', 'app.asar', 'default_app' ]
|
||||||
|
@ -82,37 +84,37 @@ unless packageJson?
|
||||||
process.nextTick -> process.exit 1
|
process.nextTick -> process.exit 1
|
||||||
throw new Error("Unable to find a valid app")
|
throw new Error("Unable to find a valid app")
|
||||||
|
|
||||||
# Set application's version.
|
### Set application's version. ###
|
||||||
app.setVersion packageJson.version if packageJson.version?
|
app.setVersion packageJson.version if packageJson.version?
|
||||||
|
|
||||||
# Set application's name.
|
### Set application's name. ###
|
||||||
if packageJson.productName?
|
if packageJson.productName?
|
||||||
app.setName packageJson.productName
|
app.setName packageJson.productName
|
||||||
else if packageJson.name?
|
else if packageJson.name?
|
||||||
app.setName packageJson.name
|
app.setName packageJson.name
|
||||||
|
|
||||||
# Set application's desktop name.
|
### Set application's desktop name. ###
|
||||||
if packageJson.desktopName?
|
if packageJson.desktopName?
|
||||||
app.setDesktopName packageJson.desktopName
|
app.setDesktopName packageJson.desktopName
|
||||||
else
|
else
|
||||||
app.setDesktopName "#{app.getName()}.desktop"
|
app.setDesktopName "#{app.getName()}.desktop"
|
||||||
|
|
||||||
# Chrome 42 disables NPAPI plugins by default, reenable them here
|
### Chrome 42 disables NPAPI plugins by default, reenable them here ###
|
||||||
app.commandLine.appendSwitch 'enable-npapi'
|
app.commandLine.appendSwitch 'enable-npapi'
|
||||||
|
|
||||||
# Set the user path according to application's name.
|
### Set the user path according to application's name. ###
|
||||||
app.setPath 'userData', path.join(app.getPath('appData'), app.getName())
|
app.setPath 'userData', path.join(app.getPath('appData'), app.getName())
|
||||||
app.setPath 'userCache', path.join(app.getPath('cache'), app.getName())
|
app.setPath 'userCache', path.join(app.getPath('cache'), app.getName())
|
||||||
app.setAppPath packagePath
|
app.setAppPath packagePath
|
||||||
|
|
||||||
# Load the chrome extension support.
|
### Load the chrome extension support. ###
|
||||||
require './chrome-extension'
|
require './chrome-extension'
|
||||||
|
|
||||||
# Load internal desktop-capturer module.
|
### Load internal desktop-capturer module. ###
|
||||||
require './desktop-capturer'
|
require './desktop-capturer'
|
||||||
|
|
||||||
# Set main startup script of the app.
|
### Set main startup script of the app. ###
|
||||||
mainStartupScript = packageJson.main or 'index.js'
|
mainStartupScript = packageJson.main or 'index.js'
|
||||||
|
|
||||||
# Finally load app's main.js and transfer control to C++.
|
### Finally load app's main.js and transfer control to C++. ###
|
||||||
Module._load path.join(packagePath, mainStartupScript), Module, true
|
Module._load path.join(packagePath, mainStartupScript), Module, true
|
||||||
|
|
|
@ -6,46 +6,52 @@ class ObjectsRegistry extends EventEmitter
|
||||||
@setMaxListeners Number.MAX_VALUE
|
@setMaxListeners Number.MAX_VALUE
|
||||||
@nextId = 0
|
@nextId = 0
|
||||||
|
|
||||||
# Stores all objects by ref-counting.
|
###
|
||||||
# (id) => {object, count}
|
Stores all objects by ref-counting.
|
||||||
|
(id) => {object, count}
|
||||||
|
###
|
||||||
@storage = {}
|
@storage = {}
|
||||||
|
|
||||||
# Stores the IDs of objects referenced by WebContents.
|
###
|
||||||
# (webContentsId) => {(id) => (count)}
|
Stores the IDs of objects referenced by WebContents.
|
||||||
|
(webContentsId) => {(id) => (count)}
|
||||||
|
###
|
||||||
@owners = {}
|
@owners = {}
|
||||||
|
|
||||||
# Register a new object, the object would be kept referenced until you release
|
###
|
||||||
# it explicitly.
|
Register a new object, the object would be kept referenced until you release
|
||||||
|
it explicitly.
|
||||||
|
###
|
||||||
add: (webContentsId, obj) ->
|
add: (webContentsId, obj) ->
|
||||||
id = @saveToStorage obj
|
id = @saveToStorage obj
|
||||||
# Remember the owner.
|
### Remember the owner. ###
|
||||||
@owners[webContentsId] ?= {}
|
@owners[webContentsId] ?= {}
|
||||||
@owners[webContentsId][id] ?= 0
|
@owners[webContentsId][id] ?= 0
|
||||||
@owners[webContentsId][id]++
|
@owners[webContentsId][id]++
|
||||||
# Returns object's id
|
### Returns object's id ###
|
||||||
id
|
id
|
||||||
|
|
||||||
# Get an object according to its ID.
|
### Get an object according to its ID. ###
|
||||||
get: (id) ->
|
get: (id) ->
|
||||||
@storage[id]?.object
|
@storage[id]?.object
|
||||||
|
|
||||||
# Dereference an object according to its ID.
|
### Dereference an object according to its ID. ###
|
||||||
remove: (webContentsId, id) ->
|
remove: (webContentsId, id) ->
|
||||||
@dereference id, 1
|
@dereference id, 1
|
||||||
# Also reduce the count in owner.
|
### Also reduce the count in owner. ###
|
||||||
pointer = @owners[webContentsId]
|
pointer = @owners[webContentsId]
|
||||||
return unless pointer?
|
return unless pointer?
|
||||||
--pointer[id]
|
--pointer[id]
|
||||||
delete pointer[id] if pointer[id] is 0
|
delete pointer[id] if pointer[id] is 0
|
||||||
|
|
||||||
# Clear all references to objects refrenced by the WebContents.
|
### Clear all references to objects refrenced by the WebContents. ###
|
||||||
clear: (webContentsId) ->
|
clear: (webContentsId) ->
|
||||||
@emit "clear-#{webContentsId}"
|
@emit "clear-#{webContentsId}"
|
||||||
return unless @owners[webContentsId]?
|
return unless @owners[webContentsId]?
|
||||||
@dereference id, count for id, count of @owners[webContentsId]
|
@dereference id, count for id, count of @owners[webContentsId]
|
||||||
delete @owners[webContentsId]
|
delete @owners[webContentsId]
|
||||||
|
|
||||||
# Private: Saves the object into storage and assigns an ID for it.
|
### Private: Saves the object into storage and assigns an ID for it. ###
|
||||||
saveToStorage: (object) ->
|
saveToStorage: (object) ->
|
||||||
id = v8Util.getHiddenValue object, 'atomId'
|
id = v8Util.getHiddenValue object, 'atomId'
|
||||||
unless id
|
unless id
|
||||||
|
@ -55,7 +61,7 @@ class ObjectsRegistry extends EventEmitter
|
||||||
++@storage[id].count
|
++@storage[id].count
|
||||||
id
|
id
|
||||||
|
|
||||||
# Private: Dereference the object from store.
|
### Private: Dereference the object from store. ###
|
||||||
dereference: (id, count) ->
|
dereference: (id, count) ->
|
||||||
pointer = @storage[id]
|
pointer = @storage[id]
|
||||||
return unless pointer?
|
return unless pointer?
|
||||||
|
|
|
@ -7,7 +7,7 @@ objectsRegistry = require './objects-registry'
|
||||||
v8Util = process.atomBinding 'v8_util'
|
v8Util = process.atomBinding 'v8_util'
|
||||||
{IDWeakMap} = process.atomBinding 'id_weak_map'
|
{IDWeakMap} = process.atomBinding 'id_weak_map'
|
||||||
|
|
||||||
# Convert a real value into meta data.
|
### Convert a real value into meta data. ###
|
||||||
valueToMeta = (sender, value, optimizeSimpleObject=false) ->
|
valueToMeta = (sender, value, optimizeSimpleObject=false) ->
|
||||||
meta = type: typeof value
|
meta = type: typeof value
|
||||||
|
|
||||||
|
@ -18,11 +18,11 @@ valueToMeta = (sender, value, optimizeSimpleObject=false) ->
|
||||||
meta.type = 'date' if value instanceof Date
|
meta.type = 'date' if value instanceof Date
|
||||||
meta.type = 'promise' if value?.constructor.name is 'Promise'
|
meta.type = 'promise' if value?.constructor.name is 'Promise'
|
||||||
|
|
||||||
# Treat simple objects as value.
|
### Treat simple objects as value. ###
|
||||||
if optimizeSimpleObject and meta.type is 'object' and v8Util.getHiddenValue value, 'simple'
|
if optimizeSimpleObject and meta.type is 'object' and v8Util.getHiddenValue value, 'simple'
|
||||||
meta.type = 'value'
|
meta.type = 'value'
|
||||||
|
|
||||||
# Treat the arguments object as array.
|
### Treat the arguments object as array. ###
|
||||||
meta.type = 'array' if meta.type is 'object' and value.callee? and value.length?
|
meta.type = 'array' if meta.type is 'object' and value.callee? and value.length?
|
||||||
|
|
||||||
if meta.type is 'array'
|
if meta.type is 'array'
|
||||||
|
@ -31,9 +31,11 @@ valueToMeta = (sender, value, optimizeSimpleObject=false) ->
|
||||||
else if meta.type is 'object' or meta.type is 'function'
|
else if meta.type is 'object' or meta.type is 'function'
|
||||||
meta.name = value.constructor.name
|
meta.name = value.constructor.name
|
||||||
|
|
||||||
# Reference the original value if it's an object, because when it's
|
###
|
||||||
# passed to renderer we would assume the renderer keeps a reference of
|
Reference the original value if it's an object, because when it's
|
||||||
# it.
|
passed to renderer we would assume the renderer keeps a reference of
|
||||||
|
it.
|
||||||
|
###
|
||||||
meta.id = objectsRegistry.add sender.getId(), value
|
meta.id = objectsRegistry.add sender.getId(), value
|
||||||
|
|
||||||
meta.members = ({name, type: typeof field} for name, field of value)
|
meta.members = ({name, type: typeof field} for name, field of value)
|
||||||
|
@ -43,7 +45,7 @@ valueToMeta = (sender, value, optimizeSimpleObject=false) ->
|
||||||
meta.then = valueToMeta sender, value.then.bind(value)
|
meta.then = valueToMeta sender, value.then.bind(value)
|
||||||
else if meta.type is 'error'
|
else if meta.type is 'error'
|
||||||
meta.members = plainObjectToMeta value
|
meta.members = plainObjectToMeta value
|
||||||
# Error.name is not part of own properties.
|
### Error.name is not part of own properties. ###
|
||||||
meta.members.push {name: 'name', value: value.name}
|
meta.members.push {name: 'name', value: value.name}
|
||||||
else if meta.type is 'date'
|
else if meta.type is 'date'
|
||||||
meta.value = value.getTime()
|
meta.value = value.getTime()
|
||||||
|
@ -53,15 +55,15 @@ valueToMeta = (sender, value, optimizeSimpleObject=false) ->
|
||||||
|
|
||||||
meta
|
meta
|
||||||
|
|
||||||
# Convert object to meta by value.
|
### Convert object to meta by value. ###
|
||||||
plainObjectToMeta = (obj) ->
|
plainObjectToMeta = (obj) ->
|
||||||
Object.getOwnPropertyNames(obj).map (name) -> {name, value: obj[name]}
|
Object.getOwnPropertyNames(obj).map (name) -> {name, value: obj[name]}
|
||||||
|
|
||||||
# Convert Error into meta data.
|
### Convert Error into meta data. ###
|
||||||
exceptionToMeta = (error) ->
|
exceptionToMeta = (error) ->
|
||||||
type: 'exception', message: error.message, stack: (error.stack || error)
|
type: 'exception', message: error.message, stack: (error.stack || error)
|
||||||
|
|
||||||
# Convert array of meta data from renderer into array of real values.
|
### Convert array of meta data from renderer into array of real values. ###
|
||||||
unwrapArgs = (sender, args) ->
|
unwrapArgs = (sender, args) ->
|
||||||
metaToValue = (meta) ->
|
metaToValue = (meta) ->
|
||||||
switch meta.type
|
switch meta.type
|
||||||
|
@ -80,7 +82,7 @@ unwrapArgs = (sender, args) ->
|
||||||
returnValue = metaToValue meta.value
|
returnValue = metaToValue meta.value
|
||||||
-> returnValue
|
-> returnValue
|
||||||
when 'function'
|
when 'function'
|
||||||
# Cache the callbacks in renderer.
|
### Cache the callbacks in renderer. ###
|
||||||
unless sender.callbacks
|
unless sender.callbacks
|
||||||
sender.callbacks = new IDWeakMap
|
sender.callbacks = new IDWeakMap
|
||||||
sender.on 'render-view-deleted', ->
|
sender.on 'render-view-deleted', ->
|
||||||
|
@ -106,8 +108,10 @@ unwrapArgs = (sender, args) ->
|
||||||
|
|
||||||
args.map metaToValue
|
args.map metaToValue
|
||||||
|
|
||||||
# Call a function and send reply asynchronously if it's a an asynchronous
|
###
|
||||||
# style function and the caller didn't pass a callback.
|
Call a function and send reply asynchronously if it's a an asynchronous
|
||||||
|
style function and the caller didn't pass a callback.
|
||||||
|
###
|
||||||
callFunction = (event, func, caller, args) ->
|
callFunction = (event, func, caller, args) ->
|
||||||
funcMarkedAsync = v8Util.getHiddenValue(func, 'asynchronous')
|
funcMarkedAsync = v8Util.getHiddenValue(func, 'asynchronous')
|
||||||
funcPassedCallback = typeof args[args.length - 1] is 'function'
|
funcPassedCallback = typeof args[args.length - 1] is 'function'
|
||||||
|
@ -121,15 +125,17 @@ callFunction = (event, func, caller, args) ->
|
||||||
ret = func.apply caller, args
|
ret = func.apply caller, args
|
||||||
event.returnValue = valueToMeta event.sender, ret, true
|
event.returnValue = valueToMeta event.sender, ret, true
|
||||||
catch e
|
catch e
|
||||||
# Catch functions thrown further down in function invocation and wrap
|
###
|
||||||
# them with the function name so it's easier to trace things like
|
Catch functions thrown further down in function invocation and wrap
|
||||||
# `Error processing argument -1.`
|
them with the function name so it's easier to trace things like
|
||||||
|
`Error processing argument -1.`
|
||||||
|
###
|
||||||
funcName = func.name ? "anonymous"
|
funcName = func.name ? "anonymous"
|
||||||
throw new Error("Could not call remote function `#{funcName}`.
|
throw new Error("Could not call remote function `#{funcName}`.
|
||||||
Check that the function signature is correct.
|
Check that the function signature is correct.
|
||||||
Underlying error: #{e.message}")
|
Underlying error: #{e.message}")
|
||||||
|
|
||||||
# Send by BrowserWindow when its render view is deleted.
|
### Send by BrowserWindow when its render view is deleted. ###
|
||||||
process.on 'ATOM_BROWSER_RELEASE_RENDER_VIEW', (id) ->
|
process.on 'ATOM_BROWSER_RELEASE_RENDER_VIEW', (id) ->
|
||||||
objectsRegistry.clear id
|
objectsRegistry.clear id
|
||||||
|
|
||||||
|
@ -164,8 +170,10 @@ ipcMain.on 'ATOM_BROWSER_CONSTRUCTOR', (event, id, args) ->
|
||||||
try
|
try
|
||||||
args = unwrapArgs event.sender, args
|
args = unwrapArgs event.sender, args
|
||||||
constructor = objectsRegistry.get id
|
constructor = objectsRegistry.get id
|
||||||
# Call new with array of arguments.
|
###
|
||||||
# http://stackoverflow.com/questions/1606797/use-of-apply-with-new-operator-is-this-possible
|
Call new with array of arguments.
|
||||||
|
http://stackoverflow.com/questions/1606797/use-of-apply-with-new-operator-is-this-possible
|
||||||
|
###
|
||||||
obj = new (Function::bind.apply(constructor, [null].concat(args)))
|
obj = new (Function::bind.apply(constructor, [null].concat(args)))
|
||||||
event.returnValue = valueToMeta event.sender, obj
|
event.returnValue = valueToMeta event.sender, obj
|
||||||
catch e
|
catch e
|
||||||
|
@ -183,7 +191,7 @@ ipcMain.on 'ATOM_BROWSER_MEMBER_CONSTRUCTOR', (event, id, method, args) ->
|
||||||
try
|
try
|
||||||
args = unwrapArgs event.sender, args
|
args = unwrapArgs event.sender, args
|
||||||
constructor = objectsRegistry.get(id)[method]
|
constructor = objectsRegistry.get(id)[method]
|
||||||
# Call new with array of arguments.
|
### Call new with array of arguments. ###
|
||||||
obj = new (Function::bind.apply(constructor, [null].concat(args)))
|
obj = new (Function::bind.apply(constructor, [null].concat(args)))
|
||||||
event.returnValue = valueToMeta event.sender, obj
|
event.returnValue = valueToMeta event.sender, obj
|
||||||
catch e
|
catch e
|
||||||
|
|
|
@ -7,14 +7,16 @@ class CallbacksRegistry
|
||||||
@callbacks = {}
|
@callbacks = {}
|
||||||
|
|
||||||
add: (callback) ->
|
add: (callback) ->
|
||||||
# The callback is already added.
|
### The callback is already added. ###
|
||||||
id = v8Util.getHiddenValue callback, 'callbackId'
|
id = v8Util.getHiddenValue callback, 'callbackId'
|
||||||
return id if id?
|
return id if id?
|
||||||
|
|
||||||
id = ++@nextId
|
id = ++@nextId
|
||||||
|
|
||||||
# Capture the location of the function and put it in the ID string,
|
###
|
||||||
# so that release errors can be tracked down easily.
|
Capture the location of the function and put it in the ID string,
|
||||||
|
so that release errors can be tracked down easily.
|
||||||
|
###
|
||||||
regexp = /at (.*)/gi
|
regexp = /at (.*)/gi
|
||||||
stackString = (new Error).stack
|
stackString = (new Error).stack
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
if process.platform is 'linux' and process.type is 'renderer'
|
if process.platform is 'linux' and process.type is 'renderer'
|
||||||
# On Linux we could not access clipboard in renderer process.
|
### On Linux we could not access clipboard in renderer process. ###
|
||||||
module.exports = require('electron').remote.clipboard
|
module.exports = require('electron').remote.clipboard
|
||||||
else
|
else
|
||||||
module.exports = process.atomBinding 'clipboard'
|
module.exports = process.atomBinding 'clipboard'
|
||||||
|
|
|
@ -10,7 +10,7 @@ class CrashReporter
|
||||||
start: (options={}) ->
|
start: (options={}) ->
|
||||||
{@productName, companyName, submitURL, autoSubmit, ignoreSystemCrashHandler, extra} = options
|
{@productName, companyName, submitURL, autoSubmit, ignoreSystemCrashHandler, extra} = options
|
||||||
|
|
||||||
# Deprecated.
|
### Deprecated. ###
|
||||||
{deprecate} = electron
|
{deprecate} = electron
|
||||||
if options.submitUrl
|
if options.submitUrl
|
||||||
submitURL ?= options.submitUrl
|
submitURL ?= options.submitUrl
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
# Deprecate a method.
|
### Deprecate a method. ###
|
||||||
deprecate = (oldName, newName, fn) ->
|
deprecate = (oldName, newName, fn) ->
|
||||||
warned = false
|
warned = false
|
||||||
->
|
->
|
||||||
|
@ -7,7 +7,7 @@ deprecate = (oldName, newName, fn) ->
|
||||||
deprecate.warn oldName, newName
|
deprecate.warn oldName, newName
|
||||||
fn.apply this, arguments
|
fn.apply this, arguments
|
||||||
|
|
||||||
# The method is renamed.
|
### The method is renamed. ###
|
||||||
deprecate.rename = (object, oldName, newName) ->
|
deprecate.rename = (object, oldName, newName) ->
|
||||||
warned = false
|
warned = false
|
||||||
newMethod = ->
|
newMethod = ->
|
||||||
|
@ -20,7 +20,7 @@ deprecate.rename = (object, oldName, newName) ->
|
||||||
else
|
else
|
||||||
object[oldName] = newMethod
|
object[oldName] = newMethod
|
||||||
|
|
||||||
# Forward the method to member.
|
### Forward the method to member. ###
|
||||||
deprecate.member = (object, method, member) ->
|
deprecate.member = (object, method, member) ->
|
||||||
warned = false
|
warned = false
|
||||||
object.prototype[method] = ->
|
object.prototype[method] = ->
|
||||||
|
@ -29,7 +29,7 @@ deprecate.member = (object, method, member) ->
|
||||||
deprecate.warn method, "#{member}.#{method}"
|
deprecate.warn method, "#{member}.#{method}"
|
||||||
this[member][method].apply this[member], arguments
|
this[member][method].apply this[member], arguments
|
||||||
|
|
||||||
# Deprecate a property.
|
### Deprecate a property. ###
|
||||||
deprecate.property = (object, property, method) ->
|
deprecate.property = (object, property, method) ->
|
||||||
Object.defineProperty object, property,
|
Object.defineProperty object, property,
|
||||||
get: ->
|
get: ->
|
||||||
|
@ -39,11 +39,12 @@ deprecate.property = (object, property, method) ->
|
||||||
deprecate.warn "#{property} property", "#{method} method"
|
deprecate.warn "#{property} property", "#{method} method"
|
||||||
this[method]()
|
this[method]()
|
||||||
|
|
||||||
# Deprecate an event.
|
### Deprecate an event. ###
|
||||||
deprecate.event = (emitter, oldName, newName, fn) ->
|
deprecate.event = (emitter, oldName, newName, fn) ->
|
||||||
warned = false
|
warned = false
|
||||||
emitter.on newName, (args...) ->
|
emitter.on newName, (args...) ->
|
||||||
if @listenerCount(oldName) > 0 # there is listeners for old API.
|
### there is listeners for old API. ###
|
||||||
|
if @listenerCount(oldName) > 0
|
||||||
unless warned or process.noDeprecation
|
unless warned or process.noDeprecation
|
||||||
warned = true
|
warned = true
|
||||||
deprecate.warn "'#{oldName}' event", "'#{newName}' event"
|
deprecate.warn "'#{oldName}' event", "'#{newName}' event"
|
||||||
|
@ -52,11 +53,11 @@ deprecate.event = (emitter, oldName, newName, fn) ->
|
||||||
else
|
else
|
||||||
@emit oldName, args...
|
@emit oldName, args...
|
||||||
|
|
||||||
# Print deprecation warning.
|
### Print deprecation warning. ###
|
||||||
deprecate.warn = (oldName, newName) ->
|
deprecate.warn = (oldName, newName) ->
|
||||||
deprecate.log "#{oldName} is deprecated. Use #{newName} instead."
|
deprecate.log "#{oldName} is deprecated. Use #{newName} instead."
|
||||||
|
|
||||||
# Print deprecation message.
|
### Print deprecation message. ###
|
||||||
deprecate.log = (message) ->
|
deprecate.log = (message) ->
|
||||||
if process.throwDeprecation
|
if process.throwDeprecation
|
||||||
throw new Error(message)
|
throw new Error(message)
|
||||||
|
|
|
@ -1,16 +1,16 @@
|
||||||
# Do not expose the internal modules to `require`.
|
### Do not expose the internal modules to `require`. ###
|
||||||
exports.hideInternalModules = ->
|
exports.hideInternalModules = ->
|
||||||
{globalPaths} = require 'module'
|
{globalPaths} = require 'module'
|
||||||
if globalPaths.length is 3
|
if globalPaths.length is 3
|
||||||
# Remove the "common/api/lib" and "browser-or-renderer/api/lib".
|
### Remove the "common/api/lib" and "browser-or-renderer/api/lib". ###
|
||||||
globalPaths.splice 0, 2
|
globalPaths.splice 0, 2
|
||||||
|
|
||||||
# Attaches properties to |exports|.
|
### Attaches properties to |exports|. ###
|
||||||
exports.defineProperties = (exports) ->
|
exports.defineProperties = (exports) ->
|
||||||
Object.defineProperties exports,
|
Object.defineProperties exports,
|
||||||
# Common modules, please sort with alphabet order.
|
### Common modules, please sort with alphabet order. ###
|
||||||
clipboard:
|
clipboard:
|
||||||
# Must be enumerable, otherwise it woulde be invisible to remote module.
|
### Must be enumerable, otherwise it woulde be invisible to remote module. ###
|
||||||
enumerable: true
|
enumerable: true
|
||||||
get: -> require '../clipboard'
|
get: -> require '../clipboard'
|
||||||
crashReporter:
|
crashReporter:
|
||||||
|
@ -22,7 +22,7 @@ exports.defineProperties = (exports) ->
|
||||||
shell:
|
shell:
|
||||||
enumerable: true
|
enumerable: true
|
||||||
get: -> require '../shell'
|
get: -> require '../shell'
|
||||||
# The internal modules, invisible unless you know their names.
|
### The internal modules, invisible unless you know their names. ###
|
||||||
CallbacksRegistry:
|
CallbacksRegistry:
|
||||||
get: -> require '../callbacks-registry'
|
get: -> require '../callbacks-registry'
|
||||||
deprecate:
|
deprecate:
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
{deprecate} = require 'electron'
|
{deprecate} = require 'electron'
|
||||||
nativeImage = process.atomBinding 'native_image'
|
nativeImage = process.atomBinding 'native_image'
|
||||||
|
|
||||||
# Deprecated.
|
### Deprecated. ###
|
||||||
deprecate.rename nativeImage, 'createFromDataUrl', 'createFromDataURL'
|
deprecate.rename nativeImage, 'createFromDataUrl', 'createFromDataURL'
|
||||||
|
|
||||||
module.exports = nativeImage
|
module.exports = nativeImage
|
||||||
|
|
|
@ -3,7 +3,7 @@ child_process = require 'child_process'
|
||||||
path = require 'path'
|
path = require 'path'
|
||||||
util = require 'util'
|
util = require 'util'
|
||||||
|
|
||||||
# Cache asar archive objects.
|
### Cache asar archive objects. ###
|
||||||
cachedArchives = {}
|
cachedArchives = {}
|
||||||
getOrCreateArchive = (p) ->
|
getOrCreateArchive = (p) ->
|
||||||
archive = cachedArchives[p]
|
archive = cachedArchives[p]
|
||||||
|
@ -12,13 +12,15 @@ getOrCreateArchive = (p) ->
|
||||||
return false unless archive
|
return false unless archive
|
||||||
cachedArchives[p] = archive
|
cachedArchives[p] = archive
|
||||||
|
|
||||||
# Clean cache on quit.
|
### Clean cache on quit. ###
|
||||||
process.on 'exit', ->
|
process.on 'exit', ->
|
||||||
archive.destroy() for own p, archive of cachedArchives
|
archive.destroy() for own p, archive of cachedArchives
|
||||||
|
|
||||||
# Separate asar package's path from full path.
|
### Separate asar package's path from full path. ###
|
||||||
splitPath = (p) ->
|
splitPath = (p) ->
|
||||||
return [false] if process.noAsar # shortcut to disable asar.
|
### shortcut to disable asar. ###
|
||||||
|
return [false] if process.noAsar
|
||||||
|
|
||||||
return [false] if typeof p isnt 'string'
|
return [false] if typeof p isnt 'string'
|
||||||
return [true, p, ''] if p.substr(-5) is '.asar'
|
return [true, p, ''] if p.substr(-5) is '.asar'
|
||||||
p = path.normalize p
|
p = path.normalize p
|
||||||
|
@ -26,7 +28,7 @@ splitPath = (p) ->
|
||||||
return [false] if index is -1
|
return [false] if index is -1
|
||||||
[true, p.substr(0, index + 5), p.substr(index + 6)]
|
[true, p.substr(0, index + 5), p.substr(index + 6)]
|
||||||
|
|
||||||
# Convert asar archive's Stats object to fs's Stats object.
|
### Convert asar archive's Stats object to fs's Stats object. ###
|
||||||
nextInode = 0
|
nextInode = 0
|
||||||
uid = if process.getuid? then process.getuid() else 0
|
uid = if process.getuid? then process.getuid() else 0
|
||||||
gid = if process.getgid? then process.getgid() else 0
|
gid = if process.getgid? then process.getgid() else 0
|
||||||
|
@ -54,7 +56,7 @@ asarStatsToFsStats = (stats) ->
|
||||||
isSocket: -> false
|
isSocket: -> false
|
||||||
}
|
}
|
||||||
|
|
||||||
# Create a ENOENT error.
|
### Create a ENOENT error. ###
|
||||||
notFoundError = (asarPath, filePath, callback) ->
|
notFoundError = (asarPath, filePath, callback) ->
|
||||||
error = new Error("ENOENT, #{filePath} not found in #{asarPath}")
|
error = new Error("ENOENT, #{filePath} not found in #{asarPath}")
|
||||||
error.code = "ENOENT"
|
error.code = "ENOENT"
|
||||||
|
@ -63,7 +65,7 @@ notFoundError = (asarPath, filePath, callback) ->
|
||||||
throw error
|
throw error
|
||||||
process.nextTick -> callback error
|
process.nextTick -> callback error
|
||||||
|
|
||||||
# Create a ENOTDIR error.
|
### Create a ENOTDIR error. ###
|
||||||
notDirError = (callback) ->
|
notDirError = (callback) ->
|
||||||
error = new Error('ENOTDIR, not a directory')
|
error = new Error('ENOTDIR, not a directory')
|
||||||
error.code = 'ENOTDIR'
|
error.code = 'ENOTDIR'
|
||||||
|
@ -72,14 +74,14 @@ notDirError = (callback) ->
|
||||||
throw error
|
throw error
|
||||||
process.nextTick -> callback error
|
process.nextTick -> callback error
|
||||||
|
|
||||||
# Create invalid archive error.
|
### Create invalid archive error. ###
|
||||||
invalidArchiveError = (asarPath, callback) ->
|
invalidArchiveError = (asarPath, callback) ->
|
||||||
error = new Error("Invalid package #{asarPath}")
|
error = new Error("Invalid package #{asarPath}")
|
||||||
unless typeof callback is 'function'
|
unless typeof callback is 'function'
|
||||||
throw error
|
throw error
|
||||||
process.nextTick -> callback error
|
process.nextTick -> callback error
|
||||||
|
|
||||||
# Override APIs that rely on passing file path instead of content to C++.
|
### Override APIs that rely on passing file path instead of content to C++. ###
|
||||||
overrideAPISync = (module, name, arg = 0) ->
|
overrideAPISync = (module, name, arg = 0) ->
|
||||||
old = module[name]
|
old = module[name]
|
||||||
module[name] = ->
|
module[name] = ->
|
||||||
|
@ -115,7 +117,7 @@ overrideAPI = (module, name, arg = 0) ->
|
||||||
arguments[arg] = newPath
|
arguments[arg] = newPath
|
||||||
old.apply this, arguments
|
old.apply this, arguments
|
||||||
|
|
||||||
# Override fs APIs.
|
### Override fs APIs. ###
|
||||||
exports.wrapFsWithAsar = (fs) ->
|
exports.wrapFsWithAsar = (fs) ->
|
||||||
lstatSync = fs.lstatSync
|
lstatSync = fs.lstatSync
|
||||||
fs.lstatSync = (p) ->
|
fs.lstatSync = (p) ->
|
||||||
|
@ -148,7 +150,7 @@ exports.wrapFsWithAsar = (fs) ->
|
||||||
[isAsar, asarPath, filePath] = splitPath p
|
[isAsar, asarPath, filePath] = splitPath p
|
||||||
return statSync p unless isAsar
|
return statSync p unless isAsar
|
||||||
|
|
||||||
# Do not distinguish links for now.
|
### Do not distinguish links for now. ###
|
||||||
fs.lstatSync p
|
fs.lstatSync p
|
||||||
|
|
||||||
stat = fs.stat
|
stat = fs.stat
|
||||||
|
@ -156,7 +158,7 @@ exports.wrapFsWithAsar = (fs) ->
|
||||||
[isAsar, asarPath, filePath] = splitPath p
|
[isAsar, asarPath, filePath] = splitPath p
|
||||||
return stat p, callback unless isAsar
|
return stat p, callback unless isAsar
|
||||||
|
|
||||||
# Do not distinguish links for now.
|
### Do not distinguish links for now. ###
|
||||||
process.nextTick -> fs.lstat p, callback
|
process.nextTick -> fs.lstat p, callback
|
||||||
|
|
||||||
statSyncNoException = fs.statSyncNoException
|
statSyncNoException = fs.statSyncNoException
|
||||||
|
@ -265,7 +267,9 @@ exports.wrapFsWithAsar = (fs) ->
|
||||||
openSync = fs.openSync
|
openSync = fs.openSync
|
||||||
readFileSync = fs.readFileSync
|
readFileSync = fs.readFileSync
|
||||||
fs.readFileSync = (p, opts) ->
|
fs.readFileSync = (p, opts) ->
|
||||||
options = opts # this allows v8 to optimize this function
|
### this allows v8 to optimize this function ###
|
||||||
|
options = opts
|
||||||
|
|
||||||
[isAsar, asarPath, filePath] = splitPath p
|
[isAsar, asarPath, filePath] = splitPath p
|
||||||
return readFileSync.apply this, arguments unless isAsar
|
return readFileSync.apply this, arguments unless isAsar
|
||||||
|
|
||||||
|
@ -353,17 +357,21 @@ exports.wrapFsWithAsar = (fs) ->
|
||||||
return internalModuleStat p unless isAsar
|
return internalModuleStat p unless isAsar
|
||||||
|
|
||||||
archive = getOrCreateArchive asarPath
|
archive = getOrCreateArchive asarPath
|
||||||
return -34 unless archive # -ENOENT
|
### -ENOENT ###
|
||||||
|
return -34 unless archive
|
||||||
|
|
||||||
stats = archive.stat filePath
|
stats = archive.stat filePath
|
||||||
return -34 unless stats # -ENOENT
|
### -ENOENT ###
|
||||||
|
return -34 unless stats
|
||||||
|
|
||||||
if stats.isDirectory then return 1 else return 0
|
if stats.isDirectory then return 1 else return 0
|
||||||
|
|
||||||
# Calling mkdir for directory inside asar archive should throw ENOTDIR
|
###
|
||||||
# error, but on Windows it throws ENOENT.
|
Calling mkdir for directory inside asar archive should throw ENOTDIR
|
||||||
# This is to work around the recursive looping bug of mkdirp since it is
|
error, but on Windows it throws ENOENT.
|
||||||
# widely used.
|
This is to work around the recursive looping bug of mkdirp since it is
|
||||||
|
widely used.
|
||||||
|
###
|
||||||
if process.platform is 'win32'
|
if process.platform is 'win32'
|
||||||
mkdir = fs.mkdir
|
mkdir = fs.mkdir
|
||||||
fs.mkdir = (p, mode, callback) ->
|
fs.mkdir = (p, mode, callback) ->
|
||||||
|
|
|
@ -1,13 +1,13 @@
|
||||||
return (process, require, asarSource) ->
|
return (process, require, asarSource) ->
|
||||||
{createArchive} = process.binding 'atom_common_asar'
|
{createArchive} = process.binding 'atom_common_asar'
|
||||||
|
|
||||||
# Make asar.coffee accessible via "require".
|
### Make asar.coffee accessible via "require". ###
|
||||||
process.binding('natives').ATOM_SHELL_ASAR = asarSource
|
process.binding('natives').ATOM_SHELL_ASAR = asarSource
|
||||||
|
|
||||||
# Monkey-patch the fs module.
|
### Monkey-patch the fs module. ###
|
||||||
require('ATOM_SHELL_ASAR').wrapFsWithAsar require('fs')
|
require('ATOM_SHELL_ASAR').wrapFsWithAsar require('fs')
|
||||||
|
|
||||||
# Make graceful-fs work with asar.
|
### Make graceful-fs work with asar. ###
|
||||||
source = process.binding 'natives'
|
source = process.binding 'natives'
|
||||||
source['original-fs'] = source.fs
|
source['original-fs'] = source.fs
|
||||||
source['fs'] = """
|
source['fs'] = """
|
||||||
|
|
|
@ -10,15 +10,17 @@ process.atomBinding = (name) ->
|
||||||
process.binding "atom_common_#{name}" if /No such module/.test e.message
|
process.binding "atom_common_#{name}" if /No such module/.test e.message
|
||||||
|
|
||||||
unless process.env.ELECTRON_HIDE_INTERNAL_MODULES
|
unless process.env.ELECTRON_HIDE_INTERNAL_MODULES
|
||||||
# Add common/api/lib to module search paths.
|
### Add common/api/lib to module search paths. ###
|
||||||
Module.globalPaths.push path.resolve(__dirname, '..', 'api', 'lib')
|
Module.globalPaths.push path.resolve(__dirname, '..', 'api', 'lib')
|
||||||
|
|
||||||
# setImmediate and process.nextTick makes use of uv_check and uv_prepare to
|
###
|
||||||
# run the callbacks, however since we only run uv loop on requests, the
|
setImmediate and process.nextTick makes use of uv_check and uv_prepare to
|
||||||
# callbacks wouldn't be called until something else activated the uv loop,
|
run the callbacks, however since we only run uv loop on requests, the
|
||||||
# which would delay the callbacks for arbitrary long time. So we should
|
callbacks wouldn't be called until something else activated the uv loop,
|
||||||
# initiatively activate the uv loop once setImmediate and process.nextTick is
|
which would delay the callbacks for arbitrary long time. So we should
|
||||||
# called.
|
initiatively activate the uv loop once setImmediate and process.nextTick is
|
||||||
|
called.
|
||||||
|
###
|
||||||
wrapWithActivateUvLoop = (func) ->
|
wrapWithActivateUvLoop = (func) ->
|
||||||
->
|
->
|
||||||
process.activateUvLoop()
|
process.activateUvLoop()
|
||||||
|
@ -28,9 +30,11 @@ global.setImmediate = wrapWithActivateUvLoop timers.setImmediate
|
||||||
global.clearImmediate = timers.clearImmediate
|
global.clearImmediate = timers.clearImmediate
|
||||||
|
|
||||||
if process.type is 'browser'
|
if process.type is 'browser'
|
||||||
# setTimeout needs to update the polling timeout of the event loop, when
|
###
|
||||||
# called under Chromium's event loop the node's event loop won't get a chance
|
setTimeout needs to update the polling timeout of the event loop, when
|
||||||
# to update the timeout, so we have to force the node's event loop to
|
called under Chromium's event loop the node's event loop won't get a chance
|
||||||
# recalculate the timeout in browser process.
|
to update the timeout, so we have to force the node's event loop to
|
||||||
|
recalculate the timeout in browser process.
|
||||||
|
###
|
||||||
global.setTimeout = wrapWithActivateUvLoop timers.setTimeout
|
global.setTimeout = wrapWithActivateUvLoop timers.setTimeout
|
||||||
global.setInterval = wrapWithActivateUvLoop timers.setInterval
|
global.setInterval = wrapWithActivateUvLoop timers.setInterval
|
||||||
|
|
|
@ -1,21 +1,21 @@
|
||||||
path = require 'path'
|
path = require 'path'
|
||||||
Module = require 'module'
|
Module = require 'module'
|
||||||
|
|
||||||
# Clear Node's global search paths.
|
### Clear Node's global search paths. ###
|
||||||
Module.globalPaths.length = 0
|
Module.globalPaths.length = 0
|
||||||
|
|
||||||
# Clear current and parent(init.coffee)'s search paths.
|
### Clear current and parent(init.coffee)'s search paths. ###
|
||||||
module.paths = []
|
module.paths = []
|
||||||
module.parent.paths = []
|
module.parent.paths = []
|
||||||
|
|
||||||
# Prevent Node from adding paths outside this app to search paths.
|
### Prevent Node from adding paths outside this app to search paths. ###
|
||||||
Module._nodeModulePaths = (from) ->
|
Module._nodeModulePaths = (from) ->
|
||||||
from = path.resolve from
|
from = path.resolve from
|
||||||
|
|
||||||
# If "from" is outside the app then we do nothing.
|
### If "from" is outside the app then we do nothing. ###
|
||||||
skipOutsidePaths = from.startsWith process.resourcesPath
|
skipOutsidePaths = from.startsWith process.resourcesPath
|
||||||
|
|
||||||
# Following logoic is copied from module.js.
|
### Following logoic is copied from module.js. ###
|
||||||
splitRe = if process.platform is 'win32' then /[\/\\]/ else /\//
|
splitRe = if process.platform is 'win32' then /[\/\\]/ else /\//
|
||||||
paths = []
|
paths = []
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
nextId = 0
|
nextId = 0
|
||||||
getNextId = -> ++nextId
|
getNextId = -> ++nextId
|
||||||
|
|
||||||
# |options.type| can not be empty and has to include 'window' or 'screen'.
|
### |options.type| can not be empty and has to include 'window' or 'screen'. ###
|
||||||
isValid = (options) ->
|
isValid = (options) ->
|
||||||
return options?.types? and Array.isArray options.types
|
return options?.types? and Array.isArray options.types
|
||||||
|
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
common = require '../../../../common/api/lib/exports/electron'
|
common = require '../../../../common/api/lib/exports/electron'
|
||||||
|
|
||||||
# Import common modules.
|
### Import common modules. ###
|
||||||
common.defineProperties exports
|
common.defineProperties exports
|
||||||
|
|
||||||
Object.defineProperties exports,
|
Object.defineProperties exports,
|
||||||
# Renderer side modules, please sort with alphabet order.
|
### Renderer side modules, please sort with alphabet order. ###
|
||||||
desktopCapturer:
|
desktopCapturer:
|
||||||
enumerable: true
|
enumerable: true
|
||||||
get: -> require '../desktop-capturer'
|
get: -> require '../desktop-capturer'
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
binding = process.atomBinding 'ipc'
|
binding = process.atomBinding 'ipc'
|
||||||
v8Util = process.atomBinding 'v8_util'
|
v8Util = process.atomBinding 'v8_util'
|
||||||
|
|
||||||
# Created by init.coffee.
|
### Created by init.coffee. ###
|
||||||
ipcRenderer = v8Util.getHiddenValue global, 'ipc'
|
ipcRenderer = v8Util.getHiddenValue global, 'ipc'
|
||||||
|
|
||||||
ipcRenderer.send = (args...) ->
|
ipcRenderer.send = (args...) ->
|
||||||
|
|
|
@ -1,16 +1,16 @@
|
||||||
{ipcRenderer, deprecate} = require 'electron'
|
{ipcRenderer, deprecate} = require 'electron'
|
||||||
{EventEmitter} = require 'events'
|
{EventEmitter} = require 'events'
|
||||||
|
|
||||||
# This module is deprecated, we mirror everything from ipcRenderer.
|
### This module is deprecated, we mirror everything from ipcRenderer. ###
|
||||||
deprecate.warn 'ipc module', 'require("electron").ipcRenderer'
|
deprecate.warn 'ipc module', 'require("electron").ipcRenderer'
|
||||||
|
|
||||||
# Routes events of ipcRenderer.
|
### Routes events of ipcRenderer. ###
|
||||||
ipc = new EventEmitter
|
ipc = new EventEmitter
|
||||||
ipcRenderer.emit = (channel, event, args...) ->
|
ipcRenderer.emit = (channel, event, args...) ->
|
||||||
ipc.emit channel, args...
|
ipc.emit channel, args...
|
||||||
EventEmitter::emit.apply ipcRenderer, arguments
|
EventEmitter::emit.apply ipcRenderer, arguments
|
||||||
|
|
||||||
# Deprecated.
|
### Deprecated. ###
|
||||||
for method of ipcRenderer when method.startsWith 'send'
|
for method of ipcRenderer when method.startsWith 'send'
|
||||||
ipc[method] = ipcRenderer[method]
|
ipc[method] = ipcRenderer[method]
|
||||||
deprecate.rename ipc, 'sendChannel', 'send'
|
deprecate.rename ipc, 'sendChannel', 'send'
|
||||||
|
|
|
@ -3,7 +3,7 @@ v8Util = process.atomBinding 'v8_util'
|
||||||
|
|
||||||
callbacksRegistry = new CallbacksRegistry
|
callbacksRegistry = new CallbacksRegistry
|
||||||
|
|
||||||
# Check for circular reference.
|
### Check for circular reference. ###
|
||||||
isCircular = (field, visited) ->
|
isCircular = (field, visited) ->
|
||||||
if typeof field is 'object'
|
if typeof field is 'object'
|
||||||
if field in visited
|
if field in visited
|
||||||
|
@ -11,7 +11,7 @@ isCircular = (field, visited) ->
|
||||||
visited.push field
|
visited.push field
|
||||||
return false
|
return false
|
||||||
|
|
||||||
# Convert the arguments object into an array of meta data.
|
### Convert the arguments object into an array of meta data. ###
|
||||||
wrapArgs = (args, visited=[]) ->
|
wrapArgs = (args, visited=[]) ->
|
||||||
valueToMeta = (value) ->
|
valueToMeta = (value) ->
|
||||||
if Array.isArray value
|
if Array.isArray value
|
||||||
|
@ -40,7 +40,7 @@ wrapArgs = (args, visited=[]) ->
|
||||||
|
|
||||||
Array::slice.call(args).map valueToMeta
|
Array::slice.call(args).map valueToMeta
|
||||||
|
|
||||||
# Convert meta data from browser into real value.
|
### Convert meta data from browser into real value. ###
|
||||||
metaToValue = (meta) ->
|
metaToValue = (meta) ->
|
||||||
switch meta.type
|
switch meta.type
|
||||||
when 'value' then meta.value
|
when 'value' then meta.value
|
||||||
|
@ -53,43 +53,47 @@ metaToValue = (meta) ->
|
||||||
throw new Error("#{meta.message}\n#{meta.stack}")
|
throw new Error("#{meta.message}\n#{meta.stack}")
|
||||||
else
|
else
|
||||||
if meta.type is 'function'
|
if meta.type is 'function'
|
||||||
# A shadow class to represent the remote function object.
|
### A shadow class to represent the remote function object. ###
|
||||||
ret =
|
ret =
|
||||||
class RemoteFunction
|
class RemoteFunction
|
||||||
constructor: ->
|
constructor: ->
|
||||||
if @constructor == RemoteFunction
|
if @constructor == RemoteFunction
|
||||||
# Constructor call.
|
### Constructor call. ###
|
||||||
obj = ipcRenderer.sendSync 'ATOM_BROWSER_CONSTRUCTOR', meta.id, wrapArgs(arguments)
|
obj = ipcRenderer.sendSync 'ATOM_BROWSER_CONSTRUCTOR', meta.id, wrapArgs(arguments)
|
||||||
|
|
||||||
# Returning object in constructor will replace constructed object
|
###
|
||||||
# with the returned object.
|
Returning object in constructor will replace constructed object
|
||||||
# http://stackoverflow.com/questions/1978049/what-values-can-a-constructor-return-to-avoid-returning-this
|
with the returned object.
|
||||||
|
http://stackoverflow.com/questions/1978049/what-values-can-a-constructor-return-to-avoid-returning-this
|
||||||
|
###
|
||||||
return metaToValue obj
|
return metaToValue obj
|
||||||
else
|
else
|
||||||
# Function call.
|
### Function call. ###
|
||||||
obj = ipcRenderer.sendSync 'ATOM_BROWSER_FUNCTION_CALL', meta.id, wrapArgs(arguments)
|
obj = ipcRenderer.sendSync 'ATOM_BROWSER_FUNCTION_CALL', meta.id, wrapArgs(arguments)
|
||||||
return metaToValue obj
|
return metaToValue obj
|
||||||
else
|
else
|
||||||
ret = v8Util.createObjectWithName meta.name
|
ret = v8Util.createObjectWithName meta.name
|
||||||
|
|
||||||
# Polulate delegate members.
|
### Polulate delegate members. ###
|
||||||
for member in meta.members
|
for member in meta.members
|
||||||
if member.type is 'function'
|
if member.type is 'function'
|
||||||
ret[member.name] = createRemoteMemberFunction meta.id, member.name
|
ret[member.name] = createRemoteMemberFunction meta.id, member.name
|
||||||
else
|
else
|
||||||
Object.defineProperty ret, member.name, createRemoteMemberProperty(meta.id, member.name)
|
Object.defineProperty ret, member.name, createRemoteMemberProperty(meta.id, member.name)
|
||||||
|
|
||||||
# Track delegate object's life time, and tell the browser to clean up
|
###
|
||||||
# when the object is GCed.
|
Track delegate object's life time, and tell the browser to clean up
|
||||||
|
when the object is GCed.
|
||||||
|
###
|
||||||
v8Util.setDestructor ret, ->
|
v8Util.setDestructor ret, ->
|
||||||
ipcRenderer.send 'ATOM_BROWSER_DEREFERENCE', meta.id
|
ipcRenderer.send 'ATOM_BROWSER_DEREFERENCE', meta.id
|
||||||
|
|
||||||
# Remember object's id.
|
### Remember object's id. ###
|
||||||
v8Util.setHiddenValue ret, 'atomId', meta.id
|
v8Util.setHiddenValue ret, 'atomId', meta.id
|
||||||
|
|
||||||
ret
|
ret
|
||||||
|
|
||||||
# Construct a plain object from the meta.
|
### Construct a plain object from the meta. ###
|
||||||
metaToPlainObject = (meta) ->
|
metaToPlainObject = (meta) ->
|
||||||
obj = switch meta.type
|
obj = switch meta.type
|
||||||
when 'error' then new Error
|
when 'error' then new Error
|
||||||
|
@ -97,53 +101,59 @@ metaToPlainObject = (meta) ->
|
||||||
obj[name] = value for {name, value} in meta.members
|
obj[name] = value for {name, value} in meta.members
|
||||||
obj
|
obj
|
||||||
|
|
||||||
# Create a RemoteMemberFunction instance.
|
###
|
||||||
# This function's content should not be inlined into metaToValue, otherwise V8
|
Create a RemoteMemberFunction instance.
|
||||||
# may consider it circular reference.
|
This function's content should not be inlined into metaToValue, otherwise V8
|
||||||
|
may consider it circular reference.
|
||||||
|
###
|
||||||
createRemoteMemberFunction = (metaId, name) ->
|
createRemoteMemberFunction = (metaId, name) ->
|
||||||
class RemoteMemberFunction
|
class RemoteMemberFunction
|
||||||
constructor: ->
|
constructor: ->
|
||||||
if @constructor is RemoteMemberFunction
|
if @constructor is RemoteMemberFunction
|
||||||
# Constructor call.
|
### Constructor call. ###
|
||||||
ret = ipcRenderer.sendSync 'ATOM_BROWSER_MEMBER_CONSTRUCTOR', metaId, name, wrapArgs(arguments)
|
ret = ipcRenderer.sendSync 'ATOM_BROWSER_MEMBER_CONSTRUCTOR', metaId, name, wrapArgs(arguments)
|
||||||
return metaToValue ret
|
return metaToValue ret
|
||||||
else
|
else
|
||||||
# Call member function.
|
### Call member function. ###
|
||||||
ret = ipcRenderer.sendSync 'ATOM_BROWSER_MEMBER_CALL', metaId, name, wrapArgs(arguments)
|
ret = ipcRenderer.sendSync 'ATOM_BROWSER_MEMBER_CALL', metaId, name, wrapArgs(arguments)
|
||||||
return metaToValue ret
|
return metaToValue ret
|
||||||
|
|
||||||
# Create configuration for defineProperty.
|
###
|
||||||
# This function's content should not be inlined into metaToValue, otherwise V8
|
Create configuration for defineProperty.
|
||||||
# may consider it circular reference.
|
This function's content should not be inlined into metaToValue, otherwise V8
|
||||||
|
may consider it circular reference.
|
||||||
|
###
|
||||||
createRemoteMemberProperty = (metaId, name) ->
|
createRemoteMemberProperty = (metaId, name) ->
|
||||||
enumerable: true,
|
enumerable: true,
|
||||||
configurable: false,
|
configurable: false,
|
||||||
set: (value) ->
|
set: (value) ->
|
||||||
# Set member data.
|
### Set member data. ###
|
||||||
ipcRenderer.sendSync 'ATOM_BROWSER_MEMBER_SET', metaId, name, value
|
ipcRenderer.sendSync 'ATOM_BROWSER_MEMBER_SET', metaId, name, value
|
||||||
value
|
value
|
||||||
get: ->
|
get: ->
|
||||||
# Get member data.
|
### Get member data. ###
|
||||||
metaToValue ipcRenderer.sendSync('ATOM_BROWSER_MEMBER_GET', metaId, name)
|
metaToValue ipcRenderer.sendSync('ATOM_BROWSER_MEMBER_GET', metaId, name)
|
||||||
|
|
||||||
# Browser calls a callback in renderer.
|
### Browser calls a callback in renderer. ###
|
||||||
ipcRenderer.on 'ATOM_RENDERER_CALLBACK', (event, id, args) ->
|
ipcRenderer.on 'ATOM_RENDERER_CALLBACK', (event, id, args) ->
|
||||||
callbacksRegistry.apply id, metaToValue(args)
|
callbacksRegistry.apply id, metaToValue(args)
|
||||||
|
|
||||||
# A callback in browser is released.
|
### A callback in browser is released. ###
|
||||||
ipcRenderer.on 'ATOM_RENDERER_RELEASE_CALLBACK', (event, id) ->
|
ipcRenderer.on 'ATOM_RENDERER_RELEASE_CALLBACK', (event, id) ->
|
||||||
callbacksRegistry.remove id
|
callbacksRegistry.remove id
|
||||||
|
|
||||||
# List all built-in modules in browser process.
|
### List all built-in modules in browser process. ###
|
||||||
browserModules = require '../../../browser/api/lib/exports/electron'
|
browserModules = require '../../../browser/api/lib/exports/electron'
|
||||||
# And add a helper receiver for each one.
|
### And add a helper receiver for each one. ###
|
||||||
for name of browserModules
|
for name of browserModules
|
||||||
do (name) ->
|
do (name) ->
|
||||||
Object.defineProperty exports, name, get: -> exports.getBuiltin name
|
Object.defineProperty exports, name, get: -> exports.getBuiltin name
|
||||||
|
|
||||||
# Get remote module.
|
###
|
||||||
# (Just like node's require, the modules are cached permanently, note that this
|
Get remote module.
|
||||||
# is safe leak since the object is not expected to get freed in browser)
|
(Just like node's require, the modules are cached permanently, note that this
|
||||||
|
is safe leak since the object is not expected to get freed in browser)
|
||||||
|
###
|
||||||
moduleCache = {}
|
moduleCache = {}
|
||||||
exports.require = (module) ->
|
exports.require = (module) ->
|
||||||
return moduleCache[module] if moduleCache[module]?
|
return moduleCache[module] if moduleCache[module]?
|
||||||
|
@ -151,10 +161,10 @@ exports.require = (module) ->
|
||||||
meta = ipcRenderer.sendSync 'ATOM_BROWSER_REQUIRE', module
|
meta = ipcRenderer.sendSync 'ATOM_BROWSER_REQUIRE', module
|
||||||
moduleCache[module] = metaToValue meta
|
moduleCache[module] = metaToValue meta
|
||||||
|
|
||||||
# Optimize require('electron').
|
### Optimize require('electron'). ###
|
||||||
moduleCache.electron = exports
|
moduleCache.electron = exports
|
||||||
|
|
||||||
# Alias to remote.require('electron').xxx.
|
### Alias to remote.require('electron').xxx. ###
|
||||||
builtinCache = {}
|
builtinCache = {}
|
||||||
exports.getBuiltin = (module) ->
|
exports.getBuiltin = (module) ->
|
||||||
return builtinCache[module] if builtinCache[module]?
|
return builtinCache[module] if builtinCache[module]?
|
||||||
|
@ -162,38 +172,38 @@ exports.getBuiltin = (module) ->
|
||||||
meta = ipcRenderer.sendSync 'ATOM_BROWSER_GET_BUILTIN', module
|
meta = ipcRenderer.sendSync 'ATOM_BROWSER_GET_BUILTIN', module
|
||||||
builtinCache[module] = metaToValue meta
|
builtinCache[module] = metaToValue meta
|
||||||
|
|
||||||
# Get current BrowserWindow object.
|
### Get current BrowserWindow object. ###
|
||||||
windowCache = null
|
windowCache = null
|
||||||
exports.getCurrentWindow = ->
|
exports.getCurrentWindow = ->
|
||||||
return windowCache if windowCache?
|
return windowCache if windowCache?
|
||||||
meta = ipcRenderer.sendSync 'ATOM_BROWSER_CURRENT_WINDOW'
|
meta = ipcRenderer.sendSync 'ATOM_BROWSER_CURRENT_WINDOW'
|
||||||
windowCache = metaToValue meta
|
windowCache = metaToValue meta
|
||||||
|
|
||||||
# Get current WebContents object.
|
### Get current WebContents object. ###
|
||||||
webContentsCache = null
|
webContentsCache = null
|
||||||
exports.getCurrentWebContents = ->
|
exports.getCurrentWebContents = ->
|
||||||
return webContentsCache if webContentsCache?
|
return webContentsCache if webContentsCache?
|
||||||
meta = ipcRenderer.sendSync 'ATOM_BROWSER_CURRENT_WEB_CONTENTS'
|
meta = ipcRenderer.sendSync 'ATOM_BROWSER_CURRENT_WEB_CONTENTS'
|
||||||
webContentsCache = metaToValue meta
|
webContentsCache = metaToValue meta
|
||||||
|
|
||||||
# Get a global object in browser.
|
### Get a global object in browser. ###
|
||||||
exports.getGlobal = (name) ->
|
exports.getGlobal = (name) ->
|
||||||
meta = ipcRenderer.sendSync 'ATOM_BROWSER_GLOBAL', name
|
meta = ipcRenderer.sendSync 'ATOM_BROWSER_GLOBAL', name
|
||||||
metaToValue meta
|
metaToValue meta
|
||||||
|
|
||||||
# Get the process object in browser.
|
### Get the process object in browser. ###
|
||||||
processCache = null
|
processCache = null
|
||||||
exports.__defineGetter__ 'process', ->
|
exports.__defineGetter__ 'process', ->
|
||||||
processCache = exports.getGlobal('process') unless processCache?
|
processCache = exports.getGlobal('process') unless processCache?
|
||||||
processCache
|
processCache
|
||||||
|
|
||||||
# Create a funtion that will return the specifed value when called in browser.
|
### Create a funtion that will return the specifed value when called in browser. ###
|
||||||
exports.createFunctionWithReturnValue = (returnValue) ->
|
exports.createFunctionWithReturnValue = (returnValue) ->
|
||||||
func = -> returnValue
|
func = -> returnValue
|
||||||
v8Util.setHiddenValue func, 'returnValue', true
|
v8Util.setHiddenValue func, 'returnValue', true
|
||||||
func
|
func
|
||||||
|
|
||||||
# Get the guest WebContents from guestInstanceId.
|
### Get the guest WebContents from guestInstanceId. ###
|
||||||
exports.getGuestWebContents = (guestInstanceId) ->
|
exports.getGuestWebContents = (guestInstanceId) ->
|
||||||
meta = ipcRenderer.sendSync 'ATOM_BROWSER_GUEST_WEB_CONTENTS', guestInstanceId
|
meta = ipcRenderer.sendSync 'ATOM_BROWSER_GUEST_WEB_CONTENTS', guestInstanceId
|
||||||
metaToValue meta
|
metaToValue meta
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
{deprecate} = require 'electron'
|
{deprecate} = require 'electron'
|
||||||
{webFrame} = process.atomBinding 'web_frame'
|
{webFrame} = process.atomBinding 'web_frame'
|
||||||
|
|
||||||
# Deprecated.
|
### Deprecated. ###
|
||||||
deprecate.rename webFrame, 'registerUrlSchemeAsSecure', 'registerURLSchemeAsSecure'
|
deprecate.rename webFrame, 'registerUrlSchemeAsSecure', 'registerURLSchemeAsSecure'
|
||||||
deprecate.rename webFrame, 'registerUrlSchemeAsBypassingCSP', 'registerURLSchemeAsBypassingCSP'
|
deprecate.rename webFrame, 'registerUrlSchemeAsBypassingCSP', 'registerURLSchemeAsBypassingCSP'
|
||||||
deprecate.rename webFrame, 'registerUrlSchemeAsPrivileged', 'registerURLSchemeAsPrivileged'
|
deprecate.rename webFrame, 'registerUrlSchemeAsPrivileged', 'registerURLSchemeAsPrivileged'
|
||||||
|
|
|
@ -3,35 +3,37 @@ path = require 'path'
|
||||||
url = require 'url'
|
url = require 'url'
|
||||||
Module = require 'module'
|
Module = require 'module'
|
||||||
|
|
||||||
# We modified the original process.argv to let node.js load the
|
###
|
||||||
# atom-renderer.js, we need to restore it here.
|
We modified the original process.argv to let node.js load the
|
||||||
|
atom-renderer.js, we need to restore it here.
|
||||||
|
###
|
||||||
process.argv.splice 1, 1
|
process.argv.splice 1, 1
|
||||||
|
|
||||||
# Clear search paths.
|
### Clear search paths. ###
|
||||||
require path.resolve(__dirname, '..', '..', 'common', 'lib', 'reset-search-paths')
|
require path.resolve(__dirname, '..', '..', 'common', 'lib', 'reset-search-paths')
|
||||||
|
|
||||||
# Import common settings.
|
### Import common settings. ###
|
||||||
require path.resolve(__dirname, '..', '..', 'common', 'lib', 'init')
|
require path.resolve(__dirname, '..', '..', 'common', 'lib', 'init')
|
||||||
|
|
||||||
globalPaths = Module.globalPaths
|
globalPaths = Module.globalPaths
|
||||||
unless process.env.ELECTRON_HIDE_INTERNAL_MODULES
|
unless process.env.ELECTRON_HIDE_INTERNAL_MODULES
|
||||||
globalPaths.push path.resolve(__dirname, '..', 'api', 'lib')
|
globalPaths.push path.resolve(__dirname, '..', 'api', 'lib')
|
||||||
|
|
||||||
# Expose public APIs.
|
### Expose public APIs. ###
|
||||||
globalPaths.push path.resolve(__dirname, '..', 'api', 'lib', 'exports')
|
globalPaths.push path.resolve(__dirname, '..', 'api', 'lib', 'exports')
|
||||||
|
|
||||||
# The global variable will be used by ipc for event dispatching
|
### The global variable will be used by ipc for event dispatching ###
|
||||||
v8Util = process.atomBinding 'v8_util'
|
v8Util = process.atomBinding 'v8_util'
|
||||||
v8Util.setHiddenValue global, 'ipc', new events.EventEmitter
|
v8Util.setHiddenValue global, 'ipc', new events.EventEmitter
|
||||||
|
|
||||||
# Process command line arguments.
|
### Process command line arguments. ###
|
||||||
nodeIntegration = 'false'
|
nodeIntegration = 'false'
|
||||||
for arg in process.argv
|
for arg in process.argv
|
||||||
if arg.indexOf('--guest-instance-id=') == 0
|
if arg.indexOf('--guest-instance-id=') == 0
|
||||||
# This is a guest web view.
|
### This is a guest web view. ###
|
||||||
process.guestInstanceId = parseInt arg.substr(arg.indexOf('=') + 1)
|
process.guestInstanceId = parseInt arg.substr(arg.indexOf('=') + 1)
|
||||||
else if arg.indexOf('--opener-id=') == 0
|
else if arg.indexOf('--opener-id=') == 0
|
||||||
# This is a guest BrowserWindow.
|
### This is a guest BrowserWindow. ###
|
||||||
process.openerId = parseInt arg.substr(arg.indexOf('=') + 1)
|
process.openerId = parseInt arg.substr(arg.indexOf('=') + 1)
|
||||||
else if arg.indexOf('--node-integration=') == 0
|
else if arg.indexOf('--node-integration=') == 0
|
||||||
nodeIntegration = arg.substr arg.indexOf('=') + 1
|
nodeIntegration = arg.substr arg.indexOf('=') + 1
|
||||||
|
@ -39,27 +41,27 @@ for arg in process.argv
|
||||||
preloadScript = arg.substr arg.indexOf('=') + 1
|
preloadScript = arg.substr arg.indexOf('=') + 1
|
||||||
|
|
||||||
if location.protocol is 'chrome-devtools:'
|
if location.protocol is 'chrome-devtools:'
|
||||||
# Override some inspector APIs.
|
### Override some inspector APIs. ###
|
||||||
require './inspector'
|
require './inspector'
|
||||||
nodeIntegration = 'true'
|
nodeIntegration = 'true'
|
||||||
else if location.protocol is 'chrome-extension:'
|
else if location.protocol is 'chrome-extension:'
|
||||||
# Add implementations of chrome API.
|
### Add implementations of chrome API. ###
|
||||||
require './chrome-api'
|
require './chrome-api'
|
||||||
nodeIntegration = 'true'
|
nodeIntegration = 'true'
|
||||||
else
|
else
|
||||||
# Override default web functions.
|
### Override default web functions. ###
|
||||||
require './override'
|
require './override'
|
||||||
# Load webview tag implementation.
|
### Load webview tag implementation. ###
|
||||||
unless process.guestInstanceId?
|
unless process.guestInstanceId?
|
||||||
require './web-view/web-view'
|
require './web-view/web-view'
|
||||||
require './web-view/web-view-attributes'
|
require './web-view/web-view-attributes'
|
||||||
|
|
||||||
if nodeIntegration in ['true', 'all', 'except-iframe', 'manual-enable-iframe']
|
if nodeIntegration in ['true', 'all', 'except-iframe', 'manual-enable-iframe']
|
||||||
# Export node bindings to global.
|
### Export node bindings to global. ###
|
||||||
global.require = require
|
global.require = require
|
||||||
global.module = module
|
global.module = module
|
||||||
|
|
||||||
# Set the __filename to the path of html file if it is file: protocol.
|
### Set the __filename to the path of html file if it is file: protocol. ###
|
||||||
if window.location.protocol is 'file:'
|
if window.location.protocol is 'file:'
|
||||||
pathname =
|
pathname =
|
||||||
if process.platform is 'win32' and window.location.pathname[0] is '/'
|
if process.platform is 'win32' and window.location.pathname[0] is '/'
|
||||||
|
@ -69,16 +71,16 @@ if nodeIntegration in ['true', 'all', 'except-iframe', 'manual-enable-iframe']
|
||||||
global.__filename = path.normalize decodeURIComponent(pathname)
|
global.__filename = path.normalize decodeURIComponent(pathname)
|
||||||
global.__dirname = path.dirname global.__filename
|
global.__dirname = path.dirname global.__filename
|
||||||
|
|
||||||
# Set module's filename so relative require can work as expected.
|
### Set module's filename so relative require can work as expected. ###
|
||||||
module.filename = global.__filename
|
module.filename = global.__filename
|
||||||
|
|
||||||
# Also search for module under the html file.
|
### Also search for module under the html file. ###
|
||||||
module.paths = module.paths.concat Module._nodeModulePaths(global.__dirname)
|
module.paths = module.paths.concat Module._nodeModulePaths(global.__dirname)
|
||||||
else
|
else
|
||||||
global.__filename = __filename
|
global.__filename = __filename
|
||||||
global.__dirname = __dirname
|
global.__dirname = __dirname
|
||||||
|
|
||||||
# Redirect window.onerror to uncaughtException.
|
### Redirect window.onerror to uncaughtException. ###
|
||||||
window.onerror = (message, filename, lineno, colno, error) ->
|
window.onerror = (message, filename, lineno, colno, error) ->
|
||||||
if global.process.listeners('uncaughtException').length > 0
|
if global.process.listeners('uncaughtException').length > 0
|
||||||
global.process.emit 'uncaughtException', error
|
global.process.emit 'uncaughtException', error
|
||||||
|
@ -86,18 +88,18 @@ if nodeIntegration in ['true', 'all', 'except-iframe', 'manual-enable-iframe']
|
||||||
else
|
else
|
||||||
false
|
false
|
||||||
|
|
||||||
# Emit the 'exit' event when page is unloading.
|
### Emit the 'exit' event when page is unloading. ###
|
||||||
window.addEventListener 'unload', ->
|
window.addEventListener 'unload', ->
|
||||||
process.emit 'exit'
|
process.emit 'exit'
|
||||||
else
|
else
|
||||||
# Delete Node's symbols after the Environment has been loaded.
|
### Delete Node's symbols after the Environment has been loaded. ###
|
||||||
process.once 'loaded', ->
|
process.once 'loaded', ->
|
||||||
delete global.process
|
delete global.process
|
||||||
delete global.setImmediate
|
delete global.setImmediate
|
||||||
delete global.clearImmediate
|
delete global.clearImmediate
|
||||||
delete global.global
|
delete global.global
|
||||||
|
|
||||||
# Load the script specfied by the "preload" attribute.
|
### Load the script specfied by the "preload" attribute. ###
|
||||||
if preloadScript
|
if preloadScript
|
||||||
try
|
try
|
||||||
require preloadScript
|
require preloadScript
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
window.onload = ->
|
window.onload = ->
|
||||||
# Use menu API to show context menu.
|
### Use menu API to show context menu. ###
|
||||||
InspectorFrontendHost.showContextMenuAtPoint = createMenu
|
InspectorFrontendHost.showContextMenuAtPoint = createMenu
|
||||||
|
|
||||||
# Use dialog API to override file chooser dialog.
|
### Use dialog API to override file chooser dialog. ###
|
||||||
WebInspector.createFileSelectorElement = createFileSelectorElement
|
WebInspector.createFileSelectorElement = createFileSelectorElement
|
||||||
|
|
||||||
convertToMenuTemplate = (items) ->
|
convertToMenuTemplate = (items) ->
|
||||||
|
@ -38,7 +38,7 @@ createMenu = (x, y, items, document) ->
|
||||||
{Menu} = remote
|
{Menu} = remote
|
||||||
|
|
||||||
menu = Menu.buildFromTemplate convertToMenuTemplate(items)
|
menu = Menu.buildFromTemplate convertToMenuTemplate(items)
|
||||||
# The menu is expected to show asynchronously.
|
### The menu is expected to show asynchronously. ###
|
||||||
setTimeout -> menu.popup remote.getCurrentWindow()
|
setTimeout -> menu.popup remote.getCurrentWindow()
|
||||||
|
|
||||||
showFileChooserDialog = (callback) ->
|
showFileChooserDialog = (callback) ->
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
{ipcRenderer, remote} = require 'electron'
|
{ipcRenderer, remote} = require 'electron'
|
||||||
|
|
||||||
# Helper function to resolve relative url.
|
### Helper function to resolve relative url. ###
|
||||||
a = window.top.document.createElement 'a'
|
a = window.top.document.createElement 'a'
|
||||||
resolveURL = (url) ->
|
resolveURL = (url) ->
|
||||||
a.href = url
|
a.href = url
|
||||||
a.href
|
a.href
|
||||||
|
|
||||||
# Window object returned by "window.open".
|
### Window object returned by "window.open". ###
|
||||||
class BrowserWindowProxy
|
class BrowserWindowProxy
|
||||||
@proxies: {}
|
@proxies: {}
|
||||||
|
|
||||||
|
@ -38,15 +38,15 @@ class BrowserWindowProxy
|
||||||
ipcRenderer.send 'ATOM_SHELL_GUEST_WINDOW_MANAGER_WEB_CONTENTS_METHOD', @guestId, 'executeJavaScript', args...
|
ipcRenderer.send 'ATOM_SHELL_GUEST_WINDOW_MANAGER_WEB_CONTENTS_METHOD', @guestId, 'executeJavaScript', args...
|
||||||
|
|
||||||
unless process.guestInstanceId?
|
unless process.guestInstanceId?
|
||||||
# Override default window.close.
|
### Override default window.close. ###
|
||||||
window.close = ->
|
window.close = ->
|
||||||
remote.getCurrentWindow().close()
|
remote.getCurrentWindow().close()
|
||||||
|
|
||||||
# Make the browser window or guest view emit "new-window" event.
|
### Make the browser window or guest view emit "new-window" event. ###
|
||||||
window.open = (url, frameName='', features='') ->
|
window.open = (url, frameName='', features='') ->
|
||||||
options = {}
|
options = {}
|
||||||
ints = [ 'x', 'y', 'width', 'height', 'min-width', 'max-width', 'min-height', 'max-height', 'zoom-factor' ]
|
ints = [ 'x', 'y', 'width', 'height', 'min-width', 'max-width', 'min-height', 'max-height', 'zoom-factor' ]
|
||||||
# Make sure to get rid of excessive whitespace in the property name
|
### Make sure to get rid of excessive whitespace in the property name ###
|
||||||
for feature in features.split /,\s*/
|
for feature in features.split /,\s*/
|
||||||
[name, value] = feature.split /\s*=/
|
[name, value] = feature.split /\s*=/
|
||||||
options[name] =
|
options[name] =
|
||||||
|
@ -62,7 +62,7 @@ window.open = (url, frameName='', features='') ->
|
||||||
options.width ?= 800
|
options.width ?= 800
|
||||||
options.height ?= 600
|
options.height ?= 600
|
||||||
|
|
||||||
# Resolve relative urls.
|
### Resolve relative urls. ###
|
||||||
url = resolveURL url
|
url = resolveURL url
|
||||||
|
|
||||||
(options[name] = parseInt(options[name], 10) if options[name]?) for name in ints
|
(options[name] = parseInt(options[name], 10) if options[name]?) for name in ints
|
||||||
|
@ -73,21 +73,21 @@ window.open = (url, frameName='', features='') ->
|
||||||
else
|
else
|
||||||
null
|
null
|
||||||
|
|
||||||
# Use the dialog API to implement alert().
|
### Use the dialog API to implement alert(). ###
|
||||||
window.alert = (message, title='') ->
|
window.alert = (message, title='') ->
|
||||||
buttons = ['OK']
|
buttons = ['OK']
|
||||||
message = message.toString()
|
message = message.toString()
|
||||||
remote.dialog.showMessageBox remote.getCurrentWindow(), {message, title, buttons}
|
remote.dialog.showMessageBox remote.getCurrentWindow(), {message, title, buttons}
|
||||||
# Alert should always return undefined.
|
### Alert should always return undefined. ###
|
||||||
return
|
return
|
||||||
|
|
||||||
# And the confirm().
|
### And the confirm(). ###
|
||||||
window.confirm = (message, title='') ->
|
window.confirm = (message, title='') ->
|
||||||
buttons = ['OK', 'Cancel']
|
buttons = ['OK', 'Cancel']
|
||||||
cancelId = 1
|
cancelId = 1
|
||||||
not remote.dialog.showMessageBox remote.getCurrentWindow(), {message, title, buttons, cancelId}
|
not remote.dialog.showMessageBox remote.getCurrentWindow(), {message, title, buttons, cancelId}
|
||||||
|
|
||||||
# But we do not support prompt().
|
### But we do not support prompt(). ###
|
||||||
window.prompt = ->
|
window.prompt = ->
|
||||||
throw new Error('prompt() is and will not be supported.')
|
throw new Error('prompt() is and will not be supported.')
|
||||||
|
|
||||||
|
@ -95,8 +95,8 @@ if process.openerId?
|
||||||
window.opener = BrowserWindowProxy.getOrCreate process.openerId
|
window.opener = BrowserWindowProxy.getOrCreate process.openerId
|
||||||
|
|
||||||
ipcRenderer.on 'ATOM_SHELL_GUEST_WINDOW_POSTMESSAGE', (event, sourceId, message, sourceOrigin) ->
|
ipcRenderer.on 'ATOM_SHELL_GUEST_WINDOW_POSTMESSAGE', (event, sourceId, message, sourceOrigin) ->
|
||||||
# Manually dispatch event instead of using postMessage because we also need to
|
### Manually dispatch event instead of using postMessage because we also need to ###
|
||||||
# set event.source.
|
### set event.source. ###
|
||||||
event = document.createEvent 'Event'
|
event = document.createEvent 'Event'
|
||||||
event.initEvent 'message', false, false
|
event.initEvent 'message', false, false
|
||||||
event.data = message
|
event.data = message
|
||||||
|
@ -104,7 +104,7 @@ ipcRenderer.on 'ATOM_SHELL_GUEST_WINDOW_POSTMESSAGE', (event, sourceId, message,
|
||||||
event.source = BrowserWindowProxy.getOrCreate(sourceId)
|
event.source = BrowserWindowProxy.getOrCreate(sourceId)
|
||||||
window.dispatchEvent event
|
window.dispatchEvent event
|
||||||
|
|
||||||
# Forward history operations to browser.
|
### Forward history operations to browser. ###
|
||||||
sendHistoryOperation = (args...) ->
|
sendHistoryOperation = (args...) ->
|
||||||
ipcRenderer.send 'ATOM_SHELL_NAVIGATION_CONTROLLER', args...
|
ipcRenderer.send 'ATOM_SHELL_NAVIGATION_CONTROLLER', args...
|
||||||
|
|
||||||
|
@ -118,7 +118,7 @@ Object.defineProperty window.history, 'length',
|
||||||
get: ->
|
get: ->
|
||||||
getHistoryOperation 'length'
|
getHistoryOperation 'length'
|
||||||
|
|
||||||
# Make document.hidden and document.visibilityState return the correct value.
|
### Make document.hidden and document.visibilityState return the correct value. ###
|
||||||
Object.defineProperty document, 'hidden',
|
Object.defineProperty document, 'hidden',
|
||||||
get: ->
|
get: ->
|
||||||
currentWindow = remote.getCurrentWindow()
|
currentWindow = remote.getCurrentWindow()
|
||||||
|
|
|
@ -4,14 +4,16 @@ webViewConstants = require './web-view-constants'
|
||||||
|
|
||||||
{remote} = require 'electron'
|
{remote} = require 'electron'
|
||||||
|
|
||||||
# Helper function to resolve url set in attribute.
|
### Helper function to resolve url set in attribute. ###
|
||||||
a = document.createElement 'a'
|
a = document.createElement 'a'
|
||||||
resolveURL = (url) ->
|
resolveURL = (url) ->
|
||||||
a.href = url
|
a.href = url
|
||||||
a.href
|
a.href
|
||||||
|
|
||||||
# Attribute objects.
|
###
|
||||||
# Default implementation of a WebView attribute.
|
Attribute objects.
|
||||||
|
Default implementation of a WebView attribute.
|
||||||
|
###
|
||||||
class WebViewAttribute
|
class WebViewAttribute
|
||||||
constructor: (name, webViewImpl) ->
|
constructor: (name, webViewImpl) ->
|
||||||
@name = name
|
@name = name
|
||||||
|
@ -20,29 +22,29 @@ class WebViewAttribute
|
||||||
|
|
||||||
@defineProperty()
|
@defineProperty()
|
||||||
|
|
||||||
# Retrieves and returns the attribute's value.
|
### Retrieves and returns the attribute's value. ###
|
||||||
getValue: -> @webViewImpl.webviewNode.getAttribute(@name) || ''
|
getValue: -> @webViewImpl.webviewNode.getAttribute(@name) || ''
|
||||||
|
|
||||||
# Sets the attribute's value.
|
### Sets the attribute's value. ###
|
||||||
setValue: (value) -> @webViewImpl.webviewNode.setAttribute(@name, value || '')
|
setValue: (value) -> @webViewImpl.webviewNode.setAttribute(@name, value || '')
|
||||||
|
|
||||||
# Changes the attribute's value without triggering its mutation handler.
|
### Changes the attribute's value without triggering its mutation handler. ###
|
||||||
setValueIgnoreMutation: (value) ->
|
setValueIgnoreMutation: (value) ->
|
||||||
@ignoreMutation = true
|
@ignoreMutation = true
|
||||||
@setValue value
|
@setValue value
|
||||||
@ignoreMutation = false
|
@ignoreMutation = false
|
||||||
|
|
||||||
# Defines this attribute as a property on the webview node.
|
### Defines this attribute as a property on the webview node. ###
|
||||||
defineProperty: ->
|
defineProperty: ->
|
||||||
Object.defineProperty @webViewImpl.webviewNode, @name,
|
Object.defineProperty @webViewImpl.webviewNode, @name,
|
||||||
get: => @getValue()
|
get: => @getValue()
|
||||||
set: (value) => @setValue value
|
set: (value) => @setValue value
|
||||||
enumerable: true
|
enumerable: true
|
||||||
|
|
||||||
# Called when the attribute's value changes.
|
### Called when the attribute's value changes. ###
|
||||||
handleMutation: ->
|
handleMutation: ->
|
||||||
|
|
||||||
# An attribute that is treated as a Boolean.
|
### An attribute that is treated as a Boolean. ###
|
||||||
class BooleanAttribute extends WebViewAttribute
|
class BooleanAttribute extends WebViewAttribute
|
||||||
constructor: (name, webViewImpl) ->
|
constructor: (name, webViewImpl) ->
|
||||||
super name, webViewImpl
|
super name, webViewImpl
|
||||||
|
@ -55,7 +57,7 @@ class BooleanAttribute extends WebViewAttribute
|
||||||
else
|
else
|
||||||
@webViewImpl.webviewNode.setAttribute @name, ''
|
@webViewImpl.webviewNode.setAttribute @name, ''
|
||||||
|
|
||||||
# Attribute that specifies whether transparency is allowed in the webview.
|
### Attribute that specifies whether transparency is allowed in the webview. ###
|
||||||
class AllowTransparencyAttribute extends BooleanAttribute
|
class AllowTransparencyAttribute extends BooleanAttribute
|
||||||
constructor: (webViewImpl) ->
|
constructor: (webViewImpl) ->
|
||||||
super webViewConstants.ATTRIBUTE_ALLOWTRANSPARENCY, webViewImpl
|
super webViewConstants.ATTRIBUTE_ALLOWTRANSPARENCY, webViewImpl
|
||||||
|
@ -64,7 +66,7 @@ class AllowTransparencyAttribute extends BooleanAttribute
|
||||||
return unless @webViewImpl.guestInstanceId
|
return unless @webViewImpl.guestInstanceId
|
||||||
guestViewInternal.setAllowTransparency @webViewImpl.guestInstanceId, @getValue()
|
guestViewInternal.setAllowTransparency @webViewImpl.guestInstanceId, @getValue()
|
||||||
|
|
||||||
# Attribute used to define the demension limits of autosizing.
|
### Attribute used to define the demension limits of autosizing. ###
|
||||||
class AutosizeDimensionAttribute extends WebViewAttribute
|
class AutosizeDimensionAttribute extends WebViewAttribute
|
||||||
constructor: (name, webViewImpl) ->
|
constructor: (name, webViewImpl) ->
|
||||||
super name, webViewImpl
|
super name, webViewImpl
|
||||||
|
@ -82,14 +84,14 @@ class AutosizeDimensionAttribute extends WebViewAttribute
|
||||||
width: parseInt @webViewImpl.attributes[webViewConstants.ATTRIBUTE_MAXWIDTH].getValue() || 0
|
width: parseInt @webViewImpl.attributes[webViewConstants.ATTRIBUTE_MAXWIDTH].getValue() || 0
|
||||||
height: parseInt @webViewImpl.attributes[webViewConstants.ATTRIBUTE_MAXHEIGHT].getValue() || 0
|
height: parseInt @webViewImpl.attributes[webViewConstants.ATTRIBUTE_MAXHEIGHT].getValue() || 0
|
||||||
|
|
||||||
# Attribute that specifies whether the webview should be autosized.
|
### Attribute that specifies whether the webview should be autosized. ###
|
||||||
class AutosizeAttribute extends BooleanAttribute
|
class AutosizeAttribute extends BooleanAttribute
|
||||||
constructor: (webViewImpl) ->
|
constructor: (webViewImpl) ->
|
||||||
super webViewConstants.ATTRIBUTE_AUTOSIZE, webViewImpl
|
super webViewConstants.ATTRIBUTE_AUTOSIZE, webViewImpl
|
||||||
|
|
||||||
handleMutation: AutosizeDimensionAttribute::handleMutation
|
handleMutation: AutosizeDimensionAttribute::handleMutation
|
||||||
|
|
||||||
# Attribute representing the state of the storage partition.
|
### Attribute representing the state of the storage partition. ###
|
||||||
class PartitionAttribute extends WebViewAttribute
|
class PartitionAttribute extends WebViewAttribute
|
||||||
constructor: (webViewImpl) ->
|
constructor: (webViewImpl) ->
|
||||||
super webViewConstants.ATTRIBUTE_PARTITION, webViewImpl
|
super webViewConstants.ATTRIBUTE_PARTITION, webViewImpl
|
||||||
|
@ -98,7 +100,7 @@ class PartitionAttribute extends WebViewAttribute
|
||||||
handleMutation: (oldValue, newValue) ->
|
handleMutation: (oldValue, newValue) ->
|
||||||
newValue = newValue || ''
|
newValue = newValue || ''
|
||||||
|
|
||||||
# The partition cannot change if the webview has already navigated.
|
### The partition cannot change if the webview has already navigated. ###
|
||||||
unless @webViewImpl.beforeFirstNavigation
|
unless @webViewImpl.beforeFirstNavigation
|
||||||
window.console.error webViewConstants.ERROR_MSG_ALREADY_NAVIGATED
|
window.console.error webViewConstants.ERROR_MSG_ALREADY_NAVIGATED
|
||||||
@setValueIgnoreMutation oldValue
|
@setValueIgnoreMutation oldValue
|
||||||
|
@ -108,7 +110,7 @@ class PartitionAttribute extends WebViewAttribute
|
||||||
@validPartitionId = false
|
@validPartitionId = false
|
||||||
window.console.error webViewConstants.ERROR_MSG_INVALID_PARTITION_ATTRIBUTE
|
window.console.error webViewConstants.ERROR_MSG_INVALID_PARTITION_ATTRIBUTE
|
||||||
|
|
||||||
# Attribute that handles the location and navigation of the webview.
|
### Attribute that handles the location and navigation of the webview. ###
|
||||||
class SrcAttribute extends WebViewAttribute
|
class SrcAttribute extends WebViewAttribute
|
||||||
constructor: (webViewImpl) ->
|
constructor: (webViewImpl) ->
|
||||||
super webViewConstants.ATTRIBUTE_SRC, webViewImpl
|
super webViewConstants.ATTRIBUTE_SRC, webViewImpl
|
||||||
|
@ -122,28 +124,36 @@ class SrcAttribute extends WebViewAttribute
|
||||||
|
|
||||||
setValueIgnoreMutation: (value) ->
|
setValueIgnoreMutation: (value) ->
|
||||||
WebViewAttribute::setValueIgnoreMutation.call(this, value)
|
WebViewAttribute::setValueIgnoreMutation.call(this, value)
|
||||||
# takeRecords() is needed to clear queued up src mutations. Without it, it
|
###
|
||||||
# is possible for this change to get picked up asyncronously by src's
|
takeRecords() is needed to clear queued up src mutations. Without it, it
|
||||||
# mutation observer |observer|, and then get handled even though we do not
|
is possible for this change to get picked up asyncronously by src's
|
||||||
# want to handle this mutation.
|
mutation observer |observer|, and then get handled even though we do not
|
||||||
|
want to handle this mutation.
|
||||||
|
###
|
||||||
@observer.takeRecords()
|
@observer.takeRecords()
|
||||||
|
|
||||||
handleMutation: (oldValue, newValue) ->
|
handleMutation: (oldValue, newValue) ->
|
||||||
# Once we have navigated, we don't allow clearing the src attribute.
|
###
|
||||||
# Once <webview> enters a navigated state, it cannot return to a
|
Once we have navigated, we don't allow clearing the src attribute.
|
||||||
# placeholder state.
|
Once <webview> enters a navigated state, it cannot return to a
|
||||||
|
placeholder state.
|
||||||
|
###
|
||||||
if not newValue and oldValue
|
if not newValue and oldValue
|
||||||
# src attribute changes normally initiate a navigation. We suppress
|
###
|
||||||
# the next src attribute handler call to avoid reloading the page
|
src attribute changes normally initiate a navigation. We suppress
|
||||||
# on every guest-initiated navigation.
|
the next src attribute handler call to avoid reloading the page
|
||||||
|
on every guest-initiated navigation.
|
||||||
|
###
|
||||||
@setValueIgnoreMutation oldValue
|
@setValueIgnoreMutation oldValue
|
||||||
return
|
return
|
||||||
@parse()
|
@parse()
|
||||||
|
|
||||||
# The purpose of this mutation observer is to catch assignment to the src
|
###
|
||||||
# attribute without any changes to its value. This is useful in the case
|
The purpose of this mutation observer is to catch assignment to the src
|
||||||
# where the webview guest has crashed and navigating to the same address
|
attribute without any changes to its value. This is useful in the case
|
||||||
# spawns off a new process.
|
where the webview guest has crashed and navigating to the same address
|
||||||
|
spawns off a new process.
|
||||||
|
###
|
||||||
setupMutationObserver: ->
|
setupMutationObserver: ->
|
||||||
@observer = new MutationObserver (mutations) =>
|
@observer = new MutationObserver (mutations) =>
|
||||||
for mutation in mutations
|
for mutation in mutations
|
||||||
|
@ -169,7 +179,7 @@ class SrcAttribute extends WebViewAttribute
|
||||||
@webViewImpl.createGuest()
|
@webViewImpl.createGuest()
|
||||||
return
|
return
|
||||||
|
|
||||||
# Navigate to |this.src|.
|
### Navigate to |this.src|. ###
|
||||||
opts = {}
|
opts = {}
|
||||||
httpreferrer = @webViewImpl.attributes[webViewConstants.ATTRIBUTE_HTTPREFERRER].getValue()
|
httpreferrer = @webViewImpl.attributes[webViewConstants.ATTRIBUTE_HTTPREFERRER].getValue()
|
||||||
if httpreferrer then opts.httpReferrer = httpreferrer
|
if httpreferrer then opts.httpReferrer = httpreferrer
|
||||||
|
@ -180,17 +190,17 @@ class SrcAttribute extends WebViewAttribute
|
||||||
guestContents = remote.getGuestWebContents(@webViewImpl.guestInstanceId)
|
guestContents = remote.getGuestWebContents(@webViewImpl.guestInstanceId)
|
||||||
guestContents.loadURL @getValue(), opts
|
guestContents.loadURL @getValue(), opts
|
||||||
|
|
||||||
# Attribute specifies HTTP referrer.
|
### Attribute specifies HTTP referrer. ###
|
||||||
class HttpReferrerAttribute extends WebViewAttribute
|
class HttpReferrerAttribute extends WebViewAttribute
|
||||||
constructor: (webViewImpl) ->
|
constructor: (webViewImpl) ->
|
||||||
super webViewConstants.ATTRIBUTE_HTTPREFERRER, webViewImpl
|
super webViewConstants.ATTRIBUTE_HTTPREFERRER, webViewImpl
|
||||||
|
|
||||||
# Attribute specifies user agent
|
### Attribute specifies user agent ###
|
||||||
class UserAgentAttribute extends WebViewAttribute
|
class UserAgentAttribute extends WebViewAttribute
|
||||||
constructor: (webViewImpl) ->
|
constructor: (webViewImpl) ->
|
||||||
super webViewConstants.ATTRIBUTE_USERAGENT, webViewImpl
|
super webViewConstants.ATTRIBUTE_USERAGENT, webViewImpl
|
||||||
|
|
||||||
# Attribute that set preload script.
|
### Attribute that set preload script. ###
|
||||||
class PreloadAttribute extends WebViewAttribute
|
class PreloadAttribute extends WebViewAttribute
|
||||||
constructor: (webViewImpl) ->
|
constructor: (webViewImpl) ->
|
||||||
super webViewConstants.ATTRIBUTE_PRELOAD, webViewImpl
|
super webViewConstants.ATTRIBUTE_PRELOAD, webViewImpl
|
||||||
|
@ -204,7 +214,7 @@ class PreloadAttribute extends WebViewAttribute
|
||||||
preload = ''
|
preload = ''
|
||||||
preload
|
preload
|
||||||
|
|
||||||
# Sets up all of the webview attributes.
|
### Sets up all of the webview attributes. ###
|
||||||
WebViewImpl::setupWebViewAttributes = ->
|
WebViewImpl::setupWebViewAttributes = ->
|
||||||
@attributes = {}
|
@attributes = {}
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
module.exports =
|
module.exports =
|
||||||
# Attributes.
|
### Attributes. ###
|
||||||
ATTRIBUTE_ALLOWTRANSPARENCY: 'allowtransparency'
|
ATTRIBUTE_ALLOWTRANSPARENCY: 'allowtransparency'
|
||||||
ATTRIBUTE_AUTOSIZE: 'autosize'
|
ATTRIBUTE_AUTOSIZE: 'autosize'
|
||||||
ATTRIBUTE_MAXHEIGHT: 'maxheight'
|
ATTRIBUTE_MAXHEIGHT: 'maxheight'
|
||||||
|
@ -17,10 +17,10 @@ module.exports =
|
||||||
ATTRIBUTE_PRELOAD: 'preload'
|
ATTRIBUTE_PRELOAD: 'preload'
|
||||||
ATTRIBUTE_USERAGENT: 'useragent'
|
ATTRIBUTE_USERAGENT: 'useragent'
|
||||||
|
|
||||||
# Internal attribute.
|
### Internal attribute. ###
|
||||||
ATTRIBUTE_INTERNALINSTANCEID: 'internalinstanceid'
|
ATTRIBUTE_INTERNALINSTANCEID: 'internalinstanceid'
|
||||||
|
|
||||||
# Error messages.
|
### Error messages. ###
|
||||||
ERROR_MSG_ALREADY_NAVIGATED: 'The object has already navigated, so its partition cannot be changed.'
|
ERROR_MSG_ALREADY_NAVIGATED: 'The object has already navigated, so its partition cannot be changed.'
|
||||||
ERROR_MSG_CANNOT_INJECT_SCRIPT: '<webview>: ' +
|
ERROR_MSG_CANNOT_INJECT_SCRIPT: '<webview>: ' +
|
||||||
'Script cannot be injected into content until the page has loaded.'
|
'Script cannot be injected into content until the page has loaded.'
|
||||||
|
|
|
@ -4,11 +4,11 @@ v8Util = process.atomBinding 'v8_util'
|
||||||
guestViewInternal = require './guest-view-internal'
|
guestViewInternal = require './guest-view-internal'
|
||||||
webViewConstants = require './web-view-constants'
|
webViewConstants = require './web-view-constants'
|
||||||
|
|
||||||
# ID generator.
|
### ID generator. ###
|
||||||
nextId = 0
|
nextId = 0
|
||||||
getNextId = -> ++nextId
|
getNextId = -> ++nextId
|
||||||
|
|
||||||
# Represents the internal state of the WebView node.
|
### Represents the internal state of the WebView node. ###
|
||||||
class WebViewImpl
|
class WebViewImpl
|
||||||
constructor: (@webviewNode) ->
|
constructor: (@webviewNode) ->
|
||||||
v8Util.setHiddenValue @webviewNode, 'internal', this
|
v8Util.setHiddenValue @webviewNode, 'internal', this
|
||||||
|
@ -17,7 +17,7 @@ class WebViewImpl
|
||||||
|
|
||||||
@beforeFirstNavigation = true
|
@beforeFirstNavigation = true
|
||||||
|
|
||||||
# on* Event handlers.
|
### on* Event handlers. ###
|
||||||
@on = {}
|
@on = {}
|
||||||
|
|
||||||
@browserPluginNode = @createBrowserPluginNode()
|
@browserPluginNode = @createBrowserPluginNode()
|
||||||
|
@ -30,20 +30,24 @@ class WebViewImpl
|
||||||
shadowRoot.appendChild @browserPluginNode
|
shadowRoot.appendChild @browserPluginNode
|
||||||
|
|
||||||
createBrowserPluginNode: ->
|
createBrowserPluginNode: ->
|
||||||
# We create BrowserPlugin as a custom element in order to observe changes
|
###
|
||||||
# to attributes synchronously.
|
We create BrowserPlugin as a custom element in order to observe changes
|
||||||
|
to attributes synchronously.
|
||||||
|
###
|
||||||
browserPluginNode = new WebViewImpl.BrowserPlugin()
|
browserPluginNode = new WebViewImpl.BrowserPlugin()
|
||||||
v8Util.setHiddenValue browserPluginNode, 'internal', this
|
v8Util.setHiddenValue browserPluginNode, 'internal', this
|
||||||
browserPluginNode
|
browserPluginNode
|
||||||
|
|
||||||
# Resets some state upon reattaching <webview> element to the DOM.
|
### Resets some state upon reattaching <webview> element to the DOM. ###
|
||||||
reset: ->
|
reset: ->
|
||||||
# If guestInstanceId is defined then the <webview> has navigated and has
|
###
|
||||||
# already picked up a partition ID. Thus, we need to reset the initialization
|
If guestInstanceId is defined then the <webview> has navigated and has
|
||||||
# state. However, it may be the case that beforeFirstNavigation is false BUT
|
already picked up a partition ID. Thus, we need to reset the initialization
|
||||||
# guestInstanceId has yet to be initialized. This means that we have not
|
state. However, it may be the case that beforeFirstNavigation is false BUT
|
||||||
# heard back from createGuest yet. We will not reset the flag in this case so
|
guestInstanceId has yet to be initialized. This means that we have not
|
||||||
# that we don't end up allocating a second guest.
|
heard back from createGuest yet. We will not reset the flag in this case so
|
||||||
|
that we don't end up allocating a second guest.
|
||||||
|
###
|
||||||
if @guestInstanceId
|
if @guestInstanceId
|
||||||
guestViewInternal.destroyGuest @guestInstanceId
|
guestViewInternal.destroyGuest @guestInstanceId
|
||||||
@webContents = null
|
@webContents = null
|
||||||
|
@ -52,34 +56,38 @@ class WebViewImpl
|
||||||
@attributes[webViewConstants.ATTRIBUTE_PARTITION].validPartitionId = true
|
@attributes[webViewConstants.ATTRIBUTE_PARTITION].validPartitionId = true
|
||||||
@internalInstanceId = 0
|
@internalInstanceId = 0
|
||||||
|
|
||||||
# Sets the <webview>.request property.
|
### Sets the <webview>.request property. ###
|
||||||
setRequestPropertyOnWebViewNode: (request) ->
|
setRequestPropertyOnWebViewNode: (request) ->
|
||||||
Object.defineProperty @webviewNode, 'request', value: request, enumerable: true
|
Object.defineProperty @webviewNode, 'request', value: request, enumerable: true
|
||||||
|
|
||||||
setupFocusPropagation: ->
|
setupFocusPropagation: ->
|
||||||
unless @webviewNode.hasAttribute 'tabIndex'
|
unless @webviewNode.hasAttribute 'tabIndex'
|
||||||
# <webview> needs a tabIndex in order to be focusable.
|
###
|
||||||
# TODO(fsamuel): It would be nice to avoid exposing a tabIndex attribute
|
<webview> needs a tabIndex in order to be focusable.
|
||||||
# to allow <webview> to be focusable.
|
TODO(fsamuel): It would be nice to avoid exposing a tabIndex attribute
|
||||||
# See http://crbug.com/231664.
|
to allow <webview> to be focusable.
|
||||||
|
See http://crbug.com/231664.
|
||||||
|
###
|
||||||
@webviewNode.setAttribute 'tabIndex', -1
|
@webviewNode.setAttribute 'tabIndex', -1
|
||||||
@webviewNode.addEventListener 'focus', (e) =>
|
@webviewNode.addEventListener 'focus', (e) =>
|
||||||
# Focus the BrowserPlugin when the <webview> takes focus.
|
### Focus the BrowserPlugin when the <webview> takes focus. ###
|
||||||
@browserPluginNode.focus()
|
@browserPluginNode.focus()
|
||||||
@webviewNode.addEventListener 'blur', (e) =>
|
@webviewNode.addEventListener 'blur', (e) =>
|
||||||
# Blur the BrowserPlugin when the <webview> loses focus.
|
### Blur the BrowserPlugin when the <webview> loses focus. ###
|
||||||
@browserPluginNode.blur()
|
@browserPluginNode.blur()
|
||||||
|
|
||||||
# This observer monitors mutations to attributes of the <webview> and
|
###
|
||||||
# updates the BrowserPlugin properties accordingly. In turn, updating
|
This observer monitors mutations to attributes of the <webview> and
|
||||||
# a BrowserPlugin property will update the corresponding BrowserPlugin
|
updates the BrowserPlugin properties accordingly. In turn, updating
|
||||||
# attribute, if necessary. See BrowserPlugin::UpdateDOMAttribute for more
|
a BrowserPlugin property will update the corresponding BrowserPlugin
|
||||||
# details.
|
attribute, if necessary. See BrowserPlugin::UpdateDOMAttribute for more
|
||||||
|
details.
|
||||||
|
###
|
||||||
handleWebviewAttributeMutation: (attributeName, oldValue, newValue) ->
|
handleWebviewAttributeMutation: (attributeName, oldValue, newValue) ->
|
||||||
if not @attributes[attributeName] or @attributes[attributeName].ignoreMutation
|
if not @attributes[attributeName] or @attributes[attributeName].ignoreMutation
|
||||||
return
|
return
|
||||||
|
|
||||||
# Let the changed attribute handle its own mutation;
|
### Let the changed attribute handle its own mutation; ###
|
||||||
@attributes[attributeName].handleMutation oldValue, newValue
|
@attributes[attributeName].handleMutation oldValue, newValue
|
||||||
|
|
||||||
handleBrowserPluginAttributeMutation: (attributeName, oldValue, newValue) ->
|
handleBrowserPluginAttributeMutation: (attributeName, oldValue, newValue) ->
|
||||||
|
@ -87,7 +95,7 @@ class WebViewImpl
|
||||||
@browserPluginNode.removeAttribute webViewConstants.ATTRIBUTE_INTERNALINSTANCEID
|
@browserPluginNode.removeAttribute webViewConstants.ATTRIBUTE_INTERNALINSTANCEID
|
||||||
@internalInstanceId = parseInt newValue
|
@internalInstanceId = parseInt newValue
|
||||||
|
|
||||||
# Track when the element resizes using the element resize callback.
|
### Track when the element resizes using the element resize callback. ###
|
||||||
webFrame.registerElementResizeCallback @internalInstanceId, @onElementResize.bind(this)
|
webFrame.registerElementResizeCallback @internalInstanceId, @onElementResize.bind(this)
|
||||||
|
|
||||||
return unless @guestInstanceId
|
return unless @guestInstanceId
|
||||||
|
@ -103,8 +111,8 @@ class WebViewImpl
|
||||||
width = node.offsetWidth
|
width = node.offsetWidth
|
||||||
height = node.offsetHeight
|
height = node.offsetHeight
|
||||||
|
|
||||||
# Check the current bounds to make sure we do not resize <webview>
|
### Check the current bounds to make sure we do not resize <webview> ###
|
||||||
# outside of current constraints.
|
### outside of current constraints. ###
|
||||||
maxWidth = @attributes[webViewConstants.ATTRIBUTE_MAXWIDTH].getValue() | width
|
maxWidth = @attributes[webViewConstants.ATTRIBUTE_MAXWIDTH].getValue() | width
|
||||||
maxHeight = @attributes[webViewConstants.ATTRIBUTE_MAXHEIGHT].getValue() | width
|
maxHeight = @attributes[webViewConstants.ATTRIBUTE_MAXHEIGHT].getValue() | width
|
||||||
minWidth = @attributes[webViewConstants.ATTRIBUTE_MINWIDTH].getValue() | width
|
minWidth = @attributes[webViewConstants.ATTRIBUTE_MINWIDTH].getValue() | width
|
||||||
|
@ -120,12 +128,14 @@ class WebViewImpl
|
||||||
newHeight <= maxHeight)
|
newHeight <= maxHeight)
|
||||||
node.style.width = newWidth + 'px'
|
node.style.width = newWidth + 'px'
|
||||||
node.style.height = newHeight + 'px'
|
node.style.height = newHeight + 'px'
|
||||||
# Only fire the DOM event if the size of the <webview> has actually
|
###
|
||||||
# changed.
|
Only fire the DOM event if the size of the <webview> has actually
|
||||||
|
changed.
|
||||||
|
###
|
||||||
@dispatchEvent webViewEvent
|
@dispatchEvent webViewEvent
|
||||||
|
|
||||||
onElementResize: (newSize) ->
|
onElementResize: (newSize) ->
|
||||||
# Dispatch the 'resize' event.
|
### Dispatch the 'resize' event. ###
|
||||||
resizeEvent = new Event('resize', bubbles: true)
|
resizeEvent = new Event('resize', bubbles: true)
|
||||||
resizeEvent.newWidth = newSize.width
|
resizeEvent.newWidth = newSize.width
|
||||||
resizeEvent.newHeight = newSize.height
|
resizeEvent.newHeight = newSize.height
|
||||||
|
@ -141,8 +151,8 @@ class WebViewImpl
|
||||||
dispatchEvent: (webViewEvent) ->
|
dispatchEvent: (webViewEvent) ->
|
||||||
@webviewNode.dispatchEvent webViewEvent
|
@webviewNode.dispatchEvent webViewEvent
|
||||||
|
|
||||||
# Adds an 'on<event>' property on the webview, which can be used to set/unset
|
### Adds an 'on<event>' property on the webview, which can be used to set/unset ###
|
||||||
# an event handler.
|
### an event handler. ###
|
||||||
setupEventProperty: (eventName) ->
|
setupEventProperty: (eventName) ->
|
||||||
propertyName = 'on' + eventName.toLowerCase()
|
propertyName = 'on' + eventName.toLowerCase()
|
||||||
Object.defineProperty @webviewNode, propertyName,
|
Object.defineProperty @webviewNode, propertyName,
|
||||||
|
@ -155,14 +165,16 @@ class WebViewImpl
|
||||||
@webviewNode.addEventListener eventName, value
|
@webviewNode.addEventListener eventName, value
|
||||||
enumerable: true
|
enumerable: true
|
||||||
|
|
||||||
# Updates state upon loadcommit.
|
### Updates state upon loadcommit. ###
|
||||||
onLoadCommit: (webViewEvent) ->
|
onLoadCommit: (webViewEvent) ->
|
||||||
oldValue = @webviewNode.getAttribute webViewConstants.ATTRIBUTE_SRC
|
oldValue = @webviewNode.getAttribute webViewConstants.ATTRIBUTE_SRC
|
||||||
newValue = webViewEvent.url
|
newValue = webViewEvent.url
|
||||||
if webViewEvent.isMainFrame and (oldValue != newValue)
|
if webViewEvent.isMainFrame and (oldValue != newValue)
|
||||||
# Touching the src attribute triggers a navigation. To avoid
|
###
|
||||||
# triggering a page reload on every guest-initiated navigation,
|
Touching the src attribute triggers a navigation. To avoid
|
||||||
# we do not handle this mutation
|
triggering a page reload on every guest-initiated navigation,
|
||||||
|
we do not handle this mutation.
|
||||||
|
###
|
||||||
@attributes[webViewConstants.ATTRIBUTE_SRC].setValueIgnoreMutation newValue
|
@attributes[webViewConstants.ATTRIBUTE_SRC].setValueIgnoreMutation newValue
|
||||||
|
|
||||||
onAttach: (storagePartitionId) ->
|
onAttach: (storagePartitionId) ->
|
||||||
|
@ -174,11 +186,13 @@ class WebViewImpl
|
||||||
userAgentOverride: @userAgentOverride
|
userAgentOverride: @userAgentOverride
|
||||||
for own attributeName, attribute of @attributes
|
for own attributeName, attribute of @attributes
|
||||||
params[attributeName] = attribute.getValue()
|
params[attributeName] = attribute.getValue()
|
||||||
# When the WebView is not participating in layout (display:none)
|
###
|
||||||
# then getBoundingClientRect() would report a width and height of 0.
|
When the WebView is not participating in layout (display:none)
|
||||||
# However, in the case where the WebView has a fixed size we can
|
then getBoundingClientRect() would report a width and height of 0.
|
||||||
# use that value to initially size the guest so as to avoid a relayout of
|
However, in the case where the WebView has a fixed size we can
|
||||||
# the on display:block.
|
use that value to initially size the guest so as to avoid a relayout of
|
||||||
|
the on display:block.
|
||||||
|
###
|
||||||
css = window.getComputedStyle @webviewNode, null
|
css = window.getComputedStyle @webviewNode, null
|
||||||
elementRect = @webviewNode.getBoundingClientRect()
|
elementRect = @webviewNode.getBoundingClientRect()
|
||||||
params.elementWidth = parseInt(elementRect.width) ||
|
params.elementWidth = parseInt(elementRect.width) ||
|
||||||
|
@ -194,14 +208,14 @@ class WebViewImpl
|
||||||
|
|
||||||
guestViewInternal.attachGuest @internalInstanceId, @guestInstanceId, @buildParams()
|
guestViewInternal.attachGuest @internalInstanceId, @guestInstanceId, @buildParams()
|
||||||
|
|
||||||
# Registers browser plugin <object> custom element.
|
### Registers browser plugin <object> custom element. ###
|
||||||
registerBrowserPluginElement = ->
|
registerBrowserPluginElement = ->
|
||||||
proto = Object.create HTMLObjectElement.prototype
|
proto = Object.create HTMLObjectElement.prototype
|
||||||
|
|
||||||
proto.createdCallback = ->
|
proto.createdCallback = ->
|
||||||
@setAttribute 'type', 'application/browser-plugin'
|
@setAttribute 'type', 'application/browser-plugin'
|
||||||
@setAttribute 'id', 'browser-plugin-' + getNextId()
|
@setAttribute 'id', 'browser-plugin-' + getNextId()
|
||||||
# The <object> node fills in the <webview> container.
|
### The <object> node fills in the <webview> container. ###
|
||||||
@style.display = 'block'
|
@style.display = 'block'
|
||||||
@style.width = '100%'
|
@style.width = '100%'
|
||||||
@style.height = '100%'
|
@style.height = '100%'
|
||||||
|
@ -212,7 +226,7 @@ registerBrowserPluginElement = ->
|
||||||
internal.handleBrowserPluginAttributeMutation name, oldValue, newValue
|
internal.handleBrowserPluginAttributeMutation name, oldValue, newValue
|
||||||
|
|
||||||
proto.attachedCallback = ->
|
proto.attachedCallback = ->
|
||||||
# Load the plugin immediately.
|
### Load the plugin immediately. ###
|
||||||
unused = this.nonExistentAttribute
|
unused = this.nonExistentAttribute
|
||||||
|
|
||||||
WebViewImpl.BrowserPlugin = webFrame.registerEmbedderCustomElement 'browserplugin',
|
WebViewImpl.BrowserPlugin = webFrame.registerEmbedderCustomElement 'browserplugin',
|
||||||
|
@ -223,7 +237,7 @@ registerBrowserPluginElement = ->
|
||||||
delete proto.detachedCallback
|
delete proto.detachedCallback
|
||||||
delete proto.attributeChangedCallback
|
delete proto.attributeChangedCallback
|
||||||
|
|
||||||
# Registers <webview> custom element.
|
### Registers <webview> custom element. ###
|
||||||
registerWebViewElement = ->
|
registerWebViewElement = ->
|
||||||
proto = Object.create HTMLObjectElement.prototype
|
proto = Object.create HTMLObjectElement.prototype
|
||||||
|
|
||||||
|
@ -250,7 +264,7 @@ registerWebViewElement = ->
|
||||||
internal.elementAttached = true
|
internal.elementAttached = true
|
||||||
internal.attributes[webViewConstants.ATTRIBUTE_SRC].parse()
|
internal.attributes[webViewConstants.ATTRIBUTE_SRC].parse()
|
||||||
|
|
||||||
# Public-facing API methods.
|
### Public-facing API methods. ###
|
||||||
methods = [
|
methods = [
|
||||||
'getURL'
|
'getURL'
|
||||||
'getTitle'
|
'getTitle'
|
||||||
|
@ -304,7 +318,7 @@ registerWebViewElement = ->
|
||||||
'insertCSS'
|
'insertCSS'
|
||||||
]
|
]
|
||||||
|
|
||||||
# Forward proto.foo* method calls to WebViewImpl.foo*.
|
### Forward proto.foo* method calls to WebViewImpl.foo*. ###
|
||||||
createBlockHandler = (m) ->
|
createBlockHandler = (m) ->
|
||||||
(args...) ->
|
(args...) ->
|
||||||
internal = v8Util.getHiddenValue this, 'internal'
|
internal = v8Util.getHiddenValue this, 'internal'
|
||||||
|
@ -318,14 +332,14 @@ registerWebViewElement = ->
|
||||||
|
|
||||||
proto[m] = createNonBlockHandler m for m in nonblockMethods
|
proto[m] = createNonBlockHandler m for m in nonblockMethods
|
||||||
|
|
||||||
# Deprecated.
|
### Deprecated. ###
|
||||||
deprecate.rename proto, 'getUrl', 'getURL'
|
deprecate.rename proto, 'getUrl', 'getURL'
|
||||||
|
|
||||||
window.WebView = webFrame.registerEmbedderCustomElement 'webview',
|
window.WebView = webFrame.registerEmbedderCustomElement 'webview',
|
||||||
prototype: proto
|
prototype: proto
|
||||||
|
|
||||||
# Delete the callbacks so developers cannot call them and produce unexpected
|
### Delete the callbacks so developers cannot call them and produce unexpected ###
|
||||||
# behavior.
|
### behavior. ###
|
||||||
delete proto.createdCallback
|
delete proto.createdCallback
|
||||||
delete proto.attachedCallback
|
delete proto.attachedCallback
|
||||||
delete proto.detachedCallback
|
delete proto.detachedCallback
|
||||||
|
|
Loading…
Add table
Reference in a new issue