Bug 1414275 - Part 2: Toggle flexbox layout highlighter from the rule view next to 'display: flex|inline-flex' declarations. r=pbro

This commit is contained in:
Gabriel Luong 2017-11-13 10:01:20 -05:00
Родитель 986ddf7712
Коммит 6339f7df3a
7 изменённых файлов: 240 добавлений и 57 удалений

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

@ -968,6 +968,7 @@ Inspector.prototype = {
// Restore the highlighter states prior to emitting "new-root".
yield Promise.all([
this.highlighters.restoreFlexboxState(),
this.highlighters.restoreGridState(),
this.highlighters.restoreShapeState()
]);

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

@ -360,6 +360,7 @@ TextPropertyEditor.prototype = {
colorSwatchClass: SHARED_SWATCH_CLASS + " " + COLOR_SWATCH_CLASS,
filterClass: "ruleview-filter",
filterSwatchClass: SHARED_SWATCH_CLASS + " " + FILTER_SWATCH_CLASS,
flexClass: "ruleview-flex",
gridClass: "ruleview-grid",
shapeClass: "ruleview-shape",
defaultColorType: !propDirty,
@ -439,6 +440,15 @@ TextPropertyEditor.prototype = {
}
}
let flexToggle = this.valueSpan.querySelector(".ruleview-flex");
if (flexToggle) {
flexToggle.setAttribute("title", l10n("rule.flexToggle.tooltip"));
if (this.ruleView.highlighters.flexboxHighlighterShown ===
this.ruleView.inspector.selection.nodeFront) {
flexToggle.classList.add("active");
}
}
let gridToggle = this.valueSpan.querySelector(".ruleview-grid");
if (gridToggle) {
gridToggle.setAttribute("title", l10n("rule.gridToggle.tooltip"));
@ -800,6 +810,7 @@ TextPropertyEditor.prototype = {
!parsedProperties.propertiesToAdd.length &&
this.committed.value === val.value &&
this.committed.priority === val.priority;
// If the value is not empty and unchanged, revert the property back to
// its original value and enabled or disabled state
if (value.trim() && isValueUnchanged) {
@ -809,6 +820,12 @@ TextPropertyEditor.prototype = {
return;
}
// Since the value was changed, check if the original propertywas a flex or grid
// display declaration and hide their respective highlighters.
if (this.isDisplayFlex()) {
this.ruleView.highlighters.hideFlexboxHighlighter();
}
if (this.isDisplayGrid()) {
this.ruleView.highlighters.hideGridHighlighter();
}
@ -941,6 +958,16 @@ TextPropertyEditor.prototype = {
return this.prop.isValid();
},
/**
* Returns true if the property is a `display: [inline-]flex` declaration.
*
* @return {Boolean} true if the property is a `display: [inline-]flex` declaration.
*/
isDisplayFlex: function () {
return this.prop.name === "display" &&
(this.prop.value === "flex" || this.prop.value === "inline-flex");
},
/**
* Returns true if the property is a `display: [inline-]grid` declaration.
*
@ -948,8 +975,7 @@ TextPropertyEditor.prototype = {
*/
isDisplayGrid: function () {
return this.prop.name === "display" &&
(this.prop.value === "grid" ||
this.prop.value === "inline-grid");
(this.prop.value === "grid" || this.prop.value === "inline-grid");
},
/**

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

@ -20,7 +20,6 @@ const INSET_POINT_TYPES = ["top", "right", "bottom", "left"];
* Highlighters overlay is a singleton managing all highlighters in the Inspector.
*/
class HighlightersOverlay {
/**
* @param {Inspector} inspector
* Inspector toolbox panel.
@ -33,6 +32,8 @@ class HighlightersOverlay {
// Only initialize the overlay if at least one of the highlighter types is supported.
this.supportsHighlighters = this.highlighterUtils.supportsCustomHighlighters();
// NodeFront of the flexbox container that is highlighted.
this.flexboxHighlighterShown = null;
// NodeFront of element that is highlighted by the geometry editor.
this.geometryEditorHighlighterShown = null;
// NodeFront of the grid container that is highlighted.
@ -45,8 +46,9 @@ class HighlightersOverlay {
this.shapesHighlighterShown = null;
// Saved state to be restore on page navigation.
this.state = {
flexbox: {},
grid: {},
shapes: {}
shapes: {},
};
this.onClick = this.onClick.bind(this);
@ -54,6 +56,10 @@ class HighlightersOverlay {
this.onMouseMove = this.onMouseMove.bind(this);
this.onMouseOut = this.onMouseOut.bind(this);
this.onWillNavigate = this.onWillNavigate.bind(this);
this.hideFlexboxHighlighter = this.hideFlexboxHighlighter.bind(this);
this.hideGridHighlighter = this.hideGridHighlighter.bind(this);
this.hideShapesHighlighter = this.hideShapesHighlighter.bind(this);
this.showFlexboxHighlighter = this.showFlexboxHighlighter.bind(this);
this.showGridHighlighter = this.showGridHighlighter.bind(this);
this.showShapesHighlighter = this.showShapesHighlighter.bind(this);
this._handleRejection = this._handleRejection.bind(this);
@ -237,6 +243,83 @@ class HighlightersOverlay {
}
}
/**
* Toggle the flexbox highlighter for the given flexbox container element.
*
* @param {NodeFront} node
* The NodeFront of the flexbox container element to highlight.
* @param {Object} options
* Object used for passing options to the flexbox highlighter.
*/
async toggleFlexboxHighlighter(node, options = {}) {
if (node == this.flexboxHighlighterShown) {
await this.hideFlexboxHighlighter(node);
return;
}
await this.showFlexboxHighlighter(node, options);
}
/**
* Show the flexbox highlighter for the given flexbox container element.
*
* @param {NodeFront} node
* The NodeFront of the flexbox container element to highlight.
* @param {Object} options
* Object used for passing options to the flexbox highlighter.
*/
async showFlexboxHighlighter(node, options) {
let highlighter = await this._getHighlighter("FlexboxHighlighter");
if (!highlighter) {
return;
}
let isShown = await highlighter.show(node, options);
if (!isShown) {
return;
}
this._toggleRuleViewIcon(node, true, ".ruleview-flex");
try {
// Save flexbox highlighter state.
let { url } = this.inspector.target;
let selector = await node.getUniqueSelector();
this.state.flexbox = { selector, options, url };
this.flexboxHighlighterShown = node;
// Emit the NodeFront of the flexbox container element that the flexbox highlighter
// was shown for.
this.emit("flexbox-highlighter-shown", node, options);
} catch (e) {
this._handleRejection(e);
}
}
/**
* Hide the flexbox highlighter for the given flexbox container element.
*
* @param {NodeFront} node
* The NodeFront of the flexbox container element to unhighlight.
*/
async hideFlexboxHighlighter(node) {
if (!this.flexboxHighlighterShown || !this.highlighters.FlexboxHighlighter) {
return;
}
this._toggleRuleViewIcon(node, false, ".ruleview-flex");
await this.highlighters.FlexboxHighlighter.hide();
// Emit the NodeFront of the flexbox container element that the flexbox highlighter
// was hidden for.
this.emit("flexbox-highlighter-hidden", this.flexboxHighlighterShown);
this.flexboxHighlighterShown = null;
// Erase flexbox highlighter state.
this.state.flexbox = null;
}
/**
* Toggle the grid highlighter for the given grid container element.
*
@ -393,6 +476,17 @@ class HighlightersOverlay {
this.emit("highlighter-event-handled");
}
/**
* Restores the saved flexbox highlighter state.
*/
async restoreFlexboxState() {
try {
await this.restoreState("flexbox", this.state.flexbox, this.showFlexboxHighlighter);
} catch (e) {
this._handleRejection(e);
}
}
/**
* Restores the saved grid highlighter state.
*/
@ -416,8 +510,9 @@ class HighlightersOverlay {
}
/**
* Helper function called by restoreGridState and restoreShapeState.
* Restores the saved highlighter state for the given highlighter and their state.
* Helper function called by restoreFlexboxState, restoreGridState and
* restoreShapeState. Restores the saved highlighter state for the given highlighter
* and their state.
*
* @param {String} name
* The name of the highlighter to be restored
@ -552,6 +647,31 @@ class HighlightersOverlay {
this.emit("highlighter-hidden");
}
/**
* Given a node front and a function that hides the given node's highlighter, hides
* the highlighter if the node front is no longer in the DOM tree. This is called
* from the "markupmutation" event handler.
*
* @param {NodeFront} node
* The NodeFront of a highlighted DOM node.
* @param {Function} hideHighlighter
* The function that will hide the highlighter of the highlighted node.
*/
async _hideHighlighterIfDeadNode(node, hideHighlighter) {
if (!node) {
return;
}
try {
let isInTree = await this.inspector.walker.isInDOMTree(node);
if (!isInTree) {
hideHighlighter(node);
}
} catch (e) {
console.error(e);
}
}
/**
* Is the current hovered node a css transform property value in the
* computed-view.
@ -565,6 +685,17 @@ class HighlightersOverlay {
return !this.isRuleView && isTransform;
}
/**
* Is the current clicked node a flex display property value in the
* rule-view.
*
* @param {DOMNode} node
* @return {Boolean}
*/
_isRuleViewDisplayFlex(node) {
return this.isRuleView && node.classList.contains("ruleview-flex");
}
/**
* Is the current clicked node a grid display property value in the
* rule-view.
@ -631,6 +762,10 @@ class HighlightersOverlay {
this.toggleGridHighlighter(this.inspector.selection.nodeFront, highlighterSettings,
"rule");
} else if (this._isRuleViewDisplayFlex(event.target)) {
event.stopPropagation();
this.toggleFlexboxHighlighter(this.inspector.selection.nodeFront);
} else if (this._isRuleViewShape(event.target)) {
event.stopPropagation();
@ -709,8 +844,8 @@ class HighlightersOverlay {
}
/**
* Handler function for "markupmutation" events. Hides the grid/shapes highlighter
* if the grid/shapes container is no longer in the DOM tree.
* Handler function for "markupmutation" events. Hides the flexbox/grid/shapes
* highlighter if the flexbox/grid/shapes container is no longer in the DOM tree.
*/
async onMarkupMutation(evt, mutations) {
let hasInterestingMutation = mutations.some(mut => mut.type === "childList");
@ -720,37 +855,19 @@ class HighlightersOverlay {
return;
}
if (this.gridHighlighterShown) {
let nodeFront = this.gridHighlighterShown;
try {
let isInTree = await this.inspector.walker.isInDOMTree(nodeFront);
if (!isInTree) {
this.hideGridHighlighter(nodeFront);
}
} catch (e) {
console.error(e);
}
}
if (this.shapesHighlighterShown) {
let nodeFront = this.shapesHighlighterShown;
try {
let isInTree = await this.inspector.walker.isInDOMTree(nodeFront);
if (!isInTree) {
this.hideShapesHighlighter(nodeFront);
}
} catch (e) {
console.error(e);
}
}
this._hideHighlighterIfDeadNode(this.flexboxHighlighterShown,
this.hideFlexboxHighlighter);
this._hideHighlighterIfDeadNode(this.gridHighlighterShown,
this.hideGridHighlighter);
this._hideHighlighterIfDeadNode(this.shapesHighlighterShown,
this.hideShapesHighlighter);
}
/**
* Clear saved highlighter shown properties on will-navigate.
*/
onWillNavigate() {
this.flexboxHighlighterShown = null;
this.geometryEditorHighlighterShown = null;
this.gridHighlighterShown = null;
this.hoveredHighlighterShown = null;
@ -785,6 +902,7 @@ class HighlightersOverlay {
this.supportsHighlighters = null;
this.state = null;
this.flexboxHighlighterShown = null;
this.geometryEditorHighlighterShown = null;
this.gridHighlighterShown = null;
this.hoveredHighlighterShown = null;
@ -793,7 +911,6 @@ class HighlightersOverlay {
this.destroyed = true;
}
}
module.exports = HighlightersOverlay;

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

@ -58,13 +58,15 @@ pref("devtools.inspector.showUserAgentStyles", false);
pref("devtools.inspector.showAllAnonymousContent", false);
// Enable the new color widget
pref("devtools.inspector.colorWidget.enabled", false);
// Enable the Flexbox highlighter
pref("devtools.inspector.flexboxHighlighter.enabled", false);
// Enable the CSS shapes highlighter
pref("devtools.inspector.shapesHighlighter.enabled", true);
// Enable the Changes View
pref("devtools.changesview.enabled", false);
// Enable the Events View
pref("devtools.eventsview.enabled", false);
// Enable the Flexbox Inspector
// Enable the Flexbox Inspector panel
pref("devtools.flexboxinspector.enabled", false);
// Enable the new Animation Inspector

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

@ -4,6 +4,13 @@
"use strict";
const Services = require("Services");
const {angleUtils} = require("devtools/client/shared/css-angle");
const {colorUtils} = require("devtools/shared/css/color");
const {getCSSLexer} = require("devtools/shared/css/lexer");
const EventEmitter = require("devtools/shared/old-event-emitter");
const {appendText} = require("devtools/client/inspector/shared/utils");
loader.lazyRequireGetter(this, "ANGLE_TAKING_FUNCTIONS",
"devtools/shared/css/properties-db", true);
loader.lazyRequireGetter(this, "BASIC_SHAPE_FUNCTIONS",
@ -15,18 +22,13 @@ loader.lazyRequireGetter(this, "COLOR_TAKING_FUNCTIONS",
loader.lazyRequireGetter(this, "CSS_TYPES",
"devtools/shared/css/properties-db", true);
const {angleUtils} = require("devtools/client/shared/css-angle");
const {colorUtils} = require("devtools/shared/css/color");
const {getCSSLexer} = require("devtools/shared/css/lexer");
const EventEmitter = require("devtools/shared/old-event-emitter");
const {appendText} = require("devtools/client/inspector/shared/utils");
const Services = require("Services");
const STYLE_INSPECTOR_PROPERTIES = "devtools/shared/locales/styleinspector.properties";
const {LocalizationHelper} = require("devtools/shared/l10n");
const STYLE_INSPECTOR_L10N = new LocalizationHelper(STYLE_INSPECTOR_PROPERTIES);
const HTML_NS = "http://www.w3.org/1999/xhtml";
const FLEXBOX_HIGHLIGHTER_ENABLED_PREF = "devtools.inspector.flexboxHighlighter.enabled";
const CSS_SHAPES_ENABLED_PREF = "devtools.inspector.shapesHighlighter.enabled";
const CSS_SHAPE_OUTSIDE_ENABLED_PREF = "layout.css.shape-outside.enabled";
@ -370,8 +372,11 @@ OutputParser.prototype = {
if (options.expectCubicBezier &&
BEZIER_KEYWORDS.indexOf(token.text) >= 0) {
this._appendCubicBezier(token.text, options);
} else if (this._isDisplayFlex(text, token, options) &&
Services.prefs.getBoolPref(FLEXBOX_HIGHLIGHTER_ENABLED_PREF)) {
this._appendHighlighterToggle(token.text, options.flexClass);
} else if (this._isDisplayGrid(text, token, options)) {
this._appendGrid(token.text, options);
this._appendHighlighterToggle(token.text, options.gridClass);
} else if (colorOK() &&
colorUtils.isValidCSSColor(token.text, this.cssColor4)) {
this._appendColor(token.text, options);
@ -472,14 +477,29 @@ OutputParser.prototype = {
},
/**
* Return true if it's a display:[inline-]grid token.
* Returns true if it's a "display: [inline-]flex" token.
*
* @param {String} text
* the parsed text.
* The parsed text.
* @param {Object} token
* the parsed token.
* The parsed token.
* @param {Object} options
* the options given to _parse.
* The options given to _parse.
*/
_isDisplayFlex: function (text, token, options) {
return options.expectDisplay &&
(token.text === "flex" || token.text === "inline-flex");
},
/**
* Returns true if it's a "display: [inline-]grid" token.
*
* @param {String} text
* The parsed text.
* @param {Object} token
* The parsed token.
* @param {Object} options
* The options given to _parse.
*/
_isDisplayGrid: function (text, token, options) {
return options.expectDisplay &&
@ -516,24 +536,23 @@ OutputParser.prototype = {
},
/**
* Append a CSS Grid highlighter toggle icon next to the value in a
* 'display: grid' declaration
* Append a Flexbox|Grid highlighter toggle icon next to the value in a
* "display: [inline-]flex" or "display: [inline-]grid" declaration.
*
* @param {String} grid
* The grid text value to append
* @param {Object} options
* Options object. For valid options and default values see
* _mergeOptions()
* @param {String} text
* The text value to append
* @param {String} className
* The class name for the toggle span
*/
_appendGrid: function (grid, options) {
_appendHighlighterToggle: function (text, className) {
let container = this._createNode("span", {});
let toggle = this._createNode("span", {
class: options.gridClass
class: className
});
let value = this._createNode("span", {});
value.textContent = grid;
value.textContent = text;
container.appendChild(toggle);
container.appendChild(value);
@ -1415,6 +1434,7 @@ OutputParser.prototype = {
* // parser to skip the call to
* // _wrapFilter. Used only for
* // previewing with the filter swatch.
* - flexClass: "" // The class to use for the flex icon.
* - gridClass: "" // The class to use for the grid icon.
* - shapeClass: "" // The class to use for the shape icon.
* - supportsColor: false // Does the CSS property support colors?
@ -1442,6 +1462,7 @@ OutputParser.prototype = {
colorClass: "",
colorSwatchClass: "",
filterSwatch: false,
flexClass: "",
gridClass: "",
shapeClass: "",
supportsColor: false,

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

@ -7,6 +7,7 @@
--rule-highlight-background-color: var(--theme-highlight-yellow);
--rule-overridden-item-border-color: var(--theme-content-color3);
--rule-header-background-color: var(--theme-toolbar-background);
--rule-flex-toggle-color: var(--grey-90);
--rule-shape-toggle-color: var(--grey-90);
}
@ -14,6 +15,7 @@
--rule-highlight-background-color: #521C76;
--rule-overridden-item-border-color: var(--theme-content-color1);
--rule-header-background-color: #141416;
--rule-flex-toggle-color: var(--grey-10);
--rule-shape-toggle-color: var(--grey-10);
}
@ -452,6 +454,7 @@
display: none;
}
.ruleview-flex,
.ruleview-grid,
.ruleview-swatch,
.ruleview-shape {
@ -467,6 +470,14 @@
position: relative;
}
.ruleview-flex {
background: url("chrome://devtools/skin/images/command-frames.svg");
-moz-context-properties: fill;
fill: var(--rule-shape-toggle-color);
border-radius: 0;
background-size: 1em;
}
.ruleview-grid {
background: url("chrome://devtools/skin/images/grid.svg");
border-radius: 0;
@ -610,6 +621,7 @@
filter: var(--theme-icon-checked-filter);
}
.ruleview-flex.active,
.ruleview-grid.active,
.ruleview-selectorhighlighter:active,
.ruleview-selectorhighlighter.highlighted,

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

@ -99,6 +99,10 @@ rule.filterSwatch.tooltip=Click to open the filter editor
# when the mouse is over a angle swatch in the rule view.
rule.angleSwatch.tooltip=Shift+click to change the angle format
# LOCALIZATION NOTE (rule.flexToggle.tooltip): Text displayed in a tooltip
# when the mouse is over a Flexbox toggle icon in the rule view.
rule.flexToggle.tooltip=Click to toggle the Flexbox highlighter
# LOCALIZATION NOTE (rule.gridToggle.tooltip): Text displayed in a tooltip
# when the mouse is over a CSS Grid toggle icon in the rule view.
rule.gridToggle.tooltip=Click to toggle the CSS Grid highlighter