Bug 1550804 - Add color scheme simulation to the inspector. r=pbro

This adds a color scheme simulation toggle button in the rules view,
which will toggle between 4 different states: default, dark, light,
and no-preference.

This feature is currently hidden away under a preference:
devtools.inspector.color-scheme-simulation.enabled

The final UI/UX still needs to be figured out, however, this initial step is
to land the ability to prototype this feature.

Differential Revision: https://phabricator.services.mozilla.com/D49833

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Gabriel Luong 2019-10-24 20:39:00 +00:00
Родитель 180df98ec0
Коммит f950443d4d
15 изменённых файлов: 267 добавлений и 18 удалений

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

@ -2019,6 +2019,8 @@ pref("devtools.inspector.new-rulesview.enabled", false);
pref("devtools.inspector.compatibility.enabled", false);
// Enable the new Box Model Highlighter with renderer in parent process
pref("devtools.inspector.use-new-box-model-highlighter", false);
// Enable color scheme simulation in the inspector.
pref("devtools.inspector.color-scheme-simulation.enabled", false);
// Grid highlighter preferences
pref("devtools.gridinspector.gridOutlineMaxColumns", 50);

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

@ -101,6 +101,7 @@
<button id="pseudo-class-panel-toggle" data-localization="title=inspector.togglePseudo.tooltip" class="devtools-button"></button>
<button id="class-panel-toggle" data-localization="title=inspector.classPanel.toggleClass.tooltip" class="devtools-button"></button>
<button id="ruleview-add-rule-button" data-localization="title=inspector.addRule.tooltip" class="devtools-button"></button>
<button id="color-scheme-simulation-toggle" data-localization="title=inspector.colorSchemeSimulation.tooltip" class="devtools-button" hidden="true"></button>
<button id="print-simulation-toggle" data-localization="title=inspector.printSimulation.tooltip" class="devtools-button" hidden="true"></button>
</div>
</div>

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

@ -28,6 +28,9 @@ createEnum(
// Updates whether or not the class list panel is expanded.
"UPDATE_CLASS_PANEL_EXPANDED",
// Updates whether or not the color scheme simulation button is hidden.
"UPDATE_COLOR_SCHEME_SIMULATION_HIDDEN",
// Updates the highlighted selector.
"UPDATE_HIGHLIGHTED_SELECTOR",

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

@ -6,6 +6,7 @@
const {
UPDATE_ADD_RULE_ENABLED,
UPDATE_COLOR_SCHEME_SIMULATION_HIDDEN,
UPDATE_HIGHLIGHTED_SELECTOR,
UPDATE_PRINT_SIMULATION_HIDDEN,
UPDATE_RULES,
@ -27,6 +28,19 @@ module.exports = {
};
},
/**
* Updates whether or not the color scheme simulation button is hidden.
*
* @param {Boolean} hidden
* Whether or not the color scheme simulation button is hidden.
*/
updateColorSchemeSimulationHidden(hidden) {
return {
type: UPDATE_COLOR_SCHEME_SIMULATION_HIDDEN,
hidden,
};
},
/**
* Updates the highlighted selector.
*

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

@ -37,6 +37,7 @@ class RulesApp extends PureComponent {
onToggleClassPanelExpanded: PropTypes.func.isRequired,
onToggleDeclaration: PropTypes.func.isRequired,
onTogglePrintSimulation: PropTypes.func.isRequired,
onToggleColorSchemeSimulation: PropTypes.func.isRequired,
onTogglePseudoClass: PropTypes.func.isRequired,
onToggleSelectorHighlighter: PropTypes.func.isRequired,
rules: PropTypes.arrayOf(PropTypes.shape(Types.rule)).isRequired,
@ -193,6 +194,7 @@ class RulesApp extends PureComponent {
onSetClassState: this.props.onSetClassState,
onToggleClassPanelExpanded: this.props.onToggleClassPanelExpanded,
onTogglePrintSimulation: this.props.onTogglePrintSimulation,
onToggleColorSchemeSimulation: this.props.onToggleColorSchemeSimulation,
onTogglePseudoClass: this.props.onTogglePseudoClass,
}),
dom.div(

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

@ -11,6 +11,7 @@ const {
const dom = require("devtools/client/shared/vendor/react-dom-factories");
const PropTypes = require("devtools/client/shared/vendor/react-prop-types");
const { connect } = require("devtools/client/shared/vendor/react-redux");
const { COLOR_SCHEMES } = require("devtools/client/inspector/rules/constants");
const SearchBox = createFactory(require("./SearchBox"));
@ -28,11 +29,13 @@ class Toolbar extends PureComponent {
return {
isAddRuleEnabled: PropTypes.bool.isRequired,
isClassPanelExpanded: PropTypes.bool.isRequired,
isColorSchemeSimulationHidden: PropTypes.bool.isRequired,
isPrintSimulationHidden: PropTypes.bool.isRequired,
onAddClass: PropTypes.func.isRequired,
onAddRule: PropTypes.func.isRequired,
onSetClassState: PropTypes.func.isRequired,
onToggleClassPanelExpanded: PropTypes.func.isRequired,
onToggleColorSchemeSimulation: PropTypes.func.isRequired,
onTogglePrintSimulation: PropTypes.func.isRequired,
onTogglePseudoClass: PropTypes.func.isRequired,
};
@ -42,6 +45,8 @@ class Toolbar extends PureComponent {
super(props);
this.state = {
// Which of the color schemes is simulated, if any.
currentColorScheme: 0,
// Whether or not the print simulation button is enabled.
isPrintSimulationEnabled: false,
// Whether or not the pseudo class panel is expanded.
@ -50,6 +55,9 @@ class Toolbar extends PureComponent {
this.onAddRuleClick = this.onAddRuleClick.bind(this);
this.onClassPanelToggle = this.onClassPanelToggle.bind(this);
this.onColorSchemeSimulationClick = this.onColorSchemeSimulationClick.bind(
this
);
this.onPrintSimulationToggle = this.onPrintSimulationToggle.bind(this);
this.onPseudoClassPanelToggle = this.onPseudoClassPanelToggle.bind(this);
}
@ -73,6 +81,16 @@ class Toolbar extends PureComponent {
});
}
onColorSchemeSimulationClick(event) {
event.stopPropagation();
this.props.onToggleColorSchemeSimulation();
this.setState(prevState => ({
currentColorScheme:
(prevState.currentColorScheme + 1) % COLOR_SCHEMES.length,
}));
}
onPrintSimulationToggle(event) {
event.stopPropagation();
this.props.onTogglePrintSimulation();
@ -97,6 +115,7 @@ class Toolbar extends PureComponent {
const {
isAddRuleEnabled,
isClassPanelExpanded,
isColorSchemeSimulationHidden,
isPrintSimulationHidden,
} = this.props;
const { isPrintSimulationEnabled, isPseudoClassPanelExpanded } = this.state;
@ -136,6 +155,15 @@ class Toolbar extends PureComponent {
onClick: this.onAddRuleClick,
title: getStr("rule.addRule.tooltip"),
}),
isColorSchemeSimulationHidden
? dom.button({
id: "color-scheme-simulation-toggle",
className: "devtools-button",
onClick: this.onColorSchemeSimulationClick,
state: COLOR_SCHEMES[this.state.currentColorScheme],
title: getStr("rule.colorSchemeSimulation.tooltip"),
})
: null,
!isPrintSimulationHidden
? dom.button({
id: "print-simulation-toggle",
@ -167,6 +195,7 @@ const mapStateToProps = state => {
return {
isAddRuleEnabled: state.rules.isAddRuleEnabled,
isClassPanelExpanded: state.classList.isClassPanelExpanded,
isColorSchemeSimulationHidden: state.rules.isColorSchemeSimulationHidden,
isPrintSimulationHidden: state.rules.isPrintSimulationHidden,
};
};

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

@ -8,3 +8,6 @@
// Rules and their Styles into one actor. For elements (which have a style
// but no associated rule) we fake a rule with the following style id.
exports.ELEMENT_STYLE = 100;
// An array of the possible color schemes that can be emulated.
exports.COLOR_SCHEMES = [null, "dark", "light", "no-preference"];

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

@ -24,6 +24,7 @@ const {
} = require("./actions/pseudo-classes");
const {
updateAddRuleEnabled,
updateColorSchemeSimulationHidden,
updateHighlightedSelector,
updatePrintSimulationHidden,
updateRules,
@ -66,6 +67,12 @@ loader.lazyRequireGetter(
"devtools/client/shared/inplace-editor",
true
);
loader.lazyRequireGetter(
this,
"COLOR_SCHEMES",
"devtools/client/inspector/rules/constants",
true
);
const PREF_UA_STYLES = "devtools.inspector.showUserAgentStyles";
@ -93,6 +100,9 @@ class RulesView {
);
this.onToggleDeclaration = this.onToggleDeclaration.bind(this);
this.onTogglePrintSimulation = this.onTogglePrintSimulation.bind(this);
this.onToggleColorSchemeSimulation = this.onToggleColorSchemeSimulation.bind(
this
);
this.onTogglePseudoClass = this.onTogglePseudoClass.bind(this);
this.onToolChanged = this.onToolChanged.bind(this);
this.onToggleSelectorHighlighter = this.onToggleSelectorHighlighter.bind(
@ -129,6 +139,7 @@ class RulesView {
onOpenSourceLink: this.onOpenSourceLink,
onSetClassState: this.onSetClassState,
onToggleClassPanelExpanded: this.onToggleClassPanelExpanded,
onToggleColorSchemeSimulation: this.onToggleColorSchemeSimulation,
onToggleDeclaration: this.onToggleDeclaration,
onTogglePrintSimulation: this.onTogglePrintSimulation,
onTogglePseudoClass: this.onTogglePseudoClass,
@ -139,7 +150,7 @@ class RulesView {
showSelectorEditor: this.showSelectorEditor,
});
this.initPrintSimulation();
this.initSimulationFeatures();
const provider = createElement(
Provider,
@ -156,19 +167,34 @@ class RulesView {
this.provider = provider;
}
async initPrintSimulation() {
const target = this.inspector.currentTarget;
async initSimulationFeatures() {
// In order to query if the emulation actor's print simulation methods are supported,
// we have to call the emulation front so that the actor is lazily loaded. This allows
// us to use `actorHasMethod`. Please see `getActorDescription` for more information.
this.emulationFront = await target.getFront("emulation");
this.emulationFront = await this.currentTarget.getFront("emulation");
if (!target.chrome) {
if (!this.currentTarget.chrome) {
this.store.dispatch(updatePrintSimulationHidden(false));
} else {
this.store.dispatch(updatePrintSimulationHidden(true));
}
// Show the color scheme simulation toggle button if:
// - The feature pref is enabled.
// - Color scheme simulation is supported for the current target.
if (
Services.prefs.getBoolPref(
"devtools.inspector.color-scheme-simulation.enabled"
) &&
(await this.currentTarget.actorHasMethod(
"emulation",
"getEmulatedColorScheme"
))
) {
this.store.dispatch(updateColorSchemeSimulationHidden(false));
} else {
this.store.dispatch(updateColorSchemeSimulationHidden(true));
}
}
destroy() {
@ -245,6 +271,16 @@ class RulesView {
return this._classList;
}
/**
* Get the current target the toolbox is debugging.
*
* @return {Target}
*/
get currentTarget() {
return this.inspector.currentTarget;
}
/**
* Creates a dummy element in the document that helps get the computed style in
* TextProperty.
@ -370,15 +406,12 @@ class RulesView {
*/
async onOpenSourceLink(ruleId) {
const rule = this.elementStyle.getRule(ruleId);
if (
!rule ||
!Tools.styleEditor.isTargetSupported(this.inspector.currentTarget)
) {
if (!rule || !Tools.styleEditor.isTargetSupported(this.currentTarget)) {
return;
}
const toolbox = await gDevTools.showToolbox(
this.inspector.currentTarget,
this.currentTarget,
"styleeditor"
);
const styleEditor = toolbox.getCurrentPanel();
@ -453,6 +486,17 @@ class RulesView {
});
}
/**
* Handler for toggling color scheme simulation.
*/
async onToggleColorSchemeSimulation() {
const currentState = await this.emulationFront.getEmulatedColorScheme();
const index = COLOR_SCHEMES.indexOf(currentState);
const nextState = COLOR_SCHEMES[(index + 1) % COLOR_SCHEMES.length];
await this.emulationFront.setEmulatedColorScheme(nextState);
await this.updateElementStyle();
}
/**
* Handler for toggling print media simulation.
*/

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

@ -8,6 +8,7 @@ const Services = require("Services");
const {
UPDATE_ADD_RULE_ENABLED,
UPDATE_COLOR_SCHEME_SIMULATION_HIDDEN,
UPDATE_HIGHLIGHTED_SELECTOR,
UPDATE_PRINT_SIMULATION_HIDDEN,
UPDATE_RULES,
@ -20,6 +21,8 @@ const INITIAL_RULES = {
highlightedSelector: "",
// Whether or not the add new rule button should be enabled.
isAddRuleEnabled: false,
// Whether or not the color scheme simulation button is hidden.
isColorSchemeSimulationHidden: false,
// Whether or not the print simulation button is hidden.
isPrintSimulationHidden: false,
// Whether or not the source links are enabled. This is determined by
@ -116,6 +119,13 @@ const reducers = {
};
},
[UPDATE_COLOR_SCHEME_SIMULATION_HIDDEN](rules, { hidden }) {
return {
...rules,
isColorSchemeSimulationHidden: hidden,
};
},
[UPDATE_HIGHLIGHTED_SELECTOR](rules, { highlightedSelector }) {
return {
...rules,

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

@ -51,6 +51,12 @@ loader.lazyRequireGetter(
"ClassListPreviewer",
"devtools/client/inspector/rules/views/class-list-previewer"
);
loader.lazyRequireGetter(
this,
"COLOR_SCHEMES",
"devtools/client/inspector/rules/constants",
true
);
loader.lazyRequireGetter(
this,
"StyleInspectorMenu",
@ -156,6 +162,9 @@ function CssRuleView(inspector, document, store) {
this._onTogglePseudoClassPanel = this._onTogglePseudoClassPanel.bind(this);
this._onTogglePseudoClass = this._onTogglePseudoClass.bind(this);
this._onToggleClassPanel = this._onToggleClassPanel.bind(this);
this._onToggleColorSchemeSimulation = this._onToggleColorSchemeSimulation.bind(
this
);
this._onTogglePrintSimulation = this._onTogglePrintSimulation.bind(this);
this.highlightElementRule = this.highlightElementRule.bind(this);
this.highlightProperty = this.highlightProperty.bind(this);
@ -170,9 +179,12 @@ function CssRuleView(inspector, document, store) {
this.pseudoClassToggle = doc.getElementById("pseudo-class-panel-toggle");
this.classPanel = doc.getElementById("ruleview-class-panel");
this.classToggle = doc.getElementById("class-panel-toggle");
this.colorSchemeSimulationButton = doc.getElementById(
"color-scheme-simulation-toggle"
);
this.printSimulationButton = doc.getElementById("print-simulation-toggle");
this._initPrintSimulation();
this._initSimulationFeatures();
this.searchClearButton.hidden = true;
@ -393,13 +405,14 @@ CssRuleView.prototype = {
},
/**
* Check the print emulation actor's backwards-compatibility via the target actor's
* actorHasMethod.
* Initializes the emulation front and enable the print and color scheme simulation
* if they are supported in the current target.
*/
async _initPrintSimulation() {
// In order to query if the emulation actor's print simulation methods are supported,
// we have to call the emulation front so that the actor is lazily loaded. This allows
// us to use `actorHasMethod`. Please see `getActorDescription` for more information.
async _initSimulationFeatures() {
// In order to query if the emulation actor's print and color simulation methods are
// supported, we have to call the emulation front so that the actor is lazily loaded.
// This allows us to use `actorHasMethod`. Please see `getActorDescription` for more
// information.
this._emulationFront = await this.currentTarget.getFront("emulation");
if (!this.currentTarget.chrome) {
@ -409,6 +422,25 @@ CssRuleView.prototype = {
this._onTogglePrintSimulation
);
}
// Show the color scheme simulation toggle button if:
// - The feature pref is enabled.
// - Color scheme simulation is supported for the current target.
if (
Services.prefs.getBoolPref(
"devtools.inspector.color-scheme-simulation.enabled"
) &&
(await this.currentTarget.actorHasMethod(
"emulation",
"getEmulatedColorScheme"
))
) {
this.colorSchemeSimulationButton.removeAttribute("hidden");
this.colorSchemeSimulationButton.addEventListener(
"click",
this._onToggleColorSchemeSimulation
);
}
},
/**
@ -817,6 +849,10 @@ CssRuleView.prototype = {
// Clean-up for print simulation.
if (this._emulationFront) {
this.colorSchemeSimulationButton.removeEventListener(
"click",
this._onToggleColorSchemeSimulation
);
this.printSimulationButton.removeEventListener(
"click",
this._onTogglePrintSimulation
@ -824,6 +860,7 @@ CssRuleView.prototype = {
this._emulationFront.destroy();
this.colorSchemeSimulationButton = null;
this.printSimulationButton = null;
this._emulationFront = null;
}
@ -1703,6 +1740,21 @@ CssRuleView.prototype = {
}
},
async _onToggleColorSchemeSimulation() {
const currentState = await this.emulationFront.getEmulatedColorScheme();
const index = COLOR_SCHEMES.indexOf(currentState);
const nextState = COLOR_SCHEMES[(index + 1) % COLOR_SCHEMES.length];
if (nextState) {
this.colorSchemeSimulationButton.setAttribute("state", nextState);
} else {
this.colorSchemeSimulationButton.removeAttribute("state");
}
await this.emulationFront.setEmulatedColorScheme(nextState);
this.refreshPanel();
},
async _onTogglePrintSimulation() {
const enabled = await this.emulationFront.getIsPrintSimulationEnabled();

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

@ -490,6 +490,11 @@ inspector.noProperties=No CSS properties found.
# that toggles print simulation.
inspector.printSimulation.tooltip = Toggle print media simulation for the page
# LOCALIZATION NOTE (inspector.colorSchemeSimulation.tooltip):
# This is the tooltip of the color scheme simulation button in the Rule View
# toolbar that toggles color scheme simulation.
inspector.colorSchemeSimulation.tooltip=Toggle color scheme simulation for the page
# LOCALIZATION NOTE (markupView.scrollableBadge.label): This is the text displayed inside a
# badge, in the inspector, next to nodes that are scrollable in the page.
markupView.scrollableBadge.label=scroll

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

@ -692,6 +692,28 @@
background-image: url("chrome://devtools/skin/images/rules-view-print-simulation.svg");
}
#color-scheme-simulation-toggle::before {
-moz-context-properties: fill, fill-opacity;
background-image: url("chrome://mozapps/skin/extensions/category-themes.svg");
background-size: 12px;
}
#color-scheme-simulation-toggle[state="dark"] {
background-color: #333;
}
#color-scheme-simulation-toggle[state="dark"]::before {
fill: white;
}
#color-scheme-simulation-toggle[state="light"]::before {
fill-color: #bbb;
}
#color-scheme-simulation-toggle[state="no-preference"]::before {
fill-opacity: 0.5;
}
.flash-out {
transition: background 1s;
}

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

@ -52,6 +52,7 @@ const EmulationActor = protocol.ActorClassWithSpec(emulationSpec, {
this.stopPrintMediaSimulation();
}
this.setEmulatedColorScheme();
this.clearDPPXOverride();
this.clearNetworkThrottling();
this.clearTouchEventsOverride();
@ -154,6 +155,48 @@ const EmulationActor = protocol.ActorClassWithSpec(emulationSpec, {
return false;
},
/* Color scheme simulation */
/**
* Returns the currently emulated color scheme.
*/
getEmulatedColorScheme() {
return this._emulatedColorScheme;
},
/**
* Sets the currently emulated color scheme or if an invalid value is given,
* the override is cleared.
*/
setEmulatedColorScheme(scheme = null) {
if (this._emulatedColorScheme === scheme) {
return;
}
let internalColorScheme;
switch (scheme) {
case "light":
internalColorScheme = Ci.nsIContentViewer.PREFERS_COLOR_SCHEME_LIGHT;
break;
case "dark":
internalColorScheme = Ci.nsIContentViewer.PREFERS_COLOR_SCHEME_DARK;
break;
case "no-preference":
internalColorScheme =
Ci.nsIContentViewer.PREFERS_COLOR_SCHEME_NO_PREFERENCE;
break;
default:
internalColorScheme = Ci.nsIContentViewer.PREFERS_COLOR_SCHEME_NONE;
}
this._emulatedColorScheme = scheme;
this.docShell.contentViewer.emulatePrefersColorScheme(internalColorScheme);
},
// The current emulated color scheme value. It's possible values are listed in the
// COLOR_SCHEMES constant in devtools/client/inspector/rules/constants.
_emulatedColorScheme: null,
/* Network Throttling */
_previousNetworkThrottling: undefined,

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

@ -140,6 +140,11 @@ rule.classPanel.noClasses=No classes on this element
# that toggles print simulation.
rule.printSimulation.tooltip=Toggle print media simulation for the page
# LOCALIZATION NOTE (rule.colorSchemeSimulation.tooltip):
# This is the tooltip of the color scheme simulation button in the Rule View
# toolbar that toggles color-scheme simulation.
rule.colorSchemeSimulation.tooltip=Toggle color-scheme simulation for the page
# LOCALIZATION NOTE (styleinspector.contextmenu.copyColor): Text displayed in the rule
# and computed view context menu when a color value was clicked.
styleinspector.contextmenu.copyColor=Copy Color

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

@ -131,6 +131,20 @@ const emulationSpec = generateActorSpec({
response: {},
},
getEmulatedColorScheme: {
request: {},
response: {
emulated: RetVal("nullable:string"),
},
},
setEmulatedColorScheme: {
request: {
scheme: Arg(0, "nullable:string"),
},
response: {},
},
getIsPrintSimulationEnabled: {
request: {},
response: {