mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 830344 - Part 2: Implement pagination when expanding objects with lots of properties, r=past
This commit is contained in:
parent
ad354ac150
commit
d6f26d3a74
@ -61,7 +61,7 @@ function performTest() {
|
||||
gVariablesView.switch = function() {};
|
||||
gVariablesView.delete = function() {};
|
||||
gVariablesView.rawObject = test;
|
||||
gVariablesView.pageSize = 5;
|
||||
gVariablesView.scrollPageSize = 5;
|
||||
|
||||
return Task.spawn(function() {
|
||||
yield waitForTick();
|
||||
|
@ -9,7 +9,7 @@
|
||||
const TAB_URL = EXAMPLE_URL + "doc_large-array-buffer.html";
|
||||
|
||||
let gTab, gDebuggee, gPanel, gDebugger;
|
||||
let gVariables;
|
||||
let gVariables, gEllipsis;
|
||||
|
||||
function test() {
|
||||
initDebugger(TAB_URL).then(([aTab, aDebuggee, aPanel]) => {
|
||||
@ -18,9 +18,12 @@ function test() {
|
||||
gPanel = aPanel;
|
||||
gDebugger = gPanel.panelWin;
|
||||
gVariables = gDebugger.DebuggerView.Variables;
|
||||
gEllipsis = Services.prefs.getComplexValue("intl.ellipsis", Ci.nsIPrefLocalizedString).data;
|
||||
|
||||
waitForSourceAndCaretAndScopes(gPanel, ".html", 18)
|
||||
.then(() => performTest())
|
||||
waitForSourceAndCaretAndScopes(gPanel, ".html", 23)
|
||||
.then(() => initialChecks())
|
||||
.then(() => verifyFirstLevel())
|
||||
.then(() => verifyNextLevels())
|
||||
.then(() => resumeDebuggerThenCloseAndFinish(gPanel))
|
||||
.then(null, aError => {
|
||||
ok(false, "Got an error: " + aError.message + "\n" + aError.stack);
|
||||
@ -32,8 +35,202 @@ function test() {
|
||||
});
|
||||
}
|
||||
|
||||
function performTest() {
|
||||
function initialChecks() {
|
||||
let localScope = gVariables.getScopeAtIndex(0);
|
||||
let bufferVar = localScope.get("buffer");
|
||||
let arrayVar = localScope.get("largeArray");
|
||||
let objectVar = localScope.get("largeObject");
|
||||
|
||||
ok(bufferVar, "There should be a 'buffer' variable present in the scope.");
|
||||
ok(arrayVar, "There should be a 'largeArray' variable present in the scope.");
|
||||
ok(objectVar, "There should be a 'largeObject' variable present in the scope.");
|
||||
|
||||
is(bufferVar.target.querySelector(".name").getAttribute("value"), "buffer",
|
||||
"Should have the right property name for 'buffer'.");
|
||||
is(bufferVar.target.querySelector(".value").getAttribute("value"), "ArrayBuffer",
|
||||
"Should have the right property value for 'buffer'.");
|
||||
ok(bufferVar.target.querySelector(".value").className.contains("token-other"),
|
||||
"Should have the right token class for 'buffer'.");
|
||||
|
||||
is(arrayVar.target.querySelector(".name").getAttribute("value"), "largeArray",
|
||||
"Should have the right property name for 'largeArray'.");
|
||||
is(arrayVar.target.querySelector(".value").getAttribute("value"), "Int8Array",
|
||||
"Should have the right property value for 'largeArray'.");
|
||||
ok(arrayVar.target.querySelector(".value").className.contains("token-other"),
|
||||
"Should have the right token class for 'largeArray'.");
|
||||
|
||||
is(objectVar.target.querySelector(".name").getAttribute("value"), "largeObject",
|
||||
"Should have the right property name for 'largeObject'.");
|
||||
is(objectVar.target.querySelector(".value").getAttribute("value"), "Object",
|
||||
"Should have the right property value for 'largeObject'.");
|
||||
ok(objectVar.target.querySelector(".value").className.contains("token-other"),
|
||||
"Should have the right token class for 'largeObject'.");
|
||||
|
||||
is(bufferVar.expanded, false,
|
||||
"The 'buffer' variable shouldn't be expanded.");
|
||||
is(arrayVar.expanded, false,
|
||||
"The 'largeArray' variable shouldn't be expanded.");
|
||||
is(objectVar.expanded, false,
|
||||
"The 'largeObject' variable shouldn't be expanded.");
|
||||
|
||||
let finished = waitForDebuggerEvents(gPanel, gDebugger.EVENTS.FETCHED_PROPERTIES, 2);
|
||||
arrayVar.expand();
|
||||
objectVar.expand();
|
||||
return finished;
|
||||
}
|
||||
|
||||
function verifyFirstLevel() {
|
||||
let localScope = gVariables.getScopeAtIndex(0);
|
||||
let arrayVar = localScope.get("largeArray");
|
||||
let objectVar = localScope.get("largeObject");
|
||||
|
||||
let arrayEnums = arrayVar.target.querySelector(".variables-view-element-details.enum").childNodes;
|
||||
let arrayNonEnums = arrayVar.target.querySelector(".variables-view-element-details.nonenum").childNodes;
|
||||
is(arrayEnums.length, 0,
|
||||
"The 'largeArray' shouldn't contain any enumerable elements.");
|
||||
is(arrayNonEnums.length, 9,
|
||||
"The 'largeArray' should contain all the created non-enumerable elements.");
|
||||
|
||||
let objectEnums = objectVar.target.querySelector(".variables-view-element-details.enum").childNodes;
|
||||
let objectNonEnums = objectVar.target.querySelector(".variables-view-element-details.nonenum").childNodes;
|
||||
is(objectEnums.length, 0,
|
||||
"The 'largeObject' shouldn't contain any enumerable elements.");
|
||||
is(objectNonEnums.length, 5,
|
||||
"The 'largeObject' should contain all the created non-enumerable elements.");
|
||||
|
||||
is(arrayVar.target.querySelectorAll(".variables-view-property .name")[0].getAttribute("value"),
|
||||
0 + gEllipsis + 1999, "The first page in the 'largeArray' is named correctly.");
|
||||
is(arrayVar.target.querySelectorAll(".variables-view-property .value")[0].getAttribute("value"),
|
||||
"", "The first page in the 'largeArray' should not have a corresponding value.");
|
||||
is(arrayVar.target.querySelectorAll(".variables-view-property .name")[1].getAttribute("value"),
|
||||
2000 + gEllipsis + 3999, "The second page in the 'largeArray' is named correctly.");
|
||||
is(arrayVar.target.querySelectorAll(".variables-view-property .value")[1].getAttribute("value"),
|
||||
"", "The second page in the 'largeArray' should not have a corresponding value.");
|
||||
is(arrayVar.target.querySelectorAll(".variables-view-property .name")[2].getAttribute("value"),
|
||||
4000 + gEllipsis + 5999, "The third page in the 'largeArray' is named correctly.");
|
||||
is(arrayVar.target.querySelectorAll(".variables-view-property .value")[2].getAttribute("value"),
|
||||
"", "The third page in the 'largeArray' should not have a corresponding value.");
|
||||
is(arrayVar.target.querySelectorAll(".variables-view-property .name")[3].getAttribute("value"),
|
||||
6000 + gEllipsis + 9999, "The fourth page in the 'largeArray' is named correctly.");
|
||||
is(arrayVar.target.querySelectorAll(".variables-view-property .value")[3].getAttribute("value"),
|
||||
"", "The fourth page in the 'largeArray' should not have a corresponding value.");
|
||||
|
||||
is(objectVar.target.querySelectorAll(".variables-view-property .name")[0].getAttribute("value"),
|
||||
0 + gEllipsis + 1999, "The first page in the 'largeObject' is named correctly.");
|
||||
is(objectVar.target.querySelectorAll(".variables-view-property .value")[0].getAttribute("value"),
|
||||
"", "The first page in the 'largeObject' should not have a corresponding value.");
|
||||
is(objectVar.target.querySelectorAll(".variables-view-property .name")[1].getAttribute("value"),
|
||||
2000 + gEllipsis + 3999, "The second page in the 'largeObject' is named correctly.");
|
||||
is(objectVar.target.querySelectorAll(".variables-view-property .value")[1].getAttribute("value"),
|
||||
"", "The second page in the 'largeObject' should not have a corresponding value.");
|
||||
is(objectVar.target.querySelectorAll(".variables-view-property .name")[2].getAttribute("value"),
|
||||
4000 + gEllipsis + 5999, "The thrid page in the 'largeObject' is named correctly.");
|
||||
is(objectVar.target.querySelectorAll(".variables-view-property .value")[2].getAttribute("value"),
|
||||
"", "The thrid page in the 'largeObject' should not have a corresponding value.");
|
||||
is(objectVar.target.querySelectorAll(".variables-view-property .name")[3].getAttribute("value"),
|
||||
6000 + gEllipsis + 9999, "The fourth page in the 'largeObject' is named correctly.");
|
||||
is(objectVar.target.querySelectorAll(".variables-view-property .value")[3].getAttribute("value"),
|
||||
"", "The fourth page in the 'largeObject' should not have a corresponding value.");
|
||||
|
||||
is(arrayVar.target.querySelectorAll(".variables-view-property .name")[4].getAttribute("value"),
|
||||
"length", "The other properties 'largeArray' are named correctly.");
|
||||
is(arrayVar.target.querySelectorAll(".variables-view-property .value")[4].getAttribute("value"),
|
||||
"10000", "The other properties 'largeArray' have the correct value.");
|
||||
is(arrayVar.target.querySelectorAll(".variables-view-property .name")[5].getAttribute("value"),
|
||||
"buffer", "The other properties 'largeArray' are named correctly.");
|
||||
is(arrayVar.target.querySelectorAll(".variables-view-property .value")[5].getAttribute("value"),
|
||||
"ArrayBuffer", "The other properties 'largeArray' have the correct value.");
|
||||
is(arrayVar.target.querySelectorAll(".variables-view-property .name")[6].getAttribute("value"),
|
||||
"byteLength", "The other properties 'largeArray' are named correctly.");
|
||||
is(arrayVar.target.querySelectorAll(".variables-view-property .value")[6].getAttribute("value"),
|
||||
"10000", "The other properties 'largeArray' have the correct value.");
|
||||
is(arrayVar.target.querySelectorAll(".variables-view-property .name")[7].getAttribute("value"),
|
||||
"byteOffset", "The other properties 'largeArray' are named correctly.");
|
||||
is(arrayVar.target.querySelectorAll(".variables-view-property .value")[7].getAttribute("value"),
|
||||
"0", "The other properties 'largeArray' have the correct value.");
|
||||
is(arrayVar.target.querySelectorAll(".variables-view-property .name")[8].getAttribute("value"),
|
||||
"__proto__", "The other properties 'largeArray' are named correctly.");
|
||||
is(arrayVar.target.querySelectorAll(".variables-view-property .value")[8].getAttribute("value"),
|
||||
"Int8ArrayPrototype", "The other properties 'largeArray' have the correct value.");
|
||||
|
||||
is(objectVar.target.querySelectorAll(".variables-view-property .name")[4].getAttribute("value"),
|
||||
"__proto__", "The other properties 'largeObject' are named correctly.");
|
||||
is(objectVar.target.querySelectorAll(".variables-view-property .value")[4].getAttribute("value"),
|
||||
"Object", "The other properties 'largeObject' have the correct value.");
|
||||
}
|
||||
|
||||
function verifyNextLevels() {
|
||||
let localScope = gVariables.getScopeAtIndex(0);
|
||||
let objectVar = localScope.get("largeObject");
|
||||
|
||||
let lastPage1 = objectVar.get(6000 + gEllipsis + 9999);
|
||||
ok(lastPage1, "The last page in the first level was retrieved successfully.");
|
||||
lastPage1.expand();
|
||||
|
||||
let pageEnums1 = lastPage1.target.querySelector(".variables-view-element-details.enum").childNodes;
|
||||
let pageNonEnums1 = lastPage1.target.querySelector(".variables-view-element-details.nonenum").childNodes;
|
||||
is(pageEnums1.length, 0,
|
||||
"The last page in the first level shouldn't contain any enumerable elements.");
|
||||
is(pageNonEnums1.length, 4,
|
||||
"The last page in the first level should contain all the created non-enumerable elements.");
|
||||
|
||||
is(lastPage1._nonenum.querySelectorAll(".variables-view-property .name")[0].getAttribute("value"),
|
||||
6000 + gEllipsis + 6999, "The first page in this level named correctly (1).");
|
||||
is(lastPage1._nonenum.querySelectorAll(".variables-view-property .name")[1].getAttribute("value"),
|
||||
7000 + gEllipsis + 7999, "The second page in this level named correctly (1).");
|
||||
is(lastPage1._nonenum.querySelectorAll(".variables-view-property .name")[2].getAttribute("value"),
|
||||
8000 + gEllipsis + 8999, "The third page in this level named correctly (1).");
|
||||
is(lastPage1._nonenum.querySelectorAll(".variables-view-property .name")[3].getAttribute("value"),
|
||||
9000 + gEllipsis + 9999, "The fourth page in this level named correctly (1).");
|
||||
|
||||
let lastPage2 = lastPage1.get(9000 + gEllipsis + 9999);
|
||||
ok(lastPage2, "The last page in the second level was retrieved successfully.");
|
||||
lastPage2.expand();
|
||||
|
||||
let pageEnums2 = lastPage2.target.querySelector(".variables-view-element-details.enum").childNodes;
|
||||
let pageNonEnums2 = lastPage2.target.querySelector(".variables-view-element-details.nonenum").childNodes;
|
||||
is(pageEnums2.length, 0,
|
||||
"The last page in the second level shouldn't contain any enumerable elements.");
|
||||
is(pageNonEnums2.length, 4,
|
||||
"The last page in the second level should contain all the created non-enumerable elements.");
|
||||
|
||||
is(lastPage2._nonenum.querySelectorAll(".variables-view-property .name")[0].getAttribute("value"),
|
||||
9000 + gEllipsis + 9199, "The first page in this level named correctly (2).");
|
||||
is(lastPage2._nonenum.querySelectorAll(".variables-view-property .name")[1].getAttribute("value"),
|
||||
9200 + gEllipsis + 9399, "The second page in this level named correctly (2).");
|
||||
is(lastPage2._nonenum.querySelectorAll(".variables-view-property .name")[2].getAttribute("value"),
|
||||
9400 + gEllipsis + 9599, "The third page in this level named correctly (2).");
|
||||
is(lastPage2._nonenum.querySelectorAll(".variables-view-property .name")[3].getAttribute("value"),
|
||||
9600 + gEllipsis + 9999, "The fourth page in this level named correctly (2).");
|
||||
|
||||
let lastPage3 = lastPage2.get(9600 + gEllipsis + 9999);
|
||||
ok(lastPage3, "The last page in the third level was retrieved successfully.");
|
||||
lastPage3.expand();
|
||||
|
||||
let pageEnums3 = lastPage3.target.querySelector(".variables-view-element-details.enum").childNodes;
|
||||
let pageNonEnums3 = lastPage3.target.querySelector(".variables-view-element-details.nonenum").childNodes;
|
||||
is(pageEnums3.length, 400,
|
||||
"The last page in the third level should contain all the created enumerable elements.");
|
||||
is(pageNonEnums3.length, 0,
|
||||
"The last page in the third level shouldn't contain any non-enumerable elements.");
|
||||
|
||||
is(lastPage3._enum.querySelectorAll(".variables-view-property .name")[0].getAttribute("value"),
|
||||
9600, "The properties in this level are named correctly (3).");
|
||||
is(lastPage3._enum.querySelectorAll(".variables-view-property .name")[1].getAttribute("value"),
|
||||
9601, "The properties in this level are named correctly (3).");
|
||||
is(lastPage3._enum.querySelectorAll(".variables-view-property .name")[398].getAttribute("value"),
|
||||
9998, "The properties in this level are named correctly (3).");
|
||||
is(lastPage3._enum.querySelectorAll(".variables-view-property .name")[399].getAttribute("value"),
|
||||
9999, "The properties in this level are named correctly (3).");
|
||||
|
||||
is(lastPage3._enum.querySelectorAll(".variables-view-property .value")[0].getAttribute("value"),
|
||||
399, "The properties in this level have the correct value (3).");
|
||||
is(lastPage3._enum.querySelectorAll(".variables-view-property .value")[1].getAttribute("value"),
|
||||
398, "The properties in this level have the correct value (3).");
|
||||
is(lastPage3._enum.querySelectorAll(".variables-view-property .value")[398].getAttribute("value"),
|
||||
1, "The properties in this level have the correct value (3).");
|
||||
is(lastPage3._enum.querySelectorAll(".variables-view-property .value")[399].getAttribute("value"),
|
||||
0, "The properties in this level have the correct value (3).");
|
||||
}
|
||||
|
||||
registerCleanupFunction(function() {
|
||||
@ -42,4 +239,5 @@ registerCleanupFunction(function() {
|
||||
gPanel = null;
|
||||
gDebugger = null;
|
||||
gVariables = null;
|
||||
gEllipsis = null;
|
||||
});
|
||||
|
@ -14,7 +14,12 @@
|
||||
<script type="text/javascript">
|
||||
function test(aNumber) {
|
||||
var buffer = new ArrayBuffer(aNumber);
|
||||
var z = new Int8Array(buffer);
|
||||
var largeArray = new Int8Array(buffer);
|
||||
var largeObject = {};
|
||||
|
||||
for (var i = 0; i < aNumber; i++) {
|
||||
largeObject[i] = aNumber - i - 1;
|
||||
}
|
||||
debugger;
|
||||
}
|
||||
</script>
|
||||
|
@ -61,14 +61,14 @@ function test() {
|
||||
|
||||
is(tabpanel.querySelectorAll(".variables-view-scope").length, 1,
|
||||
"There should be 1 json scope displayed in this tabpanel.");
|
||||
is(tabpanel.querySelectorAll(".variables-view-property").length, 6057,
|
||||
"There should be 6057 json properties displayed in this tabpanel.");
|
||||
is(tabpanel.querySelectorAll(".variables-view-property").length, 6143,
|
||||
"There should be 6143 json properties displayed in this tabpanel.");
|
||||
is(tabpanel.querySelectorAll(".variables-view-empty-notice").length, 0,
|
||||
"The empty notice should not be displayed in this tabpanel.");
|
||||
|
||||
let jsonScope = tabpanel.querySelectorAll(".variables-view-scope")[0];
|
||||
let names = ".variables-view-property .name";
|
||||
let values = ".variables-view-property .value";
|
||||
let names = ".variables-view-property > .title > .name";
|
||||
let values = ".variables-view-property > .title > .value";
|
||||
|
||||
is(jsonScope.querySelector(".name").getAttribute("value"),
|
||||
L10N.getStr("jsonScopeName"),
|
||||
@ -83,11 +83,6 @@ function test() {
|
||||
"greeting", "The second json property name was incorrect.");
|
||||
is(jsonScope.querySelectorAll(values)[1].getAttribute("value"),
|
||||
"\"Hello long string JSON!\"", "The second json property value was incorrect.");
|
||||
|
||||
is(Array.slice(jsonScope.querySelectorAll(names), -1).shift().getAttribute("value"),
|
||||
"__proto__", "The last json property name was incorrect.");
|
||||
is(Array.slice(jsonScope.querySelectorAll(values), -1).shift().getAttribute("value"),
|
||||
"Object", "The last json property value was incorrect.");
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -177,6 +177,7 @@ SideMenuWidget.prototype = {
|
||||
|
||||
this._orderedMenuElementsArray.splice(
|
||||
this._orderedMenuElementsArray.indexOf(aChild), 1);
|
||||
|
||||
this._itemsByElement.delete(aChild);
|
||||
|
||||
if (this._selectedItem == aChild) {
|
||||
|
@ -11,6 +11,8 @@ const Cu = Components.utils;
|
||||
const DBG_STRINGS_URI = "chrome://browser/locale/devtools/debugger.properties";
|
||||
const LAZY_EMPTY_DELAY = 150; // ms
|
||||
const LAZY_EXPAND_DELAY = 50; // ms
|
||||
const SCROLL_PAGE_SIZE_DEFAULT = 0;
|
||||
const APPEND_PAGE_SIZE_DEFAULT = 500;
|
||||
const PAGE_SIZE_SCROLL_HEIGHT_RATIO = 100;
|
||||
const PAGE_SIZE_MAX_JUMPS = 30;
|
||||
const SEARCH_ACTION_MAX_DELAY = 300; // ms
|
||||
@ -228,6 +230,19 @@ VariablesView.prototype = {
|
||||
*/
|
||||
lazySearch: true,
|
||||
|
||||
/**
|
||||
* The number of elements in this container to jump when Page Up or Page Down
|
||||
* keys are pressed. If falsy, then the page size will be based on the
|
||||
* container height.
|
||||
*/
|
||||
scrollPageSize: SCROLL_PAGE_SIZE_DEFAULT,
|
||||
|
||||
/**
|
||||
* The maximum number of elements allowed in a scope, variable or property
|
||||
* that allows pagination when appending children.
|
||||
*/
|
||||
appendPageSize: APPEND_PAGE_SIZE_DEFAULT,
|
||||
|
||||
/**
|
||||
* Function called each time a variable or property's value is changed via
|
||||
* user interaction. If null, then value changes are disabled.
|
||||
@ -807,14 +822,14 @@ VariablesView.prototype = {
|
||||
|
||||
case e.DOM_VK_PAGE_UP:
|
||||
// Rewind a certain number of elements based on the container height.
|
||||
this.focusItemAtDelta(-(this.pageSize || Math.min(Math.floor(this._list.scrollHeight /
|
||||
this.focusItemAtDelta(-(this.scrollPageSize || Math.min(Math.floor(this._list.scrollHeight /
|
||||
PAGE_SIZE_SCROLL_HEIGHT_RATIO),
|
||||
PAGE_SIZE_MAX_JUMPS)));
|
||||
return;
|
||||
|
||||
case e.DOM_VK_PAGE_DOWN:
|
||||
// Advance a certain number of elements based on the container height.
|
||||
this.focusItemAtDelta(+(this.pageSize || Math.min(Math.floor(this._list.scrollHeight /
|
||||
this.focusItemAtDelta(+(this.scrollPageSize || Math.min(Math.floor(this._list.scrollHeight /
|
||||
PAGE_SIZE_SCROLL_HEIGHT_RATIO),
|
||||
PAGE_SIZE_MAX_JUMPS)));
|
||||
return;
|
||||
@ -868,13 +883,6 @@ VariablesView.prototype = {
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* The number of elements in this container to jump when Page Up or Page Down
|
||||
* keys are pressed. If falsy, then the page size will be based on the
|
||||
* container height.
|
||||
*/
|
||||
pageSize: 0,
|
||||
|
||||
/**
|
||||
* Sets the text displayed in this container when there are no available items.
|
||||
* @param string aValue
|
||||
@ -1190,6 +1198,8 @@ function Scope(aView, aName, aFlags = {}) {
|
||||
|
||||
// Inherit properties and flags from the parent view. You can override
|
||||
// each of these directly onto any scope, variable or property instance.
|
||||
this.scrollPageSize = aView.scrollPageSize;
|
||||
this.appendPageSize = aView.appendPageSize;
|
||||
this.eval = aView.eval;
|
||||
this.switch = aView.switch;
|
||||
this.delete = aView.delete;
|
||||
@ -1212,6 +1222,11 @@ Scope.prototype = {
|
||||
*/
|
||||
shouldPrefetch: true,
|
||||
|
||||
/**
|
||||
* Whether this Scope should paginate its contents.
|
||||
*/
|
||||
allowPaginate: false,
|
||||
|
||||
/**
|
||||
* The class name applied to this scope's target element.
|
||||
*/
|
||||
@ -1289,14 +1304,84 @@ Scope.prototype = {
|
||||
* Additional options for adding the properties. Supported options:
|
||||
* - sorted: true to sort all the properties before adding them
|
||||
* - callback: function invoked after each item is added
|
||||
* @param string aKeysType [optional]
|
||||
* Helper argument in the case of paginated items. Can be either
|
||||
* "just-strings" or "just-numbers". Humans shouldn't use this argument.
|
||||
*/
|
||||
addItems: function(aItems, aOptions = {}) {
|
||||
addItems: function(aItems, aOptions = {}, aKeysType = "") {
|
||||
let names = Object.keys(aItems);
|
||||
|
||||
// Building the view when inspecting an object with a very large number of
|
||||
// properties may take a long time. To avoid blocking the UI, group
|
||||
// the items into several lazily populated pseudo-items.
|
||||
let exceedsThreshold = names.length >= this.appendPageSize;
|
||||
let shouldPaginate = exceedsThreshold && aKeysType != "just-strings";
|
||||
if (shouldPaginate && this.allowPaginate) {
|
||||
// Group the items to append into two separate arrays, one containing
|
||||
// number-like keys, the other one containing string keys.
|
||||
if (aKeysType == "just-numbers") {
|
||||
var numberKeys = names;
|
||||
var stringKeys = [];
|
||||
} else {
|
||||
var numberKeys = [];
|
||||
var stringKeys = [];
|
||||
for (let name of names) {
|
||||
// Be very careful. Avoid Infinity, NaN and non Natural number keys.
|
||||
let coerced = +name;
|
||||
if (Number.isInteger(coerced) && coerced > -1) {
|
||||
numberKeys.push(name);
|
||||
} else {
|
||||
stringKeys.push(name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// This object contains a very large number of properties, but they're
|
||||
// almost all strings that can't be coerced to numbers. Don't paginate.
|
||||
if (numberKeys.length < this.appendPageSize) {
|
||||
this.addItems(aItems, aOptions, "just-strings");
|
||||
return;
|
||||
}
|
||||
|
||||
// Slices a section of the { name: descriptor } data properties.
|
||||
let paginate = (aArray, aBegin = 0, aEnd = aArray.length) => {
|
||||
let store = {}
|
||||
for (let i = aBegin; i < aEnd; i++) {
|
||||
let name = aArray[i];
|
||||
store[name] = aItems[name];
|
||||
}
|
||||
return store;
|
||||
};
|
||||
|
||||
// Creates a pseudo-item that populates itself with the data properties
|
||||
// from the corresponding page range.
|
||||
let createRangeExpander = (aArray, aBegin, aEnd, aOptions, aKeyTypes) => {
|
||||
let rangeVar = this.addItem(aArray[aBegin] + Scope.ellipsis + aArray[aEnd - 1]);
|
||||
rangeVar.onexpand = () => {
|
||||
let pageItems = paginate(aArray, aBegin, aEnd);
|
||||
rangeVar.addItems(pageItems, aOptions, aKeyTypes);
|
||||
}
|
||||
rangeVar.showArrow();
|
||||
rangeVar.target.setAttribute("pseudo-item", "");
|
||||
};
|
||||
|
||||
// Divide the number keys into quarters.
|
||||
let page = +Math.round(numberKeys.length / 4).toPrecision(1);
|
||||
createRangeExpander(numberKeys, 0, page, aOptions, "just-numbers");
|
||||
createRangeExpander(numberKeys, page, page * 2, aOptions, "just-numbers");
|
||||
createRangeExpander(numberKeys, page * 2, page * 3, aOptions, "just-numbers");
|
||||
createRangeExpander(numberKeys, page * 3, numberKeys.length, aOptions, "just-numbers");
|
||||
|
||||
// Append all the string keys together.
|
||||
this.addItems(paginate(stringKeys), aOptions, "just-strings");
|
||||
return;
|
||||
}
|
||||
|
||||
// Sort all of the properties before adding them, if preferred.
|
||||
if (aOptions.sorted) {
|
||||
if (aOptions.sorted && aKeysType != "just-numbers") {
|
||||
names.sort();
|
||||
}
|
||||
|
||||
// Add the properties to the current scope.
|
||||
for (let name of names) {
|
||||
let descriptor = aItems[name];
|
||||
@ -2017,6 +2102,10 @@ DevToolsUtils.defineLazyPrototypeGetter(Scope.prototype, "_store", Map);
|
||||
DevToolsUtils.defineLazyPrototypeGetter(Scope.prototype, "_enumItems", Array);
|
||||
DevToolsUtils.defineLazyPrototypeGetter(Scope.prototype, "_nonEnumItems", Array);
|
||||
|
||||
// An ellipsis symbol (usually "…") used for localization.
|
||||
XPCOMUtils.defineLazyGetter(Scope, "ellipsis", () =>
|
||||
Services.prefs.getComplexValue("intl.ellipsis", Ci.nsIPrefLocalizedString).data);
|
||||
|
||||
/**
|
||||
* A Variable is a Scope holding Property instances.
|
||||
* Iterable via "for (let [name, property] of instance) { }".
|
||||
@ -2048,12 +2137,19 @@ function Variable(aScope, aName, aDescriptor) {
|
||||
|
||||
Variable.prototype = Heritage.extend(Scope.prototype, {
|
||||
/**
|
||||
* Whether this Scope should be prefetched when it is remoted.
|
||||
* Whether this Variable should be prefetched when it is remoted.
|
||||
*/
|
||||
get shouldPrefetch(){
|
||||
get shouldPrefetch() {
|
||||
return this.name == "window" || this.name == "this";
|
||||
},
|
||||
|
||||
/**
|
||||
* Whether this Variable should paginate its contents.
|
||||
*/
|
||||
get allowPaginate() {
|
||||
return this.name != "window" && this.name != "this";
|
||||
},
|
||||
|
||||
/**
|
||||
* The class name applied to this variable's target element.
|
||||
*/
|
||||
@ -3114,7 +3210,6 @@ let generateId = (function() {
|
||||
};
|
||||
})();
|
||||
|
||||
|
||||
/**
|
||||
* An Editable encapsulates the UI of an edit box that overlays a label,
|
||||
* allowing the user to edit the value.
|
||||
|
@ -64,7 +64,14 @@
|
||||
display: none;
|
||||
}
|
||||
|
||||
.variable-or-property[pseudo-item] > tooltip {
|
||||
.variable-or-property[pseudo-item] > tooltip,
|
||||
.variable-or-property[pseudo-item] > .title > .variables-view-edit,
|
||||
.variable-or-property[pseudo-item] > .title > .variables-view-delete,
|
||||
.variable-or-property[pseudo-item] > .title > .variables-view-add-property,
|
||||
.variable-or-property[pseudo-item] > .title > .variable-or-property-frozen-label,
|
||||
.variable-or-property[pseudo-item] > .title > .variable-or-property-sealed-label,
|
||||
.variable-or-property[pseudo-item] > .title > .variable-or-property-non-extensible-label,
|
||||
.variable-or-property[pseudo-item] > .title > .variable-or-property-non-writable-icon {
|
||||
display: none;
|
||||
}
|
||||
|
||||
|
@ -451,18 +451,8 @@
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.variables-view-scope > .variables-view-element-details:not(:empty) {
|
||||
-moz-margin-start: 2px;
|
||||
-moz-margin-end: 1px;
|
||||
}
|
||||
|
||||
/* Generic variables traits */
|
||||
|
||||
.variables-view-variable {
|
||||
-moz-margin-start: 1px;
|
||||
-moz-margin-end: 1px;
|
||||
}
|
||||
|
||||
.variables-view-variable:not(:last-child) {
|
||||
border-bottom: 1px solid rgba(128, 128, 128, .15);
|
||||
}
|
||||
@ -481,8 +471,12 @@
|
||||
-moz-box-flex: 1;
|
||||
}
|
||||
|
||||
.variable-or-property > .title > .arrow {
|
||||
-moz-margin-start: 3px;
|
||||
}
|
||||
|
||||
.variable-or-property:not([untitled]) > .variables-view-element-details {
|
||||
-moz-margin-start: 10px;
|
||||
-moz-margin-start: 7px;
|
||||
}
|
||||
|
||||
/* Traits applied when variables or properties are changed or overridden */
|
||||
|
@ -445,18 +445,8 @@
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.variables-view-scope > .variables-view-element-details:not(:empty) {
|
||||
-moz-margin-start: 2px;
|
||||
-moz-margin-end: 1px;
|
||||
}
|
||||
|
||||
/* Generic variables traits */
|
||||
|
||||
.variables-view-variable {
|
||||
-moz-margin-start: 1px;
|
||||
-moz-margin-end: 1px;
|
||||
}
|
||||
|
||||
.variables-view-variable:not(:last-child) {
|
||||
border-bottom: 1px solid rgba(128, 128, 128, .15);
|
||||
}
|
||||
@ -475,8 +465,12 @@
|
||||
-moz-box-flex: 1;
|
||||
}
|
||||
|
||||
.variable-or-property > .title > .arrow {
|
||||
-moz-margin-start: 3px;
|
||||
}
|
||||
|
||||
.variable-or-property:not([untitled]) > .variables-view-element-details {
|
||||
-moz-margin-start: 10px;
|
||||
-moz-margin-start: 7px;
|
||||
}
|
||||
|
||||
/* Traits applied when variables or properties are changed or overridden */
|
||||
|
@ -448,18 +448,8 @@
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.variables-view-scope > .variables-view-element-details:not(:empty) {
|
||||
-moz-margin-start: 2px;
|
||||
-moz-margin-end: 1px;
|
||||
}
|
||||
|
||||
/* Generic variables traits */
|
||||
|
||||
.variables-view-variable {
|
||||
-moz-margin-start: 1px;
|
||||
-moz-margin-end: 1px;
|
||||
}
|
||||
|
||||
.variables-view-variable:not(:last-child) {
|
||||
border-bottom: 1px solid rgba(128, 128, 128, .15);
|
||||
}
|
||||
@ -478,8 +468,12 @@
|
||||
-moz-box-flex: 1;
|
||||
}
|
||||
|
||||
.variable-or-property > .title > .arrow {
|
||||
-moz-margin-start: 3px;
|
||||
}
|
||||
|
||||
.variable-or-property:not([untitled]) > .variables-view-element-details {
|
||||
-moz-margin-start: 10px;
|
||||
-moz-margin-start: 7px;
|
||||
}
|
||||
|
||||
/* Traits applied when variables or properties are changed or overridden */
|
||||
|
Loading…
Reference in New Issue
Block a user