mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-28 23:31:56 +00:00
Bug 812814 - Add a way to edit or remove watch expressions while the debugger is paused, r=past
This commit is contained in:
parent
1080556613
commit
878954fbc8
@ -509,7 +509,7 @@ StackFrames.prototype = {
|
||||
// If an error was thrown during the evaluation of the watch expressions,
|
||||
// then at least one expression evaluation could not be performed.
|
||||
if (this.currentEvaluation.throw) {
|
||||
DebuggerView.WatchExpressions.removeExpression(0);
|
||||
DebuggerView.WatchExpressions.removeExpressionAt(0);
|
||||
DebuggerController.StackFrames.syncWatchExpressions();
|
||||
return;
|
||||
}
|
||||
@ -600,11 +600,15 @@ StackFrames.prototype = {
|
||||
|
||||
// If watch expressions evaluation results are available, create a scope
|
||||
// to contain all the values.
|
||||
if (watchExpressionsEvaluation) {
|
||||
if (this.syncedWatchExpressions && watchExpressionsEvaluation) {
|
||||
let label = L10N.getStr("watchExpressionsScopeLabel");
|
||||
let arrow = L10N.getStr("watchExpressionsSeparatorLabel");
|
||||
let scope = DebuggerView.Variables.addScope(label);
|
||||
scope.separator = arrow;
|
||||
scope.allowNameInput = true;
|
||||
scope.allowDeletion = true;
|
||||
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.
|
||||
@ -939,6 +943,7 @@ StackFrames.prototype = {
|
||||
this.syncedWatchExpressions =
|
||||
this.currentWatchExpressions = null;
|
||||
}
|
||||
this.currentFrame = null;
|
||||
this._onFrames();
|
||||
},
|
||||
|
||||
|
@ -945,6 +945,8 @@ create({ constructor: BreakpointsView, proto: MenuContainer.prototype }, {
|
||||
function WatchExpressionsView() {
|
||||
dumpn("WatchExpressionsView was instantiated");
|
||||
MenuContainer.call(this);
|
||||
this.switchExpression = this.switchExpression.bind(this);
|
||||
this.deleteExpression = this.deleteExpression.bind(this);
|
||||
this._createItemView = this._createItemView.bind(this);
|
||||
this._onClick = this._onClick.bind(this);
|
||||
this._onClose = this._onClose.bind(this);
|
||||
@ -1028,11 +1030,54 @@ create({ constructor: WatchExpressionsView, proto: MenuContainer.prototype }, {
|
||||
* @param number aIndex
|
||||
* The index used to identify the watch expression.
|
||||
*/
|
||||
removeExpression: function DVWE_removeExpression(aIndex) {
|
||||
removeExpressionAt: function DVWE_removeExpressionAt(aIndex) {
|
||||
this.remove(this._cache[aIndex]);
|
||||
this._cache.splice(aIndex, 1);
|
||||
},
|
||||
|
||||
/**
|
||||
* Changes the watch expression corresponding to the specified variable item.
|
||||
*
|
||||
* @param Variable aVar
|
||||
* The variable representing the watch expression evaluation.
|
||||
* @param string aExpression
|
||||
* The new watch expression text.
|
||||
*/
|
||||
switchExpression: function DVWE_switchExpression(aVar, aExpression) {
|
||||
let expressionItem =
|
||||
[i for (i of this._cache) if (i.attachment.expression == aVar.name)][0];
|
||||
|
||||
// Remove the watch expression if it's going to be a duplicate.
|
||||
if (!aExpression || this.getExpressions().indexOf(aExpression) != -1) {
|
||||
this.deleteExpression(aVar);
|
||||
return;
|
||||
}
|
||||
|
||||
// Save the watch expression code string.
|
||||
expressionItem.attachment.expression = aExpression;
|
||||
expressionItem.target.inputNode.value = aExpression;
|
||||
|
||||
// Synchronize with the controller's watch expressions store.
|
||||
DebuggerController.StackFrames.syncWatchExpressions();
|
||||
},
|
||||
|
||||
/**
|
||||
* Removes the watch expression corresponding to the specified variable item.
|
||||
*
|
||||
* @param Variable aVar
|
||||
* The variable representing the watch expression evaluation.
|
||||
*/
|
||||
deleteExpression: function DVWE_deleteExpression(aVar) {
|
||||
let expressionItem =
|
||||
[i for (i of this._cache) if (i.attachment.expression == aVar.name)][0];
|
||||
|
||||
// Remove the watch expression at its respective index.
|
||||
this.removeExpressionAt(this._cache.indexOf(expressionItem));
|
||||
|
||||
// Synchronize with the controller's watch expressions store.
|
||||
DebuggerController.StackFrames.syncWatchExpressions();
|
||||
},
|
||||
|
||||
/**
|
||||
* Gets the watch expression code string for an item in this container.
|
||||
*
|
||||
@ -1101,7 +1146,7 @@ create({ constructor: WatchExpressionsView, proto: MenuContainer.prototype }, {
|
||||
*/
|
||||
_onClose: function DVWE__onClose(e) {
|
||||
let expressionItem = this.getItemForElement(e.target);
|
||||
this.removeExpression(this._cache.indexOf(expressionItem));
|
||||
this.removeExpressionAt(this._cache.indexOf(expressionItem));
|
||||
|
||||
// Synchronize with the controller's watch expressions store.
|
||||
DebuggerController.StackFrames.syncWatchExpressions();
|
||||
@ -1116,15 +1161,15 @@ create({ constructor: WatchExpressionsView, proto: MenuContainer.prototype }, {
|
||||
_onBlur: function DVWE__onBlur({ target: textbox }) {
|
||||
let expressionItem = this.getItemForElement(textbox);
|
||||
let oldExpression = expressionItem.attachment.expression;
|
||||
let newExpression = textbox.value;
|
||||
let newExpression = textbox.value.trim();
|
||||
|
||||
// Remove the watch expression if it's empty.
|
||||
if (!newExpression) {
|
||||
this.removeExpression(this._cache.indexOf(expressionItem));
|
||||
this.removeExpressionAt(this._cache.indexOf(expressionItem));
|
||||
}
|
||||
// Remove the watch expression if it's a duplicate.
|
||||
else if (!oldExpression && this.getExpressions().indexOf(newExpression) != -1) {
|
||||
this.removeExpression(this._cache.indexOf(expressionItem));
|
||||
this.removeExpressionAt(this._cache.indexOf(expressionItem));
|
||||
}
|
||||
// Expression is eligible.
|
||||
else {
|
||||
|
@ -33,6 +33,7 @@ MOCHITEST_BROWSER_TESTS = \
|
||||
browser_dbg_propertyview-09.js \
|
||||
browser_dbg_propertyview-10.js \
|
||||
browser_dbg_propertyview-edit.js \
|
||||
browser_dbg_propertyview-edit-watch.js \
|
||||
browser_dbg_propertyview-data.js \
|
||||
browser_dbg_propertyview-filter-01.js \
|
||||
browser_dbg_propertyview-filter-02.js \
|
||||
|
@ -52,6 +52,20 @@ function test()
|
||||
is(gWatch.getExpressions().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,
|
||||
"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,
|
||||
"Duplicate watch expressions are automatically removed");
|
||||
|
||||
|
||||
addAndCheckCustomExpression(2, 0, "bazΩΩka");
|
||||
addAndCheckCustomExpression(3, 0, "bambøøcha");
|
||||
@ -194,7 +208,7 @@ function test()
|
||||
}
|
||||
|
||||
function removeAndCheckExpression(total, index, string) {
|
||||
gWatch.removeExpression(index);
|
||||
gWatch.removeExpressionAt(index);
|
||||
|
||||
is(gWatch.getExpressions().length, total,
|
||||
"There should be " + total + " watch expressions available (1)");
|
||||
|
@ -0,0 +1,502 @@
|
||||
/* vim:set ts=2 sw=2 sts=2 et: */
|
||||
/*
|
||||
* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/
|
||||
*/
|
||||
|
||||
/**
|
||||
* Make sure that the editing or removing watch expressions works properly.
|
||||
*/
|
||||
|
||||
const TAB_URL = EXAMPLE_URL + "browser_dbg_watch-expressions.html";
|
||||
|
||||
var gPane = null;
|
||||
var gTab = null;
|
||||
var gDebuggee = null;
|
||||
var gDebugger = null;
|
||||
var gWatch = null;
|
||||
var gVars = null;
|
||||
|
||||
requestLongerTimeout(2);
|
||||
|
||||
function test() {
|
||||
debug_tab_pane(TAB_URL, function(aTab, aDebuggee, aPane) {
|
||||
gTab = aTab;
|
||||
gDebuggee = aDebuggee;
|
||||
gPane = aPane;
|
||||
gDebugger = gPane.contentWindow;
|
||||
gWatch = gDebugger.DebuggerView.WatchExpressions;
|
||||
gVars = gDebugger.DebuggerView.Variables;
|
||||
|
||||
gDebugger.DebuggerController.StackFrames.autoScopeExpand = true;
|
||||
gDebugger.DebuggerView.Variables.nonEnumVisible = false;
|
||||
testFrameEval();
|
||||
});
|
||||
}
|
||||
|
||||
function testFrameEval() {
|
||||
gDebugger.addEventListener("Debugger:FetchedWatchExpressions", function test() {
|
||||
gDebugger.removeEventListener("Debugger:FetchedWatchExpressions", test, false);
|
||||
Services.tm.currentThread.dispatch({ run: function() {
|
||||
|
||||
is(gDebugger.DebuggerController.activeThread.state, "paused",
|
||||
"Should only be getting stack frames while paused.");
|
||||
|
||||
var localScope = gDebugger.DebuggerView.Variables._list.querySelectorAll(".scope")[1],
|
||||
localNodes = localScope.querySelector(".details").childNodes,
|
||||
aArg = localNodes[1],
|
||||
varT = localNodes[3];
|
||||
|
||||
is(aArg.querySelector(".name").getAttribute("value"), "aArg",
|
||||
"Should have the right name for 'aArg'.");
|
||||
is(varT.querySelector(".name").getAttribute("value"), "t",
|
||||
"Should have the right name for 't'.");
|
||||
|
||||
is(aArg.querySelector(".value").getAttribute("value"), "undefined",
|
||||
"Should have the right initial value for 'aArg'.");
|
||||
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,
|
||||
"There should be 5 hidden nodes in the watch expressions container");
|
||||
is(gWatch._container._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");
|
||||
let scope = gVars._currHierarchy.get(label);
|
||||
|
||||
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(scope.get("this")._isShown, true,
|
||||
"Should have the right visibility state for 'this'.");
|
||||
is(scope.get("this").target.querySelectorAll(".dbg-variables-delete").length, 1,
|
||||
"Should have the one close button visible for 'this'.");
|
||||
is(scope.get("this").name, "this",
|
||||
"Should have the right name for 'this'.");
|
||||
is(scope.get("this").value.type, "object",
|
||||
"Should have the right value type for 'this'.");
|
||||
is(scope.get("this").value.class, "Proxy",
|
||||
"Should have the right value type for 'this'.");
|
||||
|
||||
is(scope.get("ermahgerd")._isShown, true,
|
||||
"Should have the right visibility state for 'ermahgerd'.");
|
||||
is(scope.get("ermahgerd").target.querySelectorAll(".dbg-variables-delete").length, 1,
|
||||
"Should have the one close button visible for 'ermahgerd'.");
|
||||
is(scope.get("ermahgerd").name, "ermahgerd",
|
||||
"Should have the right name for 'ermahgerd'.");
|
||||
is(scope.get("ermahgerd").value.type, "object",
|
||||
"Should have the right value type for 'ermahgerd'.");
|
||||
is(scope.get("ermahgerd").value.class, "Function",
|
||||
"Should have the right value type for 'ermahgerd'.");
|
||||
|
||||
is(scope.get("aArg")._isShown, true,
|
||||
"Should have the right visibility state for 'aArg'.");
|
||||
is(scope.get("aArg").target.querySelectorAll(".dbg-variables-delete").length, 1,
|
||||
"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,
|
||||
"Should have the right value for 'aArg'.");
|
||||
|
||||
is(scope.get("document.title")._isShown, true,
|
||||
"Should have the right visibility state for 'document.title'.");
|
||||
is(scope.get("document.title").target.querySelectorAll(".dbg-variables-delete").length, 1,
|
||||
"Should have the one close button visible for 'document.title'.");
|
||||
is(scope.get("document.title").name, "document.title",
|
||||
"Should have the right name for 'document.title'.");
|
||||
is(scope.get("document.title").value, "42",
|
||||
"Should have the right value for 'document.title'.");
|
||||
is(typeof scope.get("document.title").value, "string",
|
||||
"Should have the right value type for 'document.title'.");
|
||||
|
||||
is(scope.get("document.title = 42")._isShown, true,
|
||||
"Should have the right visibility state for 'document.title = 42'.");
|
||||
is(scope.get("document.title = 42").target.querySelectorAll(".dbg-variables-delete").length, 1,
|
||||
"Should have the one close button visible for 'document.title = 42'.");
|
||||
is(scope.get("document.title = 42").name, "document.title = 42",
|
||||
"Should have the right name for 'document.title = 42'.");
|
||||
is(scope.get("document.title = 42").value, 42,
|
||||
"Should have the right value for 'document.title = 42'.");
|
||||
is(typeof scope.get("document.title = 42").value, "number",
|
||||
"Should have the right value type for 'document.title = 42'.");
|
||||
|
||||
testModification(scope.get("document.title = 42").target, test1, function(scope) {
|
||||
testModification(scope.get("aArg").target, test2, function(scope) {
|
||||
testModification(scope.get("aArg = 44").target, test3, function(scope) {
|
||||
testModification(scope.get("document.title = 43").target, test4, function(scope) {
|
||||
testModification(scope.get("document.title").target, test5, function(scope) {
|
||||
testExprDeletion(scope.get("this").target, test6, function(scope) {
|
||||
testExprDeletion(scope.get("ermahgerd").target, test7, function(scope) {
|
||||
resumeAndFinish();
|
||||
}, 44, 0, true);
|
||||
}, 44);
|
||||
}, " \t\r\n", "\"43\"", 44, 1, true);
|
||||
}, " \t\r\ndocument.title \t\r\n", "\"43\"", 44);
|
||||
}, " \t\r\ndocument.title \t\r\n", "\"43\"", 44);
|
||||
}, "aArg = 44", 44, 44);
|
||||
}, "document.title = 43", 43, "undefined");
|
||||
}}, 0);
|
||||
}, false);
|
||||
|
||||
addWatchExpression("this");
|
||||
addWatchExpression("ermahgerd");
|
||||
addWatchExpression("aArg");
|
||||
addWatchExpression("document.title");
|
||||
addWatchExpression("document.title = 42");
|
||||
|
||||
executeSoon(function() {
|
||||
gDebuggee.ermahgerd(); // ermahgerd!!
|
||||
});
|
||||
}
|
||||
|
||||
function testModification(aVar, aTest, aCallback, aNewValue, aNewResult, aArgResult,
|
||||
aLocalScopeIndex = 1, aDeletionFlag = null)
|
||||
{
|
||||
function makeChangesAndExitInputMode() {
|
||||
EventUtils.sendString(aNewValue);
|
||||
EventUtils.sendKey("RETURN");
|
||||
}
|
||||
|
||||
EventUtils.sendMouseEvent({ type: "dblclick" },
|
||||
aVar.querySelector(".name"),
|
||||
gDebugger);
|
||||
|
||||
executeSoon(function() {
|
||||
ok(aVar.querySelector(".element-name-input"),
|
||||
"There should be an input element created.");
|
||||
|
||||
let testContinued = false;
|
||||
let fetchedVariables = false;
|
||||
let fetchedExpressions = false;
|
||||
|
||||
let countV = 0;
|
||||
gDebugger.addEventListener("Debugger:FetchedVariables", function testV() {
|
||||
// We expect 2 Debugger:FetchedVariables events, one from the global
|
||||
// object scope and the regular one.
|
||||
if (++countV < 2) {
|
||||
info("Number of received Debugger:FetchedVariables events: " + countV);
|
||||
return;
|
||||
}
|
||||
gDebugger.removeEventListener("Debugger:FetchedVariables", testV, false);
|
||||
fetchedVariables = true;
|
||||
executeSoon(continueTest);
|
||||
}, false);
|
||||
|
||||
let countE = 0;
|
||||
gDebugger.addEventListener("Debugger:FetchedWatchExpressions", function testE() {
|
||||
// We expect only one Debugger:FetchedWatchExpressions event, since all
|
||||
// expressions are evaluated at the same time.
|
||||
if (++countE < 1) {
|
||||
info("Number of received Debugger:FetchedWatchExpressions events: " + countE);
|
||||
return;
|
||||
}
|
||||
gDebugger.removeEventListener("Debugger:FetchedWatchExpressions", testE, false);
|
||||
fetchedExpressions = true;
|
||||
executeSoon(continueTest);
|
||||
}, false);
|
||||
|
||||
function continueTest() {
|
||||
if (testContinued || !fetchedVariables || !fetchedExpressions) {
|
||||
return;
|
||||
}
|
||||
testContinued = true;
|
||||
|
||||
// Get the variable reference anew, since the old ones were discarded when
|
||||
// we resumed.
|
||||
var localScope = gDebugger.DebuggerView.Variables._list.querySelectorAll(".scope")[aLocalScopeIndex],
|
||||
localNodes = localScope.querySelector(".details").childNodes,
|
||||
aArg = localNodes[1];
|
||||
|
||||
is(aArg.querySelector(".value").getAttribute("value"), aArgResult,
|
||||
"Should have the right value for 'aArg'.");
|
||||
|
||||
let label = gDebugger.L10N.getStr("watchExpressionsScopeLabel");
|
||||
let scope = gVars._currHierarchy.get(label);
|
||||
info("Found the watch expressions scope: " + scope);
|
||||
|
||||
let aExp = scope.get(aVar.querySelector(".name").getAttribute("value"));
|
||||
info("Found the watch expression variable: " + aExp);
|
||||
|
||||
if (aDeletionFlag) {
|
||||
ok(fetchedVariables, "The variables should have been fetched.");
|
||||
ok(fetchedExpressions, "The variables should have been fetched.");
|
||||
is(aExp, undefined, "The watch expression should not have been found.");
|
||||
performCallback(scope);
|
||||
return;
|
||||
}
|
||||
|
||||
is(aExp.target.querySelector(".name").getAttribute("value"), aNewValue.trim(),
|
||||
"Should have the right name for '" + aNewValue + "'.");
|
||||
is(aExp.target.querySelector(".value").getAttribute("value"), aNewResult,
|
||||
"Should have the right value for '" + aNewValue + "'.");
|
||||
|
||||
performCallback(scope);
|
||||
}
|
||||
|
||||
makeChangesAndExitInputMode();
|
||||
});
|
||||
|
||||
function performCallback(scope) {
|
||||
executeSoon(function() {
|
||||
aTest(scope);
|
||||
aCallback(scope);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function testExprDeletion(aVar, aTest, aCallback, aArgResult,
|
||||
aLocalScopeIndex = 1, aFinalFlag = null)
|
||||
{
|
||||
let testContinued = false;
|
||||
let fetchedVariables = false;
|
||||
let fetchedExpressions = false;
|
||||
|
||||
let countV = 0;
|
||||
gDebugger.addEventListener("Debugger:FetchedVariables", function testV() {
|
||||
// We expect 2 Debugger:FetchedVariables events, one from the global
|
||||
// object scope and the regular one.
|
||||
if (++countV < 2) {
|
||||
info("Number of received Debugger:FetchedVariables events: " + countV);
|
||||
return;
|
||||
}
|
||||
gDebugger.removeEventListener("Debugger:FetchedVariables", testV, false);
|
||||
fetchedVariables = true;
|
||||
executeSoon(continueTest);
|
||||
}, false);
|
||||
|
||||
let countE = 0;
|
||||
gDebugger.addEventListener("Debugger:FetchedWatchExpressions", function testE() {
|
||||
// We expect only one Debugger:FetchedWatchExpressions event, since all
|
||||
// expressions are evaluated at the same time.
|
||||
if (++countE < 1) {
|
||||
info("Number of received Debugger:FetchedWatchExpressions events: " + countE);
|
||||
return;
|
||||
}
|
||||
gDebugger.removeEventListener("Debugger:FetchedWatchExpressions", testE, false);
|
||||
fetchedExpressions = true;
|
||||
executeSoon(continueTest);
|
||||
}, false);
|
||||
|
||||
function continueTest() {
|
||||
if ((testContinued || !fetchedVariables || !fetchedExpressions) && !aFinalFlag) {
|
||||
return;
|
||||
}
|
||||
testContinued = true;
|
||||
|
||||
// Get the variable reference anew, since the old ones were discarded when
|
||||
// we resumed.
|
||||
var localScope = gDebugger.DebuggerView.Variables._list.querySelectorAll(".scope")[aLocalScopeIndex],
|
||||
localNodes = localScope.querySelector(".details").childNodes,
|
||||
aArg = localNodes[1];
|
||||
|
||||
is(aArg.querySelector(".value").getAttribute("value"), aArgResult,
|
||||
"Should have the right value for 'aArg'.");
|
||||
|
||||
let label = gDebugger.L10N.getStr("watchExpressionsScopeLabel");
|
||||
let scope = gVars._currHierarchy.get(label);
|
||||
info("Found the watch expressions scope: " + scope);
|
||||
|
||||
if (aFinalFlag) {
|
||||
ok(fetchedVariables, "The variables should have been fetched.");
|
||||
ok(!fetchedExpressions, "The variables should never have been fetched.");
|
||||
is(scope, undefined, "The watch expressions scope should not have been found.");
|
||||
performCallback(scope);
|
||||
return;
|
||||
}
|
||||
|
||||
let aExp = scope.get(aVar.querySelector(".name").getAttribute("value"));
|
||||
info("Found the watch expression variable: " + aExp);
|
||||
|
||||
is(aExp, undefined, "Should not have found the watch expression after deletion.");
|
||||
performCallback(scope);
|
||||
}
|
||||
|
||||
function performCallback(scope) {
|
||||
executeSoon(function() {
|
||||
aTest(scope);
|
||||
aCallback(scope);
|
||||
});
|
||||
}
|
||||
|
||||
EventUtils.sendMouseEvent({ type: "click" },
|
||||
aVar.querySelector(".dbg-variables-delete"),
|
||||
gDebugger);
|
||||
}
|
||||
|
||||
function test1(scope) {
|
||||
is(gWatch._container._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,
|
||||
"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].target.inputNode.value, "document.title = 43",
|
||||
"The first textbox input value is not the correct one");
|
||||
is(gWatch._cache[0].attachment.expression, "document.title = 43",
|
||||
"The first textbox input value is not the correct one");
|
||||
is(gWatch._cache[1].target.inputNode.value, "document.title",
|
||||
"The second textbox input value is not the correct one");
|
||||
is(gWatch._cache[1].attachment.expression, "document.title",
|
||||
"The second textbox input value is not the correct one");
|
||||
is(gWatch._cache[2].target.inputNode.value, "aArg",
|
||||
"The third textbox input value is not the correct one");
|
||||
is(gWatch._cache[2].attachment.expression, "aArg",
|
||||
"The third textbox input value is not the correct one");
|
||||
is(gWatch._cache[3].target.inputNode.value, "ermahgerd",
|
||||
"The fourth textbox input value is not the correct one");
|
||||
is(gWatch._cache[3].attachment.expression, "ermahgerd",
|
||||
"The fourth textbox input value is not the correct one");
|
||||
is(gWatch._cache[4].target.inputNode.value, "this",
|
||||
"The fifth textbox input value is not the correct one");
|
||||
is(gWatch._cache[4].attachment.expression, "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,
|
||||
"There should be 5 hidden nodes in the watch expressions container");
|
||||
is(gWatch._container._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].target.inputNode.value, "document.title = 43",
|
||||
"The first textbox input value is not the correct one");
|
||||
is(gWatch._cache[0].attachment.expression, "document.title = 43",
|
||||
"The first textbox input value is not the correct one");
|
||||
is(gWatch._cache[1].target.inputNode.value, "document.title",
|
||||
"The second textbox input value is not the correct one");
|
||||
is(gWatch._cache[1].attachment.expression, "document.title",
|
||||
"The second textbox input value is not the correct one");
|
||||
is(gWatch._cache[2].target.inputNode.value, "aArg = 44",
|
||||
"The third textbox input value is not the correct one");
|
||||
is(gWatch._cache[2].attachment.expression, "aArg = 44",
|
||||
"The third textbox input value is not the correct one");
|
||||
is(gWatch._cache[3].target.inputNode.value, "ermahgerd",
|
||||
"The fourth textbox input value is not the correct one");
|
||||
is(gWatch._cache[3].attachment.expression, "ermahgerd",
|
||||
"The fourth textbox input value is not the correct one");
|
||||
is(gWatch._cache[4].target.inputNode.value, "this",
|
||||
"The fifth textbox input value is not the correct one");
|
||||
is(gWatch._cache[4].attachment.expression, "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,
|
||||
"There should be 4 hidden nodes in the watch expressions container");
|
||||
is(gWatch._container._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].target.inputNode.value, "document.title = 43",
|
||||
"The first textbox input value is not the correct one");
|
||||
is(gWatch._cache[0].attachment.expression, "document.title = 43",
|
||||
"The first textbox input value is not the correct one");
|
||||
is(gWatch._cache[1].target.inputNode.value, "document.title",
|
||||
"The second textbox input value is not the correct one");
|
||||
is(gWatch._cache[1].attachment.expression, "document.title",
|
||||
"The second textbox input value is not the correct one");
|
||||
is(gWatch._cache[2].target.inputNode.value, "ermahgerd",
|
||||
"The third textbox input value is not the correct one");
|
||||
is(gWatch._cache[2].attachment.expression, "ermahgerd",
|
||||
"The third textbox input value is not the correct one");
|
||||
is(gWatch._cache[3].target.inputNode.value, "this",
|
||||
"The fourth textbox input value is not the correct one");
|
||||
is(gWatch._cache[3].attachment.expression, "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,
|
||||
"There should be 3 hidden nodes in the watch expressions container");
|
||||
is(gWatch._container._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].target.inputNode.value, "document.title",
|
||||
"The first textbox input value is not the correct one");
|
||||
is(gWatch._cache[0].attachment.expression, "document.title",
|
||||
"The first textbox input value is not the correct one");
|
||||
is(gWatch._cache[1].target.inputNode.value, "ermahgerd",
|
||||
"The second textbox input value is not the correct one");
|
||||
is(gWatch._cache[1].attachment.expression, "ermahgerd",
|
||||
"The second textbox input value is not the correct one");
|
||||
is(gWatch._cache[2].target.inputNode.value, "this",
|
||||
"The third textbox input value is not the correct one");
|
||||
is(gWatch._cache[2].attachment.expression, "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,
|
||||
"There should be 2 hidden nodes in the watch expressions container");
|
||||
is(gWatch._container._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].target.inputNode.value, "ermahgerd",
|
||||
"The second textbox input value is not the correct one");
|
||||
is(gWatch._cache[0].attachment.expression, "ermahgerd",
|
||||
"The second textbox input value is not the correct one");
|
||||
is(gWatch._cache[1].target.inputNode.value, "this",
|
||||
"The third textbox input value is not the correct one");
|
||||
is(gWatch._cache[1].attachment.expression, "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,
|
||||
"There should be 1 hidden nodes in the watch expressions container");
|
||||
is(gWatch._container._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].target.inputNode.value, "ermahgerd",
|
||||
"The third textbox input value is not the correct one");
|
||||
is(gWatch._cache[0].attachment.expression, "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,
|
||||
"There should be 0 hidden nodes in the watch expressions container");
|
||||
is(gWatch._container._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.");
|
||||
}
|
||||
|
||||
function addWatchExpression(string) {
|
||||
gWatch.addExpression(string);
|
||||
gDebugger.editor.focus();
|
||||
}
|
||||
|
||||
function resumeAndFinish() {
|
||||
gDebugger.DebuggerController.activeThread.resume(function() {
|
||||
closeDebuggerAndFinish();
|
||||
});
|
||||
}
|
||||
|
||||
registerCleanupFunction(function() {
|
||||
removeTab(gTab);
|
||||
gPane = null;
|
||||
gTab = null;
|
||||
gDebuggee = null;
|
||||
gDebugger = null;
|
||||
gWatch = null;
|
||||
gVars = null;
|
||||
});
|
@ -4,6 +4,10 @@
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/
|
||||
*/
|
||||
|
||||
/**
|
||||
* Make sure that the editing variables or properties values works properly.
|
||||
*/
|
||||
|
||||
const TAB_URL = EXAMPLE_URL + "browser_dbg_frame-parameters.html";
|
||||
|
||||
var gPane = null;
|
||||
@ -70,7 +74,7 @@ function testModification(aVar, aCallback, aNewValue, aNewResult) {
|
||||
gDebugger);
|
||||
|
||||
executeSoon(function() {
|
||||
ok(aVar.querySelector(".element-input"),
|
||||
ok(aVar.querySelector(".element-value-input"),
|
||||
"There should be an input element created.");
|
||||
|
||||
let count = 0;
|
||||
|
@ -6,7 +6,8 @@
|
||||
<!-- Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ -->
|
||||
<script type="text/javascript">
|
||||
function ermahgerd() {
|
||||
function ermahgerd(aArg) {
|
||||
var t = document.title;
|
||||
debugger;
|
||||
(function() {
|
||||
var a = undefined;
|
||||
|
@ -20,7 +20,9 @@ this.EXPORTED_SYMBOLS = ["VariablesView", "create"];
|
||||
* Requires the devtools common.css and debugger.css skin stylesheets.
|
||||
*
|
||||
* To allow replacing variable or property values in this view, provide an
|
||||
* "eval" function property.
|
||||
* "eval" function property. To allow replacing variable or property values,
|
||||
* provide a "switch" function. To handle deleting variables or properties,
|
||||
* provide a "delete" function.
|
||||
*
|
||||
* @param nsIDOMNode aParentNode
|
||||
* The parent node to hold this view.
|
||||
@ -415,6 +417,8 @@ function Scope(aView, aName, aFlags = {}) {
|
||||
|
||||
this.ownerView = aView;
|
||||
this.eval = aView.eval;
|
||||
this.switch = aView.switch;
|
||||
this.delete = aView.delete;
|
||||
|
||||
this._store = new Map();
|
||||
this._init(aName.trim(), aFlags);
|
||||
@ -635,6 +639,24 @@ Scope.prototype = {
|
||||
*/
|
||||
set twisty(aFlag) aFlag ? this.showArrow() : this.hideArrow(),
|
||||
|
||||
/**
|
||||
* Specifies if editing variable or property names is allowed.
|
||||
* This flag applies non-recursively to the current scope.
|
||||
*/
|
||||
allowNameInput: false,
|
||||
|
||||
/**
|
||||
* Specifies if editing variable or property values is allowed.
|
||||
* This flag applies non-recursively to the current scope.
|
||||
*/
|
||||
allowValueInput: true,
|
||||
|
||||
/**
|
||||
* Specifies if removing variables or properties values is allowed.
|
||||
* This flag applies non-recursively to the current scope.
|
||||
*/
|
||||
allowDeletion: false,
|
||||
|
||||
/**
|
||||
* Gets the id associated with this item.
|
||||
* @return string
|
||||
@ -917,11 +939,14 @@ Scope.prototype = {
|
||||
* The variable's descriptor.
|
||||
*/
|
||||
function Variable(aScope, aName, aDescriptor) {
|
||||
this._onClose = this._onClose.bind(this);
|
||||
this._displayTooltip = this._displayTooltip.bind(this);
|
||||
this._activateInput = this._activateInput.bind(this);
|
||||
this._deactivateInput = this._deactivateInput.bind(this);
|
||||
this._saveInput = this._saveInput.bind(this);
|
||||
this._onInputKeyPress = this._onInputKeyPress.bind(this);
|
||||
this._activateNameInput = this._activateNameInput.bind(this);
|
||||
this._activateValueInput = this._activateValueInput.bind(this);
|
||||
this._deactivateNameInput = this._deactivateNameInput.bind(this);
|
||||
this._deactivateValueInput = this._deactivateValueInput.bind(this);
|
||||
this._onNameInputKeyPress = this._onNameInputKeyPress.bind(this);
|
||||
this._onValueInputKeyPress = this._onValueInputKeyPress.bind(this);
|
||||
|
||||
Scope.call(this, aScope, aName, aDescriptor);
|
||||
this._setGrip(aDescriptor.value);
|
||||
@ -1180,6 +1205,12 @@ create({ constructor: Variable, proto: Scope.prototype }, {
|
||||
separatorLabel.hidden = true;
|
||||
valueLabel.hidden = true;
|
||||
}
|
||||
if (this.ownerView.allowDeletion) {
|
||||
let closeNode = this._closeNode = document.createElement("toolbarbutton");
|
||||
closeNode.className = "dbg-variables-delete plain devtools-closebutton";
|
||||
closeNode.addEventListener("click", this._onClose, false);
|
||||
this._title.appendChild(closeNode);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
@ -1215,6 +1246,16 @@ create({ constructor: Variable, proto: Scope.prototype }, {
|
||||
|
||||
this._target.appendChild(tooltip);
|
||||
this._target.setAttribute("tooltip", tooltip.id);
|
||||
|
||||
if (this.ownerView.allowNameInput) {
|
||||
this._name.setAttribute("tooltiptext", L10N.getStr("variablesEditableNameTooltip"));
|
||||
}
|
||||
if (this.ownerView.allowValueInput) {
|
||||
this._valueLabel.setAttribute("tooltiptext", L10N.getStr("variablesEditableValueTooltip"));
|
||||
}
|
||||
if (this.ownerView.allowDeletion) {
|
||||
this._closeNode.setAttribute("tooltiptext", L10N.getStr("variablesCloseButtonTooltip"));
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
@ -1255,44 +1296,54 @@ create({ constructor: Variable, proto: Scope.prototype }, {
|
||||
_addEventListeners: function V__addEventListeners() {
|
||||
this._arrow.addEventListener("mousedown", this.toggle, false);
|
||||
this._name.addEventListener("mousedown", this.toggle, false);
|
||||
this._valueLabel.addEventListener("click", this._activateInput, false);
|
||||
this._name.addEventListener("dblclick", this._activateNameInput, false);
|
||||
this._valueLabel.addEventListener("click", this._activateValueInput, false);
|
||||
},
|
||||
|
||||
/**
|
||||
* Makes this variable's value editable.
|
||||
* The click listener for the close button.
|
||||
*/
|
||||
_activateInput: function V__activateInput(e) {
|
||||
if (!this.eval) {
|
||||
return;
|
||||
}
|
||||
let window = this.window;
|
||||
let document = this.document;
|
||||
_onClose: function V__onClose() {
|
||||
this.hide();
|
||||
|
||||
let title = this._title;
|
||||
let valueLabel = this._valueLabel;
|
||||
let initialString = this._valueLabel.getAttribute("value");
|
||||
if (this.delete) {
|
||||
this.delete(this);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Creates a textbox node in place of a label.
|
||||
*
|
||||
* @param nsIDOMNode aLabel
|
||||
* The label to be replaced with a textbox.
|
||||
* @param string aClassName
|
||||
* The class to be applied to the textbox.
|
||||
* @param object aCallbacks
|
||||
* An object containing the onKeypress and onBlur callbacks.
|
||||
*/
|
||||
_activateInput: function V__activateInput(aLabel, aClassName, aCallbacks) {
|
||||
let initialString = aLabel.getAttribute("value");
|
||||
|
||||
// Create a texbox input element which will be shown in the current
|
||||
// element's value location.
|
||||
// element's specified label location.
|
||||
let input = this.document.createElement("textbox");
|
||||
input.setAttribute("value", initialString);
|
||||
input.className = "plain element-input";
|
||||
input.className = "plain " + aClassName;
|
||||
input.width = this._target.clientWidth;
|
||||
|
||||
title.removeChild(valueLabel);
|
||||
title.appendChild(input);
|
||||
aLabel.parentNode.replaceChild(input, aLabel);
|
||||
input.select();
|
||||
|
||||
// When the value is a string (displayed as "value"), then we probably want
|
||||
// to change it to another string in the textbox, so to avoid typing the ""
|
||||
// again, tackle with the selection bounds just a bit.
|
||||
if (valueLabel.getAttribute("value").match(/^"[^"]*"$/)) {
|
||||
if (aLabel.getAttribute("value").match(/^"[^"]*"$/)) {
|
||||
input.selectionEnd--;
|
||||
input.selectionStart++;
|
||||
}
|
||||
|
||||
input.addEventListener("keypress", this._onInputKeyPress, false);
|
||||
input.addEventListener("blur", this._deactivateInput, false);
|
||||
input.addEventListener("keypress", aCallbacks.onKeypress, false);
|
||||
input.addEventListener("blur", aCallbacks.onBlur, false);
|
||||
|
||||
this._prevExpandable = this.twisty;
|
||||
this._prevExpanded = this.expanded;
|
||||
@ -1302,18 +1353,17 @@ create({ constructor: Variable, proto: Scope.prototype }, {
|
||||
},
|
||||
|
||||
/**
|
||||
* Deactivates this variable's editable mode.
|
||||
* Removes the textbox node in place of a label.
|
||||
*
|
||||
* @param nsIDOMNode aLabel
|
||||
* The label which was replaced with a textbox.
|
||||
* @param object aCallbacks
|
||||
* An object containing the onKeypress and onBlur callbacks.
|
||||
*/
|
||||
_deactivateInput: function V__deactivateInput(e) {
|
||||
let input = e.target;
|
||||
let title = this._title;
|
||||
let valueLabel = this._valueLabel;
|
||||
|
||||
title.removeChild(input);
|
||||
title.appendChild(valueLabel);
|
||||
|
||||
input.removeEventListener("keypress", this._onInputKeyPress, false);
|
||||
input.removeEventListener("blur", this._deactivateInput, false);
|
||||
_deactivateInput: function V__deactivateInput(aLabel, aInput, aCallbacks) {
|
||||
aInput.parentNode.replaceChild(aLabel, aInput);
|
||||
aInput.removeEventListener("keypress", aCallbacks.onKeypress, false);
|
||||
aInput.removeEventListener("blur", aCallbacks.onBlur, false);
|
||||
|
||||
this._locked = false;
|
||||
this.twisty = this._prevExpandable;
|
||||
@ -1321,37 +1371,123 @@ create({ constructor: Variable, proto: Scope.prototype }, {
|
||||
},
|
||||
|
||||
/**
|
||||
* Deactivates this variable's editable mode and evaluates a new value.
|
||||
* Makes this variable's name editable.
|
||||
*/
|
||||
_saveInput: function V__saveInput(e) {
|
||||
let input = e.target;
|
||||
let valueLabel = this._valueLabel;
|
||||
let initialString = this._valueLabel.getAttribute("value");
|
||||
let currentString = input.value;
|
||||
_activateNameInput: function V__activateNameInput() {
|
||||
if (!this.ownerView.allowNameInput || !this.switch) {
|
||||
return;
|
||||
}
|
||||
this._activateInput(this._name, "element-name-input", {
|
||||
onKeypress: this._onNameInputKeyPress,
|
||||
onBlur: this._deactivateNameInput
|
||||
});
|
||||
this._separatorLabel.hidden = true;
|
||||
this._valueLabel.hidden = true;
|
||||
},
|
||||
|
||||
this._deactivateInput(e);
|
||||
/**
|
||||
* Deactivates this variable's editable name mode.
|
||||
*/
|
||||
_deactivateNameInput: function V__deactivateNameInput(e) {
|
||||
this._deactivateInput(this._name, e.target, {
|
||||
onKeypress: this._onNameInputKeyPress,
|
||||
onBlur: this._deactivateNameInput
|
||||
});
|
||||
this._separatorLabel.hidden = false;
|
||||
this._valueLabel.hidden = false;
|
||||
},
|
||||
|
||||
/**
|
||||
* Makes this variable's value editable.
|
||||
*/
|
||||
_activateValueInput: function V__activateValueInput() {
|
||||
if (!this.ownerView.allowValueInput || !this.eval) {
|
||||
return;
|
||||
}
|
||||
this._activateInput(this._valueLabel, "element-value-input", {
|
||||
onKeypress: this._onValueInputKeyPress,
|
||||
onBlur: this._deactivateValueInput
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Deactivates this variable's editable value mode.
|
||||
*/
|
||||
_deactivateValueInput: function V__deactivateValueInput(e) {
|
||||
this._deactivateInput(this._valueLabel, e.target, {
|
||||
onKeypress: this._onValueInputKeyPress,
|
||||
onBlur: this._deactivateValueInput
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Disables this variable prior to a new name switch or value evaluation.
|
||||
*/
|
||||
_disable: function V__disable() {
|
||||
this.twisty = false;
|
||||
this._separatorLabel.hidden = true;
|
||||
this._valueLabel.hidden = true;
|
||||
this._enum.hidden = true;
|
||||
this._nonenum.hidden = true;
|
||||
},
|
||||
|
||||
/**
|
||||
* Deactivates this variable's editable mode and callbacks the new name.
|
||||
*/
|
||||
_saveNameInput: function V__saveNameInput(e) {
|
||||
let input = e.target;
|
||||
let initialString = this._name.getAttribute("value");
|
||||
let currentString = input.value.trim();
|
||||
this._deactivateNameInput(e);
|
||||
|
||||
if (initialString != currentString) {
|
||||
this._arrow.setAttribute("invisible", "");
|
||||
this._separatorLabel.hidden = true;
|
||||
this._valueLabel.hidden = true;
|
||||
this._enum.hidden = true;
|
||||
this._nonenum.hidden = true;
|
||||
this.eval("(" + this._symbolicName + "=" + currentString + ")");
|
||||
this._disable();
|
||||
this._name.value = currentString;
|
||||
this.switch(this, currentString);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* The key press listener for this variable's editable mode textbox.
|
||||
* Deactivates this variable's editable mode and evaluates the new value.
|
||||
*/
|
||||
_onInputKeyPress: function V__onInputKeyPress(e) {
|
||||
_saveValueInput: function V__saveValueInput(e) {
|
||||
let input = e.target;
|
||||
let initialString = this._valueLabel.getAttribute("value");
|
||||
let currentString = input.value.trim();
|
||||
this._deactivateValueInput(e);
|
||||
|
||||
if (initialString != currentString) {
|
||||
this._disable();
|
||||
this.eval(this._symbolicName + "=" + currentString);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* The key press listener for this variable's editable name textbox.
|
||||
*/
|
||||
_onNameInputKeyPress: function V__onNameInputKeyPress(e) {
|
||||
switch(e.keyCode) {
|
||||
case e.DOM_VK_RETURN:
|
||||
case e.DOM_VK_ENTER:
|
||||
this._saveInput(e);
|
||||
this._saveNameInput(e);
|
||||
return;
|
||||
case e.DOM_VK_ESCAPE:
|
||||
this._deactivateInput(e);
|
||||
this._deactivateNameInput(e);
|
||||
return;
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* The key press listener for this variable's editable value textbox.
|
||||
*/
|
||||
_onValueInputKeyPress: function V__onValueInputKeyPress(e) {
|
||||
switch(e.keyCode) {
|
||||
case e.DOM_VK_RETURN:
|
||||
case e.DOM_VK_ENTER:
|
||||
this._saveValueInput(e);
|
||||
return;
|
||||
case e.DOM_VK_ESCAPE:
|
||||
this._deactivateValueInput(e);
|
||||
return;
|
||||
}
|
||||
},
|
||||
@ -1361,6 +1497,7 @@ create({ constructor: Variable, proto: Scope.prototype }, {
|
||||
_initialDescriptor: null,
|
||||
_separatorLabel: null,
|
||||
_valueLabel: null,
|
||||
_closeNode: null,
|
||||
_tooltip: null,
|
||||
_valueGrip: null,
|
||||
_valueString: "",
|
||||
@ -1700,6 +1837,7 @@ XPCOMUtils.defineLazyGetter(L10N, "stringBundle", function() {
|
||||
|
||||
/**
|
||||
* The separator label between the variables or properties name and value.
|
||||
* This property applies non-recursively to the current scope.
|
||||
*/
|
||||
Scope.prototype.separator = L10N.getStr("variablesSeparatorLabel");
|
||||
|
||||
|
@ -173,6 +173,18 @@ watchExpressionsScopeLabel=Watch expressions
|
||||
# the global scope.
|
||||
globalScopeLabel=Global
|
||||
|
||||
# LOCALIZATION NOTE (variablesEditableNameTooltip): The text that is displayed
|
||||
# in the variables list on an item with an editable name.
|
||||
variablesEditableNameTooltip=Double click to edit
|
||||
|
||||
# LOCALIZATION NOTE (variablesEditableValueTooltip): The text that is displayed
|
||||
# in the variables list on an item with an editable name.
|
||||
variablesEditableValueTooltip=Click to change value
|
||||
|
||||
# LOCALIZATION NOTE (variablesCloseButtonTooltip): The text that is displayed
|
||||
# in the variables list on an item with which can be removed.
|
||||
variablesCloseButtonTooltip=Click to remove
|
||||
|
||||
# LOCALIZATION NOTE (variablesSeparatorLabel): The text that is displayed
|
||||
# in the variables list as a separator between the name and value.
|
||||
variablesSeparatorLabel=:
|
||||
|
@ -161,6 +161,10 @@
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.dbg-stackframe-details {
|
||||
-moz-padding-start: 4px;
|
||||
}
|
||||
|
||||
/**
|
||||
* Breakpoints view
|
||||
*/
|
||||
@ -209,10 +213,6 @@
|
||||
-moz-padding-start: 8px;
|
||||
}
|
||||
|
||||
.dbg-expression:last-child {
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
|
||||
.dbg-expression-arrow {
|
||||
width: 10px;
|
||||
height: auto;
|
||||
@ -236,6 +236,11 @@
|
||||
min-height: 10px;
|
||||
}
|
||||
|
||||
.dbg-variables-delete:not(:hover) {
|
||||
-moz-image-region: rect(0, 32px, 16px, 16px);
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
/**
|
||||
* Scope element
|
||||
*/
|
||||
@ -278,6 +283,7 @@
|
||||
|
||||
.variable > .title > .value {
|
||||
-moz-padding-start: 6px;
|
||||
-moz-padding-end: 4px;
|
||||
}
|
||||
|
||||
.variable:not([non-header]) > .details {
|
||||
@ -304,6 +310,7 @@
|
||||
|
||||
.property > .title > .value {
|
||||
-moz-padding-start: 6px;
|
||||
-moz-padding-end: 4px;
|
||||
}
|
||||
|
||||
.property:not([non-header]) > .details {
|
||||
@ -373,10 +380,16 @@
|
||||
* Variables and properties editing
|
||||
*/
|
||||
|
||||
#variables .element-input {
|
||||
#variables .element-value-input {
|
||||
-moz-margin-start: 5px !important;
|
||||
}
|
||||
|
||||
#variables .element-name-input {
|
||||
-moz-margin-start: -1px !important;
|
||||
color: #048;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
/**
|
||||
* Variables and properties searching
|
||||
*/
|
||||
|
@ -163,6 +163,10 @@
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.dbg-stackframe-details {
|
||||
-moz-padding-start: 4px;
|
||||
}
|
||||
|
||||
/**
|
||||
* Breakpoints view
|
||||
*/
|
||||
@ -211,10 +215,6 @@
|
||||
-moz-padding-start: 8px;
|
||||
}
|
||||
|
||||
.dbg-expression:last-child {
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
|
||||
.dbg-expression-arrow {
|
||||
width: 10px;
|
||||
height: auto;
|
||||
@ -238,6 +238,11 @@
|
||||
min-height: 10px;
|
||||
}
|
||||
|
||||
.dbg-variables-delete:not(:hover) {
|
||||
-moz-image-region: rect(0, 32px, 16px, 16px);
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
/**
|
||||
* Scope element
|
||||
*/
|
||||
@ -280,6 +285,7 @@
|
||||
|
||||
.variable > .title > .value {
|
||||
-moz-padding-start: 6px;
|
||||
-moz-padding-end: 4px;
|
||||
}
|
||||
|
||||
.variable:not([non-header]) > .details {
|
||||
@ -306,6 +312,7 @@
|
||||
|
||||
.property > .title > .value {
|
||||
-moz-padding-start: 6px;
|
||||
-moz-padding-end: 4px;
|
||||
}
|
||||
|
||||
.property:not([non-header]) > .details {
|
||||
@ -375,10 +382,16 @@
|
||||
* Variables and properties editing
|
||||
*/
|
||||
|
||||
#variables .element-input {
|
||||
#variables .element-value-input {
|
||||
-moz-margin-start: 5px !important;
|
||||
}
|
||||
|
||||
#variables .element-name-input {
|
||||
-moz-margin-start: -1px !important;
|
||||
color: #048;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
/**
|
||||
* Variables and properties searching
|
||||
*/
|
||||
|
@ -169,6 +169,10 @@
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.dbg-stackframe-details {
|
||||
-moz-padding-start: 4px;
|
||||
}
|
||||
|
||||
/**
|
||||
* Breakpoints view
|
||||
*/
|
||||
@ -217,10 +221,6 @@
|
||||
-moz-padding-start: 8px;
|
||||
}
|
||||
|
||||
.dbg-expression:last-child {
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
|
||||
.dbg-expression-arrow {
|
||||
width: 10px;
|
||||
height: auto;
|
||||
@ -244,6 +244,11 @@
|
||||
min-height: 10px;
|
||||
}
|
||||
|
||||
.dbg-variables-delete:not(:hover) {
|
||||
-moz-image-region: rect(0, 32px, 16px, 16px);
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
/**
|
||||
* Scope element
|
||||
*/
|
||||
@ -286,6 +291,7 @@
|
||||
|
||||
.variable > .title > .value {
|
||||
-moz-padding-start: 6px;
|
||||
-moz-padding-end: 4px;
|
||||
}
|
||||
|
||||
.variable:not([non-header]) > .details {
|
||||
@ -312,6 +318,7 @@
|
||||
|
||||
.property > .title > .value {
|
||||
-moz-padding-start: 6px;
|
||||
-moz-padding-end: 4px;
|
||||
}
|
||||
|
||||
.property:not([non-header]) > .details {
|
||||
@ -381,10 +388,16 @@
|
||||
* Variables and properties editing
|
||||
*/
|
||||
|
||||
#variables .element-input {
|
||||
#variables .element-value-input {
|
||||
-moz-margin-start: 5px !important;
|
||||
}
|
||||
|
||||
#variables .element-name-input {
|
||||
-moz-margin-start: -1px !important;
|
||||
color: #048;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
/**
|
||||
* Variables and properties searching
|
||||
*/
|
||||
|
Loading…
Reference in New Issue
Block a user