electron-devtools-vendor
Version:
<div align="center"> <h2>electron-devtools-vendor</h2> <img alt="MIT" src="https://img.shields.io/github/license/BlackHole1/electron-devtools-vendor?color=9cf&style=flat-square"> <img alt="GitHub repo size" src="https://img.shields.io/github/r
141 lines (122 loc) • 6.85 kB
JavaScript
define(["backbone", "underscore", "panelPort", "utils"], function(Backbone, _, panelPort, utils) {
var inspectedPageClient = new (function() {
_.extend(this, Backbone.Events);
this.initialize = function() {
// true when the injection process is being executed, tipically used by the router
// to decide whether to reload the panel or not.
this.isInjecting = false;
// Turn inspected page messages into Backbone events,
// so that Backbone.Events methods like the useful "listenTo" can be used
panelPort.onMessage.addListener(_.bind(function(message) {
if (message && message.target == "page") {
this.trigger(message.name, message);
}
}, this));
};
// Call the callback with an array containing the page frames.
// A frame is an object {url: frameURL}
this.getFrames = function(callback) {
chrome.devtools.inspectedWindow.getResources(_.bind(function(resources) {
var frames = [];
for (var i=0,l=resources.length; i<l; i++) {
var resource = resources[i];
if (resource.type == 'document') {
frames.push({url: resource.url});
}
}
callback(frames);
}, this));
};
// Execute the "func" function in the inspected page,
// passing to it the arguments specified in the "args" array (that must be JSON-compatible),
// a more specific context can be setted by using the "context" parameter.
// frameURL is an optional parameter stating the url of the page frame in which to execute
// the function, if omitted, the top frame will be used.
// The callback "onExecuted" is called with the function return value.
// The method is implemented by using devtools.inspectedWindow.eval.
this.execFunction = function(func, args, onExecuted, context, frameURL) {
if (context === undefined) { context = "this"; }
var options = frameURL ? {frameURL: frameURL} : undefined;
var evalCode = "("+func.toString()+").apply("+context+", "+JSON.stringify(args)+");";
chrome.devtools.inspectedWindow.eval(evalCode, options,
function(result, isException) { // on executed
if (isException) {
var error = _.isObject(isException) ? isException.value : result;
console.log({error: error, evalCode: evalCode, args: args});
throw error;
} else {
if (onExecuted) onExecuted(result);
}
});
};
this.sendMessage = function(messageName, frameURL, messageData) {
messageName = 'client:'+messageName;
panelPort.postMessage({
target: 'extension',
timestamp: new Date().getTime(),
name: messageName,
data: messageData,
frameURL: frameURL
});
};
// Call the callback when the inspected page (top frame) DOM is fully loaded
// or right away if that is already true.
this.ready = function(onReady) {
this.execFunction(function() {
var readyState = document.readyState;
return (readyState != "uninitialized" && readyState != "loading");
}, [], _.bind(function(hasLoaded) { // on executed
if (hasLoaded) {
onReady();
} else {
this.once("ready", onReady);
// (the event is sent only by the top frame, no need to check the frame url)
}
}, this));
};
// Reload the inspected page injecting at the beginning of each of its frame
// the scripts whose absolute base path is specified in the "scriptsBasePath" string.
// The scripts base directory must contain an index.json file with
// a scripts array which will be injected in the provided order.
// Note: the urls are considered as relative to the base path.
// "options.injectionData" is an optional JSON-compatible hash accessible to the scripts,
// is tipically used to pass special data not directly accessible from the page,
// such as the extension url, or for scripts configuration options.
// - preprocessorURL is an optional parameter stating the absolute url of the preprocessor.
this.reloadInjecting = function(scriptsBasePath, preprocessorURL, options) {
options = options || {};
var injectionData = options.injectionData || {};
var inject = _.bind(function(injectedScript, preprocessorScript) {
// Reload the inspected page with the code to inject at the beginning of it
this.isInjecting = true;
chrome.devtools.inspectedWindow.reload({
ignoreCache: true, // avoid to load the old and possibly different
// cached version of the inspected page
injectedScript: injectedScript,
preprocessorScript: preprocessorScript
});
}, this);
utils.fetchData(["index.json"], scriptsBasePath, _.bind(function(data) {
var index = JSON.parse(data[0]);
var scriptURLs = index.scripts;
utils.fetchData(scriptURLs, scriptsBasePath, _.bind(function(scripts) { // on complete
// prepare code to inject
// TODO: create and use source map to ease debugging
var injectedScript = '(function(injectionData) {' + '\n\n'
+ scripts.join('\n\n') + '\n\n'
+ '})('+JSON.stringify(injectionData)+');' + '\n'; // last "\n" prevents eventual EOF error
if (!preprocessorURL) inject(injectedScript);
else utils.fetchData([preprocessorURL], null, _.partial(inject, injectedScript), true);
}, this), true);
}, this), true); // disable request caching (avoid to load the old and possibly different cached
// version of the injected scripts), not needed in production.
};
// a plain inspected page reload without injecting anything,
// useful for stopping the debug mode (causes removal of backbone agent)
this.reload = function() {
chrome.devtools.inspectedWindow.reload();
};
this.initialize();
})();
return inspectedPageClient;
});