Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / third_party / WebKit / Source / devtools / front_end / extensions / ExtensionAPI.js
blob9eb5179f1a4556952a491fe500344287bc9d3499
1 /*
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
6 * met:
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
13 * distribution.
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 = {
36 Info: "info",
37 Warning: "warning",
38 Severe: "severe"
41 if (!apiPrivate.panels)
42 apiPrivate.panels = {};
43 apiPrivate.panels.SearchAction = {
44 CancelSearch: "cancelSearch",
45 PerformSearch: "performSearch",
46 NextSearchResult: "nextSearchResult",
47 PreviousSearchResult: "previousSearchResult"
50 apiPrivate.Events = {
51 AuditStarted: "audit-started-",
52 ButtonClicked: "button-clicked-",
53 PanelObjectSelected: "panel-objectSelected-",
54 NetworkRequestFinished: "network-request-finished",
55 OpenResource: "open-resource",
56 PanelSearch: "panel-search-",
57 ResourceAdded: "resource-added",
58 ResourceContentCommitted: "resource-content-committed",
59 ViewShown: "view-shown-",
60 ViewHidden: "view-hidden-"
63 apiPrivate.Commands = {
64 AddAuditCategory: "addAuditCategory",
65 AddAuditResult: "addAuditResult",
66 AddRequestHeaders: "addRequestHeaders",
67 ApplyStyleSheet: "applyStyleSheet",
68 CreatePanel: "createPanel",
69 CreateSidebarPane: "createSidebarPane",
70 CreateToolbarButton: "createToolbarButton",
71 EvaluateOnInspectedPage: "evaluateOnInspectedPage",
72 ForwardKeyboardEvent: "_forwardKeyboardEvent",
73 GetHAR: "getHAR",
74 GetPageResources: "getPageResources",
75 GetRequestContent: "getRequestContent",
76 GetResourceContent: "getResourceContent",
77 InspectedURLChanged: "inspectedURLChanged",
78 OpenResource: "openResource",
79 Reload: "Reload",
80 Subscribe: "subscribe",
81 SetOpenResourceHandler: "setOpenResourceHandler",
82 SetResourceContent: "setResourceContent",
83 SetSidebarContent: "setSidebarContent",
84 SetSidebarHeight: "setSidebarHeight",
85 SetSidebarPage: "setSidebarPage",
86 ShowPanel: "showPanel",
87 StopAuditCategoryRun: "stopAuditCategoryRun",
88 Unsubscribe: "unsubscribe",
89 UpdateAuditProgress: "updateAuditProgress",
90 UpdateButton: "updateButton"
94 /**
95 * @param {number} injectedScriptId
96 * @return {!Object}
97 * @suppressGlobalPropertiesCheck
99 function injectedExtensionAPI(injectedScriptId)
102 var apiPrivate = {};
104 defineCommonExtensionSymbols(apiPrivate);
106 var commands = apiPrivate.Commands;
107 var events = apiPrivate.Events;
108 var userAction = false;
110 // Here and below, all constructors are private to API implementation.
111 // For a public type Foo, if internal fields are present, these are on
112 // a private FooImpl type, an instance of FooImpl is used in a closure
113 // by Foo consutrctor to re-bind publicly exported members to an instance
114 // of Foo.
117 * @constructor
119 function EventSinkImpl(type, customDispatch)
121 this._type = type;
122 this._listeners = [];
123 this._customDispatch = customDispatch;
126 EventSinkImpl.prototype = {
127 addListener: function(callback)
129 if (typeof callback !== "function")
130 throw "addListener: callback is not a function";
131 if (this._listeners.length === 0)
132 extensionServer.sendRequest({ command: commands.Subscribe, type: this._type });
133 this._listeners.push(callback);
134 extensionServer.registerHandler("notify-" + this._type, this._dispatch.bind(this));
137 removeListener: function(callback)
139 var listeners = this._listeners;
141 for (var i = 0; i < listeners.length; ++i) {
142 if (listeners[i] === callback) {
143 listeners.splice(i, 1);
144 break;
147 if (this._listeners.length === 0)
148 extensionServer.sendRequest({ command: commands.Unsubscribe, type: this._type });
152 * @param {...} vararg
154 _fire: function(vararg)
156 var listeners = this._listeners.slice();
157 for (var i = 0; i < listeners.length; ++i)
158 listeners[i].apply(null, arguments);
161 _dispatch: function(request)
163 if (this._customDispatch)
164 this._customDispatch.call(this, request);
165 else
166 this._fire.apply(this, request.arguments);
171 * @constructor
173 function InspectorExtensionAPI()
175 this.audits = new Audits();
176 this.inspectedWindow = new InspectedWindow();
177 this.panels = new Panels();
178 this.network = new Network();
179 defineDeprecatedProperty(this, "webInspector", "resources", "network");
183 * @constructor
185 function Network()
188 * @this {EventSinkImpl}
190 function dispatchRequestEvent(message)
192 var request = message.arguments[1];
193 request.__proto__ = new Request(message.arguments[0]);
194 this._fire(request);
196 this.onRequestFinished = new EventSink(events.NetworkRequestFinished, dispatchRequestEvent);
197 defineDeprecatedProperty(this, "network", "onFinished", "onRequestFinished");
198 this.onNavigated = new EventSink(events.InspectedURLChanged);
201 Network.prototype = {
202 getHAR: function(callback)
204 function callbackWrapper(result)
206 var entries = (result && result.entries) || [];
207 for (var i = 0; i < entries.length; ++i) {
208 entries[i].__proto__ = new Request(entries[i]._requestId);
209 delete entries[i]._requestId;
211 callback(result);
213 extensionServer.sendRequest({ command: commands.GetHAR }, callback && callbackWrapper);
216 addRequestHeaders: function(headers)
218 extensionServer.sendRequest({ command: commands.AddRequestHeaders, headers: headers, extensionId: window.location.hostname });
223 * @constructor
225 function RequestImpl(id)
227 this._id = id;
230 RequestImpl.prototype = {
231 getContent: function(callback)
233 function callbackWrapper(response)
235 callback(response.content, response.encoding);
237 extensionServer.sendRequest({ command: commands.GetRequestContent, id: this._id }, callback && callbackWrapper);
242 * @constructor
244 function Panels()
246 var panels = {
247 elements: new ElementsPanel(),
248 sources: new SourcesPanel(),
251 function panelGetter(name)
253 return panels[name];
255 for (var panel in panels)
256 this.__defineGetter__(panel, panelGetter.bind(null, panel));
257 this.applyStyleSheet = function(styleSheet) { extensionServer.sendRequest({ command: commands.ApplyStyleSheet, styleSheet: styleSheet }); };
260 Panels.prototype = {
261 create: function(title, icon, page, callback)
263 var id = "extension-panel-" + extensionServer.nextObjectId();
264 var request = {
265 command: commands.CreatePanel,
266 id: id,
267 title: title,
268 icon: icon,
269 page: page
271 extensionServer.sendRequest(request, callback && callback.bind(this, new ExtensionPanel(id)));
274 setOpenResourceHandler: function(callback)
276 var hadHandler = extensionServer.hasHandler(events.OpenResource);
278 function callbackWrapper(message)
280 // Allow the panel to show itself when handling the event.
281 userAction = true;
282 try {
283 callback.call(null, new Resource(message.resource), message.lineNumber);
284 } finally {
285 userAction = false;
289 if (!callback)
290 extensionServer.unregisterHandler(events.OpenResource);
291 else
292 extensionServer.registerHandler(events.OpenResource, callbackWrapper);
294 // Only send command if we either removed an existing handler or added handler and had none before.
295 if (hadHandler === !callback)
296 extensionServer.sendRequest({ command: commands.SetOpenResourceHandler, "handlerPresent": !!callback });
299 openResource: function(url, lineNumber, callback)
301 extensionServer.sendRequest({ command: commands.OpenResource, "url": url, "lineNumber": lineNumber }, callback);
304 get SearchAction()
306 return apiPrivate.panels.SearchAction;
311 * @constructor
313 function ExtensionViewImpl(id)
315 this._id = id;
318 * @this {EventSinkImpl}
320 function dispatchShowEvent(message)
322 var frameIndex = message.arguments[0];
323 if (typeof frameIndex === "number")
324 this._fire(window.parent.frames[frameIndex]);
325 else
326 this._fire();
329 if (id) {
330 this.onShown = new EventSink(events.ViewShown + id, dispatchShowEvent);
331 this.onHidden = new EventSink(events.ViewHidden + id);
336 * @constructor
337 * @extends {ExtensionViewImpl}
338 * @param {string} hostPanelName
340 function PanelWithSidebarImpl(hostPanelName)
342 ExtensionViewImpl.call(this, null);
343 this._hostPanelName = hostPanelName;
344 this.onSelectionChanged = new EventSink(events.PanelObjectSelected + hostPanelName);
347 PanelWithSidebarImpl.prototype = {
348 createSidebarPane: function(title, callback)
350 var id = "extension-sidebar-" + extensionServer.nextObjectId();
351 var request = {
352 command: commands.CreateSidebarPane,
353 panel: this._hostPanelName,
354 id: id,
355 title: title
357 function callbackWrapper()
359 callback(new ExtensionSidebarPane(id));
361 extensionServer.sendRequest(request, callback && callbackWrapper);
364 __proto__: ExtensionViewImpl.prototype
367 function declareInterfaceClass(implConstructor)
369 return function()
371 var impl = { __proto__: implConstructor.prototype };
372 implConstructor.apply(impl, arguments);
373 populateInterfaceClass(this, impl);
377 function defineDeprecatedProperty(object, className, oldName, newName)
379 var warningGiven = false;
380 function getter()
382 if (!warningGiven) {
383 console.warn(className + "." + oldName + " is deprecated. Use " + className + "." + newName + " instead");
384 warningGiven = true;
386 return object[newName];
388 object.__defineGetter__(oldName, getter);
391 function extractCallbackArgument(args)
393 var lastArgument = args[args.length - 1];
394 return typeof lastArgument === "function" ? lastArgument : undefined;
397 var AuditCategory = declareInterfaceClass(AuditCategoryImpl);
398 var AuditResult = declareInterfaceClass(AuditResultImpl);
399 var Button = declareInterfaceClass(ButtonImpl);
400 var EventSink = declareInterfaceClass(EventSinkImpl);
401 var ExtensionPanel = declareInterfaceClass(ExtensionPanelImpl);
402 var ExtensionSidebarPane = declareInterfaceClass(ExtensionSidebarPaneImpl);
403 var PanelWithSidebar = declareInterfaceClass(PanelWithSidebarImpl);
404 var Request = declareInterfaceClass(RequestImpl);
405 var Resource = declareInterfaceClass(ResourceImpl);
408 * @constructor
409 * @extends {PanelWithSidebar}
411 function ElementsPanel()
413 PanelWithSidebar.call(this, "elements");
416 ElementsPanel.prototype = {
417 __proto__: PanelWithSidebar.prototype
421 * @constructor
422 * @extends {PanelWithSidebar}
424 function SourcesPanel()
426 PanelWithSidebar.call(this, "sources");
429 SourcesPanel.prototype = {
430 __proto__: PanelWithSidebar.prototype
434 * @constructor
435 * @extends {ExtensionViewImpl}
437 function ExtensionPanelImpl(id)
439 ExtensionViewImpl.call(this, id);
440 this.onSearch = new EventSink(events.PanelSearch + id);
443 ExtensionPanelImpl.prototype = {
445 * @return {!Object}
447 createStatusBarButton: function(iconPath, tooltipText, disabled)
449 var id = "button-" + extensionServer.nextObjectId();
450 var request = {
451 command: commands.CreateToolbarButton,
452 panel: this._id,
453 id: id,
454 icon: iconPath,
455 tooltip: tooltipText,
456 disabled: !!disabled
458 extensionServer.sendRequest(request);
459 return new Button(id);
462 show: function()
464 if (!userAction)
465 return;
467 var request = {
468 command: commands.ShowPanel,
469 id: this._id
471 extensionServer.sendRequest(request);
474 __proto__: ExtensionViewImpl.prototype
478 * @constructor
479 * @extends {ExtensionViewImpl}
481 function ExtensionSidebarPaneImpl(id)
483 ExtensionViewImpl.call(this, id);
486 ExtensionSidebarPaneImpl.prototype = {
487 setHeight: function(height)
489 extensionServer.sendRequest({ command: commands.SetSidebarHeight, id: this._id, height: height });
492 setExpression: function(expression, rootTitle, evaluateOptions)
494 var request = {
495 command: commands.SetSidebarContent,
496 id: this._id,
497 expression: expression,
498 rootTitle: rootTitle,
499 evaluateOnPage: true,
501 if (typeof evaluateOptions === "object")
502 request.evaluateOptions = evaluateOptions;
503 extensionServer.sendRequest(request, extractCallbackArgument(arguments));
506 setObject: function(jsonObject, rootTitle, callback)
508 extensionServer.sendRequest({ command: commands.SetSidebarContent, id: this._id, expression: jsonObject, rootTitle: rootTitle }, callback);
511 setPage: function(page)
513 extensionServer.sendRequest({ command: commands.SetSidebarPage, id: this._id, page: page });
516 __proto__: ExtensionViewImpl.prototype
520 * @constructor
522 function ButtonImpl(id)
524 this._id = id;
525 this.onClicked = new EventSink(events.ButtonClicked + id);
528 ButtonImpl.prototype = {
529 update: function(iconPath, tooltipText, disabled)
531 var request = {
532 command: commands.UpdateButton,
533 id: this._id,
534 icon: iconPath,
535 tooltip: tooltipText,
536 disabled: !!disabled
538 extensionServer.sendRequest(request);
543 * @constructor
545 function Audits()
549 Audits.prototype = {
551 * @return {!AuditCategory}
553 addCategory: function(displayName, resultCount)
555 var id = "extension-audit-category-" + extensionServer.nextObjectId();
556 if (typeof resultCount !== "undefined")
557 console.warn("Passing resultCount to audits.addCategory() is deprecated. Use AuditResult.updateProgress() instead.");
558 extensionServer.sendRequest({ command: commands.AddAuditCategory, id: id, displayName: displayName, resultCount: resultCount });
559 return new AuditCategory(id);
564 * @constructor
566 function AuditCategoryImpl(id)
569 * @this {EventSinkImpl}
571 function dispatchAuditEvent(request)
573 var auditResult = new AuditResult(request.arguments[0]);
574 try {
575 this._fire(auditResult);
576 } catch (e) {
577 console.error("Uncaught exception in extension audit event handler: " + e);
578 auditResult.done();
581 this._id = id;
582 this.onAuditStarted = new EventSink(events.AuditStarted + id, dispatchAuditEvent);
586 * @constructor
588 function AuditResultImpl(id)
590 this._id = id;
592 this.createURL = this._nodeFactory.bind(this, "url");
593 this.createSnippet = this._nodeFactory.bind(this, "snippet");
594 this.createText = this._nodeFactory.bind(this, "text");
595 this.createObject = this._nodeFactory.bind(this, "object");
596 this.createNode = this._nodeFactory.bind(this, "node");
599 AuditResultImpl.prototype = {
600 addResult: function(displayName, description, severity, details)
602 // shorthand for specifying details directly in addResult().
603 if (details && !(details instanceof AuditResultNode))
604 details = new AuditResultNode(Array.isArray(details) ? details : [details]);
606 var request = {
607 command: commands.AddAuditResult,
608 resultId: this._id,
609 displayName: displayName,
610 description: description,
611 severity: severity,
612 details: details
614 extensionServer.sendRequest(request);
618 * @return {!Object}
620 createResult: function()
622 return new AuditResultNode(Array.prototype.slice.call(arguments));
625 updateProgress: function(worked, totalWork)
627 extensionServer.sendRequest({ command: commands.UpdateAuditProgress, resultId: this._id, progress: worked / totalWork });
630 done: function()
632 extensionServer.sendRequest({ command: commands.StopAuditCategoryRun, resultId: this._id });
636 * @type {!Object.<string, string>}
638 get Severity()
640 return apiPrivate.audits.Severity;
644 * @return {!{type: string, arguments: !Array.<string|number>}}
646 createResourceLink: function(url, lineNumber)
648 return {
649 type: "resourceLink",
650 arguments: [url, lineNumber && lineNumber - 1]
655 * @return {!{type: string, arguments: !Array.<string|number>}}
657 _nodeFactory: function(type)
659 return {
660 type: type,
661 arguments: Array.prototype.slice.call(arguments, 1)
667 * @constructor
669 function AuditResultNode(contents)
671 this.contents = contents;
672 this.children = [];
673 this.expanded = false;
676 AuditResultNode.prototype = {
678 * @return {!Object}
680 addChild: function()
682 var node = new AuditResultNode(Array.prototype.slice.call(arguments));
683 this.children.push(node);
684 return node;
689 * @constructor
691 function InspectedWindow()
694 * @this {EventSinkImpl}
696 function dispatchResourceEvent(message)
698 this._fire(new Resource(message.arguments[0]));
702 * @this {EventSinkImpl}
704 function dispatchResourceContentEvent(message)
706 this._fire(new Resource(message.arguments[0]), message.arguments[1]);
709 this.onResourceAdded = new EventSink(events.ResourceAdded, dispatchResourceEvent);
710 this.onResourceContentCommitted = new EventSink(events.ResourceContentCommitted, dispatchResourceContentEvent);
713 InspectedWindow.prototype = {
714 reload: function(optionsOrUserAgent)
716 var options = null;
717 if (typeof optionsOrUserAgent === "object") {
718 options = optionsOrUserAgent;
719 } else if (typeof optionsOrUserAgent === "string") {
720 options = { userAgent: optionsOrUserAgent };
721 console.warn("Passing userAgent as string parameter to inspectedWindow.reload() is deprecated. " +
722 "Use inspectedWindow.reload({ userAgent: value}) instead.");
724 extensionServer.sendRequest({ command: commands.Reload, options: options });
728 * @return {?Object}
730 eval: function(expression, evaluateOptions)
732 var callback = extractCallbackArgument(arguments);
733 function callbackWrapper(result)
735 if (result.isError || result.isException)
736 callback(undefined, result);
737 else
738 callback(result.value);
740 var request = {
741 command: commands.EvaluateOnInspectedPage,
742 expression: expression
744 if (typeof evaluateOptions === "object")
745 request.evaluateOptions = evaluateOptions;
746 extensionServer.sendRequest(request, callback && callbackWrapper);
747 return null;
750 getResources: function(callback)
752 function wrapResource(resourceData)
754 return new Resource(resourceData);
756 function callbackWrapper(resources)
758 callback(resources.map(wrapResource));
760 extensionServer.sendRequest({ command: commands.GetPageResources }, callback && callbackWrapper);
765 * @constructor
767 function ResourceImpl(resourceData)
769 this._url = resourceData.url;
770 this._type = resourceData.type;
773 ResourceImpl.prototype = {
774 get url()
776 return this._url;
779 get type()
781 return this._type;
784 getContent: function(callback)
786 function callbackWrapper(response)
788 callback(response.content, response.encoding);
791 extensionServer.sendRequest({ command: commands.GetResourceContent, url: this._url }, callback && callbackWrapper);
794 setContent: function(content, commit, callback)
796 extensionServer.sendRequest({ command: commands.SetResourceContent, url: this._url, content: content, commit: commit }, callback);
800 var keyboardEventRequestQueue = [];
801 var forwardTimer = null;
803 function forwardKeyboardEvent(event)
805 const Esc = "U+001B";
806 // We only care about global hotkeys, not about random text
807 if (!event.ctrlKey && !event.altKey && !event.metaKey && !/^F\d+$/.test(event.keyIdentifier) && event.keyIdentifier !== Esc)
808 return;
809 var requestPayload = {
810 eventType: event.type,
811 ctrlKey: event.ctrlKey,
812 altKey: event.altKey,
813 metaKey: event.metaKey,
814 keyIdentifier: event.keyIdentifier,
815 location: event.location,
816 keyCode: event.keyCode
818 keyboardEventRequestQueue.push(requestPayload);
819 if (!forwardTimer)
820 forwardTimer = setTimeout(forwardEventQueue, 0);
823 function forwardEventQueue()
825 forwardTimer = null;
826 var request = {
827 command: commands.ForwardKeyboardEvent,
828 entries: keyboardEventRequestQueue
830 extensionServer.sendRequest(request);
831 keyboardEventRequestQueue = [];
834 document.addEventListener("keydown", forwardKeyboardEvent, false);
835 document.addEventListener("keypress", forwardKeyboardEvent, false);
838 * @constructor
840 function ExtensionServerClient()
842 this._callbacks = {};
843 this._handlers = {};
844 this._lastRequestId = 0;
845 this._lastObjectId = 0;
847 this.registerHandler("callback", this._onCallback.bind(this));
849 var channel = new MessageChannel();
850 this._port = channel.port1;
851 this._port.addEventListener("message", this._onMessage.bind(this), false);
852 this._port.start();
854 window.parent.postMessage("registerExtension", [ channel.port2 ], "*");
857 ExtensionServerClient.prototype = {
859 * @param {!Object} message
860 * @param {function()=} callback
862 sendRequest: function(message, callback)
864 if (typeof callback === "function")
865 message.requestId = this._registerCallback(callback);
866 this._port.postMessage(message);
870 * @return {boolean}
872 hasHandler: function(command)
874 return !!this._handlers[command];
877 registerHandler: function(command, handler)
879 this._handlers[command] = handler;
882 unregisterHandler: function(command)
884 delete this._handlers[command];
888 * @return {string}
890 nextObjectId: function()
892 return injectedScriptId.toString() + "_" + ++this._lastObjectId;
895 _registerCallback: function(callback)
897 var id = ++this._lastRequestId;
898 this._callbacks[id] = callback;
899 return id;
902 _onCallback: function(request)
904 if (request.requestId in this._callbacks) {
905 var callback = this._callbacks[request.requestId];
906 delete this._callbacks[request.requestId];
907 callback(request.result);
911 _onMessage: function(event)
913 var request = event.data;
914 var handler = this._handlers[request.command];
915 if (handler)
916 handler.call(this, request);
920 function populateInterfaceClass(interfaze, implementation)
922 for (var member in implementation) {
923 if (member.charAt(0) === "_")
924 continue;
925 var descriptor = null;
926 // Traverse prototype chain until we find the owner.
927 for (var owner = implementation; owner && !descriptor; owner = owner.__proto__)
928 descriptor = Object.getOwnPropertyDescriptor(owner, member);
929 if (!descriptor)
930 continue;
931 if (typeof descriptor.value === "function")
932 interfaze[member] = descriptor.value.bind(implementation);
933 else if (typeof descriptor.get === "function")
934 interfaze.__defineGetter__(member, descriptor.get.bind(implementation));
935 else
936 Object.defineProperty(interfaze, member, descriptor);
940 // extensionServer is a closure variable defined by the glue below -- make sure we fail if it's not there.
941 if (!extensionServer)
942 extensionServer = new ExtensionServerClient();
944 return new InspectorExtensionAPI();
948 * @suppress {checkVars, checkTypes}
950 function platformExtensionAPI(coreAPI)
952 function getTabId()
954 return tabId;
956 chrome = window.chrome || {};
957 // Override chrome.devtools as a workaround for a error-throwing getter being exposed
958 // in extension pages loaded into a non-extension process (only happens for remote client
959 // extensions)
960 var devtools_descriptor = Object.getOwnPropertyDescriptor(chrome, "devtools");
961 if (!devtools_descriptor || devtools_descriptor.get)
962 Object.defineProperty(chrome, "devtools", { value: {}, enumerable: true });
963 // Only expose tabId on chrome.devtools.inspectedWindow, not webInspector.inspectedWindow.
964 chrome.devtools.inspectedWindow = {};
965 chrome.devtools.inspectedWindow.__defineGetter__("tabId", getTabId);
966 chrome.devtools.inspectedWindow.__proto__ = coreAPI.inspectedWindow;
967 chrome.devtools.network = coreAPI.network;
968 chrome.devtools.panels = coreAPI.panels;
970 // default to expose experimental APIs for now.
971 if (extensionInfo.exposeExperimentalAPIs !== false) {
972 chrome.experimental = chrome.experimental || {};
973 chrome.experimental.devtools = chrome.experimental.devtools || {};
975 var properties = Object.getOwnPropertyNames(coreAPI);
976 for (var i = 0; i < properties.length; ++i) {
977 var descriptor = Object.getOwnPropertyDescriptor(coreAPI, properties[i]);
978 Object.defineProperty(chrome.experimental.devtools, properties[i], descriptor);
980 chrome.experimental.devtools.inspectedWindow = chrome.devtools.inspectedWindow;
982 if (extensionInfo.exposeWebInspectorNamespace)
983 window.webInspector = coreAPI;
987 * @param {!ExtensionDescriptor} extensionInfo
988 * @param {string} inspectedTabId
989 * @return {string}
991 function buildPlatformExtensionAPI(extensionInfo, inspectedTabId)
993 return "var extensionInfo = " + JSON.stringify(extensionInfo) + ";" +
994 "var tabId = " + inspectedTabId + ";" +
995 platformExtensionAPI.toString();
999 * @param {!ExtensionDescriptor} extensionInfo
1000 * @param {string} inspectedTabId
1001 * @return {string}
1003 function buildExtensionAPIInjectedScript(extensionInfo, inspectedTabId)
1005 return "(function(injectedScriptId){ " +
1006 "var extensionServer;" +
1007 defineCommonExtensionSymbols.toString() + ";" +
1008 injectedExtensionAPI.toString() + ";" +
1009 buildPlatformExtensionAPI(extensionInfo, inspectedTabId) + ";" +
1010 "platformExtensionAPI(injectedExtensionAPI(injectedScriptId));" +
1011 "return {};" +
1012 "})";