Bug 830344 - Part 2: Implement pagination when expanding objects with lots of properties, r=past

This commit is contained in:
Victor Porof 2013-12-18 19:01:38 +02:00
parent e0d9108917
commit fc7cd3b2c8
10 changed files with 346 additions and 63 deletions

View File

@ -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();

View File

@ -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;
});

View File

@ -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>

View File

@ -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.");
}
});

View File

@ -177,6 +177,7 @@ SideMenuWidget.prototype = {
this._orderedMenuElementsArray.splice(
this._orderedMenuElementsArray.indexOf(aChild), 1);
this._itemsByElement.delete(aChild);
if (this._selectedItem == aChild) {

View File

@ -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.

View File

@ -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;
}

View File

@ -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 */

View File

@ -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 */

View File

@ -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 */