Bug 1308260 - Part 6: Toggling the grid highlighter should emit the node that the grid highlighter was shown or hidden for and update the grid's highlighted state. r=pbro

This commit is contained in:
Gabriel Luong 2016-11-29 19:32:59 +08:00
Родитель 803f7e1e66
Коммит 5c701ce9da
11 изменённых файлов: 241 добавлений и 174 удалений

Просмотреть файл

@ -9,7 +9,10 @@ const { Task } = require("devtools/shared/task");
const { createFactory, createElement } = require("devtools/client/shared/vendor/react");
const { Provider } = require("devtools/client/shared/vendor/react-redux");
const { updateGrids } = require("./actions/grids");
const {
updateGridHighlighted,
updateGrids,
} = require("./actions/grids");
const App = createFactory(require("./components/App"));
const Store = require("./store");
@ -19,13 +22,17 @@ const INSPECTOR_L10N =
function LayoutView(inspector, window) {
this.document = window.document;
this.highlighters = inspector.highlighters;
this.inspector = inspector;
this.store = null;
this.walker = this.inspector.walker;
this.onGridLayoutChange = this.onGridLayoutChange.bind(this);
this.onHighlighterChange = this.onHighlighterChange.bind(this);
this.onSidebarSelect = this.onSidebarSelect.bind(this);
this.highlighters.on("grid-highlighter-hidden", this.onHighlighterChange);
this.highlighters.on("grid-highlighter-shown", this.onHighlighterChange);
this.inspector.sidebar.on("select", this.onSidebarSelect);
this.init();
@ -67,6 +74,8 @@ LayoutView.prototype = {
* and cleans up references.
*/
destroy() {
this.highlighters.off("grid-highlighter-hidden", this.onHighlighterChange);
this.highlighters.off("grid-highlighter-shown", this.onHighlighterChange);
this.inspector.sidebar.off("select", this.onSidebarSelect);
this.layoutInspector.off("grid-layout-changed", this.onGridLayoutChange);
@ -111,8 +120,9 @@ LayoutView.prototype = {
grids.push({
id: i,
gridFragments: grid.gridFragments,
highlighted: nodeFront == this.highlighters.gridHighlighterShown,
nodeFront,
gridFragments: grid.gridFragments
});
}
@ -120,7 +130,7 @@ LayoutView.prototype = {
}),
/**
* Handler for 'grid-layout-changed' events emitted from the LayoutActor.
* Handler for "grid-layout-changed" events emitted from the LayoutActor.
*
* @param {Array} grids
* Array of all GridFront in the current page.
@ -131,6 +141,21 @@ LayoutView.prototype = {
}
},
/**
* Handler for "grid-highlighter-shown" and "grid-highlighter-hidden" events emitted
* from the HighlightersOverlay. Updates the NodeFront's grid highlighted state.
*
* @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.
*/
onHighlighterChange(event, nodeFront) {
let highlighted = event === "grid-highlighter-shown";
this.store.dispatch(updateGridHighlighted(nodeFront, highlighted));
},
/**
* Handler for the inspector sidebar select event. Starts listening for
* "grid-layout-changed" if the layout panel is visible. Otherwise, stop

Просмотреть файл

@ -29,13 +29,13 @@ add_task(function* () {
let gridToggle = container.querySelector(".ruleview-grid");
info("Toggling ON the CSS grid highlighter from the rule-view.");
let onHighlighterShown = highlighters.once("highlighter-shown");
let onHighlighterShown = highlighters.once("grid-highlighter-shown");
gridToggle.click();
yield onHighlighterShown;
info("Edit the 'grid' property value to 'block'.");
let editor = yield focusEditableField(view, container);
let onHighlighterHidden = highlighters.once("highlighter-hidden");
let onHighlighterHidden = highlighters.once("grid-highlighter-hidden");
let onDone = view.once("ruleview-changed");
editor.input.value = "block;";
EventUtils.synthesizeKey("VK_RETURN", {}, view.styleWindow);

Просмотреть файл

@ -30,7 +30,7 @@ add_task(function* () {
let gridToggle = container.querySelector(".ruleview-grid");
info("Toggling ON the CSS grid highlighter from the rule-view.");
let onHighlighterShown = highlighters.once("highlighter-shown");
let onHighlighterShown = highlighters.once("grid-highlighter-shown");
gridToggle.click();
yield onHighlighterShown;

Просмотреть файл

@ -39,7 +39,7 @@ add_task(function* () {
ok(!highlighters.gridHighlighterShown, "No CSS grid highlighter is shown.");
info("Toggling ON the CSS grid highlighter from the rule-view.");
let onHighlighterShown = highlighters.once("highlighter-shown");
let onHighlighterShown = highlighters.once("grid-highlighter-shown");
gridToggle.click();
yield onHighlighterShown;
@ -52,7 +52,7 @@ add_task(function* () {
ok(highlighters.gridHighlighterShown, "CSS grid highlighter is shown.");
info("Toggling OFF the CSS grid highlighter from the rule-view.");
let onHighlighterHidden = highlighters.once("highlighter-hidden");
let onHighlighterHidden = highlighters.once("grid-highlighter-hidden");
gridToggle.click();
yield onHighlighterHidden;

Просмотреть файл

@ -45,7 +45,7 @@ add_task(function* () {
ok(!highlighters.gridHighlighterShown, "No CSS grid highlighter is shown.");
info("Toggling ON the CSS grid highlighter from the overridden rule in the rule-view.");
let onHighlighterShown = highlighters.once("highlighter-shown");
let onHighlighterShown = highlighters.once("grid-highlighter-shown");
overriddenGridToggle.click();
yield onHighlighterShown;
@ -60,7 +60,7 @@ add_task(function* () {
info("Toggling off the CSS grid highlighter from the normal grid declaration in the " +
"rule-view.");
let onHighlighterHidden = highlighters.once("highlighter-hidden");
let onHighlighterHidden = highlighters.once("grid-highlighter-hidden");
gridToggle.click();
yield onHighlighterHidden;

Просмотреть файл

@ -45,7 +45,7 @@ add_task(function* () {
info("Toggling ON the CSS grid highlighter for the first grid container from the " +
"rule-view.");
let onHighlighterShown = highlighters.once("highlighter-shown");
let onHighlighterShown = highlighters.once("grid-highlighter-shown");
gridToggle.click();
yield onHighlighterShown;
@ -72,7 +72,7 @@ add_task(function* () {
info("Toggling ON the CSS grid highlighter for the second grid container from the " +
"rule-view.");
onHighlighterShown = highlighters.once("highlighter-shown");
onHighlighterShown = highlighters.once("grid-highlighter-shown");
gridToggle.click();
yield onHighlighterShown;

Просмотреть файл

@ -736,7 +736,7 @@ TextPropertyEditor.prototype = {
}
if (this.isDisplayGrid()) {
this.ruleView.highlighters._hideGridHighlighter();
this.ruleView.highlighters.hideGridHighlighter();
}
// First, set this property value (common case, only modified a property)

Просмотреть файл

@ -6,12 +6,8 @@
"use strict";
/**
* The highlighter overlays are in-content highlighters that appear when hovering over
* property values.
*/
const promise = require("promise");
const {Task} = require("devtools/shared/task");
const EventEmitter = require("devtools/shared/event-emitter");
const { VIEW_NODE_VALUE_TYPE } = require("devtools/client/inspector/shared/node-types");
@ -36,10 +32,10 @@ function HighlightersOverlay(inspector) {
// Name of the selector highlighter shown.
this.selectorHighlighterShown = null;
this._onClick = this._onClick.bind(this);
this._onMouseMove = this._onMouseMove.bind(this);
this._onMouseOut = this._onMouseOut.bind(this);
this._onWillNavigate = this._onWillNavigate.bind(this);
this.onClick = this.onClick.bind(this);
this.onMouseMove = this.onMouseMove.bind(this);
this.onMouseOut = this.onMouseOut.bind(this);
this.onWillNavigate = this.onWillNavigate.bind(this);
EventEmitter.decorate(this);
}
@ -63,12 +59,12 @@ HighlightersOverlay.prototype = {
}
let el = view.element;
el.addEventListener("click", this._onClick, true);
el.addEventListener("mousemove", this._onMouseMove, false);
el.addEventListener("mouseout", this._onMouseOut, false);
el.ownerDocument.defaultView.addEventListener("mouseout", this._onMouseOut, false);
el.addEventListener("click", this.onClick, true);
el.addEventListener("mousemove", this.onMouseMove, false);
el.addEventListener("mouseout", this.onMouseOut, false);
el.ownerDocument.defaultView.addEventListener("mouseout", this.onMouseOut, false);
this.inspector.target.on("will-navigate", this._onWillNavigate);
this.inspector.target.on("will-navigate", this.onWillNavigate);
},
/**
@ -85,49 +81,191 @@ HighlightersOverlay.prototype = {
}
let el = view.element;
el.removeEventListener("click", this._onClick, true);
el.removeEventListener("mousemove", this._onMouseMove, false);
el.removeEventListener("mouseout", this._onMouseOut, false);
el.removeEventListener("click", this.onClick, true);
el.removeEventListener("mousemove", this.onMouseMove, false);
el.removeEventListener("mouseout", this.onMouseOut, false);
this.inspector.target.off("will-navigate", this._onWillNavigate);
this.inspector.target.off("will-navigate", this.onWillNavigate);
},
_onClick: function (event) {
/**
* Toggle the grid highlighter for the given grid container element.
*
* @param {NodeFront} node
* The NodeFront of the grid container element to highlight.
* @param {Object} options
* Object used for passing options to the grid highlighter.
*/
toggleGridHighlighter: Task.async(function* (node, options = {}) {
if (node == this.gridHighlighterShown) {
yield this.hideGridHighlighter(node);
return;
}
yield this.showGridHighlighter(node, options);
}),
/**
* Show the grid highlighter for the given grid container element.
*
* @param {NodeFront} node
* The NodeFront of the grid container element to highlight.
* @param {Object} options
* Object used for passing options to the grid highlighter.
*/
showGridHighlighter: Task.async(function* (node, options) {
let highlighter = yield this._getHighlighter("CssGridHighlighter");
if (!highlighter) {
return;
}
let isShown = yield highlighter.show(node, options);
if (!isShown) {
return;
}
this._toggleRuleViewGridIcon(node, true);
// Emit the NodeFront of the grid container element that the grid highlighter was
// shown for.
this.emit("grid-highlighter-shown", node);
this.gridHighlighterShown = node;
}),
/**
* Hide the grid highlighter for the given grid container element.
*
* @param {NodeFront} node
* The NodeFront of the grid container element to unhighlight.
*/
hideGridHighlighter: Task.async(function* (node) {
if (!this.gridHighlighterShown || !this.highlighters.CssGridHighlighter) {
return;
}
this._toggleRuleViewGridIcon(node, false);
yield this.highlighters.CssGridHighlighter.hide();
// Emit the NodeFront of the grid container element that the grid highlighter was
// hidden for.
this.emit("grid-highlighter-hidden", this.gridHighlighterShown);
this.gridHighlighterShown = null;
}),
/**
* 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) {
let utils = this.highlighterUtils;
if (this.highlighters[type]) {
return promise.resolve(this.highlighters[type]);
}
return utils.getHighlighterByType(type).then(highlighter => {
this.highlighters[type] = highlighter;
return highlighter;
});
},
/**
* Toggle all the grid icons in the rule view if the current inspector selection is the
* highlighted node.
*
* @param {NodeFront} node
* The NodeFront of the grid container element to highlight.
* @param {Boolean} active
* Whether or not the grid icon should be active.
*/
_toggleRuleViewGridIcon: function (node, active) {
if (this.inspector.selection.nodeFront != node) {
return;
}
let ruleViewEl = this.inspector.ruleview.view.element;
for (let gridIcon of ruleViewEl.querySelectorAll(".ruleview-grid")) {
gridIcon.classList.toggle("active", active);
}
},
/**
* Hide the currently shown hovered highlighter.
*/
_hideHoveredHighlighter: function () {
if (!this.hoveredHighlighterShown ||
!this.highlighters[this.hoveredHighlighterShown]) {
return;
}
// For some reason, the call to highlighter.hide doesn't always return a
// promise. This causes some tests to fail when trying to install a
// rejection handler on the result of the call. To avoid this, check
// whether the result is truthy before installing the handler.
let onHidden = this.highlighters[this.hoveredHighlighterShown].hide();
if (onHidden) {
onHidden.then(null, e => console.error(e));
}
this.hoveredHighlighterShown = null;
this.emit("highlighter-hidden");
},
/**
* Is the current hovered node a css transform property value in the
* computed-view.
*
* @param {Object} nodeInfo
* @return {Boolean}
*/
_isComputedViewTransform: function (nodeInfo) {
let isTransform = nodeInfo.type === VIEW_NODE_VALUE_TYPE &&
nodeInfo.value.property === "transform";
return !this.isRuleView && isTransform;
},
/**
* Is the current clicked node a grid display property value in the
* rule-view.
*
* @param {DOMNode} node
* @return {Boolean}
*/
_isRuleViewDisplayGrid: function (node) {
return this.isRuleView && node.classList.contains("ruleview-grid");
},
/**
* Is the current hovered node a css transform property value in the rule-view.
*
* @param {Object} nodeInfo
* @return {Boolean}
*/
_isRuleViewTransform: function (nodeInfo) {
let isTransform = nodeInfo.type === VIEW_NODE_VALUE_TYPE &&
nodeInfo.value.property === "transform";
let isEnabled = nodeInfo.value.enabled &&
!nodeInfo.value.overridden &&
!nodeInfo.value.pseudoElement;
return this.isRuleView && isTransform && isEnabled;
},
onClick: function (event) {
// Bail out if the target is not a grid property value.
if (!this._isRuleViewDisplayGrid(event.target)) {
return;
}
event.stopPropagation();
this._getHighlighter("CssGridHighlighter").then(highlighter => {
let node = this.inspector.selection.nodeFront;
// Toggle off the grid highlighter if the grid highlighter toggle is clicked
// for the current highlighted grid.
if (node === this.gridHighlighterShown) {
return highlighter.hide();
}
return highlighter.show(node);
}).then(isGridShown => {
// Toggle all the grid icons in the current rule view.
let ruleViewEl = this.inspector.ruleview.view.element;
for (let gridIcon of ruleViewEl.querySelectorAll(".ruleview-grid")) {
gridIcon.classList.toggle("active", isGridShown);
}
if (isGridShown) {
this.gridHighlighterShown = this.inspector.selection.nodeFront;
this.emit("highlighter-shown");
} else {
this.gridHighlighterShown = null;
this.emit("highlighter-hidden");
}
}).catch(e => console.error(e));
this.toggleGridHighlighter(this.inspector.selection.nodeFront);
},
_onMouseMove: function (event) {
onMouseMove: function (event) {
// Bail out if the target is the same as for the last mousemove.
if (event.target === this._lastHovered) {
return;
@ -165,7 +303,7 @@ HighlightersOverlay.prototype = {
}
},
_onMouseOut: function (event) {
onMouseOut: function (event) {
// Only hide the highlighter if the mouse leaves the currently hovered node.
if (!this._lastHovered ||
(event && this._lastHovered.contains(event.relatedTarget))) {
@ -180,110 +318,12 @@ HighlightersOverlay.prototype = {
/**
* Clear saved highlighter shown properties on will-navigate.
*/
_onWillNavigate: function () {
onWillNavigate: function () {
this.gridHighlighterShown = null;
this.hoveredHighlighterShown = null;
this.selectorHighlighterShown = null;
},
/**
* Is the current hovered node a css transform property value in the rule-view.
*
* @param {Object} nodeInfo
* @return {Boolean}
*/
_isRuleViewTransform: function (nodeInfo) {
let isTransform = nodeInfo.type === VIEW_NODE_VALUE_TYPE &&
nodeInfo.value.property === "transform";
let isEnabled = nodeInfo.value.enabled &&
!nodeInfo.value.overridden &&
!nodeInfo.value.pseudoElement;
return this.isRuleView && isTransform && isEnabled;
},
/**
* Is the current hovered node a css transform property value in the
* computed-view.
*
* @param {Object} nodeInfo
* @return {Boolean}
*/
_isComputedViewTransform: function (nodeInfo) {
let isTransform = nodeInfo.type === VIEW_NODE_VALUE_TYPE &&
nodeInfo.value.property === "transform";
return !this.isRuleView && isTransform;
},
/**
* Is the current clicked node a grid display property value in the
* rule-view.
*
* @param {DOMNode} node
* @return {Boolean}
*/
_isRuleViewDisplayGrid: function (node) {
return this.isRuleView && node.classList.contains("ruleview-grid");
},
/**
* Hide the currently shown grid highlighter.
*/
_hideGridHighlighter: function () {
if (!this.gridHighlighterShown || !this.highlighters.CssGridHighlighter) {
return;
}
let onHidden = this.highlighters.CssGridHighlighter.hide();
if (onHidden) {
onHidden.then(null, e => console.error(e));
}
this.gridHighlighterShown = null;
this.emit("highlighter-hidden");
},
/**
* Hide the currently shown hovered highlighter.
*/
_hideHoveredHighlighter: function () {
if (!this.hoveredHighlighterShown ||
!this.highlighters[this.hoveredHighlighterShown]) {
return;
}
// For some reason, the call to highlighter.hide doesn't always return a
// promise. This causes some tests to fail when trying to install a
// rejection handler on the result of the call. To avoid this, check
// whether the result is truthy before installing the handler.
let onHidden = this.highlighters[this.hoveredHighlighterShown].hide();
if (onHidden) {
onHidden.then(null, e => console.error(e));
}
this.hoveredHighlighterShown = null;
this.emit("highlighter-hidden");
},
/**
* 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) {
let utils = this.highlighterUtils;
if (this.highlighters[type]) {
return promise.resolve(this.highlighters[type]);
}
return utils.getHighlighterByType(type).then(highlighter => {
this.highlighters[type] = highlighter;
return highlighter;
});
},
/**
* Destroy this overlay instance, removing it from the view and destroying
* all initialized highlighters.
@ -296,6 +336,8 @@ HighlightersOverlay.prototype = {
}
}
this._lastHovered = null;
this.inspector = null;
this.highlighters = null;
this.highlighterUtils = null;

Просмотреть файл

@ -28,13 +28,13 @@ add_task(function* () {
info("Faking a mousemove on a non-transform property");
let {valueSpan} = getRuleViewProperty(view, "body", "color");
hs._onMouseMove({target: valueSpan});
hs.onMouseMove({target: valueSpan});
ok(!hs.highlighters[TYPE], "No highlighter exists in the rule-view (2)");
info("Faking a mousemove on a transform property");
({valueSpan} = getRuleViewProperty(view, "body", "transform"));
let onHighlighterShown = hs.once("highlighter-shown");
hs._onMouseMove({target: valueSpan});
hs.onMouseMove({target: valueSpan});
yield onHighlighterShown;
let onComputedViewReady = inspector.once("computed-view-refreshed");
@ -48,13 +48,13 @@ add_task(function* () {
info("Faking a mousemove on a non-transform property");
({valueSpan} = getComputedViewProperty(cView, "color"));
hs._onMouseMove({target: valueSpan});
hs.onMouseMove({target: valueSpan});
ok(!hs.highlighters[TYPE], "No highlighter exists in the computed-view (3)");
info("Faking a mousemove on a transform property");
({valueSpan} = getComputedViewProperty(cView, "transform"));
onHighlighterShown = hs.once("highlighter-shown");
hs._onMouseMove({target: valueSpan});
hs.onMouseMove({target: valueSpan});
yield onHighlighterShown;
ok(hs.highlighters[TYPE],

Просмотреть файл

@ -56,11 +56,11 @@ add_task(function* () {
info("Checking that the HighlighterFront's show/hide methods are called");
let onHighlighterShown = hs.once("highlighter-shown");
hs._onMouseMove({target: valueSpan});
hs.onMouseMove({target: valueSpan});
yield onHighlighterShown;
ok(HighlighterFront.isShown, "The highlighter is shown");
let onHighlighterHidden = hs.once("highlighter-hidden");
hs._onMouseOut();
hs.onMouseOut();
yield onHighlighterHidden;
ok(!HighlighterFront.isShown, "The highlighter is hidden");
@ -68,11 +68,11 @@ add_task(function* () {
" show the highlighter several times");
let nb = HighlighterFront.nbOfTimesShown;
onHighlighterShown = hs.once("highlighter-shown");
hs._onMouseMove({target: valueSpan});
hs.onMouseMove({target: valueSpan});
yield onHighlighterShown;
is(HighlighterFront.nbOfTimesShown, nb + 1, "The highlighter was shown once");
hs._onMouseMove({target: valueSpan});
hs._onMouseMove({target: valueSpan});
hs.onMouseMove({target: valueSpan});
hs.onMouseMove({target: valueSpan});
is(HighlighterFront.nbOfTimesShown, nb + 1,
"The highlighter was shown once, after several mousemove");
@ -80,7 +80,7 @@ add_task(function* () {
yield selectNode("html", inspector);
({valueSpan} = getRuleViewProperty(view, "html", "transform"));
onHighlighterShown = hs.once("highlighter-shown");
hs._onMouseMove({target: valueSpan});
hs.onMouseMove({target: valueSpan});
yield onHighlighterShown;
is(HighlighterFront.nodeFront.tagName, "HTML",
"The right NodeFront is passed to the highlighter (1)");
@ -88,7 +88,7 @@ add_task(function* () {
yield selectNode("body", inspector);
({valueSpan} = getRuleViewProperty(view, "body", "transform"));
onHighlighterShown = hs.once("highlighter-shown");
hs._onMouseMove({target: valueSpan});
hs.onMouseMove({target: valueSpan});
yield onHighlighterShown;
is(HighlighterFront.nodeFront.tagName, "BODY",
"The right NodeFront is passed to the highlighter (2)");
@ -97,7 +97,7 @@ add_task(function* () {
"non-transform property");
({valueSpan} = getRuleViewProperty(view, "body", "color"));
onHighlighterHidden = hs.once("highlighter-hidden");
hs._onMouseMove({target: valueSpan});
hs.onMouseMove({target: valueSpan});
yield onHighlighterHidden;
ok(!HighlighterFront.isShown, "The highlighter is hidden");
});

Просмотреть файл

@ -36,7 +36,7 @@ add_task(function* () {
info("Faking a mousemove on the overriden property");
let {valueSpan} = getRuleViewProperty(view, "div", "transform");
hs._onMouseMove({target: valueSpan});
hs.onMouseMove({target: valueSpan});
ok(!hs.highlighters[TYPE],
"No highlighter was created for the overriden property");
@ -48,13 +48,13 @@ add_task(function* () {
info("Faking a mousemove on the disabled property");
({valueSpan} = getRuleViewProperty(view, ".test", "transform"));
hs._onMouseMove({target: valueSpan});
hs.onMouseMove({target: valueSpan});
ok(!hs.highlighters[TYPE],
"No highlighter was created for the disabled property");
info("Faking a mousemove on the now unoverriden property");
({valueSpan} = getRuleViewProperty(view, "div", "transform"));
let onHighlighterShown = hs.once("highlighter-shown");
hs._onMouseMove({target: valueSpan});
hs.onMouseMove({target: valueSpan});
yield onHighlighterShown;
});