Bug 1359763 - Persist the box model and grid panel's accordion states. r=pbro
MozReview-Commit-ID: 46AZ5M2ZoJF
--- a/devtools/client/inspector/boxmodel/components/BoxModelApp.js
+++ b/devtools/client/inspector/boxmodel/components/BoxModelApp.js
@@ -1,29 +1,32 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
+const Services = require("Services");
const { addons, createClass, createFactory, PropTypes } =
require("devtools/client/shared/vendor/react");
const { connect } = require("devtools/client/shared/vendor/react-redux");
const { LocalizationHelper } = require("devtools/shared/l10n");
const Accordion =
createFactory(require("devtools/client/inspector/layout/components/Accordion"));
const BoxModel = createFactory(require("./BoxModel"));
const Types = require("../types");
const BOXMODEL_STRINGS_URI = "devtools/client/locales/boxmodel.properties";
const BOXMODEL_L10N = new LocalizationHelper(BOXMODEL_STRINGS_URI);
+const BOXMODEL_OPENED_PREF = "devtools.computed.boxmodel.opened";
+
const BoxModelApp = createClass({
displayName: "BoxModelApp",
propTypes: {
boxModel: PropTypes.shape(Types.boxModel).isRequired,
setSelectedNode: PropTypes.func.isRequired,
showBoxModelProperties: PropTypes.bool.isRequired,
@@ -38,17 +41,21 @@ const BoxModelApp = createClass({
render() {
return Accordion({
items: [
{
header: BOXMODEL_L10N.getStr("boxmodel.title"),
component: BoxModel,
componentProps: this.props,
- opened: true,
+ opened: Services.prefs.getBoolPref(BOXMODEL_OPENED_PREF),
+ onToggled: () => {
+ let opened = Services.prefs.getBoolPref(BOXMODEL_OPENED_PREF);
+ Services.prefs.setBoolPref(BOXMODEL_OPENED_PREF, !opened);
+ }
}
]
});
},
});
module.exports = connect(state => state)(BoxModelApp);
--- a/devtools/client/inspector/boxmodel/test/browser.ini
+++ b/devtools/client/inspector/boxmodel/test/browser.ini
@@ -8,24 +8,26 @@ support-files =
!/devtools/client/commandline/test/helpers.js
!/devtools/client/framework/test/shared-head.js
!/devtools/client/inspector/test/head.js
!/devtools/client/inspector/test/shared-head.js
!/devtools/client/shared/test/test-actor.js
!/devtools/client/shared/test/test-actor-registry.js
[browser_boxmodel.js]
+[browser_boxmodel_computed-accordion-state.js]
[browser_boxmodel_editablemodel.js]
# [browser_boxmodel_editablemodel_allproperties.js]
# Disabled for too many intermittent failures (bug 1009322)
[browser_boxmodel_editablemodel_bluronclick.js]
[browser_boxmodel_editablemodel_border.js]
[browser_boxmodel_editablemodel_pseudo.js]
[browser_boxmodel_editablemodel_stylerules.js]
[browser_boxmodel_guides.js]
+[browser_boxmodel_layout-accordion-state.js]
[browser_boxmodel_navigation.js]
[browser_boxmodel_offsetparent.js]
[browser_boxmodel_positions.js]
[browser_boxmodel_properties.js]
[browser_boxmodel_pseudo-element.js]
[browser_boxmodel_rotate-labels-on-sides.js]
[browser_boxmodel_sync.js]
[browser_boxmodel_tooltips.js]
new file mode 100644
--- /dev/null
+++ b/devtools/client/inspector/boxmodel/test/browser_boxmodel_computed-accordion-state.js
@@ -0,0 +1,84 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+// Tests that the box model's accordion state is persistent through hide/show in the
+// computed view.
+
+const TEST_URI = `
+ <style>
+ #div1 {
+ margin: 10px;
+ padding: 3px;
+ }
+ </style>
+ <div id="div1"></div>
+`;
+
+const BOXMODEL_OPENED_PREF = "devtools.computed.boxmodel.opened";
+
+add_task(function* () {
+ yield addTab("data:text/html;charset=utf-8," + encodeURIComponent(TEST_URI));
+ let { inspector, view, toolbox } = yield openBoxModelView();
+ let { document: doc } = view;
+
+ yield testAccordionStateAfterClickingHeader(doc);
+ yield testAccordionStateAfterSwitchingSidebars(inspector, doc);
+ yield testAccordionStateAfterReopeningComputedView(toolbox);
+
+ Services.prefs.clearUserPref(BOXMODEL_OPENED_PREF);
+});
+
+function* testAccordionStateAfterClickingHeader(doc) {
+ let header = doc.querySelector("#computedview-container .box-model-pane ._header");
+ let content = doc.querySelector("#computedview-container .box-model-pane ._content");
+
+ info("Checking initial state of the box model panel.");
+ is(content.style.display, "block", "The box model panel content is 'display: block'.");
+ ok(Services.prefs.getBoolPref(BOXMODEL_OPENED_PREF),
+ `${BOXMODEL_OPENED_PREF} is pref on by default.`);
+
+ info("Clicking the box model header to hide the box model panel.");
+ header.click();
+
+ info("Checking the new state of the box model panel.");
+ is(content.style.display, "none", "The box model panel content is 'display: none'.");
+ ok(!Services.prefs.getBoolPref(BOXMODEL_OPENED_PREF),
+ `${BOXMODEL_OPENED_PREF} is pref off.`);
+}
+
+function* testAccordionStateAfterSwitchingSidebars(inspector, doc) {
+ info("Checking the box model accordion state is persistent after switching sidebars.");
+
+ let content = doc.querySelector("#computedview-container .box-model-pane ._content");
+
+ info("Selecting the layout view.");
+ inspector.sidebar.select("layoutview");
+
+ info("Selecting the computed view.");
+ inspector.sidebar.select("computedview");
+
+ info("Checking the state of the box model panel.");
+ is(content.style.display, "none", "The box model panel content is 'display: none'.");
+ ok(!Services.prefs.getBoolPref(BOXMODEL_OPENED_PREF),
+ `${BOXMODEL_OPENED_PREF} is pref off.`);
+}
+
+function* testAccordionStateAfterReopeningComputedView(toolbox) {
+ info("Checking the box model accordion state is persistent after closing and "
+ + "re-opening the layout view.");
+
+ info("Closing the toolbox.");
+ yield toolbox.destroy();
+
+ info("Re-opening the layout view.");
+ let { view } = yield openBoxModelView();
+ let { document: doc } = view;
+ let content = doc.querySelector("#computedview-container .box-model-pane ._content");
+
+ info("Checking the state of the box model panel.");
+ ok(!content, "The box model panel content is not rendered.");
+ ok(!Services.prefs.getBoolPref(BOXMODEL_OPENED_PREF),
+ `${BOXMODEL_OPENED_PREF} is pref off.`);
+}
new file mode 100644
--- /dev/null
+++ b/devtools/client/inspector/boxmodel/test/browser_boxmodel_layout-accordion-state.js
@@ -0,0 +1,84 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+// Tests that the box model's accordion state is persistent through hide/show in the
+// layout view.
+
+const TEST_URI = `
+ <style>
+ #div1 {
+ margin: 10px;
+ padding: 3px;
+ }
+ </style>
+ <div id="div1"></div>
+`;
+
+const BOXMODEL_OPENED_PREF = "devtools.layout.boxmodel.opened";
+
+add_task(function* () {
+ yield addTab("data:text/html;charset=utf-8," + encodeURIComponent(TEST_URI));
+ let { inspector, boxmodel, toolbox } = yield openLayoutView();
+ let { document: doc } = boxmodel;
+
+ yield testAccordionStateAfterClickingHeader(doc);
+ yield testAccordionStateAfterSwitchingSidebars(inspector, doc);
+ yield testAccordionStateAfterReopeningLayoutView(toolbox);
+
+ Services.prefs.clearUserPref(BOXMODEL_OPENED_PREF);
+});
+
+function* testAccordionStateAfterClickingHeader(doc) {
+ let header = doc.querySelector("#layout-container .box-model-pane ._header");
+ let content = doc.querySelector("#layout-container .box-model-pane ._content");
+
+ info("Checking initial state of the box model panel.");
+ is(content.style.display, "block", "The box model panel content is 'display: block'.");
+ ok(Services.prefs.getBoolPref(BOXMODEL_OPENED_PREF),
+ `${BOXMODEL_OPENED_PREF} is pref on by default.`);
+
+ info("Clicking the box model header to hide the box model panel.");
+ header.click();
+
+ info("Checking the new state of the box model panel.");
+ is(content.style.display, "none", "The box model panel content is 'display: none'.");
+ ok(!Services.prefs.getBoolPref(BOXMODEL_OPENED_PREF),
+ `${BOXMODEL_OPENED_PREF} is pref off.`);
+}
+
+function* testAccordionStateAfterSwitchingSidebars(inspector, doc) {
+ info("Checking the box model accordion state is persistent after switching sidebars.");
+
+ let content = doc.querySelector("#layout-container .box-model-pane ._content");
+
+ info("Selecting the computed view.");
+ inspector.sidebar.select("computedview");
+
+ info("Selecting the layout view.");
+ inspector.sidebar.select("layoutview");
+
+ info("Checking the state of the box model panel.");
+ is(content.style.display, "none", "The box model panel content is 'display: none'.");
+ ok(!Services.prefs.getBoolPref(BOXMODEL_OPENED_PREF),
+ `${BOXMODEL_OPENED_PREF} is pref off.`);
+}
+
+function* testAccordionStateAfterReopeningLayoutView(toolbox) {
+ info("Checking the box model accordion state is persistent after closing and "
+ + "re-opening the layout view.");
+
+ info("Closing the toolbox.");
+ yield toolbox.destroy();
+
+ info("Re-opening the layout view.");
+ let { boxmodel } = yield openLayoutView();
+ let { document: doc } = boxmodel;
+ let content = doc.querySelector("#layout-container .box-model-pane ._content");
+
+ info("Checking the state of the box model panel.");
+ ok(!content, "The box model panel content is not rendered.");
+ ok(!Services.prefs.getBoolPref(BOXMODEL_OPENED_PREF),
+ `${BOXMODEL_OPENED_PREF} is pref off.`);
+}
--- a/devtools/client/inspector/grids/test/browser.ini
+++ b/devtools/client/inspector/grids/test/browser.ini
@@ -6,16 +6,17 @@ support-files =
!/devtools/client/commandline/test/helpers.js
!/devtools/client/framework/test/shared-head.js
!/devtools/client/inspector/test/head.js
!/devtools/client/inspector/test/shared-head.js
!/devtools/client/shared/test/test-actor.js
!/devtools/client/shared/test/test-actor-registry.js
!/devtools/client/framework/test/shared-redux-head.js
+[browser_grids_accordion-state.js]
[browser_grids_display-setting-extend-grid-lines.js]
[browser_grids_display-setting-show-grid-line-numbers.js]
[browser_grids_display-setting-show-grid-areas.js]
[browser_grids_grid-list-color-picker-on-ESC.js]
[browser_grids_grid-list-color-picker-on-RETURN.js]
[browser_grids_grid-list-element-rep.js]
[browser_grids_grid-list-no-grids.js]
[browser_grids_grid-list-on-mutation-element-added.js]
new file mode 100644
--- /dev/null
+++ b/devtools/client/inspector/grids/test/browser_grids_accordion-state.js
@@ -0,0 +1,84 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+// Tests that the grid's accordion state is persistent through hide/show in the layout
+// view.
+
+const TEST_URI = `
+ <style type='text/css'>
+ #grid {
+ display: grid;
+ }
+ </style>
+ <div id="grid">
+ <div id="cell1">cell1</div>
+ <div id="cell2">cell2</div>
+ </div>
+`;
+
+const GRID_OPENED_PREF = "devtools.layout.grid.opened";
+
+add_task(function* () {
+ yield addTab("data:text/html;charset=utf-8," + encodeURIComponent(TEST_URI));
+ let { inspector, gridInspector, toolbox } = yield openLayoutView();
+ let { document: doc } = gridInspector;
+
+ yield testAccordionStateAfterClickingHeader(doc);
+ yield testAccordionStateAfterSwitchingSidebars(inspector, doc);
+ yield testAccordionStateAfterReopeningLayoutView(toolbox);
+
+ Services.prefs.clearUserPref(GRID_OPENED_PREF);
+});
+
+function* testAccordionStateAfterClickingHeader(doc) {
+ let header = doc.querySelector(".grid-pane ._header");
+ let content = doc.querySelector(".grid-pane ._content");
+
+ info("Checking initial state of the grid panel.");
+ is(content.style.display, "block", "The grid panel content is 'display: block'.");
+ ok(Services.prefs.getBoolPref(GRID_OPENED_PREF),
+ `${GRID_OPENED_PREF} is pref on by default.`);
+
+ info("Clicking the grid header to hide the grid panel.");
+ header.click();
+
+ info("Checking the new state of the grid panel.");
+ is(content.style.display, "none", "The grid panel content is 'display: none'.");
+ ok(!Services.prefs.getBoolPref(GRID_OPENED_PREF), `${GRID_OPENED_PREF} is pref off.`);
+}
+
+function* testAccordionStateAfterSwitchingSidebars(inspector, doc) {
+ info("Checking the grid accordion state is persistent after switching sidebars.");
+
+ let content = doc.querySelector(".grid-pane ._content");
+
+ info("Selecting the computed view.");
+ inspector.sidebar.select("computedview");
+
+ info("Selecting the layout view.");
+ inspector.sidebar.select("layoutview");
+
+ info("Checking the state of the grid panel.");
+ is(content.style.display, "none", "The grid panel content is 'display: none'.");
+ ok(!Services.prefs.getBoolPref(GRID_OPENED_PREF), `${GRID_OPENED_PREF} is pref off.`);
+}
+
+function* testAccordionStateAfterReopeningLayoutView(toolbox) {
+ info("Checking the grid accordion state is persistent after closing and re-opening the "
+ + "layout view.");
+
+ info("Closing the toolbox.");
+ yield toolbox.destroy();
+
+ info("Re-opening the layout view.");
+ let { gridInspector } = yield openLayoutView();
+ let { document: doc } = gridInspector;
+ let content = doc.querySelector(".grid-pane ._content");
+
+ info("Checking the state of the grid panel.");
+ ok(!content, "The grid panel content is not rendered.");
+ ok(!Services.prefs.getBoolPref(GRID_OPENED_PREF),
+ `${GRID_OPENED_PREF} is pref off.`);
+}
--- a/devtools/client/inspector/layout/components/Accordion.js
+++ b/devtools/client/inspector/layout/components/Accordion.js
@@ -4,16 +4,17 @@
/**
* This file should not be modified and is a duplicate from the debugger.html project.
* Any changes to this file should be imported from the upstream debugger.html project.
*/
"use strict";
+const Services = require("Services");
const React = require("devtools/client/shared/vendor/react");
const { DOM: dom, PropTypes } = React;
const { div, span } = dom;
const Accordion = React.createClass({
displayName: "Accordion",
@@ -35,16 +36,20 @@ const Accordion = React.createClass({
opened[i] = !opened[i];
created[i] = true;
if (opened[i] && item.onOpened) {
item.onOpened();
}
+ if (item.onToggled) {
+ item.onToggled();
+ }
+
this.setState({ opened, created });
},
renderContainer: function (item, i) {
const { opened, created } = this.state;
const containerClassName =
item.header.toLowerCase().replace(/\s/g, "-") + "-pane";
let arrowClassName = "arrow theme-twisty";
--- a/devtools/client/inspector/layout/components/App.js
+++ b/devtools/client/inspector/layout/components/App.js
@@ -19,16 +19,19 @@ const GridTypes = require("devtools/clie
const Accordion = createFactory(require("./Accordion"));
const BOXMODEL_STRINGS_URI = "devtools/client/locales/boxmodel.properties";
const BOXMODEL_L10N = new LocalizationHelper(BOXMODEL_STRINGS_URI);
const LAYOUT_STRINGS_URI = "devtools/client/locales/layout.properties";
const LAYOUT_L10N = new LocalizationHelper(LAYOUT_STRINGS_URI);
+const BOXMODEL_OPENED_PREF = "devtools.layout.boxmodel.opened";
+const GRID_OPENED_PREF = "devtools.layout.grid.opened";
+
const App = createClass({
displayName: "App",
propTypes: {
boxModel: PropTypes.shape(BoxModelTypes.boxModel).isRequired,
getSwatchColorPickerTooltip: PropTypes.func.isRequired,
grids: PropTypes.arrayOf(PropTypes.shape(GridTypes.grid)).isRequired,
@@ -55,23 +58,31 @@ const App = createClass({
className: "devtools-monospace",
},
Accordion({
items: [
{
header: BOXMODEL_L10N.getStr("boxmodel.title"),
component: BoxModel,
componentProps: this.props,
- opened: true,
+ opened: Services.prefs.getBoolPref(BOXMODEL_OPENED_PREF),
+ onToggled: () => {
+ let opened = Services.prefs.getBoolPref(BOXMODEL_OPENED_PREF);
+ Services.prefs.setBoolPref(BOXMODEL_OPENED_PREF, !opened);
+ }
},
{
header: LAYOUT_L10N.getStr("layout.header"),
component: Grid,
componentProps: this.props,
- opened: true,
+ opened: Services.prefs.getBoolPref(GRID_OPENED_PREF),
+ onToggled: () => {
+ let opened = Services.prefs.getBoolPref(GRID_OPENED_PREF);
+ Services.prefs.setBoolPref(GRID_OPENED_PREF, !opened);
+ }
},
]
})
);
},
});
--- a/devtools/client/preferences/devtools.js
+++ b/devtools/client/preferences/devtools.js
@@ -1,12 +1,11 @@
-# -*- indent-tabs-mode: nil; js-indent-level: 2 -*-
-# This Source Code Form is subject to the terms of the Mozilla Public
-# License, v. 2.0. If a copy of the MPL was not distributed with this
-# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
// Developer edition promo preferences
pref("devtools.devedition.promo.shown", false);
pref("devtools.devedition.promo.url", "https://www.mozilla.org/firefox/developer/?utm_source=firefox-dev-tools&utm_medium=firefox-browser&utm_content=betadoorhanger");
// Only potentially show in beta release
#if MOZ_UPDATE_CHANNEL == beta
pref("devtools.devedition.promo.enabled", true);
@@ -73,16 +72,23 @@ pref("devtools.fontinspector.enabled", t
pref("devtools.layoutview.enabled", false);
// Grid highlighter preferences
pref("devtools.gridinspector.showGridAreas", false);
pref("devtools.gridinspector.showGridLineNumbers", false);
pref("devtools.gridinspector.showGridOutline", false);
pref("devtools.gridinspector.showInfiniteLines", false);
+// Whether or not the box model panel is opened in the computed view
+pref("devtools.computed.boxmodel.opened", true);
+// Whether or not the box model panel is opened in the layout view
+pref("devtools.layout.boxmodel.opened", true);
+// Whether or not the grid inspector panel is opened in the layout view
+pref("devtools.layout.grid.opened", true);
+
// By how many times eyedropper will magnify pixels
pref("devtools.eyedropper.zoom", 6);
// Enable to collapse attributes that are too long.
pref("devtools.markup.collapseAttributes", true);
// Length to collapse attributes
pref("devtools.markup.collapseAttributeLength", 120);