2 * Copyright (C) 2012 Google Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above
11 * copyright notice, this list of conditions and the following disclaimer
12 * in the documentation and/or other materials provided with the
14 * * Neither the name of Google Inc. nor the names of its
15 * contributors may be used to endorse or promote products derived from
16 * this software without specific prior written permission.
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 function defineCommonExtensionSymbols(apiPrivate)
33 if (!apiPrivate.audits)
34 apiPrivate.audits = {};
35 apiPrivate.audits.Severity = {
41 if (!apiPrivate.console)
42 apiPrivate.console = {};
43 apiPrivate.console.Severity = {
50 if (!apiPrivate.panels)
51 apiPrivate.panels = {};
52 apiPrivate.panels.SearchAction = {
53 CancelSearch: "cancelSearch",
54 PerformSearch: "performSearch",
55 NextSearchResult: "nextSearchResult",
56 PreviousSearchResult: "previousSearchResult"
60 AuditStarted: "audit-started-",
61 ButtonClicked: "button-clicked-",
62 ConsoleMessageAdded: "console-message-added",
63 PanelObjectSelected: "panel-objectSelected-",
64 NetworkRequestFinished: "network-request-finished",
65 OpenResource: "open-resource",
66 PanelSearch: "panel-search-",
67 ResourceAdded: "resource-added",
68 ResourceContentCommitted: "resource-content-committed",
69 TimelineEventRecorded: "timeline-event-recorded",
70 ViewShown: "view-shown-",
71 ViewHidden: "view-hidden-"
74 apiPrivate.Commands = {
75 AddAuditCategory: "addAuditCategory",
76 AddAuditResult: "addAuditResult",
77 AddConsoleMessage: "addConsoleMessage",
78 AddRequestHeaders: "addRequestHeaders",
79 ApplyStyleSheet: "applyStyleSheet",
80 CreatePanel: "createPanel",
81 CreateSidebarPane: "createSidebarPane",
82 CreateStatusBarButton: "createStatusBarButton",
83 EvaluateOnInspectedPage: "evaluateOnInspectedPage",
84 ForwardKeyboardEvent: "_forwardKeyboardEvent",
85 GetConsoleMessages: "getConsoleMessages",
87 GetPageResources: "getPageResources",
88 GetRequestContent: "getRequestContent",
89 GetResourceContent: "getResourceContent",
90 InspectedURLChanged: "inspectedURLChanged",
91 OpenResource: "openResource",
93 Subscribe: "subscribe",
94 SetOpenResourceHandler: "setOpenResourceHandler",
95 SetResourceContent: "setResourceContent",
96 SetSidebarContent: "setSidebarContent",
97 SetSidebarHeight: "setSidebarHeight",
98 SetSidebarPage: "setSidebarPage",
99 ShowPanel: "showPanel",
100 StopAuditCategoryRun: "stopAuditCategoryRun",
101 Unsubscribe: "unsubscribe",
102 UpdateAuditProgress: "updateAuditProgress",
103 UpdateButton: "updateButton"
108 * @param {number} injectedScriptId
111 function injectedExtensionAPI(injectedScriptId)
116 defineCommonExtensionSymbols(apiPrivate);
118 var commands = apiPrivate.Commands;
119 var events = apiPrivate.Events;
120 var userAction = false;
122 // Here and below, all constructors are private to API implementation.
123 // For a public type Foo, if internal fields are present, these are on
124 // a private FooImpl type, an instance of FooImpl is used in a closure
125 // by Foo consutrctor to re-bind publicly exported members to an instance
131 function EventSinkImpl(type, customDispatch)
134 this._listeners = [];
135 this._customDispatch = customDispatch;
138 EventSinkImpl.prototype = {
139 addListener: function(callback)
141 if (typeof callback !== "function")
142 throw "addListener: callback is not a function";
143 if (this._listeners.length === 0)
144 extensionServer.sendRequest({ command: commands.Subscribe, type: this._type });
145 this._listeners.push(callback);
146 extensionServer.registerHandler("notify-" + this._type, this._dispatch.bind(this));
149 removeListener: function(callback)
151 var listeners = this._listeners;
153 for (var i = 0; i < listeners.length; ++i) {
154 if (listeners[i] === callback) {
155 listeners.splice(i, 1);
159 if (this._listeners.length === 0)
160 extensionServer.sendRequest({ command: commands.Unsubscribe, type: this._type });
164 * @param {...} vararg
166 _fire: function(vararg)
168 var listeners = this._listeners.slice();
169 for (var i = 0; i < listeners.length; ++i)
170 listeners[i].apply(null, arguments);
173 _dispatch: function(request)
175 if (this._customDispatch)
176 this._customDispatch.call(this, request);
178 this._fire.apply(this, request.arguments);
185 function InspectorExtensionAPI()
187 this.audits = new Audits();
188 this.inspectedWindow = new InspectedWindow();
189 this.panels = new Panels();
190 this.network = new Network();
191 defineDeprecatedProperty(this, "webInspector", "resources", "network");
192 this.timeline = new Timeline();
193 this.console = new ConsoleAPI();
199 function ConsoleAPI()
201 this.onMessageAdded = new EventSink(events.ConsoleMessageAdded);
204 ConsoleAPI.prototype = {
205 getMessages: function(callback)
207 extensionServer.sendRequest({ command: commands.GetConsoleMessages }, callback);
210 addMessage: function(severity, text, url, line)
212 extensionServer.sendRequest({ command: commands.AddConsoleMessage, severity: severity, text: text, url: url, line: line });
217 return apiPrivate.console.Severity;
227 * @this {EventSinkImpl}
229 function dispatchRequestEvent(message)
231 var request = message.arguments[1];
232 request.__proto__ = new Request(message.arguments[0]);
235 this.onRequestFinished = new EventSink(events.NetworkRequestFinished, dispatchRequestEvent);
236 defineDeprecatedProperty(this, "network", "onFinished", "onRequestFinished");
237 this.onNavigated = new EventSink(events.InspectedURLChanged);
240 Network.prototype = {
241 getHAR: function(callback)
243 function callbackWrapper(result)
245 var entries = (result && result.entries) || [];
246 for (var i = 0; i < entries.length; ++i) {
247 entries[i].__proto__ = new Request(entries[i]._requestId);
248 delete entries[i]._requestId;
252 extensionServer.sendRequest({ command: commands.GetHAR }, callback && callbackWrapper);
255 addRequestHeaders: function(headers)
257 extensionServer.sendRequest({ command: commands.AddRequestHeaders, headers: headers, extensionId: window.location.hostname });
264 function RequestImpl(id)
269 RequestImpl.prototype = {
270 getContent: function(callback)
272 function callbackWrapper(response)
274 callback(response.content, response.encoding);
276 extensionServer.sendRequest({ command: commands.GetRequestContent, id: this._id }, callback && callbackWrapper);
286 elements: new ElementsPanel(),
287 sources: new SourcesPanel(),
290 function panelGetter(name)
294 for (var panel in panels)
295 this.__defineGetter__(panel, panelGetter.bind(null, panel));
296 this.applyStyleSheet = function(styleSheet) { extensionServer.sendRequest({ command: commands.ApplyStyleSheet, styleSheet: styleSheet }); };
300 create: function(title, icon, page, callback)
302 var id = "extension-panel-" + extensionServer.nextObjectId();
304 command: commands.CreatePanel,
310 extensionServer.sendRequest(request, callback && callback.bind(this, new ExtensionPanel(id)));
313 setOpenResourceHandler: function(callback)
315 var hadHandler = extensionServer.hasHandler(events.OpenResource);
317 function callbackWrapper(message)
319 // Allow the panel to show itself when handling the event.
322 callback.call(null, new Resource(message.resource), message.lineNumber);
329 extensionServer.unregisterHandler(events.OpenResource);
331 extensionServer.registerHandler(events.OpenResource, callbackWrapper);
333 // Only send command if we either removed an existing handler or added handler and had none before.
334 if (hadHandler === !callback)
335 extensionServer.sendRequest({ command: commands.SetOpenResourceHandler, "handlerPresent": !!callback });
338 openResource: function(url, lineNumber, callback)
340 extensionServer.sendRequest({ command: commands.OpenResource, "url": url, "lineNumber": lineNumber }, callback);
345 return apiPrivate.panels.SearchAction;
352 function ExtensionViewImpl(id)
357 * @this {EventSinkImpl}
359 function dispatchShowEvent(message)
361 var frameIndex = message.arguments[0];
362 if (typeof frameIndex === "number")
363 this._fire(window.parent.frames[frameIndex]);
369 this.onShown = new EventSink(events.ViewShown + id, dispatchShowEvent);
370 this.onHidden = new EventSink(events.ViewHidden + id);
376 * @extends {ExtensionViewImpl}
377 * @param {string} hostPanelName
379 function PanelWithSidebarImpl(hostPanelName)
381 ExtensionViewImpl.call(this, null);
382 this._hostPanelName = hostPanelName;
383 this.onSelectionChanged = new EventSink(events.PanelObjectSelected + hostPanelName);
386 PanelWithSidebarImpl.prototype = {
387 createSidebarPane: function(title, callback)
389 var id = "extension-sidebar-" + extensionServer.nextObjectId();
391 command: commands.CreateSidebarPane,
392 panel: this._hostPanelName,
396 function callbackWrapper()
398 callback(new ExtensionSidebarPane(id));
400 extensionServer.sendRequest(request, callback && callbackWrapper);
403 __proto__: ExtensionViewImpl.prototype
406 function declareInterfaceClass(implConstructor)
410 var impl = { __proto__: implConstructor.prototype };
411 implConstructor.apply(impl, arguments);
412 populateInterfaceClass(this, impl);
416 function defineDeprecatedProperty(object, className, oldName, newName)
418 var warningGiven = false;
422 console.warn(className + "." + oldName + " is deprecated. Use " + className + "." + newName + " instead");
425 return object[newName];
427 object.__defineGetter__(oldName, getter);
430 function extractCallbackArgument(args)
432 var lastArgument = args[args.length - 1];
433 return typeof lastArgument === "function" ? lastArgument : undefined;
436 var AuditCategory = declareInterfaceClass(AuditCategoryImpl);
437 var AuditResult = declareInterfaceClass(AuditResultImpl);
438 var Button = declareInterfaceClass(ButtonImpl);
439 var EventSink = declareInterfaceClass(EventSinkImpl);
440 var ExtensionPanel = declareInterfaceClass(ExtensionPanelImpl);
441 var ExtensionSidebarPane = declareInterfaceClass(ExtensionSidebarPaneImpl);
442 var PanelWithSidebar = declareInterfaceClass(PanelWithSidebarImpl);
443 var Request = declareInterfaceClass(RequestImpl);
444 var Resource = declareInterfaceClass(ResourceImpl);
445 var Timeline = declareInterfaceClass(TimelineImpl);
449 * @extends {PanelWithSidebar}
451 function ElementsPanel()
453 PanelWithSidebar.call(this, "elements");
456 ElementsPanel.prototype = {
457 __proto__: PanelWithSidebar.prototype
462 * @extends {PanelWithSidebar}
464 function SourcesPanel()
466 PanelWithSidebar.call(this, "sources");
469 SourcesPanel.prototype = {
470 __proto__: PanelWithSidebar.prototype
475 * @extends {ExtensionViewImpl}
477 function ExtensionPanelImpl(id)
479 ExtensionViewImpl.call(this, id);
480 this.onSearch = new EventSink(events.PanelSearch + id);
483 ExtensionPanelImpl.prototype = {
487 createStatusBarButton: function(iconPath, tooltipText, disabled)
489 var id = "button-" + extensionServer.nextObjectId();
491 command: commands.CreateStatusBarButton,
495 tooltip: tooltipText,
498 extensionServer.sendRequest(request);
499 return new Button(id);
508 command: commands.ShowPanel,
511 extensionServer.sendRequest(request);
514 __proto__: ExtensionViewImpl.prototype
519 * @extends {ExtensionViewImpl}
521 function ExtensionSidebarPaneImpl(id)
523 ExtensionViewImpl.call(this, id);
526 ExtensionSidebarPaneImpl.prototype = {
527 setHeight: function(height)
529 extensionServer.sendRequest({ command: commands.SetSidebarHeight, id: this._id, height: height });
532 setExpression: function(expression, rootTitle, evaluateOptions)
535 command: commands.SetSidebarContent,
537 expression: expression,
538 rootTitle: rootTitle,
539 evaluateOnPage: true,
541 if (typeof evaluateOptions === "object")
542 request.evaluateOptions = evaluateOptions;
543 extensionServer.sendRequest(request, extractCallbackArgument(arguments));
546 setObject: function(jsonObject, rootTitle, callback)
548 extensionServer.sendRequest({ command: commands.SetSidebarContent, id: this._id, expression: jsonObject, rootTitle: rootTitle }, callback);
551 setPage: function(page)
553 extensionServer.sendRequest({ command: commands.SetSidebarPage, id: this._id, page: page });
556 __proto__: ExtensionViewImpl.prototype
562 function ButtonImpl(id)
565 this.onClicked = new EventSink(events.ButtonClicked + id);
568 ButtonImpl.prototype = {
569 update: function(iconPath, tooltipText, disabled)
572 command: commands.UpdateButton,
575 tooltip: tooltipText,
578 extensionServer.sendRequest(request);
591 * @return {!AuditCategory}
593 addCategory: function(displayName, resultCount)
595 var id = "extension-audit-category-" + extensionServer.nextObjectId();
596 if (typeof resultCount !== "undefined")
597 console.warn("Passing resultCount to audits.addCategory() is deprecated. Use AuditResult.updateProgress() instead.");
598 extensionServer.sendRequest({ command: commands.AddAuditCategory, id: id, displayName: displayName, resultCount: resultCount });
599 return new AuditCategory(id);
606 function AuditCategoryImpl(id)
609 * @this {EventSinkImpl}
611 function dispatchAuditEvent(request)
613 var auditResult = new AuditResult(request.arguments[0]);
615 this._fire(auditResult);
617 console.error("Uncaught exception in extension audit event handler: " + e);
622 this.onAuditStarted = new EventSink(events.AuditStarted + id, dispatchAuditEvent);
628 function AuditResultImpl(id)
632 this.createURL = this._nodeFactory.bind(this, "url");
633 this.createSnippet = this._nodeFactory.bind(this, "snippet");
634 this.createText = this._nodeFactory.bind(this, "text");
635 this.createObject = this._nodeFactory.bind(this, "object");
636 this.createNode = this._nodeFactory.bind(this, "node");
639 AuditResultImpl.prototype = {
640 addResult: function(displayName, description, severity, details)
642 // shorthand for specifying details directly in addResult().
643 if (details && !(details instanceof AuditResultNode))
644 details = new AuditResultNode(details instanceof Array ? details : [details]);
647 command: commands.AddAuditResult,
649 displayName: displayName,
650 description: description,
654 extensionServer.sendRequest(request);
660 createResult: function()
662 return new AuditResultNode(Array.prototype.slice.call(arguments));
665 updateProgress: function(worked, totalWork)
667 extensionServer.sendRequest({ command: commands.UpdateAuditProgress, resultId: this._id, progress: worked / totalWork });
672 extensionServer.sendRequest({ command: commands.StopAuditCategoryRun, resultId: this._id });
676 * @type {!Object.<string, string>}
680 return apiPrivate.audits.Severity;
684 * @return {!{type: string, arguments: !Array.<string|number>}}
686 createResourceLink: function(url, lineNumber)
689 type: "resourceLink",
690 arguments: [url, lineNumber && lineNumber - 1]
695 * @return {!{type: string, arguments: !Array.<string|number>}}
697 _nodeFactory: function(type)
701 arguments: Array.prototype.slice.call(arguments, 1)
709 function AuditResultNode(contents)
711 this.contents = contents;
713 this.expanded = false;
716 AuditResultNode.prototype = {
722 var node = new AuditResultNode(Array.prototype.slice.call(arguments));
723 this.children.push(node);
731 function InspectedWindow()
734 * @this {EventSinkImpl}
736 function dispatchResourceEvent(message)
738 this._fire(new Resource(message.arguments[0]));
742 * @this {EventSinkImpl}
744 function dispatchResourceContentEvent(message)
746 this._fire(new Resource(message.arguments[0]), message.arguments[1]);
749 this.onResourceAdded = new EventSink(events.ResourceAdded, dispatchResourceEvent);
750 this.onResourceContentCommitted = new EventSink(events.ResourceContentCommitted, dispatchResourceContentEvent);
753 InspectedWindow.prototype = {
754 reload: function(optionsOrUserAgent)
757 if (typeof optionsOrUserAgent === "object")
758 options = optionsOrUserAgent;
759 else if (typeof optionsOrUserAgent === "string") {
760 options = { userAgent: optionsOrUserAgent };
761 console.warn("Passing userAgent as string parameter to inspectedWindow.reload() is deprecated. " +
762 "Use inspectedWindow.reload({ userAgent: value}) instead.");
764 extensionServer.sendRequest({ command: commands.Reload, options: options });
770 eval: function(expression, evaluateOptions)
772 var callback = extractCallbackArgument(arguments);
773 function callbackWrapper(result)
775 if (result.isError || result.isException)
776 callback(undefined, result);
778 callback(result.value);
781 command: commands.EvaluateOnInspectedPage,
782 expression: expression
784 if (typeof evaluateOptions === "object")
785 request.evaluateOptions = evaluateOptions;
786 extensionServer.sendRequest(request, callback && callbackWrapper);
790 getResources: function(callback)
792 function wrapResource(resourceData)
794 return new Resource(resourceData);
796 function callbackWrapper(resources)
798 callback(resources.map(wrapResource));
800 extensionServer.sendRequest({ command: commands.GetPageResources }, callback && callbackWrapper);
807 function ResourceImpl(resourceData)
809 this._url = resourceData.url
810 this._type = resourceData.type;
813 ResourceImpl.prototype = {
824 getContent: function(callback)
826 function callbackWrapper(response)
828 callback(response.content, response.encoding);
831 extensionServer.sendRequest({ command: commands.GetResourceContent, url: this._url }, callback && callbackWrapper);
834 setContent: function(content, commit, callback)
836 extensionServer.sendRequest({ command: commands.SetResourceContent, url: this._url, content: content, commit: commit }, callback);
843 function TimelineImpl()
845 this.onEventRecorded = new EventSink(events.TimelineEventRecorded);
848 var keyboardEventRequestQueue = [];
849 var forwardTimer = null;
851 function forwardKeyboardEvent(event)
853 const Esc = "U+001B";
854 // We only care about global hotkeys, not about random text
855 if (!event.ctrlKey && !event.altKey && !event.metaKey && !/^F\d+$/.test(event.keyIdentifier) && event.keyIdentifier !== Esc)
857 var requestPayload = {
858 eventType: event.type,
859 ctrlKey: event.ctrlKey,
860 altKey: event.altKey,
861 metaKey: event.metaKey,
862 keyIdentifier: event.keyIdentifier,
863 location: event.location,
864 keyCode: event.keyCode
866 keyboardEventRequestQueue.push(requestPayload);
868 forwardTimer = setTimeout(forwardEventQueue, 0);
871 function forwardEventQueue()
875 command: commands.ForwardKeyboardEvent,
876 entries: keyboardEventRequestQueue
878 extensionServer.sendRequest(request);
879 keyboardEventRequestQueue = [];
882 document.addEventListener("keydown", forwardKeyboardEvent, false);
883 document.addEventListener("keypress", forwardKeyboardEvent, false);
888 function ExtensionServerClient()
890 this._callbacks = {};
892 this._lastRequestId = 0;
893 this._lastObjectId = 0;
895 this.registerHandler("callback", this._onCallback.bind(this));
897 var channel = new MessageChannel();
898 this._port = channel.port1;
899 this._port.addEventListener("message", this._onMessage.bind(this), false);
902 window.parent.postMessage("registerExtension", [ channel.port2 ], "*");
905 ExtensionServerClient.prototype = {
907 * @param {function()=} callback
909 sendRequest: function(message, callback)
911 if (typeof callback === "function")
912 message.requestId = this._registerCallback(callback);
913 this._port.postMessage(message);
919 hasHandler: function(command)
921 return !!this._handlers[command];
924 registerHandler: function(command, handler)
926 this._handlers[command] = handler;
929 unregisterHandler: function(command)
931 delete this._handlers[command];
937 nextObjectId: function()
939 return injectedScriptId + "_" + ++this._lastObjectId;
942 _registerCallback: function(callback)
944 var id = ++this._lastRequestId;
945 this._callbacks[id] = callback;
949 _onCallback: function(request)
951 if (request.requestId in this._callbacks) {
952 var callback = this._callbacks[request.requestId];
953 delete this._callbacks[request.requestId];
954 callback(request.result);
958 _onMessage: function(event)
960 var request = event.data;
961 var handler = this._handlers[request.command];
963 handler.call(this, request);
967 function populateInterfaceClass(interface, implementation)
969 for (var member in implementation) {
970 if (member.charAt(0) === "_")
972 var descriptor = null;
973 // Traverse prototype chain until we find the owner.
974 for (var owner = implementation; owner && !descriptor; owner = owner.__proto__)
975 descriptor = Object.getOwnPropertyDescriptor(owner, member);
978 if (typeof descriptor.value === "function")
979 interface[member] = descriptor.value.bind(implementation);
980 else if (typeof descriptor.get === "function")
981 interface.__defineGetter__(member, descriptor.get.bind(implementation));
983 Object.defineProperty(interface, member, descriptor);
987 // extensionServer is a closure variable defined by the glue below -- make sure we fail if it's not there.
988 if (!extensionServer)
989 extensionServer = new ExtensionServerClient();
991 return new InspectorExtensionAPI();
995 * @suppress {checkVars, checkTypes}
997 function platformExtensionAPI(coreAPI)
1003 chrome = window.chrome || {};
1004 // Override chrome.devtools as a workaround for a error-throwing getter being exposed
1005 // in extension pages loaded into a non-extension process (only happens for remote client
1007 var devtools_descriptor = Object.getOwnPropertyDescriptor(chrome, "devtools");
1008 if (!devtools_descriptor || devtools_descriptor.get)
1009 Object.defineProperty(chrome, "devtools", { value: {}, enumerable: true });
1010 // Only expose tabId on chrome.devtools.inspectedWindow, not webInspector.inspectedWindow.
1011 chrome.devtools.inspectedWindow = {};
1012 chrome.devtools.inspectedWindow.__defineGetter__("tabId", getTabId);
1013 chrome.devtools.inspectedWindow.__proto__ = coreAPI.inspectedWindow;
1014 chrome.devtools.network = coreAPI.network;
1015 chrome.devtools.panels = coreAPI.panels;
1017 // default to expose experimental APIs for now.
1018 if (extensionInfo.exposeExperimentalAPIs !== false) {
1019 chrome.experimental = chrome.experimental || {};
1020 chrome.experimental.devtools = chrome.experimental.devtools || {};
1022 var properties = Object.getOwnPropertyNames(coreAPI);
1023 for (var i = 0; i < properties.length; ++i) {
1024 var descriptor = Object.getOwnPropertyDescriptor(coreAPI, properties[i]);
1025 Object.defineProperty(chrome.experimental.devtools, properties[i], descriptor);
1027 chrome.experimental.devtools.inspectedWindow = chrome.devtools.inspectedWindow;
1029 if (extensionInfo.exposeWebInspectorNamespace)
1030 window.webInspector = coreAPI;
1034 * @param {!ExtensionDescriptor} extensionInfo
1037 function buildPlatformExtensionAPI(extensionInfo)
1039 return "var extensionInfo = " + JSON.stringify(extensionInfo) + ";" +
1040 "var tabId = " + WebInspector._inspectedTabId + ";" +
1041 platformExtensionAPI.toString();
1045 * @param {!ExtensionDescriptor} extensionInfo
1048 function buildExtensionAPIInjectedScript(extensionInfo)
1050 return "(function(injectedScriptId){ " +
1051 "var extensionServer;" +
1052 defineCommonExtensionSymbols.toString() + ";" +
1053 injectedExtensionAPI.toString() + ";" +
1054 buildPlatformExtensionAPI(extensionInfo) + ";" +
1055 "platformExtensionAPI(injectedExtensionAPI(injectedScriptId));" +