mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 723071 - Add a pane to display the list of breakpoints across all scripts in the debuggee; f=msucan,past r=past
This commit is contained in:
parent
d10808c6ce
commit
0a14cf5b14
@ -52,6 +52,7 @@ let DebuggerController = {
|
||||
DebuggerView.initializePanes();
|
||||
DebuggerView.initializeEditor();
|
||||
DebuggerView.StackFrames.initialize();
|
||||
DebuggerView.Breakpoints.initialize();
|
||||
DebuggerView.Properties.initialize();
|
||||
DebuggerView.Scripts.initialize();
|
||||
DebuggerView.showCloseButton(!this._isRemoteDebugger && !this._isChromeDebugger);
|
||||
@ -75,6 +76,7 @@ let DebuggerController = {
|
||||
DebuggerView.destroyEditor();
|
||||
DebuggerView.Scripts.destroy();
|
||||
DebuggerView.StackFrames.destroy();
|
||||
DebuggerView.Breakpoints.destroy();
|
||||
DebuggerView.Properties.destroy();
|
||||
|
||||
DebuggerController.Breakpoints.destroy();
|
||||
@ -395,8 +397,6 @@ StackFrames.prototype = {
|
||||
connect: function SF_connect(aCallback) {
|
||||
window.addEventListener("Debugger:FetchedVariables", this._onFetchedVars, false);
|
||||
|
||||
this._onFramesCleared();
|
||||
|
||||
this.activeThread.addListener("paused", this._onPaused);
|
||||
this.activeThread.addListener("resumed", this._onResume);
|
||||
this.activeThread.addListener("framesadded", this._onFrames);
|
||||
@ -506,12 +506,47 @@ StackFrames.prototype = {
|
||||
let line = frame.where.line;
|
||||
let editor = DebuggerView.editor;
|
||||
|
||||
// Move the editor's caret to the proper line.
|
||||
if (DebuggerView.Scripts.isSelected(url) && line) {
|
||||
editor.setDebugLocation(line - 1);
|
||||
} else {
|
||||
editor.setDebugLocation(-1);
|
||||
this.updateEditorToLocation(url, line, true);
|
||||
},
|
||||
|
||||
/**
|
||||
* Update the source editor's current caret and debug location based on
|
||||
* a specified url and line.
|
||||
*
|
||||
* @param string aUrl
|
||||
* The target source url.
|
||||
* @param number aLine
|
||||
* The target line number in the source.
|
||||
* @param boolean aNoSwitch
|
||||
* Pass true to not switch to the script if not currently selected.
|
||||
* @param boolean aNoCaretFlag
|
||||
* Pass true to not set the caret location at the specified line.
|
||||
* @param boolean aNoDebugFlag
|
||||
* Pass true to not set the debug location at the specified line.
|
||||
*/
|
||||
updateEditorToLocation:
|
||||
function SF_updateEditorToLocation(aUrl, aLine, aNoSwitch, aNoCaretFlag, aNoDebugFlag) {
|
||||
let editor = DebuggerView.editor;
|
||||
|
||||
function set() {
|
||||
if (!aNoCaretFlag) {
|
||||
editor.setCaretPosition(aLine - 1);
|
||||
}
|
||||
if (!aNoDebugFlag) {
|
||||
editor.setDebugLocation(aLine - 1);
|
||||
}
|
||||
}
|
||||
|
||||
// Move the editor's caret to the proper url and line.
|
||||
if (DebuggerView.Scripts.isSelected(aUrl)) {
|
||||
return set();
|
||||
}
|
||||
if (!aNoSwitch && DebuggerView.Scripts.contains(aUrl)) {
|
||||
DebuggerView.Scripts.selectScript(aUrl);
|
||||
return set();
|
||||
}
|
||||
editor.setCaretPosition(-1);
|
||||
editor.setDebugLocation(-1);
|
||||
},
|
||||
|
||||
/**
|
||||
@ -550,20 +585,9 @@ StackFrames.prototype = {
|
||||
|
||||
let url = frame.where.url;
|
||||
let line = frame.where.line;
|
||||
let editor = DebuggerView.editor;
|
||||
|
||||
// Move the editor's caret to the proper line.
|
||||
if (DebuggerView.Scripts.isSelected(url) && line) {
|
||||
editor.setCaretPosition(line - 1);
|
||||
editor.setDebugLocation(line - 1);
|
||||
}
|
||||
else if (DebuggerView.Scripts.contains(url)) {
|
||||
DebuggerView.Scripts.selectScript(url);
|
||||
editor.setCaretPosition(line - 1);
|
||||
}
|
||||
else {
|
||||
editor.setDebugLocation(-1);
|
||||
}
|
||||
this.updateEditorToLocation(url, line);
|
||||
|
||||
// Start recording any added variables or properties in any scope.
|
||||
DebuggerView.Properties.createHierarchyStore();
|
||||
@ -755,7 +779,7 @@ StackFrames.prototype = {
|
||||
*/
|
||||
_addFrame: function SF__addFrame(aFrame) {
|
||||
let depth = aFrame.depth;
|
||||
let label = DebuggerController.SourceScripts._getScriptLabel(aFrame.where.url);
|
||||
let label = DebuggerController.SourceScripts.getScriptLabel(aFrame.where.url);
|
||||
|
||||
let startText = this._getFrameTitle(aFrame);
|
||||
let endText = label + ":" + aFrame.where.line;
|
||||
@ -882,10 +906,12 @@ SourceScripts.prototype = {
|
||||
}
|
||||
|
||||
this._addScript({ url: aPacket.url, startLine: aPacket.startLine }, true);
|
||||
// If there are any stored breakpoints for this script, display them again.
|
||||
for each (let bp in DebuggerController.Breakpoints.store) {
|
||||
if (bp.location.url == aPacket.url) {
|
||||
DebuggerController.Breakpoints.displayBreakpoint(bp.location);
|
||||
|
||||
// If there are any stored breakpoints for this script, display them again,
|
||||
// both in the editor and the pane.
|
||||
for each (let breakpoint in DebuggerController.Breakpoints.store) {
|
||||
if (breakpoint.location.url == aPacket.url) {
|
||||
DebuggerController.Breakpoints.displayBreakpoint(breakpoint);
|
||||
}
|
||||
}
|
||||
},
|
||||
@ -898,6 +924,7 @@ SourceScripts.prototype = {
|
||||
this._addScript(script, false);
|
||||
}
|
||||
DebuggerView.Scripts.commitScripts();
|
||||
DebuggerController.Breakpoints.updatePaneBreakpoints();
|
||||
},
|
||||
|
||||
/**
|
||||
@ -905,6 +932,7 @@ SourceScripts.prototype = {
|
||||
*/
|
||||
_onScriptsCleared: function SS__onScriptsCleared() {
|
||||
DebuggerView.Scripts.empty();
|
||||
DebuggerView.Breakpoints.emptyText();
|
||||
},
|
||||
|
||||
/**
|
||||
@ -967,7 +995,7 @@ SourceScripts.prototype = {
|
||||
* @return string
|
||||
* The resulting label at the final step.
|
||||
*/
|
||||
_trimURL: function SS__trimURL(aUrl, aLabel, aSeq) {
|
||||
_trimUrl: function SS__trimUrl(aUrl, aLabel, aSeq) {
|
||||
if (!(aUrl instanceof Ci.nsIURL)) {
|
||||
try {
|
||||
// Use an nsIURL to parse all the url path parts.
|
||||
@ -1012,7 +1040,7 @@ SourceScripts.prototype = {
|
||||
if (aSeq === 1) {
|
||||
let query = aUrl.query;
|
||||
if (query) {
|
||||
return this._trimURL(aUrl, aLabel + "?" + query, aSeq + 1);
|
||||
return this._trimUrl(aUrl, aLabel + "?" + query, aSeq + 1);
|
||||
}
|
||||
aSeq++;
|
||||
}
|
||||
@ -1020,7 +1048,7 @@ SourceScripts.prototype = {
|
||||
if (aSeq === 2) {
|
||||
let ref = aUrl.ref;
|
||||
if (ref) {
|
||||
return this._trimURL(aUrl, aLabel + "#" + aUrl.ref, aSeq + 1);
|
||||
return this._trimUrl(aUrl, aLabel + "#" + aUrl.ref, aSeq + 1);
|
||||
}
|
||||
aSeq++;
|
||||
}
|
||||
@ -1028,7 +1056,7 @@ SourceScripts.prototype = {
|
||||
if (aSeq === 3) {
|
||||
let dir = aUrl.directory;
|
||||
if (dir) {
|
||||
return this._trimURL(aUrl, dir.replace(/^\//, "") + aLabel, aSeq + 1);
|
||||
return this._trimUrl(aUrl, dir.replace(/^\//, "") + aLabel, aSeq + 1);
|
||||
}
|
||||
aSeq++;
|
||||
}
|
||||
@ -1036,13 +1064,13 @@ SourceScripts.prototype = {
|
||||
if (aSeq === 4) {
|
||||
let host = aUrl.hostPort;
|
||||
if (host) {
|
||||
return this._trimURL(aUrl, host + "/" + aLabel, aSeq + 1);
|
||||
return this._trimUrl(aUrl, host + "/" + aLabel, aSeq + 1);
|
||||
}
|
||||
aSeq++;
|
||||
}
|
||||
// Use the whole url spec but ignoring the reference.
|
||||
if (aSeq === 5) {
|
||||
return this._trimURL(aUrl, aUrl.specIgnoringRef, aSeq + 1);
|
||||
return this._trimUrl(aUrl, aUrl.specIgnoringRef, aSeq + 1);
|
||||
}
|
||||
// Give up.
|
||||
return aUrl.spec;
|
||||
@ -1059,8 +1087,8 @@ SourceScripts.prototype = {
|
||||
* @return string
|
||||
* The simplified label.
|
||||
*/
|
||||
_getScriptLabel: function SS__getScriptLabel(aUrl, aHref) {
|
||||
return this._labelsCache[aUrl] || (this._labelsCache[aUrl] = this._trimURL(aUrl));
|
||||
getScriptLabel: function SS_getScriptLabel(aUrl, aHref) {
|
||||
return this._labelsCache[aUrl] || (this._labelsCache[aUrl] = this._trimUrl(aUrl));
|
||||
},
|
||||
|
||||
/**
|
||||
@ -1081,7 +1109,7 @@ SourceScripts.prototype = {
|
||||
*/
|
||||
_addScript: function SS__addScript(aScript, aForceFlag) {
|
||||
DebuggerView.Scripts.addScript(
|
||||
this._getScriptLabel(aScript.url), aScript, aForceFlag);
|
||||
this.getScriptLabel(aScript.url), aScript, aForceFlag);
|
||||
},
|
||||
|
||||
/**
|
||||
@ -1233,6 +1261,23 @@ SourceScripts.prototype = {
|
||||
this.showScript(script, aOptions);
|
||||
},
|
||||
|
||||
/**
|
||||
* Gets the text in a source editor's specified line.
|
||||
*
|
||||
* @param number aLine [optional]
|
||||
* The line to get the text from.
|
||||
* If unspecified, it defaults to the current caret position line.
|
||||
* @return string
|
||||
* The specified line text
|
||||
*/
|
||||
getLineText: function SS_getLineText(aLine) {
|
||||
let editor = DebuggerView.editor;
|
||||
let line = aLine || editor.getCaretPosition().line;
|
||||
let start = editor.getLineStart(line);
|
||||
let end = editor.getLineEnd(line);
|
||||
return editor.getText(start, end);
|
||||
},
|
||||
|
||||
/**
|
||||
* Log an error message in the error console when a script fails to load.
|
||||
*
|
||||
@ -1395,6 +1440,25 @@ Breakpoints.prototype = {
|
||||
this._skipEditorBreakpointChange = false;
|
||||
},
|
||||
|
||||
/**
|
||||
* Update the breakpoints in the pane view. This function is invoked when the
|
||||
* scripts are added (typically after a page navigation).
|
||||
*/
|
||||
updatePaneBreakpoints: function BP_updatePaneBreakpoints() {
|
||||
let url = DebuggerView.Scripts.selected;
|
||||
if (!url) {
|
||||
return;
|
||||
}
|
||||
|
||||
this._skipEditorBreakpointChange = true;
|
||||
for each (let breakpoint in this.store) {
|
||||
if (DebuggerView.Scripts.contains(breakpoint.location.url)) {
|
||||
this.displayBreakpoint(breakpoint, true);
|
||||
}
|
||||
}
|
||||
this._skipEditorBreakpointChange = false;
|
||||
},
|
||||
|
||||
/**
|
||||
* Add a breakpoint.
|
||||
*
|
||||
@ -1412,9 +1476,11 @@ Breakpoints.prototype = {
|
||||
* @param boolean [aNoEditorUpdate=false]
|
||||
* Tells if you want to skip editor updates. Typically the editor is
|
||||
* updated to visually indicate that a breakpoint has been added.
|
||||
* @param boolean [aNoPaneUpdate=false]
|
||||
* Tells if you want to skip any breakpoint pane updates.
|
||||
*/
|
||||
addBreakpoint:
|
||||
function BP_addBreakpoint(aLocation, aCallback, aNoEditorUpdate) {
|
||||
function BP_addBreakpoint(aLocation, aCallback, aNoEditorUpdate, aNoPaneUpdate) {
|
||||
let breakpoint = this.getBreakpoint(aLocation.url, aLocation.line);
|
||||
if (breakpoint) {
|
||||
aCallback && aCallback(breakpoint);
|
||||
@ -1423,7 +1489,7 @@ Breakpoints.prototype = {
|
||||
|
||||
this.activeThread.setBreakpoint(aLocation, function(aResponse, aBpClient) {
|
||||
this.store[aBpClient.actor] = aBpClient;
|
||||
this.displayBreakpoint(aLocation, aNoEditorUpdate);
|
||||
this.displayBreakpoint(aBpClient, aNoEditorUpdate, aNoPaneUpdate);
|
||||
aCallback && aCallback(aBpClient, aResponse.error);
|
||||
}.bind(this));
|
||||
},
|
||||
@ -1431,24 +1497,37 @@ Breakpoints.prototype = {
|
||||
/**
|
||||
* Update the editor to display the specified breakpoint in the gutter.
|
||||
*
|
||||
* @param object aLocation
|
||||
* The location where you want the breakpoint. This object must have
|
||||
* two properties:
|
||||
* - url - the URL of the script.
|
||||
* - line - the line number (starting from 1).
|
||||
* @param object aBreakpoint
|
||||
* The breakpoint you want to display.
|
||||
* @param boolean [aNoEditorUpdate=false]
|
||||
* Tells if you want to skip editor updates. Typically the editor is
|
||||
* updated to visually indicate that a breakpoint has been added.
|
||||
* @param boolean [aNoPaneUpdate=false]
|
||||
* Tells if you want to skip any breakpoint pane updates.
|
||||
*/
|
||||
displayBreakpoint: function BP_displayBreakpoint(aLocation, aNoEditorUpdate) {
|
||||
displayBreakpoint:
|
||||
function BP_displayBreakpoint(aBreakpoint, aNoEditorUpdate, aNoPaneUpdate) {
|
||||
if (!aNoEditorUpdate) {
|
||||
let url = DebuggerView.Scripts.selected;
|
||||
if (url == aLocation.url) {
|
||||
if (url == aBreakpoint.location.url) {
|
||||
this._skipEditorBreakpointChange = true;
|
||||
this.editor.addBreakpoint(aLocation.line - 1);
|
||||
this.editor.addBreakpoint(aBreakpoint.location.line - 1);
|
||||
this._skipEditorBreakpointChange = false;
|
||||
}
|
||||
}
|
||||
if (!aNoPaneUpdate) {
|
||||
let { url: url, line: line } = aBreakpoint.location;
|
||||
|
||||
if (!aBreakpoint.lineText || !aBreakpoint.lineInfo) {
|
||||
let scripts = DebuggerController.SourceScripts;
|
||||
aBreakpoint.lineText = scripts.getLineText(line - 1);
|
||||
aBreakpoint.lineInfo = scripts.getScriptLabel(url) + ":" + line;
|
||||
}
|
||||
DebuggerView.Breakpoints.addBreakpoint(
|
||||
aBreakpoint.actor,
|
||||
aBreakpoint.lineInfo,
|
||||
aBreakpoint.lineText, url, line);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
@ -1463,9 +1542,11 @@ Breakpoints.prototype = {
|
||||
* @param boolean [aNoEditorUpdate=false]
|
||||
* Tells if you want to skip editor updates. Typically the editor is
|
||||
* updated to visually indicate that a breakpoint has been removed.
|
||||
* @param boolean [aNoPaneUpdate=false]
|
||||
* Tells if you want to skip any breakpoint pane updates.
|
||||
*/
|
||||
removeBreakpoint:
|
||||
function BP_removeBreakpoint(aBreakpoint, aCallback, aNoEditorUpdate) {
|
||||
function BP_removeBreakpoint(aBreakpoint, aCallback, aNoEditorUpdate, aNoPaneUpdate) {
|
||||
if (!(aBreakpoint.actor in this.store)) {
|
||||
aCallback && aCallback(aBreakpoint.location);
|
||||
return;
|
||||
@ -1482,6 +1563,9 @@ Breakpoints.prototype = {
|
||||
this._skipEditorBreakpointChange = false;
|
||||
}
|
||||
}
|
||||
if (!aNoPaneUpdate) {
|
||||
DebuggerView.Breakpoints.removeBreakpoint(aBreakpoint.actor);
|
||||
}
|
||||
|
||||
aCallback && aCallback(aBreakpoint.location);
|
||||
}.bind(this));
|
||||
|
@ -6,6 +6,7 @@
|
||||
"use strict";
|
||||
|
||||
const PROPERTY_VIEW_FLASH_DURATION = 400; // ms
|
||||
const BREAKPOINT_LINE_TOOLTIP_MAX_SIZE = 1000;
|
||||
|
||||
/**
|
||||
* Object mediating visual changes and event listeners between the debugger and
|
||||
@ -22,7 +23,7 @@ let DebuggerView = {
|
||||
* Initializes UI properties for all the displayed panes.
|
||||
*/
|
||||
initializePanes: function DV_initializePanes() {
|
||||
let stackframes = document.getElementById("stackframes");
|
||||
let stackframes = document.getElementById("stackframes+breakpoints");
|
||||
stackframes.setAttribute("width", Prefs.stackframesWidth);
|
||||
|
||||
let variables = document.getElementById("variables");
|
||||
@ -51,7 +52,7 @@ let DebuggerView = {
|
||||
* Removes the displayed panes and saves any necessary state.
|
||||
*/
|
||||
destroyPanes: function DV_destroyPanes() {
|
||||
let stackframes = document.getElementById("stackframes");
|
||||
let stackframes = document.getElementById("stackframes+breakpoints");
|
||||
Prefs.stackframesWidth = stackframes.getAttribute("width");
|
||||
|
||||
let variables = document.getElementById("variables");
|
||||
@ -807,6 +808,7 @@ StackFramesView.prototype = {
|
||||
window.addEventListener("resize", this._onFramesScroll, false);
|
||||
|
||||
this._frames = frames;
|
||||
this.emptyText();
|
||||
},
|
||||
|
||||
/**
|
||||
@ -837,6 +839,545 @@ StackFramesView.prototype = {
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Functions handling the breakpoints view.
|
||||
*/
|
||||
function BreakpointsView() {
|
||||
this._onBreakpointClick = this._onBreakpointClick.bind(this);
|
||||
this._onBreakpointCheckboxChange = this._onBreakpointCheckboxChange.bind(this);
|
||||
}
|
||||
|
||||
BreakpointsView.prototype = {
|
||||
|
||||
/**
|
||||
* Removes all elements from the breakpoints container, leaving it empty.
|
||||
*/
|
||||
empty: function DVB_empty() {
|
||||
let firstChild;
|
||||
while (firstChild = this._breakpoints.firstChild) {
|
||||
this._destroyContextMenu(firstChild);
|
||||
this._breakpoints.removeChild(firstChild);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Removes all elements from the breakpoints container, and adds a child node
|
||||
* with an empty text note attached.
|
||||
*/
|
||||
emptyText: function DVB_emptyText() {
|
||||
// Make sure the container is empty first.
|
||||
this.empty();
|
||||
|
||||
let item = document.createElement("label");
|
||||
|
||||
// The empty node should look grayed out to avoid confusion.
|
||||
item.className = "list-item empty";
|
||||
item.setAttribute("value", L10N.getStr("emptyBreakpointsText"));
|
||||
|
||||
this._breakpoints.appendChild(item);
|
||||
},
|
||||
|
||||
/**
|
||||
* Checks whether the breakpoint with the specified script URL and line is
|
||||
* among the breakpoints known to the debugger and shown in the list, and
|
||||
* returns the matched result or null if nothing is found.
|
||||
*
|
||||
* @param string aUrl
|
||||
* The original breakpoint script url.
|
||||
* @param number aLine
|
||||
* The original breakpoint script line.
|
||||
* @return object | null
|
||||
* The queried breakpoint
|
||||
*/
|
||||
getBreakpoint: function DVB_getBreakpoint(aUrl, aLine) {
|
||||
return this._breakpoints.getElementsByAttribute("location", aUrl + ":" + aLine)[0];
|
||||
},
|
||||
|
||||
/**
|
||||
* Removes a breakpoint only from the breakpoints container.
|
||||
* This doesn't remove the breakpoint from the DebuggerController!
|
||||
*
|
||||
* @param string aId
|
||||
* A breakpoint identifier specified by the debugger.
|
||||
*/
|
||||
removeBreakpoint: function DVB_removeBreakpoint(aId) {
|
||||
let breakpoint = document.getElementById("breakpoint-" + aId);
|
||||
|
||||
// Make sure we have something to remove.
|
||||
if (!breakpoint) {
|
||||
return;
|
||||
}
|
||||
this._destroyContextMenu(breakpoint);
|
||||
this._breakpoints.removeChild(breakpoint);
|
||||
|
||||
if (!this.count) {
|
||||
this.emptyText();
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Adds a breakpoint to the breakpoints container.
|
||||
* If the breakpoint already exists (was previously added), null is returned.
|
||||
* If it's already added but disabled, it will be enabled and null is returned.
|
||||
* Otherwise, the newly created element is returned.
|
||||
*
|
||||
* @param string aId
|
||||
* A breakpoint identifier specified by the debugger.
|
||||
* @param string aLineInfo
|
||||
* The script line information to be displayed in the list.
|
||||
* @param string aLineText
|
||||
* The script line text to be displayed in the list.
|
||||
* @param string aUrl
|
||||
* The original breakpoint script url.
|
||||
* @param number aLine
|
||||
* The original breakpoint script line.
|
||||
* @return object
|
||||
* The newly created html node representing the added breakpoint.
|
||||
*/
|
||||
addBreakpoint: function DVB_addBreakpoint(aId, aLineInfo, aLineText, aUrl, aLine) {
|
||||
// Make sure we don't duplicate anything.
|
||||
if (document.getElementById("breakpoint-" + aId)) {
|
||||
return null;
|
||||
}
|
||||
// Remove the empty list text if it was there.
|
||||
if (!this.count) {
|
||||
this.empty();
|
||||
}
|
||||
|
||||
// If the breakpoint was already added but disabled, enable it now.
|
||||
let breakpoint = this.getBreakpoint(aUrl, aLine);
|
||||
if (breakpoint) {
|
||||
breakpoint.id = "breakpoint-" + aId;
|
||||
breakpoint.breakpointActor = aId;
|
||||
breakpoint.getElementsByTagName("checkbox")[0].setAttribute("checked", "true");
|
||||
return;
|
||||
}
|
||||
|
||||
breakpoint = document.createElement("box");
|
||||
let bkpCheckbox = document.createElement("checkbox");
|
||||
let bkpLineInfo = document.createElement("label");
|
||||
let bkpLineText = document.createElement("label");
|
||||
|
||||
// Create a list item to be added to the stackframes container.
|
||||
breakpoint.id = "breakpoint-" + aId;
|
||||
breakpoint.className = "dbg-breakpoint list-item";
|
||||
breakpoint.setAttribute("location", aUrl + ":" + aLine);
|
||||
breakpoint.breakpointUrl = aUrl;
|
||||
breakpoint.breakpointLine = aLine;
|
||||
breakpoint.breakpointActor = aId;
|
||||
|
||||
aLineInfo = aLineInfo.trim();
|
||||
aLineText = aLineText.trim();
|
||||
|
||||
// A checkbox specifies if the breakpoint is enabled or not.
|
||||
bkpCheckbox.setAttribute("checked", "true");
|
||||
bkpCheckbox.addEventListener("click", this._onBreakpointCheckboxChange, false);
|
||||
|
||||
// This list should display the line info and text for the breakpoint.
|
||||
bkpLineInfo.className = "dbg-breakpoint-info plain";
|
||||
bkpLineText.className = "dbg-breakpoint-text plain";
|
||||
bkpLineInfo.setAttribute("value", aLineInfo);
|
||||
bkpLineText.setAttribute("value", aLineText);
|
||||
bkpLineInfo.setAttribute("crop", "end");
|
||||
bkpLineText.setAttribute("crop", "end");
|
||||
bkpLineText.setAttribute("tooltiptext", aLineText.substr(0, BREAKPOINT_LINE_TOOLTIP_MAX_SIZE));
|
||||
|
||||
// Create a context menu for the breakpoint.
|
||||
let menupopupId = this._createContextMenu(breakpoint);
|
||||
breakpoint.setAttribute("contextmenu", menupopupId);
|
||||
|
||||
let state = document.createElement("vbox");
|
||||
state.className = "state";
|
||||
state.appendChild(bkpCheckbox);
|
||||
|
||||
let content = document.createElement("vbox");
|
||||
content.className = "content";
|
||||
content.setAttribute("flex", "1");
|
||||
content.appendChild(bkpLineInfo);
|
||||
content.appendChild(bkpLineText);
|
||||
|
||||
breakpoint.appendChild(state);
|
||||
breakpoint.appendChild(content);
|
||||
|
||||
this._breakpoints.appendChild(breakpoint);
|
||||
|
||||
// Return the element for later use if necessary.
|
||||
return breakpoint;
|
||||
},
|
||||
|
||||
/**
|
||||
* Enables a breakpoint.
|
||||
*
|
||||
* @param object aBreakpoint
|
||||
* An element representing a breakpoint.
|
||||
* @param function aCallback
|
||||
* Optional function to invoke once the breakpoint is enabled.
|
||||
* @param boolean aNoCheckboxUpdate
|
||||
* Pass true to not update the checkbox checked state.
|
||||
* This is usually necessary when the checked state will be updated
|
||||
* automatically (e.g: on a checkbox click).
|
||||
*/
|
||||
enableBreakpoint:
|
||||
function DVB_enableBreakpoint(aTarget, aCallback, aNoCheckboxUpdate) {
|
||||
let { breakpointUrl: url, breakpointLine: line } = aTarget;
|
||||
let breakpoint = DebuggerController.Breakpoints.getBreakpoint(url, line)
|
||||
|
||||
if (!breakpoint) {
|
||||
if (!aNoCheckboxUpdate) {
|
||||
aTarget.getElementsByTagName("checkbox")[0].setAttribute("checked", "true");
|
||||
}
|
||||
DebuggerController.Breakpoints.
|
||||
addBreakpoint({ url: url, line: line }, aCallback);
|
||||
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
},
|
||||
|
||||
/**
|
||||
* Disables a breakpoint.
|
||||
*
|
||||
* @param object aTarget
|
||||
* An element representing a breakpoint.
|
||||
* @param function aCallback
|
||||
* Optional function to invoke once the breakpoint is disabled.
|
||||
* @param boolean aNoCheckboxUpdate
|
||||
* Pass true to not update the checkbox checked state.
|
||||
* This is usually necessary when the checked state will be updated
|
||||
* automatically (e.g: on a checkbox click).
|
||||
*/
|
||||
disableBreakpoint:
|
||||
function DVB_disableBreakpoint(aTarget, aCallback, aNoCheckboxUpdate) {
|
||||
let { breakpointUrl: url, breakpointLine: line } = aTarget;
|
||||
let breakpoint = DebuggerController.Breakpoints.getBreakpoint(url, line)
|
||||
|
||||
if (breakpoint) {
|
||||
if (!aNoCheckboxUpdate) {
|
||||
aTarget.getElementsByTagName("checkbox")[0].removeAttribute("checked");
|
||||
}
|
||||
DebuggerController.Breakpoints.
|
||||
removeBreakpoint(breakpoint, aCallback, false, true);
|
||||
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
},
|
||||
|
||||
/**
|
||||
* Gets the current number of added breakpoints.
|
||||
*/
|
||||
get count() {
|
||||
return this._breakpoints.getElementsByClassName("dbg-breakpoint").length;
|
||||
},
|
||||
|
||||
/**
|
||||
* Iterates through all the added breakpoints.
|
||||
*
|
||||
* @param function aCallback
|
||||
* Function called for each element.
|
||||
*/
|
||||
_iterate: function DVB_iterate(aCallback) {
|
||||
Array.forEach(Array.slice(this._breakpoints.childNodes), aCallback);
|
||||
},
|
||||
|
||||
/**
|
||||
* Gets the real breakpoint target when an event is handled.
|
||||
* @return object
|
||||
*/
|
||||
_getBreakpointTarget: function DVB__getBreakpointTarget(aEvent) {
|
||||
let target = aEvent.target;
|
||||
|
||||
while (target) {
|
||||
if (target.breakpointActor) {
|
||||
return target;
|
||||
}
|
||||
target = target.parentNode;
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Listener handling the breakpoint click event.
|
||||
*/
|
||||
_onBreakpointClick: function DVB__onBreakpointClick(aEvent) {
|
||||
let target = this._getBreakpointTarget(aEvent);
|
||||
let { breakpointUrl: url, breakpointLine: line } = target;
|
||||
|
||||
DebuggerController.StackFrames.updateEditorToLocation(url, line, 0, 0, 1);
|
||||
},
|
||||
|
||||
/**
|
||||
* Listener handling the breakpoint checkbox change event.
|
||||
*/
|
||||
_onBreakpointCheckboxChange: function DVB__onBreakpointCheckboxChange(aEvent) {
|
||||
aEvent.stopPropagation();
|
||||
|
||||
let target = this._getBreakpointTarget(aEvent);
|
||||
let { breakpointUrl: url, breakpointLine: line } = target;
|
||||
|
||||
if (aEvent.target.getAttribute("checked") === "true") {
|
||||
this.disableBreakpoint(target, null, true);
|
||||
} else {
|
||||
this.enableBreakpoint(target, null, true);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Listener handling the "enableSelf" menuitem command.
|
||||
*
|
||||
* @param object aTarget
|
||||
* The corresponding breakpoint element.
|
||||
*/
|
||||
_onEnableSelf: function DVB__onEnableSelf(aTarget) {
|
||||
if (!aTarget) {
|
||||
return;
|
||||
}
|
||||
if (this.enableBreakpoint(aTarget)) {
|
||||
aTarget.enableSelf.menuitem.setAttribute("hidden", "true");
|
||||
aTarget.disableSelf.menuitem.removeAttribute("hidden");
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Listener handling the "disableSelf" menuitem command.
|
||||
*
|
||||
* @param object aTarget
|
||||
* The corresponding breakpoint element.
|
||||
*/
|
||||
_onDisableSelf: function DVB__onDisableSelf(aTarget) {
|
||||
if (!aTarget) {
|
||||
return;
|
||||
}
|
||||
if (this.disableBreakpoint(aTarget)) {
|
||||
aTarget.enableSelf.menuitem.removeAttribute("hidden");
|
||||
aTarget.disableSelf.menuitem.setAttribute("hidden", "true");
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Listener handling the "deleteSelf" menuitem command.
|
||||
*
|
||||
* @param object aTarget
|
||||
* The corresponding breakpoint element.
|
||||
*/
|
||||
_onDeleteSelf: function DVB__onDeleteSelf(aTarget) {
|
||||
let { breakpointUrl: url, breakpointLine: line } = aTarget;
|
||||
let breakpoint = DebuggerController.Breakpoints.getBreakpoint(url, line)
|
||||
|
||||
if (aTarget) {
|
||||
this.removeBreakpoint(aTarget.breakpointActor);
|
||||
}
|
||||
if (breakpoint) {
|
||||
DebuggerController.Breakpoints.removeBreakpoint(breakpoint);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Listener handling the "enableOthers" menuitem command.
|
||||
*
|
||||
* @param object aTarget
|
||||
* The corresponding breakpoint element.
|
||||
*/
|
||||
_onEnableOthers: function DVB__onEnableOthers(aTarget) {
|
||||
this._iterate(function(element) {
|
||||
if (element !== aTarget) {
|
||||
this._onEnableSelf(element);
|
||||
}
|
||||
}.bind(this));
|
||||
},
|
||||
|
||||
/**
|
||||
* Listener handling the "disableOthers" menuitem command.
|
||||
*
|
||||
* @param object aTarget
|
||||
* The corresponding breakpoint element.
|
||||
*/
|
||||
_onDisableOthers: function DVB__onDisableOthers(aTarget) {
|
||||
this._iterate(function(element) {
|
||||
if (element !== aTarget) {
|
||||
this._onDisableSelf(element);
|
||||
}
|
||||
}.bind(this));
|
||||
},
|
||||
|
||||
/**
|
||||
* Listener handling the "deleteOthers" menuitem command.
|
||||
*
|
||||
* @param object aTarget
|
||||
* The corresponding breakpoint element.
|
||||
*/
|
||||
_onDeleteOthers: function DVB__onDeleteOthers(aTarget) {
|
||||
this._iterate(function(element) {
|
||||
if (element !== aTarget) {
|
||||
this._onDeleteSelf(element);
|
||||
}
|
||||
}.bind(this));
|
||||
},
|
||||
|
||||
/**
|
||||
* Listener handling the "disableAll" menuitem command.
|
||||
*
|
||||
* @param object aTarget
|
||||
* The corresponding breakpoint element.
|
||||
*/
|
||||
_onEnableAll: function DVB__onEnableAll(aTarget) {
|
||||
this._onEnableOthers(aTarget);
|
||||
this._onEnableSelf(aTarget);
|
||||
},
|
||||
|
||||
/**
|
||||
* Listener handling the "disableAll" menuitem command.
|
||||
*
|
||||
* @param object aTarget
|
||||
* The corresponding breakpoint element.
|
||||
*/
|
||||
_onDisableAll: function DVB__onDisableAll(aTarget) {
|
||||
this._onDisableOthers(aTarget);
|
||||
this._onDisableSelf(aTarget);
|
||||
},
|
||||
|
||||
/**
|
||||
* Listener handling the "deleteAll" menuitem command.
|
||||
*
|
||||
* @param object aTarget
|
||||
* The corresponding breakpoint element.
|
||||
*/
|
||||
_onDeleteAll: function DVB__onDeleteAll(aTarget) {
|
||||
this._onDeleteOthers(aTarget);
|
||||
this._onDeleteSelf(aTarget);
|
||||
},
|
||||
|
||||
/**
|
||||
* The cached breakpoints container.
|
||||
*/
|
||||
_breakpoints: null,
|
||||
|
||||
/**
|
||||
* Creates a breakpoint context menu.
|
||||
*
|
||||
* @param object aBreakpoint
|
||||
* An element representing a breakpoint.
|
||||
* @return string
|
||||
* The popup id.
|
||||
*/
|
||||
_createContextMenu: function DVB_createContextMenu(aBreakpoint) {
|
||||
let commandsetId = "breakpointMenuCommands-" + aBreakpoint.id;
|
||||
let menupopupId = "breakpointContextMenu-" + aBreakpoint.id;
|
||||
|
||||
let commandsset = document.createElement("commandsset");
|
||||
commandsset.setAttribute("id", commandsetId);
|
||||
|
||||
let menupopup = document.createElement("menupopup");
|
||||
menupopup.setAttribute("id", menupopupId);
|
||||
|
||||
/**
|
||||
* Creates a menu item specified by a name with the appropriate attributes
|
||||
* (label and command handler).
|
||||
*
|
||||
* @param string aName
|
||||
* A global identifier for the menu item.
|
||||
* @param boolean aHiddenFlag
|
||||
* True if this menuitem should be hidden.
|
||||
*/
|
||||
function createMenuItem(aName, aHiddenFlag) {
|
||||
let menuitem = document.createElement("menuitem");
|
||||
let command = document.createElement("command");
|
||||
|
||||
let func = this["_on" + aName.charAt(0).toUpperCase() + aName.slice(1)];
|
||||
let label = L10N.getStr("breakpointMenuItem." + aName);
|
||||
|
||||
let prefix = "bp-cMenu-";
|
||||
let commandId = prefix + aName + "-" + aBreakpoint.id + "-command";
|
||||
let menuitemId = prefix + aName + "-" + aBreakpoint.id + "-menuitem";
|
||||
|
||||
command.setAttribute("id", commandId);
|
||||
command.setAttribute("label", label);
|
||||
command.addEventListener("command", func.bind(this, aBreakpoint), true);
|
||||
|
||||
menuitem.setAttribute("id", menuitemId);
|
||||
menuitem.setAttribute("command", commandId);
|
||||
menuitem.setAttribute("hidden", aHiddenFlag);
|
||||
|
||||
commandsset.appendChild(command);
|
||||
menupopup.appendChild(menuitem);
|
||||
|
||||
aBreakpoint[aName] = {
|
||||
menuitem: menuitem,
|
||||
command: command
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a simple menu separator element and appends it to the current
|
||||
* menupopup hierarchy.
|
||||
*/
|
||||
function createMenuSeparator() {
|
||||
let menuseparator = document.createElement("menuseparator");
|
||||
menupopup.appendChild(menuseparator);
|
||||
}
|
||||
|
||||
createMenuItem.call(this, "enableSelf", true);
|
||||
createMenuItem.call(this, "disableSelf");
|
||||
createMenuItem.call(this, "deleteSelf");
|
||||
createMenuSeparator();
|
||||
createMenuItem.call(this, "enableOthers");
|
||||
createMenuItem.call(this, "disableOthers");
|
||||
createMenuItem.call(this, "deleteOthers");
|
||||
createMenuSeparator();
|
||||
createMenuItem.call(this, "enableAll");
|
||||
createMenuItem.call(this, "disableAll");
|
||||
createMenuSeparator();
|
||||
createMenuItem.call(this, "deleteAll");
|
||||
|
||||
let popupset = document.getElementById("debugger-popups");
|
||||
popupset.appendChild(menupopup);
|
||||
document.documentElement.appendChild(commandsset);
|
||||
|
||||
return menupopupId;
|
||||
},
|
||||
|
||||
/**
|
||||
* Destroys a breakpoint context menu.
|
||||
*
|
||||
* @param object aBreakpoint
|
||||
* An element representing a breakpoint.
|
||||
*/
|
||||
_destroyContextMenu: function DVB__destroyContextMenu(aBreakpoint) {
|
||||
let commandsetId = "breakpointMenuCommands-" + aBreakpoint.id;
|
||||
let menupopupId = "breakpointContextMenu-" + aBreakpoint.id;
|
||||
|
||||
let commandset = document.getElementById(commandsetId);
|
||||
let menupopup = document.getElementById(menupopupId);
|
||||
|
||||
if (commandset) {
|
||||
commandset.parentNode.removeChild(commandset);
|
||||
}
|
||||
if (menupopup) {
|
||||
menupopup.parentNode.removeChild(menupopup);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Initialization function, called when the debugger is initialized.
|
||||
*/
|
||||
initialize: function DVB_initialize() {
|
||||
let breakpoints = document.getElementById("breakpoints");
|
||||
breakpoints.addEventListener("click", this._onBreakpointClick, false);
|
||||
|
||||
this._breakpoints = breakpoints;
|
||||
this.emptyText();
|
||||
},
|
||||
|
||||
/**
|
||||
* Destruction function, called when the debugger is shut down.
|
||||
*/
|
||||
destroy: function DVB_destroy() {
|
||||
let breakpoints = this._breakpoints;
|
||||
breakpoints.removeEventListener("click", this._onBreakpointClick, false);
|
||||
|
||||
this._breakpoints = null;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Functions handling the properties view.
|
||||
*/
|
||||
@ -847,6 +1388,7 @@ function PropertiesView() {
|
||||
}
|
||||
|
||||
PropertiesView.prototype = {
|
||||
|
||||
/**
|
||||
* A monotonically-increasing counter, that guarantees the uniqueness of scope
|
||||
* IDs.
|
||||
@ -1923,9 +2465,10 @@ PropertiesView.prototype = {
|
||||
* Initialization function, called when the debugger is initialized.
|
||||
*/
|
||||
initialize: function DVP_initialize() {
|
||||
this.createHierarchyStore();
|
||||
|
||||
this._vars = document.getElementById("variables");
|
||||
|
||||
this.emptyText();
|
||||
this.createHierarchyStore();
|
||||
},
|
||||
|
||||
/**
|
||||
@ -1943,6 +2486,7 @@ PropertiesView.prototype = {
|
||||
*/
|
||||
DebuggerView.Scripts = new ScriptsView();
|
||||
DebuggerView.StackFrames = new StackFramesView();
|
||||
DebuggerView.Breakpoints = new BreakpointsView();
|
||||
DebuggerView.Properties = new PropertiesView();
|
||||
|
||||
/**
|
||||
|
@ -12,6 +12,20 @@
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
/**
|
||||
* Breakpoints view
|
||||
*/
|
||||
|
||||
#breakpoints {
|
||||
overflow-x: hidden;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.dbg-breakpoint > .state,
|
||||
.dbg-breakpoint > .content {
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
/**
|
||||
* Properties elements
|
||||
*/
|
||||
|
@ -80,10 +80,14 @@
|
||||
#endif
|
||||
</toolbar>
|
||||
<hbox id="dbg-content" flex="1">
|
||||
<vbox id="stackframes"/>
|
||||
<splitter id="stack-script-splitter" class="devtools-side-splitter"/>
|
||||
<vbox id="stackframes+breakpoints">
|
||||
<vbox id="stackframes" flex="1"/>
|
||||
<splitter class="devtools-horizontal-splitter"/>
|
||||
<vbox id="breakpoints"/>
|
||||
</vbox>
|
||||
<splitter class="devtools-side-splitter"/>
|
||||
<vbox id="editor" flex="1"/>
|
||||
<splitter id="script-properties-splitter" class="devtools-side-splitter"/>
|
||||
<splitter class="devtools-side-splitter"/>
|
||||
<vbox id="variables"/>
|
||||
</hbox>
|
||||
</vbox>
|
||||
|
@ -51,6 +51,7 @@ MOCHITEST_BROWSER_TESTS = \
|
||||
$(warning browser_dbg_select-line.js temporarily disabled due to oranges, see bug 726609) \
|
||||
browser_dbg_clean-exit.js \
|
||||
browser_dbg_bug723069_editor-breakpoints.js \
|
||||
browser_dbg_bug723071_editor-breakpoints-pane.js \
|
||||
browser_dbg_bug731394_editor-contextmenu.js \
|
||||
browser_dbg_displayName.js \
|
||||
browser_dbg_iframes.js \
|
||||
|
@ -21,6 +21,7 @@ function test()
|
||||
let tempScope = {};
|
||||
Cu.import("resource:///modules/source-editor.jsm", tempScope);
|
||||
let SourceEditor = tempScope.SourceEditor;
|
||||
|
||||
let scriptShown = false;
|
||||
let framesAdded = false;
|
||||
let resumed = false;
|
||||
|
@ -0,0 +1,281 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
/**
|
||||
* Bug 723071: test adding a pane to display the list of breakpoints across
|
||||
* all scripts in the debuggee.
|
||||
*/
|
||||
|
||||
const TAB_URL = EXAMPLE_URL + "browser_dbg_script-switching.html";
|
||||
|
||||
let gPane = null;
|
||||
let gTab = null;
|
||||
let gDebuggee = null;
|
||||
let gDebugger = null;
|
||||
let gScripts = null;
|
||||
let gBreakpoints = null;
|
||||
let gBreakpointsElement = null;
|
||||
|
||||
function test()
|
||||
{
|
||||
let scriptShown = false;
|
||||
let framesAdded = false;
|
||||
let resumed = false;
|
||||
let testStarted = false;
|
||||
|
||||
debug_tab_pane(TAB_URL, function(aTab, aDebuggee, aPane) {
|
||||
gTab = aTab;
|
||||
gDebuggee = aDebuggee;
|
||||
gPane = aPane;
|
||||
gDebugger = gPane.contentWindow;
|
||||
resumed = true;
|
||||
|
||||
gDebugger.DebuggerController.activeThread.addOneTimeListener("framesadded", function() {
|
||||
framesAdded = true;
|
||||
executeSoon(startTest);
|
||||
});
|
||||
|
||||
executeSoon(function() {
|
||||
gDebuggee.firstCall();
|
||||
});
|
||||
});
|
||||
|
||||
function onScriptShown(aEvent)
|
||||
{
|
||||
scriptShown = aEvent.detail.url.indexOf("-02.js") != -1;
|
||||
executeSoon(startTest);
|
||||
}
|
||||
|
||||
window.addEventListener("Debugger:ScriptShown", onScriptShown);
|
||||
|
||||
function startTest()
|
||||
{
|
||||
if (scriptShown && framesAdded && resumed && !testStarted) {
|
||||
window.removeEventListener("Debugger:ScriptShown", onScriptShown);
|
||||
testStarted = true;
|
||||
Services.tm.currentThread.dispatch({ run: performTest }, 0);
|
||||
}
|
||||
}
|
||||
|
||||
let breakpointsAdded = 0;
|
||||
let breakpointsDisabled = 0;
|
||||
let breakpointsRemoved = 0;
|
||||
|
||||
function performTest()
|
||||
{
|
||||
gScripts = gDebugger.DebuggerView.Scripts;
|
||||
|
||||
is(gDebugger.DebuggerController.activeThread.state, "paused",
|
||||
"Should only be getting stack frames while paused.");
|
||||
|
||||
is(gScripts._scripts.itemCount, 2, "Found the expected number of scripts.");
|
||||
|
||||
let editor = gDebugger.editor;
|
||||
|
||||
isnot(editor.getText().indexOf("debugger"), -1,
|
||||
"The correct script was loaded initially.");
|
||||
isnot(gScripts.selected, gScripts.scriptLocations[0],
|
||||
"the correct script is selected");
|
||||
|
||||
gBreakpoints = gPane.breakpoints;
|
||||
is(Object.keys(gBreakpoints), 0, "no breakpoints");
|
||||
ok(!gPane.getBreakpoint("chocolate", 3), "getBreakpoint('chocolate', 3) returns falsey");
|
||||
|
||||
is(editor.getBreakpoints().length, 0, "no breakpoints in the editor");
|
||||
|
||||
gBreakpointsElement = gDebugger.DebuggerView.Breakpoints._breakpoints;
|
||||
is(gBreakpointsElement.childNodes.length, 1,
|
||||
"The breakpoints pane should be empty, but showing a " +
|
||||
"'no breakpoints' information message.");
|
||||
is(gBreakpointsElement.childNodes.length,
|
||||
gBreakpointsElement.querySelectorAll(".list-item.empty").length,
|
||||
"Found junk in the breakpoints container.");
|
||||
|
||||
addBreakpoints(function() {
|
||||
is(breakpointsAdded, 3,
|
||||
"Should have added 3 breakpoints so far.");
|
||||
is(breakpointsDisabled, 0,
|
||||
"Shouldn't have disabled anything so far.");
|
||||
is(breakpointsRemoved, 0,
|
||||
"Shouldn't have removed anything so far.");
|
||||
|
||||
is(gBreakpointsElement.childNodes.length,
|
||||
gBreakpointsElement.querySelectorAll(".dbg-breakpoint").length,
|
||||
"Found junk in the breakpoints container.");
|
||||
|
||||
disableBreakpoints(function() {
|
||||
is(breakpointsAdded, 3,
|
||||
"Should still have 3 breakpoints added so far.");
|
||||
is(breakpointsDisabled, 3,
|
||||
"Should have 3 disabled breakpoints.");
|
||||
is(breakpointsRemoved, 0,
|
||||
"Shouldn't have removed anything so far.");
|
||||
|
||||
is(gBreakpointsElement.childNodes.length, breakpointsAdded,
|
||||
"Should have the same number of breakpoints in the pane.");
|
||||
is(gBreakpointsElement.childNodes.length, breakpointsDisabled,
|
||||
"Should have the same number of disabled breakpoints.");
|
||||
|
||||
addBreakpoints(function() {
|
||||
is(breakpointsAdded, 3,
|
||||
"Should still have only 3 breakpoints added so far.");
|
||||
is(breakpointsDisabled, 3,
|
||||
"Should still have 3 disabled breakpoints.");
|
||||
is(breakpointsRemoved, 0,
|
||||
"Shouldn't have removed anything so far.");
|
||||
|
||||
is(gBreakpointsElement.childNodes.length, breakpointsAdded,
|
||||
"Since half of the breakpoints already existed, but disabled, " +
|
||||
"only half of the added breakpoints are actually in the pane.");
|
||||
is(gBreakpointsElement.childNodes.length,
|
||||
gBreakpointsElement.querySelectorAll(".dbg-breakpoint").length,
|
||||
"Found junk in the breakpoints container.");
|
||||
|
||||
removeBreakpoints(function() {
|
||||
is(breakpointsRemoved, 3,
|
||||
"Should have 3 removed breakpoints.");
|
||||
|
||||
is(gBreakpointsElement.childNodes.length, 1,
|
||||
"The breakpoints pane should be empty, but showing a " +
|
||||
"'no breakpoints' information message.");
|
||||
is(gBreakpointsElement.childNodes.length,
|
||||
gBreakpointsElement.querySelectorAll(".list-item.empty").length,
|
||||
"Found junk in the breakpoints container.");
|
||||
|
||||
finish();
|
||||
});
|
||||
});
|
||||
});
|
||||
}, true);
|
||||
|
||||
function addBreakpoints(callback, increment)
|
||||
{
|
||||
let line;
|
||||
|
||||
executeSoon(function()
|
||||
{
|
||||
line = 4;
|
||||
gPane.addBreakpoint({url: gScripts.selected, line: line},
|
||||
function(cl, err) {
|
||||
onBreakpointAdd.call({ increment: increment, line: line }, cl, err);
|
||||
|
||||
line = 5;
|
||||
gPane.addBreakpoint({url: gScripts.selected, line: line},
|
||||
function(cl, err) {
|
||||
onBreakpointAdd.call({ increment: increment, line: line }, cl, err);
|
||||
|
||||
line = 6;
|
||||
gPane.addBreakpoint({url: gScripts.selected, line: line},
|
||||
function(cl, err) {
|
||||
onBreakpointAdd.call({ increment: increment, line: line }, cl, err);
|
||||
|
||||
executeSoon(function() {
|
||||
callback();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function disableBreakpoints(callback)
|
||||
{
|
||||
let nodes = Array.slice(gBreakpointsElement.childNodes);
|
||||
info("Nodes to disable: " + breakpointsAdded);
|
||||
is(nodes.length, breakpointsAdded,
|
||||
"The number of nodes to disable is incorrect.");
|
||||
|
||||
Array.forEach(nodes, function(bkp) {
|
||||
info("Disabling breakpoint: " + bkp.id);
|
||||
|
||||
gDebugger.DebuggerView.Breakpoints.disableBreakpoint(bkp, function() {
|
||||
if (++breakpointsDisabled !== breakpointsAdded) {
|
||||
return;
|
||||
}
|
||||
executeSoon(function() {
|
||||
callback();
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function removeBreakpoints(callback)
|
||||
{
|
||||
let nodes = Array.slice(gBreakpointsElement.childNodes);
|
||||
info("Nodes to remove: " + breakpointsAdded);
|
||||
is(nodes.length, breakpointsAdded,
|
||||
"The number of nodes to remove is incorrect.");
|
||||
|
||||
Array.forEach(nodes, function(bkp) {
|
||||
info("Removing breakpoint: " + bkp.id);
|
||||
|
||||
let [url, line, actor] =
|
||||
[bkp.breakpointUrl, bkp.breakpointLine, bkp.breakpointActor];
|
||||
|
||||
gDebugger.DebuggerView.Breakpoints.removeBreakpoint(actor);
|
||||
gPane.removeBreakpoint(gPane.getBreakpoint(url, line), function() {
|
||||
if (++breakpointsRemoved !== breakpointsAdded) {
|
||||
return;
|
||||
}
|
||||
executeSoon(function() {
|
||||
callback();
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function onBreakpointAdd(aBreakpointClient, aResponseError)
|
||||
{
|
||||
if (this.increment) {
|
||||
breakpointsAdded++;
|
||||
}
|
||||
|
||||
is(gBreakpointsElement.childNodes.length, breakpointsAdded, this.increment
|
||||
? "Should have added a breakpoint in the pane."
|
||||
: "Should have the same number of breakpoints in the pane.");
|
||||
|
||||
let id = "breakpoint-" + aBreakpointClient.actor;
|
||||
let bkp = gDebugger.document.getElementById(id);
|
||||
let info = bkp.getElementsByClassName("dbg-breakpoint-info")[0];
|
||||
let text = bkp.getElementsByClassName("dbg-breakpoint-text")[0];
|
||||
let check = bkp.querySelector("checkbox");
|
||||
|
||||
is(bkp.id, id,
|
||||
"Breakpoint element " + id + " found succesfully.");
|
||||
is(info.getAttribute("value"), getExpectedBreakpointInfo(this.line),
|
||||
"The expected information wasn't found in the breakpoint element.");
|
||||
is(text.getAttribute("value"), getExpectedLineText(this.line).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.");
|
||||
}
|
||||
|
||||
function getExpectedBreakpointInfo(line) {
|
||||
let url = gDebugger.DebuggerView.Scripts.selected;
|
||||
let label = gDebugger.DebuggerController.SourceScripts.getScriptLabel(url);
|
||||
return label + ":" + line;
|
||||
}
|
||||
|
||||
function getExpectedLineText(line) {
|
||||
return gDebugger.DebuggerController.SourceScripts.getLineText(line - 1);
|
||||
}
|
||||
}
|
||||
|
||||
registerCleanupFunction(function() {
|
||||
is(Object.keys(gBreakpoints).length, 0, "no breakpoint in the debugger");
|
||||
ok(!gPane.getBreakpoint(gScripts.scriptLocations[0], 5),
|
||||
"getBreakpoint(scriptLocations[0], 5) returns no breakpoint");
|
||||
|
||||
is(breakpointsAdded, 3, "correct number of breakpoints have been added");
|
||||
is(breakpointsDisabled, 3, "correct number of breakpoints have been disabled");
|
||||
is(breakpointsRemoved, 3, "correct number of breakpoints have been removed");
|
||||
removeTab(gTab);
|
||||
gPane = null;
|
||||
gTab = null;
|
||||
gDebuggee = null;
|
||||
gDebugger = null;
|
||||
gScripts = null;
|
||||
gBreakpoints = null;
|
||||
gBreakpointsElement = null;
|
||||
});
|
||||
}
|
@ -33,7 +33,7 @@ function test() {
|
||||
ok(content.Prefs.variablesWidth,
|
||||
"The debugger preferences should have a saved variablesWidth value.");
|
||||
|
||||
stackframes = content.document.getElementById("stackframes");
|
||||
stackframes = content.document.getElementById("stackframes+breakpoints");
|
||||
variables = content.document.getElementById("variables");
|
||||
|
||||
is(content.Prefs.stackframesWidth, stackframes.getAttribute("width"),
|
||||
|
@ -68,7 +68,7 @@ function testScriptLabelShortening() {
|
||||
urls.forEach(function(url) {
|
||||
executeSoon(function() {
|
||||
let loc = url.href + url.leaf;
|
||||
vs.addScript(ss._getScriptLabel(loc, url.href), { url: loc }, true);
|
||||
vs.addScript(ss.getScriptLabel(loc, url.href), { url: loc }, true);
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -67,7 +67,7 @@ function addScriptsAndCheckOrder(method, callback) {
|
||||
case 1:
|
||||
urls.forEach(function(url) {
|
||||
let loc = url.href + url.leaf;
|
||||
vs.addScript(ss._getScriptLabel(loc, url.href), { url: loc });
|
||||
vs.addScript(ss.getScriptLabel(loc, url.href), { url: loc });
|
||||
});
|
||||
vs.commitScripts();
|
||||
break;
|
||||
@ -75,7 +75,7 @@ function addScriptsAndCheckOrder(method, callback) {
|
||||
case 2:
|
||||
urls.forEach(function(url) {
|
||||
let loc = url.href + url.leaf;
|
||||
vs.addScript(ss._getScriptLabel(loc, url.href), { url: loc }, true);
|
||||
vs.addScript(ss.getScriptLabel(loc, url.href), { url: loc }, true);
|
||||
});
|
||||
break;
|
||||
|
||||
@ -84,14 +84,14 @@ function addScriptsAndCheckOrder(method, callback) {
|
||||
for (; i < urls.length / 2; i++) {
|
||||
let url = urls[i];
|
||||
let loc = url.href + url.leaf;
|
||||
vs.addScript(ss._getScriptLabel(loc, url.href), { url: loc });
|
||||
vs.addScript(ss.getScriptLabel(loc, url.href), { url: loc });
|
||||
}
|
||||
vs.commitScripts();
|
||||
|
||||
for (; i < urls.length; i++) {
|
||||
let url = urls[i];
|
||||
let loc = url.href + url.leaf;
|
||||
vs.addScript(ss._getScriptLabel(loc, url.href), { url: loc }, true);
|
||||
vs.addScript(ss.getScriptLabel(loc, url.href), { url: loc }, true);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -55,6 +55,22 @@ resumeTooltip=Click to resume
|
||||
# frames list when there are no frames to display.
|
||||
emptyStackText=No stacks to display.
|
||||
|
||||
# LOCALIZATION NOTE (emptyBreakpointsText): The text that is displayed in the
|
||||
# breakpoints list when there are no breakpoints to display.
|
||||
emptyBreakpointsText=No breakpoints to display.
|
||||
|
||||
# LOCALIZATION NOTE (breakpointMenuItem): The text for all the elements that
|
||||
# are displayed in the breakpoints menu item popup.
|
||||
breakpointMenuItem.enableSelf=Enable breakpoint
|
||||
breakpointMenuItem.disableSelf=Disable breakpoint
|
||||
breakpointMenuItem.deleteSelf=Remove breakpoint
|
||||
breakpointMenuItem.enableOthers=Enable others
|
||||
breakpointMenuItem.disableOthers=Disable others
|
||||
breakpointMenuItem.deleteOthers=Remove others
|
||||
breakpointMenuItem.enableAll=Enable all breakpoints
|
||||
breakpointMenuItem.disableAll=Disable all breakpoints
|
||||
breakpointMenuItem.deleteAll=Remove all breakpoints
|
||||
|
||||
# LOCALIZATION NOTE (loadingText): The text that is displayed in the script
|
||||
# editor when the laoding process has started but there is no file to display
|
||||
# yet.
|
||||
|
@ -28,6 +28,10 @@
|
||||
padding: 2px;
|
||||
}
|
||||
|
||||
.list-item:not(.selected):not(.empty):hover {
|
||||
background: #cddae5;
|
||||
}
|
||||
|
||||
.list-item.selected {
|
||||
background: Highlight;
|
||||
color: HighlightText;
|
||||
@ -35,6 +39,7 @@
|
||||
|
||||
.list-item.empty {
|
||||
color: GrayText;
|
||||
padding: 4px;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -55,6 +60,22 @@
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
/**
|
||||
* Breakpoints view
|
||||
*/
|
||||
|
||||
#breakpoints {
|
||||
background-color: white;
|
||||
}
|
||||
|
||||
.dbg-breakpoint-info {
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.dbg-breakpoint-text {
|
||||
font: 8pt monospace;
|
||||
}
|
||||
|
||||
/**
|
||||
* Properties view
|
||||
*/
|
||||
|
@ -30,6 +30,10 @@
|
||||
padding: 2px;
|
||||
}
|
||||
|
||||
.list-item:not(.selected):not(.empty):hover {
|
||||
background: #cddae5;
|
||||
}
|
||||
|
||||
.list-item.selected {
|
||||
background: Highlight;
|
||||
color: HighlightText;
|
||||
@ -37,6 +41,7 @@
|
||||
|
||||
.list-item.empty {
|
||||
color: GrayText;
|
||||
padding: 4px;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -57,6 +62,22 @@
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
/**
|
||||
* Breakpoints view
|
||||
*/
|
||||
|
||||
#breakpoints {
|
||||
background-color: white;
|
||||
}
|
||||
|
||||
.dbg-breakpoint-info {
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.dbg-breakpoint-text {
|
||||
font: 8pt monospace;
|
||||
}
|
||||
|
||||
/**
|
||||
* Properties view
|
||||
*/
|
||||
|
@ -36,6 +36,10 @@
|
||||
padding: 2px;
|
||||
}
|
||||
|
||||
.list-item:not(.selected):not(.empty):hover {
|
||||
background: #cddae5;
|
||||
}
|
||||
|
||||
.list-item.selected {
|
||||
background: Highlight;
|
||||
color: HighlightText;
|
||||
@ -43,6 +47,7 @@
|
||||
|
||||
.list-item.empty {
|
||||
color: GrayText;
|
||||
padding: 4px;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -63,6 +68,22 @@
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
/**
|
||||
* Breakpoints view
|
||||
*/
|
||||
|
||||
#breakpoints {
|
||||
background-color: white;
|
||||
}
|
||||
|
||||
.dbg-breakpoint-info {
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.dbg-breakpoint-text {
|
||||
font: 8pt monospace;
|
||||
}
|
||||
|
||||
/**
|
||||
* Properties view
|
||||
*/
|
||||
|
Loading…
Reference in New Issue
Block a user