--- a/devtools/client/inspector/boxmodel/box-model.js
+++ b/devtools/client/inspector/boxmodel/box-model.js
@@ -122,41 +122,44 @@ BoxModel.prototype = {
*/
updateBoxModel(reason) {
this._updateReasons = this._updateReasons || [];
if (reason) {
this._updateReasons.push(reason);
}
let lastRequest = Task.spawn((function* () {
- if (!(this.isPanelVisible() &&
- this.inspector.selection.isConnected() &&
- this.inspector.selection.isElementNode())) {
+ if (!this.inspector || !this.isPanelVisible() ||
+ !this.inspector.selection.isConnected() ||
+ !this.inspector.selection.isElementNode()) {
return null;
}
let node = this.inspector.selection.nodeFront;
+
let layout = yield this.inspector.pageStyle.getLayout(node, {
autoMargins: true,
});
+
let styleEntries = yield this.inspector.pageStyle.getApplied(node, {
// We don't need styles applied to pseudo elements of the current node.
skipPseudo: true
});
this.elementRules = styleEntries.map(e => e.rule);
// Update the layout properties with whether or not the element's position is
// editable with the geometry editor.
let isPositionEditable = yield this.inspector.pageStyle.isPositionEditable(node);
+
layout = Object.assign({}, layout, {
isPositionEditable,
});
- const actorCanGetOffSetParent
- = yield this.inspector.target.actorHasMethod("domwalker", "getOffsetParent");
+ const actorCanGetOffSetParent =
+ yield this.inspector.target.actorHasMethod("domwalker", "getOffsetParent");
if (actorCanGetOffSetParent) {
// Update the redux store with the latest offset parent DOM node
let offsetParent = yield this.inspector.walker.getOffsetParent(node);
this.store.dispatch(updateOffsetParent(offsetParent));
}
// Update the redux store with the latest layout properties and update the box
--- a/devtools/client/inspector/grids/components/GridDisplaySettings.js
+++ b/devtools/client/inspector/grids/components/GridDisplaySettings.js
@@ -58,32 +58,34 @@ module.exports = createClass({
dom.li(
{
className: "grid-settings-item",
},
dom.label(
{},
dom.input(
{
+ id: "grid-setting-extend-grid-lines",
type: "checkbox",
checked: highlighterSettings.showInfiniteLines,
onChange: this.onShowInfiniteLinesCheckboxClick,
}
),
getStr("layout.extendGridLinesInfinitely")
)
),
dom.li(
{
className: "grid-settings-item",
},
dom.label(
{},
dom.input(
{
+ id: "grid-setting-show-grid-line-numbers",
type: "checkbox",
checked: highlighterSettings.showGridLineNumbers,
onChange: this.onShowGridLineNumbersCheckboxClick,
}
),
getStr("layout.displayNumbersOnLines")
)
)
--- a/devtools/client/inspector/grids/components/GridItem.js
+++ b/devtools/client/inspector/grids/components/GridItem.js
@@ -23,18 +23,16 @@ module.exports = createClass({
grid: PropTypes.shape(Types.grid).isRequired,
setSelectedNode: PropTypes.func.isRequired,
onHideBoxModelHighlighter: PropTypes.func.isRequired,
onSetGridOverlayColor: PropTypes.func.isRequired,
onShowBoxModelHighlighterForNode: PropTypes.func.isRequired,
onToggleGridHighlighter: PropTypes.func.isRequired,
},
- mixins: [ addons.PureRenderMixin ],
-
componentDidMount() {
let tooltip = this.props.getSwatchColorPickerTooltip();
let swatchEl = findDOMNode(this).querySelector(".grid-color-swatch");
let previousColor;
tooltip.addSwatch(swatchEl, {
onCommit: this.setGridColor,
onPreview: this.setGridColor,
--- a/devtools/client/inspector/grids/components/GridList.js
+++ b/devtools/client/inspector/grids/components/GridList.js
@@ -43,17 +43,19 @@ module.exports = createClass({
{
className: "grid-container",
},
dom.span(
{},
getStr("layout.overlayGrid")
),
dom.ul(
- {},
+ {
+ id: "grid-list",
+ },
grids.map(grid => GridItem({
key: grid.id,
getSwatchColorPickerTooltip,
grid,
setSelectedNode,
onHideBoxModelHighlighter,
onSetGridOverlayColor,
onShowBoxModelHighlighterForNode,
--- a/devtools/client/inspector/grids/grid-inspector.js
+++ b/devtools/client/inspector/grids/grid-inspector.js
@@ -248,23 +248,33 @@ GridInspector.prototype = {
updateGridPanel: Task.async(function* (gridFronts) {
// Stop refreshing if the inspector or store is already destroyed.
if (!this.inspector || !this.store) {
return;
}
// Get all the GridFront from the server if no gridFronts were provided.
if (!gridFronts) {
- gridFronts = yield this.layoutInspector.getAllGrids(this.walker.rootNode);
+ try {
+ gridFronts = yield this.layoutInspector.getAllGrids(this.walker.rootNode);
+ } catch(e) {
+ return;
+ }
}
let grids = [];
for (let i = 0; i < gridFronts.length; i++) {
let grid = gridFronts[i];
- let nodeFront = yield this.walker.getNodeFromActor(grid.actorID, ["containerEl"]);
+
+ let nodeFront;
+ try {
+ nodeFront = yield this.walker.getNodeFromActor(grid.actorID, ["containerEl"]);
+ } catch (e) {
+ return;
+ }
let fallbackColor = GRID_COLORS[i % GRID_COLORS.length];
let color = this.getInitialGridColor(nodeFront, fallbackColor);
grids.push({
id: i,
color,
gridFragments: grid.gridFragments,
@@ -295,17 +305,17 @@ GridInspector.prototype = {
* @param {Event} event
* Event that was triggered.
* @param {NodeFront} nodeFront
* The NodeFront of the grid container element for which the grid highlighter
* is shown for.
* @param {Object} options
* The highlighter options used for the highlighter being shown/hidden.
*/
- onHighlighterChange(event, nodeFront, options) {
+ onHighlighterChange(event, nodeFront, options = {}) {
let highlighted = event === "grid-highlighter-shown";
let { color } = options;
// Only tell the store that the highlighter changed if it did change.
// If we're still highlighting the same node, with the same color, no need to force
// a refresh.
if (this.lastHighlighterState !== highlighted ||
this.lastHighlighterNode !== nodeFront) {
--- a/devtools/client/inspector/grids/moz.build
+++ b/devtools/client/inspector/grids/moz.build
@@ -10,8 +10,10 @@ DIRS += [
'reducers',
'utils',
]
DevToolsModules(
'grid-inspector.js',
'types.js',
)
+
+BROWSER_CHROME_MANIFESTS += ['test/browser.ini']
new file mode 100644
--- /dev/null
+++ b/devtools/client/inspector/grids/test/.eslintrc.js
@@ -0,0 +1,6 @@
+"use strict";
+
+module.exports = {
+ // Extend from the shared list of defined globals for mochitests.
+ "extends": "../../../../.eslintrc.mochitests.js"
+};
new file mode 100644
--- /dev/null
+++ b/devtools/client/inspector/grids/test/browser.ini
@@ -0,0 +1,23 @@
+[DEFAULT]
+tags = devtools
+subsuite = devtools
+support-files =
+ head.js
+ !/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_display-setting-extend-grid-lines.js]
+[browser_grids_display-setting-show-grid-line-numbers.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_01.js]
+[browser_grids_grid-list-on-mutation_02.js]
+[browser_grids_grid-list-toggle_01.js]
+[browser_grids_grid-list-toggle_02.js]
new file mode 100644
--- /dev/null
+++ b/devtools/client/inspector/grids/test/browser_grids_display-setting-extend-grid-lines.js
@@ -0,0 +1,51 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+// Tests that the 'Extend grid lines infinitely' grid highlighter setting will update
+// the redux store and pref setting.
+
+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 SHOW_INFINITE_LINES_PREF = "devtools.gridinspector.showInfiniteLines";
+
+add_task(function* () {
+ yield addTab("data:text/html;charset=utf-8," + encodeURIComponent(TEST_URI));
+ let { inspector, gridInspector } = yield openLayoutView();
+ let { document: doc } = gridInspector;
+ let { store } = inspector;
+
+ yield selectNode("#grid", inspector);
+ let checkbox = doc.getElementById("grid-setting-extend-grid-lines");
+
+ ok(!Services.prefs.getBoolPref(SHOW_INFINITE_LINES_PREF),
+ "'Extend grid lines infinitely' is pref off by default.");
+
+ info("Toggling ON the 'Extend grid lines infinitely' setting.");
+ let onCheckboxChange = waitUntilState(store, state =>
+ state.highlighterSettings.showInfiniteLines);
+ checkbox.click();
+ yield onCheckboxChange;
+
+ info("Toggling OFF the 'Extend grid lines infinitely' setting.");
+ onCheckboxChange = waitUntilState(store, state =>
+ !state.highlighterSettings.showInfiniteLines);
+ checkbox.click();
+ yield onCheckboxChange;
+
+ ok(!Services.prefs.getBoolPref(SHOW_INFINITE_LINES_PREF),
+ "'Extend grid lines infinitely' is pref off.");
+
+ Services.prefs.clearUserPref(SHOW_INFINITE_LINES_PREF);
+});
new file mode 100644
--- /dev/null
+++ b/devtools/client/inspector/grids/test/browser_grids_display-setting-show-grid-line-numbers.js
@@ -0,0 +1,55 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+// Tests that the 'Display numbers on lines' grid highlighter setting will update
+// the redux store and pref setting.
+
+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 SHOW_GRID_LINE_NUMBERS = "devtools.gridinspector.showGridLineNumbers";
+
+add_task(function* () {
+ yield addTab("data:text/html;charset=utf-8," + encodeURIComponent(TEST_URI));
+ let { inspector, gridInspector } = yield openLayoutView();
+ let { document: doc } = gridInspector;
+ let { store } = inspector;
+
+ yield selectNode("#grid", inspector);
+ let checkbox = doc.getElementById("grid-setting-show-grid-line-numbers");
+
+ info("Checking the initial state of the CSS grid highlighter setting.");
+ ok(!Services.prefs.getBoolPref(SHOW_GRID_LINE_NUMBERS),
+ "'Display numbers on lines' is pref off by default.");
+
+ info("Toggling ON the 'Display numbers on lines' setting.");
+ let onCheckboxChange = waitUntilState(store, state =>
+ state.highlighterSettings.showGridLineNumbers);
+ checkbox.click();
+ yield onCheckboxChange;
+
+ ok(Services.prefs.getBoolPref(SHOW_GRID_LINE_NUMBERS),
+ "'Display numbers on lines' is pref on.");
+
+ info("Toggling OFF the 'Display numbers on lines' setting.");
+ onCheckboxChange = waitUntilState(store, state =>
+ !state.highlighterSettings.showGridLineNumbers);
+ checkbox.click();
+ yield onCheckboxChange;
+
+ ok(!Services.prefs.getBoolPref(SHOW_GRID_LINE_NUMBERS),
+ "'Display numbers on lines' is pref off.");
+
+ Services.prefs.clearUserPref(SHOW_GRID_LINE_NUMBERS);
+});
new file mode 100644
--- /dev/null
+++ b/devtools/client/inspector/grids/test/browser_grids_grid-list-color-picker-on-ESC.js
@@ -0,0 +1,50 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+// Tests that the grid item's color change in the colorpicker is reverted when ESCAPE is
+// pressed.
+
+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>
+`;
+
+add_task(function* () {
+ yield addTab("data:text/html;charset=utf-8," + encodeURIComponent(TEST_URI));
+ let { inspector, gridInspector, toolbox } = yield openLayoutView();
+ let { document: doc } = gridInspector;
+ let { store } = inspector;
+ let cPicker = gridInspector.getSwatchColorPickerTooltip();
+ let spectrum = cPicker.spectrum;
+ let swatch = doc.querySelector(".grid-color-swatch");
+ swatch.scrollIntoView();
+
+ let onColorPickerReady = cPicker.once("ready");
+ swatch.click();
+ yield onColorPickerReady;
+
+ yield simulateColorPickerChange(cPicker, [0, 255, 0, .5]);
+
+ is(swatch.style.backgroundColor, "rgba(0, 255, 0, 0.5)",
+ "The color swatch's background was updated.");
+
+ info("Pressing ESCAPE to close the tooltip.");
+ let onGridColorUpdate = waitUntilState(store, state =>
+ state.grids[0].color === "#4B0082");
+ let onColorPickerHidden = cPicker.tooltip.once("hidden");
+ focusAndSendKey(spectrum.element.ownerDocument.defaultView, "ESCAPE");
+ yield onColorPickerHidden;
+ yield onGridColorUpdate;
+
+ is(swatch.style.backgroundColor, "rgb(75, 0, 130)",
+ "The color swatch's background was reverted after ESCAPE.");
+});
new file mode 100644
--- /dev/null
+++ b/devtools/client/inspector/grids/test/browser_grids_grid-list-color-picker-on-RETURN.js
@@ -0,0 +1,50 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+// Tests that the grid item's color change in the colorpicker is committed when RETURN is
+// pressed.
+
+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>
+`;
+
+add_task(function* () {
+ yield addTab("data:text/html;charset=utf-8," + encodeURIComponent(TEST_URI));
+ let { inspector, gridInspector, toolbox } = yield openLayoutView();
+ let { document: doc } = gridInspector;
+ let { store } = inspector;
+ let cPicker = gridInspector.getSwatchColorPickerTooltip();
+ let spectrum = cPicker.spectrum;
+ let swatch = doc.querySelector(".grid-color-swatch");
+ swatch.scrollIntoView();
+
+ let onColorPickerReady = cPicker.once("ready");
+ swatch.click();
+ yield onColorPickerReady;
+
+ yield simulateColorPickerChange(cPicker, [0, 255, 0, .5]);
+
+ is(swatch.style.backgroundColor, "rgba(0, 255, 0, 0.5)",
+ "The color swatch's background was updated.");
+
+ info("Pressing RETURN to commit the color change.");
+ let onGridColorUpdate = waitUntilState(store, state =>
+ state.grids[0].color === "#00FF0080");
+ let onColorPickerHidden = cPicker.tooltip.once("hidden");
+ focusAndSendKey(spectrum.element.ownerDocument.defaultView, "RETURN");
+ yield onColorPickerHidden;
+ yield onGridColorUpdate;
+
+ is(swatch.style.backgroundColor, "rgba(0, 255, 0, 0.5)",
+ "The color swatch's background was kept after RETURN.");
+});
new file mode 100644
--- /dev/null
+++ b/devtools/client/inspector/grids/test/browser_grids_grid-list-element-rep.js
@@ -0,0 +1,48 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+// Tests that the grid item's element rep will display the box model higlighter on hover
+// and select the node on click.
+
+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>
+`;
+
+add_task(function* () {
+ yield addTab("data:text/html;charset=utf-8," + encodeURIComponent(TEST_URI));
+ let { inspector, gridInspector, toolbox } = yield openLayoutView();
+ let { document: doc } = gridInspector;
+ let { store } = inspector;
+
+ let gridList = doc.querySelector("#grid-list");
+ let elementRep = gridList.children[0].querySelector(".open-inspector");
+ elementRep.scrollIntoView();
+
+ info("Listen to node-highlight event and mouse over the widget");
+ let onHighlight = toolbox.once("node-highlight");
+ EventUtils.synthesizeMouse(elementRep, 10, 5, {type: "mouseover"}, doc.defaultView);
+ let nodeFront = yield onHighlight;
+
+ ok(true, "The node-highlight event was fired");
+ is(nodeFront.tagName, "DIV", "The highlighted node has the correct tagName.");
+ is(nodeFront.attributes[0].name, "id",
+ "The highlighted node has the correct attributes.");
+ is(nodeFront.attributes[0].value, "grid", "The highlighted node has the correct id.");
+
+ let onSelection = inspector.selection.once("new-node-front");
+ EventUtils.sendMouseEvent({type: "click"}, elementRep, doc.defaultView);
+ yield onSelection;
+
+ is(inspector.selection.nodeFront, store.getState().grids[0].nodeFront,
+ "The selected node is the one stored on the grid item's state.")
+});
new file mode 100644
--- /dev/null
+++ b/devtools/client/inspector/grids/test/browser_grids_grid-list-no-grids.js
@@ -0,0 +1,36 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+// Tests that no grid list items and a no grids available message is displayed when
+// there are no grid containers on the page.
+
+const TEST_URI = `
+ <style type='text/css'>
+ </style>
+ <div id="grid">
+ <div id="cell1">cell1</div>
+ <div id="cell2">cell2</div>
+ </div>
+`;
+
+const HIGHLIGHTER_TYPE = "CssGridHighlighter";
+
+add_task(function* () {
+ yield addTab("data:text/html;charset=utf-8," + encodeURIComponent(TEST_URI));
+ let { inspector, gridInspector } = yield openLayoutView();
+ let { document: doc } = gridInspector;
+ let { highlighters } = inspector;
+
+ yield selectNode("#grid", inspector);
+ let noGridList = doc.querySelector(".layout-no-grids");
+ let gridList = doc.querySelector("#grid-list");
+
+ info("Checking the initial state of the Grid Inspector.");
+ ok(noGridList, "No grid list displayed.");
+ ok(!gridList, "No grid containers are listed.");
+ ok(!highlighters.highlighters[HIGHLIGHTER_TYPE],
+ "No CSS grid highlighter exists in the highlighters overlay.");
+ ok(!highlighters.gridHighlighterShown, "No CSS grid highlighter is shown.");
+});
new file mode 100644
--- /dev/null
+++ b/devtools/client/inspector/grids/test/browser_grids_grid-list-on-mutation_01.js
@@ -0,0 +1,65 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+// Tests that the grid item is removed from the grid list when the grid container is
+// removed from the page.
+
+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 HIGHLIGHTER_TYPE = "CssGridHighlighter";
+
+add_task(function* () {
+ yield addTab("data:text/html;charset=utf-8," + encodeURIComponent(TEST_URI));
+ let { inspector, gridInspector, testActor } = yield openLayoutView();
+ let { document: doc } = gridInspector;
+ let { highlighters, store } = inspector;
+
+ yield selectNode("#grid", inspector);
+ let gridList = doc.querySelector("#grid-list");
+ let checkbox = gridList.children[0].querySelector("input");
+
+ info("Checking the initial state of the Grid Inspector.");
+ is(gridList.childNodes.length, 1, "One grid container is listed.");
+ ok(!highlighters.highlighters[HIGHLIGHTER_TYPE],
+ "No CSS grid highlighter exists in the highlighters overlay.");
+ ok(!highlighters.gridHighlighterShown, "No CSS grid highlighter is shown.");
+
+ info("Toggling ON the CSS grid highlighter from the layout panel.");
+ let onHighlighterShown = highlighters.once("grid-highlighter-shown");
+ let onCheckboxChange = waitUntilState(store, state =>
+ state.grids.length == 1 && state.grids[0].highlighted);
+ checkbox.click();
+ yield onHighlighterShown;
+ yield onCheckboxChange;
+
+ info("Checking the CSS grid highlighter is created.");
+ ok(highlighters.highlighters[HIGHLIGHTER_TYPE],
+ "CSS grid highlighter is created in the highlighters overlay.");
+ ok(highlighters.gridHighlighterShown, "CSS grid highlighter is shown.");
+
+ info("Removing the #grid container in the content page.");
+ let onHighlighterHidden = highlighters.once("grid-highlighter-hidden");
+ onCheckboxChange = waitUntilState(store, state => state.grids.length == 0);
+ testActor.eval(`
+ content.document.getElementById("grid").remove();
+ `);
+ yield onHighlighterHidden;
+ yield onCheckboxChange;
+
+ info("Checking the CSS grid highlighter is not shown.");
+ ok(!highlighters.gridHighlighterShown, "No CSS grid highlighter is shown.");
+ let noGridList = doc.querySelector(".layout-no-grids");
+ ok(noGridList, "No grid list displayed.");
+});
new file mode 100644
--- /dev/null
+++ b/devtools/client/inspector/grids/test/browser_grids_grid-list-on-mutation_02.js
@@ -0,0 +1,95 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+// Tests that the grid list updates when a new grid container is added to the page.
+
+const TEST_URI = `
+ <style type='text/css'>
+ .grid {
+ display: grid;
+ }
+ </style>
+ <div id="grid1" class="grid">
+ <div class="cell1">cell1</div>
+ <div class="cell2">cell2</div>
+ </div>
+ <div id="grid2">
+ <div class="cell1">cell1</div>
+ <div class="cell2">cell2</div>
+ </div>
+`;
+
+const HIGHLIGHTER_TYPE = "CssGridHighlighter";
+
+add_task(function* () {
+ yield addTab("data:text/html;charset=utf-8," + encodeURIComponent(TEST_URI));
+ let { inspector, gridInspector, testActor } = yield openLayoutView();
+ let { document: doc } = gridInspector;
+ let { highlighters, store } = inspector;
+
+ yield selectNode("#grid", inspector);
+ let gridList = doc.querySelector("#grid-list");
+ let checkbox1 = gridList.children[0].querySelector("input");
+
+ info("Checking the initial state of the Grid Inspector.");
+ is(gridList.childNodes.length, 1, "One grid container is listed.");
+ ok(!highlighters.highlighters[HIGHLIGHTER_TYPE],
+ "No CSS grid highlighter exists in the highlighters overlay.");
+ ok(!highlighters.gridHighlighterShown, "No CSS grid highlighter is shown.");
+
+ info("Toggling ON the CSS grid highlighter from the layout panel.");
+ let onHighlighterShown = highlighters.once("grid-highlighter-shown");
+ checkbox1.click();
+ yield onHighlighterShown;
+
+ info("Checking the CSS grid highlighter is created.");
+ ok(highlighters.highlighters[HIGHLIGHTER_TYPE],
+ "CSS grid highlighter is created in the highlighters overlay.");
+ ok(highlighters.gridHighlighterShown, "CSS grid highlighter is shown.");
+
+ info("Adding the #grid2 container in the content page.");
+ let onGridListUpdate = waitUntilState(store, state =>
+ state.grids.length == 2 &&
+ state.grids[0].highlighted &&
+ !state.grids[1].highlighted);
+ testActor.eval(`
+ content.document.getElementById("grid2").classList.add("grid");
+ `);
+ yield onGridListUpdate;
+
+ info("Checking the new Grid Inspector state.");
+ is(gridList.childNodes.length, 2, "Two grid containers are listed.");
+ ok(highlighters.highlighters[HIGHLIGHTER_TYPE],
+ "CSS grid highlighter is created in the highlighters overlay.");
+ ok(highlighters.gridHighlighterShown, "CSS grid highlighter is shown.");
+
+ let checkbox2 = gridList.children[1].querySelector("input");
+
+ info("Toggling ON the CSS grid highlighter for #grid2.")
+ onHighlighterShown = highlighters.once("grid-highlighter-shown");
+ let onCheckboxChange = waitUntilState(store, state =>
+ state.grids.length == 2 &&
+ !state.grids[0].highlighted &&
+ state.grids[1].highlighted);
+ checkbox2.click();
+ yield onHighlighterShown;
+ yield onCheckboxChange;
+
+ info("Checking the CSS grid highlighter is still shown.");
+ ok(highlighters.gridHighlighterShown, "CSS grid highlighter is shown.");
+
+ info("Toggling OFF the CSS grid highlighter from the layout panel.");
+ let onHighlighterHidden = highlighters.once("grid-highlighter-hidden");
+ onCheckboxChange = waitUntilState(store, state =>
+ state.grids.length == 2 &&
+ !state.grids[0].highlighted &&
+ !state.grids[1].highlighted);
+ checkbox2.click();
+ yield onHighlighterHidden;
+ yield onCheckboxChange;
+
+ info("Checking the CSS grid highlighter is not shown.");
+ ok(!highlighters.gridHighlighterShown, "No CSS grid highlighter is shown.");
+});
new file mode 100644
--- /dev/null
+++ b/devtools/client/inspector/grids/test/browser_grids_grid-list-toggle_01.js
@@ -0,0 +1,86 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+// Tests toggling ON/OFF the grid highlighter from the grid ispector panel.
+
+const TEST_URI = `
+ <style type='text/css'>
+ #grid {
+ display: grid;
+ grid-template-columns: [col-1 col-start-1] 100px [col-2] 100px;
+ grid-template-rows: 100px 100px;
+ grid-template-areas: ". header"
+ "sidebar content";
+ }
+ #cell1 {
+ grid-column: 1;
+ grid-row: 1;
+ }
+ #cell2 {
+ grid-column: 2;
+ grid-row: 1;
+ }
+ #cell3 {
+ grid-column: 1;
+ grid-row: 2;
+ }
+ #cell4 {
+ grid-column: 2;
+ grid-row: 2;
+ }
+ </style>
+ <div id="grid">
+ <div id="cell1">cell1</div>
+ <div id="cell2">cell2</div>
+ <div id="cell3">cell3</div>
+ <div id="cell4">cell4</div>
+ </div>
+`;
+
+const HIGHLIGHTER_TYPE = "CssGridHighlighter";
+
+add_task(function* () {
+ yield addTab("data:text/html;charset=utf-8," + encodeURIComponent(TEST_URI));
+ let { gridInspector, inspector } = yield openLayoutView();
+ let { document: doc } = gridInspector;
+ let { highlighters, store } = inspector;
+
+ yield selectNode("#grid", inspector);
+ let gridList = doc.querySelector("#grid-list");
+ let checkbox = gridList.children[0].querySelector("input");
+
+ info("Checking the initial state of the Grid Inspector.");
+ is(gridList.childNodes.length, 1, "One grid container is listed.");
+ ok(!checkbox.checked, `Grid item ${checkbox.value} is unchecked in the grid list.`);
+ ok(!highlighters.highlighters[HIGHLIGHTER_TYPE],
+ "No CSS grid highlighter exists in the highlighters overlay.");
+ ok(!highlighters.gridHighlighterShown, "No CSS grid highlighter is shown.");
+
+ info("Toggling ON the CSS grid highlighter from the layout panel.");
+ let onHighlighterShown = highlighters.once("grid-highlighter-shown");
+ let onCheckboxChange = waitUntilState(store, state =>
+ state.grids.length == 1 &&
+ state.grids[0].highlighted);
+ checkbox.click();
+ yield onHighlighterShown;
+ yield onCheckboxChange;
+
+ info("Checking the CSS grid highlighter is created.");
+ ok(highlighters.highlighters[HIGHLIGHTER_TYPE],
+ "CSS grid highlighter is created in the highlighters overlay.");
+ ok(highlighters.gridHighlighterShown, "CSS grid highlighter is shown.");
+
+ info("Toggling OFF the CSS grid highlighter from the layout panel.");
+ let onHighlighterHidden = highlighters.once("grid-highlighter-hidden");
+ onCheckboxChange = waitUntilState(store, state =>
+ state.grids.length == 1 &&
+ !state.grids[0].highlighted);
+ checkbox.click();
+ yield onHighlighterHidden;
+ yield onCheckboxChange;
+
+ info("Checking the CSS grid highlighter is not shown.");
+ ok(!highlighters.gridHighlighterShown, "No CSS grid highlighter is shown.");
+});
new file mode 100644
--- /dev/null
+++ b/devtools/client/inspector/grids/test/browser_grids_grid-list-toggle_02.js
@@ -0,0 +1,86 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+// Test toggling the grid highlighter in the grid inspector panel with multiple grids in
+// the page.
+
+const TEST_URI = `
+ <style type='text/css'>
+ .grid {
+ display: grid;
+ }
+ </style>
+ <div id="grid1" class="grid">
+ <div class="cell1">cell1</div>
+ <div class="cell2">cell2</div>
+ </div>
+ <div id="grid2" class="grid">
+ <div class="cell1">cell1</div>
+ <div class="cell2">cell2</div>
+ </div>
+`;
+
+const HIGHLIGHTER_TYPE = "CssGridHighlighter";
+
+add_task(function* () {
+ yield addTab("data:text/html;charset=utf-8," + encodeURIComponent(TEST_URI));
+ let { inspector, gridInspector, testActor } = yield openLayoutView();
+ let { document: doc } = gridInspector;
+ let { highlighters, store } = inspector;
+
+ yield selectNode("#grid1", inspector);
+ let gridList = doc.querySelector("#grid-list");
+ let checkbox1 = gridList.children[0].querySelector("input");
+ let checkbox2 = gridList.children[1].querySelector("input");
+
+ info("Checking the initial state of the Grid Inspector.");
+ is(gridList.childNodes.length, 2, "2 grid containers are listed.");
+ ok(!checkbox1.checked, `Grid item ${checkbox1.value} is unchecked in the grid list.`);
+ ok(!checkbox2.checked, `Grid item ${checkbox2.value} is unchecked in the grid list.`);
+ ok(!highlighters.highlighters[HIGHLIGHTER_TYPE],
+ "No CSS grid highlighter exists in the highlighters overlay.");
+ ok(!highlighters.gridHighlighterShown, "No CSS grid highlighter is shown.");
+
+ info("Toggling ON the CSS grid highlighter for #grid1.");
+ let onHighlighterShown = highlighters.once("grid-highlighter-shown");
+ let onCheckboxChange = waitUntilState(store, state =>
+ state.grids.length == 2 &&
+ state.grids[0].highlighted &&
+ !state.grids[1].highlighted);
+ checkbox1.click();
+ yield onHighlighterShown;
+ yield onCheckboxChange;
+
+ info("Checking the CSS grid highlighter is created.");
+ ok(highlighters.highlighters[HIGHLIGHTER_TYPE],
+ "CSS grid highlighter is created in the highlighters overlay.");
+ ok(highlighters.gridHighlighterShown, "CSS grid highlighter is shown.");
+
+ info("Toggling ON the CSS grid highlighter for #grid2.")
+ onHighlighterShown = highlighters.once("grid-highlighter-shown");
+ onCheckboxChange = waitUntilState(store, state =>
+ state.grids.length == 2 &&
+ !state.grids[0].highlighted &&
+ state.grids[1].highlighted);
+ checkbox2.click();
+ yield onHighlighterShown;
+ yield onCheckboxChange;
+
+ info("Checking the CSS grid highlighter is still shown.");
+ ok(highlighters.gridHighlighterShown, "CSS grid highlighter is shown.");
+
+ info("Toggling OFF the CSS grid highlighter from the layout panel.");
+ let onHighlighterHidden = highlighters.once("grid-highlighter-hidden");
+ onCheckboxChange = waitUntilState(store, state =>
+ state.grids.length == 2 &&
+ !state.grids[0].highlighted &&
+ !state.grids[1].highlighted);
+ checkbox2.click();
+ yield onHighlighterHidden;
+ yield onCheckboxChange;
+
+ info("Checking the CSS grid highlighter is not shown.");
+ ok(!highlighters.gridHighlighterShown, "No CSS grid highlighter is shown.");
+});
new file mode 100644
--- /dev/null
+++ b/devtools/client/inspector/grids/test/head.js
@@ -0,0 +1,67 @@
+/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+/* eslint no-unused-vars: [2, {"vars": "local"}] */
+/* import-globals-from ../../../framework/test/shared-head.js */
+/* import-globals-from ../../test/head.js */
+"use strict";
+
+// Import the inspector's head.js first (which itself imports shared-head.js).
+Services.scriptloader.loadSubScript(
+ "chrome://mochitests/content/browser/devtools/client/inspector/test/head.js",
+ this);
+
+// Load the shared Redux helpers into this compartment.
+Services.scriptloader.loadSubScript(
+ "chrome://mochitests/content/browser/devtools/client/framework/test/shared-redux-head.js",
+ this);
+
+Services.prefs.setBoolPref("devtools.layoutview.enabled", true);
+Services.prefs.setIntPref("devtools.toolbox.footer.height", 350);
+registerCleanupFunction(() => {
+ Services.prefs.clearUserPref("devtools.layoutview.enabled");
+ Services.prefs.clearUserPref("devtools.toolbox.footer.height");
+});
+
+/**
+ * Open the toolbox, with the inspector tool visible, and the layout view
+ * sidebar tab selected to display the box model view with properties.
+ *
+ * @return {Promise} a promise that resolves when the inspector is ready and the box model
+ * view is visible and ready.
+ */
+function openLayoutView() {
+ return openInspectorSidebarTab("layoutview").then(data => {
+ // The actual highligher show/hide methods are mocked in box model tests.
+ // The highlighter is tested in devtools/inspector/test.
+ function mockHighlighter({highlighter}) {
+ highlighter.showBoxModel = function () {
+ return promise.resolve();
+ };
+ highlighter.hideBoxModel = function () {
+ return promise.resolve();
+ };
+ }
+ mockHighlighter(data.toolbox);
+
+ return {
+ toolbox: data.toolbox,
+ inspector: data.inspector,
+ gridInspector: data.inspector.gridInspector,
+ testActor: data.testActor
+ };
+ });
+}
+
+/**
+ * * Simulate a color change in a given color picker tooltip.
+ */
+var simulateColorPickerChange = Task.async(function* (colorPicker, newRgba) {
+ info("Getting the spectrum colorpicker object");
+ let spectrum = yield colorPicker.spectrum;
+ info("Setting the new color");
+ spectrum.rgb = newRgba;
+ info("Applying the change");
+ spectrum.updateUI();
+ spectrum.onChange();
+});
--- a/devtools/client/inspector/rules/test/head.js
+++ b/devtools/client/inspector/rules/test/head.js
@@ -493,26 +493,16 @@ function waitForStyleModification(inspec
*/
function* clickSelectorIcon(icon, view) {
let onToggled = view.once("ruleview-selectorhighlighter-toggled");
EventUtils.synthesizeMouseAtCenter(icon, {}, view.styleWindow);
yield onToggled;
}
/**
- * Make sure window is properly focused before sending a key event.
- * @param {Window} win
- * @param {Event} key
- */
-function focusAndSendKey(win, key) {
- win.document.documentElement.focus();
- EventUtils.sendKey(key, win);
-}
-
-/**
* Toggle one of the checkboxes inside the class-panel. Resolved after the DOM mutation
* has been recorded.
* @param {CssRuleView} view The rule-view instance.
* @param {String} name The class name to find the checkbox.
*/
function* toggleClassPanelCheckBox(view, name) {
info(`Clicking on checkbox for class ${name}`);
const checkBox = [...view.classPanel.querySelectorAll("[type=checkbox]")].find(box => {
--- a/devtools/client/inspector/shared/highlighters-overlay.js
+++ b/devtools/client/inspector/shared/highlighters-overlay.js
@@ -262,28 +262,36 @@ HighlightersOverlay.prototype = {
/**
* Get a highlighter front given a type. It will only be initialized once.
*
* @param {String} type
* The highlighter type. One of this.highlighters.
* @return {Promise} that resolves to the highlighter
*/
- _getHighlighter: function (type) {
+ _getHighlighter: Task.async(function* (type) {
let utils = this.highlighterUtils;
if (this.highlighters[type]) {
- return promise.resolve(this.highlighters[type]);
+ return this.highlighters[type];
}
- return utils.getHighlighterByType(type).then(highlighter => {
- this.highlighters[type] = highlighter;
- return highlighter;
- });
- },
+ let highlighter;
+
+ try {
+ highlighter = yield utils.getHighlighterByType(type);
+ } catch (e) {}
+
+ if (!highlighter) {
+ return;
+ }
+
+ this.highlighters[type] = highlighter;
+ return highlighter;
+ }),
_handleRejection: function (error) {
if (!this.destroyed) {
console.error(error);
}
},
/**
--- a/devtools/client/inspector/test/head.js
+++ b/devtools/client/inspector/test/head.js
@@ -639,16 +639,26 @@ var waitForTab = Task.async(function* ()
*/
function synthesizeKeys(input, win) {
for (let key of input.split("")) {
EventUtils.synthesizeKey(key, {}, win);
}
}
/**
+ * Make sure window is properly focused before sending a key event.
+ * @param {Window} win
+ * @param {Event} key
+ */
+function focusAndSendKey(win, key) {
+ win.document.documentElement.focus();
+ EventUtils.sendKey(key, win);
+}
+
+/**
* Given a Tooltip instance, fake a mouse event on the `target` DOM Element
* and assert that the `tooltip` is correctly displayed.
*
* @param {Tooltip} tooltip
* The tooltip instance
* @param {DOMElement} target
* The DOM Element on which a tooltip should appear
*