| author | Grant Gayed | 2012-02-08 17:04:57 (EST) |
|---|---|---|
| committer | Silenio Quarti | 2012-02-09 10:47:13 (EST) |
| commit | 219a6e0cd7cd9c4089f3a1833724930671823915 (patch) (side-by-side diff) | |
| tree | 32bafc25d9bf3e606929a6a879edccc9cd74638e | |
| parent | 0ac8592d7a33680ed6b51925e9ff740cf40975ab (diff) | |
| download | org.eclipse.orion.client-219a6e0cd7cd9c4089f3a1833724930671823915.zip org.eclipse.orion.client-219a6e0cd7cd9c4089f3a1833724930671823915.tar.gz org.eclipse.orion.client-219a6e0cd7cd9c4089f3a1833724930671823915.tar.bz2 | |
Bug 371013 - make debug work on tabs within a Chrome instance
14 files changed, 954 insertions, 343 deletions
diff --git a/bundles/org.eclipse.orion.client.debug/chromeExtension/background.html b/bundles/org.eclipse.orion.client.debug/chromeExtension/background.html new file mode 100644 index 0000000..6c5406a --- a/dev/null +++ b/bundles/org.eclipse.orion.client.debug/chromeExtension/background.html @@ -0,0 +1,139 @@ +/*******************************************************************************
+ * @license
+ * Copyright (c) 2012 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials are made
+ * available under the terms of the Eclipse Public License v1.0
+ * (http://www.eclipse.org/legal/epl-v10.html), and the Eclipse Distribution
+ * License v1.0 (http://www.eclipse.org/org/documents/edl-v10.html).
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+
+/*jslint browser:true*/
+
+<html>
+<script>
+var ADD_EVENT_TARGET = "add-event-target";
+var REMOVE_EVENT_TARGET = "remove-event-target";
+var REQUEST_ATTACH = "attach";
+var REQUEST_CONNECT_LOCAL = "connect-local";
+var REQUEST_CONNECT_PORT = "connect-port";
+var REQUEST_DETACH = "detach";
+var REQUEST_ENABLE = "enable";
+var REQUEST_GET_ID = "get-id";
+var REQUEST_GET_URL = "get-url";
+var REQUEST_GET_VERSION = "get-version";
+var REQUEST_SEND_COMMAND = "send-command";
+
+var counter = 0;
+var eventTargets = {};
+
+chrome.debugger.onDetach.addListener(function(source) {
+ for (current in eventTargets) {
+ chrome.tabs.sendRequest(eventTargets[current], {id: "event-" + source.tabId + "-" + counter++, content: {id: "detached", data: {}}});
+ }
+});
+chrome.debugger.onEvent.addListener(function(source, method, params) {
+ for (current in eventTargets) {
+ chrome.tabs.sendRequest(eventTargets[current], {id: "event-" + source.tabId + "-" + counter++, content: {id: method, data: params || {}}});
+ }
+});
+chrome.tabs.onCreated.addListener(function(tab) {
+ for (current in eventTargets) {
+ chrome.tabs.sendRequest(eventTargets[current], {id: "event-global-" + counter++, content: {id: "tabCreated", data: {id: tab.id, url: tab.url}}});
+ }
+});
+chrome.tabs.onRemoved.addListener(function(tabId, removeInfo) {
+ for (current in eventTargets) {
+ chrome.tabs.sendRequest(eventTargets[current], {id: "event-global-" + counter++, content: {id: "tabRemoved", data: {id: tabId}}});
+ }
+});
+chrome.tabs.onUpdated.addListener(function(tabId, changeInfo, tab) {
+ if (changeInfo.url) {
+ for (current in eventTargets) {
+ chrome.tabs.sendRequest(eventTargets[current], {id: "event-" + tabId + "-" + counter++, content: {id: "updateUrl", data: {url: changeInfo.url}}});
+ }
+ }
+});
+
+chrome.extension.onRequest.addListener(
+ function(request, sender, sendResponse) {
+ var content = request.content;
+ if (content.id === REQUEST_CONNECT_LOCAL) {
+ chrome.windows.getAll({populate: true}, function(windows) {
+ var data = [];
+ for (var i = 0; i < windows.length; i++) {
+ var tabs = windows[i].tabs;
+ for (var j = 0; j < tabs.length; j++) {
+ var current = tabs[j];
+ var url = current.url;
+ data.push({
+ id: current.id,
+ url: url
+ });
+ }
+ }
+ sendResponse({id: request.id, content: {data: {tabs: data}}});
+ });
+ } else if (content.id === REQUEST_CONNECT_PORT) {
+ var port = content.data.port;
+ if (isNaN(port) || !(1000 <= port && port < 65535)) {
+ sendResponse({id: request.id, content: {data: {error: "Invalid port, value must be 1000 - 65535"}}});
+ } else {
+ var url = "http://localhost:" + port + "/json";
+ var xhr = new XMLHttpRequest();
+ xhr.onreadystatechange = function() {
+ if (xhr.readyState === 4) {
+ if (xhr.responseText.length > 0) {
+ sendResponse({id: request.id, content: {data: {tabs: JSON.parse(xhr.responseText)}}});
+ }
+ }
+ };
+ xhr.onerror = function() {
+ sendResponse({id: request.id, content: {data: {error: "TODO get the error message"}}}); // TODO
+ };
+ xhr.open("GET", url, true);
+ xhr.setRequestHeader('Cache-Control','no-cache');
+ xhr.send(null);
+ }
+ } else if (content.id === REQUEST_ATTACH) {
+ var id = content.data.id;
+ chrome.debugger.attach({tabId: id}, "0.1", function() {
+ sendResponse({id: request.id, content: {data: chrome.extension.lastError ? {error: chrome.extension.lastError} : {}}});
+ });
+ } else if (content.id === REQUEST_DETACH) {
+ var id = content.data.id;
+ chrome.debugger.detach({tabId: id}, function() {
+ sendResponse({id: request.id, content: {data: chrome.extension.lastError ? {error: chrome.extension.lastError} : {}}});
+ });
+ } else if (content.id === REQUEST_SEND_COMMAND) {
+ chrome.debugger.sendCommand({tabId: content.data.id}, content.data.command, content.data.args || {}, function(result) {
+ sendResponse({id: request.id, content: {data: chrome.extension.lastError ? {error: chrome.extension.lastError} : {result: result}}});
+ });
+ } else if (content.id === ADD_EVENT_TARGET) {
+ eventTargets["t" + sender.tab.id] = sender.tab.id;
+ } else if (content.id === REMOVE_EVENT_TARGET) {
+ delete eventTargets["t" + sender.tab.id];
+ } else if (content.id === REQUEST_GET_ID) {
+ sendResponse({id: request.id, content: {data: {id: sender.tab.id}}});
+ } else if (content.id === REQUEST_GET_URL) {
+ chrome.tabs.get(content.data.id, function(tab) {
+ sendResponse({id: request.id, content: {data: chrome.extension.lastError ? {error: chrome.extension.lastError} : {url: tab.url}}});
+ });
+ } else if (content.id === REQUEST_GET_VERSION) {
+ chrome.management.getAll(function (extensions) {
+ for (var i = 0; i < extensions.length; i++) {
+ var current = extensions[i];
+ if (current.name === "Orion Debug Extension for Chrome") {
+ sendResponse({id: request.id, content: {data: {version: current.version}}});
+ return;
+ }
+ }
+ sendResponse({id: request.id, content: {data: {}}});
+ });
+ }
+ }
+);
+</script>
+</html>
diff --git a/bundles/org.eclipse.orion.client.debug/chromeExtension/bin/debugChromeExtension.crx b/bundles/org.eclipse.orion.client.debug/chromeExtension/bin/debugChromeExtension.crx Binary files differdeleted file mode 100644 index 163fd90..0000000 --- a/bundles/org.eclipse.orion.client.debug/chromeExtension/bin/debugChromeExtension.crx +++ b/dev/null diff --git a/bundles/org.eclipse.orion.client.debug/chromeExtension/debug.js b/bundles/org.eclipse.orion.client.debug/chromeExtension/debug.js new file mode 100644 index 0000000..46536fa --- a/dev/null +++ b/bundles/org.eclipse.orion.client.debug/chromeExtension/debug.js @@ -0,0 +1,55 @@ +/*******************************************************************************
+ * @license
+ * Copyright (c) 2012 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials are made
+ * available under the terms of the Eclipse Public License v1.0
+ * (http://www.eclipse.org/legal/epl-v10.html), and the Eclipse Distribution
+ * License v1.0 (http://www.eclipse.org/org/documents/edl-v10.html).
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+
+/*global chrome*/
+/*jslint browser:true*/
+
+var incoming = document.getElementById("orion-debugMessaging-toExtension");
+var outgoing = document.getElementById("orion-debugMessaging-toPage");
+
+if (incoming && outgoing) {
+ incoming.addEventListener("DOMNodeInserted", function() {
+ var children = incoming.childNodes;
+ for (var i = children.length - 1; i >= 0; i--) {
+ var current = children[i];
+ incoming.removeChild(current);
+ chrome.extension.sendRequest({id: current.id, content: JSON.parse(current.innerText)}, function(response) {
+ if (response && response.id) {
+ var responseLabel = document.createElement('label');
+ responseLabel.setAttribute('id', response.id);
+ responseLabel.style.display = 'none';
+ responseLabel.innerText = JSON.stringify(response.content);
+ var outgoingChildren = outgoing.childNodes;
+ if (outgoingChildren.length > 0) {
+ outgoing.insertBefore(responseLabel, outgoingChildren[0]);
+ } else {
+ outgoing.appendChild(responseLabel);
+ }
+ }
+ });
+ }
+ });
+
+ chrome.extension.onRequest.addListener(function(request, sender, sendResponse) {
+ var eventLabel = document.createElement('label');
+ eventLabel.setAttribute('id', request.id);
+ eventLabel.style.display = 'none';
+ eventLabel.innerText = JSON.stringify(request.content);
+ var outgoingChildren = outgoing.childNodes;
+ if (outgoingChildren.length > 0) {
+ outgoing.insertBefore(eventLabel, outgoingChildren[0]);
+ } else {
+ outgoing.appendChild(eventLabel);
+ }
+ sendResponse({});
+ });
+}
diff --git a/bundles/org.eclipse.orion.client.debug/chromeExtension/manifest.json b/bundles/org.eclipse.orion.client.debug/chromeExtension/manifest.json new file mode 100644 index 0000000..4bdf8d2 --- a/dev/null +++ b/bundles/org.eclipse.orion.client.debug/chromeExtension/manifest.json @@ -0,0 +1,15 @@ +{
+ "name":"Orion Debug Extension for Chrome",
+ "version":"0.3",
+ "content_scripts":[{
+ "matches":["http://*/*", "file://*/*"],
+ "js":["debug.js"]
+ }],
+ "background_page": "background.html",
+ "permissions": [
+ "debugger",
+ "management",
+ "tabs",
+ "http://*/json"
+ ]
+}
diff --git a/bundles/org.eclipse.orion.client.debug/chromeExtension/src/debug.js b/bundles/org.eclipse.orion.client.debug/chromeExtension/src/debug.js deleted file mode 100644 index 218ee59..0000000 --- a/bundles/org.eclipse.orion.client.debug/chromeExtension/src/debug.js +++ b/dev/null @@ -1,51 +0,0 @@ -/*******************************************************************************
- * @license
- * Copyright (c) 2012 IBM Corporation and others.
- * All rights reserved. This program and the accompanying materials are made
- * available under the terms of the Eclipse Public License v1.0
- * (http://www.eclipse.org/legal/epl-v10.html), and the Eclipse Distribution
- * License v1.0 (http://www.eclipse.org/org/documents/edl-v10.html).
- *
- * Contributors:
- * IBM Corporation - initial API and implementation
- *******************************************************************************/
-
-/*jslint browser:true*/
-
-var debugMessaging = document.getElementById("orion-debugMessaging");
-if (debugMessaging) {
- debugMessaging.addEventListener("DOMNodeInserted", function() {
- var children = debugMessaging.childNodes;
- for (var i = 0; i < children.length; i++) {
- var current = children[i];
- if (current.id.indexOf("debug-port-") === 0) {
- var port = parseInt(current.innerHTML, 10);
- debugMessaging.removeChild(current);
- if (isNaN(port) || !(1000 <= port && port < 65535)) {
- var responseLabel = document.createElement('label');
- responseLabel.setAttribute('id', 'debug-error');
- responseLabel.style.display = 'none';
- responseLabel.innerHTML = "Invalid port, value must be 1000 - 65535";
- debugMessaging.appendChild(responseLabel);
- } else {
- var url = "http://localhost:" + port + "/json";
- var xhr = new XMLHttpRequest();
- xhr.onreadystatechange = function() {
- if (xhr.readyState === 4) {
- if (xhr.responseText.length > 0) {
- var responseLabel = document.createElement('label');
- responseLabel.setAttribute('id', 'debug-response-' + port);
- responseLabel.style.display = 'none';
- responseLabel.innerHTML = xhr.responseText;
- debugMessaging.appendChild(responseLabel);
- }
- }
- };
- xhr.open("GET", url, true);
- xhr.setRequestHeader('Cache-Control','no-cache');
- xhr.send(null);
- }
- }
- }
- });
-}
diff --git a/bundles/org.eclipse.orion.client.debug/chromeExtension/src/manifest.json b/bundles/org.eclipse.orion.client.debug/chromeExtension/src/manifest.json deleted file mode 100644 index e1af3ba..0000000 --- a/bundles/org.eclipse.orion.client.debug/chromeExtension/src/manifest.json +++ b/dev/null @@ -1,9 +0,0 @@ -{
- "name":"Orion Debug Extension for Chrome",
- "version":"0.2",
- "content_scripts":[{
- "matches":["http://*/*", "file://*/*"],
- "js":["debug.js"]
- }],
- "optional-permissions":["http://*/json", "file://*/json"]
-}
diff --git a/bundles/org.eclipse.orion.client.debug/web/connections.html b/bundles/org.eclipse.orion.client.debug/web/connections.html index 44d6411..ebdd3d0 100644 --- a/bundles/org.eclipse.orion.client.debug/web/connections.html +++ b/bundles/org.eclipse.orion.client.debug/web/connections.html @@ -45,7 +45,8 @@ <div class="toolbar" id="toolbar" dojotype="dijit.layout.ContentPane" region="top"> </div> <div id="orion-debugConnectionsMainPane" dojotype="dijit.layout.ContentPane" region="center" class="mainpane"> - <div id="orion-debugMessaging"></div> + <div id="orion-debugMessaging-toExtension"></div> + <div id="orion-debugMessaging-toPage"></div> <div id="debugConnections-table"></div> </div> <div class="footer" id="footer" dojotype="dijit.layout.ContentPane" region="bottom" splitter="false"> diff --git a/bundles/org.eclipse.orion.client.debug/web/connections.js b/bundles/org.eclipse.orion.client.debug/web/connections.js index 3170842..37f9dd3 100644 --- a/bundles/org.eclipse.orion.client.debug/web/connections.js +++ b/bundles/org.eclipse.orion.client.debug/web/connections.js @@ -13,13 +13,14 @@ /*global define orion localStorage*/ /*jslint browser:true*/ -define(['require', 'dojo', 'orion/bootstrap', 'orion/commands', 'orion/fileClient', - 'orion/searchClient', 'orion/globalCommands', 'debug/connectionsTree', 'orion/treetable', 'debug/debugTab', 'debug/portInputDialog'], - function(require, dojo, mBootstrap, mCommands, mFileClient, mSearchClient, mGlobalCommands, mConnectionsTree, mTreeTable, mDebugTab) { +define(['require', 'dojo', 'orion/bootstrap', 'orion/commands', 'orion/fileClient', 'orion/searchClient', + 'orion/globalCommands', 'debug/connectionsTree', 'orion/treetable', 'debug/debugTab', 'debug/debugMessaging', + 'debug/portInputDialog'], + function(require, dojo, mBootstrap, mCommands, mFileClient, mSearchClient, mGlobalCommands, mConnectionsTree, mTreeTable, mDebugTab, mDebugMessaging) { var treeWidget; - var model = new mConnectionsTree.DebugConnectionTreeModel("debug-tableTree"); + var model = new mConnectionsTree.DebugConnectionTreeModel("debug-tableTree"); function modelUpdated() { model.getRoot(function(root) { model.getChildren(root, function(children) { @@ -31,15 +32,42 @@ define(['require', 'dojo', 'orion/bootstrap', 'orion/commands', 'orion/fileClien }); } - function initiateConnection(portString) { - var port = parseInt(portString, 10); - if (1000 <= port && port < 65535) { - var label = dojo.create("label", {id: "debug-port-" + port}); - label.style.display = "none"; - label.innerHTML = port; - dojo.place(label, "orion-debugMessaging", "first"); + var messaging = new mDebugMessaging.DebugMessaging("connectionsPage"); + + var RemoteDebugTabProvider = (function() { + function RemoteDebugTabProvider(debugTab) { + this._debugTab = debugTab; } - } + RemoteDebugTabProvider.prototype = /** @lends RemoteDebugTabProvider.prototype */{ + getChildren: function() { + return []; + }, + getUrl: function() { + return this._debugTab.getUrl(); + }, + getWSUrl: function() { + return this._debugTab.getWSUrl(); + }, + renderLabel: function(column) { + var wsUrl = this.getWSUrl(); + if (wsUrl) { + var base = require.toUrl("debug/debug.html"); + var url = base + "#" + wsUrl; + var urlLink = dojo.create("a", {href: url}, column, "last"); + dojo.place(document.createTextNode(this.getUrl() || "< Loading >"), urlLink, "last"); + } else { + dojo.create("label", {innerHTML: this.getUrl() + " [debugger attached]"}, column, "last"); + } + }, + shouldDisplayActions: function() { + return false; + }, + toString: function() { + return this.getWSUrl(); + } + }; + return RemoteDebugTabProvider; + }()); var RemoteDebugConnection = (function() { function RemoteDebugConnection(port) { @@ -54,7 +82,7 @@ define(['require', 'dojo', 'orion/bootstrap', 'orion/commands', 'orion/fileClien for (var i = this._tabs.length - 1; i >= 0; i--) { var current = this._tabs[i]; if (!value || current === value) { - current.close(); + current.detach(); this._tabs.splice(i, 1); if (value) { return; @@ -72,6 +100,9 @@ define(['require', 'dojo', 'orion/bootstrap', 'orion/commands', 'orion/fileClien getPort: function() { return this._port; }, + getId: function() { + return this.getPort(); + }, getTabs: function() { return this._tabs; }, @@ -97,45 +128,168 @@ define(['require', 'dojo', 'orion/bootstrap', 'orion/commands', 'orion/fileClien return RemoteDebugConnection; }()); - // TODO this should move to debugTab.js - var RemoteDebugTabProvider = (function() { - function RemoteDebugTabProvider(remoteDebugTab) { - this._remoteDebugTab = remoteDebugTab; + function initiateRemoteConnection(port) { + messaging.send("connect-port", {port: port}, function(data) { + if (data.error) { + // TODO log + return; + } + var tabs = data.tabs; + var connection = new RemoteDebugConnection(port); + if (model.addConnection(connection)) { +// var urlChangedFunction = function() { +// modelUpdated(); +// }; +// var tabClosedFunction = function(remoteDebugTab) { +// connection.disconnect(remoteDebugTab); +// if (connection.getTabs().length === 0) { +// model.removeConnection(connection); +// } +// modelUpdated(); +// }; + for (var j = 0; j < tabs.length; j++) { + var current = tabs[j]; + var remoteDebugTab = new mDebugTab.RemoteDebugTab(current.webSocketDebuggerUrl, current.url); +// remoteDebugTab.addUrlListener(urlChangedFunction); +// remoteDebugTab.addDetachListener(tabClosedFunction); + connection.addTab(remoteDebugTab); + } + + var portsString = localStorage.getItem("orion.debug.chromeDebugPorts"); + var portsObject = portsString ? JSON.parse(portsString) : {}; + if (!portsObject[port]) { + portsObject[port] = true; + portsString = JSON.stringify(portsObject); + localStorage.setItem("orion.debug.chromeDebugPorts", portsString); + } + modelUpdated(); + } + }); + } + + var LocalDebugTabProvider = (function() { + function LocalDebugTabProvider(debugTab) { + this._debugTab = debugTab; } - RemoteDebugTabProvider.prototype = /** @lends RemoteDebugTabProvider.prototype */{ + LocalDebugTabProvider.prototype = /** @lends LocalDebugTabProvider.prototype */{ getChildren: function() { return []; }, - getRemoteDebugTab: function() { - return this._remoteDebugTab; - }, getUrl: function() { - return this._remoteDebugTab.getUrl(); - }, - getWSUrl: function() { - return this._remoteDebugTab.getWSUrl(); + return this._debugTab.getUrl(); }, renderLabel: function(column) { - var wsUrl = this.getWSUrl(); - if (wsUrl) { - var base = require.toUrl("debug/debug.html"); - var url = base + "#" + wsUrl; - var urlLink = dojo.create("a", {href: url}, column, "last"); - dojo.place(document.createTextNode(this.getUrl() || "< Loading >"), urlLink, "last"); - } else { - dojo.create("label", {innerHTML: this.getUrl() + " [currently not debuggable]"}, column, "last"); + var base = require.toUrl("debug/debug.html"); + var url = base + "#id" + this._debugTab.getId(); + var urlLink = dojo.create("a", {href: url}, column, "last"); + dojo.place(document.createTextNode(this.getUrl() || "< Loading >"), urlLink, "last"); + }, + shouldDisplayActions: function() { + return false; + }, + toString: function() { + return this.getUrl(); + } + }; + return LocalDebugTabProvider; + }()); + + var LocalDebugConnection = (function() { + function LocalDebugConnection() { + this._tabs = []; + } + LocalDebugConnection.prototype = /** @lends LocalDebugConnection.prototype */ { + addTab: function(value) { + this._tabs.push(value); + }, + disconnect: function(value) { + for (var i = this._tabs.length - 1; i >= 0; i--) { + var current = this._tabs[i]; + if (!value || current === value) { + current.detach(); + this._tabs.splice(i, 1); + if (value) { + return; + } + } + } + }, + getChildren: function() { + var result = []; + for (var i = 0; i < this._tabs.length; i++) { + result.push(new LocalDebugTabProvider(this._tabs[i])); } + return result; + }, + getId: function() { + return "local"; + }, + getTabs: function() { + return this._tabs; + }, + removeTab: function(tab) { + for (var i = 0; i < this._tabs.length; i++) { + var current = this._tabs[i]; + if (current === tab) { + this._tabs.splice(i, 1); + return; + } + } + }, + renderLabel: function(column) { + dojo.create("label", {innerHTML: this.toString().bold()}, column, "last"); }, shouldDisplayActions: function() { return false; }, toString: function() { - return this.getWSUrl(); + return "Local Chrome browser"; } }; - return RemoteDebugTabProvider; + return LocalDebugConnection; }()); + function refreshAvailableTabs() { + model.clear(); + messaging.send("connect-local", null, function(result) { + var tabs = result.tabs; + var localDebugConnection; + messaging.send("get-id", null, function(result) { + var selfTabId = result.id; + var urlChangedFunction = function() { + modelUpdated(); + }; + for (var j = 0; j < tabs.length; j++) { + var currentTab = tabs[j]; + if (currentTab.id !== selfTabId) { + var localDebugTab = new mDebugTab.LocalDebugTab(currentTab.id, messaging, currentTab.url); + localDebugTab.addUrlListener(urlChangedFunction); + if (!localDebugConnection) { + localDebugConnection = new LocalDebugConnection(); + model.addConnection(localDebugConnection); + } + localDebugConnection.addTab(localDebugTab); + } + } + modelUpdated(); + }); + }); + + var portsString = localStorage.getItem("orion.debug.chromeDebugPorts"); + if (portsString) { + var portsObject = JSON.parse(portsString); + for (var port in portsObject) { + initiateRemoteConnection(parseInt(port, 10)); + } + } + } + + messaging.addEventListener(messaging.getId(), function(event, data) { + if (event === "tabCreated" || event === "tabRemoved") { + refreshAvailableTabs(); + } + }); + dojo.addOnLoad(function() { mBootstrap.startup().then(function(core) { var serviceRegistry = core.serviceRegistry; @@ -156,124 +310,83 @@ define(['require', 'dojo', 'orion/bootstrap', 'orion/commands', 'orion/fileClien return; } - var renderer = new mConnectionsTree.DebugConnectionRenderer(commandService); - treeWidget = new mTreeTable.TableTree({ - id: "debug-tableTree", - parent: dojo.byId("debugConnections-table"), - model: model, - showRoot: false, - renderer: renderer - }); - - var connectCommand = new mCommands.Command({ - name: "Connect", - tooltip: "Connect to a new browser", - id: "orion.debugConnections.connect", - groupId: "orion.debugGroup", - visibleWhen: function(item) { - return isChrome; - }, - callback: function() { - var dialog = new orion.debug.PortInputDialog({ - serviceRegistry: serviceRegistry, - func: function(port) { - initiateConnection(port); - } - }); - dialog.startup(); - dialog.show(); + messaging.verifyExtension(function(result) { + if (result) { + var label = dojo.create("label"); + label.innerHTML = result; + dojo.place(label, "debugConnections-table", "first"); + var url = require.toUrl("debug/ext/debugChromeExtension.crx"); + var urlLink = dojo.create("a", {href: url}, "debugConnections-table", "last"); + dojo.place(document.createTextNode(" [Click to install it]"), urlLink, "last"); + return; } - }); - commandService.addCommand(connectCommand, "dom"); - - var disconnectCommand = new mCommands.Command({ - name: "Disconnect", - tooltip: "Disconnect", - imageClass: "core-sprite-problem", - id: "orion.debugConnections.disconnect", - visibleWhen: function(item) { - return true; - }, - callback: function(data) { - var connection = data.items; - connection.disconnect(); - model.removeConnection(connection); - modelUpdated(); - - var port = connection.getPort(); - var portsString = localStorage.getItem("orion.debug.chromeDebugPorts"); - var portsObject = portsString ? JSON.parse(portsString) : {}; - if (portsObject[port]) { - delete portsObject[port]; - portsString = JSON.stringify(portsObject); - localStorage.setItem("orion.debug.chromeDebugPorts", portsString); - } - } - }); - commandService.addCommand(disconnectCommand, "object"); - - commandService.registerCommandContribution("orion.debugConnections.connect", 1, "pageActions"); - commandService.registerCommandContribution("orion.debugConnections.disconnect", 1); - mGlobalCommands.generateDomCommandsInBanner(commandService, {}); - var debugMessaging = dojo.byId("orion-debugMessaging"); - if (debugMessaging) { - var treeModel = model; - debugMessaging.addEventListener("DOMNodeInserted", function() { - var changed = false; - var children = debugMessaging.childNodes; - for (var i = 0; i < children.length; i++) { - var current = children[i]; - if (current.id.indexOf("debug-response-") === 0) { - var info = JSON.parse(current.innerHTML); - debugMessaging.removeChild(current); - - var port = current.id.substring("debug-response-".length); - var connection = new RemoteDebugConnection(port); - if (treeModel.addConnection(connection)) { - var urlChangedFunction = function() { - modelUpdated(); - }; - var tabClosedFunction = function(remoteDebugTab) { - connection.disconnect(remoteDebugTab); - if (connection.getTabs().length === 0) { - treeModel.removeConnection(connection); - } - modelUpdated(); - }; - for (var j = 0; j < info.length; j++) { - var current = info[j]; - var remoteDebugTab = new mDebugTab.RemoteDebugTab(current.webSocketDebuggerUrl, current.url); - remoteDebugTab.addUrlListener(urlChangedFunction); - remoteDebugTab.addCloseListener(tabClosedFunction); - connection.addTab(remoteDebugTab); - } + var renderer = new mConnectionsTree.DebugConnectionRenderer(commandService); + treeWidget = new mTreeTable.TableTree({ + id: "debug-tableTree", + parent: dojo.byId("debugConnections-table"), + model: model, + showRoot: false, + renderer: renderer + }); - var portsString = localStorage.getItem("orion.debug.chromeDebugPorts"); - var portsObject = portsString ? JSON.parse(portsString) : {}; - if (!portsObject[port]) { - portsObject[port] = true; - portsString = JSON.stringify(portsObject); - localStorage.setItem("orion.debug.chromeDebugPorts", portsString); + var connectCommand = new mCommands.Command({ + name: "Connect", + tooltip: "Connect to a new browser", + id: "orion.debugConnections.connect", + groupId: "orion.debugGroup", + visibleWhen: function(item) { + return isChrome; + }, + callback: function() { + var dialog = new orion.debug.PortInputDialog({ + serviceRegistry: serviceRegistry, + func: function(port) { + if (port && 1000 <= port && port < 65535) { + initiateRemoteConnection(port); } - changed = true; } - } + }); + dialog.startup(); + dialog.show(); } - - if (changed) { + }); + commandService.addCommand(connectCommand, "dom"); + + var disconnectCommand = new mCommands.Command({ + name: "Disconnect", + tooltip: "Disconnect", + imageClass: "core-sprite-problem", + id: "orion.debugConnections.disconnect", + visibleWhen: function(item) { + return true; + }, + callback: function(data) { + var connection = data.items; + connection.disconnect(); + model.removeConnection(connection); modelUpdated(); + + var port = connection.getPort(); + var portsString = localStorage.getItem("orion.debug.chromeDebugPorts"); + var portsObject = portsString ? JSON.parse(portsString) : {}; + if (portsObject[port]) { + delete portsObject[port]; + portsString = JSON.stringify(portsObject); + localStorage.setItem("orion.debug.chromeDebugPorts", portsString); + } } }); - } - - var portsString = localStorage.getItem("orion.debug.chromeDebugPorts"); - if (portsString) { - var portsObject = JSON.parse(portsString); - for (var port in portsObject) { - initiateConnection(port); - } - } + commandService.addCommand(disconnectCommand, "object"); + + // the following are intentionally commented +// commandService.registerCommandContribution("orion.debugConnections.connect", 2, "pageActions"); +// commandService.registerCommandContribution("orion.debugConnections.disconnect", 1); + mGlobalCommands.generateDomCommandsInBanner(commandService, {}); + refreshAvailableTabs(); + }); }); }); }); + + diff --git a/bundles/org.eclipse.orion.client.debug/web/connectionsTree.js b/bundles/org.eclipse.orion.client.debug/web/connectionsTree.js index 36aa0a8..ddb2e38 100644 --- a/bundles/org.eclipse.orion.client.debug/web/connectionsTree.js +++ b/bundles/org.eclipse.orion.client.debug/web/connectionsTree.js @@ -11,7 +11,6 @@ *******************************************************************************/ /*global define*/ -/*jslint browser:true*/ define(['require', 'dojo'], function(require, dojo) { @@ -26,18 +25,18 @@ define(['require', 'dojo'], function(require, dojo) { DebugConnectionTreeModel.prototype = /** @lends orion.debug.DebugConnectionTreeModel.prototype */{ addConnection: function(connection) { /* first check for a duplicate */ - var port = connection.getPort(); + var id = connection.getId(); for (var i = 0; i < this._root.length; i++) { var current = this._root[i]; - if (current.getPort() === port) { + if (current.getId() === id) { return false; } } this._root.push(connection); return true; }, - getRoot: function(/**function*/ onItem) { - onItem(this); + clear: function() { + this._root = []; }, getChildren: function(/**dojo.data.Item*/ parentItem, /**Function(items)*/ onComplete) { onComplete(parentItem === this ? this._root : parentItem.getChildren()); @@ -45,6 +44,9 @@ define(['require', 'dojo'], function(require, dojo) { getId: function(/**dojo.data.Item|String*/ item) { return (item === this || item === this._id) ? this._id : item.toString(); }, + getRoot: function(/**function*/ onItem) { + onItem(this); + }, removeConnection: function(connection) { for (var i = 0; i < this._root.length; i++) { var current = this._root[i]; @@ -79,7 +81,7 @@ define(['require', 'dojo'], function(require, dojo) { {id: tableRow.id + "actionswrapper"}, actionColumn, "only"); - this._commandService.renderCommands(actionsWrapper, "object", item, {}, "tool"); + this._commandService.renderCommands(actionsWrapper, "object", item, {}, "button"); } dojo.place(labelColumn, tableRow, "last"); dojo.place(actionColumn, tableRow, "last"); diff --git a/bundles/org.eclipse.orion.client.debug/web/debug.html b/bundles/org.eclipse.orion.client.debug/web/debug.html index ef8b27b..8bfd872 100644 --- a/bundles/org.eclipse.orion.client.debug/web/debug.html +++ b/bundles/org.eclipse.orion.client.debug/web/debug.html @@ -45,7 +45,9 @@ <div class="toolbar" id="toolbar" dojotype="dijit.layout.ContentPane" region="top">
</div>
<div id="orion-debugMainPane" dojotype="dijit.layout.ContentPane" region="center" class="mainpane">
- <div id="debug-console" style='width:100%;height:650px;border: 1px solid teal;'></div>
+ <div id="orion-debugMessaging-toExtension"></div>
+ <div id="orion-debugMessaging-toPage"></div>
+ <div id="debug-console" style='width:100%;height:650px;border: 1px solid black;'></div>
</div>
<div class="footer" id="footer" dojotype="dijit.layout.ContentPane" region="bottom" splitter="false">
</div>
diff --git a/bundles/org.eclipse.orion.client.debug/web/debug.js b/bundles/org.eclipse.orion.client.debug/web/debug.js index 814ce4c..8061f72 100644 --- a/bundles/org.eclipse.orion.client.debug/web/debug.js +++ b/bundles/org.eclipse.orion.client.debug/web/debug.js @@ -14,10 +14,8 @@ /*jslint browser:true*/
define(['require', 'dojo', 'orion/bootstrap', 'orion/commands', 'orion/fileClient', 'orion/searchClient', 'orion/globalCommands',
- 'orion/console', 'debug/debugTab'],
- function(require, dojo, mBootstrap, mCommands, mFileClient, mSearchClient, mGlobalCommands, mConsole, mDebugTab) {
-
- var console;
+ 'orion/console', 'debug/debugTab', 'debug/debugMessaging'],
+ function(require, dojo, mBootstrap, mCommands, mFileClient, mSearchClient, mGlobalCommands, mConsole, mDebugTab, mDebugMessaging) {
dojo.addOnLoad(function() {
mBootstrap.startup().then(function(core) {
@@ -39,33 +37,82 @@ define(['require', 'dojo', 'orion/bootstrap', 'orion/commands', 'orion/fileClien return;
}
+ var connection, console, messaging;
var hash = dojo.hash();
- var connection = new mDebugTab.RemoteDebugTab(hash);
- connection.addCloseListener(function() {
- var location = dojo.byId("location");
- if (location) {
- location.innerHTML = null;
+ if (hash.indexOf("ws://") === 0) {
+ connection = new mDebugTab.RemoteDebugTab(hash);
+ } else {
+ if (hash.indexOf("id") === 0) {
+ var id = parseInt(hash.substring(2), 10);
+ if (id) {
+ messaging = new mDebugMessaging.DebugMessaging("debugPage-" + id);
+ connection = new mDebugTab.LocalDebugTab(id, messaging);
+ }
+ }
+ if (!connection) {
+ return;
}
- console.appendOutput("<< Disconnected from external browser >>");
- console.setAcceptInput(false);
- });
- connection.addUrlListener(function(url) {
- var location = dojo.byId("location");
- if (location) {
- if (url === "about:blank") {
+ }
+
+ var init = function() {
+ dojo.addOnUnload(function() {
+ connection.detach();
+ });
+
+ connection.addDetachListener(function() {
+ var location = dojo.byId("location");
+ if (location) {
location.innerHTML = null;
- } else {
- location.innerHTML = url;
}
- }
- });
+ console.appendOutput("<< Disconnected from debug target >>");
+ console.setAcceptInput(false);
+ });
+ connection.addUrlListener(function(url) {
+ var location = dojo.byId("location");
+ if (location) {
+ if (url === "about:blank") {
+ location.innerHTML = null;
+ } else {
+ location.innerHTML = url;
+ }
+ }
+ });
- console = new mConsole.Console("debug-console");
- console.addInputListener(function(inputEvent) {
- connection.evaluate(inputEvent, function(result) {
- console.appendOutput(JSON.stringify(result));
+ console = new mConsole.Console("debug-console");
+ console.addInputListener(function(inputEvent) {
+ connection.evaluate(inputEvent, function(result) {
+ if (result.error) {
+ console.appendOutput("<< " + result.error + " >>");
+ } else {
+ console.appendOutput(JSON.stringify(result.result));
+ }
+ });
+ });
+
+ connection.attach(function (error) {
+ if (error) {
+ console.appendOutput("<< " + error + " >>");
+ console.setAcceptInput(false);
+ }
});
- });
+ };
+
+ if (messaging) {
+ messaging.verifyExtension(function(error) {
+ if (error) {
+ var label = dojo.create("label");
+ label.innerHTML = error;
+ dojo.place(label, "debug-console", "first");
+ var url = require.toUrl("debug/ext/debugChromeExtension.crx");
+ var urlLink = dojo.create("a", {href: url}, "debug-console", "last");
+ dojo.place(document.createTextNode(" [Click to install it]"), urlLink, "last");
+ return;
+ }
+ init();
+ });
+ } else {
+ init();
+ }
});
});
});
diff --git a/bundles/org.eclipse.orion.client.debug/web/debugMessaging.js b/bundles/org.eclipse.orion.client.debug/web/debugMessaging.js new file mode 100644 index 0000000..0bc4268 --- a/dev/null +++ b/bundles/org.eclipse.orion.client.debug/web/debugMessaging.js @@ -0,0 +1,115 @@ +/*******************************************************************************
+* @license
+* Copyright (c) 2012 IBM Corporation and others.
+* All rights reserved. This program and the accompanying materials are made
+* available under the terms of the Eclipse Public License v1.0
+* (http://www.eclipse.org/legal/epl-v10.html), and the Eclipse Distribution
+* License v1.0 (http://www.eclipse.org/org/documents/edl-v10.html).
+*
+* Contributors:
+* IBM Corporation - initial API and implementation
+*******************************************************************************/
+
+/*global define*/
+/*jslint browser:true*/
+
+define(['require', 'dojo'], function(require, dojo) {
+
+ var orion = {};
+ orion.debug = {};
+
+ orion.debug.DebugMessaging = (function() {
+ function DebugMessaging(id) {
+ this._id = id;
+
+ this._counter = 0;
+ this._eventListeners = {};
+ this._pendingRequests = {};
+ this._initialize();
+ }
+ DebugMessaging.prototype = /** @lends DebugMessaging.prototype */{
+ _initialize: function() {
+ this._incoming = dojo.byId("orion-debugMessaging-toPage");
+ this._outgoing = dojo.byId("orion-debugMessaging-toExtension");
+
+ if (this._incoming) {
+ this.send("add-event-target");
+ var self = this;
+ this._incoming.addEventListener("DOMNodeInserted", function() {
+ var children = self._incoming.childNodes;
+ for (var i = children.length - 1; i >= 0; i--) {
+ var current = children[i];
+ self._incoming.removeChild(current);
+ var response = self._pendingRequests[current.id];
+ if (response) {
+ response(JSON.parse(current.innerText).data);
+ } else if (current.id.indexOf("event-") === 0) {
+ var start = current.id.indexOf("-") + 1;
+ var end = current.id.indexOf("-", start);
+ var content = JSON.parse(current.innerText);
+ var listenerId = current.id.substring(start, end);
+ if (listenerId === "global") {
+ for (var current in self._eventListeners) {
+ self._eventListeners[current](content.id, content.data);
+ }
+ } else {
+ var listener = self._eventListeners[listenerId];
+ if (listener) {
+ listener(content.id, content.data);
+ }
+ }
+ }
+ }
+ });
+ }
+ },
+ addEventListener: function(id, func) {
+ this._eventListeners[id] = func;
+ },
+ getId: function() {
+ return this._id;
+ },
+ removeEventListener: function(id) {
+ delete this._eventListeners[id];
+ },
+ send: function(requestId, data, response) {
+ if (!this._outgoing) {
+ return false;
+ }
+
+ var messageId = "req-" + this._counter++;
+ if (response) {
+ this._pendingRequests[messageId] = response;
+ }
+ var label = dojo.create("label", {id: messageId});
+ var content = {id: requestId, data: data || {}};
+ label.innerText = JSON.stringify(content);
+ label.style.display = "none";
+ dojo.place(label, this._outgoing, "first");
+ return true;
+ },
+ verifyExtension: function(callback) {
+ var timer = setTimeout(
+ function() {callback("The Orion Debug Extension for Chrome must be installed in order to use debug.");},
+ 999);
+ var self = this;
+ this.send("get-version", null, function(result) {
+ clearTimeout(timer);
+ if (result.version) {
+ if (result.version === self.REQUIRED_VERSION) {
+ callback();
+ } else {
+ callback("An updated version of the Orion Debug Extension for Chrome must be installed in order to use debug.");
+ }
+ } else {
+ callback("The Orion Debug Extension for Chrome must be installed in order to use debug.");
+ }
+ });
+ },
+ REQUIRED_VERSION: "0.3"
+ };
+ return DebugMessaging;
+ }());
+
+ return orion.debug;
+});
diff --git a/bundles/org.eclipse.orion.client.debug/web/debugTab.js b/bundles/org.eclipse.orion.client.debug/web/debugTab.js index e53901f..82c6c97 100644 --- a/bundles/org.eclipse.orion.client.debug/web/debugTab.js +++ b/bundles/org.eclipse.orion.client.debug/web/debugTab.js @@ -17,50 +17,72 @@ define(['require', 'dojo'], function(require, dojo) { var orion = {};
orion.debug = {};
+ var StatesEnum = {
+ STATE_DISCONNECTED: 0,
+ STATE_CONNECTED: 1,
+ STATE_ENABLED: 2,
+ STATE_SUSPENDING: 3,
+ STATE_RESUMING: 4,
+ STATE_SUSPENDED: 5
+ };
+
orion.debug.RemoteDebugTab = (function() {
function RemoteDebugTab(wsUrl, url) {
+ this._wsUrl = wsUrl;
+ this._url = url;
+
this._nextId = 1;
- this._state = this.StatesEnum.STATE_DISCONNECTED;
+ this._state = StatesEnum.STATE_DISCONNECTED;
this._pendingResponses = [];
- this._closeListeners = [];
+ this._detachListeners = [];
this._urlListeners = [];
- this._url = url;
- this._wsUrl = wsUrl;
- if (this._wsUrl) {
- this._socket = new WebSocket(this._wsUrl);
- var self = this;
- this._socket.onmessage = function(evt) {
- self._handleMessage(evt.data);
- };
- this._socket.onclose = function(evt) {
- self._state = self.StatesEnum.STATE_DISCONNECTED;
- for (var i = 0; i < self._closeListeners.length; i++) {
- self._closeListeners[i](self);
- }
- };
- this._socket.onopen = function(evt) {
- self._state = self.StatesEnum.STATE_CONNECTED;
- self.enable();
- if (!self._url) {
- self._updateUrl();
- }
- };
- }
}
RemoteDebugTab.prototype = /** @lends RemoteDebugTab.prototype */{
- addCloseListener: function(listener) {
- this._closeListeners.push(listener);
+ addDetachListener: function(listener) {
+ this._detachListeners.push(listener);
},
addUrlListener: function(listener) {
this._urlListeners.push(listener);
},
- close: function() {
+ attach: function(callback) {
+ var pendingCallback = callback;
+ if (this._wsUrl) {
+ this._socket = new WebSocket(this._wsUrl);
+ var self = this;
+ this._socket.onmessage = function(evt) {
+ self._handleMessage(evt.data);
+ };
+ this._socket.onclose = function(evt) {
+ self._state = StatesEnum.STATE_DISCONNECTED;
+ if (pendingCallback) {
+ pendingCallback("Failed to connect, remote tab is likely closed or has another debugger attached");
+ pendingCallback = null;
+ return;
+ }
+ for (var i = 0; i < self._detachListeners.length; i++) {
+ self._detachListeners[i](self);
+ }
+ };
+ this._socket.onopen = function(evt) {
+ self._state = StatesEnum.STATE_CONNECTED;
+ self.enable(pendingCallback);
+ pendingCallback = null;
+ if (!self._url) {
+ self._updateUrl();
+ }
+ };
+ }
+ },
+ detach: function(callback) {
if (this._socket) {
this._socket.close();
}
+ if (callback) {
+ callback();
+ }
},
- enable: function(listener) {
- if (!this._socket || this._state !== this.StatesEnum.STATE_CONNECTED) {
+ enable: function(callback) {
+ if (!this._socket || this._state !== StatesEnum.STATE_CONNECTED) {
return false;
}
var request = {
@@ -75,18 +97,20 @@ define(['require', 'dojo'], function(require, dojo) { this._pendingResponses.push({
id: request.id,
action: function(event) {
- self._state = self.StatesEnum.STATE_ENABLED;
- if (listener) {
- listener();
+ if (!event.error) {
+ self._state = StatesEnum.STATE_ENABLED;
+ }
+ if (callback) {
+ callback(event.error);
}
}
});
}
return result;
},
- evaluate: function(expression, listener) {
+ evaluate: function(expression, callback) {
if (!this._socket ||
- (this._state !== this.StatesEnum.STATE_SUSPENDED && this._state !== this.StatesEnum.STATE_ENABLED)) {
+ (this._state !== StatesEnum.STATE_SUSPENDED && this._state !== StatesEnum.STATE_ENABLED)) {
return false;
}
var request;
@@ -115,28 +139,25 @@ define(['require', 'dojo'], function(require, dojo) { this._pendingResponses.push({
id: request.id,
action: function(event) {
- if (listener) {
- listener(event.result.result);
+ if (callback) {
+ callback(event.error ? {error: event.error.message} : {result: event.result.result});
}
}
});
}
return result;
},
- getState: function() {
- return this._state;
- },
getUrl: function() {
return this._url;
},
getWSUrl: function() {
return this._wsUrl;
},
- removeCloseListener: function(listener) {
- for (var i = 0; i < this._closeListeners.length; i++) {
- var current = this._closeListeners[i];
+ removeDetachListener: function(listener) {
+ for (var i = 0; i < this._detachListeners.length; i++) {
+ var current = this._detachListeners[i];
if (current === listener) {
- this._closeListeners.splice(i, 1);
+ this._detachListeners.splice(i, 1);
return;
}
}
@@ -150,70 +171,71 @@ define(['require', 'dojo'], function(require, dojo) { }
}
},
- resume: function(listener) {
- if (!this._socket || this._state !== this.StatesEnum.STATE_SUSPENDED) {
- return false;
- }
- var request = {
- id: this._nextId++,
- method: "Debugger.resume",
- params: {}
- };
- var requestString = JSON.stringify(request);
- var result = this._socket.send(requestString);
- if (result) {
- var self = this;
- this._pendingResponses.push({
- id: request.id,
- action: function(event) {
- self._state = self.StatesEnum.STATE_RESUMING;
- self._resumeListener = listener;
- }
- });
- }
- return result;
- },
- suspend: function(listener) {
- if (!this._socket || this._state !== this.StatesEnum.STATE_ENABLED) {
- return false;
- }
- var request = {
- id: this._nextId++,
- method: "Debugger.pause",
- params: {}
- };
- var requestString = JSON.stringify(request);
- var result = this._socket.send(requestString);
- if (result) {
- var self = this;
- this._pendingResponses.push({
- id: request.id,
- action: function(event) {
- self._state = self.StatesEnum.STATE_SUSPENDING;
- self._suspendListener = listener;
- }
- });
- }
- return result;
- },
+// resume: function(callback) {
+// if (!this._socket || this._state !== StatesEnum.STATE_SUSPENDED) {
+// return false;
+// }
+// var request = {
+// id: this._nextId++,
+// method: "Debugger.resume",
+// params: {}
+// };
+// var requestString = JSON.stringify(request);
+// var result = this._socket.send(requestString);
+// if (result) {
+// var self = this;
+// this._pendingResponses.push({
+// id: request.id,
+// action: function(event) {
+// self._state = StatesEnum.STATE_RESUMING;
+// self._resumeListener = callback;
+// }
+// });
+// }
+// return result;
+// },
+// suspend: function(callback) {
+// if (!this._socket || this._state !== StatesEnum.STATE_ENABLED) {
+// return false;
+// }
+// var request = {
+// id: this._nextId++,
+// method: "Debugger.pause",
+// params: {}
+// };
+// var requestString = JSON.stringify(request);
+// var result = this._socket.send(requestString);
+// if (result) {
+// var self = this;
+// this._pendingResponses.push({
+// id: request.id,
+// action: function(event) {
+// self._state = StatesEnum.STATE_SUSPENDING;
+// self._suspendListener = callback;
+// }
+// });
+// }
+// return result;
+// },
_handleMessage: function(wsMessage) {
var event = JSON.parse(wsMessage);
var method = event.method;
if (method === "Debugger.paused") {
this._frameId = event.params.callFrames[0].callFrameId;
- this._state = this.StatesEnum.STATE_SUSPENDED;
+ this._state = StatesEnum.STATE_SUSPENDED;
if (this._suspendListener) {
- this._suspendListener();
+ this._suspendListener(event.error);
this._suspendListener = null;
}
} else if (method === "Debugger.resumed") {
this._frameId = null;
- this._state = this.StatesEnum.STATE_ENABLED;
+ this._state = StatesEnum.STATE_ENABLED;
if (this._resumeListener) {
- this._resumeListener();
+ this._resumeListener(event.error);
this._resumeListener = null;
}
+ // TODO replace the following two with the new event
} else if (method === "Debugger.globalObjectCleared") {
this._url = null;
} else if (method === "Debugger.scriptParsed") {
@@ -251,29 +273,189 @@ define(['require', 'dojo'], function(require, dojo) { this._pendingResponses.push({
id: request.id,
action: function(event) {
- var value = event.result.result.value;
- self._url = value;
- for (var i = 0; i < self._urlListeners.length; i++) {
- self._urlListeners[i](self._url, self);
+ if (event.error) {
+ // maybe display error somehow
+ } else {
+ var value = event.result.result.value;
+ self._url = value;
+ for (var i = 0; i < self._urlListeners.length; i++) {
+ self._urlListeners[i](self._url, self);
+ }
}
}
});
return true;
}
return false;
- },
-
- StatesEnum: {
- STATE_DISCONNECTED: "Disconnected",
- STATE_CONNECTED: "Connected",
- STATE_ENABLED: "Debugging",
- STATE_SUSPENDING: "Suspending...",
- STATE_RESUMING: "Resuming...",
- STATE_SUSPENDED: "Suspended"
}
};
return RemoteDebugTab;
}());
+ orion.debug.LocalDebugTab = (function() {
+ function LocalDebugTab(id, messaging, url) {
+ this._id = id;
+ this._messaging = messaging;
+ this._url = url;
+
+ this._state = StatesEnum.STATE_DISCONNECTED;
+ this._detachListeners = [];
+ this._pendingResponses = [];
+ this._urlListeners = [];
+
+ var self = this;
+ messaging.addEventListener(id, function(event, data) {
+ if (event === "detached") {
+ self._state = StatesEnum.STATE_DISCONNECTED;
+ for (var j = 0; j < self._detachListeners.length; j++) {
+ self._detachListeners[j](self);
+ }
+ } else if (event === "updateUrl") {
+ self._url = data.url;
+ for (var i = 0; i < self._urlListeners.length; i++) {
+ self._urlListeners[i](self._url, self);
+ }
+ }
+ });
+ }
+
+ LocalDebugTab.prototype = /** @lends LocalDebugTab.prototype */{
+ addDetachListener: function(listener) {
+ this._detachListeners.push(listener);
+ },
+ addUrlListener: function(listener) {
+ this._urlListeners.push(listener);
+ },
+ attach: function(callback) {
+ if (this._state === StatesEnum.STATE_CONNECTED || this._state === StatesEnum.STATE_ENABLED) {
+ if (callback) {
+ callback();
+ }
+ return;
+ }
+ var self = this;
+ this._messaging.send("attach", {id: this._id}, function(result) {
+ if (result.error) {
+ if (callback) {
+ callback(result.error.message);
+ }
+ return;
+ }
+ self._state = StatesEnum.STATE_CONNECTED;
+ self.enable(callback);
+ });
+ },
+ detach: function(callback) {
+ if (this._state === StatesEnum.STATE_DISCONNECTED) {
+ if (callback) {
+ callback();
+ }
+ return;
+ }
+ var self = this;
+ this._messaging.send("detach", {id: this._id}, function (result) {
+ if (result.error) {
+ if (callback) {
+ callback(result.error.message);
+ }
+ return;
+ }
+ self._state = StatesEnum.STATE_DISCONNECTED;
+ for (var j = 0; j < self._detachListeners.length; j++) {
+ self._detachListeners[j](self);
+ }
+ if (callback) {
+ callback();
+ }
+ });
+ },
+ enable: function(callback) {
+ var self = this;
+ this._messaging.send("send-command", {id: this._id, command: "Debugger.enable", args: {}}, function(result) {
+ if (result.error) {
+ if (callback) {
+ callback(result.error.message);
+ }
+ return;
+ }
+ self._state = StatesEnum.STATE_ENABLED;
+ if (!self._url) {
+ self._updateUrl();
+ }
+ if (callback) {
+ callback();
+ }
+ });
+ },
+ evaluate: function(expression, callback) {
+ if (this._state !== StatesEnum.STATE_SUSPENDED && this._state !== StatesEnum.STATE_ENABLED) {
+ return false;
+ }
+ var resultListener = function(result) {
+ if (result.error) {
+ if (callback) {
+ callback({error: result.error.message});
+ }
+ return;
+ }
+ if (callback) {
+ callback({result: result.result.result});
+ }
+ };
+
+ if (this._frameId) {
+ this._messaging.send(
+ "send-command",
+ {id: this._id, command: "Debugger.evaluateOnCallFrame", args: {callFrameId: this._frameId, expression: expression}},
+ resultListener);
+ } else {
+ this._messaging.send(
+ "send-command",
+ {id: this._id, command: "Runtime.evaluate", args: {expression: expression}},
+ resultListener);
+ }
+ },
+ getId: function() {
+ return this._id;
+ },
+ getUrl: function() {
+ return this._url;
+ },
+ removeDetachListener: function(listener) {
+ for (var i = 0; i < this._detachListeners.length; i++) {
+ var current = this._detachListeners[i];
+ if (current === listener) {
+ this._detachListeners.splice(i, 1);
+ return;
+ }
+ }
+ },
+ removeUrlListener: function(listener) {
+ for (var i = 0; i < this._urlListeners.length; i++) {
+ var current = this._urlListeners[i];
+ if (current === listener) {
+ this._urlListeners.splice(i, 1);
+ return;
+ }
+ }
+ },
+ _updateUrl: function() {
+ var self = this;
+ this._messaging.send("get-url", {id: this._id}, function(result) {
+ if (result.error) {
+ // TODO log
+ return;
+ }
+ self._url = result.url;
+ for (var i = 0; i < self._urlListeners.length; i++) {
+ self._urlListeners[i](self._url, self);
+ }
+ });
+ return true;
+ }
+ };
+ return LocalDebugTab;
+ }());
+
return orion.debug;
});
diff --git a/bundles/org.eclipse.orion.client.debug/web/ext/debugChromeExtension.crx b/bundles/org.eclipse.orion.client.debug/web/ext/debugChromeExtension.crx Binary files differnew file mode 100644 index 0000000..67aa964 --- a/dev/null +++ b/bundles/org.eclipse.orion.client.debug/web/ext/debugChromeExtension.crx |

