Add ability to set global preload scripts

This commit is contained in:
Samuel Attard 2017-09-03 02:15:46 +10:00 committed by Cheng Zhao
parent d598aa1a67
commit 0ddd078aaf
10 changed files with 116 additions and 13 deletions

View file

@ -3,7 +3,8 @@
// found in the LICENSE file. // found in the LICENSE file.
#include "atom/browser/api/atom_api_window.h" #include "atom/browser/api/atom_api_window.h"
#include "atom/common/native_mate_converters/value_converter.h"
#include <algorithm>
#include "atom/browser/api/atom_api_browser_view.h" #include "atom/browser/api/atom_api_browser_view.h"
#include "atom/browser/api/atom_api_menu.h" #include "atom/browser/api/atom_api_menu.h"
@ -17,6 +18,7 @@
#include "atom/common/native_mate_converters/gurl_converter.h" #include "atom/common/native_mate_converters/gurl_converter.h"
#include "atom/common/native_mate_converters/image_converter.h" #include "atom/common/native_mate_converters/image_converter.h"
#include "atom/common/native_mate_converters/string16_converter.h" #include "atom/common/native_mate_converters/string16_converter.h"
#include "atom/common/native_mate_converters/value_converter.h"
#include "atom/common/options_switches.h" #include "atom/common/options_switches.h"
#include "base/command_line.h" #include "base/command_line.h"
#include "base/threading/thread_task_runner_handle.h" #include "base/threading/thread_task_runner_handle.h"
@ -174,6 +176,19 @@ Window::~Window() {
base::ThreadTaskRunnerHandle::Get()->DeleteSoon(FROM_HERE, window_.release()); base::ThreadTaskRunnerHandle::Get()->DeleteSoon(FROM_HERE, window_.release());
} }
std::vector<base::FilePath::StringType> g_preloads;
void Window::AddGlobalPreload(const base::FilePath::StringType preloadPath) {
g_preloads.push_back(preloadPath);
}
void Window::RemoveGlobalPreload(const base::FilePath::StringType preloadPath) {
g_preloads.erase(
std::remove(g_preloads.begin(), g_preloads.end(), preloadPath),
g_preloads.end());
}
std::vector<base::FilePath::StringType> Window::GetGlobalPreloads() {
return g_preloads;
}
void Window::WillCloseWindow(bool* prevent_default) { void Window::WillCloseWindow(bool* prevent_default) {
*prevent_default = Emit("close"); *prevent_default = Emit("close");
} }
@ -1152,6 +1167,12 @@ void Initialize(v8::Local<v8::Object> exports, v8::Local<v8::Value> unused,
&mate::TrackableObject<Window>::FromWeakMapID); &mate::TrackableObject<Window>::FromWeakMapID);
browser_window.SetMethod("getAllWindows", browser_window.SetMethod("getAllWindows",
&mate::TrackableObject<Window>::GetAll); &mate::TrackableObject<Window>::GetAll);
browser_window.SetMethod("addGlobalPreload",
&Window::AddGlobalPreload);
browser_window.SetMethod("removeGlobalPreload",
&Window::RemoveGlobalPreload);
browser_window.SetMethod("getGlobalPreloads",
&Window::GetGlobalPreloads);
mate::Dictionary dict(isolate, exports); mate::Dictionary dict(isolate, exports);
dict.Set("BrowserWindow", browser_window); dict.Set("BrowserWindow", browser_window);

View file

@ -54,6 +54,10 @@ class Window : public mate::TrackableObject<Window>,
int32_t ID() const; int32_t ID() const;
static void AddGlobalPreload(const base::FilePath::StringType preloadPath);
static void RemoveGlobalPreload(const base::FilePath::StringType preloadPath);
static std::vector<base::FilePath::StringType> GetGlobalPreloads();
protected: protected:
Window(v8::Isolate* isolate, v8::Local<v8::Object> wrapper, Window(v8::Isolate* isolate, v8::Local<v8::Object> wrapper,
const mate::Dictionary& options); const mate::Dictionary& options);

View file

@ -8,6 +8,7 @@
#include <string> #include <string>
#include <vector> #include <vector>
#include "atom/browser/api/atom_api_window.h"
#include "atom/browser/native_window.h" #include "atom/browser/native_window.h"
#include "atom/browser/web_view_manager.h" #include "atom/browser/web_view_manager.h"
#include "atom/common/native_mate_converters/value_converter.h" #include "atom/common/native_mate_converters/value_converter.h"
@ -136,6 +137,14 @@ void WebContentsPreferences::AppendExtraCommandLineSwitches(
LOG(ERROR) << "preload url must be file:// protocol."; LOG(ERROR) << "preload url must be file:// protocol.";
} }
for (auto preloadPath : atom::api::Window::GetGlobalPreloads()) {
if (base::FilePath(preloadPath).IsAbsolute())
command_line->AppendSwitchNative(switches::kGlobalPreloadScript,
preloadPath);
else
LOG(ERROR) << "preload script must have absolute path.";
}
// Run Electron APIs and preload script in isolated world // Run Electron APIs and preload script in isolated world
bool isolated; bool isolated;
if (web_preferences.GetBoolean(options::kContextIsolation, &isolated) && if (web_preferences.GetBoolean(options::kContextIsolation, &isolated) &&

View file

@ -177,17 +177,18 @@ const char kAppUserModelId[] = "app-user-model-id";
const char kAppPath[] = "app-path"; const char kAppPath[] = "app-path";
// The command line switch versions of the options. // The command line switch versions of the options.
const char kBackgroundColor[] = "background-color"; const char kBackgroundColor[] = "background-color";
const char kPreloadScript[] = "preload"; const char kPreloadScript[] = "preload";
const char kPreloadURL[] = "preload-url"; const char kPreloadURL[] = "preload-url";
const char kNodeIntegration[] = "node-integration"; const char kGlobalPreloadScript[] = "global-preload";
const char kContextIsolation[] = "context-isolation"; const char kNodeIntegration[] = "node-integration";
const char kGuestInstanceID[] = "guest-instance-id"; const char kContextIsolation[] = "context-isolation";
const char kOpenerID[] = "opener-id"; const char kGuestInstanceID[] = "guest-instance-id";
const char kScrollBounce[] = "scroll-bounce"; const char kOpenerID[] = "opener-id";
const char kHiddenPage[] = "hidden-page"; const char kScrollBounce[] = "scroll-bounce";
const char kNativeWindowOpen[] = "native-window-open"; const char kHiddenPage[] = "hidden-page";
const char kWebviewTag[] = "webview-tag"; const char kNativeWindowOpen[] = "native-window-open";
const char kWebviewTag[] = "webview-tag";
// Command switch passed to renderer process to control nodeIntegration. // Command switch passed to renderer process to control nodeIntegration.
const char kNodeIntegrationInWorker[] = "node-integration-in-worker"; const char kNodeIntegrationInWorker[] = "node-integration-in-worker";

View file

@ -91,6 +91,7 @@ extern const char kAppPath[];
extern const char kBackgroundColor[]; extern const char kBackgroundColor[];
extern const char kPreloadScript[]; extern const char kPreloadScript[];
extern const char kPreloadURL[]; extern const char kPreloadURL[];
extern const char kGlobalPreloadScript[];
extern const char kNodeIntegration[]; extern const char kNodeIntegration[];
extern const char kContextIsolation[]; extern const char kContextIsolation[];
extern const char kGuestInstanceID[]; extern const char kGuestInstanceID[];

View file

@ -662,6 +662,25 @@ console.log(installed)
**Note:** This API cannot be called before the `ready` event of the `app` module **Note:** This API cannot be called before the `ready` event of the `app` module
is emitted. is emitted.
#### `BrowserWindow.addGlobalPreload(preloadPath)`
* `preloadPath` String - An absolute path to the preload script
Adds a script that will be executed on ALL new BrowserWindows just before normal `preload` scripts run.
#### `BrowserWindow.removeGlobalPreload(preloadPath)`
* `preloadPath` String - An absolute path to the preload script
Removes the given script from the list of global preload scripts
#### `BrowserWindow.getGlobalPreloads()`
Returns `String[]` an array of paths to preload scripts that have been registered
Adds a script that will be executed on ALL new BrowserWindows just before normal `preload` scripts run.
### Instance Properties ### Instance Properties
Objects created with `new BrowserWindow` have the following properties: Objects created with `new BrowserWindow` have the following properties:

View file

@ -67,6 +67,7 @@ electron.ipcRenderer.on('ELECTRON_INTERNAL_RENDERER_ASYNC_WEB_FRAME_METHOD', (ev
let nodeIntegration = 'false' let nodeIntegration = 'false'
let webviewTag = 'false' let webviewTag = 'false'
let preloadScript = null let preloadScript = null
const globalPreloadScripts = []
let isBackgroundPage = false let isBackgroundPage = false
let appPath = null let appPath = null
for (let arg of process.argv) { for (let arg of process.argv) {
@ -86,6 +87,8 @@ for (let arg of process.argv) {
appPath = arg.substr(arg.indexOf('=') + 1) appPath = arg.substr(arg.indexOf('=') + 1)
} else if (arg.indexOf('--webview-tag=') === 0) { } else if (arg.indexOf('--webview-tag=') === 0) {
webviewTag = arg.substr(arg.indexOf('=') + 1) webviewTag = arg.substr(arg.indexOf('=') + 1)
} else if (arg.indexOf('--global-preload') === 0) {
globalPreloadScripts.push(arg.substr(arg.indexOf('=') + 1))
} }
} }
@ -171,6 +174,15 @@ if (nodeIntegration === 'true') {
}) })
} }
for (const globalPreloadScript of globalPreloadScripts) {
try {
require(globalPreloadScript)
} catch (error) {
console.error('Unable to load global preload script: ' + globalPreloadScript)
console.error(error.stack || error.message)
}
}
// Load the script specfied by the "preload" attribute. // Load the script specfied by the "preload" attribute.
if (preloadScript) { if (preloadScript) {
try { try {

View file

@ -1021,6 +1021,41 @@ describe('BrowserWindow module', () => {
}) })
}) })
describe('global preload scripts', function () {
it('can add and remove multiple global preload script', function () {
var preload = path.join(fixtures, 'module', 'set-global.js')
var preload2 = path.join(fixtures, 'module', 'set-global-2.js')
assert.deepEqual(BrowserWindow.getGlobalPreloads(), [])
BrowserWindow.addGlobalPreload(preload)
assert.deepEqual(BrowserWindow.getGlobalPreloads(), [preload])
BrowserWindow.addGlobalPreload(preload2)
assert.deepEqual(BrowserWindow.getGlobalPreloads(), [preload, preload2])
BrowserWindow.removeGlobalPreload(preload)
assert.deepEqual(BrowserWindow.getGlobalPreloads(), [preload2])
BrowserWindow.removeGlobalPreload(preload2)
assert.deepEqual(BrowserWindow.getGlobalPreloads(), [])
})
it('loads the script before other scripts in window including normal preloads', function (done) {
var preload = path.join(fixtures, 'module', 'set-global.js')
var preload2 = path.join(fixtures, 'module', 'set-global-2.js')
ipcMain.once('answer', function (event, test) {
BrowserWindow.removeGlobalPreload(preload2)
assert.equal(test, 'preload2')
done()
})
w.destroy()
BrowserWindow.addGlobalPreload(preload2)
w = new BrowserWindow({
show: false,
webPreferences: {
preload: preload
}
})
w.loadURL('file://' + path.join(fixtures, 'api', 'preload.html'))
})
})
describe('"node-integration" option', () => { describe('"node-integration" option', () => {
it('disables node integration when specified to false', (done) => { it('disables node integration when specified to false', (done) => {
const preload = path.join(fixtures, 'module', 'send-later.js') const preload = path.join(fixtures, 'module', 'send-later.js')

1
spec/fixtures/module/set-global-2.js vendored Normal file
View file

@ -0,0 +1 @@
if (!window.test) window.test = 'preload2'

View file

@ -1 +1 @@
window.test = 'preload' if (!window.test) window.test = 'preload'