зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1564999
- Add menu with simulation options to the a11y panel, r=yzen
Differential Revision: https://phabricator.services.mozilla.com/D38885 --HG-- extra : moz-landing-system : lando
This commit is contained in:
Родитель
deacf348f4
Коммит
973268af17
|
@ -59,11 +59,13 @@ class AccessibilityStartup {
|
|||
this._supports.snapshot,
|
||||
this._supports.audit,
|
||||
this._supports.hydration,
|
||||
this._supports.simulation,
|
||||
] = await Promise.all([
|
||||
this.target.actorHasMethod("accessible", "getRelations"),
|
||||
this.target.actorHasMethod("accessible", "snapshot"),
|
||||
this.target.actorHasMethod("accessible", "audit"),
|
||||
this.target.actorHasMethod("accessible", "hydrate"),
|
||||
this.target.actorHasMethod("accessibility", "getSimulator"),
|
||||
]);
|
||||
|
||||
await this._accessibility.bootstrap();
|
||||
|
|
|
@ -47,19 +47,28 @@ AccessibilityView.prototype = {
|
|||
* Initialize accessibility view, create its top level component and set the
|
||||
* data store.
|
||||
*
|
||||
* @param {Object} accessibility front that can initialize accessibility
|
||||
* @param {Object}
|
||||
* Object that contains the following properties:
|
||||
* - front {Object}
|
||||
* front that can initialize accessibility
|
||||
* walker and enable/disable accessibility
|
||||
* services.
|
||||
* @param {Object} walker front for accessibility walker actor responsible for
|
||||
* - walker {Object}
|
||||
* front for accessibility walker actor responsible for
|
||||
* managing accessible objects actors/fronts.
|
||||
* @param {JSON} supports a collection of flags indicating which accessibility
|
||||
* - supports {JSON}
|
||||
* a collection of flags indicating which accessibility
|
||||
* panel features are supported by the current serverside
|
||||
* version.
|
||||
* @param {Array} fluentBundles array of FluentBundles elements for localization
|
||||
* - fluentBundles {Array}
|
||||
* array of FluentBundles elements for localization
|
||||
* - simulator {Object}
|
||||
* front for simulator actor responsible for setting
|
||||
* color matrices in docShell
|
||||
*/
|
||||
async initialize(accessibility, walker, supports, fluentBundles) {
|
||||
async initialize({ front, walker, supports, fluentBundles, simulator }) {
|
||||
// Make sure state is reset every time accessibility panel is initialized.
|
||||
await this.store.dispatch(reset(accessibility, supports));
|
||||
await this.store.dispatch(reset(front, supports));
|
||||
const container = document.getElementById("content");
|
||||
|
||||
if (!supports.enableDisable) {
|
||||
|
@ -68,9 +77,10 @@ AccessibilityView.prototype = {
|
|||
}
|
||||
|
||||
const mainFrame = MainFrame({
|
||||
accessibility,
|
||||
accessibility: front,
|
||||
accessibilityWalker: walker,
|
||||
fluentBundles,
|
||||
simulator,
|
||||
});
|
||||
// Render top level component
|
||||
const provider = createElement(Provider, { store: this.store }, mainFrame);
|
||||
|
|
|
@ -140,13 +140,13 @@ body {
|
|||
margin-inline: 5px;
|
||||
}
|
||||
|
||||
.devtools-toolbar .accessibility-tree-filters {
|
||||
.devtools-toolbar .accessibility-tree-filters,
|
||||
.devtools-toolbar .accessibility-simulation {
|
||||
display: flex;
|
||||
flex-wrap: nowrap;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
white-space: nowrap;
|
||||
margin-inline-end: 5px;
|
||||
}
|
||||
|
||||
.devtools-toolbar .toolbar-menu-button {
|
||||
|
@ -156,12 +156,21 @@ body {
|
|||
|
||||
.devtools-toolbar .toolbar-menu-button.filters {
|
||||
max-width: 100px;
|
||||
}
|
||||
|
||||
.devtools-toolbar .toolbar-menu-button.simulation {
|
||||
max-width: 200px;
|
||||
}
|
||||
|
||||
.devtools-toolbar .toolbar-menu-button.filters,
|
||||
.devtools-toolbar .toolbar-menu-button.simulation {
|
||||
text-overflow: ellipsis;
|
||||
overflow-x: hidden;
|
||||
margin-inline-start: 3px;
|
||||
}
|
||||
|
||||
.devtools-toolbar .toolbar-menu-button::after {
|
||||
.devtools-toolbar .toolbar-menu-button::after,
|
||||
.devtools-toolbar .toolbar-menu-button.simulation::before {
|
||||
content: "";
|
||||
display: inline-block;
|
||||
-moz-context-properties: fill;
|
||||
|
@ -169,7 +178,8 @@ body {
|
|||
margin-inline-start: 3px;
|
||||
}
|
||||
|
||||
.devtools-toolbar .toolbar-menu-button.filters::after {
|
||||
.devtools-toolbar .toolbar-menu-button.filters::after,
|
||||
.devtools-toolbar .toolbar-menu-button.simulation::after {
|
||||
background: url("chrome://devtools/skin/images/select-arrow.svg") no-repeat;
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
|
@ -286,22 +296,26 @@ body {
|
|||
margin: auto;
|
||||
}
|
||||
|
||||
.description .link {
|
||||
.description .link,
|
||||
.accessibility-check-annotation .link {
|
||||
color: var(--accessibility-link-color);
|
||||
cursor: pointer;
|
||||
outline: 0;
|
||||
}
|
||||
|
||||
.description .link:hover:not(:focus) {
|
||||
.description .link:hover:not(:focus),
|
||||
.accessibility-check-annotation .link:hover:not(:focus) {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.description .link:focus:not(:active) {
|
||||
.description .link:focus:not(:active),
|
||||
.accessibility-check-annotation .link:focus:not(:active) {
|
||||
box-shadow: 0 0 0 2px var(--accessibility-toolbar-focus), 0 0 0 4px var(--accessibility-toolbar-focus-alpha30);
|
||||
border-radius: 2px;
|
||||
}
|
||||
|
||||
.description .link:active {
|
||||
.description .link:active,
|
||||
.accessibility-check-annotation .link:active {
|
||||
color: var(--accessibility-link-color-active);
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
@ -764,27 +778,10 @@ body {
|
|||
}
|
||||
|
||||
.accessibility-check-annotation .link {
|
||||
color: var(--accessibility-link-color);
|
||||
cursor: pointer;
|
||||
outline: 0;
|
||||
white-space: nowrap;
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
.accessibility-check-annotation .link:hover:not(:focus) {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.accessibility-check-annotation .link:focus:not(:active) {
|
||||
box-shadow: 0 0 0 2px var(--accessibility-toolbar-focus), 0 0 0 4px var(--accessibility-toolbar-focus-alpha30);
|
||||
border-radius: 2px;
|
||||
}
|
||||
|
||||
.accessibility-check-annotation .link:active {
|
||||
color: var(--accessibility-link-color-active);
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.accessibility-color-contrast .accessibility-contrast-value:not(:empty) {
|
||||
margin-block-end: 4px;
|
||||
}
|
||||
|
@ -815,3 +812,35 @@ body {
|
|||
.accessibility-color-contrast .accessibility-color-contrast-separator:before {
|
||||
margin-inline-end: 3px;
|
||||
}
|
||||
|
||||
.devtools-toolbar .toolbar-menu-button.simulation::before {
|
||||
width: 12px;
|
||||
height: 12px;
|
||||
margin-inline-end: 3px;
|
||||
margin-inline-start: 0px;
|
||||
background: url("chrome://devtools/skin/images/eye.svg") no-repeat;
|
||||
-moz-context-properties: fill, stroke;
|
||||
fill: var(--theme-icon-color);
|
||||
stroke: var(--theme-icon-color);
|
||||
vertical-align: -2px;
|
||||
}
|
||||
|
||||
.devtools-toolbar .toolbar-menu-button.active,
|
||||
.devtools-toolbar .toolbar-menu-button.active.devtools-button:not(:empty):not(.checked):not(:disabled):focus {
|
||||
color: var(--theme-toolbar-selected-color);
|
||||
}
|
||||
|
||||
.devtools-toolbar .toolbar-menu-button.simulation.active::before {
|
||||
fill: var(--theme-toolbar-selected-color);
|
||||
stroke: var(--theme-toolbar-selected-color);
|
||||
}
|
||||
|
||||
#simulation-menu-button-menu .link {
|
||||
background-color: transparent;
|
||||
border: none;
|
||||
}
|
||||
|
||||
#simulation-menu-button-menu .link:focus,
|
||||
#simulation-menu-button-menu .link:hover {
|
||||
background-color: var(--theme-arrowpanel-dimmed);
|
||||
}
|
||||
|
|
|
@ -6,5 +6,6 @@ DevToolsModules(
|
|||
'accessibles.js',
|
||||
'audit.js',
|
||||
'details.js',
|
||||
'simulation.js',
|
||||
'ui.js'
|
||||
)
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
"use strict";
|
||||
|
||||
const { SIMULATE } = require("devtools/client/accessibility/constants");
|
||||
|
||||
exports.simulate = (simulator, simTypes = []) => dispatch =>
|
||||
simulator
|
||||
.simulate({ types: simTypes })
|
||||
.then(success => dispatch({ error: !success, simTypes, type: SIMULATE }))
|
||||
.catch(error => dispatch({ error, type: SIMULATE }));
|
|
@ -47,6 +47,7 @@ class MainFrame extends Component {
|
|||
dispatch: PropTypes.func.isRequired,
|
||||
auditing: PropTypes.array.isRequired,
|
||||
supports: PropTypes.object,
|
||||
simulator: PropTypes.object,
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -115,6 +116,7 @@ class MainFrame extends Component {
|
|||
fluentBundles,
|
||||
enabled,
|
||||
auditing,
|
||||
simulator,
|
||||
} = this.props;
|
||||
|
||||
if (!enabled) {
|
||||
|
@ -128,7 +130,7 @@ class MainFrame extends Component {
|
|||
{ bundles: fluentBundles },
|
||||
div(
|
||||
{ className: "mainFrame", role: "presentation" },
|
||||
Toolbar({ accessibility, accessibilityWalker }),
|
||||
Toolbar({ accessibility, accessibilityWalker, simulator }),
|
||||
isAuditing && AuditProgressOverlay(),
|
||||
span(
|
||||
{
|
||||
|
|
|
@ -0,0 +1,155 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
"use strict";
|
||||
|
||||
// React
|
||||
const {
|
||||
createFactory,
|
||||
Component,
|
||||
} = require("devtools/client/shared/vendor/react");
|
||||
const {
|
||||
hr,
|
||||
span,
|
||||
div,
|
||||
} = require("devtools/client/shared/vendor/react-dom-factories");
|
||||
const PropTypes = require("devtools/client/shared/vendor/react-prop-types");
|
||||
const { L10N } = require("../utils/l10n");
|
||||
const { connect } = require("devtools/client/shared/vendor/react-redux");
|
||||
const MenuButton = createFactory(
|
||||
require("devtools/client/shared/components/menu/MenuButton")
|
||||
);
|
||||
const { openDocLink } = require("devtools/client/shared/link");
|
||||
const {
|
||||
A11Y_SIMULATION_DOCUMENTATION_LINK,
|
||||
} = require("devtools/client/accessibility/constants");
|
||||
const {
|
||||
accessibility: { SIMULATION_TYPE },
|
||||
} = require("devtools/shared/constants");
|
||||
const actions = require("../actions/simulation");
|
||||
|
||||
loader.lazyGetter(this, "MenuItem", function() {
|
||||
return createFactory(
|
||||
require("devtools/client/shared/components/menu/MenuItem")
|
||||
);
|
||||
});
|
||||
loader.lazyGetter(this, "MenuList", function() {
|
||||
return createFactory(
|
||||
require("devtools/client/shared/components/menu/MenuList")
|
||||
);
|
||||
});
|
||||
|
||||
const SIMULATION_MENU_LABELS = {
|
||||
NONE: "accessibility.filter.none",
|
||||
[SIMULATION_TYPE.DEUTERANOMALY]: "accessibility.simulation.deuteranomaly",
|
||||
[SIMULATION_TYPE.PROTANOMALY]: "accessibility.simulation.protanomaly",
|
||||
[SIMULATION_TYPE.PROTANOPIA]: "accessibility.simulation.protanopia",
|
||||
[SIMULATION_TYPE.DEUTERANOPIA]: "accessibility.simulation.deuteranopia",
|
||||
[SIMULATION_TYPE.TRITANOPIA]: "accessibility.simulation.tritanopia",
|
||||
[SIMULATION_TYPE.TRITANOMALY]: "accessibility.simulation.tritanomaly",
|
||||
[SIMULATION_TYPE.CONTRAST_LOSS]: "accessibility.simulation.contrastLoss",
|
||||
DOCUMENTATION: "accessibility.documentation.label",
|
||||
};
|
||||
|
||||
class SimulationMenuButton extends Component {
|
||||
static get propTypes() {
|
||||
return {
|
||||
simulator: PropTypes.object.isRequired,
|
||||
simulation: PropTypes.object.isRequired,
|
||||
dispatch: PropTypes.func.isRequired,
|
||||
};
|
||||
}
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.disableSimulation = this.disableSimulation.bind(this);
|
||||
}
|
||||
|
||||
disableSimulation() {
|
||||
const { dispatch, simulator } = this.props;
|
||||
|
||||
dispatch(actions.simulate(simulator));
|
||||
}
|
||||
|
||||
toggleSimulation(simKey) {
|
||||
const { dispatch, simulation, simulator } = this.props;
|
||||
|
||||
if (simulation[simKey]) {
|
||||
this.disableSimulation();
|
||||
} else {
|
||||
dispatch(actions.simulate(simulator, [simKey]));
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
const { simulation } = this.props;
|
||||
const simulationMenuButtonId = "simulation-menu-button";
|
||||
const toolbarLabelID = "accessibility-simulation-label";
|
||||
const currSimulation = Object.entries(simulation).find(
|
||||
simEntry => simEntry[1]
|
||||
);
|
||||
|
||||
const items = [
|
||||
// No simulation option
|
||||
MenuItem({
|
||||
key: "simulation-none",
|
||||
label: L10N.getStr(SIMULATION_MENU_LABELS.NONE),
|
||||
checked: !currSimulation,
|
||||
onClick: this.disableSimulation,
|
||||
}),
|
||||
hr(),
|
||||
// Simulation options
|
||||
...Object.keys(SIMULATION_TYPE).map(simType =>
|
||||
MenuItem({
|
||||
key: `simulation-${simType}`,
|
||||
label: L10N.getStr(SIMULATION_MENU_LABELS[simType]),
|
||||
checked: simulation[simType],
|
||||
onClick: this.toggleSimulation.bind(this, simType),
|
||||
})
|
||||
),
|
||||
hr(),
|
||||
// Documentation link
|
||||
MenuItem({
|
||||
className: "link",
|
||||
key: "simulation-documentation",
|
||||
label: L10N.getStr(SIMULATION_MENU_LABELS.DOCUMENTATION),
|
||||
role: "link",
|
||||
onClick: () => openDocLink(A11Y_SIMULATION_DOCUMENTATION_LINK),
|
||||
}),
|
||||
];
|
||||
|
||||
return div(
|
||||
{
|
||||
role: "group",
|
||||
className: "accessibility-simulation",
|
||||
"aria-labelledby": toolbarLabelID,
|
||||
},
|
||||
span(
|
||||
{ id: toolbarLabelID, role: "presentation" },
|
||||
L10N.getStr("accessibility.simulation")
|
||||
),
|
||||
MenuButton(
|
||||
{
|
||||
id: simulationMenuButtonId,
|
||||
menuId: simulationMenuButtonId + "-menu",
|
||||
className: `devtools-button toolbar-menu-button simulation${
|
||||
currSimulation ? " active" : ""
|
||||
}`,
|
||||
doc: document,
|
||||
label: L10N.getStr(
|
||||
SIMULATION_MENU_LABELS[currSimulation ? currSimulation[0] : "NONE"]
|
||||
),
|
||||
},
|
||||
MenuList({}, items)
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const mapStateToProps = ({ simulation }) => {
|
||||
return { simulation };
|
||||
};
|
||||
|
||||
// Exports from this module
|
||||
module.exports = connect(mapStateToProps)(SimulationMenuButton);
|
|
@ -19,6 +19,9 @@ const AccessibilityTreeFilter = createFactory(
|
|||
require("./AccessibilityTreeFilter")
|
||||
);
|
||||
const AccessibilityPrefs = createFactory(require("./AccessibilityPrefs"));
|
||||
loader.lazyGetter(this, "SimulationMenuButton", function() {
|
||||
return createFactory(require("./SimulationMenuButton"));
|
||||
});
|
||||
|
||||
const { connect } = require("devtools/client/shared/vendor/react-redux");
|
||||
const { disable, updateCanBeDisabled } = require("../actions/ui");
|
||||
|
@ -30,6 +33,7 @@ class Toolbar extends Component {
|
|||
dispatch: PropTypes.func.isRequired,
|
||||
accessibility: PropTypes.object.isRequired,
|
||||
canBeDisabled: PropTypes.bool.isRequired,
|
||||
simulator: PropTypes.object,
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -72,7 +76,7 @@ class Toolbar extends Component {
|
|||
}
|
||||
|
||||
render() {
|
||||
const { canBeDisabled, accessibilityWalker } = this.props;
|
||||
const { canBeDisabled, accessibilityWalker, simulator } = this.props;
|
||||
const { disabling } = this.state;
|
||||
const disableButtonStr = disabling
|
||||
? "accessibility.disabling"
|
||||
|
@ -88,6 +92,16 @@ class Toolbar extends Component {
|
|||
title = L10N.getStr("accessibility.disable.disabledTitle");
|
||||
}
|
||||
|
||||
const optionalSimulationSection = simulator
|
||||
? [
|
||||
div({
|
||||
role: "separator",
|
||||
className: "devtools-separator",
|
||||
}),
|
||||
SimulationMenuButton({ simulator }),
|
||||
]
|
||||
: [];
|
||||
|
||||
return div(
|
||||
{
|
||||
className: "devtools-toolbar",
|
||||
|
@ -118,6 +132,8 @@ class Toolbar extends Component {
|
|||
L10N.getStr("accessibility.beta")
|
||||
),
|
||||
AccessibilityTreeFilter({ accessibilityWalker, describedby: betaID }),
|
||||
// Simulation section is shown if webrender is enabled
|
||||
...optionalSimulationSection,
|
||||
AccessibilityPrefs()
|
||||
);
|
||||
}
|
||||
|
|
|
@ -25,6 +25,7 @@ DevToolsModules(
|
|||
'LearnMoreLink.js',
|
||||
'MainFrame.js',
|
||||
'RightSidebar.js',
|
||||
'SimulationMenuButton.js',
|
||||
'TextLabelBadge.js',
|
||||
'TextLabelCheck.js',
|
||||
'Toolbar.js'
|
||||
|
|
|
@ -69,6 +69,7 @@ exports.FILTER_TOGGLE = "FILTER_TOGGLE";
|
|||
exports.AUDIT = "AUDIT";
|
||||
exports.AUDITING = "AUDITING";
|
||||
exports.AUDIT_PROGRESS = "AUDIT_PROGRESS";
|
||||
exports.SIMULATE = "SIMULATE";
|
||||
|
||||
// List of filters for accessibility checks.
|
||||
exports.FILTERS = {
|
||||
|
@ -122,6 +123,8 @@ exports.A11Y_LEARN_MORE_LINK =
|
|||
exports.A11Y_CONTRAST_LEARN_MORE_LINK =
|
||||
"https://developer.mozilla.org/docs/Web/Accessibility/Understanding_WCAG/Perceivable/" +
|
||||
"Color_contrast?utm_source=devtools&utm_medium=a11y-panel-checks-color-contrast";
|
||||
exports.A11Y_SIMULATION_DOCUMENTATION_LINK =
|
||||
"https://developer.mozilla.org/docs/Tools/Accessibility_inspector/Simulation";
|
||||
|
||||
const A11Y_TEXT_LABEL_LINK_BASE =
|
||||
"https://developer.mozilla.org/docs/Web/Accessibility/Understanding_WCAG/Text_labels_and_names" +
|
||||
|
|
|
@ -94,6 +94,10 @@ AccessibilityPanel.prototype = {
|
|||
this.picker = new Picker(this);
|
||||
}
|
||||
|
||||
if (this.supports.simulation) {
|
||||
this.simulator = await this.front.getSimulator();
|
||||
}
|
||||
|
||||
this.fluentBundles = await this.createFluentBundles();
|
||||
|
||||
this.updateA11YServiceDurationTimer();
|
||||
|
@ -168,13 +172,13 @@ AccessibilityPanel.prototype = {
|
|||
}
|
||||
// Alright reset the flag we are about to refresh the panel.
|
||||
this.shouldRefresh = false;
|
||||
this.postContentMessage(
|
||||
"initialize",
|
||||
this.front,
|
||||
this.walker,
|
||||
this.supports,
|
||||
this.fluentBundles
|
||||
);
|
||||
this.postContentMessage("initialize", {
|
||||
front: this.front,
|
||||
walker: this.walker,
|
||||
supports: this.supports,
|
||||
fluentBundles: this.fluentBundles,
|
||||
simulator: this.simulator,
|
||||
});
|
||||
},
|
||||
|
||||
updateA11YServiceDurationTimer() {
|
||||
|
|
|
@ -6,11 +6,13 @@
|
|||
const { accessibles } = require("./accessibles");
|
||||
const { audit } = require("./audit");
|
||||
const { details } = require("./details");
|
||||
const { simulation } = require("./simulation");
|
||||
const { ui } = require("./ui");
|
||||
|
||||
exports.reducers = {
|
||||
accessibles,
|
||||
audit,
|
||||
details,
|
||||
simulation,
|
||||
ui,
|
||||
};
|
||||
|
|
|
@ -7,5 +7,6 @@ DevToolsModules(
|
|||
'audit.js',
|
||||
'details.js',
|
||||
'index.js',
|
||||
'simulation.js',
|
||||
'ui.js'
|
||||
)
|
||||
|
|
|
@ -0,0 +1,60 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
"use strict";
|
||||
|
||||
const {
|
||||
accessibility: { SIMULATION_TYPE },
|
||||
} = require("devtools/shared/constants");
|
||||
const { SIMULATE } = require("devtools/client/accessibility/constants");
|
||||
|
||||
/**
|
||||
* Initial state definition
|
||||
*/
|
||||
function getInitialState() {
|
||||
return {
|
||||
[SIMULATION_TYPE.PROTANOMALY]: false,
|
||||
[SIMULATION_TYPE.DEUTERANOMALY]: false,
|
||||
[SIMULATION_TYPE.TRITANOMALY]: false,
|
||||
[SIMULATION_TYPE.PROTANOPIA]: false,
|
||||
[SIMULATION_TYPE.DEUTERANOPIA]: false,
|
||||
[SIMULATION_TYPE.TRITANOPIA]: false,
|
||||
[SIMULATION_TYPE.CONTRAST_LOSS]: false,
|
||||
};
|
||||
}
|
||||
|
||||
function simulation(state = getInitialState(), action) {
|
||||
const { error } = action;
|
||||
|
||||
if (error) {
|
||||
console.warn(
|
||||
`Error running simulation: ${
|
||||
typeof error == "string"
|
||||
? error
|
||||
: "simulate function in simulator.js returned an error"
|
||||
}`
|
||||
);
|
||||
return state;
|
||||
}
|
||||
|
||||
switch (action.type) {
|
||||
case SIMULATE:
|
||||
const simTypes = action.simTypes;
|
||||
|
||||
if (simTypes.length === 0) {
|
||||
return getInitialState();
|
||||
}
|
||||
|
||||
const updatedState = getInitialState();
|
||||
simTypes.forEach(simType => {
|
||||
updatedState[simType] = true;
|
||||
});
|
||||
|
||||
return updatedState;
|
||||
default:
|
||||
return state;
|
||||
}
|
||||
}
|
||||
|
||||
exports.simulation = simulation;
|
|
@ -26,6 +26,7 @@ skip-if = (os == 'linux' && debug && bits == 64) # Bug 1511247
|
|||
[browser_accessibility_reload.js]
|
||||
[browser_accessibility_sidebar_checks.js]
|
||||
[browser_accessibility_sidebar.js]
|
||||
[browser_accessibility_simulation.js]
|
||||
[browser_accessibility_tree_audit_long.js]
|
||||
[browser_accessibility_tree_audit_reset.js]
|
||||
[browser_accessibility_tree_audit_toolbar.js]
|
||||
|
|
|
@ -0,0 +1,120 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
|
||||
/* global openSimulationMenu, toggleSimulationOption */
|
||||
|
||||
const {
|
||||
isWebRenderEnabled,
|
||||
} = require("devtools/server/actors/utils/accessibility");
|
||||
|
||||
const TEST_URI = `<html>
|
||||
<head>
|
||||
<meta charset="utf-8"/>
|
||||
<title>Accessibility Simulations Test</title>
|
||||
</head>
|
||||
<body>
|
||||
<h1 style="color:blue; background-color:rgba(255,255,255,1);">
|
||||
Top level header
|
||||
</h1>
|
||||
<h2 style="color:green; background-color:rgba(255,255,255,1);">
|
||||
Second level header
|
||||
</h2>
|
||||
</body>
|
||||
</html>`;
|
||||
|
||||
if (!isWebRenderEnabled(window)) {
|
||||
addA11YPanelTask(
|
||||
"Test that simulation menu button does not exist without WebRender.",
|
||||
TEST_URI,
|
||||
async function({ doc }) {
|
||||
ok(
|
||||
!doc.querySelector("#simulation-menu-button"),
|
||||
"Simulation menu is not shown without WebRender."
|
||||
);
|
||||
}
|
||||
);
|
||||
} else {
|
||||
/**
|
||||
* Test data has the format of:
|
||||
* {
|
||||
* desc {String} description for better logging
|
||||
* setup {Function} An optional setup that needs to be performed before
|
||||
* the state of the simulation components can be checked.
|
||||
* expected {JSON} An expected states for the simulation components.
|
||||
* }
|
||||
*/
|
||||
const tests = [
|
||||
{
|
||||
desc:
|
||||
"Check that the menu button is inactivate and the menu is closed initially.",
|
||||
expected: {
|
||||
simulation: {
|
||||
buttonActive: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
desc:
|
||||
"Clicking the menu button shows the menu with No Simulation selected.",
|
||||
setup: async ({ doc }) => {
|
||||
await openSimulationMenu(doc);
|
||||
},
|
||||
expected: {
|
||||
simulation: {
|
||||
buttonActive: false,
|
||||
checkedOptionIndices: [0],
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
desc:
|
||||
"Selecting an option renders the menu button active and closes the menu.",
|
||||
setup: async ({ doc }) => {
|
||||
await toggleSimulationOption(doc, 2);
|
||||
},
|
||||
expected: {
|
||||
simulation: {
|
||||
buttonActive: true,
|
||||
checkedOptionIndices: [2],
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "Reopening the menu preserves the previously selected option.",
|
||||
setup: async ({ doc }) => {
|
||||
await openSimulationMenu(doc);
|
||||
},
|
||||
expected: {
|
||||
simulation: {
|
||||
buttonActive: true,
|
||||
checkedOptionIndices: [2],
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
desc:
|
||||
"Unselecting the option renders the button inactive and closes the menu.",
|
||||
setup: async ({ doc }) => {
|
||||
await toggleSimulationOption(doc, 2);
|
||||
},
|
||||
expected: {
|
||||
simulation: {
|
||||
buttonActive: false,
|
||||
checkedOptionIndices: [0],
|
||||
},
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
/**
|
||||
* Test that checks state of simulation button and menu when
|
||||
* options are selected/unselected with web render enabled.
|
||||
*/
|
||||
addA11yPanelTestsTask(
|
||||
tests,
|
||||
TEST_URI,
|
||||
"Test selecting and unselecting simulation options updates UI."
|
||||
);
|
||||
}
|
|
@ -6,7 +6,7 @@
|
|||
|
||||
/* global waitUntilState, gBrowser */
|
||||
/* exported addTestTab, checkTreeState, checkSidebarState, checkAuditState, selectRow,
|
||||
toggleRow, toggleMenuItem, addA11yPanelTestsTask, reload, navigate */
|
||||
toggleRow, toggleMenuItem, addA11yPanelTestsTask, reload, navigate, openSimulationMenu, toggleSimulationOption */
|
||||
|
||||
"use strict";
|
||||
|
||||
|
@ -36,6 +36,8 @@ const {
|
|||
// Enable the Accessibility panel
|
||||
Services.prefs.setBoolPref("devtools.accessibility.enabled", true);
|
||||
|
||||
const SIMULATION_MENU_BUTTON_ID = "#simulation-menu-button";
|
||||
|
||||
/**
|
||||
* Enable accessibility service and wait for a11y init event.
|
||||
* @return {Object} instance of accessibility service.
|
||||
|
@ -470,6 +472,42 @@ async function checkToolbarState(doc, activeToolbarFilters) {
|
|||
ok(hasExpectedStructure, "Toolbar state is correct.");
|
||||
}
|
||||
|
||||
/**
|
||||
* Check the state of the simulation button and menu components.
|
||||
* @param {Object} doc Panel document.
|
||||
* @param {Object} expected Expected states of the simulation components:
|
||||
* menuVisible, buttonActive, checkedOptionIndices (Optional)
|
||||
*/
|
||||
async function checkSimulationState(doc, expected) {
|
||||
const { buttonActive, checkedOptionIndices } = expected;
|
||||
const simulationMenuOptions = doc
|
||||
.querySelector(SIMULATION_MENU_BUTTON_ID + "-menu")
|
||||
.querySelectorAll(".menuitem");
|
||||
|
||||
// Check simulation menu button state
|
||||
is(
|
||||
doc.querySelector(SIMULATION_MENU_BUTTON_ID).className,
|
||||
`devtools-button toolbar-menu-button simulation${
|
||||
buttonActive ? " active" : ""
|
||||
}`,
|
||||
`Simulation menu button contains ${buttonActive ? "active" : "base"} class.`
|
||||
);
|
||||
|
||||
// Check simulation menu options states, if specified
|
||||
if (checkedOptionIndices) {
|
||||
simulationMenuOptions.forEach((menuListItem, index) => {
|
||||
const isChecked = checkedOptionIndices.includes(index);
|
||||
const button = menuListItem.firstChild;
|
||||
|
||||
is(
|
||||
button.getAttribute("aria-checked"),
|
||||
isChecked ? "true" : null,
|
||||
`Simulation option ${index} is ${isChecked ? "" : "not "}selected.`
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Focus accessibility properties tree in the a11y inspector sidebar. If focused for the
|
||||
* first time, the tree will select first rendered node as defult selection for keyboard
|
||||
|
@ -590,6 +628,25 @@ async function toggleMenuItem(doc, menuButtonIndex, menuItemIndex) {
|
|||
);
|
||||
}
|
||||
|
||||
async function openSimulationMenu(doc) {
|
||||
doc.querySelector(SIMULATION_MENU_BUTTON_ID).click();
|
||||
|
||||
await BrowserTestUtils.waitForCondition(() =>
|
||||
doc
|
||||
.querySelector(SIMULATION_MENU_BUTTON_ID + "-menu")
|
||||
.classList.contains("tooltip-visible")
|
||||
);
|
||||
}
|
||||
|
||||
async function toggleSimulationOption(doc, optionIndex) {
|
||||
const simulationMenu = doc.querySelector(SIMULATION_MENU_BUTTON_ID + "-menu");
|
||||
simulationMenu.querySelectorAll(".menuitem")[optionIndex].firstChild.click();
|
||||
|
||||
await BrowserTestUtils.waitForCondition(
|
||||
() => !simulationMenu.classList.contains("tooltip-visible")
|
||||
);
|
||||
}
|
||||
|
||||
async function findAccessibleFor(
|
||||
{ toolbox: { target }, panel: { walker: accessibilityWalker } },
|
||||
selector
|
||||
|
@ -648,6 +705,7 @@ async function runA11yPanelTests(tests, env) {
|
|||
audit,
|
||||
toolbarPrefValues,
|
||||
activeToolbarFilters,
|
||||
simulation,
|
||||
} = expected;
|
||||
if (tree) {
|
||||
await checkTreeState(env.doc, tree);
|
||||
|
@ -668,6 +726,10 @@ async function runA11yPanelTests(tests, env) {
|
|||
if (typeof audit !== "undefined") {
|
||||
await checkAuditState(env.store, audit);
|
||||
}
|
||||
|
||||
if (simulation) {
|
||||
await checkSimulationState(env.doc, simulation);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -152,6 +152,7 @@ devtools.jar:
|
|||
skin/images/item-arrow-ltr.svg (themes/images/item-arrow-ltr.svg)
|
||||
skin/images/dropmarker.svg (themes/images/dropmarker.svg)
|
||||
skin/boxmodel.css (themes/boxmodel.css)
|
||||
skin/images/eye.svg (themes/images/eye.svg)
|
||||
skin/images/geometry-editor.svg (themes/images/geometry-editor.svg)
|
||||
skin/images/open-inspector.svg (themes/images/open-inspector.svg)
|
||||
skin/images/more.svg (themes/images/more.svg)
|
||||
|
|
|
@ -163,7 +163,8 @@ accessibility.badges=Accessibility checks
|
|||
|
||||
# LOCALIZATION NOTE (accessibility.filter.none): A title text for the filter
|
||||
# that is rendered within the accessibility panel toolbar for a menu item that
|
||||
# resets all filtering in tree.
|
||||
# resets all filtering in tree, and for the simulation menu item that resets
|
||||
# applied color matrices to the default matrix.
|
||||
accessibility.filter.none=None
|
||||
|
||||
# LOCALIZATION NOTE (accessibility.filter.all2): A title text for the filter
|
||||
|
@ -268,3 +269,38 @@ accessibility.pref.scroll.into.view.label=Scroll into view
|
|||
# LOCALIZATION NOTE (accessibility.documentation.label): This is the label for
|
||||
# the Documentation menu item.
|
||||
accessibility.documentation.label=Documentation…
|
||||
|
||||
# LOCALIZATION NOTE (accessibility.simulation): A title text for the toolbar
|
||||
# within the main accessibility panel that contains a list of simulations for
|
||||
# vision deficiencies.
|
||||
accessibility.simulation=Simulate:
|
||||
|
||||
# LOCALIZATION NOTE (accessibility.simulation.deuteranomaly): This label is shown
|
||||
# in the "Simulate" menu in the accessibility panel and represent the deuteranomaly simulation option.
|
||||
accessibility.simulation.deuteranomaly=Deuteranomaly (low green)
|
||||
|
||||
# LOCALIZATION NOTE (accessibility.simulation.protanomaly): This label is shown
|
||||
# in the "Simulate" menu in the accessibility panel and represent the protanomaly simulation option.
|
||||
accessibility.simulation.protanomaly=Protanomaly (low red)
|
||||
|
||||
# LOCALIZATION NOTE (accessibility.simulation.protanopia): This label is shown
|
||||
# in the "Simulate" menu in the accessibility panel and represent the protanopia simulation option.
|
||||
accessibility.simulation.protanopia=Protanopia (no red)
|
||||
|
||||
# LOCALIZATION NOTE (accessibility.simulation.deuteranopia): This label is shown
|
||||
# in the "Simulate" menu in the accessibility panel and represent the deuteranopia simulation option.
|
||||
accessibility.simulation.deuteranopia=Deuteranopia (no green)
|
||||
|
||||
# LOCALIZATION NOTE (accessibility.simulation.tritanopia): This label is shown
|
||||
# in the "Simulate" menu in the accessibility panel and represent the tritanopia simulation option.
|
||||
accessibility.simulation.tritanopia=Tritanopia (no blue)
|
||||
|
||||
# LOCALIZATION NOTE (accessibility.simulation.tritanomaly): This label is shown
|
||||
# in the "Simulate" menu in the accessibility panel and represent the tritanomaly simulation option.
|
||||
accessibility.simulation.tritanomaly=Tritanomaly (low blue)
|
||||
|
||||
# LOCALIZATION NOTE (accessibility.simulation.contrastLoss): This label is shown
|
||||
# in the "Simulate" menu in the accessibility panel and represent the contrast loss simulation option.
|
||||
# It is also shown in the simulation menu button in the accessibility panel and represent the
|
||||
# contrast loss simulation option currently selected.
|
||||
accessibility.simulation.contrastLoss=Contrast loss
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
<!-- This Source Code Form is subject to the terms of the Mozilla Public
|
||||
- License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 12 12">
|
||||
<path d="M6,2.2c-2.1,0-4.3,2-5.1,3.5c-0.1,0.1-0.1,0.3,0,0.4c0.8,1.5,3,3.5,5.1,3.5s4.3-2,5.1-3.5
|
||||
c0.1-0.1,0.1-0.3,0-0.4C10.3,4.3,8.1,2.2,6,2.2z" stroke="context-stroke" fill="none" stroke-linejoin="round"/>
|
||||
<path d="M6,7.9C7,7.9,7.9,7,7.9,6S7,4.1,6,4.1S4.1,5,4.1,6S5,7.9,6,7.9z" fill="context-fill"/>
|
||||
</svg>
|
После Ширина: | Высота: | Размер: 581 B |
Загрузка…
Ссылка в новой задаче