Merge branch 'issue/8' into develop
diff --git a/weinre.server/interfaces/WeinreClientCommands.idl b/weinre.server/interfaces/WeinreClientCommands.idl
index 35d5a74..b912cdf 100644
--- a/weinre.server/interfaces/WeinreClientCommands.idl
+++ b/weinre.server/interfaces/WeinreClientCommands.idl
@@ -18,6 +18,8 @@
void connectTarget(in string clientId, in string targetId);
void disconnectTarget(in string clientId);
+ void getExtensions(out string[] extensions)
+
void logDebug( in string message );
void logInfo( in string message );
void logWarning( in string message );
diff --git a/weinre.server/src/weinre/server/ExtensionManager.java b/weinre.server/src/weinre/server/ExtensionManager.java
new file mode 100644
index 0000000..f050904
--- /dev/null
+++ b/weinre.server/src/weinre/server/ExtensionManager.java
@@ -0,0 +1,91 @@
+/*
+ * weinre is available under *either* the terms of the modified BSD license *or* the
+ * MIT License (2008). See http://opensource.org/licenses/alphabetical for full text.
+ *
+ * Copyright (c) 2011 IBM Corporation
+ */
+
+package weinre.server;
+
+import java.io.File;
+import java.io.IOException;
+import java.net.MalformedURLException;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.jetty.util.resource.Resource;
+
+//-------------------------------------------------------------------
+public class ExtensionManager {
+ static private File weinreHomeDir = null;
+ static private File weinreExtDir = null;
+ static private long weinreExtDate = 0L;
+ static private String[] extensions = null;
+
+ static private String[] EMPTY_STRING_ARRAY = {};
+
+ //---------------------------------------------------------------
+ static {
+ initExtensions();
+ }
+
+ //---------------------------------------------------------------
+ static public String[] getExtensions() {
+ if (weinreExtDate != weinreExtDir.lastModified()) {
+ initExtensions();
+ }
+
+ return extensions;
+ }
+
+ //---------------------------------------------------------------
+ // path: /client/extensions/weinre-ext-sample/extension.html
+ static public Resource getResource(String path) throws MalformedURLException {
+ File resourceFile = new File(weinreExtDir, path.substring(18));
+ if (!resourceFile.exists()) return null;
+
+ try {
+ return Resource.newResource(resourceFile.toURI().toURL().toExternalForm(), false);
+ }
+ catch (IOException e) {
+ throw new MalformedURLException();
+ }
+ }
+
+ //---------------------------------------------------------------
+ static private void initExtensions() {
+
+ weinreHomeDir = new File(System.getProperty("user.home"), ".weinre");
+ if (!weinreHomeDir.isDirectory()) {
+ Main.info("extensions not enabled: ~/.weinre is not a directory");
+ return;
+ }
+
+ weinreExtDir = new File(weinreHomeDir, "extensions");
+ weinreExtDate = weinreExtDir.lastModified();
+ if (!weinreExtDir.isDirectory()) {
+ Main.info("extensions not enabled: ~/.weinre/extensions is not a directory");
+ return;
+ }
+
+ extensions = EMPTY_STRING_ARRAY;
+
+ List<String> extensionList = new ArrayList<String>();
+
+ String[] entries = weinreExtDir.list();
+ for (String entry: entries) {
+ if (entry.startsWith(".")) continue;
+
+ File extDir = new File(weinreExtDir, entry);
+ if (!extDir.isDirectory()) continue;
+
+ File extensionHtml = new File(extDir, "extension.html");
+ if (!extensionHtml.isFile()) continue;
+
+ extensionList.add(entry);
+ }
+
+ extensions = extensionList.toArray(EMPTY_STRING_ARRAY);
+ }
+
+}
diff --git a/weinre.server/src/weinre/server/http/ClassPathResourceHandler.java b/weinre.server/src/weinre/server/http/ClassPathResourceHandler.java
index 13b0072..f6eccda 100644
--- a/weinre.server/src/weinre/server/http/ClassPathResourceHandler.java
+++ b/weinre.server/src/weinre/server/http/ClassPathResourceHandler.java
@@ -14,6 +14,8 @@
import org.eclipse.jetty.server.handler.ResourceHandler;
import org.eclipse.jetty.util.resource.Resource;
+import weinre.server.ExtensionManager;
+
//-------------------------------------------------------------------
public class ClassPathResourceHandler extends ResourceHandler {
@@ -32,6 +34,11 @@
throw new MalformedURLException(path);
}
+ // handle extensions
+ if (path.startsWith("/client/extensions/")) {
+ return ExtensionManager.getResource(path);
+ }
+
path = pathPrefix + path;
URL url = getClass().getClassLoader().getResource(path);
if (url != null)
diff --git a/weinre.server/src/weinre/server/service/WeinreClientCommands.java b/weinre.server/src/weinre/server/service/WeinreClientCommands.java
index 76d08fa..7dcf1a8 100644
--- a/weinre.server/src/weinre/server/service/WeinreClientCommands.java
+++ b/weinre.server/src/weinre/server/service/WeinreClientCommands.java
@@ -17,6 +17,7 @@
import weinre.server.Channel;
import weinre.server.Client;
import weinre.server.ConnectionManager;
+import weinre.server.ExtensionManager;
import weinre.server.Main;
import weinre.server.Target;
@@ -58,6 +59,26 @@
}
//---------------------------------------------------------------
+ public void getExtensions(Channel channel, String callbackId) throws IOException {
+ String[] extensions = ExtensionManager.getExtensions();
+ JSONArray result = new JSONArray();
+
+ try {
+ for (String extension: extensions) {
+ JSONObject extensionObject = new JSONObject();
+ extensionObject.put("startPage", "extensions/" + extension + "/extension.html");
+
+ result.add(extensionObject);
+ }
+ }
+ catch(JSONException e) {
+ throw new RuntimeException(e);
+ }
+
+ channel.sendCallback("WeinreClientEvents", callbackId, result);
+ }
+
+ //---------------------------------------------------------------
public void connectTarget(Channel channel, String clientId, String targetId, String callbackId) {
Client client = ConnectionManager.$.getClient(clientId);
if (client == null) return;
diff --git a/weinre.server/src/weinre/server/service/WeinreTargetCommands.java b/weinre.server/src/weinre/server/service/WeinreTargetCommands.java
index 2b3a12f..80e9a22 100644
--- a/weinre.server/src/weinre/server/service/WeinreTargetCommands.java
+++ b/weinre.server/src/weinre/server/service/WeinreTargetCommands.java
@@ -10,7 +10,6 @@
import java.io.IOException;
import java.util.List;
-import org.apache.wink.json4j.JSONException;
import org.apache.wink.json4j.JSONObject;
import weinre.server.Channel;
diff --git a/weinre.web/client/ExtensionRegistryStub.js b/weinre.web/client/ExtensionRegistryStub.js
new file mode 100644
index 0000000..8e30a7e
--- /dev/null
+++ b/weinre.web/client/ExtensionRegistryStub.js
@@ -0,0 +1,11 @@
+/*
+ * weinre is available under *either* the terms of the modified BSD license *or* the
+ * MIT License (2008). See http://opensource.org/licenses/alphabetical for full text.
+ *
+ * Copyright (c) 2011 IBM Corporation
+ */
+
+(function() {
+ var ExtensionRegistryImpl = require("weinre/client/ExtensionRegistryImpl").getClass()
+ window.InspectorExtensionRegistry = new ExtensionRegistryImpl()
+})()
diff --git a/weinre.web/client/web-inspector-API.js b/weinre.web/client/web-inspector-API.js
new file mode 100644
index 0000000..e7fd7b0
--- /dev/null
+++ b/weinre.web/client/web-inspector-API.js
@@ -0,0 +1,8 @@
+/*
+ * weinre is available under *either* the terms of the modified BSD license *or* the
+ * MIT License (2008). See http://opensource.org/licenses/alphabetical for full text.
+ *
+ * Copyright (c) 2011 IBM Corporation
+ */
+
+eval(window.top.installWebInspectorAPIsource())
diff --git a/weinre.web/modules/weinre/client/Client.scoop b/weinre.web/modules/weinre/client/Client.scoop
index 584d0d3..f1368d8 100644
--- a/weinre.web/modules/weinre/client/Client.scoop
+++ b/weinre.web/modules/weinre/client/Client.scoop
@@ -13,6 +13,7 @@
requireClass ../common/Weinre
requireClass ../common/MessageDispatcher
requireClass ../common/Binding
+requireClass ../common/IDGenerator
requireClass ./InspectorBackendImpl
requireClass ./InspectorFrontendHostImpl
@@ -80,6 +81,7 @@
var toolbar = document.getElementById("toolbar")
WebInspector.addPanelToolbarIcon(toolbar, panel, toolbar.childNodes[1])
+ WebInspector.panelOrder.unshift(WebInspector.panelOrder.pop())
WebInspector.currentPanel = panel
@@ -129,6 +131,27 @@
}, 1000)
//-----------------------------------------------------------------------------
+function installWebInspectorAPIsource
+
+ if ("webInspector" in window) return
+
+ var extensionAPI = window.parent.InspectorFrontendHost.getExtensionAPI()
+ extensionAPI = extensionAPI.replace("location.hostname + location.port", "location.hostname + ':' + location.port")
+
+ // parms are: InjectedScriptHost, inspectedWindow, injectedScriptId
+ // InjectedScriptHost is not directly referenced
+ // inspectedWindow is not directly referenced
+ // injectedScriptId is used to scope object references, appears that
+ // each extension should have a unique value for this
+
+ var id = IDGenerator.next()
+ console.log("installing webInspector with injectedScriptId: " + id)
+ extensionAPI += "(null,null," + id + ")"
+ return extensionAPI
+
+//-----------------------------------------------------------------------------
static method main
Weinre.client = new Client()
Weinre.client.initialize()
+
+ window.installWebInspectorAPIsource = installWebInspectorAPIsource
\ No newline at end of file
diff --git a/weinre.web/modules/weinre/client/ConnectorList.scoop b/weinre.web/modules/weinre/client/ConnectorList.scoop
index bb0746d..b2ad6a5 100644
--- a/weinre.web/modules/weinre/client/ConnectorList.scoop
+++ b/weinre.web/modules/weinre/client/ConnectorList.scoop
@@ -44,6 +44,10 @@
}
//-----------------------------------------------------------------------------
+method get(channel)
+ return this.connectors[channel]
+
+//-----------------------------------------------------------------------------
method getNewestConnectorChannel(ignoring)
var newest = 0
diff --git a/weinre.web/modules/weinre/client/ExtensionRegistryImpl.scoop b/weinre.web/modules/weinre/client/ExtensionRegistryImpl.scoop
new file mode 100644
index 0000000..bee7c42
--- /dev/null
+++ b/weinre.web/modules/weinre/client/ExtensionRegistryImpl.scoop
@@ -0,0 +1,35 @@
+
+/*
+ * weinre is available under *either* the terms of the modified BSD license *or* the
+ * MIT License (2008). See http://opensource.org/licenses/alphabetical for full text.
+ *
+ * Copyright (c) 2011 IBM Corporation
+ */
+
+requireClass ../common/Ex
+requireClass ../common/Binding
+requireClass ../common/Weinre
+
+//-----------------------------------------------------------------------------
+class ExtensionRegistryImpl
+
+//-----------------------------------------------------------------------------
+init
+ var extensions = []
+
+//-----------------------------------------------------------------------------
+method getExtensionsAsync
+ if (extensions.length) return
+
+ Weinre.WeinreClientCommands.getExtensions(Binding(this, this._cb_getExtensions))
+
+//-----------------------------------------------------------------------------
+method _cb_getExtensions(extensionsResult)
+ extensions = extensionsResult
+ this._installExtensions()
+
+//-----------------------------------------------------------------------------
+method _installExtensions
+ WebInspector.addExtensions(extensions)
+
+
\ No newline at end of file
diff --git a/weinre.web/modules/weinre/client/InspectorFrontendHostImpl.scoop b/weinre.web/modules/weinre/client/InspectorFrontendHostImpl.scoop
index bb5093e..cbdb6c1 100644
--- a/weinre.web/modules/weinre/client/InspectorFrontendHostImpl.scoop
+++ b/weinre.web/modules/weinre/client/InspectorFrontendHostImpl.scoop
@@ -15,6 +15,10 @@
this._getPlatformAndPort()
//-----------------------------------------------------------------------------
+init
+ var _extensionAPI
+
+//-----------------------------------------------------------------------------
method loaded
//-----------------------------------------------------------------------------
@@ -44,6 +48,17 @@
Weinre.logInfo(arguments.callee.signature + "(" + JSON.stringify(object,null,4) + ")")
//-----------------------------------------------------------------------------
+method setExtensionAPI(extensionAPI)
+ _extensionAPI = extensionAPI
+
+//-----------------------------------------------------------------------------
+method getExtensionAPI
+ return _extensionAPI
+
+//-----------------------------------------------------------------------------
+method inspectedURLChanged
+
+//-----------------------------------------------------------------------------
method _getPlatformAndPort
this._platform = "weinre"
this._platformFlavor = "weinre"
diff --git a/weinre.web/modules/weinre/client/RemotePanel.scoop b/weinre.web/modules/weinre/client/RemotePanel.scoop
index 5e0ec93..fe7c5b8 100644
--- a/weinre.web/modules/weinre/client/RemotePanel.scoop
+++ b/weinre.web/modules/weinre/client/RemotePanel.scoop
@@ -64,6 +64,9 @@
method addTarget(target)
this.targetList.add(target)
+method getTarget(channel)
+ return this.targetList.get(channel)
+
method removeClient(channel)
this.clientList.remove(channel)
diff --git a/weinre.web/modules/weinre/client/WeinreClientEventsImpl.scoop b/weinre.web/modules/weinre/client/WeinreClientEventsImpl.scoop
index 8f925e4..459373d 100644
--- a/weinre.web/modules/weinre/client/WeinreClientEventsImpl.scoop
+++ b/weinre.web/modules/weinre/client/WeinreClientEventsImpl.scoop
@@ -14,6 +14,13 @@
this.client = client
//-----------------------------------------------------------------------------
+init
+ var titleNotConnected = "weinre: target not connected"
+ var titleConnectedPrefix = "weinre: "
+
+ document.title = titleNotConnected
+
+//-----------------------------------------------------------------------------
method clientRegistered(clientDescription)
if (this.client.uiAvailable()) {
WebInspector.panels.remote.addClient(clientDescription)
@@ -54,15 +61,23 @@
WebInspector.panels.elements.reset()
WebInspector.panels.timeline._clearPanel()
WebInspector.panels.resources.reset()
+
+ var target = WebInspector.panels.remote.getTarget(targetChannel)
+ document.title = titleConnectedPrefix + target.url
+
+ WebInspector.inspectedURLChanged(target.url)
//-----------------------------------------------------------------------------
method connectionDestroyed(/*int*/ clientChannel, /*int*/ targetChannel)
+
if (this.client.uiAvailable()) {
WebInspector.panels.remote.setClientState(clientChannel, "not-connected")
WebInspector.panels.remote.setTargetState(targetChannel, "not-connected")
}
if (clientChannel != Weinre.messageDispatcher.channel) return
+
+ document.title = titleNotConnected
if (!Weinre.client.autoConnect()) return
if (!this.client.uiAvailable()) return
diff --git a/weinre.web/modules/weinre/common/IDGenerator.scoop b/weinre.web/modules/weinre/common/IDGenerator.scoop
index 4829267..5af26cd 100644
--- a/weinre.web/modules/weinre/common/IDGenerator.scoop
+++ b/weinre.web/modules/weinre/common/IDGenerator.scoop
@@ -11,8 +11,8 @@
//-----------------------------------------------------------------------------
init
- var nextId = 1
- var idName = "__weinre__id"
+ var nextIdValue = 1
+ var idName = "__weinre__id"
//-----------------------------------------------------------------------------
static method checkId(object)
@@ -23,7 +23,7 @@
var id = IDGenerator.checkId(object)
if (!id) {
- id = next()
+ id = nextId()
// note:
// attempted to use Object.defineProperty() to make
@@ -40,10 +40,14 @@
}
return id
-
+
//-----------------------------------------------------------------------------
-function next
- var result = nextId
- nextId += 1
+static method next
+ return nextId()
+
+//-----------------------------------------------------------------------------
+function nextId
+ var result = nextIdValue
+ nextIdValue += 1
return result
diff --git a/weinre.web/modules/weinre/target/Target.scoop b/weinre.web/modules/weinre/target/Target.scoop
index 38ff60b..0a4d81d 100644
--- a/weinre.web/modules/weinre/target/Target.scoop
+++ b/weinre.web/modules/weinre/target/Target.scoop
@@ -90,6 +90,8 @@
//-----------------------------------------------------------------------------
method initialize()
+ var self = this
+
this.setWeinreServerURLFromScriptSrc()
this.setWeinreServerIdFromScriptSrc()
@@ -101,6 +103,18 @@
Weinre.injectedScript = injectedScriptConstructor(injectedScriptHost, window, 0, "?")
window.addEventListener("load", Binding(this, "onLoaded"), false)
+ document.addEventListener("DOMContentLoaded", Binding(this, "onDOMContent"), false)
+
+ this._startTime = currentTime()
+
+ if (document.readyState == "loaded") {
+ setTimeout(function() { self.onDOMContent() }, 10)
+ }
+
+ if (document.readyState == "complete") {
+ setTimeout(function() { self.onDOMContent() }, 10)
+ setTimeout(function() { self.onLoaded() }, 20)
+ }
var messageDispatcher = new MessageDispatcher(window.WeinreServerURL + "ws/target", window.WeinreServerId)
Weinre.messageDispatcher = messageDispatcher
@@ -160,7 +174,12 @@
Weinre.targetDescription = targetDescription
//-----------------------------------------------------------------------------
-method onLoaded()
+method onLoaded
+ Weinre.wi.InspectorNotify.loadEventFired(currentTime() - this._startTime)
+
+//-----------------------------------------------------------------------------
+method onDOMContent
+ Weinre.wi.InspectorNotify.domContentEventFired(currentTime() - this._startTime)
//-----------------------------------------------------------------------------
method setDocument()
@@ -170,3 +189,8 @@
var nodeData = Weinre.nodeStore.getNodeData(nodeId, 2)
Weinre.wi.DOMNotify.setDocument(nodeData)
+
+//-----------------------------------------------------------------------------
+// WebKit's currentTime() seems to return time in seconds
+function currentTime()
+ return (new Date().getMilliseconds()) / 1000.0
\ No newline at end of file