зеркало из https://github.com/mozilla/pjs.git
merge m-c to fx-team
This commit is contained in:
Коммит
0ae9ffc78e
|
@ -1031,6 +1031,12 @@ pref("devtools.errorconsole.enabled", false);
|
|||
pref("devtools.inspector.enabled", true);
|
||||
pref("devtools.inspector.htmlHeight", 112);
|
||||
|
||||
// Enable the Debugger
|
||||
pref("devtools.debugger.enabled", false);
|
||||
|
||||
// The default Debugger UI height
|
||||
pref("devtools.debugger.ui.height", 250);
|
||||
|
||||
// Enable the style inspector
|
||||
pref("devtools.styleinspector.enabled", true);
|
||||
|
||||
|
|
|
@ -189,6 +189,11 @@
|
|||
type="checkbox"
|
||||
command="Tools:Inspect"
|
||||
key="key_inspect"/>
|
||||
<menuitem id="appmenu_debugger"
|
||||
hidden="true"
|
||||
label="&debuggerMenu.label;"
|
||||
key="key_debugger"
|
||||
command="Tools:Debugger"/>
|
||||
<menuitem id="appmenu_scratchpad"
|
||||
hidden="true"
|
||||
label="&scratchpad.label;"
|
||||
|
|
|
@ -19,5 +19,7 @@
|
|||
#endif
|
||||
<!ENTITY % aboutHomeDTD SYSTEM "chrome://browser/locale/aboutHome.dtd">
|
||||
%aboutHomeDTD;
|
||||
<!ENTITY % debuggerDTD SYSTEM "chrome://browser/locale/devtools/debugger.dtd">
|
||||
%debuggerDTD;
|
||||
]>
|
||||
|
||||
|
|
|
@ -546,6 +546,11 @@
|
|||
accesskey="&inspectMenu.accesskey;"
|
||||
key="key_inspect"
|
||||
command="Tools:Inspect"/>
|
||||
<menuitem id="menu_debugger"
|
||||
hidden="true"
|
||||
label="&debuggerMenu.label;"
|
||||
key="key_debugger"
|
||||
command="Tools:Debugger"/>
|
||||
<menuitem id="menu_scratchpad"
|
||||
hidden="true"
|
||||
label="&scratchpad.label;"
|
||||
|
|
|
@ -127,6 +127,7 @@
|
|||
<command id="Tools:Downloads" oncommand="BrowserDownloadsUI();"/>
|
||||
<command id="Tools:WebConsole" oncommand="HUDConsoleUI.toggleHUD();"/>
|
||||
<command id="Tools:Inspect" oncommand="InspectorUI.toggleInspectorUI();" disabled="true"/>
|
||||
<command id="Tools:Debugger" oncommand="DebuggerUI.toggleDebugger();" disabled="true"/>
|
||||
<command id="Tools:Scratchpad" oncommand="Scratchpad.openScratchpad();" disabled="true"/>
|
||||
<command id="Tools:StyleEditor" oncommand="StyleEditor.openChrome();" disabled="true"/>
|
||||
<command id="Tools:Addons" oncommand="BrowserOpenAddonsMgr();"/>
|
||||
|
@ -250,6 +251,13 @@
|
|||
modifiers="accel,alt"
|
||||
#else
|
||||
modifiers="accel,shift"
|
||||
#endif
|
||||
/>
|
||||
<key id="key_debugger" key="&debuggerMenu.commandkey;" command="Tools:Debugger"
|
||||
#ifdef XP_MACOSX
|
||||
modifiers="accel,alt"
|
||||
#else
|
||||
modifiers="accel,shift"
|
||||
#endif
|
||||
/>
|
||||
<key id="key_inspect" key="&inspectMenu.commandkey;" command="Tools:Inspect"
|
||||
|
|
|
@ -181,6 +181,12 @@ XPCOMUtils.defineLazyGetter(this, "InspectorUI", function() {
|
|||
return new tmp.InspectorUI(window);
|
||||
});
|
||||
|
||||
XPCOMUtils.defineLazyGetter(this, "DebuggerUI", function() {
|
||||
let tmp = {};
|
||||
Cu.import("resource:///modules/devtools/DebuggerUI.jsm", tmp);
|
||||
return new tmp.DebuggerUI(window);
|
||||
});
|
||||
|
||||
XPCOMUtils.defineLazyGetter(this, "Tilt", function() {
|
||||
let tmp = {};
|
||||
Cu.import("resource:///modules/devtools/Tilt.jsm", tmp);
|
||||
|
@ -1729,6 +1735,16 @@ function delayedStartup(isLoadingBlank, mustLoadSidebar) {
|
|||
#endif
|
||||
}
|
||||
|
||||
// Enable Debugger?
|
||||
let enabled = gPrefService.getBoolPref("devtools.debugger.enabled");
|
||||
if (enabled) {
|
||||
document.getElementById("menu_debugger").hidden = false;
|
||||
document.getElementById("Tools:Debugger").removeAttribute("disabled");
|
||||
#ifdef MENUBAR_CAN_AUTOHIDE
|
||||
document.getElementById("appmenu_debugger").hidden = false;
|
||||
#endif
|
||||
}
|
||||
|
||||
// Enable Error Console?
|
||||
// XXX Temporarily always-enabled, see bug 601201
|
||||
let consoleEnabled = true || gPrefService.getBoolPref("devtools.errorconsole.enabled");
|
||||
|
|
|
@ -48,6 +48,7 @@
|
|||
|
||||
#highlighter-nodeinfobar-container {
|
||||
position: absolute;
|
||||
max-width: 95%;
|
||||
}
|
||||
|
||||
#highlighter-nodeinfobar-container:not([disable-transitions]) {
|
||||
|
@ -60,15 +61,17 @@
|
|||
display: block;
|
||||
white-space: nowrap;
|
||||
direction: ltr;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
#highlighter-nodeinfobar-container[locked] > #highlighter-nodeinfobar {
|
||||
pointer-events: auto;
|
||||
}
|
||||
|
||||
#highlighter-nodeinfobar-id,
|
||||
.highlighter-nodeinfobar-class,
|
||||
#highlighter-nodeinfobar-tagname {
|
||||
html|*#highlighter-nodeinfobar-id,
|
||||
html|*#highlighter-nodeinfobar-classes,
|
||||
html|*#highlighter-nodeinfobar-tagname {
|
||||
-moz-user-select: text;
|
||||
cursor: text;
|
||||
}
|
||||
|
@ -89,10 +92,6 @@
|
|||
visibility: hidden;
|
||||
}
|
||||
|
||||
#highlighter-nodeinfobar-id:empty {
|
||||
display: none;
|
||||
}
|
||||
|
||||
#highlighter-nodeinfobar-tagname {
|
||||
html|*#highlighter-nodeinfobar-tagname {
|
||||
text-transform: lowercase;
|
||||
}
|
||||
|
|
|
@ -54,6 +54,7 @@ DIRS = \
|
|||
styleinspector \
|
||||
tilt \
|
||||
scratchpad \
|
||||
debugger \
|
||||
shared \
|
||||
$(NULL)
|
||||
|
||||
|
|
|
@ -0,0 +1,377 @@
|
|||
/* -*- Mode: javascript; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Mozilla Debugger UI code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Mozilla Foundation
|
||||
* Portions created by the Initial Developer are Copyright (C) 2011
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Dave Camp <dcamp@mozilla.com> (original author)
|
||||
* Panos Astithas <past@mozilla.com>
|
||||
* Victor Porof <vporof@mozilla.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
"use strict";
|
||||
|
||||
/*global Components, NetUtil, Services, XPCOMUtils */
|
||||
/*global DebuggerServer, DebuggerClient, SourceEditor */
|
||||
const Cc = Components.classes;
|
||||
const Ci = Components.interfaces;
|
||||
const Cu = Components.utils;
|
||||
|
||||
Cu.import("resource://gre/modules/NetUtil.jsm");
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
Cu.import("resource://gre/modules/devtools/dbg-server.jsm");
|
||||
Cu.import("resource://gre/modules/devtools/dbg-client.jsm");
|
||||
Cu.import("resource:///modules/XPCOMUtils.jsm");
|
||||
Cu.import("resource:///modules/source-editor.jsm");
|
||||
|
||||
let EXPORTED_SYMBOLS = ["DebuggerUI"];
|
||||
|
||||
/**
|
||||
* Creates a pane that will host the debugger UI.
|
||||
*/
|
||||
function DebuggerPane(aTab) {
|
||||
this._tab = aTab;
|
||||
this._close = this.close.bind(this);
|
||||
this._debugTab = this.debugTab.bind(this);
|
||||
}
|
||||
|
||||
DebuggerPane.prototype = {
|
||||
/**
|
||||
* Creates and initializes the widgets contained in the debugger UI.
|
||||
*/
|
||||
create: function DP_create(gBrowser) {
|
||||
this._tab._scriptDebugger = this;
|
||||
|
||||
this._nbox = gBrowser.getNotificationBox(this._tab.linkedBrowser);
|
||||
this._splitter = gBrowser.parentNode.ownerDocument.createElement("splitter");
|
||||
this._splitter.setAttribute("class", "hud-splitter");
|
||||
this.frame = gBrowser.parentNode.ownerDocument.createElement("iframe");
|
||||
this.frame.height = DebuggerUIPreferences.height;
|
||||
|
||||
this._nbox.appendChild(this._splitter);
|
||||
this._nbox.appendChild(this.frame);
|
||||
|
||||
let self = this;
|
||||
|
||||
this.frame.addEventListener("DOMContentLoaded", function initPane(aEvent) {
|
||||
if (aEvent.target != self.frame.contentDocument) {
|
||||
return;
|
||||
}
|
||||
self.frame.removeEventListener("DOMContentLoaded", initPane, true);
|
||||
// Initialize the source editor.
|
||||
self.frame.contentWindow.editor = self.editor = new SourceEditor();
|
||||
|
||||
let config = {
|
||||
mode: SourceEditor.MODES.JAVASCRIPT,
|
||||
showLineNumbers: true,
|
||||
readOnly: true
|
||||
};
|
||||
|
||||
let editorPlaceholder = self.frame.contentDocument.getElementById("editor");
|
||||
self.editor.init(editorPlaceholder, config, self._onEditorLoad.bind(self));
|
||||
}, true);
|
||||
this.frame.addEventListener("DebuggerClose", this._close, true);
|
||||
|
||||
this.frame.setAttribute("src", "chrome://browser/content/debugger.xul");
|
||||
},
|
||||
|
||||
/**
|
||||
* The load event handler for the source editor. This method does post-load
|
||||
* editor initialization.
|
||||
*/
|
||||
_onEditorLoad: function DP__onEditorLoad() {
|
||||
// Connect to the debugger server.
|
||||
this.connect();
|
||||
},
|
||||
|
||||
/**
|
||||
* Closes the debugger UI removing child nodes and event listeners.
|
||||
*/
|
||||
close: function DP_close() {
|
||||
if (this._tab) {
|
||||
this._tab._scriptDebugger = null;
|
||||
this._tab = null;
|
||||
}
|
||||
if (this.frame) {
|
||||
DebuggerUIPreferences.height = this.frame.height;
|
||||
|
||||
this.frame.removeEventListener("unload", this._close, true);
|
||||
this.frame.removeEventListener("DebuggerClose", this._close, true);
|
||||
if (this.frame.parentNode) {
|
||||
this.frame.parentNode.removeChild(this.frame);
|
||||
}
|
||||
this.frame = null;
|
||||
}
|
||||
if (this._nbox) {
|
||||
this._nbox.removeChild(this._splitter);
|
||||
this._nbox = null;
|
||||
}
|
||||
|
||||
this._splitter = null;
|
||||
|
||||
if (this._client) {
|
||||
this._client.removeListener("newScript", this.onNewScript);
|
||||
this._client.removeListener("tabDetached", this._close);
|
||||
this._client.removeListener("tabNavigated", this._debugTab);
|
||||
this._client.close();
|
||||
this._client = null;
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Initializes a debugger client and connects it to the debugger server,
|
||||
* wiring event handlers as necessary.
|
||||
*/
|
||||
connect: function DP_connect() {
|
||||
this.frame.addEventListener("unload", this._close, true);
|
||||
|
||||
let transport = DebuggerServer.connectPipe();
|
||||
this._client = new DebuggerClient(transport);
|
||||
// Store the new script handler locally, so when it's time to remove it we
|
||||
// don't need to go through the iframe, since it might be cleared.
|
||||
this.onNewScript = this.debuggerWindow.SourceScripts.onNewScript;
|
||||
let self = this;
|
||||
this._client.addListener("tabNavigated", this._debugTab);
|
||||
this._client.addListener("tabDetached", this._close);
|
||||
this._client.addListener("newScript", this.onNewScript);
|
||||
this._client.connect(function(aType, aTraits) {
|
||||
self._client.listTabs(function(aResponse) {
|
||||
let tab = aResponse.tabs[aResponse.selected];
|
||||
self.debuggerWindow.startDebuggingTab(self._client, tab);
|
||||
if (self.onConnected) {
|
||||
self.onConnected(self);
|
||||
}
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Starts debugging the current tab. This function is called on each location
|
||||
* change in this tab.
|
||||
*/
|
||||
debugTab: function DP_debugTab(aNotification, aPacket) {
|
||||
let self = this;
|
||||
this._client.activeThread.detach(function() {
|
||||
self._client.activeTab.detach(function() {
|
||||
self._client.listTabs(function(aResponse) {
|
||||
let tab = aResponse.tabs[aResponse.selected];
|
||||
self.debuggerWindow.startDebuggingTab(self._client, tab);
|
||||
if (self.onConnected) {
|
||||
self.onConnected(self);
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
get debuggerWindow() {
|
||||
return this.frame.contentWindow;
|
||||
},
|
||||
|
||||
get debuggerClient() {
|
||||
return this._client;
|
||||
},
|
||||
|
||||
get activeThread() {
|
||||
try {
|
||||
return this.debuggerWindow.ThreadState.activeThread;
|
||||
} catch(ex) {
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
function DebuggerUI(aWindow) {
|
||||
this.aWindow = aWindow;
|
||||
|
||||
aWindow.addEventListener("Debugger:LoadSource", this._onLoadSource.bind(this));
|
||||
}
|
||||
|
||||
DebuggerUI.prototype = {
|
||||
/**
|
||||
* Starts the debugger or stops it, if it is already started.
|
||||
*/
|
||||
toggleDebugger: function DebuggerUI_toggleDebugger() {
|
||||
if (!DebuggerServer.initialized) {
|
||||
DebuggerServer.init();
|
||||
DebuggerServer.addBrowserActors();
|
||||
}
|
||||
|
||||
let gBrowser = this.aWindow.gBrowser;
|
||||
let tab = gBrowser.selectedTab;
|
||||
|
||||
if (tab._scriptDebugger) {
|
||||
// If the debugger is already open, just close it.
|
||||
tab._scriptDebugger.close();
|
||||
return tab._scriptDebugger;
|
||||
}
|
||||
|
||||
let pane = new DebuggerPane(tab);
|
||||
pane.create(gBrowser);
|
||||
return pane;
|
||||
},
|
||||
|
||||
getDebugger: function DebuggerUI_getDebugger(aTab) {
|
||||
return aTab._scriptDebugger;
|
||||
},
|
||||
|
||||
get preferences() {
|
||||
return DebuggerUIPreferences;
|
||||
},
|
||||
|
||||
/**
|
||||
* Handles notifications to load a source script from the cache or from a
|
||||
* local file.
|
||||
* XXX: it may be better to use nsITraceableChannel to get to the sources
|
||||
* without relying on caching when we can (not for eval, etc.):
|
||||
* http://www.softwareishard.com/blog/firebug/nsitraceablechannel-intercept-http-traffic/
|
||||
*/
|
||||
_onLoadSource: function DebuggerUI__onLoadSource(aEvent) {
|
||||
let gBrowser = this.aWindow.gBrowser;
|
||||
|
||||
let url = aEvent.detail;
|
||||
let scheme = Services.io.extractScheme(url);
|
||||
switch (scheme) {
|
||||
case "file":
|
||||
case "chrome":
|
||||
case "resource":
|
||||
try {
|
||||
NetUtil.asyncFetch(url, function onFetch(aStream, aStatus) {
|
||||
if (!Components.isSuccessCode(aStatus)) {
|
||||
return this.logError(url, aStatus);
|
||||
}
|
||||
let source = NetUtil.readInputStreamToString(aStream, aStream.available());
|
||||
aStream.close();
|
||||
this._onSourceLoaded(url, source);
|
||||
}.bind(this));
|
||||
} catch (ex) {
|
||||
return this.logError(url, ex.name);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
let channel = Services.io.newChannel(url, null, null);
|
||||
let chunks = [];
|
||||
let streamListener = { // nsIStreamListener inherits nsIRequestObserver
|
||||
onStartRequest: function (aRequest, aContext, aStatusCode) {
|
||||
if (!Components.isSuccessCode(aStatusCode)) {
|
||||
return this.logError(url, aStatusCode);
|
||||
}
|
||||
}.bind(this),
|
||||
onDataAvailable: function (aRequest, aContext, aStream, aOffset, aCount) {
|
||||
chunks.push(NetUtil.readInputStreamToString(aStream, aCount));
|
||||
},
|
||||
onStopRequest: function (aRequest, aContext, aStatusCode) {
|
||||
if (!Components.isSuccessCode(aStatusCode)) {
|
||||
return this.logError(url, aStatusCode);
|
||||
}
|
||||
|
||||
this._onSourceLoaded(url, chunks.join(""));
|
||||
}.bind(this)
|
||||
};
|
||||
|
||||
channel.loadFlags = channel.LOAD_FROM_CACHE;
|
||||
channel.asyncOpen(streamListener, null);
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Log an error message in the error console when a script fails to load.
|
||||
*
|
||||
* @param string aUrl
|
||||
* The URL of the source script.
|
||||
* @param string aStatus
|
||||
* The failure status code.
|
||||
*/
|
||||
logError: function DebuggerUI_logError(aUrl, aStatus) {
|
||||
let view = this.getDebugger(gBrowser.selectedTab).DebuggerView;
|
||||
Components.utils.reportError(view.getFormatStr("loadingError", [ aUrl, aStatus ]));
|
||||
},
|
||||
|
||||
/**
|
||||
* Called when source has been loaded.
|
||||
*
|
||||
* @param string aSourceUrl
|
||||
* The URL of the source script.
|
||||
* @param string aSourceText
|
||||
* The text of the source script.
|
||||
*/
|
||||
_onSourceLoaded: function DebuggerUI__onSourceLoaded(aSourceUrl, aSourceText) {
|
||||
let dbg = this.getDebugger(this.aWindow.gBrowser.selectedTab);
|
||||
if (aSourceUrl.slice(-3) == ".js") {
|
||||
dbg.editor.setMode(SourceEditor.MODES.JAVASCRIPT);
|
||||
} else {
|
||||
dbg.editor.setMode(SourceEditor.MODES.HTML);
|
||||
}
|
||||
dbg.editor.setText(aSourceText);
|
||||
let doc = dbg.frame.contentDocument;
|
||||
let scripts = doc.getElementById("scripts");
|
||||
let elt = scripts.getElementsByAttribute("value", aSourceUrl)[0];
|
||||
let script = elt.getUserData("sourceScript");
|
||||
script.loaded = true;
|
||||
script.text = aSourceText;
|
||||
elt.setUserData("sourceScript", script, null);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Various debugger UI preferences (currently just the pane height).
|
||||
*/
|
||||
let DebuggerUIPreferences = {
|
||||
|
||||
_height: -1,
|
||||
|
||||
/**
|
||||
* Gets the preferred height of the debugger pane.
|
||||
*
|
||||
* @return number
|
||||
* The preferred height.
|
||||
*/
|
||||
get height() {
|
||||
if (this._height < 0) {
|
||||
this._height = Services.prefs.getIntPref("devtools.debugger.ui.height");
|
||||
}
|
||||
return this._height;
|
||||
},
|
||||
|
||||
/**
|
||||
* Sets the preferred height of the debugger pane.
|
||||
*
|
||||
* @param number value
|
||||
* The new height.
|
||||
*/
|
||||
set height(value) {
|
||||
Services.prefs.setIntPref("devtools.debugger.ui.height", value);
|
||||
this._height = value;
|
||||
}
|
||||
};
|
|
@ -0,0 +1,53 @@
|
|||
# ***** BEGIN LICENSE BLOCK *****
|
||||
# Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
#
|
||||
# The contents of this file are subject to the Mozilla Public License Version
|
||||
# 1.1 (the "License"); you may not use this file except in compliance with
|
||||
# the License. You may obtain a copy of the License at
|
||||
# http://www.mozilla.org/MPL/
|
||||
#
|
||||
# Software distributed under the License is distributed on an "AS IS" basis,
|
||||
# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
# for the specific language governing rights and limitations under the
|
||||
# License.
|
||||
#
|
||||
# The Original Code is Mozilla Debugger UI code.
|
||||
#
|
||||
# The Initial Developer of the Original Code is
|
||||
# Mozilla Foundation
|
||||
# Portions created by the Initial Developer are Copyright (C) 2011
|
||||
# the Initial Developer. All Rights Reserved.
|
||||
#
|
||||
# Contributor(s):
|
||||
# Dave Camp <dcamp@mozilla.com>
|
||||
# Victor Porof <vporof@mozilla.com>
|
||||
#
|
||||
# Alternatively, the contents of this file may be used under the terms of
|
||||
# either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
# in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
# of those above. If you wish to allow use of your version of this file only
|
||||
# under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
# use your version of this file under the terms of the MPL, indicate your
|
||||
# decision by deleting the provisions above and replace them with the notice
|
||||
# and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
# the provisions above, a recipient may use your version of this file under
|
||||
# the terms of any one of the MPL, the GPL or the LGPL.
|
||||
#
|
||||
# ***** END LICENSE BLOCK *****
|
||||
|
||||
DEPTH = ../../..
|
||||
topsrcdir = @top_srcdir@
|
||||
srcdir = @srcdir@
|
||||
VPATH = @srcdir@
|
||||
|
||||
include $(DEPTH)/config/autoconf.mk
|
||||
|
||||
ifdef ENABLE_TESTS
|
||||
DIRS += test
|
||||
endif
|
||||
|
||||
include $(topsrcdir)/config/rules.mk
|
||||
|
||||
libs::
|
||||
$(NSINSTALL) $(srcdir)/*.jsm $(FINAL_TARGET)/modules/devtools
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -0,0 +1,173 @@
|
|||
/* -*- Mode: javascript; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is mozilla.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Mozilla Foundation
|
||||
* Portions created by the Initial Developer are Copyright (C) 2011
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Dave Camp <dcamp@mozilla.com>
|
||||
* Victor Porof <vporof@mozilla.com>
|
||||
* Panos Astithas <past@mozilla.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
/**
|
||||
* Debugger content
|
||||
*/
|
||||
|
||||
#dbg-content > * > .vbox {
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
/**
|
||||
* Debugger statusbar
|
||||
*/
|
||||
|
||||
#dbg-statusbar {
|
||||
-moz-appearance: statusbar;
|
||||
}
|
||||
|
||||
/**
|
||||
* Stack frames
|
||||
*/
|
||||
|
||||
#stack {
|
||||
width: 200px;
|
||||
}
|
||||
|
||||
#stackframes {
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
/**
|
||||
* Properties elements
|
||||
*/
|
||||
|
||||
#properties {
|
||||
width: 250px;
|
||||
}
|
||||
|
||||
#variables {
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
/**
|
||||
* Scope element
|
||||
*/
|
||||
|
||||
.scope {
|
||||
display: -moz-box;
|
||||
-moz-box-orient: vertical;
|
||||
}
|
||||
|
||||
.scope > .details {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.scope > .details[open] {
|
||||
display: -moz-box;
|
||||
-moz-box-orient: vertical;
|
||||
}
|
||||
|
||||
/**
|
||||
* Variable element
|
||||
*/
|
||||
|
||||
.variable {
|
||||
display: -moz-box;
|
||||
-moz-box-orient: vertical;
|
||||
}
|
||||
|
||||
.variable > .title {
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.variable > .details {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.variable > .details[open] {
|
||||
display: -moz-box;
|
||||
-moz-box-orient: vertical;
|
||||
}
|
||||
|
||||
/**
|
||||
* Property element
|
||||
*/
|
||||
|
||||
.property {
|
||||
display: -moz-box;
|
||||
-moz-box-orient: vertical;
|
||||
}
|
||||
|
||||
.property > .title {
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.property > .title > .key {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.property > .title > .value {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.property > .details {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.property > .details[open] {
|
||||
display: -moz-box;
|
||||
-moz-box-orient: vertical;
|
||||
}
|
||||
|
||||
/**
|
||||
* Display helpers
|
||||
*/
|
||||
|
||||
.hbox {
|
||||
display: -moz-box;
|
||||
-moz-box-orient: horizontal;
|
||||
}
|
||||
|
||||
.vbox {
|
||||
display: -moz-box;
|
||||
-moz-box-orient: vertical;
|
||||
}
|
||||
|
||||
.flex {
|
||||
-moz-box-flex: 1;
|
||||
}
|
||||
|
||||
.unselectable {
|
||||
-moz-user-select: -moz-none;
|
||||
cursor: default;
|
||||
}
|
|
@ -0,0 +1,513 @@
|
|||
/* -*- Mode: javascript; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is mozilla.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Mozilla Foundation
|
||||
* Portions created by the Initial Developer are Copyright (C) 2011
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Dave Camp <dcamp@mozilla.com>
|
||||
* Panos Astithas <past@mozilla.com>
|
||||
* Victor Porof <vporof@mozilla.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
"use strict";
|
||||
|
||||
var gInitialized = false;
|
||||
var gClient = null;
|
||||
var gTabClient = null;
|
||||
|
||||
|
||||
function initDebugger()
|
||||
{
|
||||
window.removeEventListener("DOMContentLoaded", initDebugger, false);
|
||||
if (gInitialized) {
|
||||
return;
|
||||
}
|
||||
gInitialized = true;
|
||||
|
||||
DebuggerView.Stackframes.initialize();
|
||||
DebuggerView.Properties.initialize();
|
||||
DebuggerView.Scripts.initialize();
|
||||
}
|
||||
|
||||
/**
|
||||
* Called by chrome to set up a debugging session.
|
||||
*
|
||||
* @param DebuggerClient aClient
|
||||
* The debugger client.
|
||||
* @param object aTabGrip
|
||||
* The remote protocol grip of the tab.
|
||||
*/
|
||||
function startDebuggingTab(aClient, aTabGrip)
|
||||
{
|
||||
gClient = aClient;
|
||||
|
||||
gClient.attachTab(aTabGrip.actor, function(aResponse, aTabClient) {
|
||||
if (aTabClient) {
|
||||
gTabClient = aTabClient;
|
||||
gClient.attachThread(aResponse.threadActor, function(aResponse, aThreadClient) {
|
||||
if (!aThreadClient) {
|
||||
dump("Couldn't attach to thread: "+aResponse.error+"\n");
|
||||
return;
|
||||
}
|
||||
ThreadState.connect(aThreadClient, function() {
|
||||
StackFrames.connect(aThreadClient, function() {
|
||||
SourceScripts.connect(aThreadClient, function() {
|
||||
aThreadClient.resume();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function shutdownDebugger()
|
||||
{
|
||||
window.removeEventListener("unload", shutdownDebugger, false);
|
||||
|
||||
SourceScripts.disconnect();
|
||||
StackFrames.disconnect();
|
||||
ThreadState.disconnect();
|
||||
ThreadState.activeThread = false;
|
||||
|
||||
DebuggerView.Stackframes.destroy();
|
||||
DebuggerView.Properties.destroy();
|
||||
DebuggerView.Scripts.destroy();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* ThreadState keeps the UI up to date with the state of the
|
||||
* thread (paused/attached/etc.).
|
||||
*/
|
||||
var ThreadState = {
|
||||
activeThread: null,
|
||||
|
||||
/**
|
||||
* Connect to a thread client.
|
||||
* @param object aThreadClient
|
||||
* The thread client.
|
||||
* @param function aCallback
|
||||
* The next function in the initialization sequence.
|
||||
*/
|
||||
connect: function TS_connect(aThreadClient, aCallback) {
|
||||
this.activeThread = aThreadClient;
|
||||
aThreadClient.addListener("paused", ThreadState.update);
|
||||
aThreadClient.addListener("resumed", ThreadState.update);
|
||||
aThreadClient.addListener("detached", ThreadState.update);
|
||||
this.update();
|
||||
aCallback && aCallback();
|
||||
},
|
||||
|
||||
/**
|
||||
* Update the UI after a thread state change.
|
||||
*/
|
||||
update: function TS_update(aEvent) {
|
||||
DebuggerView.Stackframes.updateState(this.activeThread.state);
|
||||
if (aEvent == "detached") {
|
||||
ThreadState.activeThread = false;
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Disconnect from the client.
|
||||
*/
|
||||
disconnect: function TS_disconnect() {
|
||||
this.activeThread.removeListener("paused", ThreadState.update);
|
||||
this.activeThread.removeListener("resumed", ThreadState.update);
|
||||
this.activeThread.removeListener("detached", ThreadState.update);
|
||||
}
|
||||
};
|
||||
|
||||
ThreadState.update = ThreadState.update.bind(ThreadState);
|
||||
|
||||
/**
|
||||
* Keeps the stack frame list up-to-date, using the thread client's
|
||||
* stack frame cache.
|
||||
*/
|
||||
var StackFrames = {
|
||||
pageSize: 25,
|
||||
activeThread: null,
|
||||
selectedFrame: null,
|
||||
|
||||
/**
|
||||
* Watch a given thread client.
|
||||
* @param object aThreadClient
|
||||
* The thread client.
|
||||
* @param function aCallback
|
||||
* The next function in the initialization sequence.
|
||||
*/
|
||||
connect: function SF_connect(aThreadClient, aCallback) {
|
||||
DebuggerView.Stackframes.addClickListener(this.onClick);
|
||||
|
||||
this.activeThread = aThreadClient;
|
||||
aThreadClient.addListener("paused", this.onPaused);
|
||||
aThreadClient.addListener("framesadded", this.onFrames);
|
||||
aThreadClient.addListener("framescleared", this.onFramesCleared);
|
||||
this.onFramesCleared();
|
||||
aCallback && aCallback();
|
||||
},
|
||||
|
||||
/**
|
||||
* Disconnect from the client.
|
||||
*/
|
||||
disconnect: function TS_disconnect() {
|
||||
this.activeThread.removeListener("paused", this.onPaused);
|
||||
this.activeThread.removeListener("framesadded", this.onFrames);
|
||||
this.activeThread.removeListener("framescleared", this.onFramesCleared);
|
||||
},
|
||||
|
||||
/**
|
||||
* Handler for the thread client's paused notification.
|
||||
*/
|
||||
onPaused: function SF_onPaused() {
|
||||
this.activeThread.fillFrames(this.pageSize);
|
||||
},
|
||||
|
||||
/**
|
||||
* Handler for the thread client's framesadded notification.
|
||||
*/
|
||||
onFrames: function SF_onFrames() {
|
||||
DebuggerView.Stackframes.empty();
|
||||
|
||||
for each (let frame in this.activeThread.cachedFrames) {
|
||||
this._addFramePanel(frame);
|
||||
}
|
||||
|
||||
if (this.activeThread.moreFrames) {
|
||||
DebuggerView.Stackframes.dirty = true;
|
||||
}
|
||||
|
||||
if (!this.selectedFrame) {
|
||||
this.selectFrame(0);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Handler for the thread client's framescleared notification.
|
||||
*/
|
||||
onFramesCleared: function SF_onFramesCleared() {
|
||||
DebuggerView.Stackframes.emptyText();
|
||||
this.selectedFrame = null;
|
||||
// Clear the properties as well.
|
||||
DebuggerView.Properties.localScope.empty();
|
||||
DebuggerView.Properties.globalScope.empty();
|
||||
},
|
||||
|
||||
/**
|
||||
* Event handler for clicks on stack frames.
|
||||
*/
|
||||
onClick: function SF_onClick(aEvent) {
|
||||
let target = aEvent.target;
|
||||
while (target) {
|
||||
if (target.stackFrame) {
|
||||
this.selectFrame(target.stackFrame.depth);
|
||||
return;
|
||||
}
|
||||
target = target.parentNode;
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Marks the stack frame in the specified depth as selected and updates the
|
||||
* properties view with the stack frame's data.
|
||||
*
|
||||
* @param number aDepth
|
||||
* The depth of the frame in the stack.
|
||||
*/
|
||||
selectFrame: function SF_selectFrame(aDepth) {
|
||||
if (this.selectedFrame !== null) {
|
||||
DebuggerView.Stackframes.highlightFrame(this.selectedFrame, false);
|
||||
}
|
||||
|
||||
this.selectedFrame = aDepth;
|
||||
if (aDepth !== null) {
|
||||
DebuggerView.Stackframes.highlightFrame(this.selectedFrame, true);
|
||||
}
|
||||
|
||||
// Display the local variables.
|
||||
let frame = this.activeThread.cachedFrames[aDepth];
|
||||
if (!frame) {
|
||||
return;
|
||||
}
|
||||
let localScope = DebuggerView.Properties.localScope;
|
||||
localScope.empty();
|
||||
// Add "this".
|
||||
if (frame["this"]) {
|
||||
let thisVar = localScope.addVar("this");
|
||||
thisVar.setGrip({ "type": frame["this"].type,
|
||||
"class": frame["this"].class });
|
||||
this._addExpander(thisVar, frame["this"]);
|
||||
}
|
||||
|
||||
if (frame.arguments && frame.arguments.length > 0) {
|
||||
// Add "arguments".
|
||||
let argsVar = localScope.addVar("arguments");
|
||||
argsVar.setGrip({ "type": "object", "class": "Arguments" });
|
||||
this._addExpander(argsVar, frame.arguments);
|
||||
|
||||
// Add variables for every argument.
|
||||
let objClient = this.activeThread.pauseGrip(frame.callee);
|
||||
objClient.getSignature(function SF_getSignature(aResponse) {
|
||||
for (let i = 0; i < aResponse.parameters.length; i++) {
|
||||
let param = aResponse.parameters[i];
|
||||
let paramVar = localScope.addVar(param);
|
||||
let paramVal = frame.arguments[i];
|
||||
paramVar.setGrip(paramVal);
|
||||
this._addExpander(paramVar, paramVal);
|
||||
}
|
||||
}.bind(this));
|
||||
}
|
||||
},
|
||||
|
||||
_addExpander: function SF_addExpander(aVar, aObject) {
|
||||
// No need for expansion for null and undefined values, but we do need them
|
||||
// for frame.arguments which is a regular array.
|
||||
if (!aObject || typeof aObject != "object" ||
|
||||
(aObject.type != "object" && !Array.isArray(aObject))) {
|
||||
return;
|
||||
}
|
||||
// Add a dummy property to force the twisty to show up.
|
||||
aVar.addProperties({ " ": { value: " " }});
|
||||
aVar.onexpand = this._addVarProperties.bind(this, aVar, aObject);
|
||||
},
|
||||
|
||||
_addVarProperties: function SF_addVarProperties(aVar, aObject) {
|
||||
// Retrieve the properties only once.
|
||||
if (aVar.fetched) {
|
||||
return;
|
||||
}
|
||||
// Clear the placeholder property put in place to display the twisty.
|
||||
aVar.empty();
|
||||
|
||||
// For arrays we have to construct a grip-like object to pass into
|
||||
// addProperties.
|
||||
if (Array.isArray(aObject)) {
|
||||
let properties = { length: { writable: true, value: aObject.length } };
|
||||
for (let i = 0; i < aObject.length; i++) {
|
||||
properties[i + ""] = { value: aObject[i] };
|
||||
}
|
||||
aVar.addProperties(properties);
|
||||
// Expansion handlers must be set after the properties are added.
|
||||
for (let i = 0; i < aObject.length; i++) {
|
||||
this._addExpander(aVar[i + ""], aObject[i]);
|
||||
}
|
||||
aVar.fetched = true;
|
||||
return;
|
||||
}
|
||||
|
||||
let objClient = this.activeThread.pauseGrip(aObject);
|
||||
objClient.getPrototypeAndProperties(function SF_onProtoAndProps(aResponse) {
|
||||
// Add __proto__.
|
||||
if (aResponse.prototype.type != "null") {
|
||||
let properties = {};
|
||||
properties["__proto__ "] = { value: aResponse.prototype };
|
||||
aVar.addProperties(properties);
|
||||
// Expansion handlers must be set after the properties are added.
|
||||
this._addExpander(aVar["__proto__ "], aResponse.prototype);
|
||||
}
|
||||
|
||||
// Sort the rest of the properties before adding them, for better UX.
|
||||
let properties = {};
|
||||
for each (let prop in Object.keys(aResponse.ownProperties).sort()) {
|
||||
properties[prop] = aResponse.ownProperties[prop];
|
||||
}
|
||||
aVar.addProperties(properties);
|
||||
// Expansion handlers must be set after the properties are added.
|
||||
for (let prop in aResponse.ownProperties) {
|
||||
this._addExpander(aVar[prop], aResponse.ownProperties[prop].value);
|
||||
}
|
||||
|
||||
aVar.fetched = true;
|
||||
}.bind(this));
|
||||
},
|
||||
|
||||
/**
|
||||
* Adds the specified stack frame to the list.
|
||||
*
|
||||
* @param Debugger.Frame aFrame
|
||||
* The new frame to add.
|
||||
*/
|
||||
_addFramePanel: function SF_addFramePanel(aFrame) {
|
||||
let depth = aFrame.depth;
|
||||
let idText = "#" + aFrame.depth + " ";
|
||||
let nameText = this._frameTitle(aFrame);
|
||||
|
||||
let panel = DebuggerView.Stackframes.addFrame(depth, idText, nameText);
|
||||
|
||||
if (panel) {
|
||||
panel.stackFrame = aFrame;
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Loads more stack frames from the debugger server cache.
|
||||
*/
|
||||
_addMoreFrames: function SF_addMoreFrames() {
|
||||
this.activeThread.fillFrames(
|
||||
this.activeThread.cachedFrames.length + this.pageSize);
|
||||
},
|
||||
|
||||
/**
|
||||
* Create a textual representation for the stack frame specified, for
|
||||
* displaying in the stack frame list.
|
||||
*
|
||||
* @param Debugger.Frame aFrame
|
||||
* The stack frame to label.
|
||||
*/
|
||||
_frameTitle: function SF_frameTitle(aFrame) {
|
||||
if (aFrame.type == "call") {
|
||||
return aFrame["calleeName"] ? aFrame["calleeName"] + "()" : "(anonymous)";
|
||||
}
|
||||
|
||||
return "(" + aFrame.type + ")";
|
||||
}
|
||||
};
|
||||
|
||||
StackFrames.onPaused = StackFrames.onPaused.bind(StackFrames);
|
||||
StackFrames.onFrames = StackFrames.onFrames.bind(StackFrames);
|
||||
StackFrames.onFramesCleared = StackFrames.onFramesCleared.bind(StackFrames);
|
||||
StackFrames.onClick = StackFrames.onClick.bind(StackFrames);
|
||||
|
||||
/**
|
||||
* Keeps the source script list up-to-date, using the thread client's
|
||||
* source script cache.
|
||||
*/
|
||||
var SourceScripts = {
|
||||
pageSize: 25,
|
||||
activeThread: null,
|
||||
|
||||
/**
|
||||
* Watch a given thread client.
|
||||
* @param object aThreadClient
|
||||
* The thread client.
|
||||
* @param function aCallback
|
||||
* The next function in the initialization sequence.
|
||||
*/
|
||||
connect: function SS_connect(aThreadClient, aCallback) {
|
||||
DebuggerView.Scripts.addChangeListener(this.onChange);
|
||||
|
||||
this.activeThread = aThreadClient;
|
||||
aThreadClient.addListener("paused", this.onPaused);
|
||||
aThreadClient.addListener("scriptsadded", this.onScripts);
|
||||
aThreadClient.addListener("scriptscleared", this.onScriptsCleared);
|
||||
this.onScriptsCleared();
|
||||
aCallback && aCallback();
|
||||
},
|
||||
|
||||
/**
|
||||
* Disconnect from the client.
|
||||
*/
|
||||
disconnect: function TS_disconnect() {
|
||||
this.activeThread.removeListener("paused", this.onPaused);
|
||||
this.activeThread.removeListener("scriptsadded", this.onScripts);
|
||||
this.activeThread.removeListener("scriptscleared", this.onScriptsCleared);
|
||||
},
|
||||
|
||||
/**
|
||||
* Handler for the thread client's paused notification.
|
||||
*/
|
||||
onPaused: function SS_onPaused() {
|
||||
this.activeThread.fillScripts();
|
||||
},
|
||||
|
||||
/**
|
||||
* Handler for the debugger client's unsolicited newScript notification.
|
||||
*/
|
||||
onNewScript: function SS_onNewScript(aNotification, aPacket) {
|
||||
this._addScript({ url: aPacket.url, startLine: aPacket.startLine });
|
||||
},
|
||||
|
||||
/**
|
||||
* Handler for the thread client's scriptsadded notification.
|
||||
*/
|
||||
onScripts: function SS_onScripts() {
|
||||
this.onScriptsCleared();
|
||||
for each (let script in this.activeThread.cachedScripts) {
|
||||
this._addScript(script);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Handler for the thread client's scriptscleared notification.
|
||||
*/
|
||||
onScriptsCleared: function SS_onScriptsCleared() {
|
||||
DebuggerView.Scripts.empty();
|
||||
},
|
||||
|
||||
/**
|
||||
* Handler for changes on the selected source script.
|
||||
*/
|
||||
onChange: function SS_onClick(aEvent) {
|
||||
let scripts = aEvent.target;
|
||||
let script = scripts.selectedItem.getUserData("sourceScript");
|
||||
this._showScript(script);
|
||||
},
|
||||
|
||||
/**
|
||||
* Add the specified script to the list and display it in the editor if the
|
||||
* editor is empty.
|
||||
*/
|
||||
_addScript: function SS_addScript(aScript) {
|
||||
DebuggerView.Scripts.addScript(aScript.url, aScript);
|
||||
|
||||
if (window.editor.getCharCount() == 0) {
|
||||
this._showScript(aScript);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Load the editor with the script text if available, otherwise fire an event
|
||||
* to load and display the script text.
|
||||
*/
|
||||
_showScript: function SS_showScript(aScript) {
|
||||
if (!aScript.loaded) {
|
||||
// Notify the chrome code that we need to load a script file.
|
||||
var evt = document.createEvent("CustomEvent");
|
||||
evt.initCustomEvent("Debugger:LoadSource", true, false, aScript.url);
|
||||
document.documentElement.dispatchEvent(evt);
|
||||
window.editor.setText(DebuggerView.getStr("loadingText"));
|
||||
} else {
|
||||
window.editor.setText(aScript.text);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
SourceScripts.onPaused = SourceScripts.onPaused.bind(SourceScripts);
|
||||
SourceScripts.onScripts = SourceScripts.onScripts.bind(SourceScripts);
|
||||
SourceScripts.onNewScript = SourceScripts.onNewScript.bind(SourceScripts);
|
||||
SourceScripts.onScriptsCleared = SourceScripts.onScriptsCleared.bind(SourceScripts);
|
||||
SourceScripts.onChange = SourceScripts.onChange.bind(SourceScripts);
|
||||
|
||||
window.addEventListener("DOMContentLoaded", initDebugger, false);
|
||||
window.addEventListener("unload", shutdownDebugger, false);
|
|
@ -0,0 +1,78 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- ***** BEGIN LICENSE BLOCK *****
|
||||
- Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
-
|
||||
- The contents of this file are subject to the Mozilla Public License Version
|
||||
- 1.1 (the "License"); you may not use this file except in compliance with
|
||||
- the License. You may obtain a copy of the License at
|
||||
- http://www.mozilla.org/MPL/
|
||||
-
|
||||
- Software distributed under the License is distributed on an "AS IS" basis,
|
||||
- WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
- for the specific language governing rights and limitations under the
|
||||
- License.
|
||||
-
|
||||
- The Original Code is mozilla.org code.
|
||||
-
|
||||
- The Initial Developer of the Original Code is
|
||||
- Mozilla Foundation.
|
||||
- Portions created by the Initial Developer are Copyright (C) 2011
|
||||
- the Initial Developer. All Rights Reserved.
|
||||
-
|
||||
- Contributor(s):
|
||||
- Dave Camp <dcamp@mozilla.com>
|
||||
- Panos Astithas <past@mozilla.com>
|
||||
- Victor Porof <vporof@mozilla.com>
|
||||
-
|
||||
- Alternatively, the contents of this file may be used under the terms of
|
||||
- either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
- the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
- in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
- of those above. If you wish to allow use of your version of this file only
|
||||
- under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
- use your version of this file under the terms of the MPL, indicate your
|
||||
- decision by deleting the provisions above and replace them with the notice
|
||||
- and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
- the provisions above, a recipient may use your version of this file under
|
||||
- the terms of any one of the MPL, the GPL or the LGPL.
|
||||
-
|
||||
- ***** END LICENSE BLOCK ***** -->
|
||||
<?xml-stylesheet href="chrome://browser/skin/" type="text/css"?>
|
||||
<?xml-stylesheet href="chrome://browser/content/orion.css" type="text/css"?>
|
||||
<?xml-stylesheet href="chrome://browser/content/debugger.css" type="text/css"?>
|
||||
<?xml-stylesheet href="chrome://browser/skin/devtools/debugger.css" type="text/css"?>
|
||||
<!DOCTYPE window [
|
||||
<!ENTITY % debuggerDTD SYSTEM "chrome://browser/locale/devtools/debugger.dtd" >
|
||||
%debuggerDTD;
|
||||
]>
|
||||
<xul:window xmlns="http://www.w3.org/1999/xhtml"
|
||||
xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
|
||||
<xul:script type="text/javascript" src="debugger.js"/>
|
||||
<xul:script type="text/javascript" src="debugger-view.js"/>
|
||||
|
||||
<div id="body" class="vbox flex">
|
||||
<xul:toolbar id="dbg-toolbar">
|
||||
<xul:button id="close">&debuggerUI.closeButton;</xul:button>
|
||||
<xul:button id="resume">&debuggerUI.resumeButton;</xul:button>
|
||||
<xul:menulist id="scripts"/>
|
||||
</xul:toolbar>
|
||||
<div id="dbg-content" class="hbox flex">
|
||||
<div id="stack" class="vbox">
|
||||
<div class="title unselectable">&debuggerUI.stackTitle;</div>
|
||||
<div id="stackframes" class="vbox flex"></div>
|
||||
</div>
|
||||
<div id="script" class="vbox flex">
|
||||
<div class="title unselectable">&debuggerUI.scriptTitle;</div>
|
||||
<div id="editor" class="vbox flex"></div>
|
||||
</div>
|
||||
<div id="properties" class="vbox">
|
||||
<div class="title unselectable">&debuggerUI.propertiesTitle;</div>
|
||||
<div id="variables" class="vbox flex"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="dbg-statusbar">
|
||||
<span id="status"></span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</xul:window>
|
|
@ -0,0 +1,90 @@
|
|||
# ***** BEGIN LICENSE BLOCK *****
|
||||
# Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
#
|
||||
# The contents of this file are subject to the Mozilla Public License Version
|
||||
# 1.1 (the "License"); you may not use this file except in compliance with
|
||||
# the License. You may obtain a copy of the License at
|
||||
# http://www.mozilla.org/MPL/
|
||||
#
|
||||
# Software distributed under the License is distributed on an "AS IS" basis,
|
||||
# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
# for the specific language governing rights and limitations under the
|
||||
# License.
|
||||
#
|
||||
# The Original Code is mozilla.org code.
|
||||
#
|
||||
# The Initial Developer of the Original Code is
|
||||
# Mozilla Foundation
|
||||
# Portions created by the Initial Developer are Copyright (C) 2011
|
||||
# the Initial Developer. All Rights Reserved.
|
||||
#
|
||||
# Contributor(s):
|
||||
# Dave Camp <dcamp@mozilla.com>
|
||||
# Victor Porof <vporof@mozilla.com>
|
||||
#
|
||||
# Alternatively, the contents of this file may be used under the terms of
|
||||
# either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
# in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
# of those above. If you wish to allow use of your version of this file only
|
||||
# under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
# use your version of this file under the terms of the MPL, indicate your
|
||||
# decision by deleting the provisions above and replace them with the notice
|
||||
# and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
# the provisions above, a recipient may use your version of this file under
|
||||
# the terms of any one of the MPL, the GPL or the LGPL.
|
||||
#
|
||||
# ***** END LICENSE BLOCK *****
|
||||
|
||||
DEPTH = ../../../..
|
||||
topsrcdir = @top_srcdir@
|
||||
srcdir = @srcdir@
|
||||
VPATH = @srcdir@
|
||||
relativesrcdir = browser/devtools/debugger/test
|
||||
|
||||
include $(DEPTH)/config/autoconf.mk
|
||||
include $(topsrcdir)/config/rules.mk
|
||||
|
||||
_BROWSER_TEST_FILES = \
|
||||
browser_dbg_debuggerstatement.js \
|
||||
browser_dbg_listtabs.js \
|
||||
browser_dbg_tabactor-01.js \
|
||||
browser_dbg_tabactor-02.js \
|
||||
browser_dbg_contextactor-01.js \
|
||||
browser_dbg_contextactor-02.js \
|
||||
testactors.js \
|
||||
browser_dbg_nav-01.js \
|
||||
browser_dbg_propertyview-01.js \
|
||||
browser_dbg_propertyview-02.js \
|
||||
browser_dbg_propertyview-03.js \
|
||||
browser_dbg_propertyview-04.js \
|
||||
browser_dbg_propertyview-05.js \
|
||||
browser_dbg_propertyview-06.js \
|
||||
browser_dbg_propertyview-07.js \
|
||||
browser_dbg_propertyview-08.js \
|
||||
browser_dbg_panesize.js \
|
||||
browser_dbg_stack-01.js \
|
||||
browser_dbg_stack-02.js \
|
||||
browser_dbg_stack-03.js \
|
||||
browser_dbg_stack-04.js \
|
||||
browser_dbg_location-changes.js \
|
||||
browser_dbg_script-switching.js \
|
||||
head.js \
|
||||
$(NULL)
|
||||
|
||||
_BROWSER_TEST_PAGES = \
|
||||
browser_dbg_tab1.html \
|
||||
browser_dbg_tab2.html \
|
||||
browser_dbg_debuggerstatement.html \
|
||||
browser_dbg_stack.html \
|
||||
browser_dbg_script-switching.html \
|
||||
test-script-switching-01.js \
|
||||
test-script-switching-02.js \
|
||||
browser_dbg_frame-parameters.html \
|
||||
$(NULL)
|
||||
|
||||
libs:: $(_BROWSER_TEST_FILES)
|
||||
$(INSTALL) $(foreach f,$^,"$f") $(DEPTH)/_tests/testing/mochitest/browser/$(relativesrcdir)
|
||||
|
||||
libs:: $(_BROWSER_TEST_PAGES)
|
||||
$(INSTALL) $(foreach f,$^,"$f") $(DEPTH)/_tests/testing/mochitest/browser/$(relativesrcdir)
|
|
@ -0,0 +1,49 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
/**
|
||||
* Check extension-added context actor lifetimes.
|
||||
*/
|
||||
|
||||
var gTab1 = null;
|
||||
var gTab1Actor = null;
|
||||
|
||||
var gClient = null;
|
||||
|
||||
function test()
|
||||
{
|
||||
DebuggerServer.addActors("chrome://mochitests/content/browser/browser/devtools/debugger/test/testactors.js");
|
||||
|
||||
let transport = DebuggerServer.connectPipe();
|
||||
gClient = new DebuggerClient(transport);
|
||||
gClient.connect(function(aType, aTraits) {
|
||||
is(aType, "browser", "Root actor should identify itself as a browser.");
|
||||
get_tab();
|
||||
});
|
||||
}
|
||||
|
||||
function get_tab()
|
||||
{
|
||||
gTab1 = addTab(TAB1_URL, function() {
|
||||
attach_tab_actor_for_url(gClient, TAB1_URL, function(aGrip) {
|
||||
gTab1Actor = aGrip.actor;
|
||||
gClient.request({ to: aGrip.actor, type: "testContextActor1" }, function(aResponse) {
|
||||
ok(aResponse.actor, "testContextActor1 request should return an actor.");
|
||||
ok(aResponse.actor.indexOf("testone") >= 0,
|
||||
"testContextActor's actorPrefix should be used.");
|
||||
gClient.request({ to: aResponse.actor, type: "ping" }, function(aResponse) {
|
||||
is(aResponse.pong, "pong", "Actor should response to requests.");
|
||||
finish_test();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function finish_test()
|
||||
{
|
||||
gClient.close(function() {
|
||||
removeTab(gTab1);
|
||||
finish();
|
||||
});
|
||||
};
|
|
@ -0,0 +1,59 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
/**
|
||||
* Check extension-added context actor lifetimes.
|
||||
*/
|
||||
|
||||
var gTab1 = null;
|
||||
var gTab1Actor = null;
|
||||
|
||||
var gClient = null;
|
||||
|
||||
function test()
|
||||
{
|
||||
DebuggerServer.addActors("chrome://mochitests/content/browser/browser/devtools/debugger/test/testactors.js");
|
||||
|
||||
let transport = DebuggerServer.connectPipe();
|
||||
gClient = new DebuggerClient(transport);
|
||||
gClient.connect(function(aType, aTraits) {
|
||||
is(aType, "browser", "Root actor should identify itself as a browser.");
|
||||
get_tab();
|
||||
});
|
||||
}
|
||||
|
||||
function get_tab()
|
||||
{
|
||||
gTab1 = addTab(TAB1_URL, function() {
|
||||
get_tab_actor_for_url(gClient, TAB1_URL, function(aGrip) {
|
||||
gTab1Actor = aGrip.actor;
|
||||
gClient.request({ to: gTab1Actor, type: "attach" }, function(aResponse) {
|
||||
gClient.request({ to: gTab1Actor, type: "testContextActor1" }, function(aResponse) {
|
||||
navigate_tab(aResponse.actor);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function navigate_tab(aTestActor)
|
||||
{
|
||||
gClient.addOneTimeListener("tabNavigated", function(aEvent, aResponse) {
|
||||
gClient.request({ to: aTestActor, type: "ping" }, function(aResponse) {
|
||||
// TODO: Currently the client is supposed to clean up after tabNavigated
|
||||
// events. We should remove this check, or even better, remove the whole
|
||||
// test.
|
||||
todo(aResponse.error, "noSuchActor", "testContextActor1 should have gone away with the navigation.");
|
||||
finish_test();
|
||||
});
|
||||
});
|
||||
gTab1.linkedBrowser.loadURI(TAB2_URL);
|
||||
}
|
||||
|
||||
function finish_test()
|
||||
{
|
||||
gClient.close(function() {
|
||||
removeTab(gTab1);
|
||||
finish();
|
||||
});
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head><title>Browser Debugger Test Tab</title>
|
||||
<!-- Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ -->
|
||||
<script type="text/javascript">
|
||||
|
||||
function runDebuggerStatement()
|
||||
{
|
||||
debugger;
|
||||
}
|
||||
|
||||
</script>
|
||||
</head>
|
||||
|
||||
<body></body>
|
||||
|
||||
</html>
|
|
@ -0,0 +1,72 @@
|
|||
/* vim:set ts=2 sw=2 sts=2 et: */
|
||||
/*
|
||||
* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/
|
||||
*/
|
||||
|
||||
// Tests the behavior of the debugger statement.
|
||||
|
||||
var gClient = null;
|
||||
var gTab = null;
|
||||
const DEBUGGER_TAB_URL = "http://example.com/browser/browser/devtools/" +
|
||||
"debugger/test/" +
|
||||
"browser_dbg_debuggerstatement.html";
|
||||
|
||||
function test()
|
||||
{
|
||||
let transport = DebuggerServer.connectPipe();
|
||||
gClient = new DebuggerClient(transport);
|
||||
gClient.connect(function(aType, aTraits) {
|
||||
gTab = addTab(DEBUGGER_TAB_URL, function() {
|
||||
attach_tab_actor_for_url(gClient, DEBUGGER_TAB_URL, function(actor, response) {
|
||||
test_early_debugger_statement(response);
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function test_early_debugger_statement(aActor)
|
||||
{
|
||||
let paused = function(aEvent, aPacket) {
|
||||
ok(false, "Pause shouldn't be called before we've attached!\n");
|
||||
finish_test();
|
||||
};
|
||||
gClient.addListener("paused", paused);
|
||||
// This should continue without nesting an event loop and calling
|
||||
// the onPaused hook, because we haven't attached yet.
|
||||
gTab.linkedBrowser.contentWindow.wrappedJSObject.runDebuggerStatement();
|
||||
|
||||
gClient.removeListener("paused", paused);
|
||||
|
||||
// Now attach and resume...
|
||||
gClient.request({ to: aActor.threadActor, type: "attach" }, function(aResponse) {
|
||||
gClient.request({ to: aActor.threadActor, type: "resume" }, function(aResponse) {
|
||||
test_debugger_statement(aActor);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function test_debugger_statement(aActor)
|
||||
{
|
||||
var stopped = false;
|
||||
gClient.addListener("paused", function(aEvent, aPacket) {
|
||||
stopped = true;
|
||||
|
||||
gClient.request({ to: aActor.threadActor, type: "resume" }, function() {
|
||||
finish_test();
|
||||
});
|
||||
});
|
||||
|
||||
// Reach around the debugging protocol and execute the debugger
|
||||
// statement.
|
||||
gTab.linkedBrowser.contentWindow.wrappedJSObject.runDebuggerStatement();
|
||||
ok(stopped, "Should trigger the pause handler on a debugger statement.");
|
||||
}
|
||||
|
||||
function finish_test()
|
||||
{
|
||||
removeTab(gTab);
|
||||
gClient.close(function() {
|
||||
finish();
|
||||
});
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<title>Debugger Function Call Parameter Test</title>
|
||||
<!-- Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ -->
|
||||
<script type="text/javascript">
|
||||
window.addEventListener("load", function() {
|
||||
function test(aArg, bArg, cArg, dArg, eArg, fArg) {
|
||||
var a = 1;
|
||||
var b = { a: a };
|
||||
var c = { a: 1, b: "beta", c: true, d: b };
|
||||
|
||||
debugger;
|
||||
}
|
||||
function load() {
|
||||
var a = { a: 1, b: "beta", c: true };
|
||||
var e = eval("test(a, 'beta', 3, false, null)");
|
||||
}
|
||||
var button = document.querySelector("button");
|
||||
button.addEventListener("click", load, false);
|
||||
});
|
||||
</script>
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<button>Click me!</button>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,100 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
var gTab1 = null;
|
||||
var gTab1Actor = null;
|
||||
|
||||
var gTab2 = null;
|
||||
var gTab2Actor = null;
|
||||
|
||||
var gClient = null;
|
||||
|
||||
function test()
|
||||
{
|
||||
let transport = DebuggerServer.connectPipe();
|
||||
gClient = new DebuggerClient(transport);
|
||||
gClient.connect(function(aType, aTraits) {
|
||||
is(aType, "browser", "Root actor should identify itself as a browser.");
|
||||
test_first_tab();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify that a new tab shows up in a listTabs call.
|
||||
*/
|
||||
function test_first_tab()
|
||||
{
|
||||
gTab1 = addTab(TAB1_URL, function() {
|
||||
gClient.listTabs(function(aResponse) {
|
||||
for each (let tab in aResponse.tabs) {
|
||||
if (tab.url == TAB1_URL) {
|
||||
gTab1Actor = tab.actor;
|
||||
}
|
||||
}
|
||||
ok(gTab1Actor, "Should find a tab actor for tab1.");
|
||||
test_second_tab();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function test_second_tab()
|
||||
{
|
||||
gTab2 = addTab(TAB2_URL, function() {
|
||||
gClient.listTabs(function(aResponse) {
|
||||
// Verify that tab1 has the same actor it used to.
|
||||
let foundTab1 = false;
|
||||
for each (let tab in aResponse.tabs) {
|
||||
if (tab.url == TAB1_URL) {
|
||||
is(tab.actor, gTab1Actor, "Tab1's actor shouldn't have changed.");
|
||||
foundTab1 = true;
|
||||
}
|
||||
if (tab.url == TAB2_URL) {
|
||||
gTab2Actor = tab.actor;
|
||||
}
|
||||
}
|
||||
ok(foundTab1, "Should have found an actor for tab 1.");
|
||||
ok(gTab2Actor != null, "Should find an actor for tab2.");
|
||||
|
||||
test_remove_tab();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function test_remove_tab()
|
||||
{
|
||||
removeTab(gTab1);
|
||||
gTab1 = null;
|
||||
gClient.listTabs(function(aResponse) {
|
||||
// Verify that tab1 is no longer included in listTabs.
|
||||
let foundTab1 = false;
|
||||
for each (let tab in aResponse.tabs) {
|
||||
if (tab.url == TAB1_URL) {
|
||||
ok(false, "Tab1 should be gone.");
|
||||
}
|
||||
}
|
||||
ok(!foundTab1, "Tab1 should be gone.");
|
||||
test_attach_removed_tab();
|
||||
});
|
||||
}
|
||||
|
||||
function test_attach_removed_tab()
|
||||
{
|
||||
removeTab(gTab2);
|
||||
gTab2 = null;
|
||||
gClient.addListener("paused", function(aEvent, aPacket) {
|
||||
ok(false, "Attaching to an exited tab actor shouldn't generate a pause.");
|
||||
finish_test();
|
||||
});
|
||||
|
||||
gClient.request({ to: gTab2Actor, type: "attach" }, function(aResponse) {
|
||||
is(aResponse.type, "exited", "Tab should consider itself exited.");
|
||||
finish_test();
|
||||
});
|
||||
}
|
||||
|
||||
function finish_test()
|
||||
{
|
||||
gClient.close(function() {
|
||||
finish();
|
||||
});
|
||||
}
|
|
@ -0,0 +1,64 @@
|
|||
/* vim:set ts=2 sw=2 sts=2 et: */
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
/**
|
||||
* Make sure that changing the tab location URL works.
|
||||
*/
|
||||
|
||||
var gPane = null;
|
||||
var gTab = null;
|
||||
var gDebuggee = null;
|
||||
var gDebugger = null;
|
||||
|
||||
function test()
|
||||
{
|
||||
debug_tab_pane(STACK_URL, function(aTab, aDebuggee, aPane) {
|
||||
gTab = aTab;
|
||||
gDebuggee = aDebuggee;
|
||||
gPane = aPane;
|
||||
gDebugger = gPane.debuggerWindow;
|
||||
|
||||
testSimpleCall();
|
||||
});
|
||||
}
|
||||
|
||||
function testSimpleCall() {
|
||||
gPane.activeThread.addOneTimeListener("framesadded", function() {
|
||||
Services.tm.currentThread.dispatch({
|
||||
run: function() {
|
||||
var frames = gDebugger.DebuggerView.Stackframes._frames,
|
||||
childNodes = frames.childNodes;
|
||||
|
||||
is(gDebugger.StackFrames.activeThread.state, "paused",
|
||||
"Should only be getting stack frames while paused.");
|
||||
|
||||
is(frames.querySelectorAll(".dbg-stackframe").length, 1,
|
||||
"Should have only one frame.");
|
||||
|
||||
is(childNodes.length, frames.querySelectorAll(".dbg-stackframe").length,
|
||||
"All children should be frames.");
|
||||
|
||||
testLocationChange();
|
||||
}
|
||||
}, 0);
|
||||
});
|
||||
|
||||
gDebuggee.simpleCall();
|
||||
}
|
||||
|
||||
function testLocationChange()
|
||||
{
|
||||
gDebugger.StackFrames.activeThread.resume(function() {
|
||||
gPane._client.addOneTimeListener("tabNavigated", function(aEvent, aPacket) {
|
||||
ok(true, "tabNavigated event was fired.");
|
||||
gPane._client.addOneTimeListener("tabAttached", function(aEvent, aPacket) {
|
||||
ok(true, "Successfully reattached to the tab again.");
|
||||
|
||||
removeTab(gTab);
|
||||
finish();
|
||||
});
|
||||
});
|
||||
content.location = TAB1_URL;
|
||||
});
|
||||
}
|
|
@ -0,0 +1,48 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
/**
|
||||
* Check tab attach/navigation.
|
||||
*/
|
||||
|
||||
var gTab1 = null;
|
||||
var gTab1Actor = null;
|
||||
|
||||
var gClient = null;
|
||||
|
||||
function test()
|
||||
{
|
||||
let transport = DebuggerServer.connectPipe();
|
||||
gClient = new DebuggerClient(transport);
|
||||
gClient.connect(function(aType, aTraits) {
|
||||
is(aType, "browser", "Root actor should identify itself as a browser.");
|
||||
get_tab();
|
||||
});
|
||||
}
|
||||
|
||||
function get_tab()
|
||||
{
|
||||
gTab1 = addTab(TAB1_URL, function() {
|
||||
get_tab_actor_for_url(gClient, TAB1_URL, function(aGrip) {
|
||||
gTab1Actor = aGrip.actor;
|
||||
gClient.request({ to: aGrip.actor, type: "attach" }, function(aResponse) {
|
||||
gClient.addOneTimeListener("tabNavigated", function(aEvent, aPacket) {
|
||||
is(aPacket.url, TAB2_URL, "Got a tab navigation notification.");
|
||||
gClient.addOneTimeListener("tabDetached", function (aEvent, aPacket) {
|
||||
ok(true, "Got a tab detach notification.");
|
||||
finish_test();
|
||||
});
|
||||
removeTab(gTab1);
|
||||
});
|
||||
gTab1.linkedBrowser.loadURI(TAB2_URL);
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function finish_test()
|
||||
{
|
||||
gClient.close(function() {
|
||||
finish();
|
||||
});
|
||||
}
|
|
@ -0,0 +1,40 @@
|
|||
/* vim:set ts=2 sw=2 sts=2 et: */
|
||||
/*
|
||||
* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/
|
||||
*/
|
||||
|
||||
function test() {
|
||||
var tab1 = addTab(TAB1_URL, function() {
|
||||
gBrowser.selectedTab = tab1;
|
||||
|
||||
ok(!DebuggerUI.getDebugger(gBrowser.selectedTab),
|
||||
"Shouldn't have a debugger pane for this tab yet.");
|
||||
|
||||
let pane = DebuggerUI.toggleDebugger();
|
||||
let someHeight = parseInt(Math.random() * 200) + 200;
|
||||
|
||||
ok(pane, "toggleDebugger() should return a pane.");
|
||||
|
||||
is(DebuggerUI.getDebugger(gBrowser.selectedTab), pane,
|
||||
"getDebugger() should return the same pane as toggleDebugger().");
|
||||
|
||||
ok(DebuggerUI.preferences.height,
|
||||
"The debugger preferences should have a saved height value.");
|
||||
|
||||
is(DebuggerUI.preferences.height, pane.frame.height,
|
||||
"The debugger pane height should be the same as the preferred value.");
|
||||
|
||||
pane.frame.height = someHeight;
|
||||
ok(DebuggerUI.preferences.height !== someHeight,
|
||||
"Height preferences shouldn't have been updated yet.");
|
||||
|
||||
pane.onConnected = function() {
|
||||
removeTab(tab1);
|
||||
finish();
|
||||
|
||||
is(DebuggerUI.preferences.height, someHeight,
|
||||
"Height preferences should have been updated by now.");
|
||||
};
|
||||
});
|
||||
}
|
|
@ -0,0 +1,89 @@
|
|||
/* vim:set ts=2 sw=2 sts=2 et: */
|
||||
/*
|
||||
* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/
|
||||
*/
|
||||
var gPane = null;
|
||||
var gTab = null;
|
||||
var gDebuggee = null;
|
||||
var gDebugger = null;
|
||||
|
||||
function test() {
|
||||
debug_tab_pane(STACK_URL, function(aTab, aDebuggee, aPane) {
|
||||
gTab = aTab;
|
||||
gDebuggee = aDebuggee;
|
||||
gPane = aPane;
|
||||
gDebugger = gPane.debuggerWindow;
|
||||
|
||||
testSimpleCall();
|
||||
});
|
||||
}
|
||||
|
||||
function testSimpleCall() {
|
||||
gPane.activeThread.addOneTimeListener("framesadded", function() {
|
||||
Services.tm.currentThread.dispatch({ run: function() {
|
||||
|
||||
let globalScope = gDebugger.DebuggerView.Properties._globalScope;
|
||||
let localScope = gDebugger.DebuggerView.Properties._localScope;
|
||||
let withScope = gDebugger.DebuggerView.Properties._withScope;
|
||||
let closureScope = gDebugger.DebuggerView.Properties._closureScope;
|
||||
|
||||
ok(globalScope,
|
||||
"Should have a globalScope container for the variables property view.");
|
||||
|
||||
ok(localScope,
|
||||
"Should have a localScope container for the variables property view.");
|
||||
|
||||
ok(withScope,
|
||||
"Should have a withScope container for the variables property view.");
|
||||
|
||||
ok(closureScope,
|
||||
"Should have a closureScope container for the variables property view.");
|
||||
|
||||
is(globalScope, gDebugger.DebuggerView.Properties.globalScope,
|
||||
"The globalScope object should be equal to the corresponding getter.");
|
||||
|
||||
is(localScope, gDebugger.DebuggerView.Properties.localScope,
|
||||
"The localScope object should be equal to the corresponding getter.");
|
||||
|
||||
is(withScope, gDebugger.DebuggerView.Properties.withScope,
|
||||
"The withScope object should be equal to the corresponding getter.");
|
||||
|
||||
is(closureScope, gDebugger.DebuggerView.Properties.closureScope,
|
||||
"The closureScope object should be equal to the corresponding getter.");
|
||||
|
||||
|
||||
ok(!globalScope.expanded,
|
||||
"The globalScope should be initially collapsed.");
|
||||
|
||||
ok(localScope.expanded,
|
||||
"The localScope should be initially expanded.");
|
||||
|
||||
ok(!withScope.expanded,
|
||||
"The withScope should be initially collapsed.");
|
||||
|
||||
ok(!withScope.visible,
|
||||
"The withScope should be initially hidden.");
|
||||
|
||||
ok(!closureScope.expanded,
|
||||
"The closureScope should be initially collapsed.");
|
||||
|
||||
ok(!closureScope.visible,
|
||||
"The closureScope should be initially hidden.");
|
||||
|
||||
is(gDebugger.DebuggerView.Properties._vars.childNodes.length, 4,
|
||||
"Should have only 4 scopes created: global, local, with and scope.");
|
||||
|
||||
resumeAndFinish();
|
||||
}}, 0);
|
||||
});
|
||||
|
||||
gDebuggee.simpleCall();
|
||||
}
|
||||
|
||||
function resumeAndFinish() {
|
||||
gDebugger.StackFrames.activeThread.resume(function() {
|
||||
removeTab(gTab);
|
||||
finish();
|
||||
});
|
||||
}
|
|
@ -0,0 +1,131 @@
|
|||
/* vim:set ts=2 sw=2 sts=2 et: */
|
||||
/*
|
||||
* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/
|
||||
*/
|
||||
var gPane = null;
|
||||
var gTab = null;
|
||||
var gDebuggee = null;
|
||||
var gDebugger = null;
|
||||
|
||||
function test() {
|
||||
debug_tab_pane(STACK_URL, function(aTab, aDebuggee, aPane) {
|
||||
gTab = aTab;
|
||||
gDebuggee = aDebuggee;
|
||||
gPane = aPane;
|
||||
gDebugger = gPane.debuggerWindow;
|
||||
|
||||
testSimpleCall();
|
||||
});
|
||||
}
|
||||
|
||||
function testSimpleCall() {
|
||||
gPane.activeThread.addOneTimeListener("framesadded", function() {
|
||||
Services.tm.currentThread.dispatch({ run: function() {
|
||||
|
||||
let testScope = gDebugger.DebuggerView.Properties._addScope("test");
|
||||
|
||||
ok(testScope,
|
||||
"Should have created a scope.");
|
||||
|
||||
is(testScope.id, "test-scope",
|
||||
"The newly created scope should have the default id set.");
|
||||
|
||||
is(testScope.querySelector(".name").textContent, "test",
|
||||
"Any new scope should have the designated title.");
|
||||
|
||||
is(testScope.querySelector(".details").childNodes.length, 0,
|
||||
"Any new scope should have a container with no child nodes.");
|
||||
|
||||
is(gDebugger.DebuggerView.Properties._vars.childNodes.length, 5,
|
||||
"Should have 5 scopes created: global, local, with, closure and test.");
|
||||
|
||||
|
||||
ok(!testScope.expanded,
|
||||
"Any new created scope should be initially collapsed.");
|
||||
|
||||
ok(testScope.visible,
|
||||
"Any new created scope should be initially visible.");
|
||||
|
||||
let expandCallbackSender = null;
|
||||
let collapseCallbackSender = null;
|
||||
let toggleCallbackSender = null;
|
||||
let hideCallbackSender = null;
|
||||
let showCallbackSender = null;
|
||||
|
||||
testScope.onexpand = function(sender) { expandCallbackSender = sender; };
|
||||
testScope.oncollapse = function(sender) { collapseCallbackSender = sender; };
|
||||
testScope.ontoggle = function(sender) { toggleCallbackSender = sender; };
|
||||
testScope.onhide = function(sender) { hideCallbackSender = sender; };
|
||||
testScope.onshow = function(sender) { showCallbackSender = sender; };
|
||||
|
||||
testScope.expand();
|
||||
ok(testScope.expanded,
|
||||
"The testScope shouldn't be collapsed anymore.");
|
||||
is(expandCallbackSender, testScope,
|
||||
"The expandCallback wasn't called as it should.");
|
||||
|
||||
testScope.collapse();
|
||||
ok(!testScope.expanded,
|
||||
"The testScope should be collapsed again.");
|
||||
is(collapseCallbackSender, testScope,
|
||||
"The collapseCallback wasn't called as it should.");
|
||||
|
||||
testScope.expanded = true;
|
||||
ok(testScope.expanded,
|
||||
"The testScope shouldn't be collapsed anymore.");
|
||||
|
||||
testScope.toggle();
|
||||
ok(!testScope.expanded,
|
||||
"The testScope should be collapsed again.");
|
||||
is(toggleCallbackSender, testScope,
|
||||
"The toggleCallback wasn't called as it should.");
|
||||
|
||||
|
||||
testScope.hide();
|
||||
ok(!testScope.visible,
|
||||
"The testScope should be invisible after hiding.");
|
||||
is(hideCallbackSender, testScope,
|
||||
"The hideCallback wasn't called as it should.");
|
||||
|
||||
testScope.show();
|
||||
ok(testScope.visible,
|
||||
"The testScope should be visible again.");
|
||||
is(showCallbackSender, testScope,
|
||||
"The showCallback wasn't called as it should.");
|
||||
|
||||
testScope.visible = false;
|
||||
ok(!testScope.visible,
|
||||
"The testScope should be invisible after hiding.");
|
||||
|
||||
|
||||
ok(!testScope.expanded,
|
||||
"The testScope should remember it is collapsed even if it is hidden.");
|
||||
|
||||
EventUtils.sendMouseEvent({ type: "click" },
|
||||
testScope.querySelector(".title"),
|
||||
gDebugger);
|
||||
|
||||
ok(testScope.expanded,
|
||||
"Clicking the testScope tilte should expand it.");
|
||||
|
||||
EventUtils.sendMouseEvent({ type: "click" },
|
||||
testScope.querySelector(".title"),
|
||||
gDebugger);
|
||||
|
||||
ok(!testScope.expanded,
|
||||
"Clicking again the testScope tilte should collapse it.");
|
||||
|
||||
resumeAndFinish();
|
||||
}}, 0);
|
||||
});
|
||||
|
||||
gDebuggee.simpleCall();
|
||||
}
|
||||
|
||||
function resumeAndFinish() {
|
||||
gDebugger.StackFrames.activeThread.resume(function() {
|
||||
removeTab(gTab);
|
||||
finish();
|
||||
});
|
||||
}
|
|
@ -0,0 +1,133 @@
|
|||
/* vim:set ts=2 sw=2 sts=2 et: */
|
||||
/*
|
||||
* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/
|
||||
*/
|
||||
var gPane = null;
|
||||
var gTab = null;
|
||||
var gDebuggee = null;
|
||||
var gDebugger = null;
|
||||
|
||||
function test() {
|
||||
debug_tab_pane(STACK_URL, function(aTab, aDebuggee, aPane) {
|
||||
gTab = aTab;
|
||||
gDebuggee = aDebuggee;
|
||||
gPane = aPane;
|
||||
gDebugger = gPane.debuggerWindow;
|
||||
|
||||
testSimpleCall();
|
||||
});
|
||||
}
|
||||
|
||||
function testSimpleCall() {
|
||||
gPane.activeThread.addOneTimeListener("framesadded", function() {
|
||||
Services.tm.currentThread.dispatch({ run: function() {
|
||||
|
||||
let testScope = gDebugger.DebuggerView.Properties._addScope("test");
|
||||
let testVar = testScope.addVar("something");
|
||||
let duplVar = testScope.addVar("something");
|
||||
|
||||
ok(testVar,
|
||||
"Should have created a variable.");
|
||||
|
||||
is(duplVar, null,
|
||||
"Shouldn't be able to duplicate variables in the same scope.");
|
||||
|
||||
is(testVar.id, "test-scope->something-variable",
|
||||
"The newly created scope should have the default id set.");
|
||||
|
||||
is(testVar.querySelector(".name").textContent, "something",
|
||||
"Any new variable should have the designated title.");
|
||||
|
||||
is(testVar.querySelector(".details").childNodes.length, 0,
|
||||
"Any new variable should have a details container with no child nodes.");
|
||||
|
||||
|
||||
ok(!testVar.expanded,
|
||||
"Any new created variable should be initially collapsed.");
|
||||
|
||||
ok(testVar.visible,
|
||||
"Any new created variable should be initially visible.");
|
||||
|
||||
|
||||
testVar.expand();
|
||||
ok(testVar.expanded,
|
||||
"The testVar shouldn't be collapsed anymore.");
|
||||
|
||||
testVar.collapse();
|
||||
ok(!testVar.expanded,
|
||||
"The testVar should be collapsed again.");
|
||||
|
||||
testVar.expanded = true;
|
||||
ok(testVar.expanded,
|
||||
"The testVar shouldn't be collapsed anymore.");
|
||||
|
||||
testVar.toggle();
|
||||
ok(!testVar.expanded,
|
||||
"The testVar should be collapsed again.");
|
||||
|
||||
|
||||
testVar.hide();
|
||||
ok(!testVar.visible,
|
||||
"The testVar should be invisible after hiding.");
|
||||
|
||||
testVar.show();
|
||||
ok(testVar.visible,
|
||||
"The testVar should be visible again.");
|
||||
|
||||
testVar.visible = false;
|
||||
ok(!testVar.visible,
|
||||
"The testVar should be invisible after hiding.");
|
||||
|
||||
|
||||
ok(!testVar.expanded,
|
||||
"The testVar should remember it is collapsed even if it is hidden.");
|
||||
|
||||
EventUtils.sendMouseEvent({ type: "click" },
|
||||
testVar.querySelector(".title"),
|
||||
gDebugger);
|
||||
|
||||
ok(testVar.expanded,
|
||||
"Clicking the testScope tilte should expand it.");
|
||||
|
||||
EventUtils.sendMouseEvent({ type: "click" },
|
||||
testVar.querySelector(".title"),
|
||||
gDebugger);
|
||||
|
||||
ok(!testVar.expanded,
|
||||
"Clicking again the testScope tilte should collapse it.");
|
||||
|
||||
|
||||
let emptyCallbackSender = null;
|
||||
let removeCallbackSender = null;
|
||||
|
||||
testScope.onempty = function(sender) { emptyCallbackSender = sender; };
|
||||
testScope.onremove = function(sender) { removeCallbackSender = sender; };
|
||||
|
||||
testScope.empty();
|
||||
is(emptyCallbackSender, testScope,
|
||||
"The emptyCallback wasn't called as it should.");
|
||||
|
||||
is(testScope.querySelector(".details").childNodes.length, 0,
|
||||
"The scope should remove all it's details container tree children.");
|
||||
|
||||
testScope.remove();
|
||||
is(removeCallbackSender, testScope,
|
||||
"The removeCallback wasn't called as it should.");
|
||||
|
||||
is(gDebugger.DebuggerView.Properties._vars.childNodes.length, 4,
|
||||
"The scope should have been removed from the parent container tree.");
|
||||
|
||||
resumeAndFinish();
|
||||
}}, 0);
|
||||
});
|
||||
|
||||
gDebuggee.simpleCall();
|
||||
}
|
||||
|
||||
function resumeAndFinish() {
|
||||
gDebugger.StackFrames.activeThread.resume(function() {
|
||||
removeTab(gTab);
|
||||
finish();
|
||||
});
|
||||
}
|
|
@ -0,0 +1,88 @@
|
|||
/* vim:set ts=2 sw=2 sts=2 et: */
|
||||
/*
|
||||
* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/
|
||||
*/
|
||||
var gPane = null;
|
||||
var gTab = null;
|
||||
var gDebuggee = null;
|
||||
var gDebugger = null;
|
||||
|
||||
function test() {
|
||||
debug_tab_pane(STACK_URL, function(aTab, aDebuggee, aPane) {
|
||||
gTab = aTab;
|
||||
gDebuggee = aDebuggee;
|
||||
gPane = aPane;
|
||||
gDebugger = gPane.debuggerWindow;
|
||||
|
||||
testSimpleCall();
|
||||
});
|
||||
}
|
||||
|
||||
function testSimpleCall() {
|
||||
gPane.activeThread.addOneTimeListener("framesadded", function() {
|
||||
Services.tm.currentThread.dispatch({ run: function() {
|
||||
|
||||
let testScope = gDebugger.DebuggerView.Properties._addScope("test");
|
||||
let testVar = testScope.addVar("something");
|
||||
|
||||
let properties = testVar.addProperties({ "child": { "value": { "type": "object",
|
||||
"class": "Object" } } });
|
||||
|
||||
is(testVar.querySelector(".details").childNodes.length, 1,
|
||||
"A new detail node should have been added in the variable tree.");
|
||||
|
||||
ok(testVar.child,
|
||||
"The added detail property should be accessible from the variable.");
|
||||
|
||||
is(testVar.child, properties.child,
|
||||
"Adding a detail property should return that exact property.");
|
||||
|
||||
|
||||
let properties2 = testVar.child.addProperties({ "grandchild": { "value": { "type": "object",
|
||||
"class": "Object" } } });
|
||||
|
||||
is(testVar.child.querySelector(".details").childNodes.length, 1,
|
||||
"A new detail node should have been added in the variable tree.");
|
||||
|
||||
ok(testVar.child.grandchild,
|
||||
"The added detail property should be accessible from the variable.");
|
||||
|
||||
is(testVar.child.grandchild, properties2.grandchild,
|
||||
"Adding a detail property should return that exact property.");
|
||||
|
||||
|
||||
testVar.child.empty();
|
||||
|
||||
is(testVar.child.querySelector(".details").childNodes.length, 0,
|
||||
"The child should remove all it's details container tree children.");
|
||||
|
||||
testVar.child.remove();
|
||||
|
||||
is(testVar.querySelector(".details").childNodes.length, 0,
|
||||
"The child should have been removed from the parent container tree.");
|
||||
|
||||
|
||||
testVar.empty();
|
||||
|
||||
is(testVar.querySelector(".details").childNodes.length, 0,
|
||||
"The var should remove all it's details container tree children.");
|
||||
|
||||
testVar.remove();
|
||||
|
||||
is(testScope.querySelector(".details").childNodes.length, 0,
|
||||
"The var should have been removed from the parent container tree.");
|
||||
|
||||
resumeAndFinish();
|
||||
}}, 0);
|
||||
});
|
||||
|
||||
gDebuggee.simpleCall();
|
||||
}
|
||||
|
||||
function resumeAndFinish() {
|
||||
gDebugger.StackFrames.activeThread.resume(function() {
|
||||
removeTab(gTab);
|
||||
finish();
|
||||
});
|
||||
}
|
|
@ -0,0 +1,96 @@
|
|||
/* vim:set ts=2 sw=2 sts=2 et: */
|
||||
/*
|
||||
* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/
|
||||
*/
|
||||
var gPane = null;
|
||||
var gTab = null;
|
||||
var gDebuggee = null;
|
||||
var gDebugger = null;
|
||||
|
||||
function test() {
|
||||
debug_tab_pane(STACK_URL, function(aTab, aDebuggee, aPane) {
|
||||
gTab = aTab;
|
||||
gDebuggee = aDebuggee;
|
||||
gPane = aPane;
|
||||
gDebugger = gPane.debuggerWindow;
|
||||
|
||||
testSimpleCall();
|
||||
});
|
||||
}
|
||||
|
||||
function testSimpleCall() {
|
||||
gPane.activeThread.addOneTimeListener("framesadded", function() {
|
||||
Services.tm.currentThread.dispatch({ run: function() {
|
||||
|
||||
let testScope = gDebugger.DebuggerView.Properties._addScope("test");
|
||||
let testVar = testScope.addVar("something");
|
||||
|
||||
testVar.setGrip(1.618);
|
||||
|
||||
is(testVar.querySelector(".info").textContent, "1.618",
|
||||
"The grip information for the variable wasn't set correctly.");
|
||||
|
||||
is(testVar.querySelector(".details").childNodes.length, 0,
|
||||
"Adding a value property shouldn't add any new tree nodes.");
|
||||
|
||||
|
||||
testVar.setGrip({ "type": "object", "class": "Window" });
|
||||
|
||||
is(testVar.querySelector(".details").childNodes.length, 0,
|
||||
"Adding type and class properties shouldn't add any new tree nodes.");
|
||||
|
||||
is(testVar.querySelector(".info").textContent, "[object Window]",
|
||||
"The information for the variable wasn't set correctly.");
|
||||
|
||||
|
||||
testVar.addProperties({ "helloWorld": { "value": "hello world" } });
|
||||
|
||||
is(testVar.querySelector(".details").childNodes.length, 1,
|
||||
"A new detail node should have been added in the variable tree.");
|
||||
|
||||
|
||||
testVar.addProperties({ "helloWorld": { "value": "hello jupiter" } });
|
||||
|
||||
is(testVar.querySelector(".details").childNodes.length, 1,
|
||||
"Shouldn't be able to duplicate nodes added in the variable tree.");
|
||||
|
||||
|
||||
testVar.addProperties({ "someProp0": { "value": "random string" },
|
||||
"someProp1": { "value": "another string" } });
|
||||
|
||||
is(testVar.querySelector(".details").childNodes.length, 3,
|
||||
"Two new detail nodes should have been added in the variable tree.");
|
||||
|
||||
|
||||
testVar.addProperties({ "someProp2": { "value": { "type": "null" } },
|
||||
"someProp3": { "value": { "type": "undefined" } },
|
||||
"someProp4": { "value": { "type": "object", "class": "Object" } } });
|
||||
|
||||
is(testVar.querySelector(".details").childNodes.length, 6,
|
||||
"Three new detail nodes should have been added in the variable tree.");
|
||||
|
||||
|
||||
testVar.empty();
|
||||
|
||||
is(testVar.querySelector(".details").childNodes.length, 0,
|
||||
"The var should remove all it's details container tree children.");
|
||||
|
||||
testVar.remove();
|
||||
|
||||
is(testScope.querySelector(".details").childNodes.length, 0,
|
||||
"The var should have been removed from the parent container tree.");
|
||||
|
||||
resumeAndFinish();
|
||||
}}, 0);
|
||||
});
|
||||
|
||||
gDebuggee.simpleCall();
|
||||
}
|
||||
|
||||
function resumeAndFinish() {
|
||||
gDebugger.StackFrames.activeThread.resume(function() {
|
||||
removeTab(gTab);
|
||||
finish();
|
||||
});
|
||||
}
|
|
@ -0,0 +1,133 @@
|
|||
/* vim:set ts=2 sw=2 sts=2 et: */
|
||||
/*
|
||||
* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/
|
||||
*/
|
||||
var gPane = null;
|
||||
var gTab = null;
|
||||
var gDebuggee = null;
|
||||
var gDebugger = null;
|
||||
|
||||
function test() {
|
||||
debug_tab_pane(STACK_URL, function(aTab, aDebuggee, aPane) {
|
||||
gTab = aTab;
|
||||
gDebuggee = aDebuggee;
|
||||
gPane = aPane;
|
||||
gDebugger = gPane.debuggerWindow;
|
||||
|
||||
testSimpleCall();
|
||||
});
|
||||
}
|
||||
|
||||
function testSimpleCall() {
|
||||
gPane.activeThread.addOneTimeListener("framesadded", function() {
|
||||
Services.tm.currentThread.dispatch({ run: function() {
|
||||
|
||||
let globalScope = gDebugger.DebuggerView.Properties.globalScope;
|
||||
let localScope = gDebugger.DebuggerView.Properties.localScope;
|
||||
let windowVar = globalScope.addVar("window");
|
||||
let documentVar = globalScope.addVar("document");
|
||||
let localVar0 = localScope.addVar("localVariable");
|
||||
let localVar1 = localScope.addVar("localVar1");
|
||||
let localVar2 = localScope.addVar("localVar2");
|
||||
let localVar3 = localScope.addVar("localVar3");
|
||||
let localVar4 = localScope.addVar("localVar4");
|
||||
let localVar5 = localScope.addVar("localVar5");
|
||||
|
||||
localVar0.setGrip(42);
|
||||
localVar1.setGrip(true);
|
||||
localVar2.setGrip("nasu");
|
||||
|
||||
localVar3.setGrip({ "type": "undefined" });
|
||||
localVar4.setGrip({ "type": "null" });
|
||||
localVar5.setGrip({ "type": "object", "class": "Object" });
|
||||
|
||||
localVar5.addProperties({ "someProp0": { "value": 42 },
|
||||
"someProp1": { "value": true },
|
||||
"someProp2": { "value": "nasu" },
|
||||
"someProp3": { "value": { "type": "undefined" } },
|
||||
"someProp4": { "value": { "type": "null" } },
|
||||
"someProp5": { "value": { "type": "object", "class": "Object" } } });
|
||||
|
||||
localVar5.someProp5.addProperties({ "someProp0": { "value": 42 },
|
||||
"someProp1": { "value": true },
|
||||
"someProp2": { "value": "nasu" },
|
||||
"someProp3": { "value": { "type": "undefined" } },
|
||||
"someProp4": { "value": { "type": "null" } },
|
||||
"someAccessor": { "get": { "type": "object", "class": "Function" },
|
||||
"set": { "type": "undefined" } } });
|
||||
|
||||
windowVar.setGrip({ "type": "object", "class": "Window" });
|
||||
windowVar.addProperties({ "helloWorld": { "value": "hello world" } });
|
||||
|
||||
documentVar.setGrip({ "type": "object", "class": "HTMLDocument" });
|
||||
documentVar.addProperties({ "onload": { "value": { "type": "null" } },
|
||||
"onunload": { "value": { "type": "null" } },
|
||||
"onfocus": { "value": { "type": "null" } },
|
||||
"onblur": { "value": { "type": "null" } },
|
||||
"onclick": { "value": { "type": "null" } },
|
||||
"onkeypress": { "value": { "type": "null" } } });
|
||||
|
||||
|
||||
ok(windowVar, "The windowVar hasn't been created correctly.");
|
||||
ok(documentVar, "The documentVar hasn't been created correctly.");
|
||||
ok(localVar0, "The localVar0 hasn't been created correctly.");
|
||||
ok(localVar1, "The localVar1 hasn't been created correctly.");
|
||||
ok(localVar2, "The localVar2 hasn't been created correctly.");
|
||||
ok(localVar3, "The localVar3 hasn't been created correctly.");
|
||||
ok(localVar4, "The localVar4 hasn't been created correctly.");
|
||||
ok(localVar5, "The localVar5 hasn't been created correctly.");
|
||||
|
||||
|
||||
is(globalScope.querySelector(".details").childNodes.length, 2,
|
||||
"The globalScope doesn't contain all the created variable elements.");
|
||||
|
||||
is(localScope.querySelector(".details").childNodes.length, 7,
|
||||
"The localScope doesn't contain all the created variable elements.");
|
||||
|
||||
|
||||
is(localVar5.querySelector(".details").childNodes.length, 6,
|
||||
"The localVar5 doesn't contain all the created properties.");
|
||||
|
||||
is(localVar5.someProp5.querySelector(".details").childNodes.length, 6,
|
||||
"The localVar5.someProp5 doesn't contain all the created properties.");
|
||||
|
||||
|
||||
is(windowVar.querySelector(".info").textContent, "[object Window]",
|
||||
"The grip information for the windowVar wasn't set correctly.");
|
||||
|
||||
is(documentVar.querySelector(".info").textContent, "[object HTMLDocument]",
|
||||
"The grip information for the documentVar wasn't set correctly.");
|
||||
|
||||
is(localVar0.querySelector(".info").textContent, "42",
|
||||
"The grip information for the localVar0 wasn't set correctly.");
|
||||
|
||||
is(localVar1.querySelector(".info").textContent, "true",
|
||||
"The grip information for the localVar1 wasn't set correctly.");
|
||||
|
||||
is(localVar2.querySelector(".info").textContent, "\"nasu\"",
|
||||
"The grip information for the localVar2 wasn't set correctly.");
|
||||
|
||||
is(localVar3.querySelector(".info").textContent, "undefined",
|
||||
"The grip information for the localVar3 wasn't set correctly.");
|
||||
|
||||
is(localVar4.querySelector(".info").textContent, "null",
|
||||
"The grip information for the localVar4 wasn't set correctly.");
|
||||
|
||||
is(localVar5.querySelector(".info").textContent, "[object Object]",
|
||||
"The grip information for the localVar5 wasn't set correctly.");
|
||||
|
||||
|
||||
resumeAndFinish();
|
||||
}}, 0);
|
||||
});
|
||||
|
||||
gDebuggee.simpleCall();
|
||||
}
|
||||
|
||||
function resumeAndFinish() {
|
||||
gDebugger.StackFrames.activeThread.resume(function() {
|
||||
removeTab(gTab);
|
||||
finish();
|
||||
});
|
||||
}
|
|
@ -0,0 +1,97 @@
|
|||
/* vim:set ts=2 sw=2 sts=2 et: */
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
/**
|
||||
* Make sure that the property view displays function parameters.
|
||||
*/
|
||||
|
||||
const TAB_URL = "http://example.com/browser/browser/devtools/debugger/test/" +
|
||||
"browser_dbg_frame-parameters.html";
|
||||
|
||||
var gPane = null;
|
||||
var gTab = null;
|
||||
var gDebuggee = null;
|
||||
var gDebugger = null;
|
||||
|
||||
function test()
|
||||
{
|
||||
debug_tab_pane(TAB_URL, function(aTab, aDebuggee, aPane) {
|
||||
gTab = aTab;
|
||||
gDebuggee = aDebuggee;
|
||||
gPane = aPane;
|
||||
gDebugger = gPane.debuggerWindow;
|
||||
|
||||
testFrameParameters();
|
||||
});
|
||||
}
|
||||
|
||||
function testFrameParameters()
|
||||
{
|
||||
// scriptsadded is fired last when switching to a paused state, so the
|
||||
// property view will have had a chance to fetch the call parameters.
|
||||
gPane.activeThread.addOneTimeListener("scriptsadded", function() {
|
||||
Services.tm.currentThread.dispatch({ run: function() {
|
||||
|
||||
var frames = gDebugger.DebuggerView.Stackframes._frames,
|
||||
childNodes = frames.childNodes,
|
||||
localScope = gDebugger.DebuggerView.Properties.localScope,
|
||||
localNodes = localScope.querySelector(".details").childNodes;
|
||||
|
||||
is(gDebugger.StackFrames.activeThread.state, "paused",
|
||||
"Should only be getting stack frames while paused.");
|
||||
|
||||
is(frames.querySelectorAll(".dbg-stackframe").length, 3,
|
||||
"Should have three frames.");
|
||||
|
||||
is(localNodes.length, 8,
|
||||
"The localScope should contain all the created variable elements.");
|
||||
|
||||
is(localNodes[0].querySelector(".info").textContent, "[object Proxy]",
|
||||
"Should have the right property value for 'this'.");
|
||||
|
||||
is(localNodes[1].querySelector(".info").textContent, "[object Arguments]",
|
||||
"Should have the right property value for 'arguments'.");
|
||||
|
||||
is(localNodes[2].querySelector(".info").textContent, "[object Object]",
|
||||
"Should have the right property value for 'aArg'.");
|
||||
|
||||
is(localNodes[3].querySelector(".info").textContent, '"beta"',
|
||||
"Should have the right property value for 'bArg'.");
|
||||
|
||||
is(localNodes[4].querySelector(".info").textContent, "3",
|
||||
"Should have the right property value for 'cArg'.");
|
||||
|
||||
is(localNodes[5].querySelector(".info").textContent, "false",
|
||||
"Should have the right property value for 'dArg'.");
|
||||
|
||||
is(localNodes[6].querySelector(".info").textContent, "null",
|
||||
"Should have the right property value for 'eArg'.");
|
||||
|
||||
is(localNodes[7].querySelector(".info").textContent, "undefined",
|
||||
"Should have the right property value for 'fArg'.");
|
||||
|
||||
resumeAndFinish();
|
||||
}}, 0);
|
||||
});
|
||||
|
||||
EventUtils.sendMouseEvent({ type: "click" },
|
||||
content.document.querySelector("button"),
|
||||
content.window);
|
||||
}
|
||||
|
||||
function resumeAndFinish() {
|
||||
gPane.activeThread.addOneTimeListener("framescleared", function() {
|
||||
Services.tm.currentThread.dispatch({ run: function() {
|
||||
var frames = gDebugger.DebuggerView.Stackframes._frames;
|
||||
|
||||
is(frames.querySelectorAll(".dbg-stackframe").length, 0,
|
||||
"Should have no frames.");
|
||||
|
||||
removeTab(gTab);
|
||||
finish();
|
||||
}}, 0);
|
||||
});
|
||||
|
||||
gDebugger.StackFrames.activeThread.resume();
|
||||
}
|
|
@ -0,0 +1,111 @@
|
|||
/* vim:set ts=2 sw=2 sts=2 et: */
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
/**
|
||||
* Make sure that the property view displays the properties of objects.
|
||||
*/
|
||||
|
||||
const TAB_URL = "http://example.com/browser/browser/devtools/debugger/test/" +
|
||||
"browser_dbg_frame-parameters.html";
|
||||
|
||||
var gPane = null;
|
||||
var gTab = null;
|
||||
var gDebuggee = null;
|
||||
var gDebugger = null;
|
||||
|
||||
function test()
|
||||
{
|
||||
debug_tab_pane(TAB_URL, function(aTab, aDebuggee, aPane) {
|
||||
gTab = aTab;
|
||||
gDebuggee = aDebuggee;
|
||||
gPane = aPane;
|
||||
gDebugger = gPane.debuggerWindow;
|
||||
|
||||
testFrameParameters();
|
||||
});
|
||||
}
|
||||
|
||||
function testFrameParameters()
|
||||
{
|
||||
// scriptsadded is fired last when switching to a paused state, so the
|
||||
// property view will have had a chance to fetch the call parameters.
|
||||
gPane.activeThread.addOneTimeListener("scriptsadded", function() {
|
||||
Services.tm.currentThread.dispatch({ run: function() {
|
||||
|
||||
var frames = gDebugger.DebuggerView.Stackframes._frames,
|
||||
localScope = gDebugger.DebuggerView.Properties.localScope,
|
||||
localNodes = localScope.querySelector(".details").childNodes;
|
||||
|
||||
is(gDebugger.StackFrames.activeThread.state, "paused",
|
||||
"Should only be getting stack frames while paused.");
|
||||
|
||||
is(frames.querySelectorAll(".dbg-stackframe").length, 3,
|
||||
"Should have three frames.");
|
||||
|
||||
is(localNodes.length, 8,
|
||||
"The localScope should contain all the created variable elements.");
|
||||
|
||||
is(localNodes[0].querySelector(".info").textContent, "[object Proxy]",
|
||||
"Should have the right property value for 'this'.");
|
||||
|
||||
// Expand the __proto__ and arguments tree nodes. This causes their
|
||||
// properties to be retrieved and displayed.
|
||||
localNodes[0].expand();
|
||||
localNodes[1].expand();
|
||||
|
||||
// Poll every few milliseconds until the properties are retrieved.
|
||||
let count = 0;
|
||||
let intervalID = content.setInterval(function(){
|
||||
if (++count > 50) {
|
||||
ok(false, "Timed out while polling for the properties.");
|
||||
resumeAndFinish();
|
||||
}
|
||||
if (!localNodes[0].fetched || !localNodes[1].fetched) {
|
||||
return;
|
||||
}
|
||||
content.clearInterval(intervalID);
|
||||
is(localNodes[0].querySelector(".property > .title > .key")
|
||||
.textContent, "__proto__ ",
|
||||
"Should have the right property name for __proto__.");
|
||||
|
||||
ok(localNodes[0].querySelector(".property > .title > .value")
|
||||
.textContent.search(/object/) != -1,
|
||||
"__proto__ should be an object.");
|
||||
|
||||
is(localNodes[1].querySelector(".info").textContent, "[object Arguments]",
|
||||
"Should have the right property value for 'arguments'.");
|
||||
|
||||
is(localNodes[1].querySelector(".property > .title > .key")
|
||||
.textContent, "length",
|
||||
"Should have the right property name for length.");
|
||||
|
||||
is(localNodes[1].querySelector(".property > .title > .value")
|
||||
.textContent, 5,
|
||||
"Should have the right argument length.");
|
||||
|
||||
resumeAndFinish();
|
||||
}, 100);
|
||||
}}, 0);
|
||||
});
|
||||
|
||||
EventUtils.synthesizeMouseAtCenter(content.document.querySelector("button"),
|
||||
{},
|
||||
content.window);
|
||||
}
|
||||
|
||||
function resumeAndFinish() {
|
||||
gPane.activeThread.addOneTimeListener("framescleared", function() {
|
||||
Services.tm.currentThread.dispatch({ run: function() {
|
||||
var frames = gDebugger.DebuggerView.Stackframes._frames;
|
||||
|
||||
is(frames.querySelectorAll(".dbg-stackframe").length, 0,
|
||||
"Should have no frames.");
|
||||
|
||||
removeTab(gTab);
|
||||
finish();
|
||||
}}, 0);
|
||||
});
|
||||
|
||||
gDebugger.StackFrames.activeThread.resume();
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<title>Browser Debugger Script Switching Test</title>
|
||||
<!-- Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ -->
|
||||
<script type="text/javascript" src="test-script-switching-01.js"></script>
|
||||
<script type="text/javascript" src="test-script-switching-02.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,101 @@
|
|||
/* vim:set ts=2 sw=2 sts=2 et: */
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
/**
|
||||
* Make sure that switching the displayed script in the UI works as advertised.
|
||||
*/
|
||||
|
||||
const TAB_URL = "http://example.com/browser/browser/devtools/debugger/" +
|
||||
"test/browser_dbg_script-switching.html";
|
||||
let tempScope = {};
|
||||
Cu.import("resource:///modules/source-editor.jsm", tempScope);
|
||||
let SourceEditor = tempScope.SourceEditor;
|
||||
|
||||
var gPane = null;
|
||||
var gTab = null;
|
||||
var gDebuggee = null;
|
||||
var gDebugger = null;
|
||||
var gScripts = null;
|
||||
|
||||
function test()
|
||||
{
|
||||
debug_tab_pane(TAB_URL, function(aTab, aDebuggee, aPane) {
|
||||
gTab = aTab;
|
||||
gDebuggee = aDebuggee;
|
||||
gPane = aPane;
|
||||
gDebugger = gPane.debuggerWindow;
|
||||
|
||||
testScriptsDisplay();
|
||||
});
|
||||
}
|
||||
|
||||
function testScriptsDisplay() {
|
||||
gPane.activeThread.addOneTimeListener("scriptsadded", function() {
|
||||
Services.tm.currentThread.dispatch({ run: function() {
|
||||
let count = 0;
|
||||
gDebugger.editor.addEventListener(SourceEditor.EVENTS.TEXT_CHANGED,
|
||||
function onScriptLoad() {
|
||||
// Skip the first change event, since we're only interested in the
|
||||
// second.
|
||||
if (count++ < 1) {
|
||||
return;
|
||||
}
|
||||
gDebugger.editor.removeEventListener(SourceEditor.EVENTS.TEXT_CHANGED,
|
||||
onScriptLoad);
|
||||
gScripts = gDebugger.DebuggerView.Scripts._scripts;
|
||||
|
||||
is(gDebugger.StackFrames.activeThread.state, "paused",
|
||||
"Should only be getting stack frames while paused.");
|
||||
|
||||
is(gScripts.itemCount, 2, "Found the expected number of scripts.");
|
||||
|
||||
ok(gDebugger.editor.getText().search(/debugger/) != -1,
|
||||
"The correct script was loaded initially.");
|
||||
|
||||
gDebugger.editor.addEventListener(SourceEditor.EVENTS.TEXT_CHANGED,
|
||||
function onChange() {
|
||||
gDebugger.editor.removeEventListener(SourceEditor.EVENTS.TEXT_CHANGED,
|
||||
onChange);
|
||||
testSwitchPaused();
|
||||
});
|
||||
gScripts.selectedIndex = 0;
|
||||
gDebugger.SourceScripts.onChange({ target: gScripts });
|
||||
});
|
||||
}}, 0);
|
||||
});
|
||||
|
||||
gDebuggee.firstCall();
|
||||
}
|
||||
|
||||
function testSwitchPaused()
|
||||
{
|
||||
ok(gDebugger.editor.getText().search(/debugger/) == -1,
|
||||
"The second script is no longer displayed.");
|
||||
|
||||
ok(gDebugger.editor.getText().search(/firstCall/) != -1,
|
||||
"The first script is displayed.");
|
||||
|
||||
gDebugger.StackFrames.activeThread.resume(function() {
|
||||
gDebugger.editor.addEventListener(SourceEditor.EVENTS.TEXT_CHANGED,
|
||||
function onSecondChange() {
|
||||
gDebugger.editor.removeEventListener(SourceEditor.EVENTS.TEXT_CHANGED,
|
||||
onSecondChange);
|
||||
testSwitchRunning();
|
||||
});
|
||||
gScripts.selectedIndex = 1;
|
||||
gDebugger.SourceScripts.onChange({ target: gScripts });
|
||||
});
|
||||
}
|
||||
|
||||
function testSwitchRunning()
|
||||
{
|
||||
ok(gDebugger.editor.getText().search(/debugger/) != -1,
|
||||
"The second script is displayed again.");
|
||||
|
||||
ok(gDebugger.editor.getText().search(/firstCall/) == -1,
|
||||
"The first script is no longer displayed.");
|
||||
|
||||
removeTab(gTab);
|
||||
finish();
|
||||
}
|
|
@ -0,0 +1,51 @@
|
|||
/* vim:set ts=2 sw=2 sts=2 et: */
|
||||
/*
|
||||
* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/
|
||||
*/
|
||||
|
||||
var gPane = null;
|
||||
var gTab = null;
|
||||
var gDebuggee = null;
|
||||
var gDebugger = null;
|
||||
|
||||
function test() {
|
||||
debug_tab_pane(STACK_URL, function(aTab, aDebuggee, aPane) {
|
||||
gTab = aTab;
|
||||
gDebuggee = aDebuggee;
|
||||
gPane = aPane;
|
||||
gDebugger = gPane.debuggerWindow;
|
||||
|
||||
testSimpleCall();
|
||||
});
|
||||
}
|
||||
|
||||
function testSimpleCall() {
|
||||
gPane.activeThread.addOneTimeListener("framesadded", function() {
|
||||
Services.tm.currentThread.dispatch({ run: function() {
|
||||
|
||||
let frames = gDebugger.DebuggerView.Stackframes._frames;
|
||||
let childNodes = frames.childNodes;
|
||||
|
||||
is(gDebugger.StackFrames.activeThread.state, "paused",
|
||||
"Should only be getting stack frames while paused.");
|
||||
|
||||
is(frames.querySelectorAll(".dbg-stackframe").length, 1,
|
||||
"Should have only one frame.");
|
||||
|
||||
is(childNodes.length, frames.querySelectorAll(".dbg-stackframe").length,
|
||||
"All children should be frames.");
|
||||
|
||||
resumeAndFinish();
|
||||
}}, 0);
|
||||
});
|
||||
|
||||
gDebuggee.simpleCall();
|
||||
}
|
||||
|
||||
function resumeAndFinish() {
|
||||
gDebugger.StackFrames.activeThread.resume(function() {
|
||||
removeTab(gTab);
|
||||
finish();
|
||||
});
|
||||
}
|
|
@ -0,0 +1,83 @@
|
|||
/* vim:set ts=2 sw=2 sts=2 et: */
|
||||
/*
|
||||
* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/
|
||||
*/
|
||||
|
||||
var gPane = null;
|
||||
var gTab = null;
|
||||
var gDebuggee = null;
|
||||
var gDebugger = null;
|
||||
|
||||
function test() {
|
||||
debug_tab_pane(STACK_URL, function(aTab, aDebuggee, aPane) {
|
||||
gTab = aTab;
|
||||
gDebuggee = aDebuggee;
|
||||
gPane = aPane;
|
||||
gDebugger = gPane.debuggerWindow;
|
||||
|
||||
testEvalCall();
|
||||
});
|
||||
}
|
||||
|
||||
function testEvalCall() {
|
||||
gPane.activeThread.addOneTimeListener("framesadded", function() {
|
||||
Services.tm.currentThread.dispatch({ run: function() {
|
||||
|
||||
let frames = gDebugger.DebuggerView.Stackframes._frames;
|
||||
let childNodes = frames.childNodes;
|
||||
|
||||
is(gDebugger.StackFrames.activeThread.state, "paused",
|
||||
"Should only be getting stack frames while paused.");
|
||||
|
||||
is(frames.querySelectorAll(".dbg-stackframe").length, 2,
|
||||
"Should have two frames.");
|
||||
|
||||
is(childNodes.length, frames.querySelectorAll(".dbg-stackframe").length,
|
||||
"All children should be frames.");
|
||||
|
||||
is(frames.querySelector("#stackframe-0 .dbg-stackframe-name").textContent,
|
||||
"(eval)", "Frame name should be (eval)");
|
||||
|
||||
ok(frames.querySelector("#stackframe-0").classList.contains("selected"),
|
||||
"First frame should be selected by default.");
|
||||
|
||||
ok(!frames.querySelector("#stackframe-1").classList.contains("selected"),
|
||||
"Second frame should not be selected.");
|
||||
|
||||
|
||||
EventUtils.sendMouseEvent({ type: "click" },
|
||||
frames.querySelector("#stackframe-1"),
|
||||
gDebugger);
|
||||
|
||||
ok(!frames.querySelector("#stackframe-0").classList.contains("selected"),
|
||||
"First frame should not be selected after click.");
|
||||
|
||||
ok(frames.querySelector("#stackframe-1").classList.contains("selected"),
|
||||
"Second frame should be selected after click.");
|
||||
|
||||
|
||||
EventUtils.sendMouseEvent({ type: "click" },
|
||||
frames.querySelector("#stackframe-0 .dbg-stackframe-name"),
|
||||
gDebugger);
|
||||
|
||||
ok(frames.querySelector("#stackframe-0").classList.contains("selected"),
|
||||
"First frame should be selected after click inside the first frame.");
|
||||
|
||||
ok(!frames.querySelector("#stackframe-1").classList.contains("selected"),
|
||||
"Second frame should not be selected after click inside the first frame.");
|
||||
|
||||
resumeAndFinish();
|
||||
}}, 0);
|
||||
});
|
||||
|
||||
gDebuggee.evalCall();
|
||||
}
|
||||
|
||||
function resumeAndFinish() {
|
||||
gDebugger.StackFrames.activeThread.resume(function() {
|
||||
removeTab(gTab);
|
||||
finish();
|
||||
});
|
||||
}
|
||||
|
|
@ -0,0 +1,68 @@
|
|||
/* vim:set ts=2 sw=2 sts=2 et: */
|
||||
/*
|
||||
* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/
|
||||
*/
|
||||
|
||||
var gPane = null;
|
||||
var gTab = null;
|
||||
var gDebuggee = null;
|
||||
var gDebugger = null;
|
||||
|
||||
function test() {
|
||||
debug_tab_pane(STACK_URL, function(aTab, aDebuggee, aPane) {
|
||||
gTab = aTab;
|
||||
gDebuggee = aDebuggee;
|
||||
gPane = aPane;
|
||||
gDebugger = gPane.debuggerWindow;
|
||||
|
||||
testRecurse();
|
||||
});
|
||||
}
|
||||
|
||||
function testRecurse() {
|
||||
gDebuggee.gRecurseLimit = (gDebugger.StackFrames.pageSize * 2) + 1;
|
||||
|
||||
gPane.activeThread.addOneTimeListener("framesadded", function() {
|
||||
Services.tm.currentThread.dispatch({ run: function() {
|
||||
|
||||
let frames = gDebugger.DebuggerView.Stackframes._frames;
|
||||
let pageSize = gDebugger.StackFrames.pageSize;
|
||||
let recurseLimit = gDebuggee.gRecurseLimit;
|
||||
let childNodes = frames.childNodes;
|
||||
|
||||
is(frames.querySelectorAll(".dbg-stackframe").length, pageSize,
|
||||
"Should have the max limit of frames.");
|
||||
|
||||
is(childNodes.length, frames.querySelectorAll(".dbg-stackframe").length,
|
||||
"All children should be frames.");
|
||||
|
||||
|
||||
gPane.activeThread.addOneTimeListener("framesadded", function() {
|
||||
|
||||
is(frames.querySelectorAll(".dbg-stackframe").length, pageSize * 2,
|
||||
"Should now have twice the max limit of frames.");
|
||||
|
||||
gPane.activeThread.addOneTimeListener("framesadded", function() {
|
||||
is(frames.querySelectorAll(".dbg-stackframe").length, recurseLimit,
|
||||
"Should have reached the recurse limit.");
|
||||
|
||||
resumeAndFinish();
|
||||
});
|
||||
|
||||
frames.scrollTop = frames.scrollHeight;
|
||||
});
|
||||
|
||||
frames.scrollTop = frames.scrollHeight;
|
||||
}}, 0);
|
||||
});
|
||||
|
||||
gDebuggee.recurse();
|
||||
}
|
||||
|
||||
function resumeAndFinish() {
|
||||
gDebugger.StackFrames.activeThread.resume(function() {
|
||||
removeTab(gTab);
|
||||
finish();
|
||||
});
|
||||
}
|
|
@ -0,0 +1,60 @@
|
|||
/* vim:set ts=2 sw=2 sts=2 et: */
|
||||
/*
|
||||
* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/
|
||||
*/
|
||||
|
||||
var gPane = null;
|
||||
var gTab = null;
|
||||
var gDebuggee = null;
|
||||
var gDebugger = null;
|
||||
|
||||
function test() {
|
||||
debug_tab_pane(STACK_URL, function(aTab, aDebuggee, aPane) {
|
||||
gTab = aTab;
|
||||
gDebuggee = aDebuggee;
|
||||
gPane = aPane;
|
||||
gDebugger = gPane.debuggerWindow;
|
||||
|
||||
testEvalCallResume();
|
||||
});
|
||||
}
|
||||
|
||||
function testEvalCallResume() {
|
||||
gPane.activeThread.addOneTimeListener("framesadded", function() {
|
||||
Services.tm.currentThread.dispatch({ run: function() {
|
||||
|
||||
let frames = gDebugger.DebuggerView.Stackframes._frames;
|
||||
let childNodes = frames.childNodes;
|
||||
|
||||
is(gDebugger.StackFrames.activeThread.state, "paused",
|
||||
"Should only be getting stack frames while paused.");
|
||||
|
||||
is(frames.querySelectorAll(".dbg-stackframe").length, 2,
|
||||
"Should have two frames.");
|
||||
|
||||
is(childNodes.length, frames.querySelectorAll(".dbg-stackframe").length,
|
||||
"All children should be frames.");
|
||||
|
||||
|
||||
gPane.activeThread.addOneTimeListener("framescleared", function() {
|
||||
|
||||
is(frames.querySelectorAll(".dbg-stackframe").length, 0,
|
||||
"Should have no frames after resume");
|
||||
|
||||
is(childNodes.length, 1,
|
||||
"Should only have one child.");
|
||||
|
||||
is(frames.querySelectorAll(".empty").length, 1,
|
||||
"Should have the empty list explanation.");
|
||||
|
||||
removeTab(gTab);
|
||||
finish();
|
||||
});
|
||||
|
||||
gPane.activeThread.resume();
|
||||
}}, 0);
|
||||
});
|
||||
|
||||
gDebuggee.evalCall();
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head><title>Browser Debugger Test Tab</title>
|
||||
<!-- Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ -->
|
||||
<script type="text/javascript">
|
||||
|
||||
function simpleCall() {
|
||||
debugger;
|
||||
}
|
||||
|
||||
function evalCall() {
|
||||
eval("debugger;");
|
||||
}
|
||||
|
||||
var gRecurseLimit = 100;
|
||||
var gRecurseDepth = 0;
|
||||
function recurse() {
|
||||
if (++gRecurseDepth == gRecurseLimit) {
|
||||
debugger;
|
||||
gRecurseDepth = 0;
|
||||
return;
|
||||
}
|
||||
recurse();
|
||||
}
|
||||
|
||||
</script>
|
||||
</head>
|
||||
|
||||
<body></body>
|
||||
|
||||
</html>
|
|
@ -0,0 +1,10 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<title>Browser Debugger Test Tab</title>
|
||||
<!-- Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ -->
|
||||
</head>
|
||||
<body>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,10 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<title>Browser Debugger Test Tab 2</title>
|
||||
<!-- Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ -->
|
||||
</head>
|
||||
<body>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,49 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
/**
|
||||
* Check extension-added tab actor lifetimes.
|
||||
*/
|
||||
|
||||
var gTab1 = null;
|
||||
var gTab1Actor = null;
|
||||
|
||||
var gClient = null;
|
||||
|
||||
function test()
|
||||
{
|
||||
DebuggerServer.addActors("chrome://mochitests/content/browser/browser/devtools/debugger/test/testactors.js");
|
||||
|
||||
let transport = DebuggerServer.connectPipe();
|
||||
gClient = new DebuggerClient(transport);
|
||||
gClient.connect(function (aType, aTraits) {
|
||||
is(aType, "browser", "Root actor should identify itself as a browser.");
|
||||
get_tab();
|
||||
});
|
||||
}
|
||||
|
||||
function get_tab()
|
||||
{
|
||||
gTab1 = addTab(TAB1_URL, function () {
|
||||
attach_tab_actor_for_url(gClient, TAB1_URL, function (aGrip) {
|
||||
gTab1Actor = aGrip.actor;
|
||||
gClient.request({ to: aGrip.actor, type: "testTabActor1" }, function (aResponse) {
|
||||
ok(aResponse.actor, "testTabActor1 request should return an actor.");
|
||||
ok(aResponse.actor.indexOf("testone") >= 0,
|
||||
"testTabActor's actorPrefix should be used.");
|
||||
gClient.request({ to: aResponse.actor, type: "ping" }, function (aResponse) {
|
||||
is(aResponse.pong, "pong", "Actor should response to requests.");
|
||||
finish_test();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function finish_test()
|
||||
{
|
||||
gClient.close(function() {
|
||||
removeTab(gTab1);
|
||||
finish();
|
||||
});
|
||||
}
|
|
@ -0,0 +1,51 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
/**
|
||||
* Check extension-added tab actor lifetimes.
|
||||
*/
|
||||
|
||||
var gTab1 = null;
|
||||
var gTab1Actor = null;
|
||||
|
||||
var gClient = null;
|
||||
|
||||
function test()
|
||||
{
|
||||
DebuggerServer.addActors("chrome://mochitests/content/browser/browser/devtools/debugger/test/testactors.js");
|
||||
|
||||
let transport = DebuggerServer.connectPipe();
|
||||
gClient = new DebuggerClient(transport);
|
||||
gClient.connect(function (aType, aTraits) {
|
||||
is(aType, "browser", "Root actor should identify itself as a browser.");
|
||||
get_tab();
|
||||
});
|
||||
}
|
||||
|
||||
function get_tab()
|
||||
{
|
||||
gTab1 = addTab(TAB1_URL, function () {
|
||||
attach_tab_actor_for_url(gClient, TAB1_URL, function (aGrip) {
|
||||
gTab1Actor = aGrip.actor;
|
||||
gClient.request({ to: aGrip.actor, type: "testTabActor1" }, function (aResponse) {
|
||||
close_tab(aResponse.actor);
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function close_tab(aTestActor)
|
||||
{
|
||||
removeTab(gTab1);
|
||||
gClient.request({ to: aTestActor, type: "ping" }, function (aResponse) {
|
||||
is(aResponse.error, "noSuchActor", "testTabActor1 should have gone away with the tab.");
|
||||
finish_test();
|
||||
});
|
||||
}
|
||||
|
||||
function finish_test()
|
||||
{
|
||||
gClient.close(function () {
|
||||
finish();
|
||||
});
|
||||
}
|
|
@ -0,0 +1,99 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
const Cc = Components.classes;
|
||||
const Ci = Components.interfaces;
|
||||
const Cu = Components.utils;
|
||||
let tempScope = {};
|
||||
Cu.import("resource:///modules/devtools/dbg-server.jsm", tempScope);
|
||||
Cu.import("resource:///modules/devtools/dbg-client.jsm", tempScope);
|
||||
Cu.import("resource:///modules/Services.jsm", tempScope);
|
||||
let DebuggerServer = tempScope.DebuggerServer;
|
||||
let DebuggerTransport = tempScope.DebuggerTransport;
|
||||
let DebuggerClient = tempScope.DebuggerClient;
|
||||
let Services = tempScope.Services;
|
||||
|
||||
const TAB1_URL = "http://example.com/browser/browser/devtools/debugger/test/browser_dbg_tab1.html";
|
||||
|
||||
const TAB2_URL = "http://example.com/browser/browser/devtools/debugger/test/browser_dbg_tab2.html";
|
||||
|
||||
const STACK_URL = "http://example.com/browser/browser/devtools/debugger/test/browser_dbg_stack.html";
|
||||
|
||||
if (!DebuggerServer.initialized) {
|
||||
DebuggerServer.init();
|
||||
DebuggerServer.addBrowserActors();
|
||||
}
|
||||
|
||||
waitForExplicitFinish();
|
||||
|
||||
function addTab(aURL, aOnload)
|
||||
{
|
||||
gBrowser.selectedTab = gBrowser.addTab(aURL);
|
||||
|
||||
let tab = gBrowser.selectedTab;
|
||||
if (aOnload) {
|
||||
let handler = function() {
|
||||
if (tab.linkedBrowser.currentURI.spec == aURL) {
|
||||
tab.removeEventListener("load", handler, false);
|
||||
aOnload();
|
||||
}
|
||||
}
|
||||
tab.addEventListener("load", handler, false);
|
||||
}
|
||||
|
||||
return tab;
|
||||
}
|
||||
|
||||
function removeTab(aTab) {
|
||||
gBrowser.removeTab(aTab);
|
||||
}
|
||||
|
||||
function get_tab_actor_for_url(aClient, aURL, aCallback) {
|
||||
aClient.listTabs(function(aResponse) {
|
||||
for each (let tab in aResponse.tabs) {
|
||||
if (tab.url == aURL) {
|
||||
aCallback(tab);
|
||||
return;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function attach_tab_actor_for_url(aClient, aURL, aCallback) {
|
||||
get_tab_actor_for_url(aClient, aURL, function(actor) {
|
||||
aClient.request({ to: actor.actor, type: "attach" }, function(aResponse) {
|
||||
aCallback(actor, aResponse);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function attach_thread_actor_for_url(aClient, aURL, aCallback) {
|
||||
attach_tab_actor_for_url(aClient, aURL, function(aTabActor, aResponse) {
|
||||
aClient.request({ "to": actor.threadActor, "type": "attach" }, function(aResponse) {
|
||||
// We don't care about the pause right now (use
|
||||
// get_actor_for_url() if you do), so resume it.
|
||||
aClient.request({ to: actor.threadActor, type: "resume" }, function(aResponse) {
|
||||
aCallback(actor);
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function debug_tab_pane(aURL, aOnDebugging)
|
||||
{
|
||||
let tab = addTab(aURL, function() {
|
||||
gBrowser.selectedTab = gTab;
|
||||
|
||||
let debuggee = tab.linkedBrowser.contentWindow.wrappedJSObject;
|
||||
|
||||
let pane = DebuggerUI.toggleDebugger();
|
||||
pane.onConnected = function() {
|
||||
// Wait for the initial resume...
|
||||
pane.debuggerWindow.gClient.addOneTimeListener("resumed", function() {
|
||||
delete pane.onConnected;
|
||||
aOnDebugging(tab, debuggee, pane);
|
||||
});
|
||||
};
|
||||
});
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
function firstCall() {
|
||||
eval("secondCall();");
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
function secondCall() {
|
||||
eval("debugger;");
|
||||
}
|
|
@ -0,0 +1,58 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
function TestActor1(aConnection, aTab, aOnDisconnect)
|
||||
{
|
||||
this.conn = aConnection;
|
||||
this.tab = aTab;
|
||||
this.onDisconnect = aOnDisconnect;
|
||||
}
|
||||
|
||||
TestActor1.prototype = {
|
||||
actorPrefix: "testone",
|
||||
|
||||
disconnect: function TA1_disconnect() {
|
||||
this.onDisconnect();
|
||||
},
|
||||
|
||||
grip: function TA1_grip() {
|
||||
return { actor: this.actorID,
|
||||
test: "TestActor1" };
|
||||
},
|
||||
|
||||
onPing: function TA1_onPing() {
|
||||
return { pong: "pong" };
|
||||
}
|
||||
};
|
||||
|
||||
TestActor1.prototype.requestTypes = {
|
||||
"ping": TestActor1.prototype.onPing
|
||||
};
|
||||
|
||||
DebuggerServer.addTabRequest("testTabActor1", function (aTab) {
|
||||
if (aTab._testTabActor1) {
|
||||
return aTab._testTabActor1.grip();
|
||||
}
|
||||
|
||||
let actor = new TestActor1(aTab.conn, aTab.browser, function () {
|
||||
delete aTab._testTabActor1;
|
||||
});
|
||||
aTab.tabActorPool.addActor(actor);
|
||||
aTab._testTabActor1 = actor;
|
||||
return actor.grip();
|
||||
});
|
||||
|
||||
|
||||
DebuggerServer.addTabRequest("testContextActor1", function (aTab, aRequest) {
|
||||
if (aTab._testContextActor1) {
|
||||
return aTab._testContextActor1.grip();
|
||||
}
|
||||
|
||||
let actor = new TestActor1(aTab.conn, aTab.browser, function () {
|
||||
delete aTab._testContextActor1;
|
||||
});
|
||||
aTab.contextActorPool.addActor(actor);
|
||||
aTab._testContextActor1 = actor;
|
||||
return actor.grip();
|
||||
});
|
||||
|
|
@ -409,11 +409,11 @@ Highlighter.prototype = {
|
|||
*
|
||||
* <box id="highlighter-nodeinfobar-container">
|
||||
* <box id="Highlighter-nodeinfobar-arrow-top"/>
|
||||
* <vbox id="highlighter-nodeinfobar">
|
||||
* <label id="highlighter-nodeinfobar-tagname"/>
|
||||
* <label id="highlighter-nodeinfobar-id"/>
|
||||
* <vbox id="highlighter-nodeinfobar-classes"/>
|
||||
* </vbox>
|
||||
* <hbox id="highlighter-nodeinfobar">
|
||||
* <xhtml:span id="highlighter-nodeinfobar-tagname"/>
|
||||
* <xhtml:span id="highlighter-nodeinfobar-id"/>
|
||||
* <xhtml:span id="highlighter-nodeinfobar-classes"/>
|
||||
* </hbox>
|
||||
* <box id="Highlighter-nodeinfobar-arrow-bottom"/>
|
||||
* </box>
|
||||
*
|
||||
|
@ -438,16 +438,16 @@ Highlighter.prototype = {
|
|||
arrowBoxBottom.className = "highlighter-nodeinfobar-arrow";
|
||||
arrowBoxBottom.id = "highlighter-nodeinfobar-arrow-bottom";
|
||||
|
||||
let tagNameLabel = this.chromeDoc.createElement("label");
|
||||
let tagNameLabel = this.chromeDoc.createElementNS("http://www.w3.org/1999/xhtml", "span");
|
||||
tagNameLabel.id = "highlighter-nodeinfobar-tagname";
|
||||
tagNameLabel.className = "plain";
|
||||
|
||||
let idLabel = this.chromeDoc.createElement("label");
|
||||
let idLabel = this.chromeDoc.createElementNS("http://www.w3.org/1999/xhtml", "span");
|
||||
idLabel.id = "highlighter-nodeinfobar-id";
|
||||
idLabel.className = "plain";
|
||||
|
||||
let classesBox = this.chromeDoc.createElement("hbox");
|
||||
let classesBox = this.chromeDoc.createElementNS("http://www.w3.org/1999/xhtml", "span");
|
||||
classesBox.id = "highlighter-nodeinfobar-classes";
|
||||
// Add some content to force a better boundingClientRect down below.
|
||||
classesBox.textContent = " ";
|
||||
|
||||
nodeInfobar.appendChild(tagNameLabel);
|
||||
nodeInfobar.appendChild(idLabel);
|
||||
|
@ -528,7 +528,7 @@ Highlighter.prototype = {
|
|||
},
|
||||
|
||||
/**
|
||||
* Update node information (tagName#id.class)
|
||||
* Update node information (tagName#id.class)
|
||||
*/
|
||||
updateInfobar: function Highlighter_updateInfobar()
|
||||
{
|
||||
|
@ -540,20 +540,9 @@ Highlighter.prototype = {
|
|||
|
||||
// Classes
|
||||
let classes = this.nodeInfo.classesBox;
|
||||
while (classes.hasChildNodes()) {
|
||||
classes.removeChild(classes.firstChild);
|
||||
}
|
||||
|
||||
if (this.node.className) {
|
||||
let fragment = this.chromeDoc.createDocumentFragment();
|
||||
for (let i = 0; i < this.node.classList.length; i++) {
|
||||
let classLabel = this.chromeDoc.createElement("label");
|
||||
classLabel.className = "highlighter-nodeinfobar-class plain";
|
||||
classLabel.textContent = "." + this.node.classList[i];
|
||||
fragment.appendChild(classLabel);
|
||||
}
|
||||
classes.appendChild(fragment);
|
||||
}
|
||||
classes.textContent = this.node.classList.length ?
|
||||
"." + Array.join(this.node.classList, ".") : "";
|
||||
},
|
||||
|
||||
/**
|
||||
|
|
|
@ -222,9 +222,11 @@ InspectorUI.prototype = {
|
|||
openInspectorUI: function IUI_openInspectorUI(aNode)
|
||||
{
|
||||
// InspectorUI is already up and running. Lock a node if asked (via context).
|
||||
if (this.isInspectorOpen && aNode) {
|
||||
this.inspectNode(aNode);
|
||||
this.stopInspecting();
|
||||
if (this.isInspectorOpen) {
|
||||
if (aNode) {
|
||||
this.inspectNode(aNode);
|
||||
this.stopInspecting();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -25,7 +25,7 @@ function test()
|
|||
function setupInfobarTest()
|
||||
{
|
||||
nodes = [
|
||||
{node: doc.querySelector("#top"), position: "bottom", tag: "DIV", id: "#top", classes: ".class1 .class2"},
|
||||
{node: doc.querySelector("#top"), position: "bottom", tag: "DIV", id: "#top", classes: ".class1.class2"},
|
||||
{node: doc.querySelector("#vertical"), position: "overlap", tag: "DIV", id: "#vertical", classes: ""},
|
||||
{node: doc.querySelector("#bottom"), position: "top", tag: "DIV", id: "#bottom", classes: ""},
|
||||
{node: doc.querySelector("body"), position: "overlap", tag: "BODY", id: "", classes: ""},
|
||||
|
@ -86,14 +86,7 @@ function test()
|
|||
is(idLabel.textContent, nodes[cursor].id, "node " + cursor + ": id matches.");
|
||||
|
||||
let classesBox = document.getElementById("highlighter-nodeinfobar-classes");
|
||||
|
||||
let displayedClasses = [];
|
||||
for (let i = 0; i < classesBox.childNodes.length; i++) {
|
||||
displayedClasses.push(classesBox.childNodes[i].textContent);
|
||||
}
|
||||
displayedClasses = displayedClasses.join(" ");
|
||||
|
||||
is(displayedClasses, nodes[cursor].classes, "node " + cursor + ": classes match.");
|
||||
is(classesBox.textContent, nodes[cursor].classes, "node " + cursor + ": classes match.");
|
||||
}
|
||||
|
||||
function finishUp() {
|
||||
|
|
|
@ -11,6 +11,9 @@ browser.jar:
|
|||
content/browser/devtools/styleinspector.css (styleinspector/styleinspector.css)
|
||||
content/browser/orion.js (sourceeditor/orion/orion.js)
|
||||
content/browser/orion.css (sourceeditor/orion/orion.css)
|
||||
content/browser/orion-mozilla.css (sourceeditor/orion/mozilla.css)
|
||||
content/browser/source-editor-overlay.xul (sourceeditor/source-editor-overlay.xul)
|
||||
* content/browser/debugger.xul (debugger/debugger.xul)
|
||||
content/browser/debugger.css (debugger/debugger.css)
|
||||
content/browser/debugger.js (debugger/debugger.js)
|
||||
content/browser/debugger-view.js (debugger/debugger-view.js)
|
||||
|
||||
|
|
|
@ -64,7 +64,7 @@ const XUL_NS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
|
|||
* SourceEditor.THEMES to Orion CSS files.
|
||||
*/
|
||||
const ORION_THEMES = {
|
||||
mozilla: ["chrome://browser/content/orion-mozilla.css"],
|
||||
mozilla: ["chrome://browser/skin/devtools/orion.css"],
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -809,6 +809,20 @@ SourceEditor.prototype = {
|
|||
return this._model.getLineDelimiter();
|
||||
},
|
||||
|
||||
/**
|
||||
* Get the indentation string used in the document being edited.
|
||||
*
|
||||
* @return string
|
||||
* The indentation string.
|
||||
*/
|
||||
getIndentationString: function SE_getIndentationString()
|
||||
{
|
||||
if (this._expandTab) {
|
||||
return (new Array(this._tabSize + 1)).join(" ");
|
||||
}
|
||||
return "\t";
|
||||
},
|
||||
|
||||
/**
|
||||
* Set the source editor mode to the file type you are editing.
|
||||
*
|
||||
|
|
|
@ -324,6 +324,9 @@ function testReturnKey()
|
|||
let lineDelimiter = editor.getLineDelimiter();
|
||||
ok(lineDelimiter, "we have the line delimiter");
|
||||
|
||||
let indentationString = editor.getIndentationString();
|
||||
is(" ", indentationString, "we have an indentation string of 7 spaces");
|
||||
|
||||
is(editor.getText(), " a" + lineDelimiter + " x\n b\n c",
|
||||
"return maintains indentation");
|
||||
|
||||
|
|
|
@ -46,3 +46,7 @@
|
|||
.ruleview-code {
|
||||
direction: ltr;
|
||||
}
|
||||
|
||||
.ruleview-property:not(:hover) > .ruleview-enableproperty {
|
||||
visibility: hidden;
|
||||
}
|
||||
|
|
|
@ -212,6 +212,9 @@ AutocompletePopup.prototype = {
|
|||
*/
|
||||
_updateSize: function AP__updateSize()
|
||||
{
|
||||
if (!this._panel) {
|
||||
return;
|
||||
}
|
||||
this._list.width = this._panel.clientWidth +
|
||||
this._scrollbarWidth;
|
||||
},
|
||||
|
|
|
@ -6948,6 +6948,12 @@ GcliTerm.prototype = {
|
|||
this.context = Cu.getWeakReference(aContentWindow);
|
||||
this.console = aConsole;
|
||||
this.createSandbox();
|
||||
|
||||
this.opts.environment.contentDocument = aContentWindow.document;
|
||||
this.opts.contentDocument = aContentWindow.document;
|
||||
this.opts.jsEnvironment.globalObject = unwrap(aContentWindow);
|
||||
|
||||
gcli._internal.reattachConsole(this.opts);
|
||||
},
|
||||
|
||||
/**
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -54,44 +54,16 @@ var Node = Components.interfaces.nsIDOMNode;
|
|||
* http://opensource.org/licenses/BSD-3-Clause
|
||||
*/
|
||||
|
||||
define('gclitest/index', ['require', 'exports', 'module' , 'gclitest/suite', 'gcli/types/javascript'], function(require, exports, module) {
|
||||
define('gclitest/index', ['require', 'exports', 'module' , 'gclitest/suite'], function(require, exports, module) {
|
||||
|
||||
var examiner = require('gclitest/suite').examiner;
|
||||
var javascript = require('gcli/types/javascript');
|
||||
|
||||
/**
|
||||
* Run the tests defined in the test suite
|
||||
* @param options How the tests are run. Properties include:
|
||||
* - window: The browser window object to run the tests against
|
||||
* - useFakeWindow: Use a test subset and a fake DOM to avoid a real document
|
||||
* - detailedResultLog: console.log test passes and failures in more detail
|
||||
* A simple proxy to examiner.run, for convenience - this is run from the
|
||||
* top level.
|
||||
*/
|
||||
exports.run = function(options) {
|
||||
options = options || {};
|
||||
|
||||
if (options.useFakeWindow) {
|
||||
// A minimum fake dom to get us through the JS tests
|
||||
var doc = { title: 'Fake DOM' };
|
||||
var fakeWindow = {
|
||||
window: { document: doc },
|
||||
document: doc
|
||||
};
|
||||
|
||||
options.window = fakeWindow;
|
||||
}
|
||||
|
||||
if (options.window) {
|
||||
javascript.setGlobalObject(options.window);
|
||||
}
|
||||
|
||||
examiner.run(options);
|
||||
|
||||
if (options.detailedResultLog) {
|
||||
examiner.log();
|
||||
}
|
||||
else {
|
||||
console.log('Completed test suite');
|
||||
}
|
||||
examiner.run(options || {});
|
||||
};
|
||||
});
|
||||
/*
|
||||
|
@ -100,7 +72,7 @@ define('gclitest/index', ['require', 'exports', 'module' , 'gclitest/suite', 'gc
|
|||
* http://opensource.org/licenses/BSD-3-Clause
|
||||
*/
|
||||
|
||||
define('gclitest/suite', ['require', 'exports', 'module' , 'gcli/index', 'test/examiner', 'gclitest/testTokenize', 'gclitest/testSplit', 'gclitest/testCli', 'gclitest/testExec', 'gclitest/testKeyboard', 'gclitest/testScratchpad', 'gclitest/testHistory', 'gclitest/testRequire', 'gclitest/testJs'], function(require, exports, module) {
|
||||
define('gclitest/suite', ['require', 'exports', 'module' , 'gcli/index', 'test/examiner', 'gclitest/testTokenize', 'gclitest/testSplit', 'gclitest/testCli', 'gclitest/testExec', 'gclitest/testKeyboard', 'gclitest/testScratchpad', 'gclitest/testHistory', 'gclitest/testRequire', 'gclitest/testResource', 'gclitest/testJs', 'gclitest/testUtil'], function(require, exports, module) {
|
||||
|
||||
// We need to make sure GCLI is initialized before we begin testing it
|
||||
require('gcli/index');
|
||||
|
@ -118,7 +90,9 @@ define('gclitest/suite', ['require', 'exports', 'module' , 'gcli/index', 'test/e
|
|||
examiner.addSuite('gclitest/testScratchpad', require('gclitest/testScratchpad'));
|
||||
examiner.addSuite('gclitest/testHistory', require('gclitest/testHistory'));
|
||||
examiner.addSuite('gclitest/testRequire', require('gclitest/testRequire'));
|
||||
examiner.addSuite('gclitest/testResource', require('gclitest/testResource'));
|
||||
examiner.addSuite('gclitest/testJs', require('gclitest/testJs'));
|
||||
examiner.addSuite('gclitest/testUtil', require('gclitest/testUtil'));
|
||||
|
||||
exports.examiner = examiner;
|
||||
});
|
||||
|
@ -161,20 +135,56 @@ examiner.addSuite = function(name, suite) {
|
|||
};
|
||||
|
||||
/**
|
||||
* Run all the tests synchronously
|
||||
* Run the tests defined in the test suite synchronously
|
||||
* @param options How the tests are run. Properties include:
|
||||
* - window: The browser window object to run the tests against
|
||||
* - useFakeWindow: Use a test subset and a fake DOM to avoid a real document
|
||||
* - detailedResultLog: console.log test passes and failures in more detail
|
||||
*/
|
||||
examiner.run = function(options) {
|
||||
examiner._checkOptions(options);
|
||||
|
||||
Object.keys(examiner.suites).forEach(function(suiteName) {
|
||||
var suite = examiner.suites[suiteName];
|
||||
suite.run(options);
|
||||
}.bind(this));
|
||||
|
||||
if (options.detailedResultLog) {
|
||||
examiner.log();
|
||||
}
|
||||
else {
|
||||
console.log('Completed test suite');
|
||||
}
|
||||
|
||||
return examiner.suites;
|
||||
};
|
||||
|
||||
/**
|
||||
* Check the options object. There should be either useFakeWindow or a window.
|
||||
* Setup the fake window if requested.
|
||||
*/
|
||||
examiner._checkOptions = function(options) {
|
||||
if (options.useFakeWindow) {
|
||||
// A minimum fake dom to get us through the JS tests
|
||||
var doc = { title: 'Fake DOM' };
|
||||
var fakeWindow = {
|
||||
window: { document: doc },
|
||||
document: doc
|
||||
};
|
||||
|
||||
options.window = fakeWindow;
|
||||
}
|
||||
|
||||
if (!options.window) {
|
||||
throw new Error('Tests need either window or useFakeWindow');
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Run all the tests asynchronously
|
||||
*/
|
||||
examiner.runAsync = function(options, callback) {
|
||||
examiner._checkOptions(options);
|
||||
this.runAsyncInternal(0, options, callback);
|
||||
};
|
||||
|
||||
|
@ -286,12 +296,12 @@ Suite.prototype.run = function(options) {
|
|||
*/
|
||||
Suite.prototype.runAsync = function(options, callback) {
|
||||
if (typeof this.suite.setup == "function") {
|
||||
this.suite.setup();
|
||||
this.suite.setup(options);
|
||||
}
|
||||
|
||||
this.runAsyncInternal(0, options, function() {
|
||||
if (typeof this.suite.shutdown == "function") {
|
||||
this.suite.shutdown();
|
||||
this.suite.shutdown(options);
|
||||
}
|
||||
|
||||
if (typeof callback === 'function') {
|
||||
|
@ -377,7 +387,7 @@ Test.prototype.run = function(options) {
|
|||
*/
|
||||
Test.prototype.runAsync = function(options, callback) {
|
||||
setTimeout(function() {
|
||||
this.run();
|
||||
this.run(options);
|
||||
if (typeof callback === 'function') {
|
||||
callback();
|
||||
}
|
||||
|
@ -1047,7 +1057,7 @@ function update(input) {
|
|||
status = requ.getStatus();
|
||||
assignC = requ.getAssignmentAt(input.cursor.start);
|
||||
statuses = requ.getInputStatusMarkup(input.cursor.start).map(function(s) {
|
||||
return s.toString()[0];
|
||||
return Array(s.string.length + 1).join(s.status.toString()[0]);
|
||||
}).join('');
|
||||
|
||||
if (requ.commandAssignment.getValue()) {
|
||||
|
@ -1506,7 +1516,7 @@ var mockDoc = {
|
|||
* http://opensource.org/licenses/BSD-3-Clause
|
||||
*/
|
||||
|
||||
define('gclitest/testKeyboard', ['require', 'exports', 'module' , 'gcli/cli', 'gcli/types', 'gcli/canon', 'gclitest/commands', 'gcli/types/node', 'test/assert'], function(require, exports, module) {
|
||||
define('gclitest/testKeyboard', ['require', 'exports', 'module' , 'gcli/cli', 'gcli/types', 'gcli/canon', 'gclitest/commands', 'gcli/types/node', 'gcli/types/javascript', 'test/assert'], function(require, exports, module) {
|
||||
|
||||
|
||||
var Requisition = require('gcli/cli').Requisition;
|
||||
|
@ -1514,16 +1524,24 @@ var Status = require('gcli/types').Status;
|
|||
var canon = require('gcli/canon');
|
||||
var commands = require('gclitest/commands');
|
||||
var nodetype = require('gcli/types/node');
|
||||
var javascript = require('gcli/types/javascript');
|
||||
|
||||
var test = require('test/assert');
|
||||
|
||||
var tempWindow;
|
||||
|
||||
exports.setup = function(options) {
|
||||
tempWindow = javascript.getGlobalObject();
|
||||
javascript.setGlobalObject(options.window);
|
||||
|
||||
exports.setup = function() {
|
||||
commands.setup();
|
||||
};
|
||||
|
||||
exports.shutdown = function() {
|
||||
exports.shutdown = function(options) {
|
||||
commands.shutdown();
|
||||
|
||||
javascript.setGlobalObject(tempWindow);
|
||||
tempWindow = undefined;
|
||||
};
|
||||
|
||||
var COMPLETES_TO = 'complete';
|
||||
|
@ -1661,15 +1679,15 @@ stubScratchpad.activate = function(value) {
|
|||
|
||||
|
||||
exports.testActivate = function(options) {
|
||||
if (options.inputter) {
|
||||
var ev = {};
|
||||
stubScratchpad.activatedCount = 0;
|
||||
options.inputter.onKeyUp(ev);
|
||||
test.is(1, stubScratchpad.activatedCount, 'scratchpad is activated');
|
||||
}
|
||||
else {
|
||||
console.log('Skipping scratchpad tests');
|
||||
if (!options.inputter) {
|
||||
console.log('No inputter. Skipping scratchpad tests');
|
||||
return;
|
||||
}
|
||||
|
||||
var ev = {};
|
||||
stubScratchpad.activatedCount = 0;
|
||||
options.inputter.onKeyUp(ev);
|
||||
test.is(1, stubScratchpad.activatedCount, 'scratchpad is activated');
|
||||
};
|
||||
|
||||
|
||||
|
@ -1837,6 +1855,86 @@ define('gclitest/requirable', ['require', 'exports', 'module' ], function(requir
|
|||
exports.setStatus = function(aStatus) { status = aStatus; };
|
||||
exports.getStatus = function() { return status; };
|
||||
|
||||
});
|
||||
/*
|
||||
* Copyright 2009-2011 Mozilla Foundation and contributors
|
||||
* Licensed under the New BSD license. See LICENSE.txt or:
|
||||
* http://opensource.org/licenses/BSD-3-Clause
|
||||
*/
|
||||
|
||||
define('gclitest/testResource', ['require', 'exports', 'module' , 'gcli/types/resource', 'gcli/types', 'test/assert'], function(require, exports, module) {
|
||||
|
||||
|
||||
var resource = require('gcli/types/resource');
|
||||
var types = require('gcli/types');
|
||||
var Status = require('gcli/types').Status;
|
||||
|
||||
var test = require('test/assert');
|
||||
|
||||
var tempDocument;
|
||||
|
||||
exports.setup = function(options) {
|
||||
tempDocument = resource.getDocument();
|
||||
resource.setDocument(options.window.document);
|
||||
};
|
||||
|
||||
exports.shutdown = function(options) {
|
||||
resource.setDocument(tempDocument);
|
||||
tempDocument = undefined;
|
||||
};
|
||||
|
||||
exports.testPredictions = function(options) {
|
||||
if (options.useFakeWindow) {
|
||||
console.log('Skipping resource tests: options.useFakeWindow = true');
|
||||
return;
|
||||
}
|
||||
|
||||
var resource1 = types.getType('resource');
|
||||
var predictions1 = resource1.parseString('').getPredictions();
|
||||
test.ok(predictions1.length > 1, 'have resources');
|
||||
predictions1.forEach(function(prediction) {
|
||||
checkPrediction(resource1, prediction);
|
||||
});
|
||||
|
||||
var resource2 = types.getType({ name: 'resource', include: 'text/javascript' });
|
||||
var predictions2 = resource2.parseString('').getPredictions();
|
||||
test.ok(predictions2.length > 1, 'have resources');
|
||||
predictions2.forEach(function(prediction) {
|
||||
checkPrediction(resource2, prediction);
|
||||
});
|
||||
|
||||
var resource3 = types.getType({ name: 'resource', include: 'text/css' });
|
||||
var predictions3 = resource3.parseString('').getPredictions();
|
||||
// jsdom fails to support digging into stylesheets
|
||||
if (!options.isNode) {
|
||||
test.ok(predictions3.length > 1, 'have resources');
|
||||
}
|
||||
predictions3.forEach(function(prediction) {
|
||||
checkPrediction(resource3, prediction);
|
||||
});
|
||||
|
||||
var resource4 = types.getType({ name: 'resource' });
|
||||
var predictions4 = resource4.parseString('').getPredictions();
|
||||
|
||||
test.is(predictions1.length, predictions4.length, 'type spec');
|
||||
test.is(predictions2.length + predictions3.length, predictions4.length, 'split');
|
||||
};
|
||||
|
||||
function checkPrediction(res, prediction) {
|
||||
var name = prediction.name;
|
||||
var value = prediction.value;
|
||||
|
||||
var conversion = res.parseString(name);
|
||||
test.is(conversion.getStatus(), Status.VALID, 'status VALID for ' + name);
|
||||
test.is(conversion.value, value, 'value for ' + name);
|
||||
|
||||
var strung = res.stringify(value);
|
||||
test.is(strung, name, 'stringify for ' + name);
|
||||
|
||||
test.is(typeof value.loadContents, 'function', 'resource for ' + name);
|
||||
test.is(typeof value.element, 'object', 'resource for ' + name);
|
||||
}
|
||||
|
||||
});
|
||||
/*
|
||||
* Copyright 2009-2011 Mozilla Foundation and contributors
|
||||
|
@ -1859,11 +1957,14 @@ var requ;
|
|||
var assign;
|
||||
var status;
|
||||
var statuses;
|
||||
var globalObject;
|
||||
var tempWindow;
|
||||
|
||||
exports.setup = function() {
|
||||
globalObject = javascript.getGlobalObject();
|
||||
Object.defineProperty(globalObject, 'donteval', {
|
||||
|
||||
exports.setup = function(options) {
|
||||
tempWindow = javascript.getGlobalObject();
|
||||
javascript.setGlobalObject(options.window);
|
||||
|
||||
Object.defineProperty(options.window, 'donteval', {
|
||||
get: function() {
|
||||
test.ok(false, 'donteval should not be used');
|
||||
return { cant: '', touch: '', 'this': '' };
|
||||
|
@ -1873,9 +1974,11 @@ exports.setup = function() {
|
|||
});
|
||||
};
|
||||
|
||||
exports.shutdown = function() {
|
||||
delete globalObject.donteval;
|
||||
globalObject = undefined;
|
||||
exports.shutdown = function(options) {
|
||||
delete options.window.donteval;
|
||||
|
||||
javascript.setGlobalObject(tempWindow);
|
||||
tempWindow = undefined;
|
||||
};
|
||||
|
||||
function input(typed) {
|
||||
|
@ -1894,7 +1997,7 @@ function input(typed) {
|
|||
|
||||
status = requ.getStatus();
|
||||
statuses = requ.getInputStatusMarkup(input.cursor.start).map(function(s) {
|
||||
return s.toString()[0];
|
||||
return Array(s.string.length + 1).join(s.status.toString()[0]);
|
||||
}).join('');
|
||||
|
||||
if (requ.commandAssignment.getValue()) {
|
||||
|
@ -1948,7 +2051,7 @@ function check(expStatuses, expStatus, expAssign, expPredict) {
|
|||
}
|
||||
}
|
||||
|
||||
exports.testBasic = function() {
|
||||
exports.testBasic = function(options) {
|
||||
input('{');
|
||||
check('V', Status.ERROR, '');
|
||||
|
||||
|
@ -1976,7 +2079,7 @@ exports.testBasic = function() {
|
|||
input('{ document.title');
|
||||
check('VVVVVVVVVVVVVVVV', Status.VALID, 'document.title', 0);
|
||||
|
||||
test.ok('donteval' in globalObject, 'donteval exists');
|
||||
test.ok('donteval' in options.window, 'donteval exists');
|
||||
|
||||
input('{ don');
|
||||
check('VVIII', Status.ERROR, 'don', 'donteval');
|
||||
|
@ -2001,6 +2104,35 @@ exports.testBasic = function() {
|
|||
};
|
||||
|
||||
|
||||
});
|
||||
/*
|
||||
* Copyright 2009-2011 Mozilla Foundation and contributors
|
||||
* Licensed under the New BSD license. See LICENSE.txt or:
|
||||
* http://opensource.org/licenses/BSD-3-Clause
|
||||
*/
|
||||
|
||||
define('gclitest/testUtil', ['require', 'exports', 'module' , 'gcli/util', 'test/assert'], function(require, exports, module) {
|
||||
|
||||
var util = require('gcli/util');
|
||||
var test = require('test/assert');
|
||||
|
||||
exports.testFindCssSelector = function(options) {
|
||||
if (options.useFakeWindow) {
|
||||
console.log('Skipping dom.findCssSelector tests due to useFakeWindow');
|
||||
return;
|
||||
}
|
||||
|
||||
var nodes = options.window.document.querySelectorAll('*');
|
||||
for (var i = 0; i < nodes.length; i++) {
|
||||
var selector = util.dom.findCssSelector(nodes[i]);
|
||||
var matches = options.window.document.querySelectorAll(selector);
|
||||
|
||||
test.is(matches.length, 1, 'multiple matches for ' + selector);
|
||||
test.is(matches[0], nodes[i], 'non-matching selector: ' + selector);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
});
|
||||
|
||||
function undefine() {
|
||||
|
@ -2018,7 +2150,9 @@ function undefine() {
|
|||
delete define.modules['gclitest/testHistory'];
|
||||
delete define.modules['gclitest/testRequire'];
|
||||
delete define.modules['gclitest/requirable'];
|
||||
delete define.modules['gclitest/testResource'];
|
||||
delete define.modules['gclitest/testJs'];
|
||||
delete define.modules['gclitest/testUtil'];
|
||||
|
||||
delete define.globalDomain.modules['gclitest/index'];
|
||||
delete define.globalDomain.modules['gclitest/suite'];
|
||||
|
@ -2034,7 +2168,9 @@ function undefine() {
|
|||
delete define.globalDomain.modules['gclitest/testHistory'];
|
||||
delete define.globalDomain.modules['gclitest/testRequire'];
|
||||
delete define.globalDomain.modules['gclitest/requirable'];
|
||||
delete define.globalDomain.modules['gclitest/testResource'];
|
||||
delete define.globalDomain.modules['gclitest/testJs'];
|
||||
delete define.globalDomain.modules['gclitest/testUtil'];
|
||||
}
|
||||
|
||||
registerCleanupFunction(function() {
|
||||
|
|
|
@ -193,6 +193,7 @@
|
|||
@BINPATH@/components/jar.xpt
|
||||
@BINPATH@/components/jsdservice.xpt
|
||||
@BINPATH@/components/jsdebugger.xpt
|
||||
@BINPATH@/components/jsinspector.xpt
|
||||
@BINPATH@/components/layout_base.xpt
|
||||
@BINPATH@/components/layout_forms.xpt
|
||||
#ifdef NS_PRINTING
|
||||
|
|
|
@ -0,0 +1,40 @@
|
|||
<!-- LOCALIZATION NOTE : FILE This file contains the Script Debugger strings -->
|
||||
<!-- LOCALIZATION NOTE : FILE Do not translate commandkey -->
|
||||
|
||||
<!-- LOCALIZATION NOTE : FILE The correct localization of this file might be to
|
||||
- keep it in English, or another language commonly spoken among web developers.
|
||||
- You want to make that choice consistent across the developer tools.
|
||||
- A good criteria is the language in which you'd find the best
|
||||
- documentation on web development on the web. -->
|
||||
|
||||
<!-- LOCALIZATION NOTE (debuggerMenu.label): This is the label for the
|
||||
- application menu item that opens the debugger UI. -->
|
||||
<!ENTITY debuggerMenu.label "Script Debugger">
|
||||
|
||||
<!-- LOCALIZATION NOTE (debuggerMenu.commandkey): This is the command key that
|
||||
- launches the debugger UI. Do not translate this one! -->
|
||||
<!ENTITY debuggerMenu.commandkey "S">
|
||||
|
||||
<!-- LOCALIZATION NOTE (debuggerUI.closeButton): This is the label for the
|
||||
- button that closes the debugger UI. -->
|
||||
<!ENTITY debuggerUI.closeButton "Close">
|
||||
|
||||
<!-- LOCALIZATION NOTE (debuggerUI.resumeButton): This is the label for the
|
||||
- button that resumes the debugger, after it has reached a paused state. In
|
||||
- a paused state the debugger can be used to inspect stack frames, local,
|
||||
- variables etc. -->
|
||||
<!ENTITY debuggerUI.resumeButton "Resume">
|
||||
|
||||
<!-- LOCALIZATION NOTE (debuggerUI.stackTitle): This is the label for the
|
||||
- widget that displays the call stack frames in the debugger. -->
|
||||
<!ENTITY debuggerUI.stackTitle "Call stack">
|
||||
|
||||
<!-- LOCALIZATION NOTE (debuggerUI.scriptTitle): This is the label for the
|
||||
- widget that displays the source code for the script that is currently
|
||||
- being inspected in the debugger. -->
|
||||
<!ENTITY debuggerUI.scriptTitle "Script">
|
||||
|
||||
<!-- LOCALIZATION NOTE (debuggerUI.propertiesTitle): This is the label for the
|
||||
- widget that displays the variables in the various available scopes in the
|
||||
- debugger. -->
|
||||
<!ENTITY debuggerUI.propertiesTitle "Scope variables">
|
|
@ -0,0 +1,46 @@
|
|||
# LOCALIZATION NOTE These strings are used inside the Script Debugger
|
||||
# which is available from the Web Developer sub-menu -> 'Script Debugger'.
|
||||
# The correct localization of this file might be to keep it in
|
||||
# English, or another language commonly spoken among web developers.
|
||||
# You want to make that choice consistent across the developer tools.
|
||||
# A good criteria is the language in which you'd find the best
|
||||
# documentation on web development on the web.
|
||||
|
||||
# LOCALIZATION NOTE (pausedState): The label that is displayed when the
|
||||
# debugger is in a paused state.
|
||||
pausedState=Paused
|
||||
|
||||
# LOCALIZATION NOTE (runningState): The label that is displayed when the
|
||||
# debugger is in a running state.
|
||||
runningState=Running
|
||||
|
||||
# LOCALIZATION NOTE (localScope): The label that is displayed in the variables
|
||||
# pane as a header on the local scope container.
|
||||
localScope=Local
|
||||
|
||||
# LOCALIZATION NOTE (globalScope): The label that is displayed in the variables
|
||||
# pane as a header on the globel scope container.
|
||||
globalScope=Global
|
||||
|
||||
# LOCALIZATION NOTE (localScope): The label that is displayed in the variables
|
||||
# pane as a header on the container for identifiers in a with block.
|
||||
withScope=With block
|
||||
|
||||
# LOCALIZATION NOTE (closureScope): The label that is displayed in the variables
|
||||
# pane as a header on container for identifiers in a closure scope.
|
||||
closureScope=Closure
|
||||
|
||||
# LOCALIZATION NOTE (emptyText): The text that is displayed in the stack frames
|
||||
# list when there are no frames to display.
|
||||
emptyText=Empty
|
||||
|
||||
# LOCALIZATION NOTE (loadingText): The text that is displayed in the script
|
||||
# editor when the laoding process has started but there is no file to display
|
||||
# yet.
|
||||
loadingText=Loading\u2026
|
||||
|
||||
# LOCALIZATION NOTE (loadingError):
|
||||
# This is the error message that is displayed on failed attempts to load an
|
||||
# external resource file.
|
||||
# %1$S=URL, %2$S=status code
|
||||
loadingError=Error loading %1$S: %2$S
|
|
@ -15,6 +15,8 @@
|
|||
* locale/browser/browser.dtd (%chrome/browser/browser.dtd)
|
||||
locale/browser/baseMenuOverlay.dtd (%chrome/browser/baseMenuOverlay.dtd)
|
||||
locale/browser/browser.properties (%chrome/browser/browser.properties)
|
||||
locale/browser/devtools/debugger.dtd (%chrome/browser/devtools/debugger.dtd)
|
||||
locale/browser/devtools/debugger.properties (%chrome/browser/devtools/debugger.properties)
|
||||
locale/browser/devtools/gcli.properties (%chrome/browser/devtools/gcli.properties)
|
||||
locale/browser/devtools/gclicommands.properties (%chrome/browser/devtools/gclicommands.properties)
|
||||
locale/browser/devtools/webconsole.properties (%chrome/browser/devtools/webconsole.properties)
|
||||
|
|
|
@ -68,6 +68,7 @@ browser/components/shell/public/Makefile
|
|||
browser/components/shell/src/Makefile
|
||||
browser/components/tabview/Makefile
|
||||
browser/devtools/Makefile
|
||||
browser/devtools/debugger/Makefile
|
||||
browser/devtools/highlighter/Makefile
|
||||
browser/devtools/scratchpad/Makefile
|
||||
browser/devtools/shared/Makefile
|
||||
|
@ -136,6 +137,7 @@ if [ "$ENABLE_TESTS" ]; then
|
|||
browser/components/privatebrowsing/test/browser/Makefile
|
||||
browser/components/tabview/test/Makefile
|
||||
browser/components/test/Makefile
|
||||
browser/devtools/debugger/test/Makefile
|
||||
browser/devtools/highlighter/test/Makefile
|
||||
browser/devtools/scratchpad/test/Makefile
|
||||
browser/devtools/shared/test/Makefile
|
||||
|
|
|
@ -2019,21 +2019,18 @@ panel[dimmed="true"] {
|
|||
|
||||
/* Highlighter - Node Infobar - text */
|
||||
|
||||
#highlighter-nodeinfobar-tagname {
|
||||
html|*#highlighter-nodeinfobar-tagname {
|
||||
color: white;
|
||||
}
|
||||
|
||||
#highlighter-nodeinfobar-id {
|
||||
html|*#highlighter-nodeinfobar-id {
|
||||
color: hsl(90, 79%, 52%);
|
||||
}
|
||||
|
||||
.highlighter-nodeinfobar-class {
|
||||
color: hsl(200, 100%, 65%);
|
||||
}
|
||||
|
||||
/* Highlighter - Node Infobar - box & arrow */
|
||||
|
||||
#highlighter-nodeinfobar {
|
||||
color: hsl(200, 100%, 65%);
|
||||
border: 1px solid hsla(210, 19%, 63%, .5);
|
||||
border-radius: 3px;
|
||||
padding: 8px 16px;
|
||||
|
|
|
@ -0,0 +1,262 @@
|
|||
/* -*- Mode: javascript; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is mozilla.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Mozilla Foundation
|
||||
* Portions created by the Initial Developer are Copyright (C) 2011
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Dave Camp <dcamp@mozilla.com>
|
||||
* Victor Porof <vporof@mozilla.com>
|
||||
* Panos Astithas <past@mozilla.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#body {
|
||||
background: -moz-dialog;
|
||||
}
|
||||
|
||||
div,
|
||||
span,
|
||||
a {
|
||||
font: inherit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Debugger toolbar
|
||||
*/
|
||||
|
||||
#dbg-toolbar {
|
||||
padding: 2px;
|
||||
}
|
||||
|
||||
#dbg-toolbar > button {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
/**
|
||||
* Debugger content
|
||||
*/
|
||||
|
||||
#dbg-content {
|
||||
padding: 6px;
|
||||
}
|
||||
|
||||
#dbg-content > * > .vbox {
|
||||
background-color: #fff;
|
||||
border: 1px solid #bbb;
|
||||
box-shadow: 0 -5px 10px -3px #ccc;
|
||||
-moz-margin-end: -1px;
|
||||
}
|
||||
|
||||
#dbg-content > * > .title {
|
||||
text-shadow: 0 1px #fff;
|
||||
}
|
||||
|
||||
/**
|
||||
* Debugger statusbar
|
||||
*/
|
||||
|
||||
#dbg-statusbar {
|
||||
font: -moz-list;
|
||||
padding: 2px;
|
||||
-moz-padding-start: 5px;
|
||||
}
|
||||
|
||||
/**
|
||||
* Lists and headers
|
||||
*/
|
||||
|
||||
.list-item {
|
||||
padding: 2px;
|
||||
font: -moz-list;
|
||||
}
|
||||
|
||||
.list-item.selected {
|
||||
background: Highlight;
|
||||
color: HighlightText;
|
||||
}
|
||||
|
||||
.list-item.empty {
|
||||
color: GrayText;
|
||||
}
|
||||
|
||||
/**
|
||||
* Stack frames
|
||||
*/
|
||||
|
||||
#stackframes {
|
||||
background-color: white;
|
||||
}
|
||||
|
||||
.dbg-stackframe-id {
|
||||
-moz-padding-end: 1em;
|
||||
}
|
||||
|
||||
/**
|
||||
* Properties elements
|
||||
*/
|
||||
|
||||
#variables {
|
||||
background-color: white;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generic element details container
|
||||
*/
|
||||
|
||||
.details {
|
||||
-moz-margin-start: 10px;
|
||||
font: -moz-list;
|
||||
}
|
||||
|
||||
/**
|
||||
* Scope element
|
||||
*/
|
||||
|
||||
.scope > .title {
|
||||
margin-top: 1px;
|
||||
-moz-margin-start: 1px;
|
||||
-moz-padding-start: 2px;
|
||||
|
||||
background: -moz-linear-gradient(bottom,
|
||||
rgb(160,175,205) 0,
|
||||
rgb(120,140,175) 100%);
|
||||
|
||||
border-bottom: 1px solid #888;
|
||||
box-shadow: 0 0 4px #ccc;
|
||||
text-shadow: 0 1px #777;
|
||||
color: #fff;
|
||||
font: -moz-list;
|
||||
}
|
||||
|
||||
.scope > .title > .name {
|
||||
padding-top: 2px;
|
||||
padding-bottom: 2px;
|
||||
}
|
||||
|
||||
.scope > .details {
|
||||
-moz-margin-start: 2px;
|
||||
-moz-margin-end: 2px;
|
||||
}
|
||||
|
||||
/**
|
||||
* Variable element
|
||||
*/
|
||||
|
||||
.variable {
|
||||
-moz-margin-start: 1px;
|
||||
-moz-margin-end: 1px;
|
||||
border-bottom: 1px dotted #aaa;
|
||||
}
|
||||
|
||||
.variable > .title > .name {
|
||||
padding-top: 2px;
|
||||
padding-bottom: 2px;
|
||||
color: #048;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
/**
|
||||
* Property element
|
||||
*/
|
||||
|
||||
.property > .title > .key {
|
||||
padding-top: 2px;
|
||||
padding-bottom: 2px;
|
||||
color: #881090;
|
||||
}
|
||||
|
||||
.property > .title > .value {
|
||||
padding-top: 2px;
|
||||
padding-bottom: 2px;
|
||||
}
|
||||
|
||||
/**
|
||||
* Property colors
|
||||
*/
|
||||
|
||||
.token-undefined {
|
||||
-moz-padding-start: 6px;
|
||||
color: #bbb;
|
||||
}
|
||||
|
||||
.token-null {
|
||||
-moz-padding-start: 6px;
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.token-boolean {
|
||||
-moz-padding-start: 6px;
|
||||
color: #777;
|
||||
}
|
||||
|
||||
.token-number {
|
||||
-moz-padding-start: 6px;
|
||||
color: #c40a16;
|
||||
}
|
||||
|
||||
.token-string {
|
||||
-moz-padding-start: 6px;
|
||||
color: #1c00cf;
|
||||
}
|
||||
|
||||
.token-other {
|
||||
-moz-padding-start: 6px;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
/**
|
||||
* Expand/collapse arrow
|
||||
*/
|
||||
|
||||
.arrow {
|
||||
-moz-appearance: treetwisty;
|
||||
-moz-margin-start: 10px;
|
||||
-moz-margin-end: 5px;
|
||||
}
|
||||
|
||||
.arrow[open] {
|
||||
-moz-appearance: treetwistyopen;
|
||||
}
|
||||
|
||||
/**
|
||||
* Display helpers
|
||||
*/
|
||||
|
||||
.unselectable {
|
||||
padding-top: 2px;
|
||||
padding-bottom: 2px;
|
||||
}
|
||||
|
||||
.info {
|
||||
padding-top: 2px;
|
||||
padding-bottom: 2px;
|
||||
}
|
|
@ -1,5 +1,6 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
.viewContainer {
|
||||
background: #cddae5; /* This will be seen as the continuation of the ruler */
|
||||
|
@ -22,17 +23,11 @@
|
|||
padding-left: 4px; /* Margin between the ruler and the editor */
|
||||
}
|
||||
|
||||
/* Styles for rulers */
|
||||
.ruler.lines {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
/* Styles for the line number ruler */
|
||||
.rulerLines {
|
||||
border-right: 1px solid #b4c4d3;
|
||||
background: #cddae5;
|
||||
color: #7a8a99;
|
||||
min-width: 1.4em;
|
||||
padding-left: 4px;
|
||||
padding-right: 4px;
|
||||
text-align: end;
|
||||
|
@ -121,9 +116,6 @@
|
|||
font-weight: bold;
|
||||
}
|
||||
|
||||
.annotationRange.currentBracket {
|
||||
}
|
||||
|
||||
.annotationRange.matchingBracket {
|
||||
outline: 1px solid grey;
|
||||
}
|
|
@ -93,6 +93,7 @@ browser.jar:
|
|||
skin/classic/browser/devtools/webconsole_networkpanel.css (devtools/webconsole_networkpanel.css)
|
||||
skin/classic/browser/devtools/webconsole.png (devtools/webconsole.png)
|
||||
skin/classic/browser/devtools/gcli.css (devtools/gcli.css)
|
||||
skin/classic/browser/devtools/orion.css (devtools/orion.css)
|
||||
skin/classic/browser/devtools/breadcrumbs/ltr-end-pressed.png (devtools/breadcrumbs/ltr-end-pressed.png)
|
||||
skin/classic/browser/devtools/breadcrumbs/ltr-end-selected-pressed.png (devtools/breadcrumbs/ltr-end-selected-pressed.png)
|
||||
skin/classic/browser/devtools/breadcrumbs/ltr-end-selected.png (devtools/breadcrumbs/ltr-end-selected.png)
|
||||
|
@ -119,6 +120,7 @@ browser.jar:
|
|||
skin/classic/browser/devtools/breadcrumbs/rtl-start-selected.png (devtools/breadcrumbs/rtl-start-selected.png)
|
||||
skin/classic/browser/devtools/splitview.css (devtools/splitview.css)
|
||||
skin/classic/browser/devtools/styleeditor.css (devtools/styleeditor.css)
|
||||
skin/classic/browser/devtools/debugger.css (devtools/debugger.css)
|
||||
skin/classic/browser/devtools/magnifying-glass.png (devtools/magnifying-glass.png)
|
||||
skin/classic/browser/devtools/itemToggle.png (devtools/itemToggle.png)
|
||||
skin/classic/browser/devtools/itemArrow-rtl.png (devtools/itemArrow-rtl.png)
|
||||
|
|
|
@ -2768,21 +2768,18 @@ panel[dimmed="true"] {
|
|||
|
||||
/* Highlighter - Node Infobar - text */
|
||||
|
||||
#highlighter-nodeinfobar-tagname {
|
||||
html|*#highlighter-nodeinfobar-tagname {
|
||||
color: white;
|
||||
}
|
||||
|
||||
#highlighter-nodeinfobar-id {
|
||||
html|*#highlighter-nodeinfobar-id {
|
||||
color: hsl(90, 79%, 52%);
|
||||
}
|
||||
|
||||
.highlighter-nodeinfobar-class {
|
||||
color: hsl(200, 100%, 65%);
|
||||
}
|
||||
|
||||
/* Highlighter - Node Infobar - box & arrow */
|
||||
|
||||
#highlighter-nodeinfobar {
|
||||
color: hsl(200, 100%, 65%);
|
||||
border: 1px solid hsla(210, 19%, 63%, .5);
|
||||
border-radius: 3px;
|
||||
padding: 8px 16px;
|
||||
|
|
|
@ -0,0 +1,258 @@
|
|||
/* -*- Mode: javascript; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is mozilla.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Mozilla Foundation
|
||||
* Portions created by the Initial Developer are Copyright (C) 2011
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Dave Camp <dcamp@mozilla.com>
|
||||
* Victor Porof <vporof@mozilla.com>
|
||||
* Panos Astithas <past@mozilla.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#body {
|
||||
background: -moz-dialog;
|
||||
}
|
||||
|
||||
div,
|
||||
span,
|
||||
a {
|
||||
font: inherit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Debugger toolbar
|
||||
*/
|
||||
|
||||
#dbg-toolbar {
|
||||
padding: 2px;
|
||||
}
|
||||
|
||||
#dbg-toolbar > button {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
#dbg-toolbar > button, menulist {
|
||||
-moz-appearance: toolbarbutton;
|
||||
}
|
||||
|
||||
/**
|
||||
* Debugger content
|
||||
*/
|
||||
|
||||
#dbg-content {
|
||||
padding: 6px;
|
||||
}
|
||||
|
||||
#dbg-content > * > .vbox {
|
||||
background-color: #fff;
|
||||
border: 1px solid #bbb;
|
||||
box-shadow: 0 -5px 10px -3px #ccc;
|
||||
-moz-margin-end: -1px;
|
||||
}
|
||||
|
||||
#dbg-content > * > .title {
|
||||
text-shadow: 0 1px #fff;
|
||||
}
|
||||
|
||||
/**
|
||||
* Debugger statusbar
|
||||
*/
|
||||
|
||||
#dbg-statusbar {
|
||||
font: -moz-list;
|
||||
padding: 2px;
|
||||
-moz-padding-start: 5px;
|
||||
}
|
||||
|
||||
/**
|
||||
* Lists and headers
|
||||
*/
|
||||
|
||||
.list-item {
|
||||
padding: 2px;
|
||||
font: -moz-list;
|
||||
}
|
||||
|
||||
.list-item.selected {
|
||||
background: Highlight;
|
||||
color: HighlightText;
|
||||
}
|
||||
|
||||
.list-item.empty {
|
||||
color: GrayText;
|
||||
}
|
||||
|
||||
/**
|
||||
* Stack frames
|
||||
*/
|
||||
|
||||
#stackframes {
|
||||
background-color: white;
|
||||
}
|
||||
|
||||
.dbg-stackframe-id {
|
||||
-moz-padding-end: 1em;
|
||||
}
|
||||
|
||||
/**
|
||||
* Properties elements
|
||||
*/
|
||||
|
||||
#variables {
|
||||
background-color: white;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generic element details container
|
||||
*/
|
||||
|
||||
.details {
|
||||
-moz-margin-start: 10px;
|
||||
font: -moz-list;
|
||||
}
|
||||
|
||||
/**
|
||||
* Scope element
|
||||
*/
|
||||
|
||||
.scope > .title {
|
||||
margin-top: 1px;
|
||||
-moz-margin-start: 1px;
|
||||
-moz-padding-start: 2px;
|
||||
|
||||
background: -moz-linear-gradient(bottom,
|
||||
rgb(160,175,205) 0,
|
||||
rgb(120,140,175) 100%);
|
||||
|
||||
border-bottom: 1px solid #888;
|
||||
box-shadow: 0 0 4px #ccc;
|
||||
text-shadow: 0 1px #777;
|
||||
color: #fff;
|
||||
font: -moz-list;
|
||||
}
|
||||
|
||||
.scope > .title > .name {
|
||||
padding-top: 4px;
|
||||
}
|
||||
|
||||
.scope > .details {
|
||||
-moz-margin-start: 2px;
|
||||
-moz-margin-end: 2px;
|
||||
}
|
||||
|
||||
/**
|
||||
* Variable element
|
||||
*/
|
||||
|
||||
.variable {
|
||||
-moz-margin-start: 1px;
|
||||
-moz-margin-end: 1px;
|
||||
border-bottom: 1px dotted #aaa;
|
||||
}
|
||||
|
||||
.variable > .title > .name {
|
||||
padding-top: 4px;
|
||||
color: #048;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
/**
|
||||
* Property element
|
||||
*/
|
||||
|
||||
.property > .title > .key {
|
||||
padding-top: 4px;
|
||||
color: #881090;
|
||||
}
|
||||
|
||||
.property > .title > .value {
|
||||
padding-top: 4px;
|
||||
}
|
||||
|
||||
/**
|
||||
* Property colors
|
||||
*/
|
||||
|
||||
.token-undefined {
|
||||
-moz-padding-start: 6px;
|
||||
color: #bbb;
|
||||
}
|
||||
|
||||
.token-null {
|
||||
-moz-padding-start: 6px;
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.token-boolean {
|
||||
-moz-padding-start: 6px;
|
||||
color: #777;
|
||||
}
|
||||
|
||||
.token-number {
|
||||
-moz-padding-start: 6px;
|
||||
color: #c40a16;
|
||||
}
|
||||
|
||||
.token-string {
|
||||
-moz-padding-start: 6px;
|
||||
color: #1c00cf;
|
||||
}
|
||||
|
||||
.token-other {
|
||||
-moz-padding-start: 6px;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
/**
|
||||
* Expand/collapse arrow
|
||||
*/
|
||||
|
||||
.arrow {
|
||||
-moz-appearance: treetwisty;
|
||||
}
|
||||
|
||||
.arrow[open] {
|
||||
-moz-appearance: treetwistyopen;
|
||||
}
|
||||
|
||||
/**
|
||||
* Display helpers
|
||||
*/
|
||||
|
||||
.unselectable {
|
||||
padding-top: 4px;
|
||||
}
|
||||
|
||||
.info {
|
||||
padding-top: 4px;
|
||||
}
|
|
@ -0,0 +1,121 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
.viewContainer {
|
||||
background: #cddae5; /* This will be seen as the continuation of the ruler */
|
||||
font-family: monospace;
|
||||
font-size: inherit; /* inherit browser's default monospace font size */
|
||||
}
|
||||
|
||||
.view {
|
||||
color: black; /* Default text color */
|
||||
background: #f0f0ff; /* Background of the editor */
|
||||
padding-left: 0;
|
||||
}
|
||||
|
||||
.readonly > .view {
|
||||
background: #f0f0ff;
|
||||
}
|
||||
|
||||
/* One line */
|
||||
.viewContent > div {
|
||||
padding-left: 4px; /* Margin between the ruler and the editor */
|
||||
}
|
||||
|
||||
/* Styles for the line number ruler */
|
||||
.rulerLines {
|
||||
border-right: 1px solid #b4c4d3;
|
||||
background: #cddae5;
|
||||
color: #7a8a99;
|
||||
padding-left: 4px;
|
||||
padding-right: 4px;
|
||||
text-align: end;
|
||||
}
|
||||
|
||||
.token_singleline_comment {
|
||||
color: #45a946; /* green */
|
||||
}
|
||||
|
||||
.token_multiline_comment {
|
||||
color: #45a946; /* green */
|
||||
}
|
||||
|
||||
.token_doc_comment {
|
||||
color: #45a946; /* green */
|
||||
}
|
||||
|
||||
.token_doc_html_markup {
|
||||
color: #dd0058; /* purple */
|
||||
}
|
||||
|
||||
.token_doc_tag {
|
||||
color: #dd0058; /* purple */
|
||||
}
|
||||
|
||||
.token_task_tag { /* "TODO" */
|
||||
color: black;
|
||||
background: yellow;
|
||||
}
|
||||
|
||||
.token_string {
|
||||
color: #1e66b1; /* blue */
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
.token_keyword {
|
||||
color: #dd0058; /* purple */
|
||||
}
|
||||
|
||||
.token_space {
|
||||
/* images/white_space.png */
|
||||
background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAkAAAAJCAIAAABv85FHAAAABnRSTlMA/wAAAACkwsAdAAAAIUlEQVR4nGP4z8CAC+GUIEXuABhgkTuABEiRw2cmae4EAH05X7xDolNRAAAAAElFTkSuQmCC");
|
||||
background-repeat: no-repeat;
|
||||
background-position: center center;
|
||||
}
|
||||
|
||||
.token_tab {
|
||||
/* images/white_tab.png */
|
||||
background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAwAAAAJCAIAAACJ2loDAAAABnRSTlMA/wD/AP83WBt9AAAAMklEQVR4nGP4TwRgoK6i52c3bz5w6zMSA6tJn28d2Lx589nnCAYu63AaSLxJRLoJPwAAeNk0aG4opfMAAAAASUVORK5CYII=");
|
||||
background-repeat: no-repeat;
|
||||
background-position: left center;
|
||||
}
|
||||
|
||||
.line_caret { /* Current line */
|
||||
background: #dae2ee; /* lighter than the background */
|
||||
}
|
||||
|
||||
.readonly .line_caret {
|
||||
background: #cddae5; /* a bit darker than the background */
|
||||
}
|
||||
|
||||
/* Styling for html syntax highlighting */
|
||||
.entity-name-tag {
|
||||
color: #dd0058; /* purple */
|
||||
}
|
||||
|
||||
.entity-other-attribute-name {
|
||||
color: #dd0058; /* purple */
|
||||
}
|
||||
|
||||
.punctuation-definition-comment {
|
||||
color: #45a946; /* green */
|
||||
}
|
||||
|
||||
.comment {
|
||||
color: #45a946; /* green */
|
||||
}
|
||||
|
||||
.string-quoted {
|
||||
color: #1e66b1; /* blue */
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
.invalid {
|
||||
color: red;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.annotationRange.matchingBracket {
|
||||
outline: 1px solid grey;
|
||||
}
|
|
@ -129,6 +129,7 @@ browser.jar:
|
|||
skin/classic/browser/devtools/goto-mdn.png (devtools/goto-mdn.png)
|
||||
skin/classic/browser/devtools/csshtmltree.css (devtools/csshtmltree.css)
|
||||
skin/classic/browser/devtools/gcli.css (devtools/gcli.css)
|
||||
skin/classic/browser/devtools/orion.css (devtools/orion.css)
|
||||
skin/classic/browser/devtools/toolbarbutton-close.png (devtools/toolbarbutton-close.png)
|
||||
* skin/classic/browser/devtools/webconsole.css (devtools/webconsole.css)
|
||||
skin/classic/browser/devtools/webconsole_networkpanel.css (devtools/webconsole_networkpanel.css)
|
||||
|
@ -159,6 +160,7 @@ browser.jar:
|
|||
skin/classic/browser/devtools/breadcrumbs/rtl-start-selected.png (devtools/breadcrumbs/rtl-start-selected.png)
|
||||
skin/classic/browser/devtools/splitview.css (devtools/splitview.css)
|
||||
skin/classic/browser/devtools/styleeditor.css (devtools/styleeditor.css)
|
||||
skin/classic/browser/devtools/debugger.css (devtools/debugger.css)
|
||||
skin/classic/browser/devtools/magnifying-glass.png (devtools/magnifying-glass.png)
|
||||
skin/classic/browser/devtools/itemToggle.png (devtools/itemToggle.png)
|
||||
skin/classic/browser/devtools/itemArrow-rtl.png (devtools/itemArrow-rtl.png)
|
||||
|
|
|
@ -2699,21 +2699,18 @@ panel[dimmed="true"] {
|
|||
|
||||
/* Highlighter - Node Infobar - text */
|
||||
|
||||
#highlighter-nodeinfobar-tagname {
|
||||
html|*#highlighter-nodeinfobar-tagname {
|
||||
color: white;
|
||||
}
|
||||
|
||||
#highlighter-nodeinfobar-id {
|
||||
html|*#highlighter-nodeinfobar-id {
|
||||
color: hsl(90, 79%, 52%);
|
||||
}
|
||||
|
||||
.highlighter-nodeinfobar-class {
|
||||
color: hsl(200, 100%, 65%);
|
||||
}
|
||||
|
||||
/* Highlighter - Node Infobar - box & arrow */
|
||||
|
||||
#highlighter-nodeinfobar {
|
||||
color: hsl(200, 100%, 65%);
|
||||
border: 1px solid hsla(210, 19%, 63%, .5);
|
||||
border-radius: 3px;
|
||||
padding: 8px 16px;
|
||||
|
|
|
@ -0,0 +1,264 @@
|
|||
/* -*- Mode: javascript; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is mozilla.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Mozilla Foundation
|
||||
* Portions created by the Initial Developer are Copyright (C) 2011
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Dave Camp <dcamp@mozilla.com>
|
||||
* Victor Porof <vporof@mozilla.com>
|
||||
* Panos Astithas <past@mozilla.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#body {
|
||||
background: -moz-dialog;
|
||||
}
|
||||
|
||||
div,
|
||||
span,
|
||||
a {
|
||||
font: inherit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Debugger toolbar
|
||||
*/
|
||||
|
||||
#dbg-toolbar {
|
||||
padding: 2px;
|
||||
}
|
||||
|
||||
#dbg-toolbar > button {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
/**
|
||||
* Debugger content
|
||||
*/
|
||||
|
||||
#dbg-content {
|
||||
padding: 6px;
|
||||
}
|
||||
|
||||
#dbg-content > * > .vbox {
|
||||
background-color: #fff;
|
||||
border: 1px solid #bbb;
|
||||
box-shadow: 0 -5px 10px -3px #ccc;
|
||||
-moz-margin-end: -1px;
|
||||
}
|
||||
|
||||
#dbg-content > * > .title {
|
||||
text-shadow: 0 1px #fff;
|
||||
}
|
||||
|
||||
/**
|
||||
* Debugger statusbar
|
||||
*/
|
||||
|
||||
#dbg-statusbar {
|
||||
font: -moz-list;
|
||||
padding: 2px;
|
||||
-moz-padding-start: 5px;
|
||||
}
|
||||
|
||||
/**
|
||||
* Lists and headers
|
||||
*/
|
||||
|
||||
.list-item {
|
||||
padding: 2px;
|
||||
font: -moz-list;
|
||||
}
|
||||
|
||||
.list-item.selected {
|
||||
background: Highlight;
|
||||
color: HighlightText;
|
||||
}
|
||||
|
||||
.list-item.empty {
|
||||
color: GrayText;
|
||||
}
|
||||
|
||||
/**
|
||||
* Stack frames
|
||||
*/
|
||||
|
||||
#stackframes {
|
||||
background-color: white;
|
||||
}
|
||||
|
||||
.dbg-stackframe-id {
|
||||
-moz-padding-end: 1em;
|
||||
}
|
||||
|
||||
/**
|
||||
* Properties elements
|
||||
*/
|
||||
|
||||
#variables {
|
||||
background-color: white;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generic element details container
|
||||
*/
|
||||
|
||||
.details {
|
||||
-moz-margin-start: 10px;
|
||||
font: -moz-list;
|
||||
}
|
||||
|
||||
/**
|
||||
* Scope element
|
||||
*/
|
||||
|
||||
.scope > .title {
|
||||
margin-top: 1px;
|
||||
-moz-margin-start: 1px;
|
||||
-moz-padding-start: 2px;
|
||||
|
||||
background: -moz-linear-gradient(bottom,
|
||||
rgb(160,175,205) 0,
|
||||
rgb(120,140,175) 100%);
|
||||
|
||||
border-bottom: 1px solid #888;
|
||||
box-shadow: 0 0 4px #ccc;
|
||||
text-shadow: 0 1px #777;
|
||||
color: #fff;
|
||||
font: -moz-list;
|
||||
}
|
||||
|
||||
.scope > .title > .name {
|
||||
padding-top: 2px;
|
||||
padding-bottom: 2px;
|
||||
}
|
||||
|
||||
.scope > .details {
|
||||
-moz-margin-start: 2px;
|
||||
-moz-margin-end: 2px;
|
||||
}
|
||||
|
||||
/**
|
||||
* Variable element
|
||||
*/
|
||||
|
||||
.variable {
|
||||
-moz-margin-start: 1px;
|
||||
-moz-margin-end: 1px;
|
||||
border-bottom: 1px dotted #aaa;
|
||||
}
|
||||
|
||||
.variable > .title > .name {
|
||||
padding-top: 2px;
|
||||
padding-bottom: 2px;
|
||||
color: #048;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
/**
|
||||
* Property element
|
||||
*/
|
||||
|
||||
.property > .title > .key {
|
||||
padding-top: 2px;
|
||||
padding-bottom: 2px;
|
||||
color: #881090;
|
||||
}
|
||||
|
||||
.property > .title > .value {
|
||||
padding-top: 2px;
|
||||
padding-bottom: 2px;
|
||||
}
|
||||
|
||||
/**
|
||||
* Property colors
|
||||
*/
|
||||
|
||||
.token-undefined {
|
||||
-moz-padding-start: 6px;
|
||||
color: #bbb;
|
||||
}
|
||||
|
||||
.token-null {
|
||||
-moz-padding-start: 6px;
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.token-boolean {
|
||||
-moz-padding-start: 6px;
|
||||
color: #777;
|
||||
}
|
||||
|
||||
.token-number {
|
||||
-moz-padding-start: 6px;
|
||||
color: #c40a16;
|
||||
}
|
||||
|
||||
.token-string {
|
||||
-moz-padding-start: 6px;
|
||||
color: #1c00cf;
|
||||
}
|
||||
|
||||
.token-other {
|
||||
-moz-padding-start: 6px;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
/**
|
||||
* Expand/collapse arrow
|
||||
*/
|
||||
|
||||
.arrow {
|
||||
width: 9px;
|
||||
height: 9px;
|
||||
-moz-margin-start: 5px;
|
||||
-moz-margin-end: 5px;
|
||||
background: url("chrome://global/skin/tree/twisty-clsd.png") center center no-repeat;
|
||||
}
|
||||
|
||||
.arrow[open] {
|
||||
background-image: url("chrome://global/skin/tree/twisty-open.png");
|
||||
}
|
||||
|
||||
/**
|
||||
* Display helpers
|
||||
*/
|
||||
|
||||
.unselectable {
|
||||
padding-top: 2px;
|
||||
padding-bottom: 2px;
|
||||
}
|
||||
|
||||
.info {
|
||||
padding-top: 2px;
|
||||
padding-bottom: 2px;
|
||||
}
|
|
@ -0,0 +1,121 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
.viewContainer {
|
||||
background: #cddae5; /* This will be seen as the continuation of the ruler */
|
||||
font-family: monospace;
|
||||
font-size: inherit; /* inherit browser's default monospace font size */
|
||||
}
|
||||
|
||||
.view {
|
||||
color: black; /* Default text color */
|
||||
background: #f0f0ff; /* Background of the editor */
|
||||
padding-left: 0;
|
||||
}
|
||||
|
||||
.readonly > .view {
|
||||
background: #f0f0ff;
|
||||
}
|
||||
|
||||
/* One line */
|
||||
.viewContent > div {
|
||||
padding-left: 4px; /* Margin between the ruler and the editor */
|
||||
}
|
||||
|
||||
/* Styles for the line number ruler */
|
||||
.rulerLines {
|
||||
border-right: 1px solid #b4c4d3;
|
||||
background: #cddae5;
|
||||
color: #7a8a99;
|
||||
padding-left: 4px;
|
||||
padding-right: 4px;
|
||||
text-align: end;
|
||||
}
|
||||
|
||||
.token_singleline_comment {
|
||||
color: #45a946; /* green */
|
||||
}
|
||||
|
||||
.token_multiline_comment {
|
||||
color: #45a946; /* green */
|
||||
}
|
||||
|
||||
.token_doc_comment {
|
||||
color: #45a946; /* green */
|
||||
}
|
||||
|
||||
.token_doc_html_markup {
|
||||
color: #dd0058; /* purple */
|
||||
}
|
||||
|
||||
.token_doc_tag {
|
||||
color: #dd0058; /* purple */
|
||||
}
|
||||
|
||||
.token_task_tag { /* "TODO" */
|
||||
color: black;
|
||||
background: yellow;
|
||||
}
|
||||
|
||||
.token_string {
|
||||
color: #1e66b1; /* blue */
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
.token_keyword {
|
||||
color: #dd0058; /* purple */
|
||||
}
|
||||
|
||||
.token_space {
|
||||
/* images/white_space.png */
|
||||
background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAkAAAAJCAIAAABv85FHAAAABnRSTlMA/wAAAACkwsAdAAAAIUlEQVR4nGP4z8CAC+GUIEXuABhgkTuABEiRw2cmae4EAH05X7xDolNRAAAAAElFTkSuQmCC");
|
||||
background-repeat: no-repeat;
|
||||
background-position: center center;
|
||||
}
|
||||
|
||||
.token_tab {
|
||||
/* images/white_tab.png */
|
||||
background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAwAAAAJCAIAAACJ2loDAAAABnRSTlMA/wD/AP83WBt9AAAAMklEQVR4nGP4TwRgoK6i52c3bz5w6zMSA6tJn28d2Lx589nnCAYu63AaSLxJRLoJPwAAeNk0aG4opfMAAAAASUVORK5CYII=");
|
||||
background-repeat: no-repeat;
|
||||
background-position: left center;
|
||||
}
|
||||
|
||||
.line_caret { /* Current line */
|
||||
background: #dae2ee; /* lighter than the background */
|
||||
}
|
||||
|
||||
.readonly .line_caret {
|
||||
background: #cddae5; /* a bit darker than the background */
|
||||
}
|
||||
|
||||
/* Styling for html syntax highlighting */
|
||||
.entity-name-tag {
|
||||
color: #dd0058; /* purple */
|
||||
}
|
||||
|
||||
.entity-other-attribute-name {
|
||||
color: #dd0058; /* purple */
|
||||
}
|
||||
|
||||
.punctuation-definition-comment {
|
||||
color: #45a946; /* green */
|
||||
}
|
||||
|
||||
.comment {
|
||||
color: #45a946; /* green */
|
||||
}
|
||||
|
||||
.string-quoted {
|
||||
color: #1e66b1; /* blue */
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
.invalid {
|
||||
color: red;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.annotationRange.matchingBracket {
|
||||
outline: 1px solid grey;
|
||||
}
|
|
@ -105,7 +105,7 @@
|
|||
height: 26px;
|
||||
background-origin: border-box;
|
||||
background-clip: border-box;
|
||||
border-top: 1px solid hsla(210,8%,5%,.5);
|
||||
border-top-width: 0;
|
||||
border-bottom: 1px solid hsla(210,8%,5%,.65);
|
||||
padding: 3px;
|
||||
}
|
||||
|
|
|
@ -113,6 +113,7 @@ browser.jar:
|
|||
skin/classic/browser/devtools/goto-mdn.png (devtools/goto-mdn.png)
|
||||
skin/classic/browser/devtools/csshtmltree.css (devtools/csshtmltree.css)
|
||||
skin/classic/browser/devtools/gcli.css (devtools/gcli.css)
|
||||
skin/classic/browser/devtools/orion.css (devtools/orion.css)
|
||||
skin/classic/browser/devtools/toolbarbutton-close.png (devtools/toolbarbutton-close.png)
|
||||
skin/classic/browser/devtools/webconsole.css (devtools/webconsole.css)
|
||||
skin/classic/browser/devtools/webconsole_networkpanel.css (devtools/webconsole_networkpanel.css)
|
||||
|
@ -143,6 +144,7 @@ browser.jar:
|
|||
skin/classic/browser/devtools/breadcrumbs/rtl-start-selected.png (devtools/breadcrumbs/rtl-start-selected.png)
|
||||
skin/classic/browser/devtools/splitview.css (devtools/splitview.css)
|
||||
skin/classic/browser/devtools/styleeditor.css (devtools/styleeditor.css)
|
||||
skin/classic/browser/devtools/debugger.css (devtools/debugger.css)
|
||||
skin/classic/browser/devtools/magnifying-glass.png (devtools/magnifying-glass.png)
|
||||
skin/classic/browser/devtools/itemToggle.png (devtools/itemToggle.png)
|
||||
skin/classic/browser/devtools/itemArrow-rtl.png (devtools/itemArrow-rtl.png)
|
||||
|
@ -275,6 +277,7 @@ browser.jar:
|
|||
skin/classic/aero/browser/devtools/goto-mdn.png (devtools/goto-mdn.png)
|
||||
skin/classic/aero/browser/devtools/csshtmltree.css (devtools/csshtmltree.css)
|
||||
skin/classic/aero/browser/devtools/gcli.css (devtools/gcli.css)
|
||||
skin/classic/aero/browser/devtools/orion.css (devtools/orion.css)
|
||||
skin/classic/aero/browser/devtools/toolbarbutton-close.png (devtools/toolbarbutton-close.png)
|
||||
skin/classic/aero/browser/devtools/webconsole.css (devtools/webconsole.css)
|
||||
skin/classic/aero/browser/devtools/webconsole_networkpanel.css (devtools/webconsole_networkpanel.css)
|
||||
|
@ -305,6 +308,7 @@ browser.jar:
|
|||
skin/classic/aero/browser/devtools/breadcrumbs/rtl-start-selected.png (devtools/breadcrumbs/rtl-start-selected.png)
|
||||
skin/classic/aero/browser/devtools/splitview.css (devtools/splitview.css)
|
||||
skin/classic/aero/browser/devtools/styleeditor.css (devtools/styleeditor.css)
|
||||
skin/classic/aero/browser/devtools/debugger.css (devtools/debugger.css)
|
||||
skin/classic/aero/browser/devtools/magnifying-glass.png (devtools/magnifying-glass.png)
|
||||
skin/classic/aero/browser/devtools/itemToggle.png (devtools/itemToggle.png)
|
||||
skin/classic/aero/browser/devtools/itemArrow-rtl.png (devtools/itemArrow-rtl.png)
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
[include:embedding/tests/unit/xpcshell.ini]
|
||||
[include:toolkit/components/commandlines/test/unit/xpcshell.ini]
|
||||
[include:toolkit/components/contentprefs/tests/unit/xpcshell.ini]
|
||||
[include:toolkit/devtools/debugger/tests/unit/xpcshell.ini]
|
||||
[include:toolkit/components/passwordmgr/test/unit/xpcshell.ini]
|
||||
# Bug 676989: tests hang on Android
|
||||
skip-if = os == "android"
|
||||
|
|
|
@ -48,6 +48,7 @@ include $(DEPTH)/config/autoconf.mk
|
|||
PARALLEL_DIRS = \
|
||||
components \
|
||||
content \
|
||||
devtools \
|
||||
locales \
|
||||
mozapps/downloads \
|
||||
mozapps/extensions \
|
||||
|
|
|
@ -0,0 +1,49 @@
|
|||
# ***** BEGIN LICENSE BLOCK *****
|
||||
# Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
#
|
||||
# The contents of this file are subject to the Mozilla Public License Version
|
||||
# 1.1 (the "License"); you may not use this file except in compliance with
|
||||
# the License. You may obtain a copy of the License at
|
||||
# http://www.mozilla.org/MPL/
|
||||
#
|
||||
# Software distributed under the License is distributed on an "AS IS" basis,
|
||||
# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
# for the specific language governing rights and limitations under the
|
||||
# License.
|
||||
#
|
||||
# The Original Code is mozilla.org code.
|
||||
#
|
||||
# The Initial Developer of the Original Code is
|
||||
# The Mozilla Foundation.
|
||||
# Portions created by the Initial Developer are Copyright (C) 2011
|
||||
# the Initial Developer. All Rights Reserved.
|
||||
#
|
||||
# Contributor(s):
|
||||
# Panos Astithas <past@mozilla.com>
|
||||
#
|
||||
# Alternatively, the contents of this file may be used under the terms of
|
||||
# either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
# in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
# of those above. If you wish to allow use of your version of this file only
|
||||
# under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
# use your version of this file under the terms of the MPL, indicate your
|
||||
# decision by deleting the provisions above and replace them with the notice
|
||||
# and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
# the provisions above, a recipient may use your version of this file under
|
||||
# the terms of any one of the MPL, the GPL or the LGPL.
|
||||
#
|
||||
# ***** END LICENSE BLOCK *****
|
||||
|
||||
DEPTH = ../..
|
||||
topsrcdir = @top_srcdir@
|
||||
srcdir = @srcdir@
|
||||
VPATH = @srcdir@
|
||||
|
||||
include $(topsrcdir)/config/config.mk
|
||||
|
||||
PARALLEL_DIRS += \
|
||||
debugger \
|
||||
$(NULL)
|
||||
|
||||
include $(topsrcdir)/config/rules.mk
|
|
@ -0,0 +1,76 @@
|
|||
# ***** BEGIN LICENSE BLOCK *****
|
||||
# Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
#
|
||||
# The contents of this file are subject to the Mozilla Public License Version
|
||||
# 1.1 (the "License"); you may not use this file except in compliance with
|
||||
# the License. You may obtain a copy of the License at
|
||||
# http://www.mozilla.org/MPL/
|
||||
#
|
||||
# Software distributed under the License is distributed on an "AS IS" basis,
|
||||
# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
# for the specific language governing rights and limitations under the
|
||||
# License.
|
||||
#
|
||||
# The Original Code is mozilla.org code.
|
||||
#
|
||||
# The Initial Developer of the Original Code is
|
||||
# The Mozilla Foundation <http://www.mozilla.org/>.
|
||||
# Portions created by the Initial Developer are Copyright (C) 2009-2011
|
||||
# the Initial Developer. All Rights Reserved.
|
||||
#
|
||||
# Contributor(s):
|
||||
# Dave Camp <dcamp@mozilla.com>
|
||||
#
|
||||
# Alternatively, the contents of this file may be used under the terms of
|
||||
# either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
# in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
# of those above. If you wish to allow use of your version of this file only
|
||||
# under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
# use your version of this file under the terms of the MPL, indicate your
|
||||
# decision by deleting the provisions above and replace them with the notice
|
||||
# and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
# the provisions above, a recipient may use your version of this file under
|
||||
# the terms of any one of the MPL, the GPL or the LGPL.
|
||||
#
|
||||
# ***** END LICENSE BLOCK *****
|
||||
|
||||
DEPTH = ../../..
|
||||
topsrcdir = @top_srcdir@
|
||||
srcdir = @srcdir@
|
||||
VPATH = @srcdir@
|
||||
|
||||
include $(DEPTH)/config/autoconf.mk
|
||||
|
||||
MODULE = jsinspector
|
||||
MODULE_NAME = jsinspector
|
||||
GRE_MODULE = 1
|
||||
|
||||
LIBRARY_NAME = jsinspector
|
||||
XPIDL_MODULE = jsinspector
|
||||
LIBXUL_LIBRARY = 1
|
||||
EXPORT_LIBRARY = 1
|
||||
IS_COMPONENT = 1
|
||||
|
||||
CPPSRCS = \
|
||||
nsJSInspector.cpp \
|
||||
$(NULL)
|
||||
|
||||
EXTRA_DSO_LDOPTS += \
|
||||
$(MOZ_COMPONENT_LIBS) \
|
||||
$(MOZ_JS_LIBS) \
|
||||
$(NULL)
|
||||
|
||||
XPIDLSRCS = \
|
||||
nsIJSInspector.idl \
|
||||
$(NULL)
|
||||
|
||||
ifdef ENABLE_TESTS
|
||||
DIRS += tests
|
||||
endif
|
||||
|
||||
include $(topsrcdir)/config/rules.mk
|
||||
|
||||
libs::
|
||||
$(NSINSTALL) $(srcdir)/*.jsm $(FINAL_TARGET)/modules/devtools
|
||||
$(NSINSTALL) $(srcdir)/server/*.jsm $(FINAL_TARGET)/modules/devtools
|
|
@ -0,0 +1,940 @@
|
|||
/* -*- Mode: javascript; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Mozilla Debug Protocol Client code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Mozilla Foundation
|
||||
* Portions created by the Initial Developer are Copyright (C) 2011
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Dave Camp <dcamp@mozilla.com> (original author)
|
||||
* Panos Astithas <past@mozilla.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
"use strict";
|
||||
const Ci = Components.interfaces;
|
||||
const Cc = Components.classes;
|
||||
const Cu = Components.utils;
|
||||
const Cr = Components.results;
|
||||
|
||||
var EXPORTED_SYMBOLS = ["DebuggerTransport",
|
||||
"DebuggerClient",
|
||||
"debuggerSocketConnect"];
|
||||
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
Cu.import("resource://gre/modules/NetUtil.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyServiceGetter(this, "socketTransportService",
|
||||
"@mozilla.org/network/socket-transport-service;1",
|
||||
"nsISocketTransportService");
|
||||
|
||||
function dumpn(str)
|
||||
{
|
||||
dump("DBG-CLIENT: " + str + "\n");
|
||||
}
|
||||
|
||||
let loader = Cc["@mozilla.org/moz/jssubscript-loader;1"]
|
||||
.getService(Ci.mozIJSSubScriptLoader);
|
||||
loader.loadSubScript("chrome://global/content/devtools/dbg-transport.js");
|
||||
|
||||
/**
|
||||
* Add simple event notification to a prototype object. Any object that has
|
||||
* some use for event notifications or the observer pattern in general can be
|
||||
* augmented with the necessary facilities by passing its prototype to this
|
||||
* function.
|
||||
*
|
||||
* @param aProto object
|
||||
* The prototype object that will be modified.
|
||||
*/
|
||||
function eventSource(aProto) {
|
||||
/**
|
||||
* Add a listener to the event source for a given event.
|
||||
*
|
||||
* @param aName string
|
||||
* The event to listen for, or null to listen to all events.
|
||||
* @param aListener function
|
||||
* Called when the event is fired. If the same listener
|
||||
* is added more the once, it will be called once per
|
||||
* addListener call.
|
||||
*/
|
||||
aProto.addListener = function EV_addListener(aName, aListener) {
|
||||
if (typeof aListener != "function") {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!this._listeners) {
|
||||
this._listeners = {};
|
||||
}
|
||||
|
||||
if (!aName) {
|
||||
aName = '*';
|
||||
}
|
||||
|
||||
this._getListeners(aName).push(aListener);
|
||||
};
|
||||
|
||||
/**
|
||||
* Add a listener to the event source for a given event. The
|
||||
* listener will be removed after it is called for the first time.
|
||||
*
|
||||
* @param aName string
|
||||
* The event to listen for, or null to respond to the first event
|
||||
* fired by the object.
|
||||
* @param aListener function
|
||||
* Called when the event is fired.
|
||||
*/
|
||||
aProto.addOneTimeListener = function EV_addOneTimeListener(aName, aListener) {
|
||||
let self = this;
|
||||
|
||||
let l = function() {
|
||||
self.removeListener(aName, l);
|
||||
aListener.apply(null, arguments);
|
||||
};
|
||||
this.addListener(aName, l);
|
||||
};
|
||||
|
||||
/**
|
||||
* Remove a listener from the event source previously added with
|
||||
* addListener().
|
||||
*
|
||||
* @param aName string
|
||||
* The event name used during addListener to add the listener.
|
||||
* @param aListener function
|
||||
* The callback to remove. If addListener was called multiple
|
||||
* times, all instances will be removed.
|
||||
*/
|
||||
aProto.removeListener = function EV_removeListener(aName, aListener) {
|
||||
if (!this._listeners || !this._listeners[aName]) {
|
||||
return;
|
||||
}
|
||||
this._listeners[aName] =
|
||||
this._listeners[aName].filter(function(l) { return l != aListener });
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns the listeners for the specified event name. If none are defined it
|
||||
* initializes an empty list and returns that.
|
||||
*
|
||||
* @param aName string
|
||||
* The event name.
|
||||
*/
|
||||
aProto._getListeners = function EV_getListeners(aName) {
|
||||
if (aName in this._listeners) {
|
||||
return this._listeners[aName];
|
||||
}
|
||||
this._listeners[aName] = [];
|
||||
return this._listeners[aName];
|
||||
};
|
||||
|
||||
/**
|
||||
* Notify listeners of an event.
|
||||
*
|
||||
* @param aName string
|
||||
* The event to fire.
|
||||
* @param arguments
|
||||
* All arguments will be passed along to the listeners,
|
||||
* including the name argument.
|
||||
*/
|
||||
aProto.notify = function EV_notify() {
|
||||
if (!this._listeners) {
|
||||
return;
|
||||
}
|
||||
|
||||
let name = arguments[0];
|
||||
let listeners = this._getListeners(name).slice(0);
|
||||
if (this._listeners['*']) {
|
||||
listeners.concat(this._listeners['*']);
|
||||
}
|
||||
|
||||
for each (let listener in listeners) {
|
||||
try {
|
||||
listener.apply(null, arguments);
|
||||
} catch (e) {
|
||||
// Prevent a bad listener from interfering with the others.
|
||||
Cu.reportError(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set of protocol messages that affect thread state, and the
|
||||
* state the actor is in after each message.
|
||||
*/
|
||||
const ThreadStateTypes = {
|
||||
"paused": "paused",
|
||||
"resumed": "attached",
|
||||
"detached": "detached"
|
||||
};
|
||||
|
||||
/**
|
||||
* Set of debug protocol request types that specify the protocol request being
|
||||
* sent to the server.
|
||||
*/
|
||||
const DebugProtocolTypes = {
|
||||
"attach": "attach",
|
||||
"clientEvaluate": "clientEvaluate",
|
||||
"delete": "delete",
|
||||
"detach": "detach",
|
||||
"frames": "frames",
|
||||
"listTabs": "listTabs",
|
||||
"nameAndParameters": "nameAndParameters",
|
||||
"ownPropertyNames": "ownPropertyNames",
|
||||
"property": "property",
|
||||
"prototype": "prototype",
|
||||
"prototypeAndProperties": "prototypeAndProperties",
|
||||
"resume": "resume",
|
||||
"scripts": "scripts",
|
||||
"setBreakpoint": "setBreakpoint"
|
||||
};
|
||||
|
||||
const ROOT_ACTOR_NAME = "root";
|
||||
|
||||
/**
|
||||
* Creates a client for the remote debugging protocol server. This client
|
||||
* provides the means to communicate with the server and exchange the messages
|
||||
* required by the protocol in a traditional JavaScript API.
|
||||
*/
|
||||
function DebuggerClient(aTransport)
|
||||
{
|
||||
this._transport = aTransport;
|
||||
this._transport.hooks = this;
|
||||
this._threadClients = {};
|
||||
this._tabClients = {};
|
||||
|
||||
this._pendingRequests = [];
|
||||
this._activeRequests = {};
|
||||
this._eventsEnabled = true;
|
||||
}
|
||||
|
||||
DebuggerClient.prototype = {
|
||||
/**
|
||||
* Connect to the server and start exchanging protocol messages.
|
||||
*
|
||||
* @param aOnConnected function
|
||||
* If specified, will be called when the greeting packet is
|
||||
* received from the debugging server.
|
||||
*/
|
||||
connect: function DC_connect(aOnConnected) {
|
||||
if (aOnConnected) {
|
||||
this.addOneTimeListener("connected", function(aName, aApplicationType, aTraits) {
|
||||
aOnConnected(aApplicationType, aTraits);
|
||||
});
|
||||
}
|
||||
|
||||
this._transport.ready();
|
||||
},
|
||||
|
||||
/**
|
||||
* Shut down communication with the debugging server.
|
||||
*
|
||||
* @param aOnClosed function
|
||||
* If specified, will be called when the debugging connection
|
||||
* has been closed.
|
||||
*/
|
||||
close: function DC_close(aOnClosed) {
|
||||
// Disable detach event notifications, because event handlers will be in a
|
||||
// cleared scope by the time they run.
|
||||
this._eventsEnabled = false;
|
||||
|
||||
if (aOnClosed) {
|
||||
this.addOneTimeListener('closed', function(aEvent) {
|
||||
aOnClosed();
|
||||
});
|
||||
}
|
||||
|
||||
let closeTransport = function _closeTransport() {
|
||||
this._transport.close();
|
||||
this._transport = null;
|
||||
}.bind(this);
|
||||
|
||||
let detachTab = function _detachTab() {
|
||||
if (this.activeTab) {
|
||||
this.activeTab.detach(closeTransport);
|
||||
} else {
|
||||
closeTransport();
|
||||
}
|
||||
}.bind(this);
|
||||
|
||||
if (this.activeThread) {
|
||||
this.activeThread.detach(detachTab);
|
||||
} else {
|
||||
detachTab();
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* List the open tabs.
|
||||
*
|
||||
* @param function aOnResponse
|
||||
* Called with the response packet.
|
||||
*/
|
||||
listTabs: function DC_listTabs(aOnResponse) {
|
||||
let packet = { to: ROOT_ACTOR_NAME, type: DebugProtocolTypes.listTabs };
|
||||
this.request(packet, function(aResponse) {
|
||||
aOnResponse(aResponse);
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Attach to a tab actor.
|
||||
*
|
||||
* @param string aTabActor
|
||||
* The actor ID for the tab to attach.
|
||||
* @param function aOnResponse
|
||||
* Called with the response packet and a TabClient
|
||||
* (which will be undefined on error).
|
||||
*/
|
||||
attachTab: function DC_attachTab(aTabActor, aOnResponse) {
|
||||
let self = this;
|
||||
let packet = { to: aTabActor, type: DebugProtocolTypes.attach };
|
||||
this.request(packet, function(aResponse) {
|
||||
if (!aResponse.error) {
|
||||
var tabClient = new TabClient(self, aTabActor);
|
||||
self._tabClients[aTabActor] = tabClient;
|
||||
self.activeTab = tabClient;
|
||||
}
|
||||
aOnResponse(aResponse, tabClient);
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Attach to a thread actor.
|
||||
*
|
||||
* @param string aThreadActor
|
||||
* The actor ID for the thread to attach.
|
||||
* @param function aOnResponse
|
||||
* Called with the response packet and a ThreadClient
|
||||
* (which will be undefined on error).
|
||||
*/
|
||||
attachThread: function DC_attachThread(aThreadActor, aOnResponse) {
|
||||
let self = this;
|
||||
let packet = { to: aThreadActor, type: DebugProtocolTypes.attach };
|
||||
this.request(packet, function(aResponse) {
|
||||
if (!aResponse.error) {
|
||||
var threadClient = new ThreadClient(self, aThreadActor);
|
||||
self._threadClients[aThreadActor] = threadClient;
|
||||
self.activeThread = threadClient;
|
||||
}
|
||||
aOnResponse(aResponse, threadClient);
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Send a request to the debugging server.
|
||||
*
|
||||
* @param aRequest object
|
||||
* A JSON packet to send to the debugging server.
|
||||
* @param aOnResponse function
|
||||
* If specified, will be called with the response packet when
|
||||
* debugging server responds.
|
||||
*/
|
||||
request: function DC_request(aRequest, aOnResponse) {
|
||||
if (!this._connected) {
|
||||
throw "Have not yet received a hello packet from the server.";
|
||||
}
|
||||
if (!aRequest.to) {
|
||||
throw "Request packet has no destination.";
|
||||
}
|
||||
|
||||
this._pendingRequests.push({ to: aRequest.to,
|
||||
request: aRequest,
|
||||
onResponse: aOnResponse });
|
||||
this._sendRequests();
|
||||
},
|
||||
|
||||
/**
|
||||
* Send pending requests to any actors that don't already have an
|
||||
* active request.
|
||||
*/
|
||||
_sendRequests: function DC_sendRequests() {
|
||||
let self = this;
|
||||
this._pendingRequests = this._pendingRequests.filter(function(request) {
|
||||
if (request.to in self._activeRequests) {
|
||||
return true;
|
||||
}
|
||||
|
||||
self._activeRequests[request.to] = request;
|
||||
self._transport.send(request.request);
|
||||
|
||||
return false;
|
||||
});
|
||||
},
|
||||
|
||||
// Transport hooks.
|
||||
|
||||
/**
|
||||
* Called by DebuggerTransport to dispatch incoming packets as appropriate.
|
||||
*
|
||||
* @param aPacket object
|
||||
* The incoming packet.
|
||||
*/
|
||||
onPacket: function DC_onPacket(aPacket) {
|
||||
if (!this._connected) {
|
||||
// Hello packet.
|
||||
this._connected = true;
|
||||
this.notify("connected",
|
||||
aPacket.applicationType,
|
||||
aPacket.traits);
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
if (!aPacket.from) {
|
||||
dumpn("Server did not specify an actor, dropping packet: " + JSON.stringify(aPacket));
|
||||
return;
|
||||
}
|
||||
|
||||
let onResponse;
|
||||
if (aPacket.from in this._activeRequests) {
|
||||
onResponse = this._activeRequests[aPacket.from].onResponse;
|
||||
delete this._activeRequests[aPacket.from];
|
||||
}
|
||||
|
||||
// paused/resumed/detached get special treatment...
|
||||
if (aPacket.type in ThreadStateTypes &&
|
||||
aPacket.from in this._threadClients) {
|
||||
this._threadClients[aPacket.from]._onThreadState(aPacket);
|
||||
}
|
||||
this.notify(aPacket.type, aPacket);
|
||||
|
||||
if (onResponse) {
|
||||
onResponse(aPacket);
|
||||
}
|
||||
} catch(ex) {
|
||||
dumpn("Error handling response: " + ex + " - " + ex.stack);
|
||||
Cu.reportError(ex);
|
||||
}
|
||||
|
||||
this._sendRequests();
|
||||
},
|
||||
|
||||
/**
|
||||
* Called by DebuggerTransport when the underlying stream is closed.
|
||||
*
|
||||
* @param aStatus nsresult
|
||||
* The status code that corresponds to the reason for closing
|
||||
* the stream.
|
||||
*/
|
||||
onClosed: function DC_onClosed(aStatus) {
|
||||
this.notify("closed");
|
||||
},
|
||||
}
|
||||
|
||||
eventSource(DebuggerClient.prototype);
|
||||
|
||||
/**
|
||||
* Creates a tab client for the remote debugging protocol server. This client
|
||||
* is a front to the tab actor created in the server side, hiding the protocol
|
||||
* details in a traditional JavaScript API.
|
||||
*
|
||||
* @param aClient DebuggerClient
|
||||
* The debugger client parent.
|
||||
* @param aActor string
|
||||
* The actor ID for this tab.
|
||||
*/
|
||||
function TabClient(aClient, aActor) {
|
||||
this._client = aClient;
|
||||
this._actor = aActor;
|
||||
}
|
||||
|
||||
TabClient.prototype = {
|
||||
/**
|
||||
* Detach the client from the tab actor.
|
||||
*
|
||||
* @param function aOnResponse
|
||||
* Called with the response packet.
|
||||
*/
|
||||
detach: function TabC_detach(aOnResponse) {
|
||||
let self = this;
|
||||
let packet = { to: this._actor, type: DebugProtocolTypes.detach };
|
||||
this._client.request(packet, function(aResponse) {
|
||||
if (self.activeTab === self._client._tabClients[self._actor]) {
|
||||
delete self.activeTab;
|
||||
}
|
||||
delete self._client._tabClients[self._actor];
|
||||
if (aOnResponse) {
|
||||
aOnResponse(aResponse);
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
eventSource(TabClient.prototype);
|
||||
|
||||
/**
|
||||
* Creates a thread client for the remote debugging protocol server. This client
|
||||
* is a front to the thread actor created in the server side, hiding the
|
||||
* protocol details in a traditional JavaScript API.
|
||||
*
|
||||
* @param aClient DebuggerClient
|
||||
* The debugger client parent.
|
||||
* @param aActor string
|
||||
* The actor ID for this thread.
|
||||
*/
|
||||
function ThreadClient(aClient, aActor) {
|
||||
this._client = aClient;
|
||||
this._actor = aActor;
|
||||
this._frameCache = [];
|
||||
this._scriptCache = {};
|
||||
}
|
||||
|
||||
ThreadClient.prototype = {
|
||||
_state: "paused",
|
||||
get state() { return this._state; },
|
||||
|
||||
_actor: null,
|
||||
get actor() { return this._actor; },
|
||||
|
||||
_assertPaused: function TC_assertPaused(aCommand) {
|
||||
if (this._state !== "paused") {
|
||||
throw aCommand + " command sent while not paused.";
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Resume a paused thread.
|
||||
*
|
||||
* @param function aOnResponse
|
||||
* Called with the response packet.
|
||||
*/
|
||||
resume: function TC_resume(aOnResponse) {
|
||||
this._assertPaused("resume");
|
||||
|
||||
// Put the client in a tentative "resuming" state so we can prevent
|
||||
// further requests that should only be sent in the paused state.
|
||||
this._state = "resuming";
|
||||
|
||||
let self = this;
|
||||
let packet = { to: this._actor, type: DebugProtocolTypes.resume };
|
||||
this._client.request(packet, function(aResponse) {
|
||||
if (aResponse.error) {
|
||||
// There was an error resuming, back to paused state.
|
||||
self._state = "paused";
|
||||
}
|
||||
if (aOnResponse) {
|
||||
aOnResponse(aResponse);
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Send a clientEvaluate packet to the debuggee. Response
|
||||
* will be a resume packet.
|
||||
*/
|
||||
eval: function TC_eval(aFrame, aExpression, aOnResponse) {
|
||||
this._assertPaused("eval");
|
||||
|
||||
// Put the client in a tentative "resuming" state so we can prevent
|
||||
// further requests that should only be sent in the paused state.
|
||||
this._state = "resuming";
|
||||
|
||||
let self = this;
|
||||
let request = { to: this._actor, type: DebugProtocolTypes.clientEvaluate,
|
||||
frame: aFrame, expression: aExpression };
|
||||
this._client.request(request, function(aResponse) {
|
||||
if (aResponse.error) {
|
||||
// There was an error resuming, back to paused state.
|
||||
self._state = "paused";
|
||||
}
|
||||
|
||||
if (aOnResponse) {
|
||||
aOnResponse(aResponse);
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Detach from the thread actor.
|
||||
*
|
||||
* @param function aOnResponse
|
||||
* Called with the response packet.
|
||||
*/
|
||||
detach: function TC_detach(aOnResponse) {
|
||||
let self = this;
|
||||
let packet = { to: this._actor, type: DebugProtocolTypes.detach };
|
||||
this._client.request(packet, function(aResponse) {
|
||||
if (self.activeThread === self._client._threadClients[self._actor]) {
|
||||
delete self.activeThread;
|
||||
}
|
||||
delete self._client._threadClients[self._actor];
|
||||
if (aOnResponse) {
|
||||
aOnResponse(aResponse);
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Request to set a breakpoint in the specified location.
|
||||
*
|
||||
* @param aLocation object
|
||||
* The source location object where the breakpoint
|
||||
* will be set.
|
||||
* @param aOnResponse integer
|
||||
* Called with the thread's response.
|
||||
*/
|
||||
setBreakpoint: function TC_setBreakpoint(aLocation, aOnResponse) {
|
||||
this._assertPaused("setBreakpoint");
|
||||
|
||||
let self = this;
|
||||
let packet = { to: this._actor, type: DebugProtocolTypes.setBreakpoint,
|
||||
location: aLocation };
|
||||
this._client.request(packet, function (aResponse) {
|
||||
if (aOnResponse) {
|
||||
let bpClient = new BreakpointClient(self._client,
|
||||
aResponse.actor);
|
||||
aOnResponse(aResponse, bpClient);
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Request the loaded scripts for the current thread.
|
||||
*
|
||||
* @param aOnResponse integer
|
||||
* Called with the thread's response.
|
||||
*/
|
||||
getScripts: function TC_getScripts(aOnResponse) {
|
||||
let packet = { to: this._actor, type: DebugProtocolTypes.scripts };
|
||||
this._client.request(packet, aOnResponse);
|
||||
},
|
||||
|
||||
/**
|
||||
* A cache of source scripts. Clients can observe the scriptsadded and
|
||||
* scriptscleared event to keep up to date on changes to this cache,
|
||||
* and can fill it using the fillScripts method.
|
||||
*/
|
||||
get cachedScripts() { return this._scriptCache; },
|
||||
|
||||
/**
|
||||
* Ensure that source scripts have been loaded in the
|
||||
* ThreadClient's source script cache. A scriptsadded event will be
|
||||
* sent when the source script cache is updated.
|
||||
*
|
||||
* @returns true if a scriptsadded notification should be expected.
|
||||
*/
|
||||
fillScripts: function TC_fillScripts() {
|
||||
let self = this;
|
||||
this.getScripts(function(aResponse) {
|
||||
for each (let script in aResponse.scripts) {
|
||||
self._scriptCache[script.url] = script;
|
||||
}
|
||||
// If the cache was modified, notify listeners.
|
||||
if (aResponse.scripts && aResponse.scripts.length) {
|
||||
self.notify("scriptsadded");
|
||||
}
|
||||
});
|
||||
return true;
|
||||
},
|
||||
|
||||
/**
|
||||
* Clear the thread's source script cache. A scriptscleared event
|
||||
* will be sent.
|
||||
*/
|
||||
_clearScripts: function TC_clearScripts() {
|
||||
if (Object.keys(this._scriptCache).length > 0) {
|
||||
this._scriptCache = {}
|
||||
this.notify("scriptscleared");
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Request frames from the callstack for the current thread.
|
||||
*
|
||||
* @param aStart integer
|
||||
* The number of the youngest stack frame to return (the youngest
|
||||
* frame is 0).
|
||||
* @param aCount integer
|
||||
* The maximum number of frames to return, or null to return all
|
||||
* frames.
|
||||
* @param aOnResponse function
|
||||
* Called with the thread's response.
|
||||
*/
|
||||
getFrames: function TC_getFrames(aStart, aCount, aOnResponse) {
|
||||
this._assertPaused("frames");
|
||||
|
||||
let packet = { to: this._actor, type: DebugProtocolTypes.frames,
|
||||
start: aStart, count: aCount ? aCount : undefined };
|
||||
this._client.request(packet, aOnResponse);
|
||||
},
|
||||
|
||||
/**
|
||||
* An array of cached frames. Clients can observe the framesadded and
|
||||
* framescleared event to keep up to date on changes to this cache,
|
||||
* and can fill it using the fillFrames method.
|
||||
*/
|
||||
get cachedFrames() { return this._frameCache; },
|
||||
|
||||
/**
|
||||
* true if there are more stack frames available on the server.
|
||||
*/
|
||||
get moreFrames() {
|
||||
return this.state === "paused"
|
||||
&& (!this._frameCache || this._frameCache.length == 0
|
||||
|| !this._frameCache[this._frameCache.length - 1].oldest);
|
||||
},
|
||||
|
||||
/**
|
||||
* Ensure that at least aTotal stack frames have been loaded in the
|
||||
* ThreadClient's stack frame cache. A framesadded event will be
|
||||
* sent when the stack frame cache is updated.
|
||||
*
|
||||
* @param aTotal number
|
||||
* The minimum number of stack frames to be included.
|
||||
*
|
||||
* @returns true if a framesadded notification should be expected.
|
||||
*/
|
||||
fillFrames: function TC_fillFrames(aTotal) {
|
||||
this._assertPaused("fillFrames");
|
||||
|
||||
if (this._frameCache.length >= aTotal) {
|
||||
return false;
|
||||
}
|
||||
|
||||
let numFrames = this._frameCache.length;
|
||||
|
||||
let self = this;
|
||||
this.getFrames(numFrames, aTotal - numFrames, function(aResponse) {
|
||||
for each (let frame in aResponse.frames) {
|
||||
self._frameCache[frame.depth] = frame;
|
||||
}
|
||||
// If we got as many frames as we asked for, there might be more
|
||||
// frames available.
|
||||
|
||||
self.notify("framesadded");
|
||||
});
|
||||
return true;
|
||||
},
|
||||
|
||||
/**
|
||||
* Clear the thread's stack frame cache. A framescleared event
|
||||
* will be sent.
|
||||
*/
|
||||
_clearFrames: function TC_clearFrames() {
|
||||
if (this._frameCache.length > 0) {
|
||||
this._frameCache = [];
|
||||
this.notify("framescleared");
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Return a GripClient object for the given object grip.
|
||||
*
|
||||
* @param aGrip object
|
||||
* A pause-lifetime object grip returned by the protocol.
|
||||
*/
|
||||
pauseGrip: function TC_pauseGrip(aGrip) {
|
||||
if (!this._pauseGrips) {
|
||||
this._pauseGrips = {};
|
||||
}
|
||||
|
||||
if (aGrip.actor in this._pauseGrips) {
|
||||
return this._pauseGrips[aGrip.actor];
|
||||
}
|
||||
|
||||
let client = new GripClient(this._client, aGrip);
|
||||
this._pauseGrips[aGrip.actor] = client;
|
||||
return client;
|
||||
},
|
||||
|
||||
/**
|
||||
* Invalidate pause-lifetime grip clients and clear the list of
|
||||
* current grip clients.
|
||||
*/
|
||||
_clearPauseGrips: function TC_clearPauseGrips(aPacket) {
|
||||
for each (let grip in this._pauseGrips) {
|
||||
grip.valid = false;
|
||||
}
|
||||
this._pauseGrips = null;
|
||||
},
|
||||
|
||||
/**
|
||||
* Handle thread state change by doing necessary cleanup and notifying all
|
||||
* registered listeners.
|
||||
*/
|
||||
_onThreadState: function TC_onThreadState(aPacket) {
|
||||
this._state = ThreadStateTypes[aPacket.type];
|
||||
this._clearFrames();
|
||||
this._clearPauseGrips();
|
||||
this._client._eventsEnabled && this.notify(aPacket.type, aPacket);
|
||||
},
|
||||
};
|
||||
|
||||
eventSource(ThreadClient.prototype);
|
||||
|
||||
/**
|
||||
* Grip clients are used to retrieve information about the relevant object.
|
||||
*
|
||||
* @param aClient DebuggerClient
|
||||
* The debugger client parent.
|
||||
* @param aGrip object
|
||||
* A pause-lifetime object grip returned by the protocol.
|
||||
*/
|
||||
function GripClient(aClient, aGrip)
|
||||
{
|
||||
this._grip = aGrip;
|
||||
this._client = aClient;
|
||||
}
|
||||
|
||||
GripClient.prototype = {
|
||||
get actor() { return this._grip.actor },
|
||||
|
||||
_valid: true,
|
||||
get valid() { return this._valid; },
|
||||
set valid(aValid) { this._valid = !!aValid; },
|
||||
|
||||
/**
|
||||
* Request the name of the function and its formal parameters.
|
||||
*
|
||||
* @param aOnResponse function
|
||||
* Called with the request's response.
|
||||
*/
|
||||
getSignature: function GC_getSignature(aOnResponse) {
|
||||
if (this._grip["class"] !== "Function") {
|
||||
throw "getSignature is only valid for function grips.";
|
||||
}
|
||||
|
||||
let packet = { to: this.actor, type: DebugProtocolTypes.nameAndParameters };
|
||||
this._client.request(packet, function (aResponse) {
|
||||
if (aOnResponse) {
|
||||
aOnResponse(aResponse);
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Request the names of the properties defined on the object and not its
|
||||
* prototype.
|
||||
*
|
||||
* @param aOnResponse function Called with the request's response.
|
||||
*/
|
||||
getOwnPropertyNames: function GC_getOwnPropertyNames(aOnResponse) {
|
||||
let packet = { to: this.actor, type: DebugProtocolTypes.ownPropertyNames };
|
||||
this._client.request(packet, function (aResponse) {
|
||||
if (aOnResponse) {
|
||||
aOnResponse(aResponse);
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Request the prototype and own properties of the object.
|
||||
*
|
||||
* @param aOnResponse function Called with the request's response.
|
||||
*/
|
||||
getPrototypeAndProperties: function GC_getPrototypeAndProperties(aOnResponse) {
|
||||
let packet = { to: this.actor,
|
||||
type: DebugProtocolTypes.prototypeAndProperties };
|
||||
this._client.request(packet, function (aResponse) {
|
||||
if (aOnResponse) {
|
||||
aOnResponse(aResponse);
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Request the property descriptor of the object's specified property.
|
||||
*
|
||||
* @param aName string The name of the requested property.
|
||||
* @param aOnResponse function Called with the request's response.
|
||||
*/
|
||||
getProperty: function GC_getProperty(aName, aOnResponse) {
|
||||
let packet = { to: this.actor, type: DebugProtocolTypes.property,
|
||||
name: aName };
|
||||
this._client.request(packet, function (aResponse) {
|
||||
if (aOnResponse) {
|
||||
aOnResponse(aResponse);
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Request the prototype of the object.
|
||||
*
|
||||
* @param aOnResponse function Called with the request's response.
|
||||
*/
|
||||
getPrototype: function GC_getPrototype(aOnResponse) {
|
||||
let packet = { to: this.actor, type: DebugProtocolTypes.prototype };
|
||||
this._client.request(packet, function (aResponse) {
|
||||
if (aOnResponse) {
|
||||
aOnResponse(aResponse);
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Breakpoint clients are used to remove breakpoints that are no longer used.
|
||||
*
|
||||
* @param aClient DebuggerClient
|
||||
* The debugger client parent.
|
||||
* @param aActor string
|
||||
* The actor ID for this breakpoint.
|
||||
*/
|
||||
function BreakpointClient(aClient, aActor) {
|
||||
this._client = aClient;
|
||||
this._actor = aActor;
|
||||
}
|
||||
|
||||
BreakpointClient.prototype = {
|
||||
|
||||
_actor: null,
|
||||
get actor() { return this._actor; },
|
||||
|
||||
/**
|
||||
* Remove the breakpoint from the server.
|
||||
*/
|
||||
remove: function BC_remove(aOnResponse) {
|
||||
let packet = { to: this._actor, type: DebugProtocolTypes["delete"] };
|
||||
this._client.request(packet, function(aResponse) {
|
||||
if (aOnResponse) {
|
||||
aOnResponse(aResponse);
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
eventSource(BreakpointClient.prototype);
|
||||
|
||||
/**
|
||||
* Connects to a debugger server socket and returns a DebuggerTransport.
|
||||
*
|
||||
* @param aHost string
|
||||
* The host name or IP address of the debugger server.
|
||||
* @param aPort number
|
||||
* The port number of the debugger server.
|
||||
*/
|
||||
function debuggerSocketConnect(aHost, aPort)
|
||||
{
|
||||
let s = socketTransportService.createTransport(null, 0, aHost, aPort, null);
|
||||
let transport = new DebuggerTransport(s.openInputStream(0, 0, 0),
|
||||
s.openOutputStream(0, 0, 0));
|
||||
return transport;
|
||||
}
|
|
@ -0,0 +1,182 @@
|
|||
/* -*- Mode: javascript; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is mozilla.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Mozilla Foundation
|
||||
* Portions created by the Initial Developer are Copyright (C) 2011
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Dave Camp <dcamp@mozilla.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
"use strict";
|
||||
Cu.import("resource://gre/modules/NetUtil.jsm");
|
||||
|
||||
/**
|
||||
* An adapter that handles data transfers between the debugger client and
|
||||
* server. It can work with both nsIPipe and nsIServerSocket transports so
|
||||
* long as the properly created input and output streams are specified. Data is
|
||||
* transferred as a JSON packet serialized into a string, with the string length
|
||||
* prepended to the packet, followed by a colon ([length]:[packet]). The
|
||||
* contents of the JSON packet are specified in the Remote Debugging Protocol
|
||||
* specification.
|
||||
*
|
||||
* @param aInput nsIInputStream
|
||||
* The input stream.
|
||||
* @param aOutput nsIOutputStream
|
||||
* The output stream.
|
||||
*/
|
||||
function DebuggerTransport(aInput, aOutput)
|
||||
{
|
||||
this._input = aInput;
|
||||
this._output = aOutput;
|
||||
this._outgoing = "";
|
||||
this._incoming = "";
|
||||
}
|
||||
|
||||
DebuggerTransport.prototype = {
|
||||
_hooks: null,
|
||||
get hooks() { return this._hooks; },
|
||||
set hooks(aHooks) { this._hooks = aHooks; },
|
||||
|
||||
/**
|
||||
* Transmit the specified packet.
|
||||
*/
|
||||
send: function DT_send(aPacket) {
|
||||
// TODO (bug 709088): remove pretty printing when the protocol is done.
|
||||
let data = JSON.stringify(aPacket, null, 2);
|
||||
data = data.length + ':' + data;
|
||||
this._outgoing += data;
|
||||
this._flushOutgoing();
|
||||
},
|
||||
|
||||
/**
|
||||
* Close the transport.
|
||||
*/
|
||||
close: function DT_close() {
|
||||
this._input.close();
|
||||
this._output.close();
|
||||
},
|
||||
|
||||
/**
|
||||
* Flush the outgoing stream.
|
||||
*/
|
||||
_flushOutgoing: function DT_flushOutgoing() {
|
||||
if (this._outgoing.length > 0) {
|
||||
var threadManager = Cc["@mozilla.org/thread-manager;1"].getService();
|
||||
this._output.asyncWait(this, 0, 0, threadManager.currentThread);
|
||||
}
|
||||
},
|
||||
|
||||
onOutputStreamReady: function DT_onOutputStreamReady(aStream) {
|
||||
let written = aStream.write(this._outgoing, this._outgoing.length);
|
||||
this._outgoing = this._outgoing.slice(written);
|
||||
this._flushOutgoing();
|
||||
},
|
||||
|
||||
/**
|
||||
* Initialize the input stream for reading.
|
||||
*/
|
||||
ready: function DT_ready() {
|
||||
let pump = Cc["@mozilla.org/network/input-stream-pump;1"]
|
||||
.createInstance(Ci.nsIInputStreamPump);
|
||||
pump.init(this._input, -1, -1, 0, 0, false);
|
||||
pump.asyncRead(this, null);
|
||||
},
|
||||
|
||||
// nsIStreamListener
|
||||
onStartRequest: function DT_onStartRequest(aRequest, aContext) {},
|
||||
|
||||
onStopRequest: function DT_onStopRequest(aRequest, aContext, aStatus) {
|
||||
this.close();
|
||||
this.hooks.onClosed(aStatus);
|
||||
},
|
||||
|
||||
onDataAvailable: function DT_onDataAvailable(aRequest, aContext,
|
||||
aStream, aOffset, aCount) {
|
||||
try {
|
||||
this._incoming += NetUtil.readInputStreamToString(aStream,
|
||||
aStream.available());
|
||||
while (this._processIncoming()) {};
|
||||
} catch(e) {
|
||||
dumpn("Unexpected error reading from debugging connection: " + e + " - " + e.stack);
|
||||
this.close();
|
||||
return;
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Process incoming packets. Returns true if a packet has been received, either
|
||||
* if it was properly parsed or not. Returns false if the incoming stream does
|
||||
* not contain a full packet yet. After a proper packet is parsed, the dispatch
|
||||
* handler DebuggerTransport.hooks.onPacket is called with the packet as a
|
||||
* parameter.
|
||||
*/
|
||||
_processIncoming: function DT__processIncoming() {
|
||||
// Well this is ugly.
|
||||
let sep = this._incoming.indexOf(':');
|
||||
if (sep < 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
let count = parseInt(this._incoming.substring(0, sep));
|
||||
if (this._incoming.length - (sep + 1) < count) {
|
||||
// Don't have a complete request yet.
|
||||
return false;
|
||||
}
|
||||
|
||||
// We have a complete request, pluck it out of the data and parse it.
|
||||
this._incoming = this._incoming.substring(sep + 1);
|
||||
let packet = this._incoming.substring(0, count);
|
||||
this._incoming = this._incoming.substring(count);
|
||||
|
||||
try {
|
||||
var parsed = JSON.parse(packet);
|
||||
} catch(e) {
|
||||
dumpn("Error parsing incoming packet: " + packet + " (" + e + " - " + e.stack + ")");
|
||||
return true;
|
||||
}
|
||||
|
||||
try {
|
||||
dumpn("Got: " + packet);
|
||||
let thr = Cc["@mozilla.org/thread-manager;1"].getService().currentThread;
|
||||
let self = this;
|
||||
thr.dispatch({run: function() {
|
||||
self.hooks.onPacket(parsed);
|
||||
}}, 0);
|
||||
} catch(e) {
|
||||
dumpn("Error handling incoming packet: " + e + " - " + e.stack);
|
||||
dumpn("Packet was: " + packet);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,67 @@
|
|||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is mozilla.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Mozilla Foundation
|
||||
* Portions created by the Initial Developer are Copyright (C) 2011
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Dave Camp <dcamp@mozilla.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#include "nsISupports.idl"
|
||||
|
||||
/**
|
||||
* Utilities for integrating the JSInspector object into an XPCOM
|
||||
* application.
|
||||
*/
|
||||
[scriptable, uuid(dbf84113-506a-4fd3-9183-a0348c6fa9cc)]
|
||||
interface nsIJSInspector : nsISupports
|
||||
{
|
||||
/**
|
||||
* Process the thread's event queue until exit.
|
||||
*
|
||||
* @return depth Returns the number of times the event loop
|
||||
* has been nested using this API.
|
||||
*/
|
||||
unsigned long enterNestedEventLoop();
|
||||
|
||||
/**
|
||||
* Exits the current nested event loop.
|
||||
*
|
||||
* @return depth The number of nested event loops left after
|
||||
* exiting the event loop.
|
||||
*
|
||||
* @throws NS_ERROR_FAILURE if there are no nested event loops
|
||||
* running.
|
||||
*/
|
||||
unsigned long exitNestedEventLoop();
|
||||
|
||||
readonly attribute unsigned long eventLoopNestLevel;
|
||||
};
|
|
@ -0,0 +1,146 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2; -*- */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is mozilla.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* The Mozilla Foundation <http://www.mozilla.org/>.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2009-2011
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Dave Camp <dcamp@mozilla.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#include "nsJSInspector.h"
|
||||
#include "nsIXPConnect.h"
|
||||
#include "nsIJSContextStack.h"
|
||||
#include "nsThreadUtils.h"
|
||||
#include "jsapi.h"
|
||||
#include "jsgc.h"
|
||||
#include "jsfriendapi.h"
|
||||
#include "jsdbgapi.h"
|
||||
#include "mozilla/ModuleUtils.h"
|
||||
#include "nsServiceManagerUtils.h"
|
||||
#include "nsMemory.h"
|
||||
|
||||
#define JSINSPECTOR_CONTRACTID \
|
||||
"@mozilla.org/jsinspector;1"
|
||||
|
||||
#define JSINSPECTOR_CID \
|
||||
{ 0xec5aa99c, 0x7abb, 0x4142, { 0xac, 0x5f, 0xaa, 0xb2, 0x41, 0x9e, 0x38, 0xe2 } }
|
||||
|
||||
namespace mozilla {
|
||||
namespace jsinspector {
|
||||
|
||||
NS_GENERIC_FACTORY_CONSTRUCTOR(nsJSInspector)
|
||||
|
||||
NS_IMPL_ISUPPORTS1(nsJSInspector, nsIJSInspector)
|
||||
|
||||
nsJSInspector::nsJSInspector() : mNestedLoopLevel(0)
|
||||
{
|
||||
}
|
||||
|
||||
nsJSInspector::~nsJSInspector()
|
||||
{
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsJSInspector::EnterNestedEventLoop(PRUint32 *out)
|
||||
{
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsIJSContextStack> stack =
|
||||
do_GetService("@mozilla.org/js/xpc/ContextStack;1", &rv);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
PRUint32 nestLevel = ++mNestedLoopLevel;
|
||||
if (NS_SUCCEEDED(stack->Push(nsnull))) {
|
||||
while (NS_SUCCEEDED(rv) && mNestedLoopLevel >= nestLevel) {
|
||||
if (!NS_ProcessNextEvent())
|
||||
rv = NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
|
||||
JSContext *cx;
|
||||
stack->Pop(&cx);
|
||||
NS_ASSERTION(cx == nsnull, "JSContextStack mismatch");
|
||||
} else {
|
||||
rv = NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
NS_ASSERTION(mNestedLoopLevel <= nestLevel,
|
||||
"nested event didn't unwind properly");
|
||||
|
||||
if (mNestedLoopLevel == nestLevel)
|
||||
--mNestedLoopLevel;
|
||||
|
||||
*out = mNestedLoopLevel;
|
||||
return rv;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsJSInspector::ExitNestedEventLoop(PRUint32 *out)
|
||||
{
|
||||
if (mNestedLoopLevel > 0) {
|
||||
--mNestedLoopLevel;
|
||||
} else {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
*out = mNestedLoopLevel;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsJSInspector::GetEventLoopNestLevel(PRUint32 *out)
|
||||
{
|
||||
*out = mNestedLoopLevel;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
NS_DEFINE_NAMED_CID(JSINSPECTOR_CID);
|
||||
|
||||
static const mozilla::Module::CIDEntry kJSInspectorCIDs[] = {
|
||||
{ &kJSINSPECTOR_CID, false, NULL, mozilla::jsinspector::nsJSInspectorConstructor },
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
static const mozilla::Module::ContractIDEntry kJSInspectorContracts[] = {
|
||||
{ JSINSPECTOR_CONTRACTID, &kJSINSPECTOR_CID },
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
static const mozilla::Module kJSInspectorModule = {
|
||||
mozilla::Module::kVersion,
|
||||
kJSInspectorCIDs,
|
||||
kJSInspectorContracts
|
||||
};
|
||||
|
||||
NSMODULE_DEFN(jsinspector) = &kJSInspectorModule;
|
|
@ -0,0 +1,64 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2; -*- */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is mozilla.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* The Mozilla Foundation <http://www.mozilla.org/>.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2009-2011
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Dave Camp <dcamp@mozilla.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#ifndef COMPONENTS_JSINSPECTOR_H
|
||||
#define COMPONENTS_JSINSPECTOR_H
|
||||
|
||||
#include "nsIJSInspector.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace jsinspector {
|
||||
|
||||
class nsJSInspector : public nsIJSInspector
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSIJSINSPECTOR
|
||||
|
||||
nsJSInspector();
|
||||
|
||||
private:
|
||||
~nsJSInspector();
|
||||
|
||||
PRUint32 mNestedLoopLevel;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,428 @@
|
|||
/* -*- Mode: javascript; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is JS Debugger Server code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Mozilla Foundation
|
||||
* Portions created by the Initial Developer are Copyright (C) 2011
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Dave Camp <dcamp@mozilla.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
"use strict";
|
||||
/**
|
||||
* Browser-specific actors.
|
||||
*/
|
||||
|
||||
var windowMediator = Cc["@mozilla.org/appshell/window-mediator;1"]
|
||||
.getService(Ci.nsIWindowMediator);
|
||||
|
||||
function createRootActor(aConnection)
|
||||
{
|
||||
return new BrowserRootActor(aConnection);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the root actor that client-server communications always start with.
|
||||
* The root actor is responsible for the initial 'hello' packet and for
|
||||
* responding to a 'listTabs' request that produces the list of currently open
|
||||
* tabs.
|
||||
*
|
||||
* @param aConnection DebuggerServerConnection
|
||||
* The conection to the client.
|
||||
*/
|
||||
function BrowserRootActor(aConnection)
|
||||
{
|
||||
this.conn = aConnection;
|
||||
this._tabActors = new WeakMap();
|
||||
this._tabActorPool = null;
|
||||
this._actorFactories = null;
|
||||
|
||||
this.onTabClosed = this.onTabClosed.bind(this);
|
||||
windowMediator.addListener(this);
|
||||
}
|
||||
|
||||
BrowserRootActor.prototype = {
|
||||
/**
|
||||
* Return a 'hello' packet as specified by the Remote Debugging Protocol.
|
||||
*/
|
||||
sayHello: function BRA_sayHello() {
|
||||
return { from: "root",
|
||||
applicationType: "browser",
|
||||
traits: [] };
|
||||
},
|
||||
|
||||
/**
|
||||
* Disconnects the actor from the browser window.
|
||||
*/
|
||||
disconnect: function BRA_disconnect() {
|
||||
windowMediator.removeListener(this);
|
||||
|
||||
// We may have registered event listeners on browser windows to
|
||||
// watch for tab closes, remove those.
|
||||
let e = windowMediator.getEnumerator("navigator:browser");
|
||||
while (e.hasMoreElements()) {
|
||||
let win = e.getNext();
|
||||
this.unwatchWindow(win);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Handles the listTabs request. Builds a list of actors
|
||||
* for the tabs running in the process. The actors will survive
|
||||
* until at least the next listTabs request.
|
||||
*/
|
||||
onListTabs: function BRA_onListTabs() {
|
||||
// Get actors for all the currently-running tabs (reusing
|
||||
// existing actors where applicable), and store them in
|
||||
// an ActorPool.
|
||||
|
||||
let actorPool = new ActorPool(this.conn);
|
||||
let actorList = [];
|
||||
|
||||
// Walk over open browser windows.
|
||||
let e = windowMediator.getEnumerator("navigator:browser");
|
||||
let selected;
|
||||
while (e.hasMoreElements()) {
|
||||
let win = e.getNext();
|
||||
|
||||
// Watch the window for tab closes so we can invalidate
|
||||
// actors as needed.
|
||||
this.watchWindow(win);
|
||||
|
||||
// List the tabs in this browser.
|
||||
let selectedBrowser = win.getBrowser().selectedBrowser;
|
||||
let browsers = win.getBrowser().browsers;
|
||||
for each (let browser in browsers) {
|
||||
if (browser == selectedBrowser) {
|
||||
selected = actorList.length;
|
||||
}
|
||||
let actor = this._tabActors.get(browser);
|
||||
if (!actor) {
|
||||
actor = new BrowserTabActor(this.conn, browser);
|
||||
actor.parentID = this.actorID;
|
||||
this._tabActors.set(browser, actor);
|
||||
}
|
||||
actorPool.addActor(actor);
|
||||
actorList.push(actor);
|
||||
}
|
||||
}
|
||||
|
||||
// Now drop the old actorID -> actor map. Actors that still
|
||||
// mattered were added to the new map, others will go
|
||||
// away.
|
||||
if (this._tabActorPool) {
|
||||
this.conn.removeActorPool(this._tabActorPool);
|
||||
}
|
||||
this._tabActorPool = actorPool;
|
||||
this.conn.addActorPool(this._tabActorPool);
|
||||
|
||||
return { "from": "root",
|
||||
"selected": selected,
|
||||
"tabs": [actor.grip()
|
||||
for each (actor in actorList)] };
|
||||
},
|
||||
|
||||
/**
|
||||
* Watch a window that was visited during onListTabs for
|
||||
* tab closures.
|
||||
*/
|
||||
watchWindow: function BRA_watchWindow(aWindow) {
|
||||
aWindow.getBrowser().tabContainer.addEventListener("TabClose",
|
||||
this.onTabClosed,
|
||||
false);
|
||||
},
|
||||
|
||||
/**
|
||||
* Stop watching a window for tab closes.
|
||||
*/
|
||||
unwatchWindow: function BRA_unwatchWindow(aWindow) {
|
||||
aWindow.getBrowser().tabContainer.removeEventListener("TabClose",
|
||||
this.onTabClosed);
|
||||
this.exitTabActor(aWindow);
|
||||
},
|
||||
|
||||
/**
|
||||
* When a tab is closed, exit its tab actor. The actor
|
||||
* will be dropped at the next listTabs request.
|
||||
*/
|
||||
onTabClosed: function BRA_onTabClosed(aEvent) {
|
||||
this.exitTabActor(aEvent.target.linkedBrowser);
|
||||
},
|
||||
|
||||
/**
|
||||
* Exit the tab actor of the specified tab.
|
||||
*/
|
||||
exitTabActor: function BRA_exitTabActor(aWindow) {
|
||||
let actor = this._tabActors.get(aWindow);
|
||||
if (actor) {
|
||||
actor.exit();
|
||||
}
|
||||
},
|
||||
|
||||
// nsIWindowMediatorListener
|
||||
onWindowTitleChange: function BRA_onWindowTitleChange(aWindow, aTitle) { },
|
||||
onOpenWindow: function BRA_onOpenWindow(aWindow) { },
|
||||
onCloseWindow: function BRA_onCloseWindow(aWindow) {
|
||||
if (aWindow.getBrowser) {
|
||||
this.unwatchWindow(aWindow);
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* The request types this actor can handle.
|
||||
*/
|
||||
BrowserRootActor.prototype.requestTypes = {
|
||||
"listTabs": BrowserRootActor.prototype.onListTabs
|
||||
};
|
||||
|
||||
/**
|
||||
* Creates a tab actor for handling requests to a browser tab, like attaching
|
||||
* and detaching.
|
||||
*
|
||||
* @param aConnection DebuggerServerConnection
|
||||
* The conection to the client.
|
||||
* @param aBrowser browser
|
||||
* The browser instance that contains this tab.
|
||||
*/
|
||||
function BrowserTabActor(aConnection, aBrowser)
|
||||
{
|
||||
this.conn = aConnection;
|
||||
this._browser = aBrowser;
|
||||
|
||||
this._onWindowCreated = this.onWindowCreated.bind(this);
|
||||
}
|
||||
|
||||
// XXX (bug 710213): BrowserTabActor attach/detach/exit/disconnect is a
|
||||
// *complete* mess, needs to be rethought asap.
|
||||
|
||||
BrowserTabActor.prototype = {
|
||||
get browser() { return this._browser; },
|
||||
|
||||
get exited() { return !this.browser; },
|
||||
get attached() { return !!this._attached },
|
||||
|
||||
_tabPool: null,
|
||||
get tabActorPool() { return this._tabPool; },
|
||||
|
||||
_contextPool: null,
|
||||
get contextActorPool() { return this._contextPool; },
|
||||
|
||||
actorPrefix: "tab",
|
||||
|
||||
grip: function BTA_grip() {
|
||||
dbg_assert(!this.exited,
|
||||
"grip() shouldn't be called on exited browser actor.");
|
||||
dbg_assert(this.actorID,
|
||||
"tab should have an actorID.");
|
||||
return { actor: this.actorID,
|
||||
title: this.browser.contentTitle,
|
||||
url: this.browser.currentURI.spec }
|
||||
},
|
||||
|
||||
/**
|
||||
* Called when the actor is removed from the connection.
|
||||
*/
|
||||
disconnect: function BTA_disconnect() {
|
||||
this._detach();
|
||||
},
|
||||
|
||||
/**
|
||||
* Called by the root actor when the underlying tab is closed.
|
||||
*/
|
||||
exit: function BTA_exit() {
|
||||
if (this.exited) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.attached) {
|
||||
this._detach();
|
||||
this.conn.send({ from: this.actorID,
|
||||
type: "tabDetached" });
|
||||
}
|
||||
|
||||
this._browser = null;
|
||||
},
|
||||
|
||||
/**
|
||||
* Does the actual work of attching to a tab.
|
||||
*/
|
||||
_attach: function BTA_attach() {
|
||||
if (this._attached) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Create a pool for tab-lifetime actors.
|
||||
dbg_assert(!this._tabPool, "Shouldn't have a tab pool if we weren't attached.");
|
||||
this._tabPool = new ActorPool(this.conn);
|
||||
this.conn.addActorPool(this._tabPool);
|
||||
|
||||
// ... and a pool for context-lifetime actors.
|
||||
this._pushContext();
|
||||
|
||||
// Watch for globals being created in this tab.
|
||||
this.browser.addEventListener("DOMWindowCreated", this._onWindowCreated, true);
|
||||
|
||||
this._attached = true;
|
||||
},
|
||||
|
||||
/**
|
||||
* Creates a thread actor and a pool for context-lifetime actors. It then sets
|
||||
* up the content window for debugging.
|
||||
*/
|
||||
_pushContext: function BTA_pushContext() {
|
||||
dbg_assert(!this._contextPool, "Can't push multiple contexts");
|
||||
|
||||
this._contextPool = new ActorPool(this.conn);
|
||||
this.conn.addActorPool(this._contextPool);
|
||||
|
||||
this.threadActor = new ThreadActor(this);
|
||||
this.threadActor.addDebuggee(this.browser.contentWindow.wrappedJSObject);
|
||||
this._contextPool.addActor(this.threadActor);
|
||||
},
|
||||
|
||||
/**
|
||||
* Exits the current thread actor and removes the context-lifetime actor pool.
|
||||
* The content window is no longer being debugged after this call.
|
||||
*/
|
||||
_popContext: function BTA_popContext() {
|
||||
dbg_assert(!!this._contextPool, "No context to pop.");
|
||||
|
||||
this.conn.removeActorPool(this._contextPool);
|
||||
this._contextPool = null;
|
||||
this.threadActor.exit();
|
||||
this.threadActor = null;
|
||||
},
|
||||
|
||||
/**
|
||||
* Does the actual work of detaching from a tab.
|
||||
*/
|
||||
_detach: function BTA_detach() {
|
||||
if (!this.attached) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.browser.removeEventListener("DOMWindowCreated", this._onWindowCreated, true);
|
||||
|
||||
this._popContext();
|
||||
|
||||
// Shut down actors that belong to this tab's pool.
|
||||
this.conn.removeActorPool(this._tabPool);
|
||||
this._tabPool = null;
|
||||
|
||||
this._attached = false;
|
||||
},
|
||||
|
||||
// Protocol Request Handlers
|
||||
|
||||
onAttach: function BTA_onAttach(aRequest) {
|
||||
if (this.exited) {
|
||||
return { type: "exited" };
|
||||
}
|
||||
|
||||
this._attach();
|
||||
|
||||
return { type: "tabAttached", threadActor: this.threadActor.actorID };
|
||||
},
|
||||
|
||||
onDetach: function BTA_onDetach(aRequest) {
|
||||
if (!this.attached) {
|
||||
return { error: "wrongState" };
|
||||
}
|
||||
|
||||
this._detach();
|
||||
|
||||
return { type: "detached" };
|
||||
},
|
||||
|
||||
/**
|
||||
* Suppresses content-initiated events. Called right before entering the
|
||||
* nested event loop.
|
||||
*/
|
||||
preNest: function BTA_preNest() {
|
||||
this.browser.contentWindow
|
||||
.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
|
||||
.getInterface(Ci.nsIDOMWindowUtils)
|
||||
.suppressEventHandling(true);
|
||||
},
|
||||
|
||||
/**
|
||||
* Re-enables content-initiated events. Called right after exiting the
|
||||
* nested event loop.
|
||||
*/
|
||||
postNest: function BTA_postNest(aNestData) {
|
||||
this.browser.contentWindow
|
||||
.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
|
||||
.getInterface(Ci.nsIDOMWindowUtils)
|
||||
.suppressEventHandling(false);
|
||||
},
|
||||
|
||||
/**
|
||||
* Handle location changes, by sending a tabNavigated notification to the
|
||||
* client.
|
||||
*/
|
||||
onWindowCreated: function BTA_onWindowCreated(evt) {
|
||||
if (evt.target === this.browser.contentDocument) {
|
||||
if (this._attached) {
|
||||
this.conn.send({ from: this.actorID, type: "tabNavigated",
|
||||
url: this.browser.contentDocument.URL });
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* The request types this actor can handle.
|
||||
*/
|
||||
BrowserTabActor.prototype.requestTypes = {
|
||||
"attach": BrowserTabActor.prototype.onAttach,
|
||||
"detach": BrowserTabActor.prototype.onDetach
|
||||
};
|
||||
|
||||
/**
|
||||
* Registers handlers for new request types defined dynamically. This is used
|
||||
* for example by add-ons to augment the functionality of the tab actor.
|
||||
*
|
||||
* @param aName string
|
||||
* The name of the new request type.
|
||||
* @param aFunction function
|
||||
* The handler for this request type.
|
||||
*/
|
||||
DebuggerServer.addTabRequest = function DS_addTabRequest(aName, aFunction) {
|
||||
BrowserTabActor.prototype.requestTypes[aName] = function(aRequest) {
|
||||
if (!this.attached) {
|
||||
return { error: "wrongState" };
|
||||
}
|
||||
return aFunction(this, aRequest);
|
||||
}
|
||||
};
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -0,0 +1,474 @@
|
|||
/* -*- Mode: javascript; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is mozilla.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Mozilla Foundation
|
||||
* Portions created by the Initial Developer are Copyright (C) 2011
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Dave Camp <dcamp@mozilla.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
"use strict";
|
||||
/**
|
||||
* Toolkit glue for the remote debugging protocol, loaded into the
|
||||
* debugging global.
|
||||
*/
|
||||
|
||||
const Ci = Components.interfaces;
|
||||
const Cc = Components.classes;
|
||||
const CC = Components.Constructor;
|
||||
const Cu = Components.utils;
|
||||
|
||||
function dumpn(str) {
|
||||
dump("DBG-SERVER: " + str + "\n");
|
||||
}
|
||||
|
||||
function dbg_assert(cond, e) {
|
||||
if (!cond) {
|
||||
return e;
|
||||
}
|
||||
}
|
||||
|
||||
loadSubScript.call(this, "chrome://global/content/devtools/dbg-transport.js");
|
||||
|
||||
// XPCOM constructors
|
||||
const ServerSocket = CC("@mozilla.org/network/server-socket;1",
|
||||
"nsIServerSocket",
|
||||
"init");
|
||||
|
||||
/***
|
||||
* Public API
|
||||
*/
|
||||
var DebuggerServer = {
|
||||
_listener: null,
|
||||
_transportInitialized: false,
|
||||
xpcInspector: null,
|
||||
|
||||
/**
|
||||
* Initialize the debugger server.
|
||||
*/
|
||||
init: function DH_init() {
|
||||
if (this.initialized) {
|
||||
return;
|
||||
}
|
||||
|
||||
Cu.import("resource://gre/modules/jsdebugger.jsm");
|
||||
this.xpcInspector = Cc["@mozilla.org/jsinspector;1"].getService(Ci.nsIJSInspector);
|
||||
this.initTransport();
|
||||
this.addActors("chrome://global/content/devtools/dbg-script-actors.js");
|
||||
},
|
||||
|
||||
/**
|
||||
* Initialize the debugger server's transport variables. This can be
|
||||
* in place of init() for cases where the jsdebugger isn't needed.
|
||||
*/
|
||||
initTransport: function DH_initTransport() {
|
||||
if (this._transportInitialized) {
|
||||
return;
|
||||
}
|
||||
|
||||
this._connections = {};
|
||||
this._nextConnID = 0;
|
||||
this._transportInitialized = true;
|
||||
},
|
||||
|
||||
get initialized() { return !!this.xpcInspector; },
|
||||
|
||||
/**
|
||||
* Load a subscript into the debugging global.
|
||||
*
|
||||
* @param aURL string A url that will be loaded as a subscript into the
|
||||
* debugging global. The user must load at least one script
|
||||
* that implements a createRootActor() function to create the
|
||||
* server's root actor.
|
||||
*/
|
||||
addActors: function DH_addActors(aURL) {
|
||||
loadSubScript.call(this, aURL);
|
||||
},
|
||||
|
||||
/**
|
||||
* Install Firefox-specific actors.
|
||||
*/
|
||||
addBrowserActors: function DH_addBrowserActors() {
|
||||
this.addActors("chrome://global/content/devtools/dbg-browser-actors.js");
|
||||
},
|
||||
|
||||
/**
|
||||
* Listens on the given port for remote debugger connections.
|
||||
*
|
||||
* @param aPort int
|
||||
* The port to listen on.
|
||||
* @param aLocalOnly bool
|
||||
* If true, server will listen on the loopback device.
|
||||
*/
|
||||
openListener: function DH_openListener(aPort, aLocalOnly) {
|
||||
this._checkInit();
|
||||
|
||||
if (this._listener) {
|
||||
throw "Debugging listener already open.";
|
||||
}
|
||||
|
||||
try {
|
||||
let socket = new ServerSocket(aPort, aLocalOnly, 4);
|
||||
socket.asyncListen(this);
|
||||
this._listener = socket;
|
||||
} catch (e) {
|
||||
dumpn("Could not start debugging listener on port " + aPort + ": " + e);
|
||||
throw Cr.NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
return true;
|
||||
},
|
||||
|
||||
/**
|
||||
* Close a previously-opened TCP listener.
|
||||
*/
|
||||
closeListener: function DH_closeListener() {
|
||||
this._checkInit();
|
||||
|
||||
if (!this._listener) {
|
||||
return false;
|
||||
}
|
||||
|
||||
this._listener.close();
|
||||
this._listener = null;
|
||||
|
||||
return true;
|
||||
},
|
||||
|
||||
/**
|
||||
* Creates a new connection to the local debugger speaking over an
|
||||
* nsIPipe.
|
||||
*
|
||||
* @returns a client-side DebuggerTransport for communicating with
|
||||
* the newly-created connection.
|
||||
*/
|
||||
connectPipe: function DH_connectPipe() {
|
||||
this._checkInit();
|
||||
|
||||
let toServer = Cc["@mozilla.org/pipe;1"].createInstance(Ci.nsIPipe);
|
||||
toServer.init(true, true, 0, 0, null);
|
||||
let toClient = Cc["@mozilla.org/pipe;1"].createInstance(Ci.nsIPipe);
|
||||
toClient.init(true, true, 0, 0, null);
|
||||
|
||||
let serverTransport = new DebuggerTransport(toServer.inputStream,
|
||||
toClient.outputStream);
|
||||
this._onConnection(serverTransport);
|
||||
|
||||
return new DebuggerTransport(toClient.inputStream, toServer.outputStream);
|
||||
},
|
||||
|
||||
|
||||
// nsIServerSocketListener implementation
|
||||
|
||||
onSocketAccepted: function DH_onSocketAccepted(aSocket, aTransport) {
|
||||
dumpn("New debugging connection on " + aTransport.host + ":" + aTransport.port);
|
||||
|
||||
try {
|
||||
let input = aTransport.openInputStream(0, 0, 0);
|
||||
let output = aTransport.openOutputStream(0, 0, 0);
|
||||
let transport = new DebuggerTransport(input, output);
|
||||
DebuggerServer._onConnection(transport);
|
||||
} catch (e) {
|
||||
dumpn("Couldn't initialize connection: " + e + " - " + e.stack);
|
||||
}
|
||||
},
|
||||
|
||||
onStopListening: function DH_onStopListening() { },
|
||||
|
||||
/**
|
||||
* Raises an exception if the server has not been properly initialized.
|
||||
*/
|
||||
_checkInit: function DH_checkInit() {
|
||||
if (!this._transportInitialized) {
|
||||
throw "DebuggerServer has not been initialized.";
|
||||
}
|
||||
|
||||
if (!this.createRootActor) {
|
||||
throw "Use DebuggerServer.addActors() to add a root actor implementation.";
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Create a new debugger connection for the given transport. Called
|
||||
* after connectPipe() or after an incoming socket connection.
|
||||
*/
|
||||
_onConnection: function DH_onConnection(aTransport) {
|
||||
let connID = "conn" + this._nextConnID++ + '.';
|
||||
let conn = new DebuggerServerConnection(connID, aTransport);
|
||||
this._connections[connID] = conn;
|
||||
|
||||
// Create a root actor for the connection and send the hello packet.
|
||||
conn.rootActor = this.createRootActor(conn);
|
||||
conn.addActor(conn.rootActor);
|
||||
aTransport.send(conn.rootActor.sayHello());
|
||||
aTransport.ready();
|
||||
},
|
||||
|
||||
/**
|
||||
* Remove the connection from the debugging server.
|
||||
*/
|
||||
_connectionClosed: function DH_connectionClosed(aConnection) {
|
||||
delete this._connections[aConnection.prefix];
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Construct an ActorPool.
|
||||
*
|
||||
* ActorPools are actorID -> actor mapping and storage. These are
|
||||
* used to accumulate and quickly dispose of groups of actors that
|
||||
* share a lifetime.
|
||||
*/
|
||||
function ActorPool(aConnection)
|
||||
{
|
||||
this.conn = aConnection;
|
||||
this._cleanups = {};
|
||||
this._actors = {};
|
||||
}
|
||||
|
||||
ActorPool.prototype = {
|
||||
/**
|
||||
* Add an actor to the actor pool. If the actor doesn't have an ID,
|
||||
* allocate one from the connection.
|
||||
*
|
||||
* @param aActor object
|
||||
* The actor implementation. If the object has a
|
||||
* 'disconnected' property, it will be called when the actor
|
||||
* pool is cleaned up.
|
||||
*/
|
||||
addActor: function AP_addActor(aActor) {
|
||||
aActor.conn = this.conn;
|
||||
if (!aActor.actorID) {
|
||||
aActor.actorID = this.conn.allocID(aActor.actorPrefix || undefined);
|
||||
}
|
||||
|
||||
if (aActor.registeredPool) {
|
||||
aActor.registeredPool.removeActor(aActor);
|
||||
}
|
||||
aActor.registeredPool = this;
|
||||
|
||||
this._actors[aActor.actorID] = aActor;
|
||||
if (aActor.disconnect) {
|
||||
this._cleanups[aActor.actorID] = aActor;
|
||||
}
|
||||
},
|
||||
|
||||
get: function AP_get(aActorID) {
|
||||
return this._actors[aActorID];
|
||||
},
|
||||
|
||||
has: function AP_has(aActorID) {
|
||||
return aActorID in this._actors;
|
||||
},
|
||||
|
||||
/**
|
||||
* Remove an actor from the actor pool.
|
||||
*/
|
||||
removeActor: function AP_remove(aActorID) {
|
||||
delete this._actors[aActorID];
|
||||
delete this._cleanups[aActorID];
|
||||
},
|
||||
|
||||
/**
|
||||
* Run all cleanups previously registered with addCleanup.
|
||||
*/
|
||||
cleanup: function AP_cleanup() {
|
||||
for each (let actor in this._cleanups) {
|
||||
actor.disconnect();
|
||||
}
|
||||
this._cleanups = {};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a DebuggerServerConnection.
|
||||
*
|
||||
* Represents a connection to this debugging global from a client.
|
||||
* Manages a set of actors and actor pools, allocates actor ids, and
|
||||
* handles incoming requests.
|
||||
*
|
||||
* @param aPrefix string
|
||||
* All actor IDs created by this connection should be prefixed
|
||||
* with aPrefix.
|
||||
* @param aTransport transport
|
||||
* Packet transport for the debugging protocol.
|
||||
*/
|
||||
function DebuggerServerConnection(aPrefix, aTransport)
|
||||
{
|
||||
this._prefix = aPrefix;
|
||||
this._transport = aTransport;
|
||||
this._transport.hooks = this;
|
||||
this._nextID = 1;
|
||||
|
||||
this._actorPool = new ActorPool(this);
|
||||
this._extraPools = [];
|
||||
}
|
||||
|
||||
DebuggerServerConnection.prototype = {
|
||||
_prefix: null,
|
||||
get prefix() { return this._prefix },
|
||||
|
||||
_transport: null,
|
||||
get transport() { return this._transport },
|
||||
|
||||
send: function DSC_send(aPacket) {
|
||||
this.transport.send(aPacket);
|
||||
},
|
||||
|
||||
allocID: function DSC_allocID(aPrefix) {
|
||||
return this.prefix + (aPrefix || '') + this._nextID++;
|
||||
},
|
||||
|
||||
/**
|
||||
* Add a map of actor IDs to the connection.
|
||||
*/
|
||||
addActorPool: function DSC_addActorPool(aActorPool) {
|
||||
this._extraPools.push(aActorPool);
|
||||
},
|
||||
|
||||
/**
|
||||
* Remove a previously-added pool of actors to the connection.
|
||||
*/
|
||||
removeActorPool: function DSC_removeActorPool(aActorPool) {
|
||||
let index = this._extraPools.splice(this._extraPools.lastIndexOf(aActorPool), 1);
|
||||
},
|
||||
|
||||
/**
|
||||
* Add an actor to the default actor pool for this connection.
|
||||
*/
|
||||
addActor: function DSC_addActor(aActor) {
|
||||
this._actorPool.addActor(aActor);
|
||||
},
|
||||
|
||||
/**
|
||||
* Remove an actor to the default actor pool for this connection.
|
||||
*/
|
||||
removeActor: function DSC_removeActor(aActor) {
|
||||
this._actorPool.removeActor(aActor);
|
||||
},
|
||||
|
||||
/**
|
||||
* Add a cleanup to the default actor pool for this connection.
|
||||
*/
|
||||
addCleanup: function DSC_addCleanup(aCleanup) {
|
||||
this._actorPool.addCleanup(aCleanup);
|
||||
},
|
||||
|
||||
/**
|
||||
* Look up an actor implementation for an actorID. Will search
|
||||
* all the actor pools registered with the connection.
|
||||
*
|
||||
* @param aActorID string
|
||||
* Actor ID to look up.
|
||||
*/
|
||||
getActor: function DSC_getActor(aActorID) {
|
||||
if (this._actorPool.has(aActorID)) {
|
||||
return this._actorPool.get(aActorID);
|
||||
}
|
||||
|
||||
for each (let pool in this._extraPools) {
|
||||
if (pool.has(aActorID)) {
|
||||
return pool.get(aActorID);
|
||||
}
|
||||
}
|
||||
|
||||
if (aActorID === "root") {
|
||||
return this.rootActor;
|
||||
}
|
||||
|
||||
return null;
|
||||
},
|
||||
|
||||
// Transport hooks.
|
||||
|
||||
/**
|
||||
* Called by DebuggerTransport to dispatch incoming packets as appropriate.
|
||||
*
|
||||
* @param aPacket object
|
||||
* The incoming packet.
|
||||
*/
|
||||
onPacket: function DSC_onPacket(aPacket) {
|
||||
let actor = this.getActor(aPacket.to);
|
||||
if (!actor) {
|
||||
this.transport.send({ from: aPacket.to ? aPacket.to : "root",
|
||||
error: "noSuchActor" });
|
||||
return;
|
||||
}
|
||||
|
||||
var ret = null;
|
||||
|
||||
// Dispatch the request to the actor.
|
||||
if (actor.requestTypes && actor.requestTypes[aPacket.type]) {
|
||||
try {
|
||||
ret = actor.requestTypes[aPacket.type].bind(actor)(aPacket);
|
||||
} catch(e) {
|
||||
dumpn(e);
|
||||
ret = { error: "unknownError",
|
||||
message: "An unknown error has occurred while processing request." };
|
||||
}
|
||||
} else {
|
||||
ret = { error: "unrecognizedPacketType",
|
||||
message: 'Actor "' + actor.actorID + '" does not recognize the packet type "' + aPacket.type + '"' };
|
||||
}
|
||||
|
||||
if (!ret) {
|
||||
// XXX: The actor wasn't ready to reply yet, don't process new
|
||||
// requests until it does.
|
||||
return;
|
||||
}
|
||||
|
||||
if (!ret.from) {
|
||||
ret.from = aPacket.to;
|
||||
}
|
||||
|
||||
this.transport.send(ret);
|
||||
},
|
||||
|
||||
/**
|
||||
* Called by DebuggerTransport when the underlying stream is closed.
|
||||
*
|
||||
* @param aStatus nsresult
|
||||
* The status code that corresponds to the reason for closing
|
||||
* the stream.
|
||||
*/
|
||||
onClosed: function DSC_onClosed(aStatus) {
|
||||
dumpn("Cleaning up connection.");
|
||||
|
||||
this._actorPool.cleanup();
|
||||
this._actorPool = null;
|
||||
this._extraPools.map(function(p) { p.cleanup(); });
|
||||
this._extraPools = null;
|
||||
|
||||
DebuggerServer._connectionClosed(this);
|
||||
}
|
||||
};
|
|
@ -0,0 +1,71 @@
|
|||
/* -*- Mode: javascript; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is mozilla.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Mozilla Foundation
|
||||
* Portions created by the Initial Developer are Copyright (C) 2011
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Dave Camp <dcamp@mozilla.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
const Cc = Components.classes;
|
||||
const Ci = Components.interfaces;
|
||||
const Cu = Components.utils;
|
||||
const Cr = Components.results;
|
||||
|
||||
var EXPORTED_SYMBOLS = ["DebuggerServer"]
|
||||
|
||||
function loadSubScript(aURL)
|
||||
{
|
||||
try {
|
||||
let loader = Components.classes["@mozilla.org/moz/jssubscript-loader;1"]
|
||||
.getService(Components.interfaces.mozIJSSubScriptLoader);
|
||||
loader.loadSubScript(aURL, this);
|
||||
} catch(e) {
|
||||
dump("Error loading: " + aURL + ": " + e + " - " + e.stack + "\n");
|
||||
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
Cu.import("resource:///modules/devtools/dbg-client.jsm");
|
||||
|
||||
// Load the debugging server in a sandbox with its own compartment.
|
||||
// Note that this is slated for elimination in bug 703718.
|
||||
var systemPrincipal = Cc["@mozilla.org/systemprincipal;1"]
|
||||
.createInstance(Ci.nsIPrincipal);
|
||||
|
||||
var gGlobal = Cu.Sandbox(systemPrincipal);
|
||||
gGlobal.importFunction(loadSubScript);
|
||||
gGlobal.loadSubScript("chrome://global/content/devtools/dbg-server.js");
|
||||
|
||||
var DebuggerServer = gGlobal.DebuggerServer;
|
|
@ -0,0 +1,50 @@
|
|||
# ***** BEGIN LICENSE BLOCK *****
|
||||
# Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
#
|
||||
# The contents of this file are subject to the Mozilla Public License Version
|
||||
# 1.1 (the "License"); you may not use this file except in compliance with
|
||||
# the License. You may obtain a copy of the License at
|
||||
# http://www.mozilla.org/MPL/
|
||||
#
|
||||
# Software distributed under the License is distributed on an "AS IS" basis,
|
||||
# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
# for the specific language governing rights and limitations under the
|
||||
# License.
|
||||
#
|
||||
# The Original Code is mozilla.org code.
|
||||
#
|
||||
# The Initial Developer of the Original Code is
|
||||
# Mozilla Foundation
|
||||
# Portions created by the Initial Developer are Copyright (C) 2011
|
||||
# the Initial Developer. All Rights Reserved.
|
||||
#
|
||||
# Contributor(s):
|
||||
# Dave Camp <dcamp@mozilla.com>
|
||||
#
|
||||
# Alternatively, the contents of this file may be used under the terms of
|
||||
# either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
# in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
# of those above. If you wish to allow use of your version of this file only
|
||||
# under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
# use your version of this file under the terms of the MPL, indicate your
|
||||
# decision by deleting the provisions above and replace them with the notice
|
||||
# and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
# the provisions above, a recipient may use your version of this file under
|
||||
# the terms of any one of the MPL, the GPL or the LGPL.
|
||||
#
|
||||
# ***** END LICENSE BLOCK *****
|
||||
|
||||
DEPTH = ../../../..
|
||||
topsrcdir = @top_srcdir@
|
||||
srcdir = @srcdir@
|
||||
VPATH = @srcdir@
|
||||
relativesrcdir = toolkit/devtools/debugger/tests
|
||||
|
||||
include $(DEPTH)/config/autoconf.mk
|
||||
|
||||
MODULE = test_debugger
|
||||
|
||||
XPCSHELL_TESTS = unit
|
||||
|
||||
include $(topsrcdir)/config/rules.mk
|
|
@ -0,0 +1,99 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
const Cc = Components.classes;
|
||||
const Ci = Components.interfaces;
|
||||
const Cu = Components.utils;
|
||||
const Cr = Components.results;
|
||||
|
||||
Cu.import("resource:///modules/devtools/dbg-server.jsm");
|
||||
Cu.import("resource:///modules/devtools/dbg-client.jsm");
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
|
||||
function check_except(func)
|
||||
{
|
||||
try {
|
||||
func();
|
||||
} catch (e) {
|
||||
do_check_true(true);
|
||||
return;
|
||||
}
|
||||
dump("Should have thrown an exception: " + func.toString());
|
||||
do_check_true(false);
|
||||
}
|
||||
|
||||
function testGlobal(aName) {
|
||||
let systemPrincipal = Cc["@mozilla.org/systemprincipal;1"]
|
||||
.createInstance(Ci.nsIPrincipal);
|
||||
|
||||
let sandbox = Cu.Sandbox(systemPrincipal);
|
||||
Cu.evalInSandbox("this.__name = '" + aName + "'", sandbox);
|
||||
return sandbox;
|
||||
}
|
||||
|
||||
function addTestGlobal(aName)
|
||||
{
|
||||
let global = testGlobal(aName);
|
||||
DebuggerServer.addTestGlobal(global);
|
||||
return global;
|
||||
}
|
||||
|
||||
function getTestGlobalContext(aClient, aName, aCallback) {
|
||||
aClient.request({ "to": "root", "type": "listContexts" }, function(aResponse) {
|
||||
for each (let context in aResponse.contexts) {
|
||||
if (context.global == aName) {
|
||||
aCallback(context);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
aCallback(null);
|
||||
});
|
||||
}
|
||||
|
||||
function attachTestGlobalClient(aClient, aName, aCallback) {
|
||||
getTestGlobalContext(aClient, aName, function(aContext) {
|
||||
aClient.attachThread(aContext.actor, aCallback);
|
||||
});
|
||||
}
|
||||
|
||||
function attachTestGlobalClientAndResume(aClient, aName, aCallback) {
|
||||
attachTestGlobalClient(aClient, aName, function(aResponse, aThreadClient) {
|
||||
aThreadClient.resume(function(aResponse) {
|
||||
aCallback(aResponse, aThreadClient);
|
||||
});
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize the testing debugger server.
|
||||
*/
|
||||
function initTestDebuggerServer()
|
||||
{
|
||||
DebuggerServer.addActors("resource://test/testactors.js");
|
||||
DebuggerServer.init();
|
||||
}
|
||||
|
||||
function finishClient(aClient)
|
||||
{
|
||||
aClient.close(function() {
|
||||
do_test_finished();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the full path of the file with the specified name in a
|
||||
* platform-independent and URL-like form.
|
||||
*/
|
||||
function getFilePath(aName)
|
||||
{
|
||||
let file = do_get_file(aName);
|
||||
let path = Services.io.newFileURI(file).spec;
|
||||
let filePrePath = "file://";
|
||||
if ("nsILocalFileWin" in Ci &&
|
||||
file instanceof Ci.nsILocalFileWin) {
|
||||
filePrePath += "/";
|
||||
}
|
||||
return path.slice(filePrePath.length);
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
var gClient;
|
||||
var gDebuggee;
|
||||
|
||||
function run_test()
|
||||
{
|
||||
DebuggerServer.addActors("resource://test/testactors.js");
|
||||
|
||||
DebuggerServer.init();
|
||||
gDebuggee = testGlobal("test-1");
|
||||
DebuggerServer.addTestGlobal(gDebuggee);
|
||||
|
||||
let transport = DebuggerServer.connectPipe();
|
||||
gClient = new DebuggerClient(transport);
|
||||
gClient.connect(function(aType, aTraits) {
|
||||
getTestGlobalContext(gClient, "test-1", function(aContext) {
|
||||
test_attach(aContext);
|
||||
});
|
||||
});
|
||||
do_test_pending();
|
||||
}
|
||||
|
||||
function test_attach(aContext)
|
||||
{
|
||||
gClient.attachThread(aContext.actor, function(aResponse, aThreadClient) {
|
||||
do_check_eq(aThreadClient.state, "paused");
|
||||
aThreadClient.resume(function() {
|
||||
cleanup();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function cleanup()
|
||||
{
|
||||
gClient.addListener("closed", function(aEvent) {
|
||||
do_test_finished();
|
||||
});
|
||||
gClient.close();
|
||||
}
|
||||
|
|
@ -0,0 +1,60 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
/**
|
||||
* Check basic breakpoint functionality.
|
||||
*/
|
||||
|
||||
var gDebuggee;
|
||||
var gClient;
|
||||
var gThreadClient;
|
||||
|
||||
function run_test()
|
||||
{
|
||||
initTestDebuggerServer();
|
||||
gDebuggee = addTestGlobal("test-stack");
|
||||
gClient = new DebuggerClient(DebuggerServer.connectPipe());
|
||||
gClient.connect(function () {
|
||||
attachTestGlobalClientAndResume(gClient, "test-stack", function (aResponse, aThreadClient) {
|
||||
gThreadClient = aThreadClient;
|
||||
test_simple_breakpoint();
|
||||
});
|
||||
});
|
||||
do_test_pending();
|
||||
}
|
||||
|
||||
function test_simple_breakpoint()
|
||||
{
|
||||
gThreadClient.addOneTimeListener("paused", function (aEvent, aPacket) {
|
||||
let path = getFilePath('test_breakpoint-01.js');
|
||||
gThreadClient.setBreakpoint({ url: path, line: gDebuggee.line0 + 3}, function (aResponse, bpClient) {
|
||||
gThreadClient.addOneTimeListener("paused", function (aEvent, aPacket) {
|
||||
// Check the return value.
|
||||
do_check_eq(aPacket.type, "paused");
|
||||
do_check_eq(aPacket.why.type, "breakpoint");
|
||||
do_check_eq(aPacket.why.actors[0], bpClient.actor);
|
||||
// Check that the breakpoint worked.
|
||||
do_check_eq(gDebuggee.a, 1);
|
||||
do_check_eq(gDebuggee.b, undefined);
|
||||
|
||||
// Remove the breakpoint.
|
||||
bpClient.remove(function (aResponse) {
|
||||
gThreadClient.resume(function () {
|
||||
finishClient(gClient);
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
// Continue until the breakpoint is hit.
|
||||
gThreadClient.resume(function () {
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
gDebuggee.eval("var line0 = Error().lineNumber;\n" +
|
||||
"debugger;\n" + // line0 + 1
|
||||
"var a = 1;\n" + // line0 + 2
|
||||
"var b = 2;\n"); // line0 + 3
|
||||
}
|
|
@ -0,0 +1,84 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
Cu.import("resource:///modules/devtools/dbg-server.jsm");
|
||||
Cu.import("resource:///modules/devtools/dbg-client.jsm");
|
||||
|
||||
var gClient;
|
||||
var gDebuggee;
|
||||
|
||||
function run_test()
|
||||
{
|
||||
DebuggerServer.addActors("resource://test/testactors.js");
|
||||
|
||||
DebuggerServer.init();
|
||||
gDebuggee = testGlobal("test-1");
|
||||
DebuggerServer.addTestGlobal(gDebuggee);
|
||||
|
||||
let transport = DebuggerServer.connectPipe();
|
||||
gClient = new DebuggerClient(transport);
|
||||
gClient.addListener("connected", function(aEvent, aType, aTraits) {
|
||||
gClient.request({ to: "root", type: "listContexts" }, function(aResponse) {
|
||||
do_check_true('contexts' in aResponse);
|
||||
for each (let context in aResponse.contexts) {
|
||||
if (context.global == "test-1") {
|
||||
test_attach(context);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
do_check_true(false);
|
||||
});
|
||||
});
|
||||
gClient.connect();
|
||||
|
||||
do_test_pending();
|
||||
}
|
||||
|
||||
function test_attach(aContext)
|
||||
{
|
||||
gClient.request({ to: aContext.actor, type: "attach" }, function(aResponse) {
|
||||
do_check_eq(aResponse.type, "paused");
|
||||
|
||||
// Resume the thread and test the debugger statement.
|
||||
gClient.request({ to: aContext.actor, type: "resume" }, function() {
|
||||
test_debugger_statement(aContext);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function test_debugger_statement(aContext)
|
||||
{
|
||||
gClient.addListener("paused", function(aName, aPacket) {
|
||||
// Reach around the protocol to check that the debuggee is in the state
|
||||
// we expect.
|
||||
do_check_true(gDebuggee.a);
|
||||
do_check_false(gDebuggee.b);
|
||||
|
||||
let xpcInspector = Cc["@mozilla.org/jsinspector;1"].getService(Ci.nsIJSInspector);
|
||||
do_check_eq(xpcInspector.eventLoopNestLevel, 1);
|
||||
|
||||
gClient.request({ to: aContext.actor, type: "resume" }, function() {
|
||||
cleanup();
|
||||
});
|
||||
});
|
||||
|
||||
Cu.evalInSandbox("var a = true; var b = false; debugger; var b = true;", gDebuggee);
|
||||
// Now make sure that we've run the code after the debugger statement...
|
||||
do_check_true(gDebuggee.b);
|
||||
}
|
||||
|
||||
function cleanup()
|
||||
{
|
||||
gClient.addListener("closed", function(aEvent, aResult) {
|
||||
do_test_finished();
|
||||
});
|
||||
|
||||
try {
|
||||
let xpcInspector = Cc["@mozilla.org/jsinspector;1"].getService(Ci.nsIJSInspector);
|
||||
do_check_eq(xpcInspector.eventLoopNestLevel, 0);
|
||||
} catch(e) {
|
||||
dump(e);
|
||||
}
|
||||
|
||||
gClient.close();
|
||||
}
|
|
@ -0,0 +1,77 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
Cu.import("resource:///modules/devtools/dbg-server.jsm");
|
||||
Cu.import("resource:///modules/devtools/dbg-client.jsm");
|
||||
|
||||
var gClient;
|
||||
var gDebuggee;
|
||||
|
||||
function run_test()
|
||||
{
|
||||
DebuggerServer.addActors("resource://test/testactors.js");
|
||||
|
||||
DebuggerServer.init();
|
||||
gDebuggee = testGlobal("test-1");
|
||||
DebuggerServer.addTestGlobal(gDebuggee);
|
||||
|
||||
let transport = DebuggerServer.connectPipe();
|
||||
gClient = new DebuggerClient(transport);
|
||||
gClient.connect(function(aType, aTraits) {
|
||||
getTestGlobalContext(gClient, "test-1", function(aContext) {
|
||||
test_attach(aContext);
|
||||
});
|
||||
});
|
||||
do_test_pending();
|
||||
}
|
||||
|
||||
function test_attach(aContext)
|
||||
{
|
||||
gClient.attachThread(aContext.actor, function(aResponse, aThreadClient) {
|
||||
do_check_eq(aThreadClient.state, "paused");
|
||||
do_check_eq(aThreadClient.actor, aContext.actor);
|
||||
aThreadClient.resume(function() {
|
||||
do_check_eq(aThreadClient.state, "attached");
|
||||
test_debugger_statement(aThreadClient);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function test_debugger_statement(aThreadClient)
|
||||
{
|
||||
aThreadClient.addListener("paused", function(aEvent, aPacket) {
|
||||
do_check_eq(aThreadClient.state, "paused");
|
||||
// Reach around the protocol to check that the debuggee is in the state
|
||||
// we expect.
|
||||
do_check_true(gDebuggee.a);
|
||||
do_check_false(gDebuggee.b);
|
||||
|
||||
let xpcInspector = Cc["@mozilla.org/jsinspector;1"].getService(Ci.nsIJSInspector);
|
||||
do_check_eq(xpcInspector.eventLoopNestLevel, 1);
|
||||
|
||||
aThreadClient.resume(function() {
|
||||
cleanup();
|
||||
});
|
||||
});
|
||||
|
||||
Cu.evalInSandbox("var a = true; var b = false; debugger; var b = true;", gDebuggee);
|
||||
|
||||
// Now make sure that we've run the code after the debugger statement...
|
||||
do_check_true(gDebuggee.b);
|
||||
}
|
||||
|
||||
function cleanup()
|
||||
{
|
||||
gClient.addListener("closed", function(aEvent) {
|
||||
do_test_finished();
|
||||
});
|
||||
|
||||
try {
|
||||
let xpcInspector = Cc["@mozilla.org/jsinspector;1"].getService(Ci.nsIJSInspector);
|
||||
do_check_eq(xpcInspector.eventLoopNestLevel, 0);
|
||||
} catch(e) {
|
||||
dump(e);
|
||||
}
|
||||
|
||||
gClient.close();
|
||||
}
|
|
@ -0,0 +1,64 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
Cu.import("resource:///modules/devtools/dbg-server.jsm");
|
||||
Cu.import("resource:///modules/devtools/dbg-client.jsm");
|
||||
|
||||
function run_test()
|
||||
{
|
||||
// Should get an exception if we try to interact with DebuggerServer
|
||||
// before we initialize it...
|
||||
check_except(function() {
|
||||
DebuggerServer.openListener(2929, true);
|
||||
});
|
||||
check_except(DebuggerServer.closeListener);
|
||||
check_except(DebuggerServer.connectPipe);
|
||||
|
||||
DebuggerServer.init();
|
||||
|
||||
// These should still fail because we haven't added a createRootActor
|
||||
// implementation yet.
|
||||
check_except(function() {
|
||||
DebuggerServer.openListener(2929, true);
|
||||
});
|
||||
check_except(DebuggerServer.closeListener);
|
||||
check_except(DebuggerServer.connectPipe);
|
||||
|
||||
DebuggerServer.addActors("resource://test/testactors.js");
|
||||
|
||||
// Now they should work.
|
||||
DebuggerServer.openListener(2929, true);
|
||||
DebuggerServer.closeListener();
|
||||
|
||||
// Make sure we got the test's root actor all set up.
|
||||
let client1 = DebuggerServer.connectPipe();
|
||||
client1.hooks = {
|
||||
onPacket: function(aPacket1) {
|
||||
do_check_eq(aPacket1.from, "root");
|
||||
do_check_eq(aPacket1.applicationType, "xpcshell-tests");
|
||||
|
||||
// Spin up a second connection, make sure it has its own root
|
||||
// actor.
|
||||
let client2 = DebuggerServer.connectPipe();
|
||||
client2.hooks = {
|
||||
onPacket: function(aPacket2) {
|
||||
do_check_eq(aPacket2.from, "root");
|
||||
do_check_neq(aPacket1.testConnectionPrefix,
|
||||
aPacket2.testConnectionPrefix);
|
||||
client2.close();
|
||||
},
|
||||
onClosed: function(aResult) {
|
||||
client1.close();
|
||||
},
|
||||
};
|
||||
client2.ready();
|
||||
},
|
||||
|
||||
onClosed: function(aResult) {
|
||||
do_test_finished();
|
||||
},
|
||||
};
|
||||
|
||||
client1.ready();
|
||||
do_test_pending();
|
||||
}
|
|
@ -0,0 +1,85 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
Cu.import("resource:///modules/devtools/dbg-server.jsm");
|
||||
Cu.import("resource:///modules/devtools/dbg-client.jsm");
|
||||
|
||||
function run_test()
|
||||
{
|
||||
DebuggerServer.init();
|
||||
DebuggerServer.addActors("resource://test/testactors.js");
|
||||
|
||||
add_test(test_socket_conn);
|
||||
add_test(test_socket_shutdown);
|
||||
add_test(test_pipe_conn);
|
||||
|
||||
run_next_test();
|
||||
}
|
||||
|
||||
function really_long() {
|
||||
let ret = "0123456789";
|
||||
for (let i = 0; i < 18; i++) {
|
||||
ret += ret;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
function test_socket_conn()
|
||||
{
|
||||
DebuggerServer.openListener(2929, true);
|
||||
|
||||
let transport = debuggerSocketConnect("127.0.0.1", 2929);
|
||||
transport.hooks = {
|
||||
onPacket: function(aPacket) {
|
||||
this.onPacket = function(aPacket) {
|
||||
transport.close();
|
||||
}
|
||||
// Verify that things work correctly when bigger than the output
|
||||
// transport buffers...
|
||||
transport.send({to: "root",
|
||||
type: "echo",
|
||||
reallylong: really_long()});
|
||||
do_check_eq(aPacket.from, "root");
|
||||
},
|
||||
onClosed: function(aStatus) {
|
||||
run_next_test();
|
||||
},
|
||||
};
|
||||
transport.ready();
|
||||
}
|
||||
|
||||
function test_socket_shutdown()
|
||||
{
|
||||
DebuggerServer.closeListener();
|
||||
|
||||
let transport = debuggerSocketConnect("127.0.0.1", 2929);
|
||||
transport.hooks = {
|
||||
onPacket: function(aPacket) {
|
||||
// Shouldn't reach this, should never connect.
|
||||
do_check_true(false);
|
||||
},
|
||||
|
||||
onClosed: function(aStatus) {
|
||||
do_check_eq(aStatus, Cr.NS_ERROR_CONNECTION_REFUSED);
|
||||
run_next_test();
|
||||
}
|
||||
};
|
||||
|
||||
transport.ready();
|
||||
}
|
||||
|
||||
function test_pipe_conn()
|
||||
{
|
||||
let transport = DebuggerServer.connectPipe();
|
||||
transport.hooks = {
|
||||
onPacket: function(aPacket) {
|
||||
do_check_eq(aPacket.from, "root");
|
||||
transport.close();
|
||||
},
|
||||
onClosed: function(aStatus) {
|
||||
run_next_test();
|
||||
}
|
||||
};
|
||||
|
||||
transport.ready();
|
||||
}
|
|
@ -0,0 +1,58 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
/**
|
||||
* Check basic eval resume/re-pause
|
||||
*/
|
||||
|
||||
var gDebuggee;
|
||||
var gClient;
|
||||
var gThreadClient;
|
||||
|
||||
function run_test()
|
||||
{
|
||||
initTestDebuggerServer();
|
||||
gDebuggee = addTestGlobal("test-stack");
|
||||
gClient = new DebuggerClient(DebuggerServer.connectPipe());
|
||||
gClient.connect(function() {
|
||||
attachTestGlobalClientAndResume(gClient, "test-stack", function(aResponse, aThreadClient) {
|
||||
gThreadClient = aThreadClient;
|
||||
test_simple_eval();
|
||||
});
|
||||
});
|
||||
do_test_pending();
|
||||
}
|
||||
|
||||
function test_simple_eval()
|
||||
{
|
||||
gThreadClient.addOneTimeListener("paused", function(aEvent, aPacket) {
|
||||
let arg1Actor = aPacket.frame["arguments"][0].actor;
|
||||
gThreadClient.eval(null, "({ obj: true })", function(aResponse) {
|
||||
do_check_eq(aResponse.type, "resumed");
|
||||
// Expect a pause notification immediately.
|
||||
gThreadClient.addOneTimeListener("paused", function(aEvent, aPacket) {
|
||||
// Check the return value...
|
||||
do_check_eq(aPacket.type, "paused");
|
||||
do_check_eq(aPacket.why.type, "clientEvaluated");
|
||||
do_check_eq(aPacket.why.value.type, "object");
|
||||
do_check_eq(aPacket.why.value["class"], "Object");
|
||||
|
||||
// Make sure the previous pause lifetime was correctly dropped.
|
||||
gClient.request({ to: arg1Actor, type: "bogusRequest" }, function(aResponse) {
|
||||
do_check_eq(aResponse.error, "noSuchActor");
|
||||
gThreadClient.resume(function() {
|
||||
finishClient(gClient);
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
gDebuggee.eval("(" + function() {
|
||||
function stopMe(arg1) { debugger; };
|
||||
stopMe({obj: true});
|
||||
} + ")()");
|
||||
}
|
|
@ -0,0 +1,48 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
/**
|
||||
* Check eval resume/re-pause with a throw.
|
||||
*/
|
||||
|
||||
var gDebuggee;
|
||||
var gClient;
|
||||
var gThreadClient;
|
||||
|
||||
function run_test()
|
||||
{
|
||||
initTestDebuggerServer();
|
||||
gDebuggee = addTestGlobal("test-stack");
|
||||
gClient = new DebuggerClient(DebuggerServer.connectPipe());
|
||||
gClient.connect(function() {
|
||||
attachTestGlobalClientAndResume(gClient, "test-stack", function(aResponse, aThreadClient) {
|
||||
gThreadClient = aThreadClient;
|
||||
test_throw_eval();
|
||||
});
|
||||
});
|
||||
do_test_pending();
|
||||
}
|
||||
|
||||
function test_throw_eval()
|
||||
{
|
||||
gThreadClient.addOneTimeListener("paused", function(aEvent, aPacket) {
|
||||
gThreadClient.eval(null, "throw 'failure'", function(aResponse) {
|
||||
do_check_eq(aResponse.type, "resumed");
|
||||
// Expect a pause notification immediately.
|
||||
gThreadClient.addOneTimeListener("paused", function(aEvent, aPacket) {
|
||||
// Check the return value...
|
||||
do_check_eq(aPacket.type, "paused");
|
||||
do_check_eq(aPacket.why.type, "clientEvaluated");
|
||||
do_check_eq(aPacket.why.exception, "failure");
|
||||
gThreadClient.resume(function() {
|
||||
finishClient(gClient);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
gDebuggee.eval("(" + function() {
|
||||
function stopMe(arg1) { debugger; };
|
||||
stopMe({obj: true});
|
||||
} + ")()");
|
||||
}
|
|
@ -0,0 +1,50 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
/**
|
||||
* Check syntax errors in an eval.
|
||||
*/
|
||||
|
||||
var gDebuggee;
|
||||
var gClient;
|
||||
var gThreadClient;
|
||||
|
||||
function run_test()
|
||||
{
|
||||
initTestDebuggerServer();
|
||||
gDebuggee = addTestGlobal("test-stack");
|
||||
gClient = new DebuggerClient(DebuggerServer.connectPipe());
|
||||
gClient.connect(function() {
|
||||
attachTestGlobalClientAndResume(gClient, "test-stack", function(aResponse, aThreadClient) {
|
||||
gThreadClient = aThreadClient;
|
||||
test_syntax_error_eval();
|
||||
});
|
||||
});
|
||||
do_test_pending();
|
||||
}
|
||||
|
||||
function test_syntax_error_eval()
|
||||
{
|
||||
gThreadClient.addOneTimeListener("paused", function(aEvent, aPacket) {
|
||||
gThreadClient.eval(null, "%$@!@#", function(aResponse) {
|
||||
do_check_eq(aResponse.type, "resumed");
|
||||
// Expect a pause notification immediately.
|
||||
gThreadClient.addOneTimeListener("paused", function(aEvent, aPacket) {
|
||||
// Check the return value...
|
||||
do_check_eq(aPacket.type, "paused");
|
||||
do_check_eq(aPacket.why.type, "clientEvaluated");
|
||||
do_check_eq(aPacket.why.exception.type, "object");
|
||||
do_check_eq(aPacket.why.exception["class"], "Error");
|
||||
|
||||
gThreadClient.resume(function() {
|
||||
finishClient(gClient);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
gDebuggee.eval("(" + function() {
|
||||
function stopMe(arg1) { debugger; };
|
||||
stopMe({obj: true});
|
||||
} + ")()");
|
||||
}
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче