summaryrefslogtreecommitdiffstats
path: root/WebCore/inspector/front-end/ExtensionAPI.js
diff options
context:
space:
mode:
Diffstat (limited to 'WebCore/inspector/front-end/ExtensionAPI.js')
-rw-r--r--WebCore/inspector/front-end/ExtensionAPI.js322
1 files changed, 322 insertions, 0 deletions
diff --git a/WebCore/inspector/front-end/ExtensionAPI.js b/WebCore/inspector/front-end/ExtensionAPI.js
new file mode 100644
index 0000000..476a463
--- /dev/null
+++ b/WebCore/inspector/front-end/ExtensionAPI.js
@@ -0,0 +1,322 @@
+/*
+ * Copyright (C) 2010 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.
+ */
+
+var injectedExtensionAPI = function(InjectedScriptHost, inspectedWindow, injectedScriptId)
+{
+
+// 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.
+
+function EventSinkImpl(type)
+{
+ this._type = type;
+ this._listeners = [];
+}
+
+EventSinkImpl.prototype = {
+ addListener: function(callback)
+ {
+ if (this._listeners.length === 0)
+ extensionServer.sendRequest({ command: "subscribe", type: this._type });
+ this._listeners.push(callback);
+ extensionServer.registerHandler("notify-" + this._type, bind(this._fire, 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: "unsubscribe", type: this._type });
+ },
+
+ _fire: function(request)
+ {
+ var listeners = this._listeners.slice();
+ for (var i = 0; i < listeners.length; ++i)
+ listeners[i].apply(null, request.arguments);
+ }
+}
+
+function EventSink(type)
+{
+ var impl = new EventSinkImpl(type);
+ this.addListener = bind(impl.addListener, impl);
+ this.removeListener = bind(impl.removeListener, impl);
+}
+
+function InspectorExtensionAPI()
+{
+ this.inspectedWindow = new InspectedWindow();
+ this.panels = new Panels();
+ this.resources = new Resources();
+ this.onReset = new EventSink("reset");
+}
+
+InspectorExtensionAPI.prototype = {
+ log: function(message)
+ {
+ extensionServer.sendRequest({ command: "log", message: message });
+ }
+}
+
+function Resources()
+{
+ this.onFinished = new EventSink("resource-finished");
+}
+
+Resources.prototype = {
+ getAll: function(callback)
+ {
+ return extensionServer.sendRequest({ command: "getResources" }, callback);
+ },
+
+ get: function(id, callback)
+ {
+ return extensionServer.sendRequest({ command: "getResources", id: id }, callback);
+ }
+}
+
+var wellKnownPanelNames = [
+ "elements",
+ "scripts"
+];
+
+function Panels()
+{
+ var panels = [];
+ function panelGetter(name)
+ {
+ return panels[name];
+ }
+
+ for (var i = 0; i < wellKnownPanelNames.length; ++i) {
+ var name = wellKnownPanelNames[i];
+ panels[name] = new Panel(name);
+ this.__defineGetter__(name, bind(panelGetter, null, name));
+ }
+}
+
+Panels.prototype = {
+ create: function(label, pageURL, iconURL, callback)
+ {
+ var id = "extension-panel-" + extensionServer.nextObjectId();
+ function callbackWrapper(result)
+ {
+ if (result.isError)
+ callback(result);
+ else {
+ panel = new ExtensionPanel(id);
+ callback(panel);
+ }
+ }
+ var request = {
+ command: "createPanel",
+ id: id,
+ label: label,
+ url: expandURL(pageURL),
+ icon: expandURL(iconURL)
+ };
+ extensionServer.sendRequest(request, callback && bind(callbackWrapper, this));
+ }
+}
+
+function PanelImpl(id)
+{
+ this._id = id;
+ this.onSelectionChanged = new EventSink("panel-objectSelected-" + id);
+}
+
+PanelImpl.prototype = {
+ createSidebarPane: function(title, url, callback)
+ {
+ var id = "extension-sidebar-" + extensionServer.nextObjectId();
+ function callbackWrapper(result)
+ {
+ if (result.isError)
+ callback(result);
+ else
+ callback(new ExtensionSidebarPane(id));
+ }
+ extensionServer.sendRequest({ command: "createSidebarPane", panel: this._id, id: id, title: title, url: expandURL(url) }, callback && callbackWrapper);
+ }
+}
+
+function Panel(id)
+{
+ var impl = new PanelImpl(id);
+ this.createSidebarPane = bind(impl.createSidebarPane, impl);
+}
+
+function ExtensionPanel(id)
+{
+ Panel.call(this, id);
+ this.onSearch = new EventSink("panel-search-" + id);
+}
+
+ExtensionPanel.prototype = {
+}
+
+ExtensionPanel.prototype.__proto__ = Panel.prototype;
+
+function ExtensionSidebarPaneImpl(id)
+{
+ this._id = id;
+}
+
+ExtensionSidebarPaneImpl.prototype = {
+ setHeight: function(height)
+ {
+ extensionServer.sendRequest({ command: "setSidebarHeight", id: this._id, height: height });
+ },
+
+ setExpanded: function(expanded)
+ {
+ extensionServer.sendRequest({ command: "setSidebarExpanded", id: this._id, expanded: expanded });
+ }
+}
+
+function ExtensionSidebarPane(id)
+{
+ var impl = new ExtensionSidebarPaneImpl(id);
+ this.setHeight = bind(impl.setHeight, impl);
+ this.setExpanded = bind(impl.setExpanded, impl);
+}
+
+function InspectedWindow()
+{
+ this.onLoaded = new EventSink("inspectedPageLoaded");
+ this.onNavigated = new EventSink("inspectedURLChanged");
+ this.onDOMContentLoaded = new EventSink("DOMContentLoaded");
+}
+
+InspectedWindow.prototype = {
+ reload: function()
+ {
+ return extensionServer.sendRequest({ command: "reload" });
+ },
+
+ evaluate: function(expression, callback)
+ {
+ return extensionServer.sendRequest({ command: "evaluateOnInspectedPage", expression: expression }, callback);
+ }
+}
+
+function ExtensionServerClient()
+{
+ this._callbacks = {};
+ this._handlers = {};
+ this._lastRequestId = 0;
+ this._lastObjectId = 0;
+
+ this.registerHandler("callback", bind(this._onCallback, this));
+
+ var channel = new MessageChannel();
+ this._port = channel.port1;
+ this._port.addEventListener("message", bind(this._onMessage, this), false);
+ this._port.start();
+
+ top.postMessage("registerExtension", [ channel.port2 ], "*");
+}
+
+ExtensionServerClient.prototype = {
+ sendRequest: function(message, callback)
+ {
+ if (typeof callback === "function")
+ message.requestId = this._registerCallback(callback);
+ return this._port.postMessage(message);
+ },
+
+ registerHandler: function(command, handler)
+ {
+ this._handlers[command] = handler;
+ },
+
+ nextObjectId: function()
+ {
+ return injectedScriptId + "_" + ++this._lastObjectId;
+ },
+
+ _registerCallback: function(callback)
+ {
+ var id = ++this._lastRequestId;
+ this._callbacks[id] = callback;
+ return id;
+ },
+
+ _onCallback: function(request)
+ {
+ if (request.requestId in this._callbacks) {
+ this._callbacks[request.requestId](request.result);
+ delete this._callbacks[request.requestId];
+ }
+ },
+
+ _onMessage: function(event)
+ {
+ var request = event.data;
+ var handler = this._handlers[request.command];
+ if (handler)
+ handler.call(this, request);
+ }
+}
+
+function expandURL(url)
+{
+ if (!url)
+ return url;
+ if (/^[^/]+:/.exec(url)) // See if url has schema.
+ return url;
+ var baseURL = location.protocol + "//" + location.hostname + location.port;
+ if (/^\//.exec(url))
+ return baseURL + url;
+ return baseURL + location.pathname.replace(/\/[^/]*$/,"/") + url;
+}
+
+function bind(func, thisObject)
+{
+ var args = Array.prototype.slice.call(arguments, 2);
+ return function() { return func.apply(thisObject, args.concat(Array.prototype.slice.call(arguments, 0))); };
+}
+
+var extensionServer = new ExtensionServerClient();
+
+webInspector = new InspectorExtensionAPI();
+
+}