diff --git a/atom/browser/api/lib/browser-window.coffee b/atom/browser/api/lib/browser-window.coffee index d76bfbf4283c..8af84aadb60e 100644 --- a/atom/browser/api/lib/browser-window.coffee +++ b/atom/browser/api/lib/browser-window.coffee @@ -36,7 +36,7 @@ BrowserWindow::openDevTools = -> @devToolsWebContents.once 'destroyed', => @devToolsWebContents = null # Emit devtools events. - @emit 'dev-tools-opened' + @devToolsWebContents.once 'did-finish-load', => @emit 'dev-tools-opened' @devToolsWebContents.once 'destroyed', => @emit 'dev-tools-closed' BrowserWindow::toggleDevTools = -> diff --git a/atom/browser/lib/chrome-extension.coffee b/atom/browser/lib/chrome-extension.coffee index 6ca1bc1651dd..98b430f00f3a 100644 --- a/atom/browser/lib/chrome-extension.coffee +++ b/atom/browser/lib/chrome-extension.coffee @@ -15,22 +15,12 @@ getHostForPath = (path) -> getPathForHost = (host) -> hostPathMap[host] -app.once 'ready', -> - protocol = require 'protocol' - BrowserWindow = require 'browser-window' - - protocol.registerProtocol 'chrome-extension', (request) -> - parsed = url.parse request.url - return unless parsed.hostname and parsed.path? - - return unless /extension-\d+/.test parsed.hostname - - directory = getPathForHost parsed.hostname - return new protocol.RequestFileJob(path.join(directory, parsed.path)) - - BrowserWindow::loadDevToolsExtension = (srcDirectory) -> - manifest = JSON.parse fs.readFileSync(path.join(srcDirectory, 'manifest.json')) +# 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. page = url.format @@ -38,6 +28,61 @@ app.once 'ready', -> slashes: true hostname: getHostForPath srcDirectory pathname: manifest.devtools_page + extensionInfoMap[manifest.name] = + startPage: page + name: manifest.name + srcDirectory: srcDirectory + extensionInfoMap[manifest.name] - extensionInfo = startPage: page, name: manifest.name - @devToolsWebContents?.executeJavaScript "WebInspector.addExtensions([#{JSON.stringify(extensionInfo)}]);" +# Load persistented extensions. +loadedExtensionsPath = path.join app.getDataPath(), 'DevTools Extensions' + +try + loadedExtensions = JSON.parse fs.readFileSync(loadedExtensionsPath) + loadedExtensions = [] unless Array.isArray loadedExtensions + # Preheat the extensionInfo cache. + getExtensionInfoFromPath srcDirectory for srcDirectory in loadedExtensions +catch e + +# Persistent loaded extensions. +app.on 'will-quit', -> + try + loadedExtensions = Object.keys(extensionInfoMap).map (key) -> extensionInfoMap[key].srcDirectory + try + fs.mkdirSync path.dirname(loadedExtensionsPath) + catch e + fs.writeFileSync loadedExtensionsPath, JSON.stringify(loadedExtensions) + catch e + +# We can not use protocol or BrowserWindow until app is ready. +app.once 'ready', -> + protocol = require 'protocol' + BrowserWindow = require 'browser-window' + + # The chrome-extension: can map a extension URL request to real file path. + protocol.registerProtocol 'chrome-extension', (request) -> + parsed = url.parse request.url + return unless parsed.hostname and parsed.path? + return unless /extension-\d+/.test parsed.hostname + + directory = getPathForHost parsed.hostname + return unless directory? + return new protocol.RequestFileJob(path.join(directory, parsed.path)) + + BrowserWindow::_loadDevToolsExtensions = (extensionInfoArray) -> + @devToolsWebContents?.executeJavaScript "WebInspector.addExtensions(#{JSON.stringify(extensionInfoArray)});" + + BrowserWindow.addDevToolsExtension = (srcDirectory) -> + extensionInfo = getExtensionInfoFromPath srcDirectory + window._loadDevToolsExtensions [extensionInfo] for window in BrowserWindow.getAllWindows() + extensionInfo.name + + BrowserWindow.removeDevToolsExtension = (name) -> + delete extensionInfoMap[name] + + # Load persistented extensions when devtools is opened. + init = BrowserWindow::_init + BrowserWindow::_init = -> + init.call this + @on 'dev-tools-opened', -> + @_loadDevToolsExtensions Object.keys(extensionInfoMap).map (key) -> extensionInfoMap[key] diff --git a/atom/browser/lib/init.coffee b/atom/browser/lib/init.coffee index 3c5b059b3130..e164b8801b15 100644 --- a/atom/browser/lib/init.coffee +++ b/atom/browser/lib/init.coffee @@ -52,9 +52,6 @@ setImmediate -> detail: message buttons: ['OK'] - # Load the chrome extension support. - require './chrome-extension.js' - # Load the RPC server. require './rpc-server.js' @@ -80,5 +77,8 @@ setImmediate -> else if packageJson.name? app.setName packageJson.name + # Load the chrome extension support. + require './chrome-extension.js' + # Finally load app's main.js and transfer control to C++. module._load path.join(packagePath, packageJson.main), module, true