Merge mozilla-central to mozilla-inbound

This commit is contained in:
Ehsan Akhgari 2013-06-22 08:42:15 -04:00
Родитель d52fe41442 b30cafc29f
Коммит 9af8ee20af
124 изменённых файлов: 3712 добавлений и 2693 удалений

Просмотреть файл

@ -1,5 +1,5 @@
<?xml version="1.0"?>
<blocklist xmlns="http://www.mozilla.org/2006/addons-blocklist" lastupdate="1370990544000">
<blocklist xmlns="http://www.mozilla.org/2006/addons-blocklist" lastupdate="1371672180000">
<emItems>
<emItem blockID="i350" id="sqlmoz@facebook.com">
<versionRange minVersion="0" maxVersion="*" severity="3">
@ -265,6 +265,10 @@
<versionRange minVersion="3.1.22.0" maxVersion="3.1.22.0">
</versionRange>
</emItem>
<emItem blockID="i376" id="{9e09ac65-43c0-4b9d-970f-11e2e9616c55}">
<versionRange minVersion="0" maxVersion="*" severity="3">
</versionRange>
</emItem>
<emItem blockID="i44" id="sigma@labs.mozilla">
</emItem>
<emItem blockID="i246" id="support@vide1flash2.com">
@ -290,7 +294,7 @@
</versionRange>
</emItem>
<emItem blockID="i115" id="{ec8030f7-c20a-464f-9b0e-13a3a9e97384}">
<versionRange minVersion="0" maxVersion="*">
<versionRange minVersion="0" maxVersion="*" severity="3">
</versionRange>
</emItem>
<emItem blockID="i7" id="{2224e955-00e9-4613-a844-ce69fccaae91}">
@ -509,6 +513,10 @@
<versionRange minVersion="0" maxVersion="*" severity="1">
</versionRange>
</emItem>
<emItem blockID="i372" id="5nc3QHFgcb@r06Ws9gvNNVRfH.com">
<versionRange minVersion="0" maxVersion="*" severity="3">
</versionRange>
</emItem>
<emItem blockID="i356" id="{341f4dac-1966-47ff-aacf-0ce175f1498a}">
<versionRange minVersion="0" maxVersion="*" severity="1">
</versionRange>
@ -563,10 +571,18 @@
<versionRange minVersion="0" maxVersion="*">
</versionRange>
</emItem>
<emItem blockID="i380" id="{cc8f597b-0765-404e-a575-82aefbd81daf}">
<versionRange minVersion="0" maxVersion="*" severity="3">
</versionRange>
</emItem>
<emItem blockID="i314" id="crossriderapp8812@crossrider.com">
<versionRange minVersion="0" maxVersion="*" severity="1">
</versionRange>
</emItem>
<emItem blockID="i378" id="{a7aae4f0-bc2e-a0dd-fb8d-68ce32c9261f}">
<versionRange minVersion="0" maxVersion="*" severity="3">
</versionRange>
</emItem>
<emItem blockID="i73" id="a1g0a9g219d@a1.com">
<versionRange minVersion="0" maxVersion="*">
</versionRange>
@ -579,12 +595,16 @@
<versionRange minVersion="0" maxVersion="*" severity="3">
</versionRange>
</emItem>
<emItem blockID="i21" id="support@update-firefox.com">
</emItem>
<emItem blockID="i322" id="jid0-Y6TVIzs0r7r4xkOogmJPNAGFGBw@jetpack">
<versionRange minVersion="0" maxVersion="*" severity="3">
</versionRange>
</emItem>
<emItem blockID="i21" id="support@update-firefox.com">
</emItem>
<emItem blockID="i374" id="update@firefox.com">
<versionRange minVersion="0" maxVersion="*" severity="3">
</versionRange>
</emItem>
</emItems>
<pluginItems>

Просмотреть файл

@ -1073,19 +1073,13 @@ pref("devtools.debugger.chrome-enabled", true);
pref("devtools.debugger.chrome-debugging-host", "localhost");
pref("devtools.debugger.chrome-debugging-port", 6080);
pref("devtools.debugger.remote-host", "localhost");
pref("devtools.debugger.remote-autoconnect", false);
pref("devtools.debugger.remote-connection-retries", 3);
pref("devtools.debugger.remote-timeout", 20000);
pref("devtools.debugger.pause-on-exceptions", false);
pref("devtools.debugger.source-maps-enabled", true);
// The default Debugger UI settings
pref("devtools.debugger.ui.win-x", 0);
pref("devtools.debugger.ui.win-y", 0);
pref("devtools.debugger.ui.win-width", 900);
pref("devtools.debugger.ui.win-height", 400);
pref("devtools.debugger.ui.panes-sources-width", 200);
pref("devtools.debugger.ui.panes-instruments-width", 300);
pref("devtools.debugger.ui.pause-on-exceptions", false);
pref("devtools.debugger.ui.panes-visible-on-startup", false);
pref("devtools.debugger.ui.variables-sorting-enabled", true);
pref("devtools.debugger.ui.variables-only-enum-visible", false);
@ -1193,7 +1187,7 @@ pref("browser.panorama.animate_zoom", true);
// Defines the url to be used for new tabs.
pref("browser.newtab.url", "about:newtab");
// Activates preloading of the new tab url.
pref("browser.newtab.preload", false);
pref("browser.newtab.preload", true);
// Toggles the content of 'about:newtab'. Shows the grid when enabled.
pref("browser.newtabpage.enabled", true);

Просмотреть файл

@ -19,7 +19,5 @@
#endif
<!ENTITY % aboutHomeDTD SYSTEM "chrome://browser/locale/aboutHome.dtd">
%aboutHomeDTD;
<!ENTITY % debuggerDTD SYSTEM "chrome://browser/locale/devtools/debugger.dtd">
%debuggerDTD;
]>

Просмотреть файл

@ -95,7 +95,7 @@
<command id="Tools:DevToolbox" oncommand="gDevToolsBrowser.toggleToolboxCommand(gBrowser);"/>
<command id="Tools:DevToolbar" oncommand="DeveloperToolbar.toggle();" disabled="true" hidden="true"/>
<command id="Tools:DevToolbarFocus" oncommand="DeveloperToolbar.focusToggle();" disabled="true"/>
<command id="Tools:ChromeDebugger" oncommand="DebuggerUI.toggleChromeDebugger();" disabled="true" hidden="true"/>
<command id="Tools:ChromeDebugger" oncommand="BrowserDebuggerProcess.init();" disabled="true" hidden="true"/>
<command id="Tools:BrowserConsole" oncommand="HUDConsoleUI.toggleBrowserConsole();"/>
<command id="Tools:Scratchpad" oncommand="Scratchpad.openScratchpad();" disabled="true" hidden="true"/>
<command id="Tools:ResponsiveUI" oncommand="ResponsiveUI.toggle();" disabled="true" hidden="true"/>

Просмотреть файл

@ -115,10 +115,10 @@ XPCOMUtils.defineLazyGetter(this, "DeveloperToolbar", function() {
return new tmp.DeveloperToolbar(window, document.getElementById("developer-toolbar"));
});
XPCOMUtils.defineLazyGetter(this, "DebuggerUI", function() {
XPCOMUtils.defineLazyGetter(this, "BrowserDebuggerProcess", function() {
let tmp = {};
Cu.import("resource:///modules/devtools/DebuggerUI.jsm", tmp);
return new tmp.DebuggerUI(window);
Cu.import("resource:///modules/devtools/DebuggerProcess.jsm", tmp);
return tmp.BrowserDebuggerProcess;
});
XPCOMUtils.defineLazyModuleGetter(this, "Social",

Просмотреть файл

@ -45,10 +45,20 @@ function testOnWindow(options) {
win.removeEventListener("load", onLoad, false);
windowsToClose.push(win);
gWindow = win;
executeSoon(TestRunner.next);
whenDelayedStartupFinished(win, TestRunner.next);
}, false);
}
function whenDelayedStartupFinished(win, callback) {
const topic = "browser-delayed-startup-finished";
Services.obs.addObserver(function onStartup(subject) {
if (win == subject) {
Services.obs.removeObserver(onStartup, topic);
executeSoon(callback);
}
}, topic, false);
}
registerCleanupFunction(function () {
gWindow = window;
windowsToClose.forEach(function(win) {

Просмотреть файл

@ -38,7 +38,7 @@ function test() {
/images\/background\.png points to a resource that is not available at line 10\./,
/NETWORK section line 13 \(\/checking\.cgi\) prevents caching of line 13 \(\/checking\.cgi\) in the NETWORK section\./,
/\/checking\.cgi points to a resource that is not available at line 13\./,
/Asterisk \(\*\) incorrectly used in the NETWORK section at line 14\. If a line in the NETWORK section contains only a single asterisk character, then any URI not listed in the manifest will be treated as if the URI was listed in the NETWORK section\. Otherwice such URIs will be treated as unavailable\. Other uses of the \* character are prohibited/,
/Asterisk \(\*\) incorrectly used in the NETWORK section at line 14\. If a line in the NETWORK section contains only a single asterisk character, then any URI not listed in the manifest will be treated as if the URI was listed in the NETWORK section\. Otherwise such URIs will be treated as unavailable\. Other uses of the \* character are prohibited/,
/\.\.\/rel\.html points to a resource that is not available at line 17\./,
/\.\.\/\.\.\/rel\.html points to a resource that is not available at line 18\./,
/\.\.\/\.\.\/\.\.\/rel\.html points to a resource that is not available at line 19\./,
@ -64,7 +64,7 @@ function test() {
/http:\/\/example\.com\/check\.png points to a resource that is not available at line 41\./,
/Spaces in URIs need to be replaced with % at line 42\./,
/http:\/\/example\.com\/cr oss\.png points to a resource that is not available at line 42\./,
/Asterisk \(\*\) incorrectly used in the CACHE section at line 43\. If a line in the NETWORK section contains only a single asterisk character, then any URI not listed in the manifest will be treated as if the URI was listed in the NETWORK section\. Otherwice such URIs will be treated as unavailable\. Other uses of the \* character are prohibited/,
/Asterisk \(\*\) incorrectly used in the CACHE section at line 43\. If a line in the NETWORK section contains only a single asterisk character, then any URI not listed in the manifest will be treated as if the URI was listed in the NETWORK section\. Otherwise such URIs will be treated as unavailable\. Other uses of the \* character are prohibited/,
/The SETTINGS section may only contain a single value, "prefer-online" or "fast" at line 47\./,
/FALLBACK section line 50 \(\/section1\/ \/offline1\.html\) prevents caching of line 30 \(\/section1\/blockedbyfallback\.html\) in the CACHE section\./,
/\/offline1\.html points to a resource that is not available at line 50\./,

Просмотреть файл

@ -34,9 +34,10 @@ XPCOMUtils.defineLazyModuleGetter(this, "console",
*/
function getAllBreakpoints(dbg) {
let breakpoints = [];
let SourceUtils = dbg.panelWin.SourceUtils;
let sources = dbg.panelWin.DebuggerView.Sources;
let { trimUrlLength: tr } = dbg.panelWin.SourceUtils;
for (let source in dbg.panelWin.DebuggerView.Sources) {
for (let source in sources) {
for (let { attachment: breakpoint } in source) {
breakpoints.push({
id: source.value + ":" + breakpoint.lineNumber,
@ -44,8 +45,7 @@ function getAllBreakpoints(dbg) {
url: source.value,
lineNumber: breakpoint.lineNumber,
lineText: breakpoint.lineText,
truncatedLineText: SourceUtils.trimUrlLength(breakpoint.lineText,
MAX_LINE_TEXT_LENGTH, "end")
truncatedLineText: tr(breakpoint.lineText, MAX_LINE_TEXT_LENGTH, "end")
});
}
}
@ -199,11 +199,9 @@ gcli.addCommand({
name: "selection",
lookup: function(context) {
let dbg = getPanel(context, "jsdebugger");
if (dbg == null) {
return [];
}
return getAllBreakpoints(dbg).map(breakpoint => {
return {
name: breakpoint.label,
@ -223,8 +221,8 @@ gcli.addCommand({
return gcli.lookup("debuggerStopped");
}
let breakpoint = dbg.getBreakpoint(args.breakpoint.url,
args.breakpoint.lineNumber);
let breakpoint = dbg.getBreakpoint(
args.breakpoint.url, args.breakpoint.lineNumber);
if (breakpoint == null) {
return gcli.lookup("breakNotFound");

Просмотреть файл

@ -15,9 +15,6 @@ Cu.import("resource:///modules/devtools/shared/event-emitter.js");
XPCOMUtils.defineLazyModuleGetter(this, "Promise",
"resource://gre/modules/commonjs/sdk/core/promise.js");
XPCOMUtils.defineLazyModuleGetter(this, "DebuggerServer",
"resource://gre/modules/devtools/dbg-server.jsm");
this.DebuggerPanel = function DebuggerPanel(iframeWindow, toolbox) {
this.panelWin = iframeWindow;
this._toolbox = toolbox;

Просмотреть файл

@ -0,0 +1,164 @@
/* -*- Mode: javascript; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
/* 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/. */
"use strict";
const { classes: Cc, interfaces: Ci, utils: Cu } = Components;
const DBG_XUL = "chrome://browser/content/devtools/debugger.xul";
const CHROME_DEBUGGER_PROFILE_NAME = "-chrome-debugger";
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/devtools/dbg-server.jsm");
Cu.import("resource:///modules/devtools/ViewHelpers.jsm");
let require = Cu.import("resource://gre/modules/devtools/Loader.jsm", {}).devtools.require;
let Telemetry = require("devtools/shared/telemetry");
this.EXPORTED_SYMBOLS = ["BrowserDebuggerProcess"];
/**
* Constructor for creating a process that will hold a chrome debugger.
*
* @param function aOnClose [optional]
* A function called when the process stops running.
* @param function aOnRun [optional]
* A function called when the process starts running.
*/
this.BrowserDebuggerProcess = function BrowserDebuggerProcess(aOnClose, aOnRun) {
this._closeCallback = aOnClose;
this._runCallback = aOnRun;
this._telemetry = new Telemetry();
this._initServer();
this._initProfile();
this._create();
}
/**
* Initializes and starts a chrome debugger process.
* @return object
*/
BrowserDebuggerProcess.init = function(aOnClose, aOnRun) {
return new BrowserDebuggerProcess(aOnClose, aOnRun);
};
BrowserDebuggerProcess.prototype = {
/**
* Initializes the debugger server.
*/
_initServer: function() {
if (!DebuggerServer.initialized) {
DebuggerServer.init();
DebuggerServer.addBrowserActors();
}
DebuggerServer.openListener(Prefs.chromeDebuggingPort);
},
/**
* Initializes a profile for the remote debugger process.
*/
_initProfile: function() {
let profileService = Cc["@mozilla.org/toolkit/profile-service;1"]
.createInstance(Ci.nsIToolkitProfileService);
let profileName;
try {
// Attempt to get the required chrome debugging profile name string.
profileName = profileService.selectedProfile.name + CHROME_DEBUGGER_PROFILE_NAME;
} catch (e) {
// Requested profile string could not be retrieved.
profileName = CHROME_DEBUGGER_PROFILE_NAME;
let msg = "Querying the current profile failed. " + e.name + ": " + e.message;
dumpn(msg);
Cu.reportError(msg);
}
let profileObject;
try {
// Attempt to get the required chrome debugging profile toolkit object.
profileObject = profileService.getProfileByName(profileName);
// The profile exists but the corresponding folder may have been deleted.
var enumerator = Services.dirsvc.get("ProfD", Ci.nsIFile).parent.directoryEntries;
while (enumerator.hasMoreElements()) {
let profileDir = enumerator.getNext().QueryInterface(Ci.nsIFile);
if (profileDir.leafName.contains(profileName)) {
// Requested profile was found and the folder exists.
this._dbgProfile = profileObject;
return;
}
}
// Requested profile was found but the folder was deleted. Cleanup needed.
profileObject.remove(true);
} catch (e) {
// Requested profile object was not found.
let msg = "Creating a profile failed. " + e.name + ": " + e.message;
dumpn(msg);
Cu.reportError(msg);
}
// Create a new chrome debugging profile.
this._dbgProfile = profileService.createProfile(null, null, profileName);
profileService.flush();
},
/**
* Creates and initializes the profile & process for the remote debugger.
*/
_create: function() {
dumpn("Initializing chrome debugging process.");
let process = this._dbgProcess = Cc["@mozilla.org/process/util;1"].createInstance(Ci.nsIProcess);
process.init(Services.dirsvc.get("XREExeF", Ci.nsIFile));
dumpn("Running chrome debugging process.");
let args = ["-no-remote", "-foreground", "-P", this._dbgProfile.name, "-chrome", DBG_XUL];
process.runwAsync(args, args.length, { observe: () => this.close() });
this._telemetry.toolOpened("jsbrowserdebugger");
dumpn("Chrome debugger is now running...");
if (typeof this._runCallback == "function") {
this._runCallback.call({}, this);
}
},
/**
* Closes the remote debugger, removing the profile and killing the process.
*/
close: function() {
if (this._dbgProcess.isRunning) {
dumpn("Killing chrome debugging process...");
this._dbgProcess.kill();
}
this._telemetry.toolClosed("jsbrowserdebugger");
dumpn("Chrome debugger is now closed...");
if (typeof this._closeCallback == "function") {
this._closeCallback.call({}, this);
}
}
};
/**
* Shortcuts for accessing various debugger preferences.
*/
let Prefs = new ViewHelpers.Prefs("devtools.debugger", {
chromeDebuggingHost: ["Char", "chrome-debugging-host"],
chromeDebuggingPort: ["Int", "chrome-debugging-port"]
});
/**
* Helper method for debugging.
* @param string
*/
function dumpn(str) {
if (wantLogging) {
dump("DBG-FRONTEND: " + str + "\n");
}
}
let wantLogging = Services.prefs.getBoolPref("devtools.debugger.log");

Просмотреть файл

@ -1,564 +0,0 @@
/* -*- Mode: javascript; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
/* 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/. */
"use strict";
const Cc = Components.classes;
const Ci = Components.interfaces;
const Cu = Components.utils;
const DBG_XUL = "chrome://browser/content/devtools/debugger.xul";
const DBG_STRINGS_URI = "chrome://browser/locale/devtools/debugger.properties";
const CHROME_DEBUGGER_PROFILE_NAME = "-chrome-debugger";
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
var require = Cu.import("resource://gre/modules/devtools/Loader.jsm", {}).devtools.require;
let Telemetry = require("devtools/shared/telemetry");
XPCOMUtils.defineLazyModuleGetter(this,
"DebuggerServer", "resource://gre/modules/devtools/dbg-server.jsm");
XPCOMUtils.defineLazyModuleGetter(this,
"Services", "resource://gre/modules/Services.jsm");
this.EXPORTED_SYMBOLS = ["DebuggerUI"];
/**
* Provides a simple mechanism of managing debugger instances.
*
* @param nsIDOMWindow aWindow
* The chrome window for which the DebuggerUI instance is created.
*/
this.DebuggerUI = function DebuggerUI(aWindow) {
this.chromeWindow = aWindow;
this.listenToTabs();
};
DebuggerUI.prototype = {
/**
* Update the status of tool's menuitems and buttons when
* the user switches tabs.
*/
listenToTabs: function() {
let win = this.chromeWindow;
let tabs = win.gBrowser.tabContainer;
let bound_refreshCommand = this.refreshCommand.bind(this);
tabs.addEventListener("TabSelect", bound_refreshCommand, true);
win.addEventListener("unload", function onClose(aEvent) {
win.removeEventListener("unload", onClose, false);
tabs.removeEventListener("TabSelect", bound_refreshCommand, true);
}, false);
},
/**
* Called by the DebuggerPane to update the Debugger toggle switches with the
* debugger state.
*/
refreshCommand: function() {
let scriptDebugger = this.getDebugger();
let command = this.chromeWindow.document.getElementById("Tools:Debugger");
let selectedTab = this.chromeWindow.gBrowser.selectedTab;
if (scriptDebugger && scriptDebugger.ownerTab === selectedTab) {
command.setAttribute("checked", "true");
} else {
command.setAttribute("checked", "false");
}
},
/**
* Starts a debugger for the current tab, or stops it if already started.
*
* @return DebuggerPane | null
* The script debugger instance if it's started, null if stopped.
*/
toggleDebugger: function() {
let scriptDebugger = this.findDebugger();
let selectedTab = this.chromeWindow.gBrowser.selectedTab;
if (scriptDebugger) {
scriptDebugger.close();
return null;
}
return new DebuggerPane(this, selectedTab);
},
/**
* Starts a remote debugger in a new window, or stops it if already started.
*
* @return RemoteDebuggerWindow | null
* The remote debugger instance if it's started, null if stopped.
*/
toggleRemoteDebugger: function() {
let remoteDebugger = this.getRemoteDebugger();
if (remoteDebugger) {
remoteDebugger.close();
return null;
}
return new RemoteDebuggerWindow(this);
},
/**
* Starts a chrome debugger in a new process, or stops it if already started.
*
* @return ChromeDebuggerProcess | null
* The chrome debugger instance if it's started, null if stopped.
*/
toggleChromeDebugger: function(aOnClose, aOnRun) {
let chromeDebugger = this.getChromeDebugger();
if (chromeDebugger) {
chromeDebugger.close();
return null;
}
return new ChromeDebuggerProcess(this, aOnClose, aOnRun);
},
/**
* Gets the current script debugger from any open window.
*
* @return DebuggerPane | null
* The script debugger instance if it exists, null otherwise.
*/
findDebugger: function() {
let enumerator = Services.wm.getEnumerator("navigator:browser");
while (enumerator.hasMoreElements()) {
let chromeWindow = enumerator.getNext().QueryInterface(Ci.nsIDOMWindow);
let scriptDebugger = chromeWindow.DebuggerUI.getDebugger();
if (scriptDebugger) {
return scriptDebugger;
}
}
return null;
},
/**
* Get the current script debugger.
*
* @return DebuggerPane | null
* The script debugger instance if it exists, null otherwise.
*/
getDebugger: function() {
return '_scriptDebugger' in this ? this._scriptDebugger : null;
},
/**
* Get the remote debugger for the current chrome window.
*
* @return RemoteDebuggerWindow | null
* The remote debugger instance if it exists, null otherwise.
*/
getRemoteDebugger: function() {
return '_remoteDebugger' in this ? this._remoteDebugger : null;
},
/**
* Get the chrome debugger for the current firefox instance.
*
* @return ChromeDebuggerProcess | null
* The chrome debugger instance if it exists, null otherwise.
*/
getChromeDebugger: function() {
return '_chromeDebugger' in this ? this._chromeDebugger : null;
}
};
/**
* Creates a pane that will host the debugger.
*
* @param DebuggerUI aDebuggerUI
* The parent instance creating the new debugger.
* @param XULElement aTab
* The tab in which to create the debugger.
*/
this.DebuggerPane = function DebuggerPane(aDebuggerUI, aTab) {
this.globalUI = aDebuggerUI;
this._win = aDebuggerUI.chromeWindow;
this._tab = aTab;
this.close = this.close.bind(this);
this._initServer();
this._create();
}
DebuggerPane.prototype = {
/**
* Initializes the debugger server.
*/
_initServer: function() {
if (!DebuggerServer.initialized) {
DebuggerServer.init();
DebuggerServer.addBrowserActors();
}
},
/**
* Creates and initializes the widgets containing the debugger UI.
*/
_create: function() {
this.globalUI._scriptDebugger = this;
let gBrowser = this._win.gBrowser;
let ownerDocument = gBrowser.parentNode.ownerDocument;
this._splitter = ownerDocument.createElement("splitter");
this._splitter.setAttribute("class", "devtools-horizontal-splitter");
this._frame = ownerDocument.createElement("iframe");
this._nbox = gBrowser.getNotificationBox(this._tab.linkedBrowser);
this._nbox.appendChild(this._splitter);
this._nbox.appendChild(this._frame);
let self = this;
this._frame.addEventListener("Debugger:Loaded", function dbgLoaded() {
self._frame.removeEventListener("Debugger:Loaded", dbgLoaded, true);
self._frame.addEventListener("Debugger:Unloaded", self.close, true);
// Bind shortcuts for accessing the breakpoint methods in the debugger.
let bkp = self.contentWindow.DebuggerController.Breakpoints;
self.addBreakpoint = bkp.addBreakpoint;
self.removeBreakpoint = bkp.removeBreakpoint;
self.getBreakpoint = bkp.getBreakpoint;
self.breakpoints = bkp.store;
}, true);
this._frame.setAttribute("src", DBG_XUL);
this.globalUI.refreshCommand();
},
/**
* Closes the debugger, removing child nodes and event listeners.
*
* @param function aCloseCallback
* Clients can pass a close callback to be notified when
* the panel successfully closes.
*/
close: function(aCloseCallback) {
if (!this.globalUI) {
return;
}
delete this.globalUI._scriptDebugger;
// This method is also used as an event handler, so only
// use aCloseCallback if it's a function.
if (typeof aCloseCallback == "function") {
let frame = this._frame;
frame.addEventListener("unload", function onUnload() {
frame.removeEventListener("unload", onUnload, true);
aCloseCallback();
}, true)
}
this._frame.removeEventListener("Debugger:Unloaded", this.close, true);
this._nbox.removeChild(this._splitter);
this._nbox.removeChild(this._frame);
this._splitter = null;
this._frame = null;
this._nbox = null;
this._win = null;
this._tab = null;
// Remove shortcuts for accessing the breakpoint methods in the debugger.
delete this.addBreakpoint;
delete this.removeBreakpoint;
delete this.getBreakpoint;
delete this.breakpoints;
this.globalUI.refreshCommand();
this.globalUI = null;
},
/**
* Gets the chrome window owning this debugger instance.
* @return XULWindow
*/
get ownerWindow() {
return this._win;
},
/**
* Gets the tab owning this debugger instance.
* @return XULElement
*/
get ownerTab() {
return this._tab;
},
/**
* Gets the debugger content window.
* @return nsIDOMWindow
*/
get contentWindow() {
return this._frame ? this._frame.contentWindow : null;
}
};
/**
* Creates a window that will host a remote debugger.
*
* @param DebuggerUI aDebuggerUI
* The parent instance creating the new debugger.
*/
this.RemoteDebuggerWindow = function RemoteDebuggerWindow(aDebuggerUI) {
this.globalUI = aDebuggerUI;
this._win = aDebuggerUI.chromeWindow;
this.close = this.close.bind(this);
this._create();
}
RemoteDebuggerWindow.prototype = {
/**
* Creates and initializes the widgets containing the remote debugger UI.
*/
_create: function() {
this.globalUI._remoteDebugger = this;
this._dbgwin = this.globalUI.chromeWindow.open(DBG_XUL,
L10N.getStr("remoteDebuggerWindowTitle"), "chrome,dependent,resizable");
let self = this;
this._dbgwin.addEventListener("Debugger:Loaded", function dbgLoaded() {
self._dbgwin.removeEventListener("Debugger:Loaded", dbgLoaded, true);
self._dbgwin.addEventListener("Debugger:Unloaded", self.close, true);
// Bind shortcuts for accessing the breakpoint methods in the debugger.
let bkp = self.contentWindow.DebuggerController.Breakpoints;
self.addBreakpoint = bkp.addBreakpoint;
self.removeBreakpoint = bkp.removeBreakpoint;
self.getBreakpoint = bkp.getBreakpoint;
self.breakpoints = bkp.store;
}, true);
this._dbgwin._remoteFlag = true;
},
/**
* Closes the remote debugger, along with the parent window if necessary.
*/
close: function() {
if (!this.globalUI) {
return;
}
delete this.globalUI._remoteDebugger;
this._dbgwin.removeEventListener("Debugger:Unloaded", this.close, true);
this._dbgwin.close();
this._dbgwin = null;
this._win = null;
// Remove shortcuts for accessing the breakpoint methods in the debugger.
delete this.addBreakpoint;
delete this.removeBreakpoint;
delete this.getBreakpoint;
delete this.breakpoints;
this.globalUI = null;
},
/**
* Gets the chrome window owning this debugger instance.
* @return XULWindow
*/
get ownerWindow() {
return this._win;
},
/**
* Gets the remote debugger content window.
* @return nsIDOMWindow.
*/
get contentWindow() {
return this._dbgwin;
}
};
/**
* Creates a process that will hold a chrome debugger.
*
* @param DebuggerUI aDebuggerUI
* The parent instance creating the new debugger.
* @param function aOnClose
* Optional, a function called when the process exits.
* @param function aOnRun
* Optional, a function called when the process starts running.
*/
this.ChromeDebuggerProcess = function ChromeDebuggerProcess(aDebuggerUI, aOnClose, aOnRun) {
this.globalUI = aDebuggerUI;
this._win = aDebuggerUI.chromeWindow;
this._closeCallback = aOnClose;
this._runCallback = aOnRun;
this._telemetry = new Telemetry();
this._initServer();
this._initProfile();
this._create();
}
ChromeDebuggerProcess.prototype = {
/**
* Initializes the debugger server.
*/
_initServer: function() {
if (!DebuggerServer.initialized) {
DebuggerServer.init();
DebuggerServer.addBrowserActors();
}
DebuggerServer.openListener(Prefs.chromeDebuggingPort);
},
/**
* Initializes a profile for the remote debugger process.
*/
_initProfile: function() {
let profileService = Cc["@mozilla.org/toolkit/profile-service;1"]
.createInstance(Ci.nsIToolkitProfileService);
let profileName;
try {
// Attempt to get the required chrome debugging profile name string.
profileName = profileService.selectedProfile.name + CHROME_DEBUGGER_PROFILE_NAME;
} catch (e) {
// Requested profile string could not be retrieved.
profileName = CHROME_DEBUGGER_PROFILE_NAME;
Cu.reportError(e);
}
let profileObject;
try {
// Attempt to get the required chrome debugging profile toolkit object.
profileObject = profileService.getProfileByName(profileName);
// The profile exists but the corresponding folder may have been deleted.
var enumerator = Services.dirsvc.get("ProfD", Ci.nsIFile).parent.directoryEntries;
while (enumerator.hasMoreElements()) {
let profileDir = enumerator.getNext().QueryInterface(Ci.nsIFile);
if (profileDir.leafName.contains(profileName)) {
// Requested profile was found and the folder exists.
this._dbgProfile = profileObject;
return;
}
}
// Requested profile was found but the folder was deleted. Cleanup needed.
profileObject.remove(true);
} catch (e) {
// Requested profile object was not found.
Cu.reportError(e);
}
// Create a new chrome debugging profile.
this._dbgProfile = profileService.createProfile(null, null, profileName);
profileService.flush();
},
/**
* Creates and initializes the profile & process for the remote debugger.
*/
_create: function() {
this.globalUI._chromeDebugger = this;
let file = Services.dirsvc.get("XREExeF", Ci.nsIFile);
dumpn("Initializing chrome debugging process");
let process = Cc["@mozilla.org/process/util;1"].createInstance(Ci.nsIProcess);
process.init(file);
let args = [
"-no-remote", "-P", this._dbgProfile.name,
"-chrome", DBG_XUL];
dumpn("Running chrome debugging process");
process.runwAsync(args, args.length, { observe: this.close.bind(this) });
this._dbgProcess = process;
this._telemetry.toolOpened("jsbrowserdebugger");
if (typeof this._runCallback == "function") {
this._runCallback.call({}, this);
}
},
/**
* Closes the remote debugger, removing the profile and killing the process.
*/
close: function() {
dumpn("Closing chrome debugging process");
this._telemetry.toolClosed("jsbrowserdebugger");
if (!this.globalUI) {
dumpn("globalUI is missing");
return;
}
delete this.globalUI._chromeDebugger;
if (this._dbgProcess.isRunning) {
dumpn("Killing chrome debugging process...");
this._dbgProcess.kill();
}
dumpn("...done.");
if (typeof this._closeCallback == "function") {
this._closeCallback.call({}, this);
}
this._dbgProcess = null;
this._dbgProfile = null;
this._win = null;
this.globalUI = null;
}
};
/**
* Localization convenience methods.
*/
let L10N = {
/**
* L10N shortcut function.
*
* @param string aName
* @return string
*/
getStr: function(aName) {
return this.stringBundle.GetStringFromName(aName);
}
};
XPCOMUtils.defineLazyGetter(L10N, "stringBundle", function() {
return Services.strings.createBundle(DBG_STRINGS_URI);
});
/**
* Shortcuts for accessing various debugger preferences.
*/
let Prefs = {};
/**
* Gets the preferred default remote browser debugging port.
* @return number
*/
XPCOMUtils.defineLazyGetter(Prefs, "chromeDebuggingPort", function() {
return Services.prefs.getIntPref("devtools.debugger.chrome-debugging-port");
});
/**
* Helper method for debugging.
* @param string
*/
function dumpn(str) {
if (wantLogging) {
dump("DBG-FRONTEND: " + str + "\n");
}
}
let wantLogging = Services.prefs.getBoolPref("devtools.debugger.log");

Просмотреть файл

@ -16,7 +16,6 @@ const CALL_STACK_PAGE_SIZE = 25; // frames
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/devtools/dbg-server.jsm");
Cu.import("resource://gre/modules/devtools/dbg-client.jsm");
Cu.import("resource://gre/modules/commonjs/sdk/core/promise.js");
Cu.import("resource:///modules/source-editor.jsm");
@ -67,31 +66,18 @@ let DebuggerController = {
return this._startup.promise;
}
this._isInitialized = true;
window.removeEventListener("DOMContentLoaded", this.startupDebugger, true);
// Chrome debugging lives in a different process and needs to handle
// debugger startup by itself.
if (window._isChromeDebugger) {
window.removeEventListener("DOMContentLoaded", this.startupDebugger, true);
}
let deferred = this._startup = Promise.defer();
DebuggerView.initialize(() => {
DebuggerView._isInitialized = true;
VariablesViewController.attach(DebuggerView.Variables, {
getGripClient: aObject => {
return this.activeThread.pauseGrip(aObject);
}
});
// Relay events from the VariablesView.
DebuggerView.Variables.on("fetched", (aEvent, aType) => {
switch (aType) {
case "variables":
window.dispatchEvent(document, "Debugger:FetchedVariables");
break;
case "properties":
window.dispatchEvent(document, "Debugger:FetchedProperties");
break;
}
});
// Chrome debugging needs to initiate the connection by itself.
if (window._isChromeDebugger) {
this.connect().then(deferred.resolve);
@ -115,12 +101,18 @@ let DebuggerController = {
}
this._isDestroyed = true;
this._startup = null;
window.removeEventListener("unload", this.shutdownDebugger, true);
// Chrome debugging lives in a different process and needs to handle
// debugger shutdown by itself.
if (window._isChromeDebugger) {
window.removeEventListener("unload", this.shutdownDebugger, true);
}
let deferred = this._shutdown = Promise.defer();
DebuggerView.destroy(() => {
DebuggerView._isDestroyed = true;
this.SourceScripts.disconnect();
this.StackFrames.disconnect();
this.ThreadState.disconnect();
@ -168,9 +160,9 @@ let DebuggerController = {
return deferred.promise;
}
// Chrome debugging needs to make the connection to the debuggee.
let transport = debuggerSocketConnect(Prefs.chromeDebuggingHost,
Prefs.chromeDebuggingPort);
// Chrome debugging needs to make its own connection to the debuggee.
let transport = debuggerSocketConnect(
Prefs.chromeDebuggingHost, Prefs.chromeDebuggingPort);
let client = new DebuggerClient(transport);
client.addListener("tabNavigated", this._onTabNavigated);
@ -195,7 +187,8 @@ let DebuggerController = {
}
// When debugging local or a remote instance, the connection is closed by
// the RemoteTarget.
// the RemoteTarget. Chrome debugging needs to specifically close its own
// connection to the debuggee.
if (window._isChromeDebugger) {
this.client.removeListener("tabNavigated", this._onTabNavigated);
this.client.removeListener("tabDetached", this._onTabDetached);
@ -238,6 +231,15 @@ let DebuggerController = {
this.shutdownDebugger();
},
/**
* Warn if resuming execution produced a wrongOrder error.
*/
_ensureResumptionOrder: function(aResponse) {
if (aResponse.error == "wrongOrder") {
DebuggerView.Toolbar.showResumeWarning(aResponse.lastPausedUrl);
}
},
/**
* Sets up a debugging session.
*
@ -273,15 +275,6 @@ let DebuggerController = {
}, { useSourceMaps: Prefs.sourceMapsEnabled });
},
/**
* Warn if resuming execution produced a wrongOrder error.
*/
_ensureResumptionOrder: function(aResponse) {
if (aResponse.error == "wrongOrder") {
DebuggerView.Toolbar.showResumeWarning(aResponse.lastPausedUrl);
}
},
/**
* Sets up a chrome debugging session.
*
@ -330,10 +323,9 @@ let DebuggerController = {
return;
}
// Update the source list widget.
DebuggerView.Sources.empty();
SourceUtils.clearCache();
DebuggerView._handleTabNavigation();
this.SourceScripts._handleTabNavigation();
// Update the stack frame list.
this.activeThread._clearFrames();
this.activeThread.fillFrames(CALL_STACK_PAGE_SIZE);
@ -416,13 +408,12 @@ ThreadState.prototype = {
_update: function(aEvent) {
DebuggerView.Toolbar.toggleResumeButtonState(this.activeThread.state);
if (DebuggerController._target && (aEvent == "paused" || aEvent == "resumed")) {
DebuggerController._target.emit("thread-" + aEvent);
if (gTarget && (aEvent == "paused" || aEvent == "resumed")) {
gTarget.emit("thread-" + aEvent);
}
}
};
/**
* Keeps the stack frame list up-to-date, using the thread client's
* stack frame cache.
@ -544,6 +535,7 @@ StackFrames.prototype = {
// Conditional breakpoints are { breakpoint, expression } tuples. The
// boolean evaluation of the expression decides if the active thread
// automatically resumes execution or not.
// TODO: handle all of this server-side: Bug 812172.
if (this.currentBreakpointLocation) {
let { url, line } = this.currentBreakpointLocation;
let breakpointClient = DebuggerController.Breakpoints.getBreakpoint(url, line);
@ -574,9 +566,10 @@ StackFrames.prototype = {
// Watch expressions are evaluated in the context of the topmost frame,
// and the results are displayed in the variables view.
// TODO: handle all of this server-side: Bug 832470, comment 14.
if (this.currentWatchExpressions) {
// Evaluation causes the stack frames to be cleared and active thread to
// pause, sending a 'clientEvaluated' packed and adding the frames again.
// pause, sending a 'clientEvaluated' packet and adding the frames again.
this.evaluate(this.currentWatchExpressions, 0);
this._isWatchExpressionsEvaluation = true;
return;
@ -585,16 +578,13 @@ StackFrames.prototype = {
if (this._isWatchExpressionsEvaluation) {
this._isWatchExpressionsEvaluation = false;
// If an error was thrown during the evaluation of the watch expressions,
// then at least one expression evaluation could not be performed.
// then at least one expression evaluation could not be performed. So
// remove the most recent watch expression and try again.
if (this.currentEvaluation.throw) {
DebuggerView.WatchExpressions.removeExpressionAt(0);
DebuggerView.WatchExpressions.removeAt(0);
DebuggerController.StackFrames.syncWatchExpressions();
return;
}
// If the watch expressions were evaluated successfully, attach
// the results to the topmost frame.
let topmostFrame = this.activeThread.cachedFrames[0];
topmostFrame.watchExpressionsEvaluation = this.currentEvaluation.return;
}
@ -605,8 +595,7 @@ StackFrames.prototype = {
DebuggerView.StackFrames.empty();
for (let frame of this.activeThread.cachedFrames) {
let depth = frame.depth;
let { url, line } = frame.where;
let { depth, where: { url, line } } = frame;
let frameLocation = NetworkHelper.convertToUnicode(unescape(url));
let frameTitle = StackFrameUtils.getFrameTitle(frame);
@ -660,14 +649,14 @@ StackFrames.prototype = {
* The depth of the frame in the stack.
*/
selectFrame: function(aDepth) {
// Make sure the frame at the specified depth exists first.
let frame = this.activeThread.cachedFrames[this.currentFrame = aDepth];
if (!frame) {
return;
}
let { environment, watchExpressionsEvaluation } = frame;
let { url, line } = frame.where;
// Check if the frame does not represent the evaluation of debuggee code.
let { environment, where: { url, line } } = frame;
if (!environment) {
return;
}
@ -686,7 +675,7 @@ StackFrames.prototype = {
// If watch expressions evaluation results are available, create a scope
// to contain all the values.
if (this.syncedWatchExpressions && watchExpressionsEvaluation) {
if (this.syncedWatchExpressions && aDepth == 0) {
let label = L10N.getStr("watchExpressionsScopeLabel");
let scope = DebuggerView.Variables.addScope(label);
@ -697,14 +686,16 @@ StackFrames.prototype = {
scope.switch = DebuggerView.WatchExpressions.switchExpression;
scope.delete = DebuggerView.WatchExpressions.deleteExpression;
// The evaluation hasn't thrown, so display the returned results and
// always expand the watch expressions scope by default.
this._fetchWatchExpressions(scope, watchExpressionsEvaluation);
// The evaluation hasn't thrown, so fetch and add the returned results.
this._fetchWatchExpressions(scope, this.currentEvaluation.return);
// The watch expressions scope is always automatically expanded.
scope.expand();
}
do {
// Create a scope to contain all the inspected variables.
// Create a scope to contain all the inspected variables in the
// current environment.
let label = StackFrameUtils.getScopeLabel(environment);
let scope = DebuggerView.Variables.addScope(label);
let innermost = environment == frame.environment;
@ -714,6 +705,8 @@ StackFrames.prototype = {
this._insertScopeFrameReferences(scope, frame);
}
// Handle the expansion of the scope, lazily populating it with the
// variables in the current environment.
DebuggerView.Variables.controller.addExpander(scope, environment);
// The innermost scope is always automatically expanded, because it
@ -730,42 +723,25 @@ StackFrames.prototype = {
},
/**
* Adds the watch expressions evaluation results to a scope in the view.
*
* @param Scope aScope
* The scope where the watch expressions will be placed into.
* @param object aExp
* The grip of the evaluation results.
* Loads more stack frames from the debugger server cache.
*/
_fetchWatchExpressions: function(aScope, aExp) {
// Fetch the expressions only once.
if (aScope._fetched) {
return;
}
aScope._fetched = true;
addMoreFrames: function() {
this.activeThread.fillFrames(
this.activeThread.cachedFrames.length + CALL_STACK_PAGE_SIZE);
},
// Add nodes for every watch expression in scope.
this.activeThread.pauseGrip(aExp).getPrototypeAndProperties((aResponse) => {
let ownProperties = aResponse.ownProperties;
let totalExpressions = DebuggerView.WatchExpressions.itemCount;
for (let i = 0; i < totalExpressions; i++) {
let name = DebuggerView.WatchExpressions.getExpression(i);
let expVal = ownProperties[i].value;
let expRef = aScope.addItem(name, ownProperties[i]);
DebuggerView.Variables.controller.addExpander(expRef, expVal);
// Revert some of the custom watch expressions scope presentation flags.
expRef.switch = null;
expRef.delete = null;
expRef.descriptorTooltip = true;
expRef.separatorStr = L10N.getStr("variablesSeparatorLabel");
}
// Signal that watch expressions have been fetched.
window.dispatchEvent(document, "Debugger:FetchedWatchExpressions");
DebuggerView.Variables.commitHierarchy();
});
/**
* Evaluate an expression in the context of the selected frame. This is used
* for modifying the value of variables or properties in scope.
*
* @param string aExpression
* The expression to evaluate.
* @param number aFrame [optional]
* The frame depth used for evaluation.
*/
evaluate: function(aExpression, aFrame = this.currentFrame || 0) {
let frame = this.activeThread.cachedFrames[aFrame];
this.activeThread.eval(frame.actor, aExpression);
},
/**
@ -795,18 +771,51 @@ StackFrames.prototype = {
},
/**
* Loads more stack frames from the debugger server cache.
* Adds the watch expressions evaluation results to a scope in the view.
*
* @param Scope aScope
* The scope where the watch expressions will be placed into.
* @param object aExp
* The grip of the evaluation results.
*/
addMoreFrames: function() {
this.activeThread.fillFrames(
this.activeThread.cachedFrames.length + CALL_STACK_PAGE_SIZE);
_fetchWatchExpressions: function(aScope, aExp) {
// Fetch the expressions only once.
if (aScope._fetched) {
return;
}
aScope._fetched = true;
// Add nodes for every watch expression in scope.
this.activeThread.pauseGrip(aExp).getPrototypeAndProperties((aResponse) => {
let ownProperties = aResponse.ownProperties;
let totalExpressions = DebuggerView.WatchExpressions.itemCount;
for (let i = 0; i < totalExpressions; i++) {
let name = DebuggerView.WatchExpressions.getString(i);
let expVal = ownProperties[i].value;
let expRef = aScope.addItem(name, ownProperties[i]);
DebuggerView.Variables.controller.addExpander(expRef, expVal);
// Revert some of the custom watch expressions scope presentation flags,
// so that they don't propagate to child items.
expRef.switch = null;
expRef.delete = null;
expRef.descriptorTooltip = true;
expRef.separatorStr = L10N.getStr("variablesSeparatorLabel");
}
// Signal that watch expressions have been fetched.
window.dispatchEvent(document, "Debugger:FetchedWatchExpressions");
DebuggerView.Variables.commitHierarchy();
});
},
/**
* Updates a list of watch expressions to evaluate on each pause.
* TODO: handle all of this server-side: Bug 832470, comment 14.
*/
syncWatchExpressions: function() {
let list = DebuggerView.WatchExpressions.getExpressions();
let list = DebuggerView.WatchExpressions.getAllStrings();
// Sanity check all watch expressions before syncing them. To avoid
// having the whole watch expressions array throw because of a single
@ -834,7 +843,7 @@ StackFrames.prototype = {
// breaking the code integrity inside the eval block.
str.replace(/"/g, "\\$&") + "\" + " + "'\\n'" + " + \"" +
"} catch (e) {" +
"e.name + ': ' + e.message;" + // FIXME: bug 812765, 812764
"e.name + ': ' + e.message;" + // TODO: Bug 812765, 812764.
"}" +
"\")"
).join(",") +
@ -845,20 +854,6 @@ StackFrames.prototype = {
}
this.currentFrame = null;
this._onFrames();
},
/**
* Evaluate an expression in the context of the selected frame. This is used
* for modifying the value of variables or properties in scope.
*
* @param string aExpression
* The expression to evaluate.
* @param number aFrame [optional]
* The frame depth used for evaluation.
*/
evaluate: function(aExpression, aFrame = this.currentFrame || 0) {
let frame = this.activeThread.cachedFrames[aFrame];
this.activeThread.eval(frame.actor, aExpression);
}
};
@ -868,8 +863,8 @@ StackFrames.prototype = {
*/
function SourceScripts() {
this._cache = new Map(); // Can't use a WeakMap because keys are strings.
this._onNewSource = this._onNewSource.bind(this);
this._onNewGlobal = this._onNewGlobal.bind(this);
this._onNewSource = this._onNewSource.bind(this);
this._onSourcesAdded = this._onSourcesAdded.bind(this);
this._onFetch = this._onFetch.bind(this);
this._onTimeout = this._onTimeout.bind(this);
@ -972,7 +967,7 @@ SourceScripts.prototype = {
*/
_onSourcesAdded: function(aResponse) {
if (aResponse.error) {
Cu.reportError(new Error("Error getting sources: " + aResponse.message));
Cu.reportError("Error getting sources: " + aResponse.message);
return;
}
@ -1285,7 +1280,8 @@ Breakpoints.prototype = {
/**
* Update the breakpoints in the editor view. This function takes the list of
* breakpoints in the debugger and adds them back into the editor view.
* This is invoked when the selected script is changed.
* This is invoked when the selected script is changed, or when new sources
* are received via the _onNewSource and _onSourcesAdded event listeners.
*/
updateEditorBreakpoints: function() {
for each (let breakpointClient in this.store) {
@ -1301,7 +1297,8 @@ Breakpoints.prototype = {
/**
* Update the breakpoints in the pane view. This function takes the list of
* breakpoints in the debugger and adds them back into the breakpoints pane.
* This is invoked when scripts are added.
* This is invoked when new sources are received via the _onNewSource and
* _onSourcesAdded event listeners.
*/
updatePaneBreakpoints: function() {
for each (let breakpointClient in this.store) {
@ -1336,6 +1333,11 @@ Breakpoints.prototype = {
* - noPaneHighlight: tells if you don't want to highlight the breakpoint
*/
addBreakpoint: function(aLocation, aCallback, aFlags = {}) {
// Make sure a proper location is available.
if (!aLocation) {
aCallback && aCallback(null, new Error("Invalid breakpoint location."));
return;
}
let breakpointClient = this.getBreakpoint(aLocation.url, aLocation.line);
// If the breakpoint was already added, callback immediately.
@ -1375,9 +1377,10 @@ Breakpoints.prototype = {
// Attach any specified conditional expression to the breakpoint client.
aBreakpointClient.conditionalExpression = aFlags.conditionalExpression;
// Preserve information about the breakpoint's line text, to display it in
// the sources pane without requiring fetching the source.
aBreakpointClient.lineText = DebuggerView.getEditorLine(line - 1).trim();
// Preserve information about the breakpoint's line text, to display it
// in the sources pane without requiring fetching the source (for example,
// after the target navigated).
aBreakpointClient.lineText = DebuggerView.getEditorLineText(line - 1).trim();
// Show the breakpoint in the editor and breakpoints pane.
this._showBreakpoint(aBreakpointClient, aFlags);
@ -1400,7 +1403,12 @@ Breakpoints.prototype = {
* @see DebuggerController.Breakpoints.addBreakpoint
*/
removeBreakpoint: function(aBreakpointClient, aCallback, aFlags = {}) {
let breakpointActor = (aBreakpointClient || {}).actor;
// Make sure a proper breakpoint client is available.
if (!aBreakpointClient) {
aCallback && aCallback(null, new Error("Invalid breakpoint client."));
return;
}
let breakpointActor = aBreakpointClient.actor;
// If the breakpoint was already removed, callback immediately.
if (!this.store[breakpointActor]) {
@ -1454,6 +1462,9 @@ Breakpoints.prototype = {
if (!aFlags.noPaneHighlight) {
DebuggerView.Sources.highlightBreakpoint(url, line, aFlags);
}
// Notify that we've shown a breakpoint.
window.dispatchEvent(document, "Debugger:BreakpointShown", aBreakpointClient);
},
/**
@ -1480,17 +1491,20 @@ Breakpoints.prototype = {
if (!aFlags.noPaneUpdate) {
DebuggerView.Sources.removeBreakpoint(url, line);
}
// Notify that we've hidden a breakpoint.
window.dispatchEvent(document, "Debugger:BreakpointHidden", aBreakpointClient);
},
/**
* Get the breakpoint object at the given location.
* Get the BreakpointActor client object at the given location.
*
* @param string aUrl
* The URL of where the breakpoint is.
* @param number aLine
* The line number where the breakpoint is.
* @return object
* The BreakpointActor object.
* The BreakpointActor client object.
*/
getBreakpoint: function(aUrl, aLine) {
for each (let breakpointClient in this.store) {
@ -1514,33 +1528,14 @@ let L10N = new ViewHelpers.L10N(DBG_STRINGS_URI);
let Prefs = new ViewHelpers.Prefs("devtools.debugger", {
chromeDebuggingHost: ["Char", "chrome-debugging-host"],
chromeDebuggingPort: ["Int", "chrome-debugging-port"],
windowX: ["Int", "ui.win-x"],
windowY: ["Int", "ui.win-y"],
windowWidth: ["Int", "ui.win-width"],
windowHeight: ["Int", "ui.win-height"],
sourcesWidth: ["Int", "ui.panes-sources-width"],
instrumentsWidth: ["Int", "ui.panes-instruments-width"],
pauseOnExceptions: ["Bool", "ui.pause-on-exceptions"],
panesVisibleOnStartup: ["Bool", "ui.panes-visible-on-startup"],
variablesSortingEnabled: ["Bool", "ui.variables-sorting-enabled"],
variablesOnlyEnumVisible: ["Bool", "ui.variables-only-enum-visible"],
variablesSearchboxVisible: ["Bool", "ui.variables-searchbox-visible"],
sourceMapsEnabled: ["Bool", "source-maps-enabled"],
remoteHost: ["Char", "remote-host"],
remotePort: ["Int", "remote-port"],
remoteAutoConnect: ["Bool", "remote-autoconnect"],
remoteConnectionRetries: ["Int", "remote-connection-retries"],
remoteTimeout: ["Int", "remote-timeout"]
});
/**
* Returns true if this is a remote debugger instance.
* @return boolean
*/
XPCOMUtils.defineLazyGetter(window, "_isRemoteDebugger", function() {
// We're inside a single top level XUL window, not an iframe container.
return !(window.frameElement instanceof XULElement) &&
!!window._remoteFlag;
pauseOnExceptions: ["Bool", "pause-on-exceptions"],
sourceMapsEnabled: ["Bool", "source-maps-enabled"]
});
/**
@ -1548,9 +1543,8 @@ XPCOMUtils.defineLazyGetter(window, "_isRemoteDebugger", function() {
* @return boolean
*/
XPCOMUtils.defineLazyGetter(window, "_isChromeDebugger", function() {
// We're inside a single top level XUL window, but not a remote debugger.
return !(window.frameElement instanceof XULElement) &&
!window._remoteFlag;
// We're inside a single top level XUL window in a different process.
return !(window.frameElement instanceof XULElement);
});
/**
@ -1567,15 +1561,15 @@ DebuggerController.Breakpoints = new Breakpoints();
* Export some properties to the global scope for easier access.
*/
Object.defineProperties(window, {
"create": {
get: function() ViewHelpers.create,
},
"dispatchEvent": {
get: function() ViewHelpers.dispatchEvent,
},
"editor": {
get: function() DebuggerView.editor
},
"gTarget": {
get: function() DebuggerController._target
},
"gClient": {
get: function() DebuggerController.client
},

Просмотреть файл

@ -11,14 +11,13 @@
function SourcesView() {
dumpn("SourcesView was instantiated");
this._breakpointsCache = new Map(); // Can't use a WeakMap because keys are strings.
this._onBreakpointRemoved = this._onBreakpointRemoved.bind(this);
this._onEditorLoad = this._onEditorLoad.bind(this);
this._onEditorUnload = this._onEditorUnload.bind(this);
this._onEditorSelection = this._onEditorSelection.bind(this);
this._onEditorContextMenu = this._onEditorContextMenu.bind(this);
this._onSourceSelect = this._onSourceSelect.bind(this);
this._onSourceClick = this._onSourceClick.bind(this);
this._onBreakpointRemoved = this._onBreakpointRemoved.bind(this);
this._onBreakpointClick = this._onBreakpointClick.bind(this);
this._onBreakpointCheckboxClick = this._onBreakpointCheckboxClick.bind(this);
this._onConditionalPopupShowing = this._onConditionalPopupShowing.bind(this);
@ -28,14 +27,14 @@ function SourcesView() {
this._onConditionalTextboxKeyPress = this._onConditionalTextboxKeyPress.bind(this);
}
create({ constructor: SourcesView, proto: MenuContainer.prototype }, {
SourcesView.prototype = Heritage.extend(WidgetMethods, {
/**
* Initialization function, called when the debugger is started.
*/
initialize: function() {
dumpn("Initializing the SourcesView");
this.node = new SideMenuWidget(document.getElementById("sources"));
this.widget = new SideMenuWidget(document.getElementById("sources"));
this.emptyText = L10N.getStr("noSourcesText");
this.unavailableText = L10N.getStr("noMatchingSourcesText");
@ -47,8 +46,8 @@ create({ constructor: SourcesView, proto: MenuContainer.prototype }, {
window.addEventListener("Debugger:EditorLoaded", this._onEditorLoad, false);
window.addEventListener("Debugger:EditorUnloaded", this._onEditorUnload, false);
this.node.addEventListener("select", this._onSourceSelect, false);
this.node.addEventListener("click", this._onSourceClick, false);
this.widget.addEventListener("select", this._onSourceSelect, false);
this.widget.addEventListener("click", this._onSourceClick, false);
this._cbPanel.addEventListener("popupshowing", this._onConditionalPopupShowing, false);
this._cbPanel.addEventListener("popupshown", this._onConditionalPopupShown, false);
this._cbPanel.addEventListener("popuphiding", this._onConditionalPopupHiding, false);
@ -69,8 +68,8 @@ create({ constructor: SourcesView, proto: MenuContainer.prototype }, {
window.removeEventListener("Debugger:EditorLoaded", this._onEditorLoad, false);
window.removeEventListener("Debugger:EditorUnloaded", this._onEditorUnload, false);
this.node.removeEventListener("select", this._onSourceSelect, false);
this.node.removeEventListener("click", this._onSourceClick, false);
this.widget.removeEventListener("select", this._onSourceSelect, false);
this.widget.removeEventListener("click", this._onSourceClick, false);
this._cbPanel.removeEventListener("popupshowing", this._onConditionalPopupShowing, false);
this._cbPanel.removeEventListener("popupshowing", this._onConditionalPopupShown, false);
this._cbPanel.removeEventListener("popuphiding", this._onConditionalPopupHiding, false);
@ -107,7 +106,7 @@ create({ constructor: SourcesView, proto: MenuContainer.prototype }, {
let group = SourceUtils.getSourceGroup(url.split(" -> ").pop());
// Append a source item to this container.
let sourceItem = this.push([label, url, group], {
this.push([label, url, group], {
staged: aOptions.staged, /* stage the item to be appended later? */
attachment: {
source: aSource
@ -150,9 +149,9 @@ create({ constructor: SourcesView, proto: MenuContainer.prototype }, {
// Append a breakpoint child item to the corresponding source item.
let breakpointItem = sourceItem.append(breakpointView.container, {
attachment: Object.create(aOptions, {
view: { value: breakpointView },
popup: { value: contextMenu }
attachment: Heritage.extend(aOptions, {
view: breakpointView,
popup: contextMenu
}),
attributes: [
["contextmenu", contextMenu.menupopupId]
@ -162,8 +161,6 @@ create({ constructor: SourcesView, proto: MenuContainer.prototype }, {
finalize: this._onBreakpointRemoved
});
this._breakpointsCache.set(this._getBreakpointKey(url, line), breakpointItem);
// If this is a conditional breakpoint, display a panel to input the
// corresponding conditional expression.
if (aOptions.openPopupFlag) {
@ -205,12 +202,13 @@ create({ constructor: SourcesView, proto: MenuContainer.prototype }, {
* The breakpoint source location.
* @param number aLineNumber
* The breakpoint line number.
* @return MenuItem
* @return object
* The corresponding breakpoint item if found, null otherwise.
*/
getBreakpoint: function(aSourceLocation, aLineNumber) {
let breakpointKey = this._getBreakpointKey(aSourceLocation, aLineNumber);
return this._breakpointsCache.get(breakpointKey);
return this.getItemForPredicate((aItem) =>
aItem.attachment.sourceLocation == aSourceLocation &&
aItem.attachment.lineNumber == aLineNumber);
},
/**
@ -240,7 +238,6 @@ create({ constructor: SourcesView, proto: MenuContainer.prototype }, {
if (aOptions.id) {
breakpointItem.attachment.view.container.id = "breakpoint-" + aOptions.id;
}
// Update the checkbox state if necessary.
if (!aOptions.silent) {
breakpointItem.attachment.view.checkbox.setAttribute("checked", "true");
@ -248,11 +245,15 @@ create({ constructor: SourcesView, proto: MenuContainer.prototype }, {
let { sourceLocation: url, lineNumber: line } = breakpointItem.attachment;
let breakpointLocation = { url: url, line: line };
DebuggerController.Breakpoints.addBreakpoint(breakpointLocation, aOptions.callback, {
noPaneUpdate: true,
noPaneHighlight: true,
conditionalExpression: breakpointItem.attachment.conditionalExpression
});
// Only create a new breakpoint if it doesn't exist yet.
if (!DebuggerController.Breakpoints.getBreakpoint(url, line)) {
DebuggerController.Breakpoints.addBreakpoint(breakpointLocation, aOptions.callback, {
noPaneUpdate: true,
noPaneHighlight: true,
conditionalExpression: breakpointItem.attachment.conditionalExpression
});
}
// Breakpoint is now enabled.
breakpointItem.attachment.disabled = false;
@ -288,12 +289,16 @@ create({ constructor: SourcesView, proto: MenuContainer.prototype }, {
let { sourceLocation: url, lineNumber: line } = breakpointItem.attachment;
let breakpointClient = DebuggerController.Breakpoints.getBreakpoint(url, line);
DebuggerController.Breakpoints.removeBreakpoint(breakpointClient, aOptions.callback, {
noPaneUpdate: true
});
// Remember the conditional expression for when the breakpoint is enabled.
breakpointItem.attachment.conditionalExpression = breakpointClient.conditionalExpression;
// Only remove the breakpoint if it exists.
if (breakpointClient) {
DebuggerController.Breakpoints.removeBreakpoint(breakpointClient, aOptions.callback, {
noPaneUpdate: true
});
// Remember the current conditional expression, to be reapplied when the
// breakpoint is re-enabled via enableBreakpoint().
breakpointItem.attachment.conditionalExpression = breakpointClient.conditionalExpression;
}
// Breakpoint is now disabled.
breakpointItem.attachment.disabled = true;
@ -347,13 +352,13 @@ create({ constructor: SourcesView, proto: MenuContainer.prototype }, {
* Gets the currently selected breakpoint item.
* @return object
*/
get selectedBreakpoint() this._selectedBreakpoint,
get selectedBreakpointItem() this._selectedBreakpoint,
/**
* Gets the currently selected breakpoint client.
* @return object
*/
get selectedClient() {
get selectedBreakpointClient() {
let breakpointItem = this._selectedBreakpoint;
if (breakpointItem) {
let { sourceLocation: url, lineNumber: line } = breakpointItem.attachment;
@ -365,7 +370,7 @@ create({ constructor: SourcesView, proto: MenuContainer.prototype }, {
/**
* Marks a breakpoint as selected in this sources container.
*
* @param MenuItem aItem
* @param object aItem
* The breakpoint item to select.
*/
_selectBreakpoint: function(aItem) {
@ -374,10 +379,10 @@ create({ constructor: SourcesView, proto: MenuContainer.prototype }, {
}
this._unselectBreakpoint();
this._selectedBreakpoint = aItem;
this._selectedBreakpoint.markSelected();
this._selectedBreakpoint.target.classList.add("selected");
// Ensure the currently selected breakpoint is visible.
this.node.ensureElementIsVisible(aItem.target);
this.widget.ensureElementIsVisible(aItem.target);
},
/**
@ -385,7 +390,7 @@ create({ constructor: SourcesView, proto: MenuContainer.prototype }, {
*/
_unselectBreakpoint: function() {
if (this._selectedBreakpoint) {
this._selectedBreakpoint.markDeselected();
this._selectedBreakpoint.target.classList.remove("selected");
this._selectedBreakpoint = null;
}
},
@ -394,17 +399,17 @@ create({ constructor: SourcesView, proto: MenuContainer.prototype }, {
* Opens a conditional breakpoint's expression input popup.
*/
_openConditionalPopup: function() {
let selectedBreakpoint = this.selectedBreakpoint;
let selectedClient = this.selectedClient;
let selectedBreakpointItem = this.selectedBreakpointItem;
let selectedBreakpointClient = this.selectedBreakpointClient;
if (selectedClient.conditionalExpression === undefined) {
this._cbTextbox.value = selectedClient.conditionalExpression = "";
if (selectedBreakpointClient.conditionalExpression === undefined) {
this._cbTextbox.value = selectedBreakpointClient.conditionalExpression = "";
} else {
this._cbTextbox.value = selectedClient.conditionalExpression;
this._cbTextbox.value = selectedBreakpointClient.conditionalExpression;
}
this._cbPanel.hidden = false;
this._cbPanel.openPopup(this.selectedBreakpoint.attachment.view.lineNumber,
this._cbPanel.openPopup(selectedBreakpointItem.attachment.view.lineNumber,
BREAKPOINT_CONDITIONAL_POPUP_POSITION,
BREAKPOINT_CONDITIONAL_POPUP_OFFSET_X,
BREAKPOINT_CONDITIONAL_POPUP_OFFSET_Y);
@ -530,16 +535,15 @@ create({ constructor: SourcesView, proto: MenuContainer.prototype }, {
let menuitemId = prefix + aName + "-" + aOptions.actor + "-menuitem";
let label = L10N.getStr("breakpointMenuItem." + aName);
let func = this["_on" + aName.charAt(0).toUpperCase() + aName.slice(1)];
let func = "_on" + aName.charAt(0).toUpperCase() + aName.slice(1);
command.id = commandId;
command.setAttribute("label", label);
command.addEventListener("command", func.bind(this, aOptions), false);
command.addEventListener("command", () => this[func](aOptions.actor), false);
menuitem.id = menuitemId;
menuitem.setAttribute("command", commandId);
menuitem.setAttribute("command", commandId);
menuitem.setAttribute("hidden", aHiddenFlag);
aHiddenFlag && menuitem.setAttribute("hidden", "true");
commandset.appendChild(command);
menupopup.appendChild(menuitem);
@ -555,34 +559,19 @@ create({ constructor: SourcesView, proto: MenuContainer.prototype }, {
}
},
/**
* Destroys the context menu for a breakpoint.
*
* @param object aContextMenu
* An object containing the breakpoint commandset and menu popup ids.
*/
_destroyContextMenu: function(aContextMenu) {
dumpn("Destroying context menu: " +
aContextMenu.commandsetId + " & " + aContextMenu.menupopupId);
let commandset = document.getElementById(aContextMenu.commandsetId);
let menupopup = document.getElementById(aContextMenu.menupopupId);
commandset.parentNode.removeChild(commandset);
menupopup.parentNode.removeChild(menupopup);
},
/**
* Function called each time a breakpoint item is removed.
*
* @param MenuItem aItem
* The corresponding menu item.
* @param object aItem
* The corresponding item.
*/
_onBreakpointRemoved: function(aItem) {
dumpn("Finalizing breakpoint item: " + aItem);
let { sourceLocation: url, lineNumber: line, popup } = aItem.attachment;
this._destroyContextMenu(popup);
this._breakpointsCache.delete(this._getBreakpointKey(url, line));
// Destroy the context menu for the breakpoint.
let contextMenu = aItem.attachment.popup;
document.getElementById(contextMenu.commandsetId).remove();
document.getElementById(contextMenu.menupopupId).remove();
},
/**
@ -630,12 +619,13 @@ create({ constructor: SourcesView, proto: MenuContainer.prototype }, {
/**
* The select listener for the sources container.
*/
_onSourceSelect: function() {
if (!this.refresh()) {
_onSourceSelect: function({ detail: sourceItem }) {
if (!sourceItem) {
return;
}
// The container is not empty and an actual item was selected.
let selectedSource = sourceItem.attachment.source;
let selectedSource = this.selectedItem.attachment.source;
if (DebuggerView.editorSource != selectedSource) {
DebuggerView.editorSource = selectedSource;
}
@ -656,6 +646,7 @@ create({ constructor: SourcesView, proto: MenuContainer.prototype }, {
let sourceItem = this.getItemForElement(e.target);
let breakpointItem = this.getItemForElement.call(sourceItem, e.target);
let { sourceLocation: url, lineNumber: line } = breakpointItem.attachment;
let breakpointClient = DebuggerController.Breakpoints.getBreakpoint(url, line);
let conditionalExpression = (breakpointClient || {}).conditionalExpression;
@ -677,7 +668,7 @@ create({ constructor: SourcesView, proto: MenuContainer.prototype }, {
silent: true
});
// Don't update the editor location (propagate into DVS__onBreakpointClick).
// Don't update the editor location (avoid propagating into _onBreakpointClick).
e.preventDefault();
e.stopPropagation();
},
@ -708,7 +699,7 @@ create({ constructor: SourcesView, proto: MenuContainer.prototype }, {
* The input listener for the breakpoints conditional expression textbox.
*/
_onConditionalTextboxInput: function() {
this.selectedClient.conditionalExpression = this._cbTextbox.value;
this.selectedBreakpointClient.conditionalExpression = this._cbTextbox.value;
},
/**
@ -779,157 +770,233 @@ create({ constructor: SourcesView, proto: MenuContainer.prototype }, {
},
/**
* Listener handling the "setConditional" menuitem command.
* Function invoked on the "setConditional" menuitem command.
*
* @param object aDetails
* The breakpoint details (sourceLocation, lineNumber etc.).
* @param string aId
* The original breakpoint client actor. If a breakpoint was disabled
* and then re-enabled, then this will not correspond to the entry in
* the controller's breakpoints store.
* @param function aCallback [optional]
* A function to invoke once this operation finishes.
*/
_onSetConditional: function(aDetails) {
let { sourceLocation: url, lineNumber: line, actor } = aDetails;
let breakpointItem = this.getBreakpoint(url, line);
_onSetConditional: function(aId, aCallback = () => {}) {
let targetBreakpoint = this.getItemForPredicate(aItem => aItem.attachment.actor == aId);
let { sourceLocation: url, lineNumber: line } = targetBreakpoint.attachment;
// Highlight the breakpoint and show a conditional expression popup.
this.highlightBreakpoint(url, line, { openPopup: true });
// Breakpoint is now highlighted.
aCallback();
},
/**
* Listener handling the "enableSelf" menuitem command.
* Function invoked on the "enableSelf" menuitem command.
*
* @param object aDetails
* The breakpoint details (sourceLocation, lineNumber etc.).
* @param string aId
* The original breakpoint client actor. If a breakpoint was disabled
* and then re-enabled, then this will not correspond to the entry in
* the controller's breakpoints store.
* @param function aCallback [optional]
* A function to invoke once this operation finishes.
*/
_onEnableSelf: function(aDetails) {
let { sourceLocation: url, lineNumber: line, actor } = aDetails;
_onEnableSelf: function(aId, aCallback = () => {}) {
let targetBreakpoint = this.getItemForPredicate(aItem => aItem.attachment.actor == aId);
let { sourceLocation: url, lineNumber: line, actor } = targetBreakpoint.attachment;
// Enable the breakpoint, in this container and the controller store.
if (this.enableBreakpoint(url, line)) {
let prefix = "bp-cMenu-"; // "breakpoints context menu"
let enableSelfId = prefix + "enableSelf-" + actor + "-menuitem";
let disableSelfId = prefix + "disableSelf-" + actor + "-menuitem";
document.getElementById(enableSelfId).setAttribute("hidden", "true");
document.getElementById(disableSelfId).removeAttribute("hidden");
// Breakpoint is now enabled.
// Breakpoints can only be set while the debuggee is paused, so if the
// active thread wasn't paused, wait for a resume before continuing.
if (gThreadClient.state != "paused") {
gThreadClient.addOneTimeListener("resumed", aCallback);
} else {
aCallback();
}
}
},
/**
* Listener handling the "disableSelf" menuitem command.
* Function invoked on the "disableSelf" menuitem command.
*
* @param object aDetails
* The breakpoint details (sourceLocation, lineNumber etc.).
* @param string aId
* The original breakpoint client actor. If a breakpoint was disabled
* and then re-enabled, then this will not correspond to the entry in
* the controller's breakpoints store.
* @param function aCallback [optional]
* A function to invoke once this operation finishes.
*/
_onDisableSelf: function(aDetails) {
let { sourceLocation: url, lineNumber: line, actor } = aDetails;
_onDisableSelf: function(aId, aCallback = () => {}) {
let targetBreakpoint = this.getItemForPredicate(aItem => aItem.attachment.actor == aId);
let { sourceLocation: url, lineNumber: line, actor } = targetBreakpoint.attachment;
// Disable the breakpoint, in this container and the controller store.
if (this.disableBreakpoint(url, line)) {
let prefix = "bp-cMenu-"; // "breakpoints context menu"
let enableSelfId = prefix + "enableSelf-" + actor + "-menuitem";
let disableSelfId = prefix + "disableSelf-" + actor + "-menuitem";
document.getElementById(enableSelfId).removeAttribute("hidden");
document.getElementById(disableSelfId).setAttribute("hidden", "true");
// Breakpoint is now disabled.
aCallback();
}
},
/**
* Listener handling the "deleteSelf" menuitem command.
* Function invoked on the "deleteSelf" menuitem command.
*
* @param object aDetails
* The breakpoint details (sourceLocation, lineNumber etc.).
* @param string aId
* The original breakpoint client actor. If a breakpoint was disabled
* and then re-enabled, then this will not correspond to the entry in
* the controller's breakpoints store.
* @param function aCallback [optional]
* A function to invoke once this operation finishes.
*/
_onDeleteSelf: function(aDetails) {
let { sourceLocation: url, lineNumber: line } = aDetails;
let breakpointClient = DebuggerController.Breakpoints.getBreakpoint(url, line);
_onDeleteSelf: function(aId, aCallback = () => {}) {
let targetBreakpoint = this.getItemForPredicate(aItem => aItem.attachment.actor == aId);
let { sourceLocation: url, lineNumber: line } = targetBreakpoint.attachment;
// Remove the breakpoint, from this container and the controller store.
this.removeBreakpoint(url, line);
DebuggerController.Breakpoints.removeBreakpoint(breakpointClient);
gBreakpoints.removeBreakpoint(gBreakpoints.getBreakpoint(url, line), aCallback);
},
/**
* Listener handling the "enableOthers" menuitem command.
* Function invoked on the "enableOthers" menuitem command.
*
* @param object aDetails
* The breakpoint details (sourceLocation, lineNumber etc.).
* @param string aId
* The original breakpoint client actor. If a breakpoint was disabled
* and then re-enabled, then this will not correspond to the entry in
* the controller's breakpoints store.
* @param function aCallback [optional]
* A function to invoke once this operation finishes.
*/
_onEnableOthers: function(aDetails) {
for (let [, item] of this._breakpointsCache) {
if (item.attachment.actor != aDetails.actor) {
this._onEnableSelf(item.attachment);
_onEnableOthers: function(aId, aCallback = () => {}) {
let targetBreakpoint = this.getItemForPredicate(aItem => aItem.attachment.actor == aId);
// Find a disabled breakpoint and re-enable it. Do this recursively until
// all required breakpoints are enabled, because each operation is async.
for (let source in this) {
for (let otherBreakpoint in source) {
if (otherBreakpoint != targetBreakpoint &&
otherBreakpoint.attachment.disabled) {
this._onEnableSelf(otherBreakpoint.attachment.actor, () =>
this._onEnableOthers(aId, aCallback));
return;
}
}
}
// All required breakpoints are now enabled.
aCallback();
},
/**
* Listener handling the "disableOthers" menuitem command.
* Function invoked on the "disableOthers" menuitem command.
*
* @param object aDetails
* The breakpoint details (sourceLocation, lineNumber etc.).
* @param string aId
* The original breakpoint client actor. If a breakpoint was disabled
* and then re-enabled, then this will not correspond to the entry in
* the controller's breakpoints store.
* @param function aCallback [optional]
* A function to invoke once this operation finishes.
*/
_onDisableOthers: function(aDetails) {
for (let [, item] of this._breakpointsCache) {
if (item.attachment.actor != aDetails.actor) {
this._onDisableSelf(item.attachment);
_onDisableOthers: function(aId, aCallback = () => {}) {
let targetBreakpoint = this.getItemForPredicate(aItem => aItem.attachment.actor == aId);
// Find an enabled breakpoint and disable it. Do this recursively until
// all required breakpoints are disabled, because each operation is async.
for (let source in this) {
for (let otherBreakpoint in source) {
if (otherBreakpoint != targetBreakpoint &&
!otherBreakpoint.attachment.disabled) {
this._onDisableSelf(otherBreakpoint.attachment.actor, () =>
this._onDisableOthers(aId, aCallback));
return;
}
}
}
// All required breakpoints are now disabled.
aCallback();
},
/**
* Listener handling the "deleteOthers" menuitem command.
* Function invoked on the "deleteOthers" menuitem command.
*
* @param object aDetails
* The breakpoint details (sourceLocation, lineNumber etc.).
* @param string aId
* The original breakpoint client actor. If a breakpoint was disabled
* and then re-enabled, then this will not correspond to the entry in
* the controller's breakpoints store.
* @param function aCallback [optional]
* A function to invoke once this operation finishes.
*/
_onDeleteOthers: function(aDetails) {
for (let [, item] of this._breakpointsCache) {
if (item.attachment.actor != aDetails.actor) {
this._onDeleteSelf(item.attachment);
_onDeleteOthers: function(aId, aCallback = () => {}) {
let targetBreakpoint = this.getItemForPredicate(aItem => aItem.attachment.actor == aId);
// Find a breakpoint and delete it. Do this recursively until all required
// breakpoints are deleted, because each operation is async.
for (let source in this) {
for (let otherBreakpoint in source) {
if (otherBreakpoint != targetBreakpoint) {
this._onDeleteSelf(otherBreakpoint.attachment.actor, () =>
this._onDeleteOthers(aId, aCallback));
return;
}
}
}
// All required breakpoints are now deleted.
aCallback();
},
/**
* Listener handling the "enableAll" menuitem command.
* Function invoked on the "enableAll" menuitem command.
*
* @param object aDetails
* The breakpoint details (sourceLocation, lineNumber etc.).
* @param string aId
* The original breakpoint client actor. If a breakpoint was disabled
* and then re-enabled, then this will not correspond to the entry in
* the controller's breakpoints store.
* @param function aCallback [optional]
* A function to invoke once this operation finishes.
*/
_onEnableAll: function(aDetails) {
this._onEnableOthers(aDetails);
this._onEnableSelf(aDetails);
_onEnableAll: function(aId) {
this._onEnableOthers(aId, () => this._onEnableSelf(aId));
},
/**
* Listener handling the "disableAll" menuitem command.
* Function invoked on the "disableAll" menuitem command.
*
* @param object aDetails
* The breakpoint details (sourceLocation, lineNumber etc.).
* @param string aId
* The original breakpoint client actor. If a breakpoint was disabled
* and then re-enabled, then this will not correspond to the entry in
* the controller's breakpoints store.
* @param function aCallback [optional]
* A function to invoke once this operation finishes.
*/
_onDisableAll: function(aDetails) {
this._onDisableOthers(aDetails);
this._onDisableSelf(aDetails);
_onDisableAll: function(aId) {
this._onDisableOthers(aId, () => this._onDisableSelf(aId));
},
/**
* Listener handling the "deleteAll" menuitem command.
* Function invoked on the "deleteAll" menuitem command.
*
* @param object aDetails
* The breakpoint details (sourceLocation, lineNumber etc.).
* @param string aId
* The original breakpoint client actor. If a breakpoint was disabled
* and then re-enabled, then this will not correspond to the entry in
* the controller's breakpoints store.
* @param function aCallback [optional]
* A function to invoke once this operation finishes.
*/
_onDeleteAll: function(aDetails) {
this._onDeleteOthers(aDetails);
this._onDeleteSelf(aDetails);
_onDeleteAll: function(aId) {
this._onDeleteOthers(aId, () => this._onDeleteSelf(aId));
},
/**
* Gets an identifier for a breakpoint's details in the current cache.
*
* @param string aSourceLocation
* The breakpoint source location.
* @param number aLineNumber
* The breakpoint line number.
* @return string
* The breakpoint identifier.
*/
_getBreakpointKey: function(aSourceLocation, aLineNumber) {
return [aSourceLocation, aLineNumber].join();
},
_breakpointsCache: null,
_commandset: null,
_popupset: null,
_cmPopup: null,
@ -1175,7 +1242,6 @@ let SourceUtils = {
function WatchExpressionsView() {
dumpn("WatchExpressionsView was instantiated");
this._cache = []; // Array instead of a map because indices are important.
this.switchExpression = this.switchExpression.bind(this);
this.deleteExpression = this.deleteExpression.bind(this);
this._createItemView = this._createItemView.bind(this);
@ -1185,20 +1251,18 @@ function WatchExpressionsView() {
this._onKeyPress = this._onKeyPress.bind(this);
}
create({ constructor: WatchExpressionsView, proto: MenuContainer.prototype }, {
WatchExpressionsView.prototype = Heritage.extend(WidgetMethods, {
/**
* Initialization function, called when the debugger is started.
*/
initialize: function() {
dumpn("Initializing the WatchExpressionsView");
this.node = new ListWidget(document.getElementById("expressions"));
this._variables = document.getElementById("variables");
this.node.permaText = L10N.getStr("addWatchExpressionText");
this.node.itemFactory = this._createItemView;
this.node.setAttribute("context", "debuggerWatchExpressionsContextMenu");
this.node.addEventListener("click", this._onClick, false);
this.widget = new ListWidget(document.getElementById("expressions"));
this.widget.permaText = L10N.getStr("addWatchExpressionText");
this.widget.itemFactory = this._createItemView;
this.widget.setAttribute("context", "debuggerWatchExpressionsContextMenu");
this.widget.addEventListener("click", this._onClick, false);
},
/**
@ -1207,7 +1271,7 @@ create({ constructor: WatchExpressionsView, proto: MenuContainer.prototype }, {
destroy: function() {
dumpn("Destroying the WatchExpressionsView");
this.node.removeEventListener("click", this._onClick, false);
this.widget.removeEventListener("click", this._onClick, false);
},
/**
@ -1226,28 +1290,14 @@ create({ constructor: WatchExpressionsView, proto: MenuContainer.prototype }, {
relaxed: true, /* this container should allow dupes & degenerates */
attachment: {
initialExpression: aExpression,
currentExpression: "",
id: this._generateId()
currentExpression: ""
}
});
// Automatically focus the new watch expression input.
expressionItem.attachment.inputNode.select();
expressionItem.attachment.inputNode.focus();
this._variables.scrollTop = 0;
this._cache.splice(0, 0, expressionItem);
},
/**
* Removes the watch expression with the specified index from this container.
*
* @param number aIndex
* The index used to identify the watch expression.
*/
removeExpressionAt: function(aIndex) {
this.remove(this._cache[aIndex]);
this._cache.splice(aIndex, 1);
DebuggerView.Variables.parentNode.scrollTop = 0;
},
/**
@ -1262,10 +1312,10 @@ create({ constructor: WatchExpressionsView, proto: MenuContainer.prototype }, {
*/
switchExpression: function(aVar, aExpression) {
let expressionItem =
[i for (i of this._cache) if (i.attachment.currentExpression == aVar.name)][0];
[i for (i in this) if (i.attachment.currentExpression == aVar.name)][0];
// Remove the watch expression if it's going to be empty or a duplicate.
if (!aExpression || this.getExpressions().indexOf(aExpression) != -1) {
if (!aExpression || this.getAllStrings().indexOf(aExpression) != -1) {
this.deleteExpression(aVar);
return;
}
@ -1288,10 +1338,10 @@ create({ constructor: WatchExpressionsView, proto: MenuContainer.prototype }, {
*/
deleteExpression: function(aVar) {
let expressionItem =
[i for (i of this._cache) if (i.attachment.currentExpression == aVar.name)][0];
[i for (i in this) if (i.attachment.currentExpression == aVar.name)][0];
// Remove the watch expression at its respective index.
this.removeExpressionAt(this._cache.indexOf(expressionItem));
// Remove the watch expression.
this.remove(expressionItem);
// Synchronize with the controller's watch expressions store.
DebuggerController.StackFrames.syncWatchExpressions();
@ -1305,8 +1355,8 @@ create({ constructor: WatchExpressionsView, proto: MenuContainer.prototype }, {
* @return string
* The watch expression code string.
*/
getExpression: function(aIndex) {
return this._cache[aIndex].attachment.currentExpression;
getString: function(aIndex) {
return this.getItemAtIndex(aIndex).attachment.currentExpression;
},
/**
@ -1315,8 +1365,8 @@ create({ constructor: WatchExpressionsView, proto: MenuContainer.prototype }, {
* @return array
* The watch expressions code strings.
*/
getExpressions: function() {
return [item.attachment.currentExpression for (item of this._cache)];
getAllStrings: function() {
return this.orderedItems.map((e) => e.attachment.currentExpression);
},
/**
@ -1343,9 +1393,7 @@ create({ constructor: WatchExpressionsView, proto: MenuContainer.prototype }, {
inputNode.addEventListener("blur", this._onBlur, false);
inputNode.addEventListener("keypress", this._onKeyPress, false);
aElementNode.id = "expression-" + aAttachment.id;
aElementNode.className = "dbg-expression title";
aElementNode.appendChild(arrowNode);
aElementNode.appendChild(inputNode);
aElementNode.appendChild(closeNode);
@ -1360,7 +1408,7 @@ create({ constructor: WatchExpressionsView, proto: MenuContainer.prototype }, {
*/
_onCmdAddExpression: function(aText) {
// Only add a new expression if there's no pending input.
if (this.getExpressions().indexOf("") == -1) {
if (this.getAllStrings().indexOf("") == -1) {
this.addExpression(aText || DebuggerView.editor.getSelectedText());
}
},
@ -1371,7 +1419,6 @@ create({ constructor: WatchExpressionsView, proto: MenuContainer.prototype }, {
_onCmdRemoveAllExpressions: function() {
// Empty the view of all the watch expressions and clear the cache.
this.empty();
this._cache.length = 0;
// Synchronize with the controller's watch expressions store.
DebuggerController.StackFrames.syncWatchExpressions();
@ -1396,8 +1443,8 @@ create({ constructor: WatchExpressionsView, proto: MenuContainer.prototype }, {
* The click listener for a watch expression's close button.
*/
_onClose: function(e) {
let expressionItem = this.getItemForElement(e.target);
this.removeExpressionAt(this._cache.indexOf(expressionItem));
// Remove the watch expression.
this.remove(this.getItemForElement(e.target));
// Synchronize with the controller's watch expressions store.
DebuggerController.StackFrames.syncWatchExpressions();
@ -1417,11 +1464,11 @@ create({ constructor: WatchExpressionsView, proto: MenuContainer.prototype }, {
// Remove the watch expression if it's empty.
if (!newExpression) {
this.removeExpressionAt(this._cache.indexOf(expressionItem));
this.remove(expressionItem);
}
// Remove the watch expression if it's a duplicate.
else if (!oldExpression && this.getExpressions().indexOf(newExpression) != -1) {
this.removeExpressionAt(this._cache.indexOf(expressionItem));
else if (!oldExpression && this.getAllStrings().indexOf(newExpression) != -1) {
this.remove(expressionItem);
}
// Expression is eligible.
else {
@ -1443,21 +1490,7 @@ create({ constructor: WatchExpressionsView, proto: MenuContainer.prototype }, {
DebuggerView.editor.focus();
return;
}
},
/**
* Gets an identifier for a new watch expression item in the current cache.
* @return string
*/
_generateId: (function() {
let count = 0;
return function() {
return (++count) + "";
};
})(),
_variables: null,
_cache: null
}
});
/**
@ -1475,19 +1508,19 @@ function GlobalSearchView() {
this._onMatchClick = this._onMatchClick.bind(this);
}
create({ constructor: GlobalSearchView, proto: MenuContainer.prototype }, {
GlobalSearchView.prototype = Heritage.extend(WidgetMethods, {
/**
* Initialization function, called when the debugger is started.
*/
initialize: function() {
dumpn("Initializing the GlobalSearchView");
this.node = new ListWidget(document.getElementById("globalsearch"));
this.widget = new ListWidget(document.getElementById("globalsearch"));
this._splitter = document.querySelector("#globalsearch + .devtools-horizontal-splitter");
this.node.emptyText = L10N.getStr("noMatchingStringsText");
this.node.itemFactory = this._createItemView;
this.node.addEventListener("scroll", this._onScroll, false);
this.widget.emptyText = L10N.getStr("noMatchingStringsText");
this.widget.itemFactory = this._createItemView;
this.widget.addEventListener("scroll", this._onScroll, false);
},
/**
@ -1496,7 +1529,7 @@ create({ constructor: GlobalSearchView, proto: MenuContainer.prototype }, {
destroy: function() {
dumpn("Destroying the GlobalSearchView");
this.node.removeEventListener("scroll", this._onScroll, false);
this.widget.removeEventListener("scroll", this._onScroll, false);
},
/**
@ -1504,7 +1537,7 @@ create({ constructor: GlobalSearchView, proto: MenuContainer.prototype }, {
* @return boolean
*/
get hidden()
this.node.getAttribute("hidden") == "true" ||
this.widget.getAttribute("hidden") == "true" ||
this._splitter.getAttribute("hidden") == "true",
/**
@ -1512,7 +1545,7 @@ create({ constructor: GlobalSearchView, proto: MenuContainer.prototype }, {
* @param boolean aFlag
*/
set hidden(aFlag) {
this.node.setAttribute("hidden", aFlag);
this.widget.setAttribute("hidden", aFlag);
this._splitter.setAttribute("hidden", aFlag);
},
@ -1526,9 +1559,10 @@ create({ constructor: GlobalSearchView, proto: MenuContainer.prototype }, {
},
/**
* Focuses the next found match in the source editor.
* Selects the next found item in this container.
* Does not change the currently focused node.
*/
focusNextMatch: function() {
selectNext: function() {
let totalLineResults = LineResults.size();
if (!totalLineResults) {
return;
@ -1542,9 +1576,10 @@ create({ constructor: GlobalSearchView, proto: MenuContainer.prototype }, {
},
/**
* Focuses the previously found match in the source editor.
* Selects the previously found item in this container.
* Does not change the currently focused node.
*/
focusPrevMatch: function() {
selectPrev: function() {
let totalLineResults = LineResults.size();
if (!totalLineResults) {
return;
@ -1821,7 +1856,7 @@ create({ constructor: GlobalSearchView, proto: MenuContainer.prototype }, {
return;
}
let { top, height } = aTarget.getBoundingClientRect();
let { clientHeight } = this.node._parent;
let { clientHeight } = this.widget._parent;
if (top - height <= clientHeight || this._forceExpandResults) {
sourceResultsItem.instance.expand();
@ -1835,7 +1870,9 @@ create({ constructor: GlobalSearchView, proto: MenuContainer.prototype }, {
* The match to scroll into view.
*/
_scrollMatchIntoViewIfNeeded: function(aMatch) {
let boxObject = this.node._parent.boxObject.QueryInterface(Ci.nsIScrollBoxObject);
// TODO: Accessing private widget properties. Figure out what's the best
// way to expose such things. Bug 876271.
let boxObject = this.widget._parent.boxObject.QueryInterface(Ci.nsIScrollBoxObject);
boxObject.ensureElementIsVisible(aMatch);
},
@ -2207,7 +2244,7 @@ LineResults.prototype.__iterator__ = function() {
*/
SourceResults.getItemForElement =
LineResults.getItemForElement = function(aElement) {
return MenuContainer.prototype.getItemForElement.call(this, aElement);
return WidgetMethods.getItemForElement.call(this, aElement);
};
/**

Просмотреть файл

@ -58,7 +58,7 @@ ToolbarView.prototype = {
this._stepInButton.setAttribute("tooltiptext", this._stepInTooltip);
this._stepOutButton.setAttribute("tooltiptext", this._stepOutTooltip);
// TODO: bug 806775
// TODO: bug 806775 - group scripts by globals using hostAnnotations.
// this.toggleChromeGlobalsContainer(window._isChromeDebugger);
},
@ -75,6 +75,21 @@ ToolbarView.prototype = {
this._stepOutButton.removeEventListener("mousedown", this._onStepOutPressed, false);
},
/**
* Display a warning when trying to resume a debuggee while another is paused.
* Debuggees must be unpaused in a Last-In-First-Out order.
*
* @param string aPausedUrl
* The URL of the last paused debuggee.
*/
showResumeWarning: function(aPausedUrl) {
let label = L10N.getFormatStr("resumptionOrderPanelTitle", aPausedUrl);
let descriptionNode = document.getElementById("resumption-panel-desc");
descriptionNode.setAttribute("value", label);
this._resumeOrderPanel.openPopup(this._resumeButton);
},
/**
* Sets the resume button state based on the debugger active thread.
*
@ -94,19 +109,6 @@ ToolbarView.prototype = {
}
},
/**
* Display a warning when trying to resume a debuggee while another is paused.
* Debuggees must be unpaused in a Last-In-First-Out order.
*
* @param string aPausedUrl
* The URL of the last paused debuggee.
*/
showResumeWarning: function(aPausedUrl) {
let label = L10N.getFormatStr("resumptionOrderPanelTitle", [aPausedUrl]);
document.getElementById("resumption-panel-desc").textContent = label;
this._resumeOrderPanel.openPopup(this._resumeButton);
},
/**
* Sets the chrome globals container hidden or visible. It's hidden by default.
*
@ -248,8 +250,10 @@ OptionsView.prototype = {
* Listener handling the 'pause on exceptions' menuitem command.
*/
_togglePauseOnExceptions: function() {
DebuggerController.activeThread.pauseOnExceptions(Prefs.pauseOnExceptions =
this._pauseOnExceptionsItem.getAttribute("checked") == "true");
let pref = Prefs.pauseOnExceptions =
this._pauseOnExceptionsItem.getAttribute("checked") == "true";
DebuggerController.activeThread.pauseOnExceptions(pref);
},
/**
@ -264,16 +268,20 @@ OptionsView.prototype = {
* Listener handling the 'show non-enumerables' menuitem command.
*/
_toggleShowVariablesOnlyEnum: function() {
DebuggerView.Variables.onlyEnumVisible = Prefs.variablesOnlyEnumVisible =
let pref = Prefs.variablesOnlyEnumVisible =
this._showVariablesOnlyEnumItem.getAttribute("checked") == "true";
DebuggerView.Variables.onlyEnumVisible = pref;
},
/**
* Listener handling the 'show variables searchbox' menuitem command.
*/
_toggleShowVariablesFilterBox: function() {
DebuggerView.Variables.searchEnabled = Prefs.variablesSearchboxVisible =
let pref = Prefs.variablesSearchboxVisible =
this._showVariablesFilterBoxItem.getAttribute("checked") == "true";
DebuggerView.Variables.searchEnabled = pref;
},
/**
@ -282,6 +290,7 @@ OptionsView.prototype = {
_toggleShowOriginalSource: function() {
function reconfigure() {
window.removeEventListener("Debugger:OptionsPopupHidden", reconfigure, false);
// The popup panel needs more time to hide after triggering onpopuphidden.
window.setTimeout(function() {
DebuggerController.reconfigureThread(pref);
@ -299,8 +308,8 @@ OptionsView.prototype = {
_pauseOnExceptionsItem: null,
_showPanesOnStartupItem: null,
_showVariablesOnlyEnumItem: null,
_showOriginalSourceItem: null,
_showVariablesFilterBoxItem: null
_showVariablesFilterBoxItem: null,
_showOriginalSourceItem: null
};
/**
@ -313,19 +322,19 @@ function ChromeGlobalsView() {
this._onClick = this._onClick.bind(this);
}
create({ constructor: ChromeGlobalsView, proto: MenuContainer.prototype }, {
ChromeGlobalsView.prototype = Heritage.extend(WidgetMethods, {
/**
* Initialization function, called when the debugger is started.
*/
initialize: function() {
dumpn("Initializing the ChromeGlobalsView");
this.node = document.getElementById("chrome-globals");
this.widget = document.getElementById("chrome-globals");
this.emptyText = L10N.getStr("noGlobalsText");
this.unavailableText = L10N.getStr("noMatchingGlobalsText");
this.node.addEventListener("select", this._onSelect, false);
this.node.addEventListener("click", this._onClick, false);
this.widget.addEventListener("select", this._onSelect, false);
this.widget.addEventListener("click", this._onClick, false);
// Show an empty label by default.
this.empty();
@ -337,17 +346,14 @@ create({ constructor: ChromeGlobalsView, proto: MenuContainer.prototype }, {
destroy: function() {
dumpn("Destroying the ChromeGlobalsView");
this.node.removeEventListener("select", this._onSelect, false);
this.node.removeEventListener("click", this._onClick, false);
this.widget.removeEventListener("select", this._onSelect, false);
this.widget.removeEventListener("click", this._onClick, false);
},
/**
* The select listener for the chrome globals container.
*/
_onSelect: function() {
if (!this.refresh()) {
return;
}
// TODO: bug 806775, do something useful for chrome debugging.
},
@ -366,14 +372,13 @@ create({ constructor: ChromeGlobalsView, proto: MenuContainer.prototype }, {
function StackFramesView() {
dumpn("StackFramesView was instantiated");
this._framesCache = new Map(); // Can't use a WeakMap because keys are numbers.
this._onStackframeRemoved = this._onStackframeRemoved.bind(this);
this._onSelect = this._onSelect.bind(this);
this._onScroll = this._onScroll.bind(this);
this._afterScroll = this._afterScroll.bind(this);
}
create({ constructor: StackFramesView, proto: MenuContainer.prototype }, {
StackFramesView.prototype = Heritage.extend(WidgetMethods, {
/**
* Initialization function, called when the debugger is started.
*/
@ -388,9 +393,9 @@ create({ constructor: StackFramesView, proto: MenuContainer.prototype }, {
document.getElementById("debuggerPopupset").appendChild(menupopup);
document.getElementById("debuggerCommands").appendChild(commandset);
this.node = new BreadcrumbsWidget(document.getElementById("stackframes"));
this.node.addEventListener("select", this._onSelect, false);
this.node.addEventListener("scroll", this._onScroll, true);
this.widget = new BreadcrumbsWidget(document.getElementById("stackframes"));
this.widget.addEventListener("select", this._onSelect, false);
this.widget.addEventListener("scroll", this._onScroll, true);
window.addEventListener("resize", this._onScroll, true);
this.autoFocusOnFirstItem = false;
@ -403,8 +408,8 @@ create({ constructor: StackFramesView, proto: MenuContainer.prototype }, {
destroy: function() {
dumpn("Destroying the StackFramesView");
this.node.removeEventListener("select", this._onSelect, false);
this.node.removeEventListener("scroll", this._onScroll, true);
this.widget.removeEventListener("select", this._onSelect, false);
this.widget.removeEventListener("scroll", this._onScroll, true);
window.removeEventListener("resize", this._onScroll, true);
},
@ -426,7 +431,7 @@ create({ constructor: StackFramesView, proto: MenuContainer.prototype }, {
let menuEntry = this._createMenuEntry.apply(this, arguments);
// Append a stack frame item to this container.
let stackframeItem = this.push(frameView, {
this.push([frameView], {
index: 0, /* specifies on which position should the item be appended */
attachment: {
popup: menuEntry,
@ -440,8 +445,6 @@ create({ constructor: StackFramesView, proto: MenuContainer.prototype }, {
// menuitem and command are also destroyed.
finalize: this._onStackframeRemoved
});
this._framesCache.set(aDepth, stackframeItem);
},
/**
@ -449,7 +452,7 @@ create({ constructor: StackFramesView, proto: MenuContainer.prototype }, {
* @param number aDepth
*/
set selectedDepth(aDepth) {
this.selectedItem = this._framesCache.get(aDepth);
this.selectedItem = (aItem) => aItem.attachment.depth == aDepth;
},
/**
@ -553,34 +556,19 @@ create({ constructor: StackFramesView, proto: MenuContainer.prototype }, {
};
},
/**
* Destroys a context menu item for a stack frame.
*
* @param object aMenuEntry
* An object containing the stack frame command and menu item.
*/
_destroyMenuEntry: function(aMenuEntry) {
dumpn("Destroying context menu: " +
aMenuEntry.command.id + " & " + aMenuEntry.menuitem.id);
let command = aMenuEntry.command;
let menuitem = aMenuEntry.menuitem;
command.parentNode.removeChild(command);
menuitem.parentNode.removeChild(menuitem);
},
/**
* Function called each time a stack frame item is removed.
*
* @param MenuItem aItem
* The corresponding menu item.
* @param object aItem
* The corresponding item.
*/
_onStackframeRemoved: function(aItem) {
dumpn("Finalizing stackframe item: " + aItem);
let { popup, depth } = aItem.attachment;
this._destroyMenuEntry(popup);
this._framesCache.delete(depth);
// Destroy the context menu item for the stack frame.
let contextItem = aItem.attachment.popup;
contextItem.command.remove();
contextItem.menuitem.remove();
},
/**
@ -592,6 +580,8 @@ create({ constructor: StackFramesView, proto: MenuContainer.prototype }, {
// The container is not empty and an actual item was selected.
gStackFrames.selectFrame(stackframeItem.attachment.depth);
// Update the context menu to show the currently selected stackframe item
// as a checked entry.
for (let otherItem in this) {
if (otherItem != stackframeItem) {
otherItem.attachment.popup.menuitem.removeAttribute("checked");
@ -618,7 +608,9 @@ create({ constructor: StackFramesView, proto: MenuContainer.prototype }, {
* Requests the addition of more frames from the controller.
*/
_afterScroll: function() {
let list = this.node._list;
// TODO: Accessing private widget properties. Figure out what's the best
// way to expose such things. Bug 876271.
let list = this.widget._list;
let scrollPosition = list.scrollPosition;
let scrollWidth = list.scrollWidth;
@ -633,7 +625,6 @@ create({ constructor: StackFramesView, proto: MenuContainer.prototype }, {
}
},
_framesCache: null,
_commandset: null,
_menupopup: null,
_scrollTimeout: null
@ -757,7 +748,7 @@ FilterView.prototype = {
this._variableOperatorLabel.setAttribute("value",
L10N.getFormatStr("searchPanelVariable", this._variableSearchKey));
// TODO: bug 806775
// TODO: bug 806775 - group scripts by globals using hostAnnotations.
// if (window._isChromeDebugger) {
// this.target = DebuggerView.ChromeGlobals;
// } else {
@ -821,7 +812,9 @@ FilterView.prototype = {
if (globalFlagIndex != 0 && functionFlagIndex != 0 && variableFlagIndex != 0) {
let fileEnd = lineFlagIndex != -1
? lineFlagIndex
: tokenFlagIndex != -1 ? tokenFlagIndex : rawLength;
: tokenFlagIndex != -1
? tokenFlagIndex
: rawLength;
let lineEnd = tokenFlagIndex != -1
? tokenFlagIndex
@ -946,10 +939,10 @@ FilterView.prototype = {
DebuggerView.FilteredSources.syncFileSearch();
// Hide all the groups with no visible children.
view.node.hideEmptyGroups();
view.widget.hideEmptyGroups();
// Ensure the currently selected item is visible.
view.node.ensureSelectionIsVisible({ withGroup: true });
view.widget.ensureSelectionIsVisible({ withGroup: true });
// Remember the previously searched file to avoid redundant filtering.
this._prevSearchedFile = aFile;
@ -1114,7 +1107,7 @@ FilterView.prototype = {
DebuggerView.editor.focus();
this.clearSearch();
} else {
DebuggerView.FilteredSources[["focusNext", "focusPrev"][action]]();
DebuggerView.FilteredSources[["selectNext", "selectPrev"][action]]();
}
this._prevSearchedFile = file;
return;
@ -1125,7 +1118,7 @@ FilterView.prototype = {
if (isReturnKey && (isDifferentToken || DebuggerView.GlobalSearch.hidden)) {
DebuggerView.GlobalSearch.performSearch(token);
} else {
DebuggerView.GlobalSearch[["focusNextMatch", "focusPrevMatch"][action]]();
DebuggerView.GlobalSearch[["selectNext", "selectPrev"][action]]();
}
this._prevSearchedToken = token;
return;
@ -1136,7 +1129,7 @@ FilterView.prototype = {
if (isReturnKey && (isDifferentToken || DebuggerView.FilteredFunctions.hidden)) {
DebuggerView.FilteredFunctions.performSearch(token);
} else if (!isReturnKey) {
DebuggerView.FilteredFunctions[["focusNext", "focusPrev"][action]]();
DebuggerView.FilteredFunctions[["selectNext", "selectPrev"][action]]();
} else {
DebuggerView.FilteredFunctions.clearView();
DebuggerView.editor.focus();
@ -1285,13 +1278,12 @@ FilterView.prototype = {
*/
function FilteredSourcesView() {
dumpn("FilteredSourcesView was instantiated");
ResultsPanelContainer.call(this);
this.onClick = this.onClick.bind(this);
this.onSelect = this.onSelect.bind(this);
this._onClick = this._onClick.bind(this);
this._onSelect = this._onSelect.bind(this);
}
create({ constructor: FilteredSourcesView, proto: ResultsPanelContainer.prototype }, {
FilteredSourcesView.prototype = Heritage.extend(ResultsPanelContainer.prototype, {
/**
* Initialization function, called when the debugger is started.
*/
@ -1299,6 +1291,8 @@ create({ constructor: FilteredSourcesView, proto: ResultsPanelContainer.prototyp
dumpn("Initializing the FilteredSourcesView");
this.anchor = document.getElementById("searchbox");
this.widget.addEventListener("select", this._onSelect, false);
this.widget.addEventListener("click", this._onClick, false);
},
/**
@ -1307,6 +1301,8 @@ create({ constructor: FilteredSourcesView, proto: ResultsPanelContainer.prototyp
destroy: function() {
dumpn("Destroying the FilteredSourcesView");
this.widget.removeEventListener("select", this._onSelect, false);
this.widget.removeEventListener("click", this._onClick, false);
this.anchor = null;
},
@ -1328,8 +1324,8 @@ create({ constructor: FilteredSourcesView, proto: ResultsPanelContainer.prototyp
let visibleItems = DebuggerView.Sources.visibleItems;
let displayedItems = visibleItems.slice(0, RESULTS_PANEL_MAX_RESULTS);
// Append a location item item to this container.
for (let item of displayedItems) {
// Append a location item item to this container.
let trimmedLabel = SourceUtils.trimUrlLength(item.label);
let trimmedValue = SourceUtils.trimUrlLength(item.value, 0, "start");
let locationItem = this.push([trimmedLabel, trimmedValue], {
@ -1342,7 +1338,7 @@ create({ constructor: FilteredSourcesView, proto: ResultsPanelContainer.prototyp
}
// Select the first entry in this container.
this.select(0);
this.selectedIndex = 0;
// Only display the results panel if there's at least one entry available.
this.hidden = this.itemCount == 0;
@ -1351,10 +1347,10 @@ create({ constructor: FilteredSourcesView, proto: ResultsPanelContainer.prototyp
/**
* The click listener for this container.
*/
onClick: function(e) {
_onClick: function(e) {
let locationItem = this.getItemForElement(e.target);
if (locationItem) {
this.select(locationItem);
this.selectedItem = locationItem;
DebuggerView.Filtering.clearSearch();
}
},
@ -1362,11 +1358,10 @@ create({ constructor: FilteredSourcesView, proto: ResultsPanelContainer.prototyp
/**
* The select listener for this container.
*
* @param MenuItem aItem
* @param object aItem
* The item associated with the element to select.
*/
onSelect: function(e) {
let locationItem = this.getItemForElement(e.target);
_onSelect: function({ detail: locationItem }) {
if (locationItem) {
DebuggerView.updateEditor(locationItem.attachment.fullValue, 0);
}
@ -1378,14 +1373,13 @@ create({ constructor: FilteredSourcesView, proto: ResultsPanelContainer.prototyp
*/
function FilteredFunctionsView() {
dumpn("FilteredFunctionsView was instantiated");
ResultsPanelContainer.call(this);
this._performFunctionSearch = this._performFunctionSearch.bind(this);
this.onClick = this.onClick.bind(this);
this.onSelect = this.onSelect.bind(this);
this._onClick = this._onClick.bind(this);
this._onSelect = this._onSelect.bind(this);
}
create({ constructor: FilteredFunctionsView, proto: ResultsPanelContainer.prototype }, {
FilteredFunctionsView.prototype = Heritage.extend(ResultsPanelContainer.prototype, {
/**
* Initialization function, called when the debugger is started.
*/
@ -1393,6 +1387,8 @@ create({ constructor: FilteredFunctionsView, proto: ResultsPanelContainer.protot
dumpn("Initializing the FilteredFunctionsView");
this.anchor = document.getElementById("searchbox");
this.widget.addEventListener("select", this._onSelect, false);
this.widget.addEventListener("click", this._onClick, false);
},
/**
@ -1401,6 +1397,8 @@ create({ constructor: FilteredFunctionsView, proto: ResultsPanelContainer.protot
destroy: function() {
dumpn("Destroying the FilteredFunctionsView");
this.widget.removeEventListener("select", this._onSelect, false);
this.widget.removeEventListener("click", this._onClick, false);
this.anchor = null;
},
@ -1562,17 +1560,19 @@ create({ constructor: FilteredFunctionsView, proto: ResultsPanelContainer.protot
}
// Select the first entry in this container.
this.select(0);
this.selectedIndex = 0;
// Only display the results panel if there's at least one entry available.
this.hidden = this.itemCount == 0;
},
/**
* The click listener for this container.
*/
onClick: function(e) {
_onClick: function(e) {
let functionItem = this.getItemForElement(e.target);
if (functionItem) {
this.select(functionItem);
this.selectedItem = functionItem;
DebuggerView.Filtering.clearSearch();
}
},
@ -1580,8 +1580,7 @@ create({ constructor: FilteredFunctionsView, proto: ResultsPanelContainer.protot
/**
* The select listener for this container.
*/
onSelect: function(e) {
let functionItem = this.getItemForElement(e.target);
_onSelect: function({ detail: functionItem }) {
if (functionItem) {
let sourceUrl = functionItem.attachment.sourceUrl;
let scriptOffset = functionItem.attachment.scriptOffset;

Просмотреть файл

@ -41,7 +41,6 @@ let DebuggerView = {
initialize: function(aCallback) {
dumpn("Initializing the DebuggerView");
this._initializeWindow();
this._initializePanes();
this.Toolbar.initialize();
@ -55,14 +54,7 @@ let DebuggerView = {
this.WatchExpressions.initialize();
this.GlobalSearch.initialize();
this.Variables = new VariablesView(document.getElementById("variables"));
this.Variables.searchPlaceholder = L10N.getStr("emptyVariablesFilterText");
this.Variables.emptyText = L10N.getStr("emptyVariablesText");
this.Variables.onlyEnumVisible = Prefs.variablesOnlyEnumVisible;
this.Variables.searchEnabled = Prefs.variablesSearchboxVisible;
this.Variables.eval = DebuggerController.StackFrames.evaluate;
this.Variables.lazyEmpty = true;
this._initializeVariablesView();
this._initializeEditor(aCallback);
},
@ -86,47 +78,12 @@ let DebuggerView = {
this.WatchExpressions.destroy();
this.GlobalSearch.destroy();
this._destroyWindow();
this._destroyPanes();
this._destroyEditor();
aCallback();
},
/**
* Initializes the UI for the window.
*/
_initializeWindow: function() {
dumpn("Initializing the DebuggerView window");
let isRemote = window._isRemoteDebugger;
let isChrome = window._isChromeDebugger;
if (isRemote || isChrome) {
window.moveTo(Prefs.windowX, Prefs.windowY);
window.resizeTo(Prefs.windowWidth, Prefs.windowHeight);
if (isRemote) {
document.title = L10N.getStr("remoteDebuggerWindowTitle");
} else {
document.title = L10N.getStr("chromeDebuggerWindowTitle");
}
}
},
/**
* Destroys the UI for the window.
*/
_destroyWindow: function() {
dumpn("Destroying the DebuggerView window");
if (window._isRemoteDebugger || window._isChromeDebugger) {
Prefs.windowX = window.screenX;
Prefs.windowY = window.screenY;
Prefs.windowWidth = window.outerWidth;
Prefs.windowHeight = window.outerHeight;
}
},
/**
* Initializes the UI for all the displayed panes.
*/
@ -159,6 +116,37 @@ let DebuggerView = {
this._instrumentsPaneToggleButton = null;
},
/**
* Initializes the VariablesView instance and attaches a controller.
*/
_initializeVariablesView: function() {
this.Variables = new VariablesView(document.getElementById("variables"), {
searchPlaceholder: L10N.getStr("emptyVariablesFilterText"),
emptyText: L10N.getStr("emptyVariablesText"),
onlyEnumVisible: Prefs.variablesOnlyEnumVisible,
searchEnabled: Prefs.variablesSearchboxVisible,
eval: DebuggerController.StackFrames.evaluate,
lazyEmpty: true
});
// Attach a controller that handles interfacing with the debugger protocol.
VariablesViewController.attach(this.Variables, {
getGripClient: aObject => gThreadClient.pauseGrip(aObject)
});
// Relay events from the VariablesView.
this.Variables.on("fetched", (aEvent, aType) => {
switch (aType) {
case "variables":
window.dispatchEvent(document, "Debugger:FetchedVariables");
break;
case "properties":
window.dispatchEvent(document, "Debugger:FetchedProperties");
break;
}
});
},
/**
* Initializes the SourceEditor instance.
*
@ -392,7 +380,7 @@ let DebuggerView = {
* @return string
* The specified line's text.
*/
getEditorLine: function(aLine) {
getEditorLineText: function(aLine) {
let line = aLine || this.editor.getCaretPosition().line;
let start = this.editor.getLineStart(line);
let end = this.editor.getLineEnd(line);
@ -405,7 +393,7 @@ let DebuggerView = {
* @return string
* The selected text.
*/
getEditorSelection: function() {
getEditorSelectionText: function() {
let selection = this.editor.getSelection();
return this.editor.getText(selection.start, selection.end);
},
@ -483,12 +471,13 @@ let DebuggerView = {
Options: null,
Filtering: null,
FilteredSources: null,
FilteredFunctions: null,
GlobalSearch: null,
ChromeGlobals: null,
StackFrames: null,
Sources: null,
WatchExpressions: null,
GlobalSearch: null,
Variables: null,
WatchExpressions: null,
_editor: null,
_editorSource: null,
_loadingText: "",
@ -502,32 +491,26 @@ let DebuggerView = {
};
/**
* A stacked list of items, compatible with MenuContainer instances, used for
* A stacked list of items, compatible with WidgetMethods instances, used for
* displaying views like the watch expressions, filtering or search results etc.
*
* You should never need to access these methods directly, use the wrapper
* MenuContainer instances.
* You should never need to access these methods directly, use the wrapped
* WidgetMethods instead.
*
* Custom methods introduced by this view, not necessary for a MenuContainer:
* - set emptyText(aValue:string)
* - set permaText(aValue:string)
* - set itemType(aType:string)
* - set itemFactory(aCallback:function)
*
* @param nsIDOMNode aAssociatedNode
* The element associated with the displayed container.
* @param nsIDOMNode aNode
* The element associated with the widget.
*/
function ListWidget(aAssociatedNode) {
this._parent = aAssociatedNode;
function ListWidget(aNode) {
this._parent = aNode;
// Create an internal list container.
this._list = document.createElement("vbox");
this._parent.appendChild(this._list);
// Delegate some of the associated node's methods to satisfy the interface
// required by MenuContainer instances.
ViewHelpers.delegateWidgetAttributeMethods(this, aAssociatedNode);
ViewHelpers.delegateWidgetEventMethods(this, aAssociatedNode);
// required by WidgetMethods instances.
ViewHelpers.delegateWidgetAttributeMethods(this, aNode);
ViewHelpers.delegateWidgetEventMethods(this, aNode);
}
ListWidget.prototype = {
@ -728,16 +711,12 @@ ListWidget.prototype = {
/**
* A custom items container, used for displaying views like the
* FilteredSources, FilteredFunctions etc., inheriting the generic MenuContainer.
* FilteredSources, FilteredFunctions etc., inheriting the generic WidgetMethods.
*/
function ResultsPanelContainer() {
this._createItemView = this._createItemView.bind(this);
}
create({ constructor: ResultsPanelContainer, proto: MenuContainer.prototype }, {
onClick: null,
onSelect: null,
ResultsPanelContainer.prototype = Heritage.extend(WidgetMethods, {
/**
* Sets the anchor node for this container panel.
* @param nsIDOMNode aNode
@ -755,23 +734,17 @@ create({ constructor: ResultsPanelContainer, proto: MenuContainer.prototype }, {
this._panel.setAttribute("noautofocus", "true");
document.documentElement.appendChild(this._panel);
}
if (!this.node) {
this.node = new ListWidget(this._panel);
this.node.itemType = "vbox";
this.node.itemFactory = this._createItemView;
this.node.addEventListener("click", this.onClick, false);
if (!this.widget) {
this.widget = new ListWidget(this._panel);
this.widget.itemType = "vbox";
this.widget.itemFactory = this._createItemView;
}
}
// Cleanup the anchor and remove the previously created panel.
else {
if (this._panel) {
document.documentElement.removeChild(this._panel);
this._panel = null;
}
if (this.node) {
this.node.removeEventListener("click", this.onClick, false);
this.node = null;
}
this._panel.remove();
this._panel = null;
this.widget = null;
}
},
@ -781,26 +754,6 @@ create({ constructor: ResultsPanelContainer, proto: MenuContainer.prototype }, {
*/
get anchor() this._anchor,
/**
* Sets the default top, left and position params when opening the panel.
* @param object aOptions
*/
set options(aOptions) {
this._top = aOptions.top;
this._left = aOptions.left;
this._position = aOptions.position;
},
/**
* Gets the default params for when opening the panel.
* @return object
*/
get options() ({
top: this._top,
left: this._left,
position: this._position
}),
/**
* Sets the container panel hidden or visible. It's hidden by default.
* @param boolean aFlag
@ -809,7 +762,7 @@ create({ constructor: ResultsPanelContainer, proto: MenuContainer.prototype }, {
if (aFlag) {
this._panel.hidePopup();
} else {
this._panel.openPopup(this._anchor, this._position, this._left, this._top);
this._panel.openPopup(this._anchor, this.position, this.left, this.top);
this.anchor.focus();
}
},
@ -828,52 +781,30 @@ create({ constructor: ResultsPanelContainer, proto: MenuContainer.prototype }, {
clearView: function() {
this.hidden = true;
this.empty();
window.dispatchEvent(document, "Debugger:ResultsPanelContainer:ViewCleared");
},
/**
* Focuses the next found item in this container.
* Selects the next found item in this container.
* Does not change the currently focused node.
*/
focusNext: function() {
selectNext: function() {
let nextIndex = this.selectedIndex + 1;
if (nextIndex >= this.itemCount) {
nextIndex = 0;
}
this.select(this.getItemAtIndex(nextIndex));
this.selectedItem = this.getItemAtIndex(nextIndex);
},
/**
* Focuses the previously found item in this container.
* Selects the previously found item in this container.
* Does not change the currently focused node.
*/
focusPrev: function() {
selectPrev: function() {
let prevIndex = this.selectedIndex - 1;
if (prevIndex < 0) {
prevIndex = this.itemCount - 1;
}
this.select(this.getItemAtIndex(prevIndex));
},
/**
* Updates the selected item in this container.
*
* @param MenuItem | number aItem
* The item associated with the element to select.
*/
select: function(aItem) {
if (typeof aItem == "number") {
this.select(this.getItemAtIndex(aItem));
return;
}
// Update the currently selected item in this container using the
// selectedItem setter in the MenuContainer prototype chain.
this.selectedItem = aItem;
// Invoke the attached selection callback if available in any
// inheriting prototype.
if (this.onSelect) {
this.onSelect({ target: aItem.target });
}
this.selectedItem = this.getItemAtIndex(prevIndex);
},
/**
@ -892,6 +823,7 @@ create({ constructor: ResultsPanelContainer, proto: MenuContainer.prototype }, {
*/
_createItemView: function(aElementNode, aAttachment, aLabel, aValue, aDescription) {
let labelsGroup = document.createElement("hbox");
if (aDescription) {
let preLabelNode = document.createElement("label");
preLabelNode.className = "plain results-panel-item-pre";
@ -916,49 +848,7 @@ create({ constructor: ResultsPanelContainer, proto: MenuContainer.prototype }, {
_anchor: null,
_panel: null,
_position: RESULTS_PANEL_POPUP_POSITION,
_left: 0,
_top: 0
position: RESULTS_PANEL_POPUP_POSITION,
left: 0,
top: 0
});
/**
* A simple way of displaying a "Connect to..." prompt.
*/
function RemoteDebuggerPrompt() {
this.remote = {};
}
RemoteDebuggerPrompt.prototype = {
/**
* Shows the prompt and waits for a remote host and port to connect to.
*
* @param boolean aIsReconnectingFlag
* True to show the reconnect message instead of the connect request.
*/
show: function(aIsReconnectingFlag) {
let check = { value: Prefs.remoteAutoConnect };
let input = { value: Prefs.remoteHost + ":" + Prefs.remotePort };
let parts;
while (true) {
let result = Services.prompt.prompt(null,
L10N.getStr("remoteDebuggerPromptTitle"),
L10N.getStr(aIsReconnectingFlag
? "remoteDebuggerReconnectMessage"
: "remoteDebuggerPromptMessage"), input,
L10N.getStr("remoteDebuggerPromptCheck"), check);
if (!result) {
return false;
}
if ((parts = input.value.split(":")).length == 2) {
let [host, port] = parts;
if (host.length && port.length) {
this.remote = { host: host, port: port, auto: check.value };
return true;
}
}
}
}
};

Просмотреть файл

@ -7,8 +7,7 @@
/* Sources search view */
#globalsearch {
overflow-x: hidden;
overflow-y: auto;
overflow: auto;
}
/* Watch expressions view */

Просмотреть файл

@ -15,7 +15,13 @@
<?xul-overlay href="chrome://global/content/editMenuOverlay.xul"?>
<?xul-overlay href="chrome://browser/content/devtools/source-editor-overlay.xul"?>
<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
macanimationtype="document"
fullscreenbutton="true"
screenX="4" screenY="4"
width="960" height="480"
persist="screenX screenY width height sizemode">
<script type="text/javascript" src="chrome://global/content/globalOverlay.js"/>
<script type="text/javascript" src="debugger-controller.js"/>
<script type="text/javascript" src="debugger-view.js"/>

Просмотреть файл

@ -15,7 +15,6 @@ MOCHITEST_BROWSER_TESTS = \
browser_dbg_clean-exit.js \
browser_dbg_cmd.js \
browser_dbg_cmd_break.js \
$(browser_dbg_createRemote.js disabled for intermittent failures, bug 753225) \
browser_dbg_debuggerstatement.js \
browser_dbg_listtabs-01.js \
browser_dbg_listtabs-02.js \
@ -86,6 +85,8 @@ MOCHITEST_BROWSER_TESTS = \
browser_dbg_breakpoint-new-script.js \
browser_dbg_bug723069_editor-breakpoints.js \
browser_dbg_bug723071_editor-breakpoints-pane.js \
browser_dbg_bug723071_editor-breakpoints-highlight.js \
browser_dbg_bug723071_editor-breakpoints-contextmenu.js \
browser_dbg_bug740825_conditional-breakpoints-01.js \
browser_dbg_bug740825_conditional-breakpoints-02.js \
browser_dbg_bug727429_watch-expressions-01.js \

Просмотреть файл

@ -29,7 +29,7 @@ function testAddBreakpoint()
gDebugger.DebuggerController.activeThread.addOneTimeListener("framesadded", function() {
Services.tm.currentThread.dispatch({ run: function() {
var frames = gDebugger.DebuggerView.StackFrames._container._list;
var frames = gDebugger.DebuggerView.StackFrames.widget._list;
is(gDebugger.DebuggerController.activeThread.state, "paused",
"The debugger statement was reached.");

Просмотреть файл

@ -0,0 +1,463 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Test if the context menu associated with each breakpoint does what it should.
*/
const TAB_URL = EXAMPLE_URL + "browser_dbg_script-switching.html";
let gPane = null;
let gTab = null;
let gDebuggee = null;
let gDebugger = null;
let gEditor = null;
let gSources = null;
function test()
{
debug_tab_pane(TAB_URL, function(aTab, aDebuggee, aPane) {
gTab = aTab;
gDebuggee = aDebuggee;
gPane = aPane;
gDebugger = gPane.panelWin;
gEditor = gDebugger.DebuggerView.editor;
gSources = gDebugger.DebuggerView.Sources;
gSources.preferredSource = EXAMPLE_URL + "test-script-switching-02.js";
gDebugger.addEventListener("Debugger:SourceShown", function _onEvent(aEvent) {
let url = aEvent.detail.url;
if (url.indexOf("-02") != -1) {
gDebugger.removeEventListener(aEvent.type, _onEvent);
performTestWhileNotPaused();
}
});
});
function addBreakpoints(callback) {
gPane.addBreakpoint({url: gSources.values[0], line: 5}, function(cl, err) {
gPane.addBreakpoint({url: gSources.values[1], line: 6}, function(cl, err) {
gPane.addBreakpoint({url: gSources.values[1], line: 7}, function(cl, err) {
gPane.addBreakpoint({url: gSources.values[1], line: 8}, function(cl, err) {
gPane.addBreakpoint({url: gSources.values[1], line: 9}, function(cl, err) {
callback();
});
});
});
});
});
}
function performTestWhileNotPaused()
{
info("Performing test while not paused...");
addBreakpoints(function() {
initialChecks();
checkBreakpointToggleSelf(0, function() {
checkBreakpointToggleOthers(0, function() {
checkBreakpointToggleSelf(1, function() {
checkBreakpointToggleOthers(1, function() {
checkBreakpointToggleSelf(2, function() {
checkBreakpointToggleOthers(2, function() {
checkBreakpointToggleSelf(3, function() {
checkBreakpointToggleOthers(3, function() {
checkBreakpointToggleSelf(4, function() {
checkBreakpointToggleOthers(4, function() {
testDeleteAll(function() {
performTestWhilePaused();
});
});
});
});
});
});
});
});
});
});
});
});
}
function performTestWhilePaused()
{
info("Performing test while paused...");
addBreakpoints(function() {
initialChecks();
pauseAndCheck(function() {
checkBreakpointToggleSelf(0, function() {
checkBreakpointToggleOthers(0, function() {
checkBreakpointToggleSelf(1, function() {
checkBreakpointToggleOthers(1, function() {
checkBreakpointToggleSelf(2, function() {
checkBreakpointToggleOthers(2, function() {
checkBreakpointToggleSelf(3, function() {
checkBreakpointToggleOthers(3, function() {
checkBreakpointToggleSelf(4, function() {
checkBreakpointToggleOthers(4, function() {
testDeleteAll(function() {
closeDebuggerAndFinish();
});
}, true);
});
}, true);
});
}, true);
});
}, true);
});
}, true);
});
});
});
}
function pauseAndCheck(callback) {
gDebugger.gThreadClient.addOneTimeListener("resumed", function() {
pauseAndCallback(function() {
is(gSources.selectedLabel, "test-script-switching-01.js",
"The currently selected source is incorrect (1).");
is(gSources.selectedIndex, 1,
"The currently selected source is incorrect (2).");
waitForCaretPos(4, function() {
ok(true, "The editor location is correct after pausing.");
callback();
});
});
});
}
function pauseAndCallback(callback) {
let scriptShown = false;
let framesadded = false;
let testContinued = false;
gDebugger.addEventListener("Debugger:SourceShown", function _onEvent(aEvent) {
let url = aEvent.detail.url;
if (url.indexOf("-01") != -1) {
gDebugger.removeEventListener(aEvent.type, _onEvent);
scriptShown = true;
executeSoon(continueTest);
}
});
gDebugger.gThreadClient.addOneTimeListener("framesadded", function() {
framesadded = true;
executeSoon(continueTest);
});
function continueTest() {
if (scriptShown && framesadded && !testContinued) {
testContinued = true;
callback();
}
}
EventUtils.sendMouseEvent({ type: "click" },
gDebuggee.document.querySelector("button"),
gDebuggee.window);
}
function initialChecks() {
for (let source in gSources) {
for (let breakpoint in source) {
let { sourceLocation: url, lineNumber: line, actor } = breakpoint.attachment;
ok(gPane.getBreakpoint(url, line),
"All breakpoint items should have corresponding clients (1).");
ok(breakpoint.attachment.actor,
"All breakpoint items should have corresponding clients (2).");
is(!!breakpoint.attachment.disabled, false,
"All breakpoints should initially be enabled.");
let prefix = "bp-cMenu-"; // "breakpoints context menu"
let enableSelfId = prefix + "enableSelf-" + actor + "-menuitem";
let disableSelfId = prefix + "disableSelf-" + actor + "-menuitem";
is(gDebugger.document.getElementById(enableSelfId).getAttribute("hidden"), "true",
"The 'Enable breakpoint' context menu item should initially be hidden'.");
ok(!gDebugger.document.getElementById(disableSelfId).hasAttribute("hidden"),
"The 'Disable breakpoint' context menu item should initially not be hidden'.");
is(breakpoint.attachment.view.checkbox.getAttribute("checked"), "true",
"All breakpoints should initially have a checked checkbox.");
}
}
}
function checkBreakpointToggleSelf(index, callback) {
EventUtils.sendMouseEvent({ type: "click" },
gDebugger.document.querySelectorAll(".dbg-breakpoint")[index],
gDebugger);
let selectedBreakpoint = gSources.selectedBreakpointItem;
let { sourceLocation: url, lineNumber: line, actor } = selectedBreakpoint.attachment;
ok(gPane.getBreakpoint(url, line),
"There should be a breakpoint client available (1).");
ok(gSources.selectedBreakpointClient,
"There should be a breakpoint client available (2).");
is(!!selectedBreakpoint.attachment.disabled, false,
"The breakpoint should not be disabled yet.");
let prefix = "bp-cMenu-"; // "breakpoints context menu"
let enableSelfId = prefix + "enableSelf-" + actor + "-menuitem";
let disableSelfId = prefix + "disableSelf-" + actor + "-menuitem";
is(gDebugger.document.getElementById(enableSelfId).getAttribute("hidden"), "true",
"The 'Enable breakpoint' context menu item should be hidden'.");
ok(!gDebugger.document.getElementById(disableSelfId).hasAttribute("hidden"),
"The 'Disable breakpoint' context menu item should not be hidden'.");
waitForCaretPos(selectedBreakpoint.attachment.lineNumber - 1, function() {
ok(true, "The editor location is correct (" + index + ").");
gDebugger.addEventListener("Debugger:BreakpointHidden", function _onEvent(aEvent) {
gDebugger.removeEventListener(aEvent.type, _onEvent);
ok(!gPane.getBreakpoint(url, line),
"There should be no breakpoint client available (2).");
ok(!gSources.selectedBreakpointClient,
"There should be no breakpoint client available (3).");
gDebugger.addEventListener("Debugger:BreakpointShown", function _onEvent(aEvent) {
gDebugger.removeEventListener(aEvent.type, _onEvent);
ok(gPane.getBreakpoint(url, line),
"There should be a breakpoint client available (4).");
ok(gSources.selectedBreakpointClient,
"There should be a breakpoint client available (5).");
callback();
});
// Test re-disabling this breakpoint.
executeSoon(function() {
gSources._onEnableSelf(selectedBreakpoint.attachment.actor);
is(selectedBreakpoint.attachment.disabled, false,
"The current breakpoint should now be enabled.")
is(gDebugger.document.getElementById(enableSelfId).getAttribute("hidden"), "true",
"The 'Enable breakpoint' context menu item should be hidden'.");
ok(!gDebugger.document.getElementById(disableSelfId).hasAttribute("hidden"),
"The 'Disable breakpoint' context menu item should not be hidden'.");
ok(selectedBreakpoint.attachment.view.checkbox.hasAttribute("checked"),
"The breakpoint should now be checked.");
});
});
// Test disabling this breakpoint.
executeSoon(function() {
gSources._onDisableSelf(selectedBreakpoint.attachment.actor);
is(selectedBreakpoint.attachment.disabled, true,
"The current breakpoint should now be disabled.")
ok(!gDebugger.document.getElementById(enableSelfId).hasAttribute("hidden"),
"The 'Enable breakpoint' context menu item should not be hidden'.");
is(gDebugger.document.getElementById(disableSelfId).getAttribute("hidden"), "true",
"The 'Disable breakpoint' context menu item should be hidden'.");
ok(!selectedBreakpoint.attachment.view.checkbox.hasAttribute("checked"),
"The breakpoint should now be unchecked.");
});
});
}
function checkBreakpointToggleOthers(index, callback, whilePaused) {
let count = 4
gDebugger.addEventListener("Debugger:BreakpointHidden", function _onEvent(aEvent) {
info(count + " breakpoints remain to be hidden...");
if (!(--count)) {
gDebugger.removeEventListener(aEvent.type, _onEvent);
ok(true, "All breakpoints except one were hidden.");
let selectedBreakpoint = gSources.selectedBreakpointItem;
let { sourceLocation: url, lineNumber: line, actor } = selectedBreakpoint.attachment;
ok(gPane.getBreakpoint(url, line),
"There should be a breakpoint client available (6).");
ok(gSources.selectedBreakpointClient,
"There should be a breakpoint client available (7).");
is(!!selectedBreakpoint.attachment.disabled, false,
"The targetted breakpoint should not have been disabled.");
for (let source in gSources) {
for (let otherBreakpoint in source) {
if (otherBreakpoint != selectedBreakpoint) {
ok(!gPane.getBreakpoint(
otherBreakpoint.attachment.sourceLocation,
otherBreakpoint.attachment.lineNumber),
"There should be no breakpoint client for a disabled breakpoint (8).");
is(otherBreakpoint.attachment.disabled, true,
"Non-targetted breakpoints should have been disabled (9).");
}
}
}
count = 4;
gDebugger.addEventListener("Debugger:BreakpointShown", function _onEvent(aEvent) {
info(count + " breakpoints remain to be reshown...");
if (!(--count)) {
gDebugger.removeEventListener(aEvent.type, _onEvent);
ok(true, "All breakpoints are now reshown.");
for (let source in gSources) {
for (let someBreakpoint in source) {
ok(gPane.getBreakpoint(
someBreakpoint.attachment.sourceLocation,
someBreakpoint.attachment.lineNumber),
"There should be a breakpoint client for all enabled breakpoints (10).");
is(someBreakpoint.attachment.disabled, false,
"All breakpoints should now have been enabled (11).");
}
}
count = 5;
gDebugger.addEventListener("Debugger:BreakpointHidden", function _onEvent(aEvent) {
info(count + " breakpoints remain to be rehidden...");
if (!(--count)) {
gDebugger.removeEventListener(aEvent.type, _onEvent);
ok(true, "All breakpoints are now rehidden.");
for (let source in gSources) {
for (let someBreakpoint in source) {
ok(!gPane.getBreakpoint(
someBreakpoint.attachment.sourceLocation,
someBreakpoint.attachment.lineNumber),
"There should be no breakpoint client for a disabled breakpoint (12).");
is(someBreakpoint.attachment.disabled, true,
"All breakpoints should now have been disabled (13).");
}
}
count = 5;
gDebugger.addEventListener("Debugger:BreakpointShown", function _onEvent(aEvent) {
info(count + " breakpoints remain to be reshown...");
if (!(--count)) {
gDebugger.removeEventListener(aEvent.type, _onEvent);
ok(true, "All breakpoints are now rehidden.");
for (let source in gSources) {
for (let someBreakpoint in source) {
ok(gPane.getBreakpoint(
someBreakpoint.attachment.sourceLocation,
someBreakpoint.attachment.lineNumber),
"There should be a breakpoint client for all enabled breakpoints (14).");
is(someBreakpoint.attachment.disabled, false,
"All breakpoints should now have been enabled (15).");
}
}
// Done.
if (!whilePaused) {
gDebugger.gThreadClient.addOneTimeListener("resumed", callback);
} else {
callback();
}
}
});
// Test re-enabling all breakpoints.
enableAll();
}
});
// Test disabling all breakpoints.
if (!whilePaused) {
gDebugger.gThreadClient.addOneTimeListener("resumed", disableAll);
} else {
disableAll();
}
}
});
// Test re-enabling other breakpoints.
enableOthers();
}
});
// Test disabling other breakpoints.
if (!whilePaused) {
gDebugger.gThreadClient.addOneTimeListener("resumed", disableOthers);
} else {
disableOthers();
}
}
function testDeleteAll(callback) {
let count = 5
gDebugger.addEventListener("Debugger:BreakpointHidden", function _onEvent(aEvent) {
info(count + " breakpoints remain to be hidden...");
if (!(--count)) {
gDebugger.removeEventListener(aEvent.type, _onEvent);
ok(true, "All breakpoints were hidden.");
ok(!gSources.selectedBreakpointItem,
"There should be no breakpoint item available (16).");
ok(!gSources.selectedBreakpointClient,
"There should be no breakpoint client available (17).");
for (let source in gSources) {
for (let otherBreakpoint in source) {
ok(false, "It's a trap!");
}
}
// Done.
callback();
}
});
// Test deleting all breakpoints.
deleteAll();
}
function disableOthers() {
gSources._onDisableOthers(gSources.selectedBreakpointItem.attachment.actor);
}
function enableOthers() {
gSources._onEnableOthers(gSources.selectedBreakpointItem.attachment.actor);
}
function disableAll() {
gSources._onDisableAll(gSources.selectedBreakpointItem.attachment.actor);
}
function enableAll() {
gSources._onEnableAll(gSources.selectedBreakpointItem.attachment.actor);
}
function deleteAll() {
gSources._onDeleteAll(gSources.selectedBreakpointItem.attachment.actor);
}
function waitForCaretPos(number, callback)
{
// Poll every few milliseconds until the source editor line is active.
let count = 0;
let intervalID = window.setInterval(function() {
info("count: " + count + " ");
if (++count > 50) {
ok(false, "Timed out while polling for the line.");
window.clearInterval(intervalID);
return closeDebuggerAndFinish();
}
if (gEditor.getCaretPosition().line != number) {
return;
}
// We got the source editor at the expected line, it's safe to callback.
window.clearInterval(intervalID);
callback();
}, 100);
}
registerCleanupFunction(function() {
removeTab(gTab);
gPane = null;
gTab = null;
gDebuggee = null;
gDebugger = null;
gEditor = null;
gSources = null;
});
}

Просмотреть файл

@ -0,0 +1,221 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Test if breakpoints are highlighted when they should.
*/
const TAB_URL = EXAMPLE_URL + "browser_dbg_script-switching.html";
let gPane = null;
let gTab = null;
let gDebuggee = null;
let gDebugger = null;
let gEditor = null;
let gSources = null;
function test()
{
debug_tab_pane(TAB_URL, function(aTab, aDebuggee, aPane) {
gTab = aTab;
gDebuggee = aDebuggee;
gPane = aPane;
gDebugger = gPane.panelWin;
gEditor = gDebugger.DebuggerView.editor;
gSources = gDebugger.DebuggerView.Sources;
gSources.preferredSource = EXAMPLE_URL + "test-script-switching-02.js";
gDebugger.addEventListener("Debugger:SourceShown", function _onEvent(aEvent) {
let url = aEvent.detail.url;
if (url.indexOf("-02") != -1) {
gDebugger.removeEventListener(aEvent.type, _onEvent);
performTest();
}
});
});
function performTest()
{
initialChecks();
gPane.addBreakpoint({url: gSources.values[0], line: 5}, function(cl, err) {
initialChecks();
gPane.addBreakpoint({url: gSources.values[1], line: 6}, function(cl, err) {
initialChecks();
gPane.addBreakpoint({url: gSources.values[1], line: 7}, function(cl, err) {
initialChecks();
gPane.addBreakpoint({url: gSources.values[1], line: 8}, function(cl, err) {
initialChecks();
gPane.addBreakpoint({url: gSources.values[1], line: 9}, function(cl, err) {
initialChecks();
testHighlight1();
});
});
});
});
});
}
function initialChecks() {
is(gSources.selectedValue, gSources.values[1],
"The currently selected source is incorrect (0).");
is(gEditor.getCaretPosition().line, 0,
"The editor caret line was incorrect (0).");
is(gEditor.getCaretPosition().col, 0,
"The editor caret column was incorrect (0).");
}
function testHighlight1() {
gSources.highlightBreakpoint(gSources.values[0], 5);
checkHighlight(gSources.values[0], 5);
is(gSources.selectedValue, gSources.values[1],
"The currently selected source is incorrect (1).");
is(gEditor.getCaretPosition().line, 0,
"The editor caret line was incorrect (1).");
is(gEditor.getCaretPosition().col, 0,
"The editor caret column was incorrect (1).");
EventUtils.sendMouseEvent({ type: "click" },
gDebugger.document.querySelectorAll(".dbg-breakpoint")[0],
gDebugger);
waitForCaretPos(4, function() {
ok(true, "The editor location is correct (1).");
testHighlight2();
});
}
function testHighlight2() {
gSources.highlightBreakpoint(gSources.values[1], 6);
checkHighlight(gSources.values[1], 6);
is(gSources.selectedValue, gSources.values[0],
"The currently selected source is incorrect (2).");
is(gEditor.getCaretPosition().line, 4,
"The editor caret line was incorrect (2).");
is(gEditor.getCaretPosition().col, 0,
"The editor caret column was incorrect (2).");
EventUtils.sendMouseEvent({ type: "click" },
gDebugger.document.querySelectorAll(".dbg-breakpoint")[1],
gDebugger);
waitForCaretPos(5, function() {
ok(true, "The editor location is correct (2).");
testHighlight3();
});
}
function testHighlight3() {
gSources.highlightBreakpoint(gSources.values[1], 7);
checkHighlight(gSources.values[1], 7);
is(gSources.selectedValue, gSources.values[1],
"The currently selected source is incorrect (3).");
is(gEditor.getCaretPosition().line, 5,
"The editor caret line was incorrect (3).");
is(gEditor.getCaretPosition().col, 0,
"The editor caret column was incorrect (3).");
EventUtils.sendMouseEvent({ type: "click" },
gDebugger.document.querySelectorAll(".dbg-breakpoint")[2],
gDebugger);
waitForCaretPos(6, function() {
ok(true, "The editor location is correct (3).");
testHighlight4();
});
}
function testHighlight4() {
gSources.highlightBreakpoint(gSources.values[1], 8);
checkHighlight(gSources.values[1], 8);
is(gSources.selectedValue, gSources.values[1],
"The currently selected source is incorrect (4).");
is(gEditor.getCaretPosition().line, 6,
"The editor caret line was incorrect (4).");
is(gEditor.getCaretPosition().col, 0,
"The editor caret column was incorrect (4).");
EventUtils.sendMouseEvent({ type: "click" },
gDebugger.document.querySelectorAll(".dbg-breakpoint")[3],
gDebugger);
waitForCaretPos(7, function() {
ok(true, "The editor location is correct (4).");
testHighlight5();
});
}
function testHighlight5() {
gSources.highlightBreakpoint(gSources.values[1], 9);
checkHighlight(gSources.values[1], 9);
is(gSources.selectedValue, gSources.values[1],
"The currently selected source is incorrect (5).");
is(gEditor.getCaretPosition().line, 7,
"The editor caret line was incorrect (5).");
is(gEditor.getCaretPosition().col, 0,
"The editor caret column was incorrect (5).");
EventUtils.sendMouseEvent({ type: "click" },
gDebugger.document.querySelectorAll(".dbg-breakpoint")[4],
gDebugger);
waitForCaretPos(8, function() {
ok(true, "The editor location is correct (5).");
closeDebuggerAndFinish();
});
}
function checkHighlight(aUrl, aLine) {
is(gSources.selectedBreakpointItem, gSources.getBreakpoint(aUrl, aLine),
"The currently selected breakpoint item is incorrect.");
is(gSources.selectedBreakpointClient, gPane.getBreakpoint(aUrl, aLine),
"The currently selected breakpoint client is incorrect.");
is(gSources.selectedBreakpointItem.attachment.sourceLocation, aUrl,
"The selected breakpoint item's source location attachment is incorrect.");
is(gSources.selectedBreakpointItem.attachment.lineNumber, aLine,
"The selected breakpoint item's source line number is incorrect.");
ok(gSources.selectedBreakpointItem.target.classList.contains("selected"),
"The selected breakpoint item's target should have a selected class.");
}
function waitForCaretPos(number, callback)
{
// Poll every few milliseconds until the source editor line is active.
let count = 0;
let intervalID = window.setInterval(function() {
info("count: " + count + " ");
if (++count > 50) {
ok(false, "Timed out while polling for the line.");
window.clearInterval(intervalID);
return closeDebuggerAndFinish();
}
if (gEditor.getCaretPosition().line != number) {
return;
}
// We got the source editor at the expected line, it's safe to callback.
window.clearInterval(intervalID);
callback();
}, 100);
}
registerCleanupFunction(function() {
removeTab(gTab);
gPane = null;
gTab = null;
gDebuggee = null;
gDebugger = null;
gEditor = null;
gSources = null;
});
}

Просмотреть файл

@ -85,8 +85,8 @@ function test()
ok(!gPane.getBreakpoint("chocolate", 3), "getBreakpoint('chocolate', 3) returns falsey");
is(gEditor.getBreakpoints().length, 0, "no breakpoints in the editor");
gBreakpointsParent = gSources._container._parent;
gBreakpointsList = gSources._container._list;
gBreakpointsParent = gSources.widget._parent;
gBreakpointsList = gSources.widget._list;
is(gBreakpointsParent.childNodes.length, 1, // one sources list
"Found junk in the breakpoints container.");
@ -270,7 +270,7 @@ function test()
"Breakpoint element " + id + " found successfully.");
is(line.getAttribute("value"), this.line,
"The expected information wasn't found in the breakpoint element.");
is(text.getAttribute("value"), gDebugger.DebuggerView.getEditorLine(this.line - 1).trim(),
is(text.getAttribute("value"), gDebugger.DebuggerView.getEditorLineText(this.line - 1).trim(),
"The expected line text wasn't found in the breakpoint element.");
is(check.getAttribute("checked"), "true",
"The breakpoint enable checkbox is checked as expected.");

Просмотреть файл

@ -28,7 +28,7 @@ function test()
function performTest()
{
is(gWatch.getExpressions().length, 0,
is(gWatch.getAllStrings().length, 0,
"There should initially be no watch expressions");
addAndCheckExpressions(1, 0, "a");
@ -41,26 +41,27 @@ function test()
addAndCheckExpressions(2, 0, "", true);
gDebugger.editor.focus();
is(gWatch.getExpressions().length, 1,
is(gWatch.getAllStrings().length, 1,
"Empty watch expressions are automatically removed");
addAndCheckExpressions(2, 0, "a", true);
gDebugger.editor.focus();
is(gWatch.getExpressions().length, 1,
is(gWatch.getAllStrings().length, 1,
"Duplicate watch expressions are automatically removed");
addAndCheckExpressions(2, 0, "a\t", true);
addAndCheckExpressions(2, 0, "a\r", true);
addAndCheckExpressions(2, 0, "a\n", true);
gDebugger.editor.focus();
is(gWatch.getExpressions().length, 1,
is(gWatch.getAllStrings().length, 1,
"Duplicate watch expressions are automatically removed");
addAndCheckExpressions(2, 0, "\ta", true);
addAndCheckExpressions(2, 0, "\ra", true);
addAndCheckExpressions(2, 0, "\na", true);
gDebugger.editor.focus();
is(gWatch.getExpressions().length, 1,
is(gWatch.getAllStrings().length, 1,
"Duplicate watch expressions are automatically removed");
@ -72,11 +73,11 @@ function test()
gWatch.getItemAtIndex(0).attachment.closeNode,
gDebugger);
is(gWatch.getExpressions().length, 2,
is(gWatch.getAllStrings().length, 2,
"Watch expressions are removed when the close button is pressed");
is(gWatch.getExpressions()[0], "bazΩΩka",
is(gWatch.getAllStrings()[0], "bazΩΩka",
"The expression at index " + 0 + " should be correct (1)");
is(gWatch.getExpressions()[1], "a",
is(gWatch.getAllStrings()[1], "a",
"The expression at index " + 1 + " should be correct (2)");
@ -84,9 +85,9 @@ function test()
gWatch.getItemAtIndex(0).attachment.closeNode,
gDebugger);
is(gWatch.getExpressions().length, 1,
is(gWatch.getAllStrings().length, 1,
"Watch expressions are removed when the close button is pressed");
is(gWatch.getExpressions()[0], "a",
is(gWatch.getAllStrings()[0], "a",
"The expression at index " + 0 + " should be correct (3)");
@ -94,15 +95,15 @@ function test()
gWatch.getItemAtIndex(0).attachment.closeNode,
gDebugger);
is(gWatch.getExpressions().length, 0,
is(gWatch.getAllStrings().length, 0,
"Watch expressions are removed when the close button is pressed");
EventUtils.sendMouseEvent({ type: "click" },
gWatch._container._parent,
gWatch.widget._parent,
gDebugger);
is(gWatch.getExpressions().length, 1,
is(gWatch.getAllStrings().length, 1,
"Watch expressions are added when the view container is pressed");
@ -118,8 +119,7 @@ function test()
gDebugger.editor.focus();
let id = gWatch.getItemAtIndex(index).attachment.id;
let element = gDebugger.document.getElementById("expression-" + id);
let element = gWatch.getItemAtIndex(index).target;
is(gWatch.getItemAtIndex(index).attachment.initialExpression, "",
"The initial expression at index " + index + " should be correct (1)");
@ -131,43 +131,38 @@ function test()
is(gWatch.getItemForElement(element).attachment.currentExpression, string,
"The expression at index " + index + " should be correct (2)");
is(gWatch.getExpression(index), string,
is(gWatch.getString(index), string,
"The expression at index " + index + " should be correct (3)");
is(gWatch.getExpressions()[index], string,
is(gWatch.getAllStrings()[index], string,
"The expression at index " + index + " should be correct (4)");
}
function addAndCheckExpressions(total, index, string, noBlur) {
gWatch.addExpression(string);
is(gWatch.getExpressions().length, total,
is(gWatch.getAllStrings().length, total,
"There should be " + total + " watch expressions available (1)");
is(gWatch.itemCount, total,
"There should be " + total + " watch expressions available (2)");
ok(gWatch.getItemAtIndex(index),
"The expression at index " + index + " should be available");
ok(gWatch.getItemAtIndex(index).attachment.id,
"The expression at index " + index + " should have an id");
is(gWatch.getItemAtIndex(index).attachment.initialExpression, string,
"The expression at index " + index + " should have an initial expression");
let id = gWatch.getItemAtIndex(index).attachment.id;
let element = gDebugger.document.getElementById("expression-" + id);
let element = gWatch.getItemAtIndex(index).target;
ok(element,
"Three should be a new expression item in the view");
"There should be a new expression item in the view");
ok(gWatch.getItemForElement(element),
"The watch expression item should be accessible");
is(gWatch.getItemForElement(element), gWatch.getItemAtIndex(index),
"The correct watch expression item was accessed");
ok(gWatch.getItemAtIndex(index) instanceof gDebugger.MenuItem,
ok(gWatch.widget.getItemAtIndex(index) instanceof XULElement,
"The correct watch expression element was accessed (1)");
ok(gWatch._container.getItemAtIndex(index) instanceof XULElement,
is(element, gWatch.widget.getItemAtIndex(index),
"The correct watch expression element was accessed (2)");
is(element, gWatch._container.getItemAtIndex(index),
"The correct watch expression element was accessed (3)");
is(gWatch.getItemForElement(element).attachment.arrowNode.hidden, false,
"The arrow node should be visible");
@ -176,12 +171,12 @@ function test()
is(gWatch.getItemForElement(element).attachment.inputNode.getAttribute("focused"), "true",
"The textbox input should be focused");
is(gWatch._variables.scrollTop, 0,
is(gDebugger.DebuggerView.Variables.parentNode.scrollTop, 0,
"The variables view should be scrolled to top");
is(gWatch._cache[0], gWatch.getItemAtIndex(index),
is(gWatch.orderedItems[0], gWatch.getItemAtIndex(index),
"The correct watch expression was added to the cache (1)");
is(gWatch._cache[0], gWatch.getItemForElement(element),
is(gWatch.orderedItems[0], gWatch.getItemForElement(element),
"The correct watch expression was added to the cache (2)");
if (!noBlur) {
@ -197,30 +192,27 @@ function test()
is(gWatch.getItemForElement(element).attachment.currentExpression, string,
"The expression at index " + index + " should be correct (2)");
is(gWatch.getExpression(index), string,
is(gWatch.getString(index), string,
"The expression at index " + index + " should be correct (3)");
is(gWatch.getExpressions()[index], string,
is(gWatch.getAllStrings()[index], string,
"The expression at index " + index + " should be correct (4)");
}
}
function removeAndCheckExpression(total, index, string) {
gWatch.removeExpressionAt(index);
gWatch.removeAt(index);
is(gWatch.getExpressions().length, total,
is(gWatch.getAllStrings().length, total,
"There should be " + total + " watch expressions available (1)");
is(gWatch.itemCount, total,
"There should be " + total + " watch expressions available (2)");
ok(gWatch.getItemAtIndex(index),
"The expression at index " + index + " should still be available");
ok(gWatch.getItemAtIndex(index).attachment.id,
"The expression at index " + index + " should still have an id");
is(gWatch.getItemAtIndex(index).attachment.initialExpression, string,
"The expression at index " + index + " should still have an initial expression");
let id = gWatch.getItemAtIndex(index).attachment.id;
let element = gDebugger.document.getElementById("expression-" + id);
let element = gWatch.getItemAtIndex(index).target;
is(gWatch.getItemAtIndex(index).attachment.initialExpression, string,
"The initial expression at index " + index + " should be correct (1)");
@ -232,9 +224,9 @@ function test()
is(gWatch.getItemForElement(element).attachment.currentExpression, string,
"The expression at index " + index + " should be correct (2)");
is(gWatch.getExpression(index), string,
is(gWatch.getString(index), string,
"The expression at index " + index + " should be correct (3)");
is(gWatch.getExpressions()[index], string,
is(gWatch.getAllStrings()[index], string,
"The expression at index " + index + " should be correct (4)");
}

Просмотреть файл

@ -62,9 +62,9 @@ function test()
function performTest()
{
is(gWatch._container._parent.querySelectorAll(".dbg-expression[hidden=true]").length, 0,
is(gWatch.widget._parent.querySelectorAll(".dbg-expression[hidden=true]").length, 0,
"There should be 0 hidden nodes in the watch expressions container");
is(gWatch._container._parent.querySelectorAll(".dbg-expression:not([hidden=true])").length, 27,
is(gWatch.widget._parent.querySelectorAll(".dbg-expression:not([hidden=true])").length, 27,
"There should be 27 visible nodes in the watch expressions container");
test1(function() {
@ -90,9 +90,9 @@ function test()
function finishTest()
{
is(gWatch._container._parent.querySelectorAll(".dbg-expression[hidden=true]").length, 0,
is(gWatch.widget._parent.querySelectorAll(".dbg-expression[hidden=true]").length, 0,
"There should be 0 hidden nodes in the watch expressions container");
is(gWatch._container._parent.querySelectorAll(".dbg-expression:not([hidden=true])").length, 27,
is(gWatch.widget._parent.querySelectorAll(".dbg-expression:not([hidden=true])").length, 27,
"There should be 27 visible nodes in the watch expressions container");
closeDebuggerAndFinish();
@ -104,7 +104,7 @@ function test()
checkWatchExpressions("ReferenceError: a is not defined",
{ type: "object", class: "Object" },
{ type: "object", class: "String" },
undefined,
{ type: "undefined" },
26);
callback();
});
@ -116,9 +116,9 @@ function test()
function test2(callback) {
waitForWatchExpressions(function() {
info("Performing test2");
checkWatchExpressions(undefined,
checkWatchExpressions({ type: "undefined" },
{ type: "object", class: "Window" },
undefined,
{ type: "undefined" },
"sensational",
26);
callback();
@ -133,7 +133,7 @@ function test()
info("Performing test3");
checkWatchExpressions({ type: "object", class: "Object" },
{ type: "object", class: "Window" },
undefined,
{ type: "undefined" },
"sensational",
26);
callback();
@ -148,7 +148,7 @@ function test()
info("Performing test4");
checkWatchExpressions(5,
{ type: "object", class: "Window" },
undefined,
{ type: "undefined" },
"sensational",
27);
callback();
@ -164,7 +164,7 @@ function test()
info("Performing test5");
checkWatchExpressions(5,
{ type: "object", class: "Window" },
undefined,
{ type: "undefined" },
"sensational",
27);
callback();
@ -180,7 +180,7 @@ function test()
info("Performing test6");
checkWatchExpressions(5,
{ type: "object", class: "Window" },
undefined,
{ type: "undefined" },
"sensational",
27);
callback();
@ -196,7 +196,7 @@ function test()
info("Performing test7");
checkWatchExpressions(5,
{ type: "object", class: "Window" },
undefined,
{ type: "undefined" },
"sensational",
27);
callback();
@ -212,7 +212,7 @@ function test()
info("Performing test8");
checkWatchExpressions(5,
{ type: "object", class: "Window" },
undefined,
{ type: "undefined" },
"sensational",
27);
callback();
@ -253,9 +253,9 @@ function test()
expected_arguments,
total)
{
is(gWatch._container._parent.querySelectorAll(".dbg-expression[hidden=true]").length, total,
is(gWatch.widget._parent.querySelectorAll(".dbg-expression[hidden=true]").length, total,
"There should be " + total + " hidden nodes in the watch expressions container");
is(gWatch._container._parent.querySelectorAll(".dbg-expression:not([hidden=true])").length, 0,
is(gWatch.widget._parent.querySelectorAll(".dbg-expression:not([hidden=true])").length, 0,
"There should be 0 visible nodes in the watch expressions container");
let label = gDebugger.L10N.getStr("watchExpressionsScopeLabel");
@ -355,13 +355,24 @@ function test()
is(w12.value.type, "object", "The eleventh value type is correct");
is(w12.value.class, "Array", "The twelfth value class is correct");
is(w13.value, false, "The 13th value is correct");
is(w14.value, expected_arguments, "The 14th value is correct");
if (typeof expected_arguments == "object") {
is(w14.value.type, expected_arguments.type, "The 14th value type is correct");
is(w14.value.class, expected_arguments.class, "The 14th value class is correct");
} else {
is(w14.value, expected_arguments, "The 14th value is correct");
}
is(w15.value, "SyntaxError: unterminated string literal", "The 15th value is correct");
is(w16.value, "SyntaxError: unterminated string literal", "The 16th value is correct");
is(w17.value, "URIError: malformed URI sequence", "The 17th value is correct");
is(w18.value, undefined, "The 18th value is correct");
is(w19.value, undefined, "The 19th value is correct");
is(w18.value.type, "undefined", "The 18th value type is correct");
is(w18.value.class, undefined, "The 18th value class is correct");
is(w19.value.type, "undefined", "The 19th value type is correct");
is(w19.value.class, undefined, "The 19th value class is correct");
is(w20.value, "SyntaxError: syntax error", "The 20th value is correct");
is(w21.value, "SyntaxError: syntax error", "The 21th value is correct");
is(w22.value, "TypeError: (intermediate value).foo is not a function", "The 22th value is correct");

Просмотреть файл

@ -137,16 +137,16 @@ function test()
isnot(gSources.selectedItem, null,
"There should be a selected script in the scripts pane.")
is(gSources.selectedBreakpoint, null,
is(gSources.selectedBreakpointItem, null,
"There should be no selected breakpoint in the scripts pane.")
is(gSources.selectedClient, null,
is(gSources.selectedBreakpointClient, null,
"There should be no selected client in the scripts pane.");
is(gSources._conditionalPopupVisible, false,
"The breakpoint conditional expression popup should not be shown.");
is(gDebugger.DebuggerView.StackFrames._container._list.querySelectorAll(".dbg-stackframe").length, 0,
is(gDebugger.DebuggerView.StackFrames.widget._list.querySelectorAll(".dbg-stackframe").length, 0,
"There should be no visible stackframes.");
is(gDebugger.DebuggerView.Sources._container._list.querySelectorAll(".dbg-breakpoint").length, 13,
is(gDebugger.DebuggerView.Sources.widget._list.querySelectorAll(".dbg-breakpoint").length, 13,
"There should be thirteen visible breakpoints.");
testReload();
@ -159,7 +159,7 @@ function test()
{
resume(line, function() {
waitForCaretPos(line - 1, function() {
testBreakpoint(gSources.selectedBreakpoint, gSources.selectedClient, url, line, true);
testBreakpoint(gSources.selectedBreakpointItem, gSources.selectedBreakpointClient, url, line, true);
callback();
});
});
@ -281,9 +281,9 @@ function test()
isnot(gSources.selectedItem, null,
"There should be a selected script in the scripts pane.")
is(gSources.selectedBreakpoint, null,
is(gSources.selectedBreakpointItem, null,
"There should be no selected breakpoint in the scripts pane.")
is(gSources.selectedClient, null,
is(gSources.selectedBreakpointClient, null,
"There should be no selected client in the scripts pane.");
is(gSources._conditionalPopupVisible, false,
"The breakpoint conditional expression popup should not be shown.");
@ -330,8 +330,8 @@ function test()
window.clearInterval(intervalID);
return closeDebuggerAndFinish();
}
if ((gSources.selectedClient !== expected) &&
(gSources.selectedClient || bogusClient).location.line !== expected) {
if ((gSources.selectedBreakpointClient !== expected) &&
(gSources.selectedBreakpointClient || bogusClient).location.line !== expected) {
return;
}
// We arrived at the expected line, it's safe to callback.
@ -351,7 +351,7 @@ function test()
window.clearInterval(intervalID);
return closeDebuggerAndFinish();
}
if (gSources._container._list.querySelectorAll(".dbg-breakpoint").length != total) {
if (gSources.widget._list.querySelectorAll(".dbg-breakpoint").length != total) {
return;
}
// We got all the breakpoints, it's safe to callback.

Просмотреть файл

@ -92,8 +92,8 @@ function test()
waitForBreakpoint(12, function() {
waitForCaretPos(10, function() {
waitForPopup(false, function() {
testBreakpoint(gSources.selectedBreakpoint,
gSources.selectedClient,
testBreakpoint(gSources.selectedBreakpointItem,
gSources.selectedBreakpointClient,
gSources.selectedValue, 12, false, false, false);
executeSoon(addBreakpoint2);
@ -110,8 +110,8 @@ function test()
waitForBreakpoint(13, function() {
waitForCaretPos(12, function() {
waitForPopup(false, function() {
testBreakpoint(gSources.selectedBreakpoint,
gSources.selectedClient,
testBreakpoint(gSources.selectedBreakpointItem,
gSources.selectedBreakpointClient,
gSources.selectedValue, 13, false, false, true);
executeSoon(modBreakpoint2);
@ -128,8 +128,8 @@ function test()
waitForBreakpoint(13, function() {
waitForCaretPos(12, function() {
waitForPopup(true, function() {
testBreakpoint(gSources.selectedBreakpoint,
gSources.selectedClient,
testBreakpoint(gSources.selectedBreakpointItem,
gSources.selectedBreakpointClient,
gSources.selectedValue, 13, true, true, true);
executeSoon(addBreakpoint3);
@ -146,8 +146,8 @@ function test()
waitForBreakpoint(14, function() {
waitForCaretPos(13, function() {
waitForPopup(true, function() {
testBreakpoint(gSources.selectedBreakpoint,
gSources.selectedClient,
testBreakpoint(gSources.selectedBreakpointItem,
gSources.selectedBreakpointClient,
gSources.selectedValue, 14, true, true, true);
executeSoon(modBreakpoint3);
@ -164,7 +164,7 @@ function test()
waitForBreakpoint(14, function() {
waitForCaretPos(13, function() {
waitForPopup(false, function() {
is(gSources.selectedClient.conditionalExpression, "bamboocha",
is(gSources.selectedBreakpointClient.conditionalExpression, "bamboocha",
"The bamboocha expression wasn't fonud on the conditional breakpoint");
executeSoon(setContextMenu);
@ -210,8 +210,8 @@ function test()
waitForBreakpoint(15, function() {
waitForCaretPos(14, function() {
waitForPopup(false, function() {
testBreakpoint(gSources.selectedBreakpoint,
gSources.selectedClient,
testBreakpoint(gSources.selectedBreakpointItem,
gSources.selectedBreakpointClient,
gSources.selectedValue, 15, false, false, true);
executeSoon(delBreakpoint4);
@ -228,7 +228,7 @@ function test()
waitForBreakpoint(null, function() {
waitForCaretPos(14, function() {
waitForPopup(false, function() {
is(gSources.selectedBreakpoint, null,
is(gSources.selectedBreakpointItem, null,
"There should be no selected breakpoint in the breakpoints pane.")
is(gSources._conditionalPopupVisible, false,
"The breakpoint conditional expression popup should not be shown.");
@ -246,8 +246,8 @@ function test()
waitForBreakpoint(14, function() {
waitForCaretPos(13, function() {
waitForPopup(false, function() {
testBreakpoint(gSources.selectedBreakpoint,
gSources.selectedClient,
testBreakpoint(gSources.selectedBreakpointItem,
gSources.selectedBreakpointClient,
gSources.selectedValue, 14, false, true, true);
executeSoon(testHighlights1);
@ -258,11 +258,11 @@ function test()
function testHighlights1()
{
isnot(gSources.selectedBreakpoint, null,
isnot(gSources.selectedBreakpointItem, null,
"There should be a selected breakpoint in the breakpoints pane.");
is(gSources.selectedBreakpoint.attachment.sourceLocation, gSources.selectedValue,
is(gSources.selectedBreakpointItem.attachment.sourceLocation, gSources.selectedValue,
"The selected breakpoint should have the correct location.");
is(gSources.selectedBreakpoint.attachment.lineNumber, 14,
is(gSources.selectedBreakpointItem.attachment.lineNumber, 14,
"The selected breakpoint should have the correct line number.");
is(gSources._conditionalPopupVisible, false,
"The breakpoint conditional expression popup should not be shown.");
@ -275,11 +275,11 @@ function test()
waitForCaretPos(12, function() {
waitForPopup(false, function() {
isnot(gSources.selectedBreakpoint, null,
isnot(gSources.selectedBreakpointItem, null,
"There should be a selected breakpoint in the breakpoints pane.");
is(gSources.selectedBreakpoint.attachment.sourceLocation, gSources.selectedValue,
is(gSources.selectedBreakpointItem.attachment.sourceLocation, gSources.selectedValue,
"The selected breakpoint should have the correct location.");
is(gSources.selectedBreakpoint.attachment.lineNumber, 13,
is(gSources.selectedBreakpointItem.attachment.lineNumber, 13,
"The selected breakpoint should have the correct line number.");
is(gSources._conditionalPopupVisible, false,
"The breakpoint conditional expression popup should not be shown.");
@ -292,11 +292,11 @@ function test()
waitForCaretPos(11, function() {
waitForPopup(false, function() {
isnot(gSources.selectedBreakpoint, null,
isnot(gSources.selectedBreakpointItem, null,
"There should be a selected breakpoint in the breakpoints pane.");
is(gSources.selectedBreakpoint.attachment.sourceLocation, gSources.selectedValue,
is(gSources.selectedBreakpointItem.attachment.sourceLocation, gSources.selectedValue,
"The selected breakpoint should have the correct location.");
is(gSources.selectedBreakpoint.attachment.lineNumber, 12,
is(gSources.selectedBreakpointItem.attachment.lineNumber, 12,
"The selected breakpoint should have the correct line number.");
is(gSources._conditionalPopupVisible, false,
"The breakpoint conditional expression popup should not be shown.");
@ -309,7 +309,7 @@ function test()
waitForCaretPos(10, function() {
waitForPopup(false, function() {
is(gSources.selectedBreakpoint, null,
is(gSources.selectedBreakpointItem, null,
"There should not be a selected breakpoint in the breakpoints pane.");
is(gSources._conditionalPopupVisible, false,
"The breakpoint conditional expression popup should not be shown.");
@ -322,7 +322,7 @@ function test()
waitForCaretPos(14, function() {
waitForPopup(false, function() {
is(gSources.selectedBreakpoint, null,
is(gSources.selectedBreakpointItem, null,
"There should not be a selected breakpoint in the breakpoints pane.");
is(gSources._conditionalPopupVisible, false,
"The breakpoint conditional expression popup should not be shown.");
@ -345,16 +345,16 @@ function test()
function testHighlights2()
{
EventUtils.sendMouseEvent({ type: "click" },
gSources._container._list.querySelectorAll(".dbg-breakpoint")[2],
gSources.widget._list.querySelectorAll(".dbg-breakpoint")[2],
gDebugger);
waitForCaretPos(13, function() {
waitForPopup(true, function() {
isnot(gSources.selectedBreakpoint, null,
isnot(gSources.selectedBreakpointItem, null,
"There should be a selected breakpoint in the breakpoints pane.");
is(gSources.selectedBreakpoint.attachment.sourceLocation, gSources.selectedValue,
is(gSources.selectedBreakpointItem.attachment.sourceLocation, gSources.selectedValue,
"The selected breakpoint should have the correct location.");
is(gSources.selectedBreakpoint.attachment.lineNumber, 14,
is(gSources.selectedBreakpointItem.attachment.lineNumber, 14,
"The selected breakpoint should have the correct line number.");
is(gSources._conditionalPopupVisible, true,
"The breakpoint conditional expression popup should be shown.");
@ -364,16 +364,16 @@ function test()
"The source editor caret position should be at column 0");
EventUtils.sendMouseEvent({ type: "click" },
gSources._container._list.querySelectorAll(".dbg-breakpoint")[1],
gSources.widget._list.querySelectorAll(".dbg-breakpoint")[1],
gDebugger);
waitForCaretPos(12, function() {
waitForPopup(true, function() {
isnot(gSources.selectedBreakpoint, null,
isnot(gSources.selectedBreakpointItem, null,
"There should be a selected breakpoint in the breakpoints pane.");
is(gSources.selectedBreakpoint.attachment.sourceLocation, gSources.selectedValue,
is(gSources.selectedBreakpointItem.attachment.sourceLocation, gSources.selectedValue,
"The selected breakpoint should have the correct location.");
is(gSources.selectedBreakpoint.attachment.lineNumber, 13,
is(gSources.selectedBreakpointItem.attachment.lineNumber, 13,
"The selected breakpoint should have the correct line number.");
is(gSources._conditionalPopupVisible, true,
"The breakpoint conditional expression popup should be shown.");
@ -383,16 +383,16 @@ function test()
"The source editor caret position should be at column 0");
EventUtils.sendMouseEvent({ type: "click" },
gSources._container._list.querySelectorAll(".dbg-breakpoint")[0],
gSources.widget._list.querySelectorAll(".dbg-breakpoint")[0],
gDebugger);
waitForCaretPos(11, function() {
waitForPopup(false, function() {
isnot(gSources.selectedBreakpoint, null,
isnot(gSources.selectedBreakpointItem, null,
"There should be a selected breakpoint in the breakpoints pane.");
is(gSources.selectedBreakpoint.attachment.sourceLocation, gSources.selectedValue,
is(gSources.selectedBreakpointItem.attachment.sourceLocation, gSources.selectedValue,
"The selected breakpoint should have the correct location.");
is(gSources.selectedBreakpoint.attachment.lineNumber, 12,
is(gSources.selectedBreakpointItem.attachment.lineNumber, 12,
"The selected breakpoint should have the correct line number.");
is(gSources._conditionalPopupVisible, false,
"The breakpoint conditional expression popup should be shown.");
@ -417,7 +417,7 @@ function test()
waitForBreakpoint(null, function() {
waitForPopup(false, function() {
is(gSources.selectedBreakpoint, null,
is(gSources.selectedBreakpointItem, null,
"There should be no selected breakpoint in the breakpoints pane.")
is(gSources._conditionalPopupVisible, false,
"The breakpoint conditional expression popup should not be shown.");
@ -434,7 +434,7 @@ function test()
waitForBreakpoint(null, function() {
waitForPopup(false, function() {
is(gSources.selectedBreakpoint, null,
is(gSources.selectedBreakpointItem, null,
"There should be no selected breakpoint in the breakpoints pane.")
is(gSources._conditionalPopupVisible, false,
"The breakpoint conditional expression popup should not be shown.");
@ -502,8 +502,8 @@ function test()
window.clearInterval(intervalID);
return closeDebuggerAndFinish();
}
if ((gSources.selectedClient !== expected) &&
(gSources.selectedClient || bogusClient).location.line !== expected) {
if ((gSources.selectedBreakpointClient !== expected) &&
(gSources.selectedBreakpointClient || bogusClient).location.line !== expected) {
return;
}
// We arrived at the expected line, it's safe to callback.

Просмотреть файл

@ -64,8 +64,7 @@ function testSimpleCall() {
is(profile.rootDir.path, gProcess._dbgProfile.rootDir.path,
"The remote debugger profile doesn't have the correct rootDir!");
let chromeDebug = DebuggerUI.toggleChromeDebugger();
info("toggleChromeDebugger() returned " + chromeDebug);
gProcess.close();
}}, 0);
}

Просмотреть файл

@ -1,181 +0,0 @@
/*
* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/
*/
// Tests that a remote debugger can be created in a new window.
var gWindow = null;
var gTab = null;
var gRemoteHost = null;
var gRemotePort = null;
var gRemoteTimeout = null;
var gAutoConnect = null;
const TEST_URL = EXAMPLE_URL + "browser_dbg_iframes.html";
function test() {
debug_remote(TEST_URL, function(aTab, aDebuggee, aWindow) {
gTab = aTab;
gWindow = aWindow;
let gDebugger = gWindow.panelWin;
info("Current remote window x: " +
Services.prefs.getIntPref("devtools.debugger.ui.win-x"));
info("Current remote window y: " +
Services.prefs.getIntPref("devtools.debugger.ui.win-y"));
info("Current remote window width: " +
Services.prefs.getIntPref("devtools.debugger.ui.win-width"));
info("Current remote window height: " +
Services.prefs.getIntPref("devtools.debugger.ui.win-height"));
is(gDebugger.Prefs.windowX,
Services.prefs.getIntPref("devtools.debugger.ui.win-x"),
"Current window x pref corresponds to the debugger pref.");
is(gDebugger.Prefs.windowY,
Services.prefs.getIntPref("devtools.debugger.ui.win-y"),
"Current window y pref corresponds to the debugger pref.");
is(gDebugger.Prefs.windowWidth,
Services.prefs.getIntPref("devtools.debugger.ui.win-width"),
"Current window width pref corresponds to the debugger pref.");
is(gDebugger.Prefs.windowHeight,
Services.prefs.getIntPref("devtools.debugger.ui.win-height"),
"Current window height pref corresponds to the debugger pref.");
info("Current remote host: " +
Services.prefs.getCharPref("devtools.debugger.remote-host"));
info("Current remote port: " +
Services.prefs.getIntPref("devtools.debugger.remote-port"));
info("Current remote retries: " +
Services.prefs.getIntPref("devtools.debugger.remote-connection-retries"));
info("Current remote timeout: " +
Services.prefs.getIntPref("devtools.debugger.remote-timeout"));
info("Current autoconnect flag: " +
Services.prefs.getBoolPref("devtools.debugger.remote-autoconnect"));
is(gDebugger.Prefs.remoteHost,
Services.prefs.getCharPref("devtools.debugger.remote-host"),
"Current remote host corresponds to the debugger pref.");
is(gDebugger.Prefs.remotePort,
Services.prefs.getIntPref("devtools.debugger.remote-port"),
"Current remote port corresponds to the debugger pref.");
is(gDebugger.Prefs.remoteConnectionRetries,
Services.prefs.getIntPref("devtools.debugger.remote-connection-retries"),
"Current remote retries corresponds to the debugger pref.");
is(gDebugger.Prefs.remoteTimeout,
Services.prefs.getIntPref("devtools.debugger.remote-timeout"),
"Current remote timeout corresponds to the debugger pref.");
is(gDebugger.Prefs.remoteAutoConnect,
Services.prefs.getBoolPref("devtools.debugger.remote-autoconnect"),
"Current autoconnect flag corresponds to the debugger pref.");
is(gDebugger.document.getElementById("close").getAttribute("hidden"), "true",
"The close button should be hidden in a remote debugger.");
is(gDebugger.DebuggerController.activeThread.paused, false,
"Should be running after debug_remote.");
gDebugger.DebuggerController.activeThread.addOneTimeListener("framesadded", function() {
Services.tm.currentThread.dispatch({ run: function() {
let frames = gDebugger.DebuggerView.StackFrames._container._list;
let childNodes = frames.childNodes;
is(gDebugger.DebuggerController.activeThread.paused, true,
"Should be paused after an interrupt request.");
is(frames.querySelectorAll(".dbg-stackframe").length, 1,
"Should have one frame in the stack.");
gDebugger.DebuggerController.activeThread.addOneTimeListener("resumed", function() {
Services.tm.currentThread.dispatch({ run: function() {
closeDebuggerAndFinish(true);
}}, 0);
});
EventUtils.sendMouseEvent({ type: "mousedown" },
gDebugger.document.getElementById("resume"),
gDebugger);
}}, 0);
});
let iframe = gTab.linkedBrowser.contentWindow.wrappedJSObject.frames[0];
is(iframe.document.title, "Browser Debugger Test Tab", "Found the iframe");
function handler() {
if (iframe.document.readyState != "complete") {
return;
}
iframe.window.removeEventListener("load", handler, false);
executeSoon(iframe.runDebuggerStatement);
};
iframe.window.addEventListener("load", handler, false);
handler();
},
function beforeTabAdded() {
if (!DebuggerServer.initialized) {
DebuggerServer.init(function() { return true; });
DebuggerServer.addBrowserActors();
}
DebuggerServer.closeListener();
gRemoteHost = Services.prefs.getCharPref("devtools.debugger.remote-host");
gRemotePort = Services.prefs.getIntPref("devtools.debugger.remote-port");
gRemoteTimeout = Services.prefs.getIntPref("devtools.debugger.remote-timeout");
gAutoConnect = Services.prefs.getBoolPref("devtools.debugger.remote-autoconnect");
// Open the listener at some point in the future to test automatic reconnect.
openListener(gRemoteHost, gRemotePort + 1, gRemoteTimeout / 10);
});
}
let attempts = 0;
function openListener(host, port, timeout) {
Services.prefs.setCharPref("devtools.debugger.remote-host", host);
Services.prefs.setIntPref("devtools.debugger.remote-port", port);
Services.prefs.setIntPref("devtools.debugger.remote-timeout", timeout);
Services.prefs.setBoolPref("devtools.debugger.remote-autoconnect", true);
info("Attempting to open a new listener on port " + port);
try {
info("Closing listener...");
DebuggerServer.closeListener();
info("Opening listener...");
DebuggerServer.openListener(port);
} catch (e) {
info(e);
info("Exception caught when opening listener on port " + port);
info("Retrying with port " + (++port));
if (++attempts < 100) {
DebuggerServer.closeListener();
openListener(port);
} else {
ok(false, "Timed out while opening a listener.");
}
}
}
registerCleanupFunction(function() {
Services.prefs.setCharPref("devtools.debugger.remote-host", gRemoteHost);
Services.prefs.setIntPref("devtools.debugger.remote-port", gRemotePort);
Services.prefs.setIntPref("devtools.debugger.remote-timeout", gRemoteTimeout);
Services.prefs.setBoolPref("devtools.debugger.remote-autoconnect", gAutoConnect);
removeTab(gTab);
gWindow = null;
gTab = null;
gRemoteHost = null;
gRemotePort = null;
gRemoteTimeout = null;
gAutoConnect = null;
});

Просмотреть файл

@ -28,7 +28,7 @@ function testAnonCall() {
gDebugger.DebuggerController.activeThread.addOneTimeListener("framesadded", function() {
Services.tm.currentThread.dispatch({ run: function() {
let frames = gDebugger.DebuggerView.StackFrames._container._list;
let frames = gDebugger.DebuggerView.StackFrames.widget._list;
is(gDebugger.DebuggerController.activeThread.state, "paused",
"Should only be getting stack frames while paused.");
@ -50,7 +50,7 @@ function testInferredName() {
gDebugger.DebuggerController.activeThread.addOneTimeListener("framesadded", function() {
Services.tm.currentThread.dispatch({ run: function() {
let frames = gDebugger.DebuggerView.StackFrames._container._list;
let frames = gDebugger.DebuggerView.StackFrames.widget._list;
is(gDebugger.DebuggerController.activeThread.state, "paused",
"Should only be getting stack frames while paused.");

Просмотреть файл

@ -23,7 +23,7 @@ function test() {
gDebugger.DebuggerController.activeThread.addOneTimeListener("framesadded", function() {
Services.tm.currentThread.dispatch({ run: function() {
let frames = gDebugger.DebuggerView.StackFrames._container._list;
let frames = gDebugger.DebuggerView.StackFrames.widget._list;
let childNodes = frames.childNodes;
is(gDebugger.DebuggerController.activeThread.paused, true,

Просмотреть файл

@ -48,7 +48,7 @@ function test()
}
function testSimpleCall() {
var frames = gDebugger.DebuggerView.StackFrames._container._list,
var frames = gDebugger.DebuggerView.StackFrames.widget._list,
childNodes = frames.childNodes;
is(gDebugger.DebuggerController.activeThread.state, "paused",
@ -85,7 +85,7 @@ function testLocationChange()
is(gDebugger.editor.getText().length, 0,
"The source editor not have any text displayed.");
let menulist = gDebugger.DebuggerView.Sources._container;
let menulist = gDebugger.DebuggerView.Sources.widget;
let noScripts = gDebugger.L10N.getStr("noSourcesText");
is(menulist.getAttribute("label"), noScripts,
"The menulist should display a notice that there are no scripts availalble.");

Просмотреть файл

@ -35,7 +35,7 @@ function testAddBreakpoint()
controller.activeThread.addOneTimeListener("framesadded", function() {
Services.tm.currentThread.dispatch({ run: function() {
var frames = gDebugger.DebuggerView.StackFrames._container._list;
var frames = gDebugger.DebuggerView.StackFrames.widget._list;
is(controller.activeThread.state, "paused",
"The debugger statement was reached.");

Просмотреть файл

@ -48,7 +48,7 @@ function test()
}
function testSimpleCall() {
var frames = gDebugger.DebuggerView.StackFrames._container._list,
var frames = gDebugger.DebuggerView.StackFrames.widget._list,
childNodes = frames.childNodes;
is(gDebugger.DebuggerController.activeThread.state, "paused",
@ -85,7 +85,7 @@ function testLocationChange()
isnot(gDebugger.editor.getText().length, 0,
"The source editor should have some text displayed.");
let menulist = gDebugger.DebuggerView.Sources._container;
let menulist = gDebugger.DebuggerView.Sources.widget;
let noScripts = gDebugger.L10N.getStr("noSourcesText");
isnot(menulist.getAttribute("label"), noScripts,
"The menulist should not display a notice that there are no scripts availalble.");

Просмотреть файл

@ -27,7 +27,7 @@ function testSimpleCall() {
gDebugger.DebuggerController.activeThread.addOneTimeListener("framesadded", function() {
Services.tm.currentThread.dispatch({
run: function() {
var frames = gDebugger.DebuggerView.StackFrames._container._list,
var frames = gDebugger.DebuggerView.StackFrames.widget._list,
childNodes = frames.childNodes;
is(gDebugger.DebuggerController.activeThread.state, "paused",

Просмотреть файл

@ -18,9 +18,9 @@ requestLongerTimeout(2);
function test()
{
gPrevPref = Services.prefs.getBoolPref(
"devtools.debugger.ui.pause-on-exceptions");
"devtools.debugger.pause-on-exceptions");
Services.prefs.setBoolPref(
"devtools.debugger.ui.pause-on-exceptions", true);
"devtools.debugger.pause-on-exceptions", true);
debug_tab_pane(TAB_URL, function(aTab, aDebuggee, aPane) {
gTab = aTab;
@ -71,7 +71,7 @@ function testWithFrame()
gDebugger.removeEventListener("Debugger:FetchedVariables", testB, false);
Services.tm.currentThread.dispatch({ run: function() {
var frames = gDebugger.DebuggerView.StackFrames._container._list,
var frames = gDebugger.DebuggerView.StackFrames.widget._list,
scopes = gDebugger.DebuggerView.Variables._list,
innerScope = scopes.firstChild,
innerNodes = innerScope.querySelector(".variables-view-element-details").childNodes;

Просмотреть файл

@ -37,7 +37,7 @@ function testPause() {
gDebugger.DebuggerController.activeThread.addOneTimeListener("paused", function() {
Services.tm.currentThread.dispatch({ run: function() {
let frames = gDebugger.DebuggerView.StackFrames._container._list;
let frames = gDebugger.DebuggerView.StackFrames.widget._list;
let childNodes = frames.childNodes;
is(gDebugger.DebuggerController.activeThread.paused, true,

Просмотреть файл

@ -36,7 +36,7 @@ function testlabelshortening() {
let vs = gDebugger.DebuggerView.Sources;
let ss = gDebugger.DebuggerController.SourceScripts;
vs.empty();
vs._container.removeEventListener("select", vs._onScriptsChange, false);
vs.widget.removeEventListener("select", vs._onScriptsChange, false);
is(sv.trimUrlQuery("a/b/c.d?test=1&random=4#reference"), "a/b/c.d",
"Trimming the url query isn't done properly.");

Просмотреть файл

@ -29,6 +29,7 @@ function testSimpleCall() {
let windowVar = globalScope.addItem("window");
let documentVar = globalScope.addItem("document");
let localVar0 = localScope.addItem("localVariable");
let localVar1 = localScope.addItem("localVar1");
let localVar2 = localScope.addItem("localVar2");
let localVar3 = localScope.addItem("localVar3");
@ -43,36 +44,62 @@ function testSimpleCall() {
localVar4.setGrip({ "type": "null" });
localVar5.setGrip({ "type": "object", "class": "Object" });
localVar5.addItems({ "someProp0": { "value": 42, "enumerable": true },
"someProp1": { "value": true , "enumerable": true},
"someProp2": { "value": "nasu", "enumerable": true},
"someProp3": { "value": { "type": "undefined" }, "enumerable": true},
"someProp4": { "value": { "type": "null" }, "enumerable": true },
"someProp5": {
"value": { "type": "object", "class": "Object" },
"enumerable": true
}
});
localVar5.addItems({
"someProp0": { "value": 42, "enumerable": true },
"someProp1": { "value": true , "enumerable": true},
"someProp2": { "value": "nasu", "enumerable": true},
"someProp3": { "value": { "type": "undefined" }, "enumerable": true},
"someProp4": { "value": { "type": "null" }, "enumerable": true },
"someProp5": {
"value": { "type": "object", "class": "Object" },
"enumerable": true
},
"someUndefined": {
"value": { "type": "undefined" },
"enumerable": true
},
"someAccessor": {
"get": { "type": "object", "class": "Function" },
"set": { "type": "undefined" },
"enumerable": true
}
});
localVar5.get("someProp5").addItems({ "someProp0": { "value": 42, "enumerable": true },
"someProp1": { "value": true, "enumerable": true },
"someProp2": { "value": "nasu", "enumerable": true },
"someProp3": { "value": { "type": "undefined" }, "enumerable": true },
"someProp4": { "value": { "type": "null" }, "enumerable": true },
"someAccessor": { "get": { "type": "object", "class": "Function" },
"set": { "type": "undefined" }, "enumerable": true }
});
localVar5.get("someProp5").addItems({
"someProp0": { "value": 42, "enumerable": true },
"someProp1": { "value": true, "enumerable": true },
"someProp2": { "value": "nasu", "enumerable": true },
"someProp3": { "value": { "type": "undefined" }, "enumerable": true },
"someProp4": { "value": { "type": "null" }, "enumerable": true },
"someProp5": {
"value": { "type": "object", "class": "Object" },
"enumerable": true
},
"someUndefined": {
"value": { "type": "undefined" },
"enumerable": true
},
"someAccessor": {
"get": { "type": "object", "class": "Function" },
"set": { "type": "undefined" },
"enumerable": true
}
});
windowVar.setGrip({ "type": "object", "class": "Window" });
windowVar.addItems({ "helloWorld": { "value": "hello world" } });
windowVar.addItems({
"helloWorld": { "value": "hello world" }
});
documentVar.setGrip({ "type": "object", "class": "HTMLDocument" });
documentVar.addItems({ "onload": { "value": { "type": "null" } },
"onunload": { "value": { "type": "null" } },
"onfocus": { "value": { "type": "null" } },
"onblur": { "value": { "type": "null" } },
"onclick": { "value": { "type": "null" } },
"onkeypress": { "value": { "type": "null" } } });
documentVar.addItems({
"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.");
@ -84,7 +111,6 @@ function testSimpleCall() {
ok(localVar4, "The localVar4 hasn't been created correctly.");
ok(localVar5, "The localVar5 hasn't been created correctly.");
for each (let elt in globalScope.target.querySelector(".nonenum").childNodes) {
info("globalScope :: " + { id: elt.id, className: elt.className }.toSource());
}
@ -97,38 +123,63 @@ function testSimpleCall() {
is(localScope.target.querySelector(".nonenum").childNodes.length, 6,
"The localScope doesn't contain all the created variable elements.");
is(localVar5.target.querySelector(".variables-view-element-details").childNodes.length, 6,
is(localVar5.target.querySelector(".variables-view-element-details").childNodes.length, 8,
"The localVar5 doesn't contain all the created properties.");
is(localVar5.get("someProp5").target.querySelector(".variables-view-element-details").childNodes.length, 6,
is(localVar5.get("someProp5").target.querySelector(".variables-view-element-details").childNodes.length, 8,
"The localVar5.someProp5 doesn't contain all the created properties.");
is(windowVar.target.querySelector(".value").getAttribute("value"), "[object Window]",
"The grip information for the windowVar wasn't set correctly.");
is(documentVar.target.querySelector(".value").getAttribute("value"), "[object HTMLDocument]",
"The grip information for the documentVar wasn't set correctly.");
is(localVar0.target.querySelector(".value").getAttribute("value"), "42",
"The grip information for the localVar0 wasn't set correctly.");
is(localVar1.target.querySelector(".value").getAttribute("value"), "true",
"The grip information for the localVar1 wasn't set correctly.");
is(localVar2.target.querySelector(".value").getAttribute("value"), "\"nasu\"",
"The grip information for the localVar2 wasn't set correctly.");
is(localVar3.target.querySelector(".value").getAttribute("value"), "undefined",
"The grip information for the localVar3 wasn't set correctly.");
is(localVar4.target.querySelector(".value").getAttribute("value"), "null",
"The grip information for the localVar4 wasn't set correctly.");
is(localVar5.target.querySelector(".value").getAttribute("value"), "[object Object]",
"The grip information for the localVar5 wasn't set correctly.");
is(localVar5.get("someProp0").target.querySelector(".value").getAttribute("value"), "42",
"The grip information for the localVar0 wasn't set correctly.");
is(localVar5.get("someProp1").target.querySelector(".value").getAttribute("value"), "true",
"The grip information for the localVar1 wasn't set correctly.");
is(localVar5.get("someProp2").target.querySelector(".value").getAttribute("value"), "\"nasu\"",
"The grip information for the localVar2 wasn't set correctly.");
is(localVar5.get("someProp3").target.querySelector(".value").getAttribute("value"), "undefined",
"The grip information for the localVar3 wasn't set correctly.");
is(localVar5.get("someProp4").target.querySelector(".value").getAttribute("value"), "null",
"The grip information for the localVar4 wasn't set correctly.");
is(localVar5.get("someProp5").target.querySelector(".value").getAttribute("value"), "[object Object]",
"The grip information for the localVar5 wasn't set correctly.");
is(localVar5.get("someUndefined").target.querySelector(".value").getAttribute("value"), "undefined",
"The grip information for the someUndefined wasn't set correctly.");
is(localVar5.get("someAccessor").target.querySelector(".value").getAttribute("value"), "",
"The grip information for the someAccessor wasn't set correctly.");
is(localVar5.get("someProp5").get("someProp0").target.querySelector(".value").getAttribute("value"), "42",
"The grip information for the sub-localVar0 wasn't set correctly.");
is(localVar5.get("someProp5").get("someProp1").target.querySelector(".value").getAttribute("value"), "true",
"The grip information for the sub-localVar1 wasn't set correctly.");
is(localVar5.get("someProp5").get("someProp2").target.querySelector(".value").getAttribute("value"), "\"nasu\"",
"The grip information for the sub-localVar2 wasn't set correctly.");
is(localVar5.get("someProp5").get("someProp3").target.querySelector(".value").getAttribute("value"), "undefined",
"The grip information for the sub-localVar3 wasn't set correctly.");
is(localVar5.get("someProp5").get("someProp4").target.querySelector(".value").getAttribute("value"), "null",
"The grip information for the sub-localVar4 wasn't set correctly.");
is(localVar5.get("someProp5").get("someProp5").target.querySelector(".value").getAttribute("value"), "[object Object]",
"The grip information for the sub-localVar5 wasn't set correctly.");
is(localVar5.get("someProp5").get("someUndefined").target.querySelector(".value").getAttribute("value"), "undefined",
"The grip information for the sub-someUndefined wasn't set correctly.");
is(localVar5.get("someProp5").get("someAccessor").target.querySelector(".value").getAttribute("value"), "",
"The grip information for the sub-someAccessor wasn't set correctly.");
gDebugger.DebuggerController.activeThread.resume(function() {
closeDebuggerAndFinish();
});

Просмотреть файл

@ -29,7 +29,7 @@ function testFrameParameters()
gDebugger.removeEventListener("Debugger:FetchedVariables", test, false);
Services.tm.currentThread.dispatch({ run: function() {
var frames = gDebugger.DebuggerView.StackFrames._container._list,
var frames = gDebugger.DebuggerView.StackFrames.widget._list,
localScope = gDebugger.DebuggerView.Variables._list.querySelector(".variables-view-scope"),
localNodes = localScope.querySelector(".variables-view-element-details").childNodes;
@ -88,7 +88,7 @@ function resumeAndFinish() {
gDebugger.addEventListener("Debugger:AfterFramesCleared", function listener() {
gDebugger.removeEventListener("Debugger:AfterFramesCleared", listener, true);
var frames = gDebugger.DebuggerView.StackFrames._container._list;
var frames = gDebugger.DebuggerView.StackFrames.widget._list;
is(frames.querySelectorAll(".dbg-stackframe").length, 0,
"Should have no frames.");

Просмотреть файл

@ -29,7 +29,7 @@ function testFrameParameters()
gDebugger.removeEventListener("Debugger:FetchedVariables", test, false);
Services.tm.currentThread.dispatch({ run: function() {
var frames = gDebugger.DebuggerView.StackFrames._container._list,
var frames = gDebugger.DebuggerView.StackFrames.widget._list,
localScope = gDebugger.DebuggerView.Variables._list.querySelectorAll(".variables-view-scope")[0],
localNodes = localScope.querySelector(".variables-view-element-details").childNodes,
localNonEnums = localScope.querySelector(".nonenum").childNodes;
@ -226,7 +226,7 @@ function resumeAndFinish() {
gDebugger.addEventListener("Debugger:AfterFramesCleared", function listener() {
gDebugger.removeEventListener("Debugger:AfterFramesCleared", listener, true);
var frames = gDebugger.DebuggerView.StackFrames._container._list;
var frames = gDebugger.DebuggerView.StackFrames.widget._list;
is(frames.querySelectorAll(".dbg-stackframe").length, 0,
"Should have no frames.");

Просмотреть файл

@ -40,7 +40,7 @@ function testFrameParameters()
gDebugger.removeEventListener("Debugger:FetchedVariables", test, false);
Services.tm.currentThread.dispatch({ run: function() {
var frames = gDebugger.DebuggerView.StackFrames._container._list,
var frames = gDebugger.DebuggerView.StackFrames.widget._list,
globalScope = gDebugger.DebuggerView.Variables._list.querySelectorAll(".variables-view-scope")[2],
globalNodes = globalScope.querySelector(".variables-view-element-details").childNodes;
@ -85,7 +85,7 @@ function resumeAndFinish() {
gDebugger.addEventListener("Debugger:AfterFramesCleared", function listener() {
gDebugger.removeEventListener("Debugger:AfterFramesCleared", listener, true);
Services.tm.currentThread.dispatch({ run: function() {
var frames = gDebugger.DebuggerView.StackFrames._container._list;
var frames = gDebugger.DebuggerView.StackFrames.widget._list;
is(frames.querySelectorAll(".dbg-stackframe").length, 0,
"Should have no frames.");

Просмотреть файл

@ -40,7 +40,7 @@ function testWithFrame()
gDebugger.removeEventListener("Debugger:FetchedVariables", test, false);
Services.tm.currentThread.dispatch({ run: function() {
var frames = gDebugger.DebuggerView.StackFrames._container._list,
var frames = gDebugger.DebuggerView.StackFrames.widget._list,
scopes = gDebugger.DebuggerView.Variables._list,
innerScope = scopes.querySelectorAll(".variables-view-scope")[0],
globalScope = scopes.querySelectorAll(".variables-view-scope")[4],
@ -90,7 +90,7 @@ function resumeAndFinish() {
gDebugger.addEventListener("Debugger:AfterFramesCleared", function listener() {
gDebugger.removeEventListener("Debugger:AfterFramesCleared", listener, true);
Services.tm.currentThread.dispatch({ run: function() {
var frames = gDebugger.DebuggerView.StackFrames._container._list;
var frames = gDebugger.DebuggerView.StackFrames.widget._list;
is(frames.querySelectorAll(".dbg-stackframe").length, 0,
"Should have no frames.");

Просмотреть файл

@ -221,7 +221,7 @@ function resumeAndFinish() {
gDebugger.addEventListener("Debugger:AfterFramesCleared", function listener() {
gDebugger.removeEventListener("Debugger:AfterFramesCleared", listener, true);
Services.tm.currentThread.dispatch({ run: function() {
let frames = gDebugger.DebuggerView.StackFrames._container._list;
let frames = gDebugger.DebuggerView.StackFrames.widget._list;
is(frames.querySelectorAll(".dbg-stackframe").length, 0,
"Should have no frames.");

Просмотреть файл

@ -248,6 +248,9 @@ function testEdit(what, string, callback, expected)
if (isNaN(expected[w1.name]) && typeof expected[w1.name] == "number") {
ok(isNaN(w1.value),
"The first expression value is correct after the edit (NaN).");
} else if (expected[w1.name] === undefined) {
is(w1.value.type, "undefined",
"The first expression value is correct after the edit (undefined).");
} else {
is(w1.value, expected[w1.name],
"The first expression value is correct after the edit.");
@ -258,6 +261,9 @@ function testEdit(what, string, callback, expected)
if (isNaN(expected[w2.name]) && typeof expected[w2.name] == "number") {
ok(isNaN(w2.value),
"The second expression value is correct after the edit (NaN).");
} else if (expected[w2.name] === undefined) {
is(w2.value.type, "undefined",
"The second expression value is correct after the edit (undefined).");
} else {
is(w2.value, expected[w2.name],
"The second expression value is correct after the edit.");
@ -268,6 +274,9 @@ function testEdit(what, string, callback, expected)
if (isNaN(expected[w3.name]) && typeof expected[w3.name] == "number") {
ok(isNaN(w3.value),
"The third expression value is correct after the edit (NaN).");
} else if (expected[w3.name] === undefined) {
is(w3.value.type, "undefined",
"The third expression value is correct after the edit (undefined).");
} else {
is(w3.value, expected[w3.name],
"The third expression value is correct after the edit.");

Просмотреть файл

@ -57,9 +57,9 @@ function testFrameEval() {
is(varT.querySelector(".value").getAttribute("value"), "\"Browser Debugger Watch Expressions Test\"",
"Should have the right initial value for 't'.");
is(gWatch._container._parent.querySelectorAll(".dbg-expression[hidden=true]").length, 5,
is(gWatch.widget._parent.querySelectorAll(".dbg-expression[hidden=true]").length, 5,
"There should be 5 hidden nodes in the watch expressions container");
is(gWatch._container._parent.querySelectorAll(".dbg-expression:not([hidden=true])").length, 0,
is(gWatch.widget._parent.querySelectorAll(".dbg-expression:not([hidden=true])").length, 0,
"There should be 0 visible nodes in the watch expressions container");
let label = gDebugger.L10N.getStr("watchExpressionsScopeLabel");
@ -96,7 +96,9 @@ function testFrameEval() {
"Should have the one close button visible for 'aArg'.");
is(scope.get("aArg").name, "aArg",
"Should have the right name for 'aArg'.");
is(scope.get("aArg").value, undefined,
is(scope.get("aArg").value.type, "undefined",
"Should have the right value for 'aArg'.");
is(scope.get("aArg").value.class, undefined,
"Should have the right value for 'aArg'.");
is(scope.get("document.title")._isContentVisible, true,
@ -330,159 +332,159 @@ function testExprDeletion(aVar, aTest, aCallback, aArgResult,
}
function test1(scope) {
is(gWatch._container._parent.querySelectorAll(".dbg-expression[hidden=true]").length, 5,
is(gWatch.widget._parent.querySelectorAll(".dbg-expression[hidden=true]").length, 5,
"There should be 5 hidden nodes in the watch expressions container");
is(gWatch._container._parent.querySelectorAll(".dbg-expression:not([hidden=true])").length, 0,
is(gWatch.widget._parent.querySelectorAll(".dbg-expression:not([hidden=true])").length, 0,
"There should be 0 visible nodes in the watch expressions container");
ok(scope, "There should be a wach expressions scope in the variables view");
is(scope._store.size, 5, "There should be 5 evaluations availalble");
is(gWatch._cache[0].attachment.inputNode.value, "document.title = 43",
is(gWatch.getItemAtIndex(0).attachment.inputNode.value, "document.title = 43",
"The first textbox input value is not the correct one");
is(gWatch._cache[0].attachment.currentExpression, "document.title = 43",
is(gWatch.getItemAtIndex(0).attachment.currentExpression, "document.title = 43",
"The first textbox input value is not the correct one");
is(gWatch._cache[1].attachment.inputNode.value, "document.title",
is(gWatch.getItemAtIndex(1).attachment.inputNode.value, "document.title",
"The second textbox input value is not the correct one");
is(gWatch._cache[1].attachment.currentExpression, "document.title",
is(gWatch.getItemAtIndex(1).attachment.currentExpression, "document.title",
"The second textbox input value is not the correct one");
is(gWatch._cache[2].attachment.inputNode.value, "aArg",
is(gWatch.getItemAtIndex(2).attachment.inputNode.value, "aArg",
"The third textbox input value is not the correct one");
is(gWatch._cache[2].attachment.currentExpression, "aArg",
is(gWatch.getItemAtIndex(2).attachment.currentExpression, "aArg",
"The third textbox input value is not the correct one");
is(gWatch._cache[3].attachment.inputNode.value, "ermahgerd",
is(gWatch.getItemAtIndex(3).attachment.inputNode.value, "ermahgerd",
"The fourth textbox input value is not the correct one");
is(gWatch._cache[3].attachment.currentExpression, "ermahgerd",
is(gWatch.getItemAtIndex(3).attachment.currentExpression, "ermahgerd",
"The fourth textbox input value is not the correct one");
is(gWatch._cache[4].attachment.inputNode.value, "this",
is(gWatch.getItemAtIndex(4).attachment.inputNode.value, "this",
"The fifth textbox input value is not the correct one");
is(gWatch._cache[4].attachment.currentExpression, "this",
is(gWatch.getItemAtIndex(4).attachment.currentExpression, "this",
"The fifth textbox input value is not the correct one");
}
function test2(scope) {
is(gWatch._container._parent.querySelectorAll(".dbg-expression[hidden=true]").length, 5,
is(gWatch.widget._parent.querySelectorAll(".dbg-expression[hidden=true]").length, 5,
"There should be 5 hidden nodes in the watch expressions container");
is(gWatch._container._parent.querySelectorAll(".dbg-expression:not([hidden=true])").length, 0,
is(gWatch.widget._parent.querySelectorAll(".dbg-expression:not([hidden=true])").length, 0,
"There should be 0 visible nodes in the watch expressions container");
ok(scope, "There should be a wach expressions scope in the variables view");
is(scope._store.size, 5, "There should be 5 evaluations availalble");
is(gWatch._cache[0].attachment.inputNode.value, "document.title = 43",
is(gWatch.getItemAtIndex(0).attachment.inputNode.value, "document.title = 43",
"The first textbox input value is not the correct one");
is(gWatch._cache[0].attachment.currentExpression, "document.title = 43",
is(gWatch.getItemAtIndex(0).attachment.currentExpression, "document.title = 43",
"The first textbox input value is not the correct one");
is(gWatch._cache[1].attachment.inputNode.value, "document.title",
is(gWatch.getItemAtIndex(1).attachment.inputNode.value, "document.title",
"The second textbox input value is not the correct one");
is(gWatch._cache[1].attachment.currentExpression, "document.title",
is(gWatch.getItemAtIndex(1).attachment.currentExpression, "document.title",
"The second textbox input value is not the correct one");
is(gWatch._cache[2].attachment.inputNode.value, "aArg = 44",
is(gWatch.getItemAtIndex(2).attachment.inputNode.value, "aArg = 44",
"The third textbox input value is not the correct one");
is(gWatch._cache[2].attachment.currentExpression, "aArg = 44",
is(gWatch.getItemAtIndex(2).attachment.currentExpression, "aArg = 44",
"The third textbox input value is not the correct one");
is(gWatch._cache[3].attachment.inputNode.value, "ermahgerd",
is(gWatch.getItemAtIndex(3).attachment.inputNode.value, "ermahgerd",
"The fourth textbox input value is not the correct one");
is(gWatch._cache[3].attachment.currentExpression, "ermahgerd",
is(gWatch.getItemAtIndex(3).attachment.currentExpression, "ermahgerd",
"The fourth textbox input value is not the correct one");
is(gWatch._cache[4].attachment.inputNode.value, "this",
is(gWatch.getItemAtIndex(4).attachment.inputNode.value, "this",
"The fifth textbox input value is not the correct one");
is(gWatch._cache[4].attachment.currentExpression, "this",
is(gWatch.getItemAtIndex(4).attachment.currentExpression, "this",
"The fifth textbox input value is not the correct one");
}
function test3(scope) {
is(gWatch._container._parent.querySelectorAll(".dbg-expression[hidden=true]").length, 4,
is(gWatch.widget._parent.querySelectorAll(".dbg-expression[hidden=true]").length, 4,
"There should be 4 hidden nodes in the watch expressions container");
is(gWatch._container._parent.querySelectorAll(".dbg-expression:not([hidden=true])").length, 0,
is(gWatch.widget._parent.querySelectorAll(".dbg-expression:not([hidden=true])").length, 0,
"There should be 0 visible nodes in the watch expressions container");
ok(scope, "There should be a wach expressions scope in the variables view");
is(scope._store.size, 4, "There should be 4 evaluations availalble");
is(gWatch._cache[0].attachment.inputNode.value, "document.title = 43",
is(gWatch.getItemAtIndex(0).attachment.inputNode.value, "document.title = 43",
"The first textbox input value is not the correct one");
is(gWatch._cache[0].attachment.currentExpression, "document.title = 43",
is(gWatch.getItemAtIndex(0).attachment.currentExpression, "document.title = 43",
"The first textbox input value is not the correct one");
is(gWatch._cache[1].attachment.inputNode.value, "document.title",
is(gWatch.getItemAtIndex(1).attachment.inputNode.value, "document.title",
"The second textbox input value is not the correct one");
is(gWatch._cache[1].attachment.currentExpression, "document.title",
is(gWatch.getItemAtIndex(1).attachment.currentExpression, "document.title",
"The second textbox input value is not the correct one");
is(gWatch._cache[2].attachment.inputNode.value, "ermahgerd",
is(gWatch.getItemAtIndex(2).attachment.inputNode.value, "ermahgerd",
"The third textbox input value is not the correct one");
is(gWatch._cache[2].attachment.currentExpression, "ermahgerd",
is(gWatch.getItemAtIndex(2).attachment.currentExpression, "ermahgerd",
"The third textbox input value is not the correct one");
is(gWatch._cache[3].attachment.inputNode.value, "this",
is(gWatch.getItemAtIndex(3).attachment.inputNode.value, "this",
"The fourth textbox input value is not the correct one");
is(gWatch._cache[3].attachment.currentExpression, "this",
is(gWatch.getItemAtIndex(3).attachment.currentExpression, "this",
"The fourth textbox input value is not the correct one");
}
function test4(scope) {
is(gWatch._container._parent.querySelectorAll(".dbg-expression[hidden=true]").length, 3,
is(gWatch.widget._parent.querySelectorAll(".dbg-expression[hidden=true]").length, 3,
"There should be 3 hidden nodes in the watch expressions container");
is(gWatch._container._parent.querySelectorAll(".dbg-expression:not([hidden=true])").length, 0,
is(gWatch.widget._parent.querySelectorAll(".dbg-expression:not([hidden=true])").length, 0,
"There should be 0 visible nodes in the watch expressions container");
ok(scope, "There should be a wach expressions scope in the variables view");
is(scope._store.size, 3, "There should be 3 evaluations availalble");
is(gWatch._cache[0].attachment.inputNode.value, "document.title",
is(gWatch.getItemAtIndex(0).attachment.inputNode.value, "document.title",
"The first textbox input value is not the correct one");
is(gWatch._cache[0].attachment.currentExpression, "document.title",
is(gWatch.getItemAtIndex(0).attachment.currentExpression, "document.title",
"The first textbox input value is not the correct one");
is(gWatch._cache[1].attachment.inputNode.value, "ermahgerd",
is(gWatch.getItemAtIndex(1).attachment.inputNode.value, "ermahgerd",
"The second textbox input value is not the correct one");
is(gWatch._cache[1].attachment.currentExpression, "ermahgerd",
is(gWatch.getItemAtIndex(1).attachment.currentExpression, "ermahgerd",
"The second textbox input value is not the correct one");
is(gWatch._cache[2].attachment.inputNode.value, "this",
is(gWatch.getItemAtIndex(2).attachment.inputNode.value, "this",
"The third textbox input value is not the correct one");
is(gWatch._cache[2].attachment.currentExpression, "this",
is(gWatch.getItemAtIndex(2).attachment.currentExpression, "this",
"The third textbox input value is not the correct one");
}
function test5(scope) {
is(gWatch._container._parent.querySelectorAll(".dbg-expression[hidden=true]").length, 2,
is(gWatch.widget._parent.querySelectorAll(".dbg-expression[hidden=true]").length, 2,
"There should be 2 hidden nodes in the watch expressions container");
is(gWatch._container._parent.querySelectorAll(".dbg-expression:not([hidden=true])").length, 0,
is(gWatch.widget._parent.querySelectorAll(".dbg-expression:not([hidden=true])").length, 0,
"There should be 0 visible nodes in the watch expressions container");
ok(scope, "There should be a wach expressions scope in the variables view");
is(scope._store.size, 2, "There should be 2 evaluations availalble");
is(gWatch._cache[0].attachment.inputNode.value, "ermahgerd",
is(gWatch.getItemAtIndex(0).attachment.inputNode.value, "ermahgerd",
"The second textbox input value is not the correct one");
is(gWatch._cache[0].attachment.currentExpression, "ermahgerd",
is(gWatch.getItemAtIndex(0).attachment.currentExpression, "ermahgerd",
"The second textbox input value is not the correct one");
is(gWatch._cache[1].attachment.inputNode.value, "this",
is(gWatch.getItemAtIndex(1).attachment.inputNode.value, "this",
"The third textbox input value is not the correct one");
is(gWatch._cache[1].attachment.currentExpression, "this",
is(gWatch.getItemAtIndex(1).attachment.currentExpression, "this",
"The third textbox input value is not the correct one");
}
function test6(scope) {
is(gWatch._container._parent.querySelectorAll(".dbg-expression[hidden=true]").length, 1,
is(gWatch.widget._parent.querySelectorAll(".dbg-expression[hidden=true]").length, 1,
"There should be 1 hidden nodes in the watch expressions container");
is(gWatch._container._parent.querySelectorAll(".dbg-expression:not([hidden=true])").length, 0,
is(gWatch.widget._parent.querySelectorAll(".dbg-expression:not([hidden=true])").length, 0,
"There should be 0 visible nodes in the watch expressions container");
ok(scope, "There should be a wach expressions scope in the variables view");
is(scope._store.size, 1, "There should be 1 evaluation availalble");
is(gWatch._cache[0].attachment.inputNode.value, "ermahgerd",
is(gWatch.getItemAtIndex(0).attachment.inputNode.value, "ermahgerd",
"The third textbox input value is not the correct one");
is(gWatch._cache[0].attachment.currentExpression, "ermahgerd",
is(gWatch.getItemAtIndex(0).attachment.currentExpression, "ermahgerd",
"The third textbox input value is not the correct one");
}
function test7(scope) {
is(gWatch._container._parent.querySelectorAll(".dbg-expression[hidden=true]").length, 0,
is(gWatch.widget._parent.querySelectorAll(".dbg-expression[hidden=true]").length, 0,
"There should be 0 hidden nodes in the watch expressions container");
is(gWatch._container._parent.querySelectorAll(".dbg-expression:not([hidden=true])").length, 0,
is(gWatch.widget._parent.querySelectorAll(".dbg-expression:not([hidden=true])").length, 0,
"There should be 0 visible nodes in the watch expressions container");
is(scope, undefined, "There should be no watch expressions scope available.");
is(gWatch._cache.length, 0, "The watch expressions cache should be empty.");
is(gWatch.itemCount, 0, "The watch expressions container should be empty.");
}
function addWatchExpression(string) {

Просмотреть файл

@ -315,7 +315,7 @@ function prepareVariables(aCallback)
gDebugger.removeEventListener("Debugger:FetchedVariables", test, false);
Services.tm.currentThread.dispatch({ run: function() {
var frames = gDebugger.DebuggerView.StackFrames._container._list,
var frames = gDebugger.DebuggerView.StackFrames.widget._list,
scopes = gDebugger.DebuggerView.Variables._list,
innerScope = scopes.querySelectorAll(".variables-view-scope")[0],
mathScope = scopes.querySelectorAll(".variables-view-scope")[1],

Просмотреть файл

@ -251,7 +251,7 @@ function prepareVariables(aCallback)
gDebugger.removeEventListener("Debugger:FetchedVariables", test, false);
Services.tm.currentThread.dispatch({ run: function() {
var frames = gDebugger.DebuggerView.StackFrames._container._list,
var frames = gDebugger.DebuggerView.StackFrames.widget._list,
scopes = gDebugger.DebuggerView.Variables._list,
innerScope = scopes.querySelectorAll(".variables-view-scope")[0],
mathScope = scopes.querySelectorAll(".variables-view-scope")[1],

Просмотреть файл

@ -215,7 +215,7 @@ function prepareVariables(aCallback)
gDebugger.removeEventListener("Debugger:FetchedVariables", test, false);
Services.tm.currentThread.dispatch({ run: function() {
var frames = gDebugger.DebuggerView.StackFrames._container._list,
var frames = gDebugger.DebuggerView.StackFrames.widget._list,
scopes = gDebugger.DebuggerView.Variables._list,
innerScope = scopes.querySelectorAll(".variables-view-scope")[0],
mathScope = scopes.querySelectorAll(".variables-view-scope")[1],

Просмотреть файл

@ -185,7 +185,7 @@ function prepareVariables(aCallback)
gDebugger.removeEventListener("Debugger:FetchedVariables", test, false);
Services.tm.currentThread.dispatch({ run: function() {
var frames = gDebugger.DebuggerView.StackFrames._container._list,
var frames = gDebugger.DebuggerView.StackFrames.widget._list,
scopes = gDebugger.DebuggerView.Variables._list,
innerScope = scopes.querySelectorAll(".variables-view-scope")[0],
mathScope = scopes.querySelectorAll(".variables-view-scope")[1],

Просмотреть файл

@ -185,7 +185,7 @@ function prepareVariables(aCallback)
gDebugger.removeEventListener("Debugger:FetchedVariables", test, false);
Services.tm.currentThread.dispatch({ run: function() {
var frames = gDebugger.DebuggerView.StackFrames._container._list,
var frames = gDebugger.DebuggerView.StackFrames.widget._list,
scopes = gDebugger.DebuggerView.Variables._list,
innerScope = scopes.querySelectorAll(".variables-view-scope")[0],
mathScope = scopes.querySelectorAll(".variables-view-scope")[1],

Просмотреть файл

@ -255,7 +255,7 @@ function prepareVariables(aCallback)
gDebugger.removeEventListener("Debugger:FetchedVariables", test, false);
Services.tm.currentThread.dispatch({ run: function() {
var frames = gDebugger.DebuggerView.StackFrames._container._list,
var frames = gDebugger.DebuggerView.StackFrames.widget._list,
scopes = gDebugger.DebuggerView.Variables._list,
innerScope = scopes.querySelectorAll(".variables-view-scope")[0],
mathScope = scopes.querySelectorAll(".variables-view-scope")[1],

Просмотреть файл

@ -60,7 +60,7 @@ function testVariablesExpand()
gDebugger.removeEventListener("Debugger:FetchedVariables", test, false);
Services.tm.currentThread.dispatch({ run: function() {
var frames = gDebugger.DebuggerView.StackFrames._container._list,
var frames = gDebugger.DebuggerView.StackFrames.widget._list,
scopes = gDebugger.DebuggerView.Variables._list,
innerScope = scopes.querySelectorAll(".variables-view-scope")[0],
mathScope = scopes.querySelectorAll(".variables-view-scope")[1],

Просмотреть файл

@ -9,5 +9,6 @@
<script type="text/javascript" src="test-script-switching-02.js"></script>
</head>
<body>
<button onclick="firstCall()">Click me!</button>
</body>
</html>

Просмотреть файл

@ -117,35 +117,35 @@ function testScriptSearching() {
ok(gEditor.getCaretPosition().line == 8 &&
gEditor.getCaretPosition().col == 2 + token.length,
"The editor didn't jump to the correct token. (6)");
isnot(gSources._container.getAttribute("label"), noMatchingSources,
isnot(gSources.widget.getAttribute("label"), noMatchingSources,
"The scripts container should not display a notice that matches are found.");
write(":13#" + token);
ok(gEditor.getCaretPosition().line == 8 &&
gEditor.getCaretPosition().col == 2 + token.length,
"The editor didn't jump to the correct token. (7)");
isnot(gSources._container.getAttribute("label"), noMatchingSources,
isnot(gSources.widget.getAttribute("label"), noMatchingSources,
"The scripts container should not display a notice that matches are found.");
write(":#" + token);
ok(gEditor.getCaretPosition().line == 8 &&
gEditor.getCaretPosition().col == 2 + token.length,
"The editor didn't jump to the correct token. (8)");
isnot(gSources._container.getAttribute("label"), noMatchingSources,
isnot(gSources.widget.getAttribute("label"), noMatchingSources,
"The scripts container should not display a notice that matches are found.");
write("::#" + token);
ok(gEditor.getCaretPosition().line == 8 &&
gEditor.getCaretPosition().col == 2 + token.length,
"The editor didn't jump to the correct token. (9)");
isnot(gSources._container.getAttribute("label"), noMatchingSources,
isnot(gSources.widget.getAttribute("label"), noMatchingSources,
"The scripts container should not display a notice that matches are found.");
write(":::#" + token);
ok(gEditor.getCaretPosition().line == 8 &&
gEditor.getCaretPosition().col == 2 + token.length,
"The editor didn't jump to the correct token. (10)");
isnot(gSources._container.getAttribute("label"), noMatchingSources,
isnot(gSources.widget.getAttribute("label"), noMatchingSources,
"The scripts container should not display a notice that matches are found.");
@ -153,35 +153,35 @@ function testScriptSearching() {
ok(gEditor.getCaretPosition().line == 8 &&
gEditor.getCaretPosition().col == 2 + token.length,
"The editor didn't jump to the correct token. (6)");
isnot(gSources._container.getAttribute("label"), noMatchingSources,
isnot(gSources.widget.getAttribute("label"), noMatchingSources,
"The scripts container should not display a notice that matches are found.");
write("#" + token + ":13");
ok(gEditor.getCaretPosition().line == 8 &&
gEditor.getCaretPosition().col == 2 + token.length,
"The editor didn't jump to the correct token. (7)");
isnot(gSources._container.getAttribute("label"), noMatchingSources,
isnot(gSources.widget.getAttribute("label"), noMatchingSources,
"The scripts container should not display a notice that matches are found.");
write("#" + token + ":");
ok(gEditor.getCaretPosition().line == 8 &&
gEditor.getCaretPosition().col == 2 + token.length,
"The editor didn't jump to the correct token. (8)");
isnot(gSources._container.getAttribute("label"), noMatchingSources,
isnot(gSources.widget.getAttribute("label"), noMatchingSources,
"The scripts container should not display a notice that matches are found.");
write("#" + token + "::");
ok(gEditor.getCaretPosition().line == 8 &&
gEditor.getCaretPosition().col == 2 + token.length,
"The editor didn't jump to the correct token. (9)");
isnot(gSources._container.getAttribute("label"), noMatchingSources,
isnot(gSources.widget.getAttribute("label"), noMatchingSources,
"The scripts container should not display a notice that matches are found.");
write("#" + token + ":::");
ok(gEditor.getCaretPosition().line == 8 &&
gEditor.getCaretPosition().col == 2 + token.length,
"The editor didn't jump to the correct token. (10)");
isnot(gSources._container.getAttribute("label"), noMatchingSources,
isnot(gSources.widget.getAttribute("label"), noMatchingSources,
"The scripts container should not display a notice that matches are found.");
@ -189,14 +189,14 @@ function testScriptSearching() {
ok(gEditor.getCaretPosition().line == 8 &&
gEditor.getCaretPosition().col == 2 + token.length,
"The editor didn't remain at the correct token. (11)");
isnot(gSources._container.getAttribute("label"), noMatchingSources,
isnot(gSources.widget.getAttribute("label"), noMatchingSources,
"The scripts container should not display a notice that matches are found.");
write("#__i do not exist__");
ok(gEditor.getCaretPosition().line == 8 &&
gEditor.getCaretPosition().col == 2 + token.length,
"The editor didn't remain at the correct token. (12)");
isnot(gSources._container.getAttribute("label"), noMatchingSources,
isnot(gSources.widget.getAttribute("label"), noMatchingSources,
"The scripts container should not display a notice that matches are found.");
@ -205,7 +205,7 @@ function testScriptSearching() {
ok(gEditor.getCaretPosition().line == 2 &&
gEditor.getCaretPosition().col == 44 + token.length,
"The editor didn't jump to the correct token. (12.1)");
isnot(gSources._container.getAttribute("label"), noMatchingSources,
isnot(gSources.widget.getAttribute("label"), noMatchingSources,
"The scripts container should not display a notice that matches are found.");
clear();
@ -213,14 +213,14 @@ function testScriptSearching() {
ok(gEditor.getCaretPosition().line == 2 &&
gEditor.getCaretPosition().col == 44 + token.length,
"The editor shouldn't jump to another token. (12.2)");
isnot(gSources._container.getAttribute("label"), noMatchingSources,
isnot(gSources.widget.getAttribute("label"), noMatchingSources,
"The scripts container should not display a notice that matches are found.");
EventUtils.sendKey("ENTER", gDebugger);
ok(gEditor.getCaretPosition().line == 2 &&
gEditor.getCaretPosition().col == 44 + token.length,
"The editor shouldn't jump to another token. (12.3)");
isnot(gSources._container.getAttribute("label"), noMatchingSources,
isnot(gSources.widget.getAttribute("label"), noMatchingSources,
"The scripts container should not display a notice that matches are found.");
@ -266,7 +266,7 @@ function testScriptSearching() {
"The editor didn't remain at the correct token. (19)");
is(gSources.visibleItems.length, 1,
"Not all the scripts are shown after the search. (20)");
isnot(gSources._container.getAttribute("label"), noMatchingSources,
isnot(gSources.widget.getAttribute("label"), noMatchingSources,
"The scripts container should not display a notice that matches are found.");
closeDebuggerAndFinish();

Просмотреть файл

@ -195,7 +195,7 @@ function fourthSearch(i, string, token) {
gEditor.getCaretPosition().col == 8 + token.length + i,
"The editor didn't remain at the correct token. (6)");
is(gSources._container.getAttribute("label"), noMatchingSources,
is(gSources.widget.getAttribute("label"), noMatchingSources,
"The scripts container should display a notice that no scripts match the searched token.");
is(gSources.visibleItems.length, 0,
"No scripts should be displayed in the scripts container after a bogus search.");
@ -207,7 +207,7 @@ function fourthSearch(i, string, token) {
gEditor.getCaretPosition().col == 8 + token.length + i,
"The editor didn't remain at the correct token. (7)");
isnot(gSources._container.getAttribute("label"), noMatchingSources,
isnot(gSources.widget.getAttribute("label"), noMatchingSources,
"The scripts container should not display a notice after the searchbox was emptied.");
is(gSources.visibleItems.length, 2,
"Not all the scripts are shown after the searchbox was emptied.");
@ -226,7 +226,7 @@ function noMatchingSourcesSingleCharCheck(token, i) {
gEditor.getCaretPosition().col == 8 + token.length + i,
"The editor didn't remain at the correct token. (8)");
is(gSources._container.getAttribute("label"), noMatchingSources,
is(gSources.widget.getAttribute("label"), noMatchingSources,
"The scripts container should display a notice after no matches are found.");
is(gSources.visibleItems.length, 0,
"No scripts should be shown after no matches are found.");

Просмотреть файл

@ -67,9 +67,9 @@ function testScriptSearching() {
}
function firstSearch() {
is(gSearchView._container._list.childNodes.length, 0,
is(gSearchView.widget._list.childNodes.length, 0,
"The global search pane shouldn't have any child nodes yet.");
is(gSearchView._container._parent.hidden, true,
is(gSearchView.widget._parent.hidden, true,
"The global search pane shouldn't be visible yet.");
is(gSearchView._splitter.hidden, true,
"The global search pane splitter shouldn't be visible yet.");
@ -183,9 +183,9 @@ function firstSearch() {
}
function secondSearch() {
isnot(gSearchView._container._list.childNodes.length, 0,
isnot(gSearchView.widget._list.childNodes.length, 0,
"The global search pane should have some child nodes from the previous search.");
is(gSearchView._container._parent.hidden, false,
is(gSearchView.widget._parent.hidden, false,
"The global search pane should be visible from the previous search.");
is(gSearchView._splitter.hidden, false,
"The global search pane splitter should be visible from the previous search.");
@ -289,9 +289,9 @@ function secondSearch() {
function testClearView() {
gSearchView.clearView();
is(gSearchView._container._list.childNodes.length, 0,
is(gSearchView.widget._list.childNodes.length, 0,
"The global search pane shouldn't have any child nodes after clearView().");
is(gSearchView._container._parent.hidden, true,
is(gSearchView.widget._parent.hidden, true,
"The global search pane shouldn't be visible after clearView().");
is(gSearchView._splitter.hidden, true,
"The global search pane splitter shouldn't be visible after clearView().");

Просмотреть файл

@ -67,9 +67,9 @@ function testScriptSearching() {
}
function doSearch() {
is(gSearchView._container._list.childNodes.length, 0,
is(gSearchView.widget._list.childNodes.length, 0,
"The global search pane shouldn't have any child nodes yet.");
is(gSearchView._container._parent.hidden, true,
is(gSearchView.widget._parent.hidden, true,
"The global search pane shouldn't be visible yet.");
is(gSearchView._splitter.hidden, true,
"The global search pane splitter shouldn't be visible yet.");
@ -89,9 +89,9 @@ function doSearch() {
is(gSources.visibleItems.length, 2,
"Not all the scripts are shown after the global search.");
isnot(gSearchView._container._list.childNodes.length, 0,
isnot(gSearchView.widget._list.childNodes.length, 0,
"The global search pane should be visible now.");
isnot(gSearchView._container._parent.hidden, true,
isnot(gSearchView.widget._parent.hidden, true,
"The global search pane should be visible now.");
isnot(gSearchView._splitter.hidden, true,
"The global search pane splitter should be visible now.");
@ -231,9 +231,9 @@ function testSearchTokenEmpty() {
is(gSources.visibleItems.length, 2,
"Not all the correct scripts are shown after the search. (5)");
is(gSearchView._container._list.childNodes.length, 0,
is(gSearchView.widget._list.childNodes.length, 0,
"The global search pane shouldn't have any child nodes after clear().");
is(gSearchView._container._parent.hidden, true,
is(gSearchView.widget._parent.hidden, true,
"The global search pane shouldn't be visible after clear().");
is(gSearchView._splitter.hidden, true,
"The global search pane splitter shouldn't be visible after clear().");

Просмотреть файл

@ -69,9 +69,9 @@ function testScriptSearching() {
}
function doSearch() {
is(gSearchView._container._list.childNodes.length, 0,
is(gSearchView.widget._list.childNodes.length, 0,
"The global search pane shouldn't have any child nodes yet.");
is(gSearchView._container._parent.hidden, true,
is(gSearchView.widget._parent.hidden, true,
"The global search pane shouldn't be visible yet.");
is(gSearchView._splitter.hidden, true,
"The global search pane splitter shouldn't be visible yet.");
@ -91,9 +91,9 @@ function doSearch() {
is(gSources.visibleItems.length, 2,
"Not all the scripts are shown after the global search.");
isnot(gSearchView._container._list.childNodes.length, 0,
isnot(gSearchView.widget._list.childNodes.length, 0,
"The global search pane should be visible now.");
isnot(gSearchView._container._parent.hidden, true,
isnot(gSearchView.widget._parent.hidden, true,
"The global search pane should be visible now.");
isnot(gSearchView._splitter.hidden, true,
"The global search pane splitter should be visible now.");
@ -116,9 +116,9 @@ function testLocationChange()
info("Still attached to the tab.");
executeSoon(function() {
is(gSearchView._container._list.childNodes.length, 0,
is(gSearchView.widget._list.childNodes.length, 0,
"The global search pane shouldn't have any child nodes after a page navigation.");
is(gSearchView._container._parent.hidden, true,
is(gSearchView.widget._parent.hidden, true,
"The global search pane shouldn't be visible after a page navigation.");
is(gSearchView._splitter.hidden, true,
"The global search pane splitter shouldn't be visible after a page navigation.");

Просмотреть файл

@ -65,7 +65,7 @@ function testScriptSearching() {
}
function doSearch() {
is(gSearchView._container._parent.hidden, true,
is(gSearchView.widget._parent.hidden, true,
"The global search pane shouldn't be visible yet.");
gDebugger.addEventListener("Debugger:GlobalSearch:MatchFound", function _onEvent(aEvent) {
@ -89,7 +89,7 @@ function doSearch() {
function testFocusLost()
{
is(gSearchView._container._parent.hidden, false,
is(gSearchView.widget._parent.hidden, false,
"The global search pane should be visible after a search.");
gDebugger.addEventListener("Debugger:GlobalSearch:ViewCleared", function _onEvent(aEvent) {
@ -112,7 +112,7 @@ function testFocusLost()
}
function reshowSearch() {
is(gSearchView._container._parent.hidden, true,
is(gSearchView.widget._parent.hidden, true,
"The global search pane shouldn't be visible after the search was stopped.");
gDebugger.addEventListener("Debugger:GlobalSearch:MatchFound", function _onEvent(aEvent) {
@ -136,7 +136,7 @@ function reshowSearch() {
function testEscape()
{
is(gSearchView._container._parent.hidden, false,
is(gSearchView.widget._parent.hidden, false,
"The global search pane should be visible after a re-search.");
gDebugger.addEventListener("Debugger:GlobalSearch:ViewCleared", function _onEvent(aEvent) {
@ -160,7 +160,7 @@ function testEscape()
function finalCheck()
{
is(gSearchView._container._parent.hidden, true,
is(gSearchView.widget._parent.hidden, true,
"The global search pane shouldn't be visible after the search was escaped.");
closeDebuggerAndFinish();

Просмотреть файл

@ -484,12 +484,12 @@ function clickAndSwitch() {
}
});
ok(gFilteredSources._container._parent.querySelectorAll(".results-panel-item")[0]
ok(gFilteredSources.widget._parent.querySelectorAll(".results-panel-item")[0]
.classList.contains("results-panel-item"),
"The first visible item target isn't the correct one.");
EventUtils.sendMouseEvent({ type: "click" },
gFilteredSources._container._parent.querySelectorAll(".results-panel-item")[0],
gFilteredSources.widget._parent.querySelectorAll(".results-panel-item")[0],
gDebugger);
}
@ -571,12 +571,12 @@ function clickAndSwitchAgain() {
}
});
ok(gFilteredSources._container._parent.querySelectorAll(".results-panel-item")[2]
ok(gFilteredSources.widget._parent.querySelectorAll(".results-panel-item")[2]
.classList.contains("results-panel-item"),
"The first visible item target isn't the correct one.");
EventUtils.sendMouseEvent({ type: "click" },
gFilteredSources._container._parent.querySelectorAll(".results-panel-item")[2],
gFilteredSources.widget._parent.querySelectorAll(".results-panel-item")[2],
gDebugger);
}

Просмотреть файл

@ -46,7 +46,7 @@ function addScriptAndCheckOrder(method, callback) {
let sv = gDebugger.SourceUtils;
let vs = gDebugger.DebuggerView.Sources;
vs.empty();
vs._container.removeEventListener("select", vs._onScriptsChange, false);
vs.widget.removeEventListener("select", vs._onScriptsChange, false);
let urls = [
{ href: "ici://some.address.com/random/", leaf: "subrandom/" },

Просмотреть файл

@ -97,7 +97,7 @@ function testSelectLine() {
});
});
let frames = gDebugger.DebuggerView.StackFrames._container._list;
let frames = gDebugger.DebuggerView.StackFrames.widget._list;
let childNodes = frames.childNodes;
is(frames.querySelectorAll(".dbg-stackframe").length, 4,

Просмотреть файл

@ -103,7 +103,7 @@ function testHitBreakpoint() {
activeThread.addOneTimeListener("framesadded", function (aEvent, aPacket) {
// Make sure that we have JavaScript stack frames.
let frames = gDebugger.DebuggerView.StackFrames._container._list;
let frames = gDebugger.DebuggerView.StackFrames.widget._list;
let childNodes = frames.childNodes;
is(frames.querySelectorAll(".dbg-stackframe").length, 1,
@ -142,7 +142,7 @@ function testToggleOnPause() {
"The debugger's editor should have the JS source displayed.");
// Make sure that we have coffee script stack frames.
let frames = gDebugger.DebuggerView.StackFrames._container._list;
let frames = gDebugger.DebuggerView.StackFrames.widget._list;
let childNodes = frames.childNodes;
is(frames.querySelectorAll(".dbg-stackframe").length, 1,

Просмотреть файл

@ -24,7 +24,7 @@ function testSimpleCall() {
gDebugger.DebuggerController.activeThread.addOneTimeListener("framesadded", function() {
Services.tm.currentThread.dispatch({ run: function() {
let frames = gDebugger.DebuggerView.StackFrames._container._list;
let frames = gDebugger.DebuggerView.StackFrames.widget._list;
let childNodes = frames.childNodes;
is(gDebugger.DebuggerController.activeThread.state, "paused",

Просмотреть файл

@ -24,7 +24,7 @@ function testEvalCall() {
gDebugger.DebuggerController.activeThread.addOneTimeListener("framesadded", function() {
Services.tm.currentThread.dispatch({ run: function() {
let frames = gDebugger.DebuggerView.StackFrames._container._list;
let frames = gDebugger.DebuggerView.StackFrames.widget._list;
let childNodes = frames.childNodes;
is(gDebugger.DebuggerController.activeThread.state, "paused",

Просмотреть файл

@ -26,7 +26,7 @@ function testRecurse() {
gDebugger.DebuggerController.activeThread.addOneTimeListener("framesadded", function() {
Services.tm.currentThread.dispatch({ run: function() {
let frames = gDebugger.DebuggerView.StackFrames._container._list;
let frames = gDebugger.DebuggerView.StackFrames.widget._list;
let pageSize = gDebugger.gCallStackPageSize;
let recurseLimit = gDebuggee.gRecurseLimit;
let childNodes = frames.childNodes;

Просмотреть файл

@ -24,7 +24,7 @@ function testEvalCallResume() {
gDebugger.DebuggerController.activeThread.addOneTimeListener("framesadded", function() {
Services.tm.currentThread.dispatch({ run: function() {
let frames = gDebugger.DebuggerView.StackFrames._container._list;
let frames = gDebugger.DebuggerView.StackFrames.widget._list;
let childNodes = frames.childNodes;
is(gDebugger.DebuggerController.activeThread.state, "paused",

Просмотреть файл

@ -51,7 +51,7 @@ function test() {
function testRecurse()
{
let frames = gDebugger.DebuggerView.StackFrames._container._list;
let frames = gDebugger.DebuggerView.StackFrames.widget._list;
let childNodes = frames.childNodes;
is(frames.querySelectorAll(".dbg-stackframe").length, 4,

Просмотреть файл

@ -192,35 +192,12 @@ function debug_tab_pane(aURL, aOnDebugging, aBeforeTabAdded) {
});
}
function debug_remote(aURL, aOnDebugging, aBeforeTabAdded) {
// Make any necessary preparations (start the debugger server etc.)
if (aBeforeTabAdded) {
aBeforeTabAdded();
}
let tab = addTab(aURL, function() {
let debuggee = tab.linkedBrowser.contentWindow.wrappedJSObject;
info("Opening Remote Debugger");
let win = DebuggerUI.toggleRemoteDebugger();
// Wait for the initial resume...
win.panelWin.gClient.addOneTimeListener("resumed", function() {
info("Remote Debugger has started");
win._dbgwin.DebuggerView.Variables.lazyEmpty = false;
win._dbgwin.DebuggerView.Variables.lazyAppend = false;
win._dbgwin.DebuggerView.Variables.lazyExpand = false;
aOnDebugging(tab, debuggee, win);
});
});
}
function debug_chrome(aURL, aOnClosing, aOnDebugging) {
let tab = addTab(aURL, function() {
let debuggee = tab.linkedBrowser.contentWindow.wrappedJSObject;
info("Opening Browser Debugger");
let win = DebuggerUI.toggleChromeDebugger(aOnClosing, function(process) {
let win = BrowserDebuggerProcess.init(aOnClosing, function(process) {
// The remote debugging process has started...
info("Browser Debugger has started");

Просмотреть файл

@ -107,7 +107,7 @@ Tools.inspector = {
Tools.jsdebugger = {
id: "jsdebugger",
key: l10n("open.commandkey", debuggerStrings),
key: l10n("debuggerMenu.commandkey", debuggerStrings),
accesskey: l10n("debuggerMenu.accesskey", debuggerStrings),
modifiers: osString == "Darwin" ? "accel,alt" : "accel,shift",
ordinal: 3,

Просмотреть файл

@ -553,9 +553,6 @@ NetMonitorController.NetworkEventsHandler = new NetworkEventsHandler();
* Export some properties to the global scope for easier access.
*/
Object.defineProperties(window, {
"create": {
get: function() ViewHelpers.create
},
"gNetwork": {
get: function() NetMonitorController.NetworkEventsHandler
}

Просмотреть файл

@ -47,13 +47,13 @@ const DEFAULT_EDITOR_CONFIG = {
showLineNumbers: true
};
const GENERIC_VARIABLES_VIEW_SETTINGS = {
lazyEmpty: false,
lazyEmpty: true,
lazyEmptyDelay: 10, // ms
searchEnabled: true,
descriptorTooltip: false,
editableValueTooltip: "",
editableNameTooltip: "",
preventDisableOnChage: true,
preventDescriptorModifiers: true,
eval: () => {},
switch: () => {}
};
@ -260,9 +260,7 @@ ToolbarView.prototype = {
function RequestsMenuView() {
dumpn("RequestsMenuView was instantiated");
this._cache = new Map(); // Can't use a WeakMap because keys are strings.
this._flushRequests = this._flushRequests.bind(this);
this._onRequestItemRemoved = this._onRequestItemRemoved.bind(this);
this._onSelect = this._onSelect.bind(this);
this._onResize = this._onResize.bind(this);
this._byFile = this._byFile.bind(this);
@ -270,20 +268,20 @@ function RequestsMenuView() {
this._byType = this._byType.bind(this);
}
create({ constructor: RequestsMenuView, proto: MenuContainer.prototype }, {
RequestsMenuView.prototype = Heritage.extend(WidgetMethods, {
/**
* Initialization function, called when the network monitor is started.
*/
initialize: function() {
dumpn("Initializing the RequestsMenuView");
this.node = new SideMenuWidget($("#requests-menu-contents"), false);
this.widget = new SideMenuWidget($("#requests-menu-contents"), false);
this._summary = $("#request-menu-network-summary");
this.node.maintainSelectionVisible = false;
this.node.autoscrollWithAppendedItems = true;
this.widget.maintainSelectionVisible = false;
this.widget.autoscrollWithAppendedItems = true;
this.node.addEventListener("select", this._onSelect, false);
this.widget.addEventListener("select", this._onSelect, false);
window.addEventListener("resize", this._onResize, false);
},
@ -293,7 +291,7 @@ create({ constructor: RequestsMenuView, proto: MenuContainer.prototype }, {
destroy: function() {
dumpn("Destroying the SourcesView");
this.node.removeEventListener("select", this._onSelect, false);
this.widget.removeEventListener("select", this._onSelect, false);
window.removeEventListener("resize", this._onResize, false);
},
@ -338,33 +336,31 @@ create({ constructor: RequestsMenuView, proto: MenuContainer.prototype }, {
this._registerLastRequestEnd(unixTime);
// Append a network request item to this container.
let requestItem = this.push(menuView, {
let requestItem = this.push([menuView, aId], {
attachment: {
id: aId,
startedDeltaMillis: unixTime - this._firstRequestStartedMillis,
startedMillis: unixTime,
method: aMethod,
url: aUrl,
isXHR: aIsXHR
},
finalize: this._onRequestItemRemoved
}
});
$("#details-pane-toggle").disabled = false;
$("#requests-menu-empty-notice").hidden = true;
this.refreshSummary();
this._cache.set(aId, requestItem);
this.refreshZebra();
},
/**
* Filters all network requests in this container by a specified type.
*
* @param string aType
* Either null, "html", "css", "js", "xhr", "fonts", "images", "media"
* Either "all", "html", "css", "js", "xhr", "fonts", "images", "media"
* or "flash".
*/
filterOn: function(aType) {
filterOn: function(aType = "all") {
let target = $("#requests-menu-filter-" + aType + "-button");
let buttons = document.querySelectorAll(".requests-menu-footer-button");
@ -372,16 +368,15 @@ create({ constructor: RequestsMenuView, proto: MenuContainer.prototype }, {
if (button != target) {
button.removeAttribute("checked");
} else {
button.setAttribute("checked", "");
button.setAttribute("checked", "true");
}
}
// Filter on nothing.
if (!target) {
this.filterContents(() => true);
}
// Filter on whatever was requested.
else switch (aType) {
switch (aType) {
case "all":
this.filterContents(() => true);
break;
case "html":
this.filterContents(this._onHtml);
break;
@ -409,13 +404,15 @@ create({ constructor: RequestsMenuView, proto: MenuContainer.prototype }, {
}
this.refreshSummary();
this.refreshZebra();
},
/**
* Sorts all network requests in this container by a specified detail.
*
* @param string aType
* Either "status", "method", "file", "domain", "type", "size" or "waterfall".
* Either "status", "method", "file", "domain", "type", "size" or
* "waterfall".
*/
sortBy: function(aType = "waterfall") {
let target = $("#requests-menu-" + aType + "-button");
@ -491,15 +488,18 @@ create({ constructor: RequestsMenuView, proto: MenuContainer.prototype }, {
}
break;
}
this.refreshSummary();
this.refreshZebra();
},
/**
* Predicates used when filtering items.
*
* @param MenuItem aItem
* The filtered menu item.
* @param object aItem
* The filtered item.
* @return boolean
* True if the menu item should be visible, false otherwise.
* True if the item should be visible, false otherwise.
*/
_onHtml: function({ attachment: { mimeType } })
mimeType && mimeType.contains("/html"),
@ -544,10 +544,10 @@ create({ constructor: RequestsMenuView, proto: MenuContainer.prototype }, {
/**
* Predicates used when sorting items.
*
* @param MenuItem aFirst
* The first menu item used in the comparison.
* @param MenuItem aSecond
* The second menu item used in the comparison.
* @param object aFirst
* The first item used in the comparison.
* @param object aSecond
* The second item used in the comparison.
* @return number
* -1 to sort aFirst to a lower index than aSecond
* 0 to leave aFirst and aSecond unchanged with respect to each other
@ -603,6 +603,26 @@ create({ constructor: RequestsMenuView, proto: MenuContainer.prototype }, {
);
},
/**
* Adds odd/even attributes to all the visible items in this container.
*/
refreshZebra: function() {
let visibleItems = this.orderedVisibleItems;
for (let i = 0, len = visibleItems.length; i < len; i++) {
let requestItem = visibleItems[i];
let requestTarget = requestItem.target;
if (i % 2 == 0) {
requestTarget.setAttribute("even", "");
requestTarget.removeAttribute("odd");
} else {
requestTarget.setAttribute("odd", "");
requestTarget.removeAttribute("even");
}
}
},
/**
* Schedules adding additional information to a network request.
*
@ -634,7 +654,7 @@ create({ constructor: RequestsMenuView, proto: MenuContainer.prototype }, {
// For each queued additional information packet, get the corresponding
// request item in the view and update it based on the specified data.
for (let [id, data] of this._updateQueue) {
let requestItem = this._cache.get(id);
let requestItem = this.getItemByValue(id);
if (!requestItem) {
// Packet corresponds to a dead request item, target navigated.
continue;
@ -707,7 +727,7 @@ create({ constructor: RequestsMenuView, proto: MenuContainer.prototype }, {
// This update may have additional information about a request which
// isn't shown yet in the network details pane.
let selectedItem = this.selectedItem;
if (selectedItem && selectedItem.attachment.id == id) {
if (selectedItem && selectedItem.value == id) {
NetMonitorView.NetworkDetails.populate(selectedItem.attachment);
}
}
@ -723,6 +743,7 @@ create({ constructor: RequestsMenuView, proto: MenuContainer.prototype }, {
this.sortContents();
this.filterContents();
this.refreshSummary();
this.refreshZebra();
},
/**
@ -768,7 +789,7 @@ create({ constructor: RequestsMenuView, proto: MenuContainer.prototype }, {
/**
* Updates the information displayed in a network request item view.
*
* @param MenuItem aItem
* @param object aItem
* The network request item in this container.
* @param string aKey
* The type of information that is to be updated.
@ -817,7 +838,7 @@ create({ constructor: RequestsMenuView, proto: MenuContainer.prototype }, {
/**
* Creates a waterfall representing timing information in a network request item view.
*
* @param MenuItem aItem
* @param object aItem
* The network request item in this container.
* @param object aTimings
* An object containing timing information.
@ -892,7 +913,7 @@ create({ constructor: RequestsMenuView, proto: MenuContainer.prototype }, {
// Apply CSS transforms to each waterfall in this container totalTime
// accurately translate and resize as needed.
for (let [, { target, attachment }] of this._cache) {
for (let { target, attachment } in this) {
let timingsNode = $(".requests-menu-timings", target);
let startCapNode = $(".requests-menu-timings-cap.start", target);
let endCapNode = $(".requests-menu-timings-cap.end", target);
@ -1028,7 +1049,7 @@ create({ constructor: RequestsMenuView, proto: MenuContainer.prototype }, {
* Reapplies the current waterfall background on all request items.
*/
_flushWaterfallBackgrounds: function() {
for (let [, { target }] of this._cache) {
for (let { target } in this) {
let waterfallNode = $(".requests-menu-waterfall", target);
waterfallNode.style.backgroundImage = this._cachedWaterfallBackground;
}
@ -1063,17 +1084,6 @@ create({ constructor: RequestsMenuView, proto: MenuContainer.prototype }, {
});
},
/**
* Function called each time a network request item is removed.
*
* @param MenuItem aItem
* The corresponding menu item.
*/
_onRequestItemRemoved: function(aItem) {
dumpn("Finalizing network request item: " + aItem);
this._cache.delete(aItem.attachment.id);
},
/**
* The selection listener for this container.
*/
@ -1173,7 +1183,7 @@ create({ constructor: RequestsMenuView, proto: MenuContainer.prototype }, {
* empty set.
*
* @param array aItemsArray
* @return MenuItem
* @return object
*/
_getOldestRequest: function(aItemsArray) {
if (!aItemsArray.length) {
@ -1188,7 +1198,7 @@ create({ constructor: RequestsMenuView, proto: MenuContainer.prototype }, {
* empty set.
*
* @param array aItemsArray
* @return MenuItem
* @return object
*/
_getNewestRequest: function(aItemsArray) {
if (!aItemsArray.length) {
@ -1217,7 +1227,6 @@ create({ constructor: RequestsMenuView, proto: MenuContainer.prototype }, {
return this._cachedWaterfallWidth;
},
_cache: null,
_summary: null,
_canvas: null,
_ctx: null,
@ -1246,26 +1255,26 @@ NetworkDetailsView.prototype = {
initialize: function() {
dumpn("Initializing the RequestsMenuView");
this.node = $("#details-pane");
this.widget = $("#details-pane");
this._headers = new VariablesView($("#all-headers"),
Object.create(GENERIC_VARIABLES_VIEW_SETTINGS, {
emptyText: { value: L10N.getStr("headersEmptyText"), enumerable: true },
searchPlaceholder: { value: L10N.getStr("headersFilterText"), enumerable: true }
Heritage.extend(GENERIC_VARIABLES_VIEW_SETTINGS, {
emptyText: L10N.getStr("headersEmptyText"),
searchPlaceholder: L10N.getStr("headersFilterText")
}));
this._cookies = new VariablesView($("#all-cookies"),
Object.create(GENERIC_VARIABLES_VIEW_SETTINGS, {
emptyText: { value: L10N.getStr("cookiesEmptyText"), enumerable: true },
searchPlaceholder: { value: L10N.getStr("cookiesFilterText"), enumerable: true }
Heritage.extend(GENERIC_VARIABLES_VIEW_SETTINGS, {
emptyText: L10N.getStr("cookiesEmptyText"),
searchPlaceholder: L10N.getStr("cookiesFilterText")
}));
this._params = new VariablesView($("#request-params"),
Object.create(GENERIC_VARIABLES_VIEW_SETTINGS, {
emptyText: { value: L10N.getStr("paramsEmptyText"), enumerable: true },
searchPlaceholder: { value: L10N.getStr("paramsFilterText"), enumerable: true }
Heritage.extend(GENERIC_VARIABLES_VIEW_SETTINGS, {
emptyText: L10N.getStr("paramsEmptyText"),
searchPlaceholder: L10N.getStr("paramsFilterText")
}));
this._json = new VariablesView($("#response-content-json"),
Object.create(GENERIC_VARIABLES_VIEW_SETTINGS, {
searchPlaceholder: { value: L10N.getStr("jsonFilterText"), enumerable: true }
Heritage.extend(GENERIC_VARIABLES_VIEW_SETTINGS, {
searchPlaceholder: L10N.getStr("jsonFilterText")
}));
this._paramsQueryString = L10N.getStr("paramsQueryString");
@ -1276,7 +1285,7 @@ NetworkDetailsView.prototype = {
this._requestCookies = L10N.getStr("requestCookies");
this._responseCookies = L10N.getStr("responseCookies");
$("tabpanels", this.node).addEventListener("select", this._onTabSelect);
$("tabpanels", this.widget).addEventListener("select", this._onTabSelect);
},
/**
@ -1334,7 +1343,7 @@ NetworkDetailsView.prototype = {
*/
_onTabSelect: function() {
let { src, populated } = this._dataSrc || {};
let tab = this.node.selectedIndex;
let tab = this.widget.selectedIndex;
// Make sure the data source is valid and don't populate the same tab twice.
if (!src || populated[tab]) {
@ -1446,7 +1455,7 @@ NetworkDetailsView.prototype = {
headersScope.expanded = true;
for (let header of aResponse.headers) {
let headerVar = headersScope.addItem(header.name, { null: true }, true);
let headerVar = headersScope.addItem(header.name, {}, true);
gNetwork.getString(header.value).then((aString) => headerVar.setGrip(aString));
}
},
@ -1489,7 +1498,7 @@ NetworkDetailsView.prototype = {
cookiesScope.expanded = true;
for (let cookie of aResponse.cookies) {
let cookieVar = cookiesScope.addItem(cookie.name, { null: true }, true);
let cookieVar = cookiesScope.addItem(cookie.name, {}, true);
gNetwork.getString(cookie.value).then((aString) => cookieVar.setGrip(aString));
// By default the cookie name and value are shown. If this is the only
@ -1591,7 +1600,7 @@ NetworkDetailsView.prototype = {
paramsScope.expanded = true;
for (let param of paramsArray) {
let headerVar = paramsScope.addItem(param.name, { null: true }, true);
let headerVar = paramsScope.addItem(param.name, {}, true);
headerVar.setGrip(param.value);
}
},

Просмотреть файл

@ -102,7 +102,7 @@
tabindex="0"/>
</toolbar>
<label id="requests-menu-empty-notice"
value="&netmonitorUI.emptyNotice;"/>
value="&netmonitorUI.emptyNotice2;"/>
<vbox id="requests-menu-contents" flex="1">
<hbox id="requests-menu-item-template" hidden="true">
<hbox class="requests-menu-subitem requests-menu-status-and-method"
@ -138,7 +138,8 @@
flex="100"/>
<button id="requests-menu-filter-all-button"
class="requests-menu-footer-button"
onclick="NetMonitorView.RequestsMenu.filterOn(null)"
checked="true"
onclick="NetMonitorView.RequestsMenu.filterOn('all')"
label="&netmonitorUI.footer.filterAll;">
</button>
<button id="requests-menu-filter-html-button"

Просмотреть файл

@ -24,7 +24,7 @@ function test() {
is(NetMonitorView.detailsPaneHidden, false,
"The details pane should not be hidden after toggle button was pressed.");
testButtons();
testButtons("all");
testContents([1, 1, 1, 1, 1, 1, 1, 1])
.then(() => {
EventUtils.sendMouseEvent({ type: "click" }, $("#requests-menu-filter-html-button"));
@ -68,7 +68,7 @@ function test() {
})
.then(() => {
EventUtils.sendMouseEvent({ type: "click" }, $("#requests-menu-filter-all-button"));
testButtons();
testButtons("all");
return testContents([1, 1, 1, 1, 1, 1, 1, 1]);
})
.then(() => {

Просмотреть файл

@ -24,7 +24,7 @@ function test() {
is(NetMonitorView.detailsPaneHidden, false,
"The details pane should not be hidden after toggle button was pressed.");
testButtons();
testButtons("all");
testContents([1, 1, 1, 1, 1, 1, 1, 1])
.then(() => {
info("Testing html filtering.");

Просмотреть файл

@ -25,12 +25,12 @@ function test() {
is(NetMonitorView.detailsPaneHidden, false,
"The details pane should not be hidden after toggle button was pressed.");
testButtons();
testButtons("all");
testContents([0, 1, 2, 3, 4, 5, 6], 7, 0)
.then(() => {
info("Sorting by size, ascending.");
EventUtils.sendMouseEvent({ type: "click" }, $("#requests-menu-size-button"));
testButtons();
testButtons("all");
return testContents([6, 4, 5, 0, 1, 2, 3], 7, 6);
})
.then(() => {

Просмотреть файл

@ -29,10 +29,10 @@ function test() {
let requestItem = RequestsMenu.getItemAtIndex(0);
let target = requestItem.target;
is(typeof requestItem.attachment.id, "string",
"The attached id is incorrect.");
isnot(requestItem.attachment.id, "",
"The attached id should not be empty.");
is(typeof requestItem.value, "string",
"The attached request id is incorrect.");
isnot(requestItem.value, "",
"The attached request id should not be empty.");
is(typeof requestItem.attachment.startedDeltaMillis, "number",
"The attached startedDeltaMillis is incorrect.");

Просмотреть файл

@ -19,126 +19,151 @@ function test() {
.then(() => {
info("Testing swap(0, 0)");
RequestsMenu.swapItemsAtIndices(0, 0);
RequestsMenu.refreshZebra();
return testContents([0, 1, 2, 3, 4]);
})
.then(() => {
info("Testing swap(0, 1)");
RequestsMenu.swapItemsAtIndices(0, 1);
RequestsMenu.refreshZebra();
return testContents([1, 0, 2, 3, 4]);
})
.then(() => {
info("Testing swap(0, 2)");
RequestsMenu.swapItemsAtIndices(0, 2);
RequestsMenu.refreshZebra();
return testContents([1, 2, 0, 3, 4]);
})
.then(() => {
info("Testing swap(0, 3)");
RequestsMenu.swapItemsAtIndices(0, 3);
RequestsMenu.refreshZebra();
return testContents([1, 2, 3, 0, 4]);
})
.then(() => {
info("Testing swap(0, 4)");
RequestsMenu.swapItemsAtIndices(0, 4);
RequestsMenu.refreshZebra();
return testContents([1, 2, 3, 4, 0]);
})
.then(() => {
info("Testing swap(1, 0)");
RequestsMenu.swapItemsAtIndices(1, 0);
RequestsMenu.refreshZebra();
return testContents([0, 2, 3, 4, 1]);
})
.then(() => {
info("Testing swap(1, 1)");
RequestsMenu.swapItemsAtIndices(1, 1);
RequestsMenu.refreshZebra();
return testContents([0, 2, 3, 4, 1]);
})
.then(() => {
info("Testing swap(1, 2)");
RequestsMenu.swapItemsAtIndices(1, 2);
RequestsMenu.refreshZebra();
return testContents([0, 1, 3, 4, 2]);
})
.then(() => {
info("Testing swap(1, 3)");
RequestsMenu.swapItemsAtIndices(1, 3);
RequestsMenu.refreshZebra();
return testContents([0, 3, 1, 4, 2]);
})
.then(() => {
info("Testing swap(1, 4)");
RequestsMenu.swapItemsAtIndices(1, 4);
RequestsMenu.refreshZebra();
return testContents([0, 3, 4, 1, 2]);
})
.then(() => {
info("Testing swap(2, 0)");
RequestsMenu.swapItemsAtIndices(2, 0);
RequestsMenu.refreshZebra();
return testContents([2, 3, 4, 1, 0]);
})
.then(() => {
info("Testing swap(2, 1)");
RequestsMenu.swapItemsAtIndices(2, 1);
RequestsMenu.refreshZebra();
return testContents([1, 3, 4, 2, 0]);
})
.then(() => {
info("Testing swap(2, 2)");
RequestsMenu.swapItemsAtIndices(2, 2);
RequestsMenu.refreshZebra();
return testContents([1, 3, 4, 2, 0]);
})
.then(() => {
info("Testing swap(2, 3)");
RequestsMenu.swapItemsAtIndices(2, 3);
RequestsMenu.refreshZebra();
return testContents([1, 2, 4, 3, 0]);
})
.then(() => {
info("Testing swap(2, 4)");
RequestsMenu.swapItemsAtIndices(2, 4);
RequestsMenu.refreshZebra();
return testContents([1, 4, 2, 3, 0]);
})
.then(() => {
info("Testing swap(3, 0)");
RequestsMenu.swapItemsAtIndices(3, 0);
RequestsMenu.refreshZebra();
return testContents([1, 4, 2, 0, 3]);
})
.then(() => {
info("Testing swap(3, 1)");
RequestsMenu.swapItemsAtIndices(3, 1);
RequestsMenu.refreshZebra();
return testContents([3, 4, 2, 0, 1]);
})
.then(() => {
info("Testing swap(3, 2)");
RequestsMenu.swapItemsAtIndices(3, 2);
RequestsMenu.refreshZebra();
return testContents([2, 4, 3, 0, 1]);
})
.then(() => {
info("Testing swap(3, 3)");
RequestsMenu.swapItemsAtIndices(3, 3);
RequestsMenu.refreshZebra();
return testContents([2, 4, 3, 0, 1]);
})
.then(() => {
info("Testing swap(3, 4)");
RequestsMenu.swapItemsAtIndices(3, 4);
RequestsMenu.refreshZebra();
return testContents([2, 3, 4, 0, 1]);
})
.then(() => {
info("Testing swap(4, 0)");
RequestsMenu.swapItemsAtIndices(4, 0);
RequestsMenu.refreshZebra();
return testContents([2, 3, 0, 4, 1]);
})
.then(() => {
info("Testing swap(4, 1)");
RequestsMenu.swapItemsAtIndices(4, 1);
RequestsMenu.refreshZebra();
return testContents([2, 3, 0, 1, 4]);
})
.then(() => {
info("Testing swap(4, 2)");
RequestsMenu.swapItemsAtIndices(4, 2);
RequestsMenu.refreshZebra();
return testContents([4, 3, 0, 1, 2]);
})
.then(() => {
info("Testing swap(4, 3)");
RequestsMenu.swapItemsAtIndices(4, 3);
RequestsMenu.refreshZebra();
return testContents([3, 4, 0, 1, 2]);
})
.then(() => {
info("Testing swap(4, 4)");
RequestsMenu.swapItemsAtIndices(4, 4);
RequestsMenu.refreshZebra();
return testContents([3, 4, 0, 1, 2]);
})
.then(() => {

Просмотреть файл

@ -191,6 +191,13 @@ function verifyRequestItemTarget(aRequestItem, aMethod, aUrl, aData = {}) {
info("> Verifying: " + aMethod + " " + aUrl + " " + aData.toSource());
info("> Request: " + aRequestItem.attachment.toSource());
let requestsMenu = aRequestItem.ownerView;
let widgetIndex = requestsMenu.indexOfItem(aRequestItem);
let visibleIndex = requestsMenu.orderedVisibleItems.indexOf(aRequestItem);
info("Widget index of item: " + widgetIndex);
info("Visible index of item: " + visibleIndex);
let { fuzzyUrl, status, statusText, type, fullMimeType, size, time } = aData;
let { attachment, target } = aRequestItem
@ -259,4 +266,18 @@ function verifyRequestItemTarget(aRequestItem, aMethod, aUrl, aData = {}) {
ok(~~(value.match(/[0-9]+/)) >= 0, "The displayed time is incorrect.");
ok(~~(tooltip.match(/[0-9]+/)) >= 0, "The tooltip time is incorrect.");
}
if (visibleIndex != -1) {
if (visibleIndex % 2 == 0) {
ok(aRequestItem.target.hasAttribute("even"),
"Unexpected 'even' attribute for " + aRequestItem.value);
ok(!aRequestItem.target.hasAttribute("odd"),
"Unexpected 'odd' attribute for " + aRequestItem.value);
} else {
ok(!aRequestItem.target.hasAttribute("even"),
"Unexpected 'even' attribute for " + aRequestItem.value);
ok(aRequestItem.target.hasAttribute("odd"),
"Unexpected 'odd' attribute for " + aRequestItem.value);
}
}
}

Просмотреть файл

@ -270,12 +270,12 @@ ProfileUI.prototype = {
function SidebarView(el) {
EventEmitter.decorate(this);
this.node = new SideMenuWidget(el);
this.widget = new SideMenuWidget(el);
}
ViewHelpers.create({ constructor: SidebarView, proto: MenuContainer.prototype }, {
SidebarView.prototype = Heritage.extend(WidgetMethods, {
getItemByProfile: function (profile) {
return this.orderedItems.filter((item) => item.attachment.uid === profile.uid)[0];
return this.getItemForPredicate(item => item.attachment.uid === profile.uid);
},
setProfileState: function (profile, state) {
@ -402,7 +402,7 @@ ProfilerPanel.prototype = {
this.controller = new ProfilerController(this.target);
this.sidebar = new SidebarView(this.document.querySelector("#profiles-list"));
this.sidebar.node.addEventListener("select", (ev) => {
this.sidebar.widget.addEventListener("select", (ev) => {
if (!ev.detail)
return;
@ -489,7 +489,7 @@ ProfilerPanel.prototype = {
box.appendChild(h3);
box.appendChild(span);
this.sidebar.push(box, { attachment: { uid: uid, name: name, state: PROFILE_IDLE } });
this.sidebar.push([box], { attachment: { uid: uid, name: name, state: PROFILE_IDLE } });
let profile = new ProfileUI(uid, name, this);
this.profiles.set(uid, profile);

Просмотреть файл

@ -273,7 +273,7 @@ var Scratchpad = {
get sidebar()
{
if (!this._sidebar) {
this._sidebar = new ScratchpadSidebar();
this._sidebar = new ScratchpadSidebar(this);
}
return this._sidebar;
},
@ -475,7 +475,7 @@ var Scratchpad = {
this.sidebar.open(aString, aResult).then(resolve, reject);
}
}, reject);
return deferred.promise;
},
@ -882,7 +882,7 @@ var Scratchpad = {
/**
* Clear a range of files from the list.
*
*
* @param integer aIndex
* Index of file in menu to remove.
* @param integer aLength
@ -1481,12 +1481,12 @@ var Scratchpad = {
* Encapsulates management of the sidebar containing the VariablesView for
* object inspection.
*/
function ScratchpadSidebar()
function ScratchpadSidebar(aScratchpad)
{
let ToolSidebar = devtools.require("devtools/framework/sidebar").ToolSidebar;
let tabbox = document.querySelector("#scratchpad-sidebar");
this._sidebar = new ToolSidebar(tabbox, this);
this._splitter = document.querySelector(".devtools-side-splitter");
this._scratchpad = aScratchpad;
}
ScratchpadSidebar.prototype = {
@ -1495,11 +1495,6 @@ ScratchpadSidebar.prototype = {
*/
_sidebar: null,
/*
* The splitter element between the sidebar and the editor.
*/
_splitter: null,
/*
* The VariablesView for this sidebar.
*/
@ -1531,7 +1526,11 @@ ScratchpadSidebar.prototype = {
if (!this.variablesView) {
let window = this._sidebar.getWindowForTab("variablesview");
let container = window.document.querySelector("#variables");
this.variablesView = new VariablesView(container);
this.variablesView = new VariablesView(container, {
searchEnabled: true,
searchPlaceholder: this._scratchpad.strings
.GetStringFromName("propertiesFilterPlaceholder")
});
}
this._update(aObject).then(() => deferred.resolve());
};
@ -1555,7 +1554,6 @@ ScratchpadSidebar.prototype = {
if (!this.visible) {
this.visible = true;
this._sidebar.show();
this._splitter.setAttribute("state", "open");
}
},
@ -1567,7 +1565,6 @@ ScratchpadSidebar.prototype = {
if (this.visible) {
this.visible = false;
this._sidebar.hide();
this._splitter.setAttribute("state", "collapsed");
}
},

Просмотреть файл

@ -288,10 +288,10 @@
<notificationbox id="scratchpad-notificationbox" flex="1">
<hbox flex="1">
<vbox id="scratchpad-editor" flex="1"/>
<splitter class="devtools-side-splitter"
collapse="after"
state="collapsed"/>
<tabbox id="scratchpad-sidebar" class="devtools-sidebar-tabs" width="300">
<splitter class="devtools-side-splitter"/>
<tabbox id="scratchpad-sidebar" class="devtools-sidebar-tabs"
width="300"
hidden="true">
<tabs/>
<tabpanels flex="1"/>
</tabbox>

Просмотреть файл

@ -41,6 +41,15 @@ function runTests()
ok(found, "found the property");
finish();
let tabbox = sidebar._sidebar._tabbox;
is(tabbox.width, 300, "Scratchpad sidebar width is correct");
ok(!tabbox.hasAttribute("hidden"), "Scratchpad sidebar visible");
sidebar.hide();
ok(tabbox.hasAttribute("hidden"), "Scratchpad sidebar hidden");
sp.inspect().then(function() {
is(tabbox.width, 300, "Scratchpad sidebar width is still correct");
ok(!tabbox.hasAttribute("hidden"), "Scratchpad sidebar visible again");
finish();
});
});
}
}

Просмотреть файл

@ -17,20 +17,7 @@ this.EXPORTED_SYMBOLS = ["BreadcrumbsWidget"];
/**
* A breadcrumb-like list of items.
*
* You can use this widget alone, but it works great with a MenuContainer!
* In that case, you should never need to access the methods in the
* BreadcrumbsWidget directly, use the wrapper MenuContainer instance instead.
*
* @see ViewHelpers.jsm
*
* function MyView() {
* this.node = new BreadcrumbsWidget(document.querySelector(".my-node"));
* }
* ViewHelpers.create({ constructor: MyView, proto: MenuContainer.prototype }, {
* myMethod: function() {},
* ...
* });
* This widget should be used in tandem with the WidgetMethods in ViewHelpers.jsm
*
* @param nsIDOMNode aNode
* The element associated with the widget.

Просмотреть файл

@ -21,20 +21,7 @@ this.EXPORTED_SYMBOLS = ["SideMenuWidget"];
/**
* A simple side menu, with the ability of grouping menu items.
*
* You can use this widget alone, but it works great with a MenuContainer!
* In that case, you should never need to access the methods in the
* SideMenuWidget directly, use the wrapper MenuContainer instance instead.
*
* @see ViewHelpers.jsm
*
* function MyView() {
* this.node = new SideMenuWidget(document.querySelector(".my-node"));
* }
* ViewHelpers.create({ constructor: MyView, proto: MenuContainer.prototype }, {
* myMethod: function() {},
* ...
* });
* This widget should be used in tandem with the WidgetMethods in ViewHelpers.jsm
*
* @param nsIDOMNode aNode
* The element associated with the widget.

Просмотреть файл

@ -53,7 +53,7 @@ const STR = Services.strings.createBundle(DBG_STRINGS_URI);
* e.g. { lazyEmpty: true, searchEnabled: true ... }
*/
this.VariablesView = function VariablesView(aParentNode, aFlags = {}) {
this._store = [];
this._store = []; // Can't use a Map because Scope names needn't be unique.
this._itemsByElement = new WeakMap();
this._prevHierarchy = new Map();
this._currHierarchy = new Map();
@ -84,13 +84,13 @@ VariablesView.prototype = {
/**
* Helper setter for populating this container with a raw object.
*
* @param object aData
* @param object aObject
* The raw object to display. You can only provide this object
* if you want the variables view to work in sync mode.
*/
set rawObject(aObject) {
this.empty();
this.addScope().addItem().populate(aObject);
this.addScope().addItem().populate(aObject, { sorted: true });
},
/**
@ -245,6 +245,16 @@ VariablesView.prototype = {
*/
preventDisableOnChage: false,
/**
* Specifies if, whenever a variable or property descriptor is available,
* configurable, enumerable, writable, frozen, sealed and extensible
* attributes should not affect presentation.
*
* This flag is applied recursively onto each scope in this view and
* affects only the child nodes when they're created.
*/
preventDescriptorModifiers: false,
/**
* The tooltip text shown on a variable or property's value if an |eval|
* function is provided, in order to change the variable or property's value.
@ -282,15 +292,6 @@ VariablesView.prototype = {
*/
deleteButtonTooltip: STR.GetStringFromName("variablesCloseButtonTooltip"),
/**
* Specifies if the configurable, enumerable or writable tooltip should be
* shown whenever a variable or property descriptor is available.
*
* This flag is applied recursively onto each scope in this view and
* affects only the child nodes when they're created.
*/
descriptorTooltip: true,
/**
* Specifies the context menu attribute set on variables and properties.
*
@ -1086,7 +1087,6 @@ function Scope(aView, aName, aFlags = {}) {
this._openEnum = this._openEnum.bind(this);
this._openNonEnum = this._openNonEnum.bind(this);
this._batchAppend = this._batchAppend.bind(this);
this._batchItems = [];
// Inherit properties and flags from the parent view. You can override
// each of these directly onto any scope, variable or property instance.
@ -1097,13 +1097,18 @@ function Scope(aView, aName, aFlags = {}) {
this.editableNameTooltip = aView.editableNameTooltip;
this.editButtonTooltip = aView.editButtonTooltip;
this.deleteButtonTooltip = aView.deleteButtonTooltip;
this.descriptorTooltip = aView.descriptorTooltip;
this.preventDescriptorModifiers = aView.preventDescriptorModifiers;
this.contextMenuId = aView.contextMenuId;
this.separatorStr = aView.separatorStr;
this._store = new Map();
this._enumItems = [];
this._nonEnumItems = [];
// Creating maps and arrays thousands of times for variables or properties
// with a large number of children fills up a lot of memory. Make sure
// these are instantiated only if needed.
XPCOMUtils.defineLazyGetter(this, "_store", () => new Map());
XPCOMUtils.defineLazyGetter(this, "_enumItems", () => []);
XPCOMUtils.defineLazyGetter(this, "_nonEnumItems", () => []);
XPCOMUtils.defineLazyGetter(this, "_batchItems", () => []);
this._init(aName.trim(), aFlags);
}
@ -1991,7 +1996,7 @@ Scope.prototype = {
editableNameTooltip: "",
editButtonTooltip: "",
deleteButtonTooltip: "",
descriptorTooltip: true,
preventDescriptorModifiers: false,
contextMenuId: "",
separatorStr: "",
@ -2034,7 +2039,7 @@ Scope.prototype = {
* The variable's descriptor.
*/
function Variable(aScope, aName, aDescriptor) {
this._displayTooltip = this._displayTooltip.bind(this);
this._setTooltips = this._setTooltips.bind(this);
this._activateNameInput = this._activateNameInput.bind(this);
this._activateValueInput = this._activateValueInput.bind(this);
@ -2051,7 +2056,7 @@ function Variable(aScope, aName, aDescriptor) {
this._absoluteName = aScope.name + "[\"" + aName + "\"]";
}
ViewHelpers.create({ constructor: Variable, proto: Scope.prototype }, {
Variable.prototype = Heritage.extend(Scope.prototype, {
/**
* Whether this Scope should be prefetched when it is remoted.
*/
@ -2265,7 +2270,7 @@ ViewHelpers.create({ constructor: Variable, proto: Scope.prototype }, {
if (this._nameString) {
this._displayVariable();
this._customizeVariable();
this._prepareTooltip();
this._prepareTooltips();
this._setAttributes();
this._addEventListeners();
}
@ -2353,7 +2358,10 @@ ViewHelpers.create({ constructor: Variable, proto: Scope.prototype }, {
* Adds specific nodes for this variable based on custom flags.
*/
_customizeVariable: function() {
if (this.ownerView.eval) {
let ownerView = this.ownerView;
let descriptor = this._initialDescriptor;
if (ownerView.eval) {
if (!this._isUndefined && (this.getter || this.setter)) {
let editNode = this._editNode = this.document.createElement("toolbarbutton");
editNode.className = "plain variables-view-edit";
@ -2361,61 +2369,95 @@ ViewHelpers.create({ constructor: Variable, proto: Scope.prototype }, {
this._title.appendChild(editNode);
}
}
if (this.ownerView.delete) {
if (!this._isUndefined || !(this.ownerView.getter && this.ownerView.setter)) {
if (ownerView.delete) {
if (!this._isUndefined || !(ownerView.getter && ownerView.setter)) {
let deleteNode = this._deleteNode = this.document.createElement("toolbarbutton");
deleteNode.className = "plain variables-view-delete";
deleteNode.addEventListener("click", this._onDelete.bind(this), false);
this._title.appendChild(deleteNode);
}
}
if (this.ownerView.contextMenuId) {
this._title.setAttribute("context", this.ownerView.contextMenuId);
if (ownerView.contextMenuId) {
this._title.setAttribute("context", ownerView.contextMenuId);
}
},
/**
* Prepares a tooltip for this variable.
*/
_prepareTooltip: function() {
this._target.addEventListener("mouseover", this._displayTooltip, false);
},
if (ownerView.preventDescriptorModifiers) {
return;
}
/**
* Creates a tooltip for this variable.
*/
_displayTooltip: function() {
this._target.removeEventListener("mouseover", this._displayTooltip, false);
if (this.ownerView.descriptorTooltip) {
let document = this.document;
let tooltip = document.createElement("tooltip");
tooltip.id = "tooltip-" + this._idString;
tooltip.setAttribute("orient", "horizontal");
let labels = ["configurable", "enumerable", "writable", "native-getter",
"frozen", "sealed", "non-extensible"];
for (let label of labels) {
let labelElement = document.createElement("label");
labelElement.setAttribute("value", label);
tooltip.appendChild(labelElement);
if (!descriptor.writable && !ownerView.getter && !ownerView.setter) {
let nonWritableIcon = this.document.createElement("hbox");
nonWritableIcon.className = "variable-or-property-non-writable-icon";
this._title.appendChild(nonWritableIcon);
}
if (descriptor.value && typeof descriptor.value == "object") {
if (descriptor.value.frozen) {
let frozenLabel = this.document.createElement("label");
frozenLabel.className = "plain variable-or-property-frozen-label";
frozenLabel.setAttribute("value", "F");
this._title.appendChild(frozenLabel);
}
if (descriptor.value.sealed) {
let sealedLabel = this.document.createElement("label");
sealedLabel.className = "plain variable-or-property-sealed-label";
sealedLabel.setAttribute("value", "S");
this._title.appendChild(sealedLabel);
}
if (!descriptor.value.extensible) {
let nonExtensibleLabel = this.document.createElement("label");
nonExtensibleLabel.className = "plain variable-or-property-non-extensible-label";
nonExtensibleLabel.setAttribute("value", "N");
this._title.appendChild(nonExtensibleLabel);
}
}
},
this._target.appendChild(tooltip);
this._target.setAttribute("tooltip", tooltip.id);
/**
* Prepares all tooltips for this variable.
*/
_prepareTooltips: function() {
this._target.addEventListener("mouseover", this._setTooltips, false);
},
/**
* Sets all tooltips for this variable.
*/
_setTooltips: function() {
this._target.removeEventListener("mouseover", this._setTooltips, false);
let ownerView = this.ownerView;
if (ownerView.preventDescriptorModifiers) {
return;
}
if (this.ownerView.eval && !this._isUndefined && (this.getter || this.setter)) {
this._editNode.setAttribute("tooltiptext", this.ownerView.editButtonTooltip);
let tooltip = this.document.createElement("tooltip");
tooltip.id = "tooltip-" + this._idString;
tooltip.setAttribute("orient", "horizontal");
let labels = [
"configurable", "enumerable", "writable",
"frozen", "sealed", "extensible", "WebIDL"];
for (let label of labels) {
let labelElement = this.document.createElement("label");
labelElement.setAttribute("value", label);
tooltip.appendChild(labelElement);
}
if (this.ownerView.eval) {
this._valueLabel.setAttribute("tooltiptext", this.ownerView.editableValueTooltip);
this._target.appendChild(tooltip);
this._target.setAttribute("tooltip", tooltip.id);
if (this._editNode && ownerView.eval) {
this._editNode.setAttribute("tooltiptext", ownerView.editButtonTooltip);
}
if (this.ownerView.switch) {
this._name.setAttribute("tooltiptext", this.ownerView.editableNameTooltip);
if (this._valueLabel && ownerView.eval) {
this._valueLabel.setAttribute("tooltiptext", ownerView.editableValueTooltip);
}
if (this.ownerView.delete) {
this._deleteNode.setAttribute("tooltiptext", this.ownerView.deleteButtonTooltip);
if (this._name && ownerView.switch) {
this._name.setAttribute("tooltiptext", ownerView.editableNameTooltip);
}
if (this._deleteNode && ownerView.delete) {
this._deleteNode.setAttribute("tooltiptext", ownerView.deleteButtonTooltip);
}
},
@ -2424,48 +2466,56 @@ ViewHelpers.create({ constructor: Variable, proto: Scope.prototype }, {
* and specifies if it's a 'this', '<exception>' or '__proto__' reference.
*/
_setAttributes: function() {
let ownerView = this.ownerView;
if (ownerView.preventDescriptorModifiers) {
return;
}
let descriptor = this._initialDescriptor;
let target = this._target;
let name = this._nameString;
if (this.ownerView.eval) {
this._target.setAttribute("editable", "");
if (ownerView.eval) {
target.setAttribute("editable", "");
}
if (!descriptor.null) {
if (!descriptor.configurable) {
this._target.setAttribute("non-configurable", "");
if (!descriptor.configurable) {
target.setAttribute("non-configurable", "");
}
if (!descriptor.enumerable) {
target.setAttribute("non-enumerable", "");
}
if (!descriptor.writable && !ownerView.getter && !ownerView.setter) {
target.setAttribute("non-writable", "");
}
if (descriptor.value && typeof descriptor.value == "object") {
if (descriptor.value.frozen) {
target.setAttribute("frozen", "");
}
if (!descriptor.enumerable) {
this._target.setAttribute("non-enumerable", "");
if (descriptor.value.sealed) {
target.setAttribute("sealed", "");
}
if (!descriptor.writable && !this.ownerView.getter && !this.ownerView.setter) {
this._target.setAttribute("non-writable", "");
}
if (descriptor.value && typeof descriptor.value == "object") {
if (descriptor.value.frozen) {
this._target.setAttribute("frozen", "");
}
if (descriptor.value.sealed) {
this._target.setAttribute("sealed", "");
}
if (!descriptor.value.extensible) {
this._target.setAttribute("non-extensible", "");
}
if (!descriptor.value.extensible) {
target.setAttribute("non-extensible", "");
}
}
if (descriptor && "getterValue" in descriptor) {
this._target.setAttribute("safe-getter", "");
target.setAttribute("safe-getter", "");
}
if (name == "this") {
this._target.setAttribute("self", "");
target.setAttribute("self", "");
}
else if (name == "<exception>") {
this._target.setAttribute("exception", "");
target.setAttribute("exception", "");
}
else if (name == "<return>") {
this._target.setAttribute("return", "");
target.setAttribute("return", "");
}
else if (name == "__proto__") {
this._target.setAttribute("proto", "");
target.setAttribute("proto", "");
}
},
@ -2776,7 +2826,7 @@ function Property(aVar, aName, aDescriptor) {
this._absoluteName = aVar._absoluteName + "[\"" + aName + "\"]";
}
ViewHelpers.create({ constructor: Property, proto: Variable.prototype }, {
Property.prototype = Heritage.extend(Variable.prototype, {
/**
* Initializes this property's id, view and binds event listeners.
*
@ -2793,7 +2843,7 @@ ViewHelpers.create({ constructor: Property, proto: Variable.prototype }, {
if (this._nameString) {
this._displayVariable();
this._customizeVariable();
this._prepareTooltip();
this._prepareTooltips();
this._setAttributes();
this._addEventListeners();
}
@ -2937,11 +2987,11 @@ VariablesView.isPrimitive = function(aDescriptor) {
// As described in the remote debugger protocol, the value grip
// must be contained in a 'value' property.
let grip = aDescriptor.value;
if (!grip || typeof grip != "object") {
if (typeof grip != "object") {
return true;
}
// For convenience, undefined, null and long strings are considered primitives.
// For convenience, undefined, null and long strings are considered types.
let type = grip.type;
if (type == "undefined" || type == "null" || type == "longString") {
return true;
@ -2968,9 +3018,8 @@ VariablesView.isUndefined = function(aDescriptor) {
// As described in the remote debugger protocol, the value grip
// must be contained in a 'value' property.
// For convenience, undefined is considered a type.
let grip = aDescriptor.value;
if (grip && grip.type == "undefined") {
if (typeof grip == "object" && grip.type == "undefined") {
return true;
}

Просмотреть файл

@ -15,33 +15,35 @@ const PAGE_SIZE_ITEM_COUNT_RATIO = 5;
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
this.EXPORTED_SYMBOLS = ["ViewHelpers", "MenuItem", "MenuContainer"];
this.EXPORTED_SYMBOLS = ["Heritage", "ViewHelpers", "WidgetMethods"];
/**
* Inheritance helpers from the addon SDK's core/heritage.
* Remove these when all devtools are loadered.
*/
this.Heritage = {
/**
* @see extend in sdk/core/heritage.
*/
extend: function(aPrototype, aProperties = {}) {
return Object.create(aPrototype, this.getOwnPropertyDescriptors(aProperties));
},
/**
* @see getOwnPropertyDescriptors in sdk/core/heritage.
*/
getOwnPropertyDescriptors: function(aObject) {
return Object.getOwnPropertyNames(aObject).reduce((aDescriptor, aName) => {
aDescriptor[aName] = Object.getOwnPropertyDescriptor(aObject, aName);
return aDescriptor;
}, {});
}
};
/**
* Helpers for creating and messaging between UI components.
*/
this.ViewHelpers = {
/**
* Sugar for prototypal inheritance using Object.create.
* Creates a new object with the specified prototype object and properties.
*
* @param object aObject
* An object containing the following properties:
* - constructor: the function to configure the prototype for
* - proto: the prototype to extend
* @param object aProperties
* The properties extending the prototype.
*/
create: function({ constructor, proto }, aProperties = {}) {
let descriptors = {
constructor: { value: constructor }
};
for (let name in aProperties) {
descriptors[name] = Object.getOwnPropertyDescriptor(aProperties, name);
}
constructor.prototype = Object.create(proto, descriptors);
},
/**
* Convenience method, dispatching a custom event.
*
@ -69,7 +71,6 @@ this.ViewHelpers = {
/**
* Helper delegating some of the DOM attribute methods of a node to a widget.
* @see MenuContainer constructor
*
* @param object aWidget
* The widget to assign the methods to.
@ -84,7 +85,6 @@ this.ViewHelpers = {
/**
* Helper delegating some of the DOM event methods of a node to a widget.
* @see MenuContainer constructor
*
* @param object aWidget
* The widget to assign the methods to.
@ -107,6 +107,18 @@ this.ViewHelpers = {
return aObject && aObject.on && aObject.off && aObject.once && aObject.emit;
},
/**
* Checks if the specified object is an instance of a DOM node.
*
* @return boolean
* True if it's a node, false otherwise.
*/
isNode: function(aObject) {
return aObject instanceof Ci.nsIDOMNode ||
aObject instanceof Ci.nsIDOMElement ||
aObject instanceof Ci.nsIDOMDocumentFragment;
},
/**
* Prevents event propagation when navigation keys are pressed.
*
@ -346,43 +358,46 @@ ViewHelpers.Prefs.prototype = {
};
/**
* A generic MenuItem is used to describe elements present in a MenuContainer.
* A generic Item is used to describe children present in a Widget.
* The label, value and description properties are necessarily strings.
* Iterable via "for (let childItem in parentItem) { }".
*
* @param object aOwnerView
* The owner view creating this item.
* @param any aAttachment
* Some attached primitive/object.
* @param nsIDOMNode | nsIDOMDocumentFragment | array aContents [optional]
* A prebuilt node, or an array containing the following properties:
* - aLabel: the label displayed in the container
* - aLabel: the label displayed in the widget
* - aValue: the actual internal value of the item
* - aDescription: an optional description of the item
*/
this.MenuItem = function MenuItem(aAttachment, aContents = []) {
function Item(aOwnerView, aAttachment, aContents = []) {
this.ownerView = aOwnerView;
this.attachment = aAttachment;
// Allow the insertion of prebuilt nodes.
if (aContents instanceof Ci.nsIDOMNode ||
aContents instanceof Ci.nsIDOMDocumentFragment) {
this._prebuiltTarget = aContents;
}
// Delegate the item view creation to a container widget.
else {
let [aLabel, aValue, aDescription] = aContents;
this._label = aLabel + "";
this._value = aValue + "";
this._description = (aDescription || "") + "";
let [aLabel, aValue, aDescription] = aContents;
this._label = aLabel + "";
this._value = aValue + "";
this._description = (aDescription || "") + "";
// Allow the insertion of prebuilt nodes, otherwise delegate the item view
// creation to a widget.
if (ViewHelpers.isNode(aLabel)) {
this._prebuiltTarget = aLabel;
}
XPCOMUtils.defineLazyGetter(this, "_itemsByElement", () => new Map());
};
MenuItem.prototype = {
Item.prototype = {
get label() this._label,
get value() this._value,
get description() this._description,
get target() this._target,
/**
* Immediately appends a child item to this menu item.
* Immediately appends a child item to this item.
*
* @param nsIDOMNode aElement
* An nsIDOMNode representing the child element to append.
@ -390,32 +405,32 @@ MenuItem.prototype = {
* Additional options or flags supported by this operation:
* - attachment: some attached primitive/object for the item
* - attributes: a batch of attributes set to the displayed element
* - finalize: function invoked when the child node is removed
* @return MenuItem
* - finalize: function invoked when the child item is removed
* @return Item
* The item associated with the displayed element.
*/
append: function(aElement, aOptions = {}) {
let item = new MenuItem(aOptions.attachment);
let item = new Item(this, aOptions.attachment);
// Handle any additional options before appending the child node.
// Entangle the item with the newly inserted child node.
this._entangleItem(item, this._target.appendChild(aElement));
// Handle any additional options after entangling the item.
if (aOptions.attributes) {
this.setAttributes(aOptions.attributes);
aOptions.attributes.forEach(e => item._target.setAttribute(e[0], e[1]));
}
if (aOptions.finalize) {
item.finalize = aOptions.finalize;
}
// Entangle the item with the newly inserted child node.
this._entangleItem(item, this._target.appendChild(aElement));
// Return the item associated with the displayed element.
return item;
},
/**
* Immediately removes the specified child item from this menu item.
* Immediately removes the specified child item from this item.
*
* @param MenuItem aItem
* @param Item aItem
* The item associated with the element to remove.
*/
remove: function(aItem) {
@ -426,53 +441,15 @@ MenuItem.prototype = {
this._untangleItem(aItem);
},
/**
* Visually marks this menu item as selected.
*/
markSelected: function() {
if (!this._target) {
return;
}
this._target.classList.add("selected");
},
/**
* Visually marks this menu item as deselected.
*/
markDeselected: function() {
if (!this._target) {
return;
}
this._target.classList.remove("selected");
},
/**
* Batch sets attributes on an element.
*
* @param array aAttributes
* An array of [name, value] tuples representing the attributes.
* @param nsIDOMNode aElement [optional]
* A custom element to set the attributes to.
*/
setAttributes: function(aAttributes, aElement = this._target) {
for (let [name, value] of aAttributes) {
aElement.setAttribute(name, value);
}
},
/**
* Entangles an item (model) with a displayed node element (view).
*
* @param MenuItem aItem
* The item describing the element.
* @param Item aItem
* The item describing a target element.
* @param nsIDOMNode aElement
* The element displaying the item.
*/
_entangleItem: function(aItem, aElement) {
if (!this._itemsByElement) {
this._itemsByElement = new Map(); // This needs to be iterable.
}
this._itemsByElement.set(aElement, aItem);
aItem._target = aElement;
},
@ -480,8 +457,8 @@ MenuItem.prototype = {
/**
* Untangles an item (model) from a displayed node element (view).
*
* @param MenuItem aItem
* The item describing the element.
* @param Item aItem
* The item describing a target element.
*/
_untangleItem: function(aItem) {
if (aItem.finalize) {
@ -499,8 +476,8 @@ MenuItem.prototype = {
/**
* Deletes an item from the its parent's storage maps.
*
* @param MenuItem aItem
* The item to forget.
* @param Item aItem
* The item describing a target element.
*/
_unlinkItem: function(aItem) {
this._itemsByElement.delete(aItem._target);
@ -530,16 +507,27 @@ MenuItem.prototype = {
};
/**
* A generic MenuContainer is used for displaying MenuItem instances.
* Iterable via "for (let item in menuContainer) { }".
* Some generic Widget methods handling Item instances.
* Iterable via "for (let childItem in wrappedView) { }".
*
* Usage:
* function MyView() {
* this.widget = new MyWidget(document.querySelector(".my-node"));
* }
*
* MyView.prototype = Heritage.extend(WidgetMethods, {
* myMethod: function() {},
* ...
* });
*
* See https://gist.github.com/victorporof/5749386 for more details.
*
* Language:
* - An "item" is an instance (or compatible interface) of a MenuItem.
* - An "item" is an instance of an Item.
* - An "element" or "node" is a nsIDOMNode.
*
* The element node or widget supplied to all instances of this container
* can either be a <menulist>, or any other object interfacing the following
* methods:
* The supplied element node or widget can either be a <xul:menulist>, or any
* other object interfacing the following methods:
* - function:nsIDOMNode insertItemAt(aIndex:number, aLabel:string, aValue:string)
* - function:nsIDOMNode getItemAtIndex(aIndex:number)
* - function removeChild(aChild:nsIDOMNode)
@ -557,25 +545,25 @@ MenuItem.prototype = {
* - "keyPress" -> (aName:string, aEvent:KeyboardEvent)
* - "mousePress" -> (aName:string, aEvent:MouseEvent)
*/
this.MenuContainer = function MenuContainer() {
};
MenuContainer.prototype = {
this.WidgetMethods = {
/**
* Sets the element node or widget associated with this container.
* @param nsIDOMNode | object aWidget
*/
set node(aWidget) {
this._container = aWidget;
this._itemsByLabel = new Map(); // Can't use a WeakMap for itemsByLabel or
this._itemsByValue = new Map(); // itemsByValue because keys are strings,
this._itemsByElement = new Map(); // and itemsByElement needs to be iterable.
this._stagedItems = [];
set widget(aWidget) {
this._widget = aWidget;
// Can't use WeakMaps for itemsByLabel or itemsByValue because
// keys are strings, and itemsByElement needs to be iterable.
XPCOMUtils.defineLazyGetter(this, "_itemsByLabel", () => new Map());
XPCOMUtils.defineLazyGetter(this, "_itemsByValue", () => new Map());
XPCOMUtils.defineLazyGetter(this, "_itemsByElement", () => new Map());
XPCOMUtils.defineLazyGetter(this, "_stagedItems", () => []);
// Handle internal events emitted by the widget if necessary.
if (ViewHelpers.isEventEmitter(this._container)) {
this._container.on("keyPress", this._onWidgetKeyPress.bind(this));
this._container.on("mousePress", this._onWidgetMousePress.bind(this));
if (ViewHelpers.isEventEmitter(aWidget)) {
aWidget.on("keyPress", this._onWidgetKeyPress.bind(this));
aWidget.on("mousePress", this._onWidgetMousePress.bind(this));
}
},
@ -583,20 +571,22 @@ MenuContainer.prototype = {
* Gets the element node or widget associated with this container.
* @return nsIDOMNode | object
*/
get node() this._container,
get widget() this._widget,
/**
* Prepares an item to be added to this container. This allows for a large
* number of items to be batched up before being sorted and added.
* Prepares an item to be added to this container. This allows, for example,
* for a large number of items to be batched up before being sorted & added.
*
* If the "staged" flag is not set to true, the item will be immediately
* If the "staged" flag is *not* set to true, the item will be immediately
* inserted at the correct position in this container, so that all the items
* remain sorted. This can (possibly) be much slower than batching up
* still remain sorted. This can (possibly) be much slower than batching up
* multiple items.
*
* By default, this container assumes that all the items should be displayed
* sorted by their label. This can be overridden with the "index" flag,
* specifying on which position should an item be appended.
* specifying on which position should an item be appended. The "staged" and
* "index" flags are mutually exclusive, meaning that all staged items
* will always be appended.
*
* Furthermore, this container makes sure that all the items are unique
* (two items with the same label or value are not allowed) and non-degenerate
@ -615,13 +605,13 @@ MenuContainer.prototype = {
* - relaxed: true if this container should allow dupes & degenerates
* - attachment: some attached primitive/object for the item
* - attributes: a batch of attributes set to the displayed element
* - finalize: function invokde when the item is untangled (removed)
* @return MenuItem
* - finalize: function invoked when the item is removed
* @return Item
* The item associated with the displayed element if an unstaged push,
* undefined if the item was staged for a later commit.
*/
push: function(aContents, aOptions = {}) {
let item = new MenuItem(aOptions.attachment, aContents);
let item = new Item(this, aOptions.attachment, aContents);
// Batch the item to be added later.
if (aOptions.staged) {
@ -673,36 +663,46 @@ MenuContainer.prototype = {
if (!selectedItem) {
return false;
}
this._container.removeAttribute("notice");
this._container.setAttribute("label", selectedItem._label);
this._container.setAttribute("tooltiptext", selectedItem._value);
this._widget.removeAttribute("notice");
this._widget.setAttribute("label", selectedItem._label);
this._widget.setAttribute("tooltiptext", selectedItem._value);
return true;
},
/**
* Immediately removes the specified item from this container.
*
* @param MenuItem aItem
* @param Item aItem
* The item associated with the element to remove.
*/
remove: function(aItem) {
if (!aItem) {
return;
}
this._container.removeChild(aItem._target);
this._widget.removeChild(aItem._target);
this._untangleItem(aItem);
},
/**
* Removes the item at the specified index from this container.
*
* @param number aIndex
* The index of the item to remove.
*/
removeAt: function(aIndex) {
this.remove(this.getItemAtIndex(aIndex));
},
/**
* Removes all items from this container.
*/
empty: function() {
this._preferredValue = this.selectedValue;
this._container.selectedItem = null;
this._container.removeAllItems();
this._container.setAttribute("notice", this.emptyText);
this._container.setAttribute("label", this.emptyText);
this._container.removeAttribute("tooltiptext");
this._widget.selectedItem = null;
this._widget.removeAllItems();
this._widget.setAttribute("notice", this.emptyText);
this._widget.setAttribute("label", this.emptyText);
this._widget.removeAttribute("tooltiptext");
for (let [, item] of this._itemsByElement) {
this._untangleItem(item);
@ -719,9 +719,9 @@ MenuContainer.prototype = {
* current label to signal that it is unavailable and removes the tooltip.
*/
setUnavailable: function() {
this._container.setAttribute("notice", this.unavailableText);
this._container.setAttribute("label", this.unavailableText);
this._container.removeAttribute("tooltiptext");
this._widget.setAttribute("notice", this.unavailableText);
this._widget.setAttribute("label", this.unavailableText);
this._widget.removeAttribute("tooltiptext");
},
/**
@ -739,8 +739,7 @@ MenuContainer.prototype = {
* Toggles all the items in this container hidden or visible.
*
* This does not change the default filtering predicate, so newly inserted
* items will always be visible. Use MenuContainer.prototype.filterContents
* if you care.
* items will always be visible. Use WidgetMethods.filterContents if you care.
*
* @param boolean aVisibleFlag
* Specifies the intended visibility.
@ -771,8 +770,8 @@ MenuContainer.prototype = {
* Sorts all the items in this container based on a predicate.
*
* @param function aPredicate [optional]
* Items are sorted according to the return value of the function, which
* will become the new default sorting predicate in this container.
* Items are sorted according to the return value of the function,
* which will become the new default sorting predicate in this container.
* If unspecified, all items will be sorted by their label.
*/
sortContents: function(aPredicate = this._currentSortPredicate) {
@ -786,10 +785,10 @@ MenuContainer.prototype = {
/**
* Visually swaps two items in this container.
*
* @param MenuItem aFirst
* The first menu item to be swapped.
* @param MenuItem aSecond
* The second menu item to be swapped.
* @param Item aFirst
* The first item to be swapped.
* @param Item aSecond
* The second item to be swapped.
*/
swapItems: function(aFirst, aSecond) {
if (aFirst == aSecond) { // We're just dandy, thank you.
@ -816,7 +815,7 @@ MenuContainer.prototype = {
let j = this._indexOfElement(secondTarget);
// 2. Remeber the selection index, to reselect an item, if necessary.
let selectedTarget = this._container.selectedItem;
let selectedTarget = this._widget.selectedItem;
let selectedIndex = -1;
if (selectedTarget == firstTarget) {
selectedIndex = i;
@ -825,8 +824,8 @@ MenuContainer.prototype = {
}
// 3. Silently nuke both items, nobody needs to know about this.
this._container.removeChild(firstTarget);
this._container.removeChild(secondTarget);
this._widget.removeChild(firstTarget);
this._widget.removeChild(secondTarget);
this._unlinkItem(aFirst);
this._unlinkItem(aSecond);
@ -836,9 +835,9 @@ MenuContainer.prototype = {
// 5. Restore the previous selection, if necessary.
if (selectedIndex == i) {
this._container.selectedItem = aFirst._target;
this._widget.selectedItem = aFirst._target;
} else if (selectedIndex == j) {
this._container.selectedItem = aSecond._target;
this._widget.selectedItem = aSecond._target;
}
},
@ -846,9 +845,9 @@ MenuContainer.prototype = {
* Visually swaps two items in this container at specific indices.
*
* @param number aFirst
* The index of the first menu item to be swapped.
* The index of the first item to be swapped.
* @param number aSecond
* The index of the second menu item to be swapped.
* The index of the second item to be swapped.
*/
swapItemsAtIndices: function(aFirst, aSecond) {
this.swapItems(this.getItemAtIndex(aFirst), this.getItemAtIndex(aSecond));
@ -865,7 +864,7 @@ MenuContainer.prototype = {
*/
containsLabel: function(aLabel) {
return this._itemsByLabel.has(aLabel) ||
this._stagedItems.some(function({item}) item._label == aLabel);
this._stagedItems.some(({ item }) => item._label == aLabel);
},
/**
@ -879,21 +878,22 @@ MenuContainer.prototype = {
*/
containsValue: function(aValue) {
return this._itemsByValue.has(aValue) ||
this._stagedItems.some(function({item}) item._value == aValue);
this._stagedItems.some(({ item }) => item._value == aValue);
},
/**
* Gets the preferred selected value to be displayed in this container.
* Gets the "preferred value". This is the latest selected item's value,
* remembered just before emptying this container.
* @return string
*/
get preferredValue() this._preferredValue,
/**
* Retrieves the item associated with the selected element.
* @return MenuItem
* @return Item
*/
get selectedItem() {
let selectedElement = this._container.selectedItem;
let selectedElement = this._widget.selectedItem;
if (selectedElement) {
return this._itemsByElement.get(selectedElement);
}
@ -905,7 +905,7 @@ MenuContainer.prototype = {
* @return number
*/
get selectedIndex() {
let selectedElement = this._container.selectedItem;
let selectedElement = this._widget.selectedItem;
if (selectedElement) {
return this._indexOfElement(selectedElement);
}
@ -917,7 +917,7 @@ MenuContainer.prototype = {
* @return string
*/
get selectedLabel() {
let selectedElement = this._container.selectedItem;
let selectedElement = this._widget.selectedItem;
if (selectedElement) {
return this._itemsByElement.get(selectedElement)._label;
}
@ -929,7 +929,7 @@ MenuContainer.prototype = {
* @return string
*/
get selectedValue() {
let selectedElement = this._container.selectedItem;
let selectedElement = this._widget.selectedItem;
if (selectedElement) {
return this._itemsByElement.get(selectedElement)._value;
}
@ -938,12 +938,18 @@ MenuContainer.prototype = {
/**
* Selects the element with the entangled item in this container.
* @param MenuItem aItem
* @param Item | function aItem
*/
set selectedItem(aItem) {
// A predicate is allowed to select a specific item.
// If no item is matched, then the current selection is removed.
if (typeof aItem == "function") {
aItem = this.getItemForPredicate(aItem);
}
// A falsy item is allowed to invalidate the current selection.
let targetElement = aItem ? aItem._target : null;
let prevElement = this._container.selectedItem;
let prevElement = this._widget.selectedItem;
// Make sure the currently selected item's target element is also focused.
if (this.autoFocusOnSelection && targetElement) {
@ -955,8 +961,12 @@ MenuContainer.prototype = {
if (targetElement == prevElement) {
return;
}
this._container.selectedItem = targetElement;
this._widget.selectedItem = targetElement;
ViewHelpers.dispatchEvent(targetElement || prevElement, "select", aItem);
// Updates this container to reflect the information provided by the
// currently selected item.
this.refresh();
},
/**
@ -964,7 +974,7 @@ MenuContainer.prototype = {
* @param number aIndex
*/
set selectedIndex(aIndex) {
let targetElement = this._container.getItemAtIndex(aIndex);
let targetElement = this._widget.getItemAtIndex(aIndex);
if (targetElement) {
this.selectedItem = this._itemsByElement.get(targetElement);
return;
@ -1062,7 +1072,7 @@ MenuContainer.prototype = {
// command dispatcher mechanism has a relative node to work with.
// If there's no selection, just select an item at a corresponding index
// (e.g. the first item in this container if aDelta <= 1).
let selectedElement = this._container.selectedItem;
let selectedElement = this._widget.selectedItem;
if (selectedElement) {
selectedElement.focus();
} else {
@ -1117,7 +1127,7 @@ MenuContainer.prototype = {
if (this._cachedCommandDispatcher) {
return this._cachedCommandDispatcher;
}
let someElement = this._container.getItemAtIndex(0);
let someElement = this._widget.getItemAtIndex(0);
if (someElement) {
let commandDispatcher = someElement.ownerDocument.commandDispatcher;
return this._cachedCommandDispatcher = commandDispatcher;
@ -1144,11 +1154,11 @@ MenuContainer.prototype = {
*
* @param number aIndex
* The index used to identify the element.
* @return MenuItem
* @return Item
* The matched item, or null if nothing is found.
*/
getItemAtIndex: function(aIndex) {
return this.getItemForElement(this._container.getItemAtIndex(aIndex));
return this.getItemForElement(this._widget.getItemAtIndex(aIndex));
},
/**
@ -1156,7 +1166,7 @@ MenuContainer.prototype = {
*
* @param string aLabel
* The label used to identify the element.
* @return MenuItem
* @return Item
* The matched item, or null if nothing is found.
*/
getItemByLabel: function(aLabel) {
@ -1168,7 +1178,7 @@ MenuContainer.prototype = {
*
* @param string aValue
* The value used to identify the element.
* @return MenuItem
* @return Item
* The matched item, or null if nothing is found.
*/
getItemByValue: function(aValue) {
@ -1180,7 +1190,7 @@ MenuContainer.prototype = {
*
* @param nsIDOMNode aElement
* The element used to identify the item.
* @return MenuItem
* @return Item
* The matched item, or null if nothing is found.
*/
getItemForElement: function(aElement) {
@ -1194,10 +1204,33 @@ MenuContainer.prototype = {
return null;
},
/**
* Gets a visible item in this container validating a specified predicate.
*
* @param function aPredicate
* The first item which validates this predicate is returned
* @return Item
* The matched item, or null if nothing is found.
*/
getItemForPredicate: function(aPredicate, aOwner = this) {
for (let [element, item] of aOwner._itemsByElement) {
let match;
if (aPredicate(item) && !element.hidden) {
match = item;
} else {
match = this.getItemForPredicate(aPredicate, item);
}
if (match) {
return match;
}
}
return null;
},
/**
* Finds the index of an item in the container.
*
* @param MenuItem aItem
* @param Item aItem
* The item get the index for.
* @return number
* The index of the matched item, or -1 if nothing is found.
@ -1215,11 +1248,8 @@ MenuContainer.prototype = {
* The index of the matched element, or -1 if nothing is found.
*/
_indexOfElement: function(aElement) {
let container = this._container;
let itemCount = this._itemsByElement.size;
for (let i = 0; i < itemCount; i++) {
if (container.getItemAtIndex(i) == aElement) {
for (let i = 0; i < this._itemsByElement.size; i++) {
if (this._widget.getItemAtIndex(i) == aElement) {
return i;
}
}
@ -1227,7 +1257,25 @@ MenuContainer.prototype = {
},
/**
* Returns the list of labels in this container.
* Gets the total number of items in this container.
* @return number
*/
get itemCount() this._itemsByElement.size,
/**
* Returns a list of items in this container, in no particular order.
* @return array
*/
get items() {
let items = [];
for (let [, item] of this._itemsByElement) {
items.push(item);
}
return items;
},
/**
* Returns a list of labels in this container, in no particular order.
* @return array
*/
get labels() {
@ -1239,7 +1287,7 @@ MenuContainer.prototype = {
},
/**
* Returns the list of values in this container.
* Returns a list of values in this container, in no particular order.
* @return array
*/
get values() {
@ -1251,16 +1299,19 @@ MenuContainer.prototype = {
},
/**
* Gets the total number of items in this container.
* @return number
* Returns a list of all the visible (non-hidden) items in this container,
* in no particular order.
* @return array
*/
get itemCount() this._itemsByElement.size,
/**
* Gets the total number of visible (non-hidden) items in this container.
* @return number
*/
get visibleItemsCount() this.visibleItems.length,
get visibleItems() {
let items = [];
for (let [element, item] of this._itemsByElement) {
if (!element.hidden) {
items.push(item);
}
}
return items;
},
/**
* Returns a list of all items in this container, in the displayed order.
@ -1292,21 +1343,6 @@ MenuContainer.prototype = {
return items;
},
/**
* Returns a list of all the visible (non-hidden) items in this container,
* in no particular order.
* @return array
*/
get visibleItems() {
let items = [];
for (let [element, item] of this._itemsByElement) {
if (!element.hidden) {
items.push(item);
}
}
return items;
},
/**
* Specifies the required conditions for an item to be considered unique.
* Possible values:
@ -1320,10 +1356,10 @@ MenuContainer.prototype = {
/**
* Checks if an item is unique in this container.
*
* @param MenuItem aItem
* An object containing a label and a value property (at least).
* @param Item aItem
* The item for which to verify uniqueness.
* @return boolean
* True if the element is unique, false otherwise.
* True if the item is unique, false otherwise.
*/
isUnique: function(aItem) {
switch (this.uniquenessQualifier) {
@ -1342,25 +1378,28 @@ MenuContainer.prototype = {
},
/**
* Checks if an item's label and value are eligible for this container.
* Checks if an item is eligible for this container.
*
* @param MenuItem aItem
* An object containing a label and a value property (at least).
* @param Item aItem
* The item for which to verify eligibility.
* @return boolean
* True if the element is eligible, false otherwise.
* True if the item is eligible, false otherwise.
*/
isEligible: function(aItem) {
return aItem._prebuiltTarget || (this.isUnique(aItem) &&
aItem._label != "undefined" && aItem._label != "null" &&
aItem._value != "undefined" && aItem._value != "null");
let isUnique = this.isUnique(aItem);
let isPrebuilt = !!aItem._prebuiltTarget;
let isDegenerate = aItem._label == "undefined" || aItem._label == "null" ||
aItem._value == "undefined" || aItem._value == "null";
return isPrebuilt || (isUnique && !isDegenerate);
},
/**
* Finds the expected item index in this container based on the default
* sort predicate.
*
* @param MenuItem aItem
* The item to get the expected index for.
* @param Item aItem
* The item for which to get the expected index.
* @return number
* The expected item index.
*/
@ -1380,7 +1419,7 @@ MenuContainer.prototype = {
*
* @param number aIndex
* The position in the container intended for this item.
* @param MenuItem aItem
* @param Item aItem
* An object containing a label and a value property (at least).
* @param object aOptions [optional]
* Additional options or flags supported by this operation:
@ -1388,7 +1427,7 @@ MenuContainer.prototype = {
* - relaxed: true if this container should allow dupes & degenerates
* - attributes: a batch of attributes set to the displayed element
* - finalize: function when the item is untangled (removed)
* @return MenuItem
* @return Item
* The item associated with the displayed element, null if rejected.
*/
_insertItemAt: function(aIndex, aItem, aOptions = {}) {
@ -1398,7 +1437,7 @@ MenuContainer.prototype = {
}
// Entangle the item with the newly inserted node.
this._entangleItem(aItem, this._container.insertItemAt(aIndex,
this._entangleItem(aItem, this._widget.insertItemAt(aIndex,
aItem._prebuiltTarget || aItem._label, // Allow the insertion of prebuilt nodes.
aItem._value,
aItem._description,
@ -1412,7 +1451,7 @@ MenuContainer.prototype = {
aItem._target.focus();
}
if (aOptions.attributes) {
aItem.setAttributes(aOptions.attributes, aItem._target);
aOptions.attributes.forEach(e => aItem._target.setAttribute(e[0], e[1]));
}
if (aOptions.finalize) {
aItem.finalize = aOptions.finalize;
@ -1425,8 +1464,8 @@ MenuContainer.prototype = {
/**
* Entangles an item (model) with a displayed node element (view).
*
* @param MenuItem aItem
* The item describing the element.
* @param Item aItem
* The item describing a target element.
* @param nsIDOMNode aElement
* The element displaying the item.
*/
@ -1440,8 +1479,8 @@ MenuContainer.prototype = {
/**
* Untangles an item (model) from a displayed node element (view).
*
* @param MenuItem aItem
* The item describing the element.
* @param Item aItem
* The item describing a target element.
*/
_untangleItem: function(aItem) {
if (aItem.finalize) {
@ -1459,8 +1498,8 @@ MenuContainer.prototype = {
/**
* Deletes an item from the its parent's storage maps.
*
* @param MenuItem aItem
* The item to forget.
* @param Item aItem
* The item describing a target element.
*/
_unlinkItem: function(aItem) {
this._itemsByLabel.delete(aItem._label);
@ -1525,10 +1564,10 @@ MenuContainer.prototype = {
* The predicate used when filtering items. By default, all items in this
* view are visible.
*
* @param MenuItem aItem
* The filtered menu item.
* @param Item aItem
* The item passing through the filter.
* @return boolean
* True if the menu item should be visible, false otherwise.
* True if the item should be visible, false otherwise.
*/
_currentFilterPredicate: function(aItem) {
return true;
@ -1538,10 +1577,10 @@ MenuContainer.prototype = {
* The predicate used when sorting items. By default, items in this view
* are sorted by their label.
*
* @param MenuItem aFirst
* The first menu item used in the comparison.
* @param MenuItem aSecond
* The second menu item used in the comparison.
* @param Item aFirst
* The first item used in the comparison.
* @param Item aSecond
* The second item used in the comparison.
* @return number
* -1 to sort aFirst to a lower index than aSecond
* 0 to leave aFirst and aSecond unchanged with respect to each other
@ -1551,11 +1590,7 @@ MenuContainer.prototype = {
return +(aFirst._label.toLowerCase() > aSecond._label.toLowerCase());
},
_container: null,
_stagedItems: null,
_itemsByLabel: null,
_itemsByValue: null,
_itemsByElement: null,
_widget: null,
_preferredValue: null,
_cachedCommandDispatcher: null
};
@ -1563,11 +1598,8 @@ MenuContainer.prototype = {
/**
* A generator-iterator over all the items in this container.
*/
MenuItem.prototype.__iterator__ =
MenuContainer.prototype.__iterator__ = function() {
if (!this._itemsByElement) {
return;
}
Item.prototype.__iterator__ =
WidgetMethods.__iterator__ = function() {
for (let [, item] of this._itemsByElement) {
yield item;
}

Просмотреть файл

@ -50,3 +50,10 @@
.variable-or-property[non-match] > .title {
display: none;
}
.variable-or-property:not([safe-getter]) > tooltip > label[value=WebIDL],
.variable-or-property:not([non-extensible]) > tooltip > label[value=extensible],
.variable-or-property:not([frozen]) > tooltip > label[value=frozen],
.variable-or-property:not([sealed]) > tooltip > label[value=sealed] {
display: none;
}

Просмотреть файл

@ -33,7 +33,7 @@ XPCOMUtils.defineLazyModuleGetter(this, "WebConsoleUtils",
XPCOMUtils.defineLazyModuleGetter(this, "Promise",
"resource://gre/modules/commonjs/sdk/core/promise.js");
XPCOMUtils.defineLazyModuleGetter(this, "ViewHelpers",
XPCOMUtils.defineLazyModuleGetter(this, "Heritage",
"resource:///modules/devtools/ViewHelpers.jsm");
let Telemetry = devtools.require("devtools/shared/telemetry");
@ -525,7 +525,7 @@ function BrowserConsole()
this._telemetry = new Telemetry();
}
ViewHelpers.create({ constructor: BrowserConsole, proto: WebConsole.prototype },
BrowserConsole.prototype = Heritage.extend(WebConsole.prototype,
{
_browserConsole: true,
_bc_init: null,

Просмотреть файл

@ -248,6 +248,10 @@ These should match what Safari and other Apple applications use on OS X Lion. --
<!ENTITY scratchpad.keycode "VK_F4">
<!ENTITY scratchpad.keytext "F4">
<!-- LOCALIZATION NOTE (chromeDebuggerMenu.label): This is the label for the
- application menu item that opens the browser debugger UI in the Tools menu. -->
<!ENTITY chromeDebuggerMenu.label "Browser Debugger">
<!ENTITY devToolbarCloseButton.tooltiptext "Close Developer Toolbar">
<!ENTITY devToolbarMenu.label "Developer Toolbar">
<!ENTITY devToolbarMenu.accesskey "v">

Просмотреть файл

@ -78,7 +78,7 @@ cacheManifestOnlyFirstLine2="CACHE MANIFEST" is only valid on the first line but
# LOCALIZATION NOTE (asteriskInWrongSection2): the associated cache manifest
# has an asterisk (*) in a section other than the NETWORK section. Parameters:
# %1$S is the section name, %2$S is the line number.
asteriskInWrongSection2=Asterisk (*) incorrectly used in the %1$S section at line %2$S. If a line in the NETWORK section contains only a single asterisk character, then any URI not listed in the manifest will be treated as if the URI was listed in the NETWORK section. Otherwice such URIs will be treated as unavailable. Other uses of the * character are prohibited.
asteriskInWrongSection2=Asterisk (*) incorrectly used in the %1$S section at line %2$S. If a line in the NETWORK section contains only a single asterisk character, then any URI not listed in the manifest will be treated as if the URI was listed in the NETWORK section. Otherwise such URIs will be treated as unavailable. Other uses of the * character are prohibited.
# LOCALIZATION NOTE (escapeSpaces): the associated cache manifest has a space
# in a URI. Spaces must be replaced with %20. Parameters: %S is the line

Просмотреть файл

@ -11,26 +11,6 @@
- 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.label2 "Debugger">
<!-- LOCALIZATION NOTE (debuggerMenu.accesskey): This is accesskey for the
- Tools menu entry of Debugger that opens the debugger UI. -->
<!ENTITY debuggerMenu.accesskey "D">
<!-- LOCALIZATION NOTE (remoteDebuggerMenu.label): This is the label for the
- application menu item that opens the remote debugger UI. -->
<!ENTITY remoteDebuggerMenu.label "Remote Debugger">
<!-- LOCALIZATION NOTE (chromeDebuggerMenu.label): This is the label for the
- application menu item that opens the browser debugger UI. -->
<!ENTITY chromeDebuggerMenu.label "Browser 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.tooltip): This is the tooltip for
- the button that closes the debugger UI. -->
<!ENTITY debuggerUI.closeButton.tooltip "Close">

Просмотреть файл

@ -10,42 +10,21 @@
# A good criteria is the language in which you'd find the best
# documentation on web development on the web.
# LOCALIZATION NOTE (open.commandkey): The key used to open the debugger in
# combination to e.g. ctrl + shift
open.commandkey=S
# LOCALIZATION NOTE (ToolboxDebugger.label):
# This string is displayed in the title of the tab when the debugger is
# displayed inside the developer tools window and in the Developer Tools Menu.
ToolboxDebugger.label=Debugger
# LOCALIZATION NOTE (debuggerMenu.accesskey): The access key used to open the
# debugger.
# LOCALIZATION NOTE (ToolboxDebugger.tooltip):
# This string is displayed in the tooltip of the tab when the debugger is
# displayed inside the developer tools window..
ToolboxDebugger.tooltip=JavaScript Debugger
# LOCALIZATION NOTE (debuggerMenu.commandkey, debuggerMenu.accesskey)
# Used for the menuitem in the tool menu
debuggerMenu.commandkey=S
debuggerMenu.accesskey=D
# LOCALIZATION NOTE (chromeDebuggerWindowTitle): The title displayed for the
# chrome (browser) debugger window.
chromeDebuggerWindowTitle=Browser Debugger
# LOCALIZATION NOTE (remoteDebuggerWindowTitle): The title displayed for the
# remote debugger window.
remoteDebuggerWindowTitle=Remote Debugger
# LOCALIZATION NOTE (remoteDebuggerPromptTitle): The title displayed on the
# debugger prompt asking for the remote host and port to connect to.
remoteDebuggerPromptTitle=Remote Connection
# LOCALIZATION NOTE (remoteDebuggerPromptMessage): The message displayed on the
# debugger prompt asking for the remote host and port to connect to.
remoteDebuggerPromptMessage=Enter hostname and port number (host:port)
# LOCALIZATION NOTE (remoteDebuggerPromptCheck): The message displayed on the
# debugger prompt asking if the prompt should be shown again next time.
remoteDebuggerPromptCheck=Don't ask me again
# LOCALIZATION NOTE (remoteDebuggerReconnectMessage): The message displayed on the
# debugger prompt asking for the remote host and port to connect to.
remoteDebuggerReconnectMessage=Server not found. Try again? (host:port)
# LOCALIZATION NOTE (remoteDebuggerReconnectMessage): The message displayed on the
# debugger prompt asking for the remote host and port to connect to.
remoteDebuggerConnectionFailedMessage=Could not find a server at the specified hostname and port number.
# LOCALIZATION NOTE (collapsePanes): This is the tooltip for the button
# that collapses the left and right panes in the debugger UI.
collapsePanes=Collapse panes
@ -168,16 +147,6 @@ watchExpressionsScopeLabel=Watch expressions
# the global scope.
globalScopeLabel=Global
# LOCALIZATION NOTE (ToolboxDebugger.label):
# This string is displayed in the title of the tab when the debugger is
# displayed inside the developer tools window and in the Developer Tools Menu.
ToolboxDebugger.label=Debugger
# LOCALIZATION NOTE (ToolboxDebugger.tooltip):
# This string is displayed in the tooltip of the tab when the debugger is
# displayed inside the developer tools window..
ToolboxDebugger.tooltip=JavaScript Debugger
# LOCALIZATION NOTE (variablesEditableNameTooltip): The text that is displayed
# in the variables list on an item with an editable name.
variablesEditableNameTooltip=Double click to edit

Просмотреть файл

@ -11,9 +11,9 @@
- A good criteria is the language in which you'd find the best
- documentation on web development on the web. -->
<!-- LOCALIZATION NOTE (netmonitorUI.emptyNotice): This is the label displayed
<!-- LOCALIZATION NOTE (netmonitorUI.emptyNotice2): This is the label displayed
- in the network table when empty. -->
<!ENTITY netmonitorUI.emptyNotice "Reload the page to see detailed information about network activity.">
<!ENTITY netmonitorUI.emptyNotice2 "Perform a request or reload the page to see detailed information about network activity.">
<!-- LOCALIZATION NOTE (netmonitorUI.toolbar.status): This is the label displayed
- in the network table toolbar, above the "status" column. -->

Просмотреть файл

@ -81,3 +81,7 @@ help.openDocumentationPage=https://developer.mozilla.org/en/Tools/Scratchpad
# LOCALIZATION NOTE (fileExists.notification): This is the message displayed
# over the top of the the editor when a file does not exist.
fileNoLongerExists.notification=This file no longer exists.
# LOCALIZATION NOTE (propertiesFilterPlaceholder): this is the text that
# appears in the filter text box for the properties view container.
propertiesFilterPlaceholder=Filter properties

Просмотреть файл

@ -12,10 +12,11 @@ const Ci = Components.interfaces;
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/Promise.jsm");
const HTML_NS = "http://www.w3.org/1999/xhtml";
const XUL_NS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
const XUL_PAGE = "data:application/vnd.mozilla.xul+xml;charset=utf-8,<window id='win'/>";
const XUL_PAGE = "data:application/vnd.mozilla.xul+xml;charset=utf-8,<window%20id='win'/>";
const NEWTAB_URL = "about:newtab";
const PREF_BRANCH = "browser.newtab.";
@ -290,12 +291,12 @@ let HiddenBrowsers = {
function HiddenBrowser(width, height) {
this.resize(width, height);
HostFrame.get(aFrame => {
HostFrame.get().then(aFrame => {
let doc = aFrame.document;
this._browser = doc.createElementNS(XUL_NS, "browser");
this._browser.setAttribute("type", "content");
this._browser.setAttribute("src", NEWTAB_URL);
doc.getElementById("win").appendChild(this._browser);
this.preload();
});
}
@ -333,16 +334,6 @@ HiddenBrowser.prototype = {
observe: function () {
this._timer = null;
this.preload();
},
preload: function () {
if (!this._browser) {
return;
}
// Make sure the browser has the right size.
this.resize(this._width, this._height);
// Start pre-loading the new tab page.
this._browser.loadURI(NEWTAB_URL);
@ -370,7 +361,7 @@ HiddenBrowser.prototype = {
let HostFrame = {
_frame: null,
_loading: false,
_deferred: null,
get hiddenDOMDocument() {
return Services.appShell.hiddenDOMWindow.document;
@ -380,38 +371,46 @@ let HostFrame = {
return this.hiddenDOMDocument.readyState === "complete";
},
get: function (callback) {
if (this._frame) {
callback(this._frame);
} else if (this.isReady && !this._loading) {
this._create(callback);
this._loading = true;
} else {
Services.tm.currentThread.dispatch(() => HostFrame.get(callback),
Ci.nsIThread.DISPATCH_NORMAL);
get: function () {
if (!this._deferred) {
this._deferred = Promise.defer();
this._create();
}
return this._deferred.promise;
},
destroy: function () {
this._frame = null;
if (this._frame) {
if (!Cu.isDeadWrapper(this._frame)) {
this._frame.removeEventListener("load", this, true);
this._frame.remove();
}
this._frame = null;
this._deferred = null;
}
},
_create: function (callback) {
let doc = this.hiddenDOMDocument;
let iframe = doc.createElementNS(HTML_NS, "iframe");
doc.documentElement.appendChild(iframe);
handleEvent: function () {
let contentWindow = this._frame.contentWindow;
if (contentWindow.location.href === XUL_PAGE) {
this._frame.removeEventListener("load", this, true);
this._deferred.resolve(contentWindow);
} else {
contentWindow.location = XUL_PAGE;
}
},
let frame = iframe.contentWindow;
let docShell = frame.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIDocShell);
docShell.createAboutBlankContentViewer(null);
frame.location = XUL_PAGE;
let eventHandler = docShell.chromeEventHandler;
eventHandler.addEventListener("DOMContentLoaded", function onLoad() {
eventHandler.removeEventListener("DOMContentLoaded", onLoad, false);
callback(HostFrame._frame = frame);
}, false);
_create: function () {
if (this.isReady) {
let doc = this.hiddenDOMDocument;
this._frame = doc.createElementNS(HTML_NS, "iframe");
this._frame.addEventListener("load", this, true);
doc.documentElement.appendChild(this._frame);
} else {
let flags = Ci.nsIThread.DISPATCH_NORMAL;
Services.tm.currentThread.dispatch(() => this._create(), flags);
}
}
};

Просмотреть файл

@ -312,7 +312,7 @@ box.requests-menu-status[code^="5"] {
/* SideMenuWidget */
.side-menu-widget-item:nth-child(even) {
.side-menu-widget-item[odd] {
background: rgba(255,255,255,0.05);
}

Просмотреть файл

@ -476,7 +476,7 @@
}
.variable-or-property:not(:focus) > .title > .token-boolean {
color: #777;
color: #1c00cf;
}
.variable-or-property:not(:focus) > .title > .token-number {
@ -484,16 +484,16 @@
}
.variable-or-property:not(:focus) > .title > .token-string {
color: #1c00cf;
color: #282;
}
.variable-or-property:not(:focus) > .title > .token-other {
color: #333;
}
/* Non enumerable, configurable and writable variables and properties */
/* Custom configurable/enumerable/writable or frozen/sealed/extensible
* variables and properties */
.variable-or-property[proto] > .title > .name,
.variable-or-property[non-enumerable]:not([self]):not([exception]):not([return]) > .title > .name {
opacity: 0.5;
}
@ -502,17 +502,11 @@
border-bottom: 1px dashed #99f;
}
.variable-or-property[non-configurable][non-writable] > .title > .name {
.variable-or-property[non-writable] > .title > .name {
border-bottom: 1px dashed #f99;
}
.variable-or-property[safe-getter] > .title > .name {
border-bottom: 1px dashed #8b0;
}
.variable-or-property[non-writable] > .title:after {
content: " ";
display: inline-block;
.variable-or-property-non-writable-icon {
background: url("chrome://browser/skin/identity-icons-https.png") no-repeat;
width: 16px;
height: 16px;
@ -520,12 +514,25 @@
}
@media (min-resolution: 2dppx) {
.variable-or-property[non-writable] > .title:after {
.variable-or-property-non-writable-icon {
background-image: url("chrome://browser/skin/identity-icons-https@2x.png");
background-size: 32px;
}
}
.variable-or-property-frozen-label,
.variable-or-property-sealed-label,
.variable-or-property-non-extensible-label {
-moz-padding-end: 4px;
color: #666;
}
/* Special variables and properties */
.variable-or-property[safe-getter] > .title > .name {
border-bottom: 1px dashed #8b0;
}
.variable-or-property[exception]:not(:focus) > .title > .name {
color: #a00;
text-shadow: 0 0 8px #fcc;
@ -536,21 +543,6 @@
text-shadow: 0 0 8px #cfc;
}
.variable-or-property[non-extensible]:not([non-writable]) > .title:after {
content: "N";
display: inline-block;
}
.variable-or-property[sealed]:not([non-writable]) > .title:after {
content: "S";
display: inline-block;
}
.variable-or-property[frozen]:not([non-writable]) > .title:after {
content: "F";
display: inline-block;
}
/* Variables and properties tooltips */
.variable-or-property > tooltip > label {
@ -559,15 +551,16 @@
.variable-or-property[non-enumerable] > tooltip > label[value=enumerable],
.variable-or-property[non-configurable] > tooltip > label[value=configurable],
.variable-or-property[non-writable] > tooltip > label[value=writable] {
.variable-or-property[non-writable] > tooltip > label[value=writable],
.variable-or-property[non-extensible] > tooltip > label[value=extensible] {
color: #800;
text-decoration: line-through;
}
.variable-or-property:not([safe-getter]) > tooltip > label[value=native-getter],
.variable-or-property:not([non-extensible]) > tooltip > label[value=non-extensible],
.variable-or-property:not([frozen]) > tooltip > label[value=frozen],
.variable-or-property:not([sealed]) > tooltip > label[value=sealed] {
display: none;
.variable-or-property[safe-getter] > tooltip > label[value=WebIDL] {
-moz-padding-start: 4px;
-moz-border-start: 1px dotted #000;
color: #080;
}
/* Variables and properties editing */

Просмотреть файл

@ -312,7 +312,7 @@ box.requests-menu-status[code^="5"] {
/* SideMenuWidget */
.side-menu-widget-item:nth-child(even) {
.side-menu-widget-item[odd] {
background: rgba(255,255,255,0.05);
}

Просмотреть файл

@ -476,7 +476,7 @@
}
.variable-or-property:not(:focus) > .title > .token-boolean {
color: #777;
color: #1c00cf;
}
.variable-or-property:not(:focus) > .title > .token-number {
@ -484,16 +484,16 @@
}
.variable-or-property:not(:focus) > .title > .token-string {
color: #1c00cf;
color: #282;
}
.variable-or-property:not(:focus) > .title > .token-other {
color: #333;
}
/* Non enumerable, configurable and writable variables and properties */
/* Custom configurable/enumerable/writable or frozen/sealed/extensible
* variables and properties */
.variable-or-property[proto] > .title > .name,
.variable-or-property[non-enumerable]:not([self]):not([exception]):not([return]) > .title > .name {
opacity: 0.5;
}
@ -502,17 +502,11 @@
border-bottom: 1px dashed #99f;
}
.variable-or-property[non-configurable][non-writable] > .title > .name {
.variable-or-property[non-writable] > .title > .name {
border-bottom: 1px dashed #f99;
}
.variable-or-property[safe-getter] > .title > .name {
border-bottom: 1px dashed #8b0;
}
.variable-or-property[non-writable] > .title:after {
content: " ";
display: inline-block;
.variable-or-property-non-writable-icon {
background: url("chrome://browser/skin/identity-icons-https.png") no-repeat;
width: 16px;
height: 16px;
@ -520,12 +514,25 @@
}
@media (min-resolution: 2dppx) {
.variable-or-property[non-writable] > .title:after {
.variable-or-property-non-writable-icon {
background-image: url("chrome://browser/skin/identity-icons-https@2x.png");
background-size: 32px;
}
}
.variable-or-property-frozen-label,
.variable-or-property-sealed-label,
.variable-or-property-non-extensible-label {
-moz-padding-end: 4px;
color: #666;
}
/* Special variables and properties */
.variable-or-property[safe-getter] > .title > .name {
border-bottom: 1px dashed #8b0;
}
.variable-or-property[exception]:not(:focus) > .title > .name {
color: #a00;
text-shadow: 0 0 8px #fcc;
@ -536,21 +543,6 @@
text-shadow: 0 0 8px #cfc;
}
.variable-or-property[non-extensible]:not([non-writable]) > .title:after {
content: "N";
display: inline-block;
}
.variable-or-property[sealed]:not([non-writable]) > .title:after {
content: "S";
display: inline-block;
}
.variable-or-property[frozen]:not([non-writable]) > .title:after {
content: "F";
display: inline-block;
}
/* Variables and properties tooltips */
.variable-or-property > tooltip > label {
@ -559,15 +551,16 @@
.variable-or-property[non-enumerable] > tooltip > label[value=enumerable],
.variable-or-property[non-configurable] > tooltip > label[value=configurable],
.variable-or-property[non-writable] > tooltip > label[value=writable] {
.variable-or-property[non-writable] > tooltip > label[value=writable],
.variable-or-property[non-extensible] > tooltip > label[value=extensible] {
color: #800;
text-decoration: line-through;
}
.variable-or-property:not([safe-getter]) > tooltip > label[value=native-getter],
.variable-or-property:not([non-extensible]) > tooltip > label[value=non-extensible],
.variable-or-property:not([frozen]) > tooltip > label[value=frozen],
.variable-or-property:not([sealed]) > tooltip > label[value=sealed] {
display: none;
.variable-or-property[safe-getter] > tooltip > label[value=WebIDL] {
-moz-padding-start: 4px;
-moz-border-start: 1px dotted #000;
color: #080;
}
/* Variables and properties editing */

Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше