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