Bug 828664 - Debugger is sad when inspecting an array of > 10k elements in a variables view, r=rcampbell

This commit is contained in:
Victor Porof 2013-01-21 23:59:29 +02:00
parent f99c7e4d2c
commit 3e1128f45d
15 changed files with 761 additions and 245 deletions

View File

@ -15,6 +15,17 @@ const NEW_SCRIPT_DISPLAY_DELAY = 200; // ms
const FETCH_SOURCE_RESPONSE_DELAY = 50; // ms
const FRAME_STEP_CLEAR_DELAY = 100; // ms
const CALL_STACK_PAGE_SIZE = 25; // frames
const VARIABLES_VIEW_NON_SORTABLE = [
"Array",
"Int8Array",
"Uint8Array",
"Int16Array",
"Uint16Array",
"Int32Array",
"Uint32Array",
"Float32Array",
"Float64Array"
];
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
@ -50,7 +61,6 @@ let DebuggerController = {
return;
}
this._isInitialized = true;
window.removeEventListener("load", this._startupDebugger, true);
DebuggerView.initialize(function() {
@ -671,7 +681,7 @@ StackFrames.prototype = {
let label = this._getScopeLabel(environment);
let scope = DebuggerView.Variables.addScope(label);
// Special additions to the innermost scope.
// Handle additions to the innermost scope.
if (environment == frame.environment) {
this._insertScopeFrameReferences(scope, frame);
this._fetchScopeVariables(scope, environment);
@ -703,7 +713,7 @@ StackFrames.prototype = {
let callback = this._fetchScopeVariables.bind(this, aScope, aEnv);
// It's a good idea to be prepared in case of an expansion.
aScope.onmouseover = callback;
aScope.addEventListener("mouseover", callback, false);
// Make sure that variables are always available on expansion.
aScope.onexpand = callback;
},
@ -727,7 +737,7 @@ StackFrames.prototype = {
// Some variables are likely to contain a very large number of properties.
// It's a good idea to be prepared in case of an expansion.
if (aVar.name == "window" || aVar.name == "this") {
aVar.onmouseover = callback;
aVar.addEventListener("mouseover", callback, false);
}
// Make sure that properties are always available on expansion.
aVar.onexpand = callback;
@ -742,11 +752,11 @@ StackFrames.prototype = {
* The grip of the evaluation results.
*/
_fetchWatchExpressions: function SF__fetchWatchExpressions(aScope, aExp) {
// Retrieve the expressions only once.
if (aScope.fetched) {
// Fetch the expressions only once.
if (aScope._fetched) {
return;
}
aScope.fetched = true;
aScope._fetched = true;
// Add nodes for every watch expression in scope.
this.activeThread.pauseGrip(aExp).getPrototypeAndProperties(function(aResponse) {
@ -776,11 +786,11 @@ StackFrames.prototype = {
* The scope's environment.
*/
_fetchScopeVariables: function SF__fetchScopeVariables(aScope, aEnv) {
// Retrieve the variables only once.
if (aScope.fetched) {
// Fetch the variables only once.
if (aScope._fetched) {
return;
}
aScope.fetched = true;
aScope._fetched = true;
switch (aEnv.type) {
case "with":
@ -799,6 +809,10 @@ StackFrames.prototype = {
// Add nodes for every argument and every other variable in scope.
this._insertScopeArguments(aEnv.bindings.arguments, aScope);
this._insertScopeVariables(aEnv.bindings.variables, aScope);
// No need to signal that variables have been fetched, since
// the scope arguments and variables are already attached to the
// environment bindings, so pausing the active thread is unnecessary.
break;
default:
Cu.reportError("Unknown Debugger.Environment type: " + aEnv.type);
@ -861,11 +875,11 @@ StackFrames.prototype = {
}
let variableNames = Object.keys(aVariables);
// Sort all of the variables before adding them if preferred.
// Sort all of the variables before adding them, if preferred.
if (Prefs.variablesSortingEnabled) {
variableNames.sort();
}
// Add the sorted variables to the specified scope.
// Add the variables to the specified scope.
for (let name of variableNames) {
let varRef = aScope.addVar(name, aVariables[name]);
let varVal = aVariables[name].value;
@ -883,18 +897,19 @@ StackFrames.prototype = {
* The grip of the variable.
*/
_fetchVarProperties: function SF__fetchVarProperties(aVar, aGrip) {
// Retrieve the properties only once.
if (aVar.fetched) {
// Fetch the properties only once.
if (aVar._fetched) {
return;
}
aVar.fetched = true;
aVar._fetched = true;
this.activeThread.pauseGrip(aGrip).getPrototypeAndProperties(function(aResponse) {
let { ownProperties, prototype } = aResponse;
let sortable = VARIABLES_VIEW_NON_SORTABLE.indexOf(aGrip.class) == -1;
// Add all the variable properties.
if (ownProperties) {
aVar.addProperties(ownProperties);
aVar.addProperties(ownProperties, { sorted: sortable });
// Expansion handlers must be set after the properties are added.
for (let name in ownProperties) {
this._addVarExpander(aVar.get(name), ownProperties[name].value);
@ -908,6 +923,7 @@ StackFrames.prototype = {
this._addVarExpander(aVar.get("__proto__"), prototype);
}
// Mark the variable as having retrieved all its properties.
aVar._retrieved = true;
// Signal that properties have been fetched.

View File

@ -34,6 +34,7 @@ MOCHITEST_BROWSER_TESTS = \
browser_dbg_propertyview-10.js \
browser_dbg_propertyview-edit.js \
browser_dbg_propertyview-edit-watch.js \
browser_dbg_propertyview-big-data.js \
browser_dbg_propertyview-data.js \
browser_dbg_propertyview-filter-01.js \
browser_dbg_propertyview-filter-02.js \
@ -102,6 +103,7 @@ MOCHITEST_BROWSER_PAGES = \
browser_dbg_script-switching.html \
test-script-switching-01.js \
test-script-switching-02.js \
browser_dbg_big-data.html \
browser_dbg_frame-parameters.html \
browser_dbg_update-editor-mode.html \
test-editor-mode \

View File

@ -0,0 +1,27 @@
<!DOCTYPE HTML>
<html>
<head>
<meta charset='utf-8'/>
<title>Debugger Big Data Test</title>
<!-- Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ -->
<script type="text/javascript">
window.addEventListener("load", function() {
function test(aNumber) {
var buffer = new ArrayBuffer(aNumber);
var z = new Int8Array(buffer);
debugger;
};
function load() {
test(10000);
}
var button = document.querySelector("button");
button.addEventListener("click", load, false);
});
</script>
</head>
<body>
<button>Click me!</button>
</body>
</html>

View File

@ -25,27 +25,15 @@ function test()
function testFrameParameters()
{
dump("Started testFrameParameters!\n");
gDebugger.addEventListener("Debugger:FetchedVariables", function test() {
dump("Entered Debugger:FetchedVariables!\n");
gDebugger.removeEventListener("Debugger:FetchedVariables", test, false);
Services.tm.currentThread.dispatch({ run: function() {
dump("After currentThread.dispatch!\n");
var frames = gDebugger.DebuggerView.StackFrames._container._list,
childNodes = frames.childNodes,
localScope = gDebugger.DebuggerView.Variables._list.querySelector(".scope"),
localNodes = localScope.querySelector(".details").childNodes;
dump("Got our variables:\n");
dump("frames - " + frames.constructor + "\n");
dump("childNodes - " + childNodes.constructor + "\n");
dump("localScope - " + localScope.constructor + "\n");
dump("localNodes - " + localNodes.constructor + "\n");
is(gDebugger.DebuggerController.activeThread.state, "paused",
"Should only be getting stack frames while paused.");

View File

@ -25,27 +25,15 @@ function test()
function testFrameParameters()
{
dump("Started testFrameParameters!\n");
gDebugger.addEventListener("Debugger:FetchedVariables", function test() {
dump("Entered Debugger:FetchedVariables!\n");
gDebugger.removeEventListener("Debugger:FetchedVariables", test, false);
Services.tm.currentThread.dispatch({ run: function() {
dump("After currentThread.dispatch!\n");
var frames = gDebugger.DebuggerView.StackFrames._container._list,
localScope = gDebugger.DebuggerView.Variables._list.querySelectorAll(".scope")[0],
localNodes = localScope.querySelector(".details").childNodes,
localNonEnums = localScope.querySelector(".nonenum").childNodes;
dump("Got our variables:\n");
dump("frames - " + frames.constructor + "\n");
dump("localScope - " + localScope.constructor + "\n");
dump("localNodes - " + localNodes.constructor + "\n");
dump("localNonEnums - " + localNonEnums.constructor + "\n");
is(gDebugger.DebuggerController.activeThread.state, "paused",
"Should only be getting stack frames while paused.");
@ -57,23 +45,45 @@ function testFrameParameters()
is(localNodes[0].querySelector(".value").getAttribute("value"), "[object Proxy]",
"Should have the right property value for 'this'.");
is(localNodes[8].querySelector(".value").getAttribute("value"), "[object Arguments]",
"Should have the right property value for 'arguments'.");
is(localNodes[10].querySelector(".value").getAttribute("value"), "[object Object]",
"Should have the right property value for 'c'.");
let thisNode, argumentsNode, cNode;
for (let [id, scope] in gDebugger.DebuggerView.Variables) {
if (scope.target === localScope) {
for (let [name, variable] in scope) {
if (variable.target === localNodes[0]) {
thisNode = variable;
}
if (variable.target === localNodes[8]) {
argumentsNode = variable;
}
if (variable.target === localNodes[10]) {
cNode = variable;
}
}
}
}
let gVars = gDebugger.DebuggerView.Variables;
is(gVars.getScopeForNode(
gVars._list.querySelectorAll(".scope")[0]).target,
gVars._list.querySelectorAll(".scope")[0],
"getScopeForNode([0]) didn't return the expected scope.");
is(gVars.getScopeForNode(
gVars._list.querySelectorAll(".scope")[1]).target,
gVars._list.querySelectorAll(".scope")[1],
"getScopeForNode([1]) didn't return the expected scope.");
is(gVars.getScopeForNode(
gVars._list.querySelectorAll(".scope")[2]).target,
gVars._list.querySelectorAll(".scope")[2],
"getScopeForNode([2]) didn't return the expected scope.");
is(gVars.getScopeForNode(gVars._list.querySelectorAll(".scope")[0]).expanded, true,
"The local scope should be expanded by default.");
is(gVars.getScopeForNode(gVars._list.querySelectorAll(".scope")[1]).expanded, false,
"The block scope should be collapsed by default.");
is(gVars.getScopeForNode(gVars._list.querySelectorAll(".scope")[2]).expanded, false,
"The global scope should be collapsed by default.");
let thisNode = gVars.getVariableOrPropertyForNode(localNodes[0]);
let argumentsNode = gVars.getVariableOrPropertyForNode(localNodes[8]);
let cNode = gVars.getVariableOrPropertyForNode(localNodes[10]);
is(thisNode.expanded, false,
"The thisNode should not be expanded at this point.");
is(argumentsNode.expanded, false,
"The argumentsNode should not be expanded at this point.");
is(cNode.expanded, false,
"The cNode should not be expanded at this point.");
// Expand the 'this', 'arguments' and 'c' tree nodes. This causes
// their properties to be retrieved and displayed.
@ -81,6 +91,13 @@ function testFrameParameters()
argumentsNode.expand();
cNode.expand();
is(thisNode.expanded, true,
"The thisNode should be expanded at this point.");
is(argumentsNode.expanded, true,
"The argumentsNode should be expanded at this point.");
is(cNode.expanded, true,
"The cNode should be expanded at this point.");
// Poll every few milliseconds until the properties are retrieved.
// It's important to set the timer in the chrome window, because the
// content window timers are disabled while the debuggee is paused.
@ -98,52 +115,103 @@ function testFrameParameters()
return;
}
window.clearInterval(intervalID);
is(thisNode.target.querySelector(".property > .title > .name")
.getAttribute("value"), "InstallTrigger",
"Should have the right property name for InstallTrigger.");
ok(thisNode.target.querySelector(".property > .title > .value")
.getAttribute("value").search(/object/) == -1,
"InstallTrigger should not be an object.");
is(thisNode.target.querySelector(".value")
.getAttribute("value"), "[object Proxy]",
"Should have the right property value for 'this'.");
is(thisNode.get("window").target.querySelector(".name")
.getAttribute("value"), "window",
"Should have the right property name for 'window'.");
ok(thisNode.get("window").target.querySelector(".value")
.getAttribute("value").search(/object/) != -1,
"'window' should be an object.");
is(thisNode.get("document").target.querySelector(".name")
.getAttribute("value"), "document",
"Should have the right property name for 'document'.");
ok(thisNode.get("document").target.querySelector(".value")
.getAttribute("value").search(/object/) != -1,
"'document' should be an object.");
is(argumentsNode.target.querySelector(".value")
.getAttribute("value"), "[object Arguments]",
"Should have the right property value for 'arguments'.");
ok(argumentsNode.target.querySelector(".property > .title > .value")
.getAttribute("value").search(/object/) != -1,
"Arguments should be an object.");
.getAttribute("value"), "[object Arguments]",
"Should have the right property value for 'arguments'.");
is(argumentsNode.target.querySelectorAll(".property > .title > .name")[0]
.getAttribute("value"), "0",
"Should have the right property name for 'arguments[0]'.");
ok(argumentsNode.target.querySelectorAll(".property > .title > .value")[0]
.getAttribute("value").search(/object/) != -1,
"'arguments[0]' should be an object.");
is(argumentsNode.target.querySelectorAll(".property > .title > .name")[7]
.getAttribute("value"), "__proto__",
"Should have the right property name for '__proto__'.");
.getAttribute("value"), "__proto__",
"Should have the right property name for '__proto__'.");
ok(argumentsNode.target.querySelectorAll(".property > .title > .value")[7]
.getAttribute("value").search(/object/) != -1,
"__proto__ should be an object.");
.getAttribute("value").search(/object/) != -1,
"'__proto__' should be an object.");
is(cNode.target.querySelector(".value")
.getAttribute("value"), "[object Object]",
.getAttribute("value"), "[object Object]",
"Should have the right property value for 'c'.");
is(cNode.target.querySelectorAll(".property > .title > .name")[0]
.getAttribute("value"), "a",
.getAttribute("value"), "a",
"Should have the right property name for 'c.a'.");
is(cNode.target.querySelectorAll(".property > .title > .value")[0]
.getAttribute("value"), "1",
.getAttribute("value"), "1",
"Should have the right value for 'c.a'.");
is(cNode.target.querySelectorAll(".property > .title > .name")[1]
.getAttribute("value"), "b",
.getAttribute("value"), "b",
"Should have the right property name for 'c.b'.");
is(cNode.target.querySelectorAll(".property > .title > .value")[1]
.getAttribute("value"), "\"beta\"",
.getAttribute("value"), "\"beta\"",
"Should have the right value for 'c.b'.");
is(cNode.target.querySelectorAll(".property > .title > .name")[2]
.getAttribute("value"), "c",
.getAttribute("value"), "c",
"Should have the right property name for 'c.c'.");
is(cNode.target.querySelectorAll(".property > .title > .value")[2]
.getAttribute("value"), "true",
.getAttribute("value"), "true",
"Should have the right value for 'c.c'.");
is(gVars.getVariableOrPropertyForNode(
cNode.target.querySelectorAll(".property")[0]).target,
cNode.target.querySelectorAll(".property")[0],
"getVariableOrPropertyForNode([0]) didn't return the expected property.");
is(gVars.getVariableOrPropertyForNode(
cNode.target.querySelectorAll(".property")[1]).target,
cNode.target.querySelectorAll(".property")[1],
"getVariableOrPropertyForNode([1]) didn't return the expected property.");
is(gVars.getVariableOrPropertyForNode(
cNode.target.querySelectorAll(".property")[2]).target,
cNode.target.querySelectorAll(".property")[2],
"getVariableOrPropertyForNode([2]) didn't return the expected property.");
is(cNode.find(
cNode.target.querySelectorAll(".property")[0]).target,
cNode.target.querySelectorAll(".property")[0],
"find([0]) didn't return the expected property.");
is(cNode.find(
cNode.target.querySelectorAll(".property")[1]).target,
cNode.target.querySelectorAll(".property")[1],
"find([1]) didn't return the expected property.");
is(cNode.find(
cNode.target.querySelectorAll(".property")[2]).target,
cNode.target.querySelectorAll(".property")[2],
"find([2]) didn't return the expected property.");
resumeAndFinish();
}, 100);
}}, 0);

View File

@ -0,0 +1,143 @@
/* vim:set ts=2 sw=2 sts=2 et: */
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Make sure that the property view remains responsive when faced with
* huge ammounts of data.
*/
const TAB_URL = EXAMPLE_URL + "browser_dbg_big-data.html";
var gPane = null;
var gTab = null;
var gDebugger = null;
requestLongerTimeout(10);
function test()
{
debug_tab_pane(TAB_URL, function(aTab, aDebuggee, aPane) {
gTab = aTab;
gPane = aPane;
gDebugger = gPane.panelWin;
gDebugger.DebuggerController.StackFrames.autoScopeExpand = true;
gDebugger.DebuggerView.Variables.nonEnumVisible = false;
gDebugger.DebuggerView.Variables.lazyAppend = true;
testWithFrame();
});
}
function testWithFrame()
{
let count = 0;
gDebugger.addEventListener("Debugger:FetchedVariables", function test1() {
// We expect 2 Debugger:FetchedVariables events, one from the global object
// scope and the regular one.
if (++count < 2) {
info("Number of received Debugger:FetchedVariables events: " + count);
return;
}
gDebugger.removeEventListener("Debugger:FetchedVariables", test1, false);
Services.tm.currentThread.dispatch({ run: function() {
var scopes = gDebugger.DebuggerView.Variables._list,
innerScope = scopes.querySelectorAll(".scope")[0],
loadScope = scopes.querySelectorAll(".scope")[1],
globalScope = scopes.querySelectorAll(".scope")[2],
innerNodes = innerScope.querySelector(".details").childNodes,
arrayNodes = innerNodes[4].querySelector(".details").childNodes;
is(innerNodes[3].querySelector(".name").getAttribute("value"), "buffer",
"Should have the right property name for |buffer|.");
is(innerNodes[3].querySelector(".value").getAttribute("value"), "[object ArrayBuffer]",
"Should have the right property value for |buffer|.");
is(innerNodes[4].querySelector(".name").getAttribute("value"), "z",
"Should have the right property name for |z|.");
is(innerNodes[4].querySelector(".value").getAttribute("value"), "[object Int8Array]",
"Should have the right property value for |z|.");
EventUtils.sendMouseEvent({ type: "mousedown" }, innerNodes[3].querySelector(".arrow"), gDebugger);
EventUtils.sendMouseEvent({ type: "mousedown" }, innerNodes[4].querySelector(".arrow"), gDebugger);
gDebugger.addEventListener("Debugger:FetchedProperties", function test2() {
gDebugger.removeEventListener("Debugger:FetchedProperties", test2, false);
Services.tm.currentThread.dispatch({ run: function() {
let total = 10000;
let loaded = 0;
let paints = 0;
waitForProperties(total, {
onLoading: function(count) {
ok(count >= loaded, "Should have loaded more properties.");
info("Displayed " + count + " properties, not finished yet.");
info("Remaining " + (total - count) + " properties to display.");
loaded = count;
paints++;
loadScope.hidden = true;
globalScope.hidden = true;
scopes.parentNode.scrollTop = scopes.parentNode.scrollHeight;
},
onFinished: function(count) {
ok(count == total, "Displayed all the properties.");
isnot(paints, 0, "Debugger was unresponsive, sad panda.");
for (let i = 0; i < arrayNodes.length; i++) {
let node = arrayNodes[i];
let name = node.querySelector(".name").getAttribute("value");
is(name, i + "", "The array items aren't in the correct order.");
}
closeDebuggerAndFinish();
}
});
}}, 0);
}, false);
}}, 0);
}, false);
EventUtils.sendMouseEvent({ type: "click" },
content.document.querySelector("button"),
content.window);
}
function waitForProperties(total, callbacks)
{
var scopes = gDebugger.DebuggerView.Variables._list,
innerScope = scopes.querySelectorAll(".scope")[0],
innerNodes = innerScope.querySelector(".details").childNodes,
arrayNodes = innerNodes[4].querySelector(".details").childNodes;
// Poll every few milliseconds until the properties are retrieved.
let count = 0;
let intervalID = window.setInterval(function() {
info("count: " + count + " ");
if (++count > total) {
ok(false, "Timed out while polling for the properties.");
window.clearInterval(intervalID);
return closeDebuggerAndFinish();
}
// Still need to wait for a few more properties to be fetched.
if (arrayNodes.length < total) {
callbacks.onLoading(arrayNodes.length);
return;
}
// We got all the properties, it's safe to callback.
window.clearInterval(intervalID);
callbacks.onFinished(arrayNodes.length);
}, 100);
}
registerCleanupFunction(function() {
removeTab(gTab);
gPane = null;
gTab = null;
gDebugger = null;
});

View File

@ -78,7 +78,7 @@ function testHierarchy() {
"There should be 1 scope, 1 var, 1 proto, 8 props, 1 getter and 1 setter.");
gScope = gVariablesView._currHierarchy.get("");
gVariable = gVariablesView._currHierarchy.get(".");
gVariable = gVariablesView._currHierarchy.get("[\"\"]");
is(gVariablesView._store.size, 1,
"There should be only one scope in the view");

View File

@ -70,7 +70,7 @@ function testFrameEval() {
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,
is(scope.get("this").target.querySelectorAll(".dbg-variable-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'.");
@ -81,7 +81,7 @@ function testFrameEval() {
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,
is(scope.get("ermahgerd").target.querySelectorAll(".dbg-variable-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'.");
@ -92,7 +92,7 @@ function testFrameEval() {
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,
is(scope.get("aArg").target.querySelectorAll(".dbg-variable-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'.");
@ -101,7 +101,7 @@ function testFrameEval() {
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,
is(scope.get("document.title").target.querySelectorAll(".dbg-variable-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'.");
@ -112,7 +112,7 @@ function testFrameEval() {
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,
is(scope.get("document.title = 42").target.querySelectorAll(".dbg-variable-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'.");
@ -325,7 +325,7 @@ function testExprDeletion(aVar, aTest, aCallback, aArgResult,
}
EventUtils.sendMouseEvent({ type: "click" },
aVar.querySelector(".dbg-variables-delete"),
aVar.querySelector(".dbg-variable-delete"),
gDebugger);
}

View File

@ -38,7 +38,7 @@ function testSearchbox()
ok(!gDebugger.DebuggerView.Variables._parent.parentNode.querySelector(".variables-searchinput.devtools-searchinput"),
"The searchbox element should not be found.");
gDebugger.DebuggerView.Variables.enableSearch();
gDebugger.DebuggerView.Variables._enableSearch();
ok(gDebugger.DebuggerView.Variables._searchboxNode,
"There should be a searchbox available after enabling.");
ok(gDebugger.DebuggerView.Variables._searchboxContainer.hidden,
@ -47,13 +47,13 @@ function testSearchbox()
"The searchbox element should be found.");
gDebugger.DebuggerView.Variables.disableSearch();
gDebugger.DebuggerView.Variables._disableSearch();
ok(!gDebugger.DebuggerView.Variables._searchboxNode,
"There shouldn't be a searchbox available after disabling.");
ok(!gDebugger.DebuggerView.Variables._parent.parentNode.querySelector(".variables-searchinput.devtools-searchinput"),
"The searchbox element should not be found.");
gDebugger.DebuggerView.Variables.enableSearch();
gDebugger.DebuggerView.Variables._enableSearch();
ok(gDebugger.DebuggerView.Variables._searchboxNode,
"There should be a searchbox available after enabling.");
ok(gDebugger.DebuggerView.Variables._searchboxContainer.hidden,
@ -61,20 +61,24 @@ function testSearchbox()
ok(gDebugger.DebuggerView.Variables._parent.parentNode.querySelector(".variables-searchinput.devtools-searchinput"),
"The searchbox element should be found.");
let placeholder = "freshly squeezed mango juice";
gDebugger.DebuggerView.Variables.searchPlaceholder = placeholder;
is(gDebugger.DebuggerView.Variables.searchPlaceholder, placeholder,
"The placeholder getter didn't return the expected string");
ok(gDebugger.DebuggerView.Variables._searchboxNode.getAttribute("placeholder"),
placeholder, "There correct placeholder should be applied to the searchbox.");
gDebugger.DebuggerView.Variables.disableSearch();
gDebugger.DebuggerView.Variables._disableSearch();
ok(!gDebugger.DebuggerView.Variables._searchboxNode,
"There shouldn't be a searchbox available after disabling again.");
ok(!gDebugger.DebuggerView.Variables._parent.parentNode.querySelector(".variables-searchinput.devtools-searchinput"),
"The searchbox element should not be found.");
gDebugger.DebuggerView.Variables.enableSearch();
gDebugger.DebuggerView.Variables._enableSearch();
ok(gDebugger.DebuggerView.Variables._searchboxNode,
"There should be a searchbox available after enabling again.");
ok(gDebugger.DebuggerView.Variables._searchboxContainer.hidden,

View File

@ -38,7 +38,7 @@ function testSearchbox()
ok(!gDebugger.DebuggerView.Variables._parent.parentNode.querySelector(".variables-searchinput.devtools-searchinput"),
"The searchbox element should not be found.");
gDebugger.DebuggerView.Variables.enableSearch();
gDebugger.DebuggerView.Variables._enableSearch();
ok(gDebugger.DebuggerView.Variables._searchboxNode,
"There should be a searchbox available after enabling.");
ok(gDebugger.DebuggerView.Variables._parent.parentNode.querySelector(".variables-searchinput.devtools-searchinput"),

View File

@ -183,6 +183,7 @@ function debug_tab_pane(aURL, aOnDebugging) {
// Wait for the initial resume...
dbg.panelWin.gClient.addOneTimeListener("resumed", function() {
dbg._view.Variables.lazyEmpty = false;
dbg._view.Variables.lazyAppend = false;
aOnDebugging(tab, debuggee, dbg);
});
});
@ -205,6 +206,7 @@ function debug_remote(aURL, aOnDebugging, aBeforeTabAdded) {
// Wait for the initial resume...
win.panelWin.gClient.addOneTimeListener("resumed", function() {
win._dbgwin.DebuggerView.Variables.lazyEmpty = false;
win._dbgwin.DebuggerView.Variables.lazyAppend = false;
aOnDebugging(tab, debuggee, win);
});
}, true);

File diff suppressed because it is too large Load Diff

View File

@ -289,11 +289,17 @@
min-height: 10px;
}
.dbg-variables-delete:not(:hover) {
.dbg-variable-delete:not(:hover) {
-moz-image-region: rect(0, 32px, 16px, 16px);
opacity: 0.5;
}
.dbg-variable-throbber {
background: url("chrome://global/skin/icons/loading_16.png");
width: 16px;
height: 16px;
}
/**
* Scope element
*/

View File

@ -291,11 +291,17 @@
min-height: 10px;
}
.dbg-variables-delete:not(:hover) {
.dbg-variable-delete:not(:hover) {
-moz-image-region: rect(0, 32px, 16px, 16px);
opacity: 0.5;
}
.dbg-variable-throbber {
background: url("chrome://global/skin/icons/loading_16.png");
width: 16px;
height: 16px;
}
/**
* Scope element
*/

View File

@ -297,11 +297,17 @@
min-height: 10px;
}
.dbg-variables-delete:not(:hover) {
.dbg-variable-delete:not(:hover) {
-moz-image-region: rect(0, 32px, 16px, 16px);
opacity: 0.5;
}
.dbg-variable-throbber {
background: url("chrome://global/skin/icons/loading_16.png");
width: 16px;
height: 16px;
}
/**
* Scope element
*/