blob: 62e4fac1d923e5feb10027f73a862e6820f46072 [file] [log] [blame]
/*
* Copyright (C) 2012 Google Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/* eslint-disable indent */
function defineCommonExtensionSymbols(apiPrivate)
{
if (!apiPrivate.audits)
apiPrivate.audits = {};
apiPrivate.audits.Severity = {
Info: "info",
Warning: "warning",
Severe: "severe"
};
if (!apiPrivate.panels)
apiPrivate.panels = {};
apiPrivate.panels.SearchAction = {
CancelSearch: "cancelSearch",
PerformSearch: "performSearch",
NextSearchResult: "nextSearchResult",
PreviousSearchResult: "previousSearchResult"
};
/** @enum {string} */
apiPrivate.Events = {
AuditStarted: "audit-started-",
ButtonClicked: "button-clicked-",
PanelObjectSelected: "panel-objectSelected-",
NetworkRequestFinished: "network-request-finished",
OpenResource: "open-resource",
PanelSearch: "panel-search-",
ResourceAdded: "resource-added",
ResourceContentCommitted: "resource-content-committed",
ViewShown: "view-shown-",
ViewHidden: "view-hidden-"
};
/** @enum {string} */
apiPrivate.Commands = {
AddAuditCategory: "addAuditCategory",
AddAuditResult: "addAuditResult",
AddRequestHeaders: "addRequestHeaders",
ApplyStyleSheet: "applyStyleSheet",
CreatePanel: "createPanel",
CreateSidebarPane: "createSidebarPane",
CreateToolbarButton: "createToolbarButton",
EvaluateOnInspectedPage: "evaluateOnInspectedPage",
ForwardKeyboardEvent: "_forwardKeyboardEvent",
GetHAR: "getHAR",
GetPageResources: "getPageResources",
GetRequestContent: "getRequestContent",
GetResourceContent: "getResourceContent",
InspectedURLChanged: "inspectedURLChanged",
OpenResource: "openResource",
Reload: "Reload",
Subscribe: "subscribe",
SetOpenResourceHandler: "setOpenResourceHandler",
SetResourceContent: "setResourceContent",
SetSidebarContent: "setSidebarContent",
SetSidebarHeight: "setSidebarHeight",
SetSidebarPage: "setSidebarPage",
ShowPanel: "showPanel",
StopAuditCategoryRun: "stopAuditCategoryRun",
Unsubscribe: "unsubscribe",
UpdateAuditProgress: "updateAuditProgress",
UpdateButton: "updateButton"
};
}
/**
* @param {number} injectedScriptId
* @return {!Object}
* @suppressGlobalPropertiesCheck
*/
function injectedExtensionAPI(injectedScriptId)
{
var apiPrivate = {};
defineCommonExtensionSymbols(apiPrivate);
var commands = apiPrivate.Commands;
var events = apiPrivate.Events;
var userAction = false;
// Here and below, all constructors are private to API implementation.
// For a public type Foo, if internal fields are present, these are on
// a private FooImpl type, an instance of FooImpl is used in a closure
// by Foo consutrctor to re-bind publicly exported members to an instance
// of Foo.
/**
* @constructor
*/
function EventSinkImpl(type, customDispatch)
{
this._type = type;
this._listeners = [];
this._customDispatch = customDispatch;
}
EventSinkImpl.prototype = {
addListener: function(callback)
{
if (typeof callback !== "function")
throw "addListener: callback is not a function";
if (this._listeners.length === 0)
extensionServer.sendRequest({ command: commands.Subscribe, type: this._type });
this._listeners.push(callback);
extensionServer.registerHandler("notify-" + this._type, this._dispatch.bind(this));
},
removeListener: function(callback)
{
var listeners = this._listeners;
for (var i = 0; i < listeners.length; ++i) {
if (listeners[i] === callback) {
listeners.splice(i, 1);
break;
}
}
if (this._listeners.length === 0)
extensionServer.sendRequest({ command: commands.Unsubscribe, type: this._type });
},
/**
* @param {...} vararg
*/
_fire: function(vararg)
{
var listeners = this._listeners.slice();
for (var i = 0; i < listeners.length; ++i)
listeners[i].apply(null, arguments);
},
_dispatch: function(request)
{
if (this._customDispatch)
this._customDispatch.call(this, request);
else
this._fire.apply(this, request.arguments);
}
}
/**
* @constructor
*/
function InspectorExtensionAPI()
{
this.audits = new Audits();
this.inspectedWindow = new InspectedWindow();
this.panels = new Panels();
this.network = new Network();
defineDeprecatedProperty(this, "webInspector", "resources", "network");
}
/**
* @constructor
*/
function Network()
{
/**
* @this {EventSinkImpl}
*/
function dispatchRequestEvent(message)
{
var request = message.arguments[1];
request.__proto__ = new Request(message.arguments[0]);
this._fire(request);
}
this.onRequestFinished = new EventSink(events.NetworkRequestFinished, dispatchRequestEvent);
defineDeprecatedProperty(this, "network", "onFinished", "onRequestFinished");
this.onNavigated = new EventSink(events.InspectedURLChanged);
}
Network.prototype = {
getHAR: function(callback)
{
function callbackWrapper(result)
{
var entries = (result && result.entries) || [];
for (var i = 0; i < entries.length; ++i) {
entries[i].__proto__ = new Request(entries[i]._requestId);
delete entries[i]._requestId;
}
callback(result);
}
extensionServer.sendRequest({ command: commands.GetHAR }, callback && callbackWrapper);
},
addRequestHeaders: function(headers)
{
extensionServer.sendRequest({ command: commands.AddRequestHeaders, headers: headers, extensionId: window.location.hostname });
}
}
/**
* @constructor
*/
function RequestImpl(id)
{
this._id = id;
}
RequestImpl.prototype = {
getContent: function(callback)
{
function callbackWrapper(response)
{
callback(response.content, response.encoding);
}
extensionServer.sendRequest({ command: commands.GetRequestContent, id: this._id }, callback && callbackWrapper);
}
}
/**
* @constructor
*/
function Panels()
{
var panels = {
elements: new ElementsPanel(),
sources: new SourcesPanel(),
};
function panelGetter(name)
{
return panels[name];
}
for (var panel in panels)
this.__defineGetter__(panel, panelGetter.bind(null, panel));
this.applyStyleSheet = function(styleSheet) { extensionServer.sendRequest({ command: commands.ApplyStyleSheet, styleSheet: styleSheet }); };
}
Panels.prototype = {
create: function(title, icon, page, callback)
{
var id = "extension-panel-" + extensionServer.nextObjectId();
var request = {
command: commands.CreatePanel,
id: id,
title: title,
icon: icon,
page: page
};
extensionServer.sendRequest(request, callback && callback.bind(this, new ExtensionPanel(id)));
},
setOpenResourceHandler: function(callback)
{
var hadHandler = extensionServer.hasHandler(events.OpenResource);
function callbackWrapper(message)
{
// Allow the panel to show itself when handling the event.
userAction = true;
try {
callback.call(null, new Resource(message.resource), message.lineNumber);
} finally {
userAction = false;
}
}
if (!callback)
extensionServer.unregisterHandler(events.OpenResource);
else
extensionServer.registerHandler(events.OpenResource, callbackWrapper);
// Only send command if we either removed an existing handler or added handler and had none before.
if (hadHandler === !callback)
extensionServer.sendRequest({ command: commands.SetOpenResourceHandler, "handlerPresent": !!callback });
},
openResource: function(url, lineNumber, callback)
{
extensionServer.sendRequest({ command: commands.OpenResource, "url": url, "lineNumber": lineNumber }, callback);
},
get SearchAction()
{
return apiPrivate.panels.SearchAction;
}
}
/**
* @constructor
*/
function ExtensionViewImpl(id)
{
this._id = id;
/**
* @this {EventSinkImpl}
*/
function dispatchShowEvent(message)
{
var frameIndex = message.arguments[0];
if (typeof frameIndex === "number")
this._fire(window.parent.frames[frameIndex]);
else
this._fire();
}
if (id) {
this.onShown = new EventSink(events.ViewShown + id, dispatchShowEvent);
this.onHidden = new EventSink(events.ViewHidden + id);
}
}
/**
* @constructor
* @extends {ExtensionViewImpl}
* @param {string} hostPanelName
*/
function PanelWithSidebarImpl(hostPanelName)
{
ExtensionViewImpl.call(this, null);
this._hostPanelName = hostPanelName;
this.onSelectionChanged = new EventSink(events.PanelObjectSelected + hostPanelName);
}
PanelWithSidebarImpl.prototype = {
createSidebarPane: function(title, callback)
{
var id = "extension-sidebar-" + extensionServer.nextObjectId();
var request = {
command: commands.CreateSidebarPane,
panel: this._hostPanelName,
id: id,
title: title
};
function callbackWrapper()
{
callback(new ExtensionSidebarPane(id));
}
extensionServer.sendRequest(request, callback && callbackWrapper);
},
__proto__: ExtensionViewImpl.prototype
}
function declareInterfaceClass(implConstructor)
{
return function()
{
var impl = { __proto__: implConstructor.prototype };
implConstructor.apply(impl, arguments);
populateInterfaceClass(this, impl);
};
}
function defineDeprecatedProperty(object, className, oldName, newName)
{
var warningGiven = false;
function getter()
{
if (!warningGiven) {
console.warn(className + "." + oldName + " is deprecated. Use " + className + "." + newName + " instead");
warningGiven = true;
}
return object[newName];
}
object.__defineGetter__(oldName, getter);
}
function extractCallbackArgument(args)
{
var lastArgument = args[args.length - 1];
return typeof lastArgument === "function" ? lastArgument : undefined;
}
var AuditCategory = declareInterfaceClass(AuditCategoryImpl);
var AuditResult = declareInterfaceClass(AuditResultImpl);
var Button = declareInterfaceClass(ButtonImpl);
var EventSink = declareInterfaceClass(EventSinkImpl);
var ExtensionPanel = declareInterfaceClass(ExtensionPanelImpl);
var ExtensionSidebarPane = declareInterfaceClass(ExtensionSidebarPaneImpl);
var PanelWithSidebar = declareInterfaceClass(PanelWithSidebarImpl);
var Request = declareInterfaceClass(RequestImpl);
var Resource = declareInterfaceClass(ResourceImpl);
/**
* @constructor
* @extends {PanelWithSidebar}
*/
function ElementsPanel()
{
PanelWithSidebar.call(this, "elements");
}
ElementsPanel.prototype = {
__proto__: PanelWithSidebar.prototype
}
/**
* @constructor
* @extends {PanelWithSidebar}
*/
function SourcesPanel()
{
PanelWithSidebar.call(this, "sources");
}
SourcesPanel.prototype = {
__proto__: PanelWithSidebar.prototype
}
/**
* @constructor
* @extends {ExtensionViewImpl}
*/
function ExtensionPanelImpl(id)
{
ExtensionViewImpl.call(this, id);
this.onSearch = new EventSink(events.PanelSearch + id);
}
ExtensionPanelImpl.prototype = {
/**
* @return {!Object}
*/
createStatusBarButton: function(iconPath, tooltipText, disabled)
{
var id = "button-" + extensionServer.nextObjectId();
var request = {
command: commands.CreateToolbarButton,
panel: this._id,
id: id,
icon: iconPath,
tooltip: tooltipText,
disabled: !!disabled
};
extensionServer.sendRequest(request);
return new Button(id);
},
show: function()
{
if (!userAction)
return;
var request = {
command: commands.ShowPanel,
id: this._id
};
extensionServer.sendRequest(request);
},
__proto__: ExtensionViewImpl.prototype
}
/**
* @constructor
* @extends {ExtensionViewImpl}
*/
function ExtensionSidebarPaneImpl(id)
{
ExtensionViewImpl.call(this, id);
}
ExtensionSidebarPaneImpl.prototype = {
setHeight: function(height)
{
extensionServer.sendRequest({ command: commands.SetSidebarHeight, id: this._id, height: height });
},
setExpression: function(expression, rootTitle, evaluateOptions)
{
var request = {
command: commands.SetSidebarContent,
id: this._id,
expression: expression,
rootTitle: rootTitle,
evaluateOnPage: true,
};
if (typeof evaluateOptions === "object")
request.evaluateOptions = evaluateOptions;
extensionServer.sendRequest(request, extractCallbackArgument(arguments));
},
setObject: function(jsonObject, rootTitle, callback)
{
extensionServer.sendRequest({ command: commands.SetSidebarContent, id: this._id, expression: jsonObject, rootTitle: rootTitle }, callback);
},
setPage: function(page)
{
extensionServer.sendRequest({ command: commands.SetSidebarPage, id: this._id, page: page });
},
__proto__: ExtensionViewImpl.prototype
}
/**
* @constructor
*/
function ButtonImpl(id)
{
this._id = id;
this.onClicked = new EventSink(events.ButtonClicked + id);
}
ButtonImpl.prototype = {
update: function(iconPath, tooltipText, disabled)
{
var request = {
command: commands.UpdateButton,
id: this._id,
icon: iconPath,
tooltip: tooltipText,
disabled: !!disabled
};
extensionServer.sendRequest(request);
}
};
/**
* @constructor
*/
function Audits()
{
}
Audits.prototype = {
/**
* @return {!AuditCategory}
*/
addCategory: function(displayName, resultCount)
{
var id = "extension-audit-category-" + extensionServer.nextObjectId();
if (typeof resultCount !== "undefined")
console.warn("Passing resultCount to audits.addCategory() is deprecated. Use AuditResult.updateProgress() instead.");
extensionServer.sendRequest({ command: commands.AddAuditCategory, id: id, displayName: displayName, resultCount: resultCount });
return new AuditCategory(id);
}
}
/**
* @constructor
*/
function AuditCategoryImpl(id)
{
/**
* @this {EventSinkImpl}
*/
function dispatchAuditEvent(request)
{
var auditResult = new AuditResult(request.arguments[0]);
try {
this._fire(auditResult);
} catch (e) {
console.error("Uncaught exception in extension audit event handler: " + e);
auditResult.done();
}
}
this._id = id;
this.onAuditStarted = new EventSink(events.AuditStarted + id, dispatchAuditEvent);
}
/**
* @constructor
*/
function AuditResultImpl(id)
{
this._id = id;
this.createURL = this._nodeFactory.bind(this, "url");
this.createSnippet = this._nodeFactory.bind(this, "snippet");
this.createText = this._nodeFactory.bind(this, "text");
this.createObject = this._nodeFactory.bind(this, "object");
this.createNode = this._nodeFactory.bind(this, "node");
}
AuditResultImpl.prototype = {
addResult: function(displayName, description, severity, details)
{
// shorthand for specifying details directly in addResult().
if (details && !(details instanceof AuditResultNode))
details = new AuditResultNode(Array.isArray(details) ? details : [details]);
var request = {
command: commands.AddAuditResult,
resultId: this._id,
displayName: displayName,
description: description,
severity: severity,
details: details
};
extensionServer.sendRequest(request);
},
/**
* @return {!Object}
*/
createResult: function()
{
return new AuditResultNode(Array.prototype.slice.call(arguments));
},
updateProgress: function(worked, totalWork)
{
extensionServer.sendRequest({ command: commands.UpdateAuditProgress, resultId: this._id, progress: worked / totalWork });
},
done: function()
{
extensionServer.sendRequest({ command: commands.StopAuditCategoryRun, resultId: this._id });
},
/**
* @type {!Object.<string, string>}
*/
get Severity()
{
return apiPrivate.audits.Severity;
},
/**
* @return {!{type: string, arguments: !Array.<string|number>}}
*/
createResourceLink: function(url, lineNumber)
{
return {
type: "resourceLink",
arguments: [url, lineNumber && lineNumber - 1]
};
},
/**
* @return {!{type: string, arguments: !Array.<string|number>}}
*/
_nodeFactory: function(type)
{
return {
type: type,
arguments: Array.prototype.slice.call(arguments, 1)
};
}
}
/**
* @constructor
*/
function AuditResultNode(contents)
{
this.contents = contents;
this.children = [];
this.expanded = false;
}
AuditResultNode.prototype = {
/**
* @return {!Object}
*/
addChild: function()
{
var node = new AuditResultNode(Array.prototype.slice.call(arguments));
this.children.push(node);
return node;
}
};
/**
* @constructor
*/
function InspectedWindow()
{
/**
* @this {EventSinkImpl}
*/
function dispatchResourceEvent(message)
{
this._fire(new Resource(message.arguments[0]));
}
/**
* @this {EventSinkImpl}
*/
function dispatchResourceContentEvent(message)
{
this._fire(new Resource(message.arguments[0]), message.arguments[1]);
}
this.onResourceAdded = new EventSink(events.ResourceAdded, dispatchResourceEvent);
this.onResourceContentCommitted = new EventSink(events.ResourceContentCommitted, dispatchResourceContentEvent);
}
InspectedWindow.prototype = {
reload: function(optionsOrUserAgent)
{
var options = null;
if (typeof optionsOrUserAgent === "object") {
options = optionsOrUserAgent;
} else if (typeof optionsOrUserAgent === "string") {
options = { userAgent: optionsOrUserAgent };
console.warn("Passing userAgent as string parameter to inspectedWindow.reload() is deprecated. " +
"Use inspectedWindow.reload({ userAgent: value}) instead.");
}
extensionServer.sendRequest({ command: commands.Reload, options: options });
},
/**
* @return {?Object}
*/
eval: function(expression, evaluateOptions)
{
var callback = extractCallbackArgument(arguments);
function callbackWrapper(result)
{
if (result.isError || result.isException)
callback(undefined, result);
else
callback(result.value);
}
var request = {
command: commands.EvaluateOnInspectedPage,
expression: expression
};
if (typeof evaluateOptions === "object")
request.evaluateOptions = evaluateOptions;
extensionServer.sendRequest(request, callback && callbackWrapper);
return null;
},
getResources: function(callback)
{
function wrapResource(resourceData)
{
return new Resource(resourceData);
}
function callbackWrapper(resources)
{
callback(resources.map(wrapResource));
}
extensionServer.sendRequest({ command: commands.GetPageResources }, callback && callbackWrapper);
}
}
/**
* @constructor
*/
function ResourceImpl(resourceData)
{
this._url = resourceData.url;
this._type = resourceData.type;
}
ResourceImpl.prototype = {
get url()
{
return this._url;
},
get type()
{
return this._type;
},
getContent: function(callback)
{
function callbackWrapper(response)
{
callback(response.content, response.encoding);
}
extensionServer.sendRequest({ command: commands.GetResourceContent, url: this._url }, callback && callbackWrapper);
},
setContent: function(content, commit, callback)
{
extensionServer.sendRequest({ command: commands.SetResourceContent, url: this._url, content: content, commit: commit }, callback);
}
}
var keyboardEventRequestQueue = [];
var forwardTimer = null;
function forwardKeyboardEvent(event)
{
// We only care about global hotkeys, not about random text
if (!event.ctrlKey && !event.altKey && !event.metaKey && !/^F\d+$/.test(event.key) && event.key !== "Escape")
return;
var requestPayload = {
eventType: event.type,
ctrlKey: event.ctrlKey,
altKey: event.altKey,
metaKey: event.metaKey,
keyIdentifier: event.keyIdentifier,
key: event.key,
code: event.code,
location: event.location,
keyCode: event.keyCode
};
keyboardEventRequestQueue.push(requestPayload);
if (!forwardTimer)
forwardTimer = setTimeout(forwardEventQueue, 0);
}
function forwardEventQueue()
{
forwardTimer = null;
var request = {
command: commands.ForwardKeyboardEvent,
entries: keyboardEventRequestQueue
};
extensionServer.sendRequest(request);
keyboardEventRequestQueue = [];
}
document.addEventListener("keydown", forwardKeyboardEvent, false);
document.addEventListener("keypress", forwardKeyboardEvent, false);
/**
* @constructor
*/
function ExtensionServerClient()
{
this._callbacks = {};
this._handlers = {};
this._lastRequestId = 0;
this._lastObjectId = 0;
this.registerHandler("callback", this._onCallback.bind(this));
var channel = new MessageChannel();
this._port = channel.port1;
this._port.addEventListener("message", this._onMessage.bind(this), false);
this._port.start();
window.parent.postMessage("registerExtension", "*", [ channel.port2 ]);
}
ExtensionServerClient.prototype = {
/**
* @param {!Object} message
* @param {function()=} callback
*/
sendRequest: function(message, callback)
{
if (typeof callback === "function")
message.requestId = this._registerCallback(callback);
this._port.postMessage(message);
},
/**
* @return {boolean}
*/
hasHandler: function(command)
{
return !!this._handlers[command];
},
registerHandler: function(command, handler)
{
this._handlers[command] = handler;
},
unregisterHandler: function(command)
{
delete this._handlers[command];
},
/**
* @return {string}
*/
nextObjectId: function()
{
return injectedScriptId.toString() + "_" + ++this._lastObjectId;
},
_registerCallback: function(callback)
{
var id = ++this._lastRequestId;
this._callbacks[id] = callback;
return id;
},
_onCallback: function(request)
{
if (request.requestId in this._callbacks) {
var callback = this._callbacks[request.requestId];
delete this._callbacks[request.requestId];
callback(request.result);
}
},
_onMessage: function(event)
{
var request = event.data;
var handler = this._handlers[request.command];
if (handler)
handler.call(this, request);
}
}
function populateInterfaceClass(interfaze, implementation)
{
for (var member in implementation) {
if (member.charAt(0) === "_")
continue;
var descriptor = null;
// Traverse prototype chain until we find the owner.
for (var owner = implementation; owner && !descriptor; owner = owner.__proto__)
descriptor = Object.getOwnPropertyDescriptor(owner, member);
if (!descriptor)
continue;
if (typeof descriptor.value === "function")
interfaze[member] = descriptor.value.bind(implementation);
else if (typeof descriptor.get === "function")
interfaze.__defineGetter__(member, descriptor.get.bind(implementation));
else
Object.defineProperty(interfaze, member, descriptor);
}
}
// extensionServer is a closure variable defined by the glue below -- make sure we fail if it's not there.
if (!extensionServer)
extensionServer = new ExtensionServerClient();
return new InspectorExtensionAPI();
}
/**
* @suppress {checkVars, checkTypes}
*/
function platformExtensionAPI(coreAPI)
{
function getTabId()
{
return tabId;
}
var chrome = window.chrome || {};
// Override chrome.devtools as a workaround for a error-throwing getter being exposed
// in extension pages loaded into a non-extension process (only happens for remote client
// extensions)
var devtools_descriptor = Object.getOwnPropertyDescriptor(chrome, "devtools");
if (!devtools_descriptor || devtools_descriptor.get)
Object.defineProperty(chrome, "devtools", { value: {}, enumerable: true });
// Only expose tabId on chrome.devtools.inspectedWindow, not webInspector.inspectedWindow.
chrome.devtools.inspectedWindow = {};
chrome.devtools.inspectedWindow.__defineGetter__("tabId", getTabId);
chrome.devtools.inspectedWindow.__proto__ = coreAPI.inspectedWindow;
chrome.devtools.network = coreAPI.network;
chrome.devtools.panels = coreAPI.panels;
chrome.devtools.panels.themeName = themeName;
// default to expose experimental APIs for now.
if (extensionInfo.exposeExperimentalAPIs !== false) {
chrome.experimental = chrome.experimental || {};
chrome.experimental.devtools = chrome.experimental.devtools || {};
var properties = Object.getOwnPropertyNames(coreAPI);
for (var i = 0; i < properties.length; ++i) {
var descriptor = Object.getOwnPropertyDescriptor(coreAPI, properties[i]);
Object.defineProperty(chrome.experimental.devtools, properties[i], descriptor);
}
chrome.experimental.devtools.inspectedWindow = chrome.devtools.inspectedWindow;
}
if (extensionInfo.exposeWebInspectorNamespace)
window.webInspector = coreAPI;
}
/**
* @param {!ExtensionDescriptor} extensionInfo
* @param {string} inspectedTabId
* @param {string} themeName
* @return {string}
*/
function buildPlatformExtensionAPI(extensionInfo, inspectedTabId, themeName)
{
return "var extensionInfo = " + JSON.stringify(extensionInfo) + ";" +
"var tabId = " + inspectedTabId + ";" +
"var themeName = '" + themeName + "';" +
platformExtensionAPI.toString();
}
/**
* @param {!ExtensionDescriptor} extensionInfo
* @param {string} inspectedTabId
* @param {string} themeName
* @return {string}
*/
function buildExtensionAPIInjectedScript(extensionInfo, inspectedTabId, themeName)
{
return "(function(injectedScriptId){ " +
"var extensionServer;" +
defineCommonExtensionSymbols.toString() + ";" +
injectedExtensionAPI.toString() + ";" +
buildPlatformExtensionAPI(extensionInfo, inspectedTabId, themeName) + ";" +
"platformExtensionAPI(injectedExtensionAPI(injectedScriptId));" +
"return {};" +
"})";
}