fix(client): store accessibility for screenreaders (#42996)
* fix: store accessibility for screenreaders * Apply suggestions from code review Co-authored-by: Shaun Hamilton <shauhami020@gmail.com> * fix: remove old comments * feat: at short cut announcement when running test * feat: announce that accesibility mode is turned on * fix: use Redux values * Apply suggestions from code review Co-authored-by: Shaun Hamilton <shauhami020@gmail.com> * Apply suggestions from Oliver Co-authored-by: Oliver Eyton-Williams <ojeytonwilliams@gmail.com> * fix: "rip out redux stuff" and use store instead * Apply suggestions from code review Co-authored-by: Oliver Eyton-Williams <ojeytonwilliams@gmail.com> * Apply suggestions from code review Co-authored-by: Oliver Eyton-Williams <ojeytonwilliams@gmail.com> * fix: old use of props * Update client/src/templates/Challenges/classic/editor.tsx Co-authored-by: Shaun Hamilton <shauhami020@gmail.com> Co-authored-by: Shaun Hamilton <shauhami020@gmail.com> Co-authored-by: Oliver Eyton-Williams <ojeytonwilliams@gmail.com>pull/43131/head
parent
cbf553639d
commit
eccc642d83
|
@ -8,9 +8,7 @@ import {
|
|||
canFocusEditorSelector,
|
||||
consoleOutputSelector,
|
||||
executeChallenge,
|
||||
inAccessibilityModeSelector,
|
||||
saveEditorContent,
|
||||
setAccessibilityMode,
|
||||
setEditorFocusability,
|
||||
visibleEditorsSelector,
|
||||
updateFile
|
||||
|
@ -31,7 +29,6 @@ const propTypes = {
|
|||
executeChallenge: PropTypes.func.isRequired,
|
||||
ext: PropTypes.string,
|
||||
fileKey: PropTypes.string,
|
||||
inAccessibilityMode: PropTypes.bool.isRequired,
|
||||
initialEditorContent: PropTypes.string,
|
||||
initialExt: PropTypes.string,
|
||||
output: PropTypes.arrayOf(PropTypes.string),
|
||||
|
@ -40,7 +37,6 @@ const propTypes = {
|
|||
onResize: PropTypes.func
|
||||
}),
|
||||
saveEditorContent: PropTypes.func.isRequired,
|
||||
setAccessibilityMode: PropTypes.func.isRequired,
|
||||
setEditorFocusability: PropTypes.func,
|
||||
theme: PropTypes.string,
|
||||
title: PropTypes.string,
|
||||
|
@ -57,21 +53,12 @@ const mapStateToProps = createSelector(
|
|||
visibleEditorsSelector,
|
||||
canFocusEditorSelector,
|
||||
consoleOutputSelector,
|
||||
inAccessibilityModeSelector,
|
||||
isDonationModalOpenSelector,
|
||||
userSelector,
|
||||
(
|
||||
visibleEditors,
|
||||
canFocus,
|
||||
output,
|
||||
accessibilityMode,
|
||||
open,
|
||||
{ theme = 'default' }
|
||||
) => ({
|
||||
(visibleEditors, canFocus, output, open, { theme = 'default' }) => ({
|
||||
visibleEditors,
|
||||
canFocus: open ? false : canFocus,
|
||||
output,
|
||||
inAccessibilityMode: accessibilityMode,
|
||||
theme
|
||||
})
|
||||
);
|
||||
|
@ -79,7 +66,6 @@ const mapStateToProps = createSelector(
|
|||
const mapDispatchToProps = {
|
||||
executeChallenge,
|
||||
saveEditorContent,
|
||||
setAccessibilityMode,
|
||||
setEditorFocusability,
|
||||
updateFile
|
||||
};
|
||||
|
|
|
@ -16,7 +16,7 @@ import React, {
|
|||
} from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
import { createSelector } from 'reselect';
|
||||
|
||||
import store from 'store';
|
||||
import { Loader } from '../../../components/helpers';
|
||||
import { userSelector, isDonationModalOpenSelector } from '../../../redux';
|
||||
import {
|
||||
|
@ -27,14 +27,13 @@ import {
|
|||
ResizePropsType,
|
||||
TestType
|
||||
} from '../../../redux/prop-types';
|
||||
|
||||
import {
|
||||
canFocusEditorSelector,
|
||||
consoleOutputSelector,
|
||||
executeChallenge,
|
||||
inAccessibilityModeSelector,
|
||||
saveEditorContent,
|
||||
setEditorFocusability,
|
||||
setAccessibilityMode,
|
||||
updateFile,
|
||||
challengeTestsSelector,
|
||||
submitChallenge
|
||||
|
@ -55,13 +54,11 @@ interface EditorProps {
|
|||
executeChallenge: (isShouldCompletionModalOpen?: boolean) => void;
|
||||
ext: ExtTypes;
|
||||
fileKey: FileKeyTypes;
|
||||
inAccessibilityMode: boolean;
|
||||
initialEditorContent: string;
|
||||
initialExt: string;
|
||||
output: string[];
|
||||
resizeProps: ResizePropsType;
|
||||
saveEditorContent: () => void;
|
||||
setAccessibilityMode: (isAccessible: boolean) => void;
|
||||
setEditorFocusability: (isFocusable: boolean) => void;
|
||||
submitChallenge: () => void;
|
||||
tests: TestType[];
|
||||
|
@ -100,21 +97,18 @@ interface EditorPropertyStore {
|
|||
const mapStateToProps = createSelector(
|
||||
canFocusEditorSelector,
|
||||
consoleOutputSelector,
|
||||
inAccessibilityModeSelector,
|
||||
isDonationModalOpenSelector,
|
||||
userSelector,
|
||||
challengeTestsSelector,
|
||||
(
|
||||
canFocus: boolean,
|
||||
output: string[],
|
||||
accessibilityMode: boolean,
|
||||
open,
|
||||
{ theme = 'default' }: { theme: string },
|
||||
tests: [{ text: string; testString: string }]
|
||||
) => ({
|
||||
canFocus: open ? false : canFocus,
|
||||
output,
|
||||
inAccessibilityMode: accessibilityMode,
|
||||
theme,
|
||||
tests
|
||||
})
|
||||
|
@ -125,7 +119,6 @@ const mapStateToProps = createSelector(
|
|||
const mapDispatchToProps = {
|
||||
executeChallenge,
|
||||
saveEditorContent,
|
||||
setAccessibilityMode,
|
||||
setEditorFocusability,
|
||||
updateFile,
|
||||
submitChallenge
|
||||
|
@ -297,12 +290,31 @@ const Editor = (props: EditorProps): JSX.Element => {
|
|||
// TODO this should *probably* be set on focus
|
||||
editorRef.current = editor;
|
||||
data.editor = editor;
|
||||
|
||||
const storedAccessibilityMode = () => {
|
||||
const accessibility = store.get('accessibilityMode') as boolean;
|
||||
if (!accessibility) {
|
||||
store.set('accessibilityMode', false);
|
||||
}
|
||||
// Only able to set the arialabel when accessibility mode is set to true
|
||||
// Otherwise it gets overwritten by the monaco default aria-label
|
||||
if (accessibility) {
|
||||
editor.updateOptions({
|
||||
ariaLabel:
|
||||
'Accessibility mode set to true. Press Ctrl+e to disable or press Alt+F1 for more options'
|
||||
});
|
||||
}
|
||||
|
||||
return accessibility;
|
||||
};
|
||||
|
||||
const accessibilityMode = storedAccessibilityMode();
|
||||
editor.updateOptions({
|
||||
accessibilitySupport: props.inAccessibilityMode ? 'on' : 'auto'
|
||||
accessibilitySupport: accessibilityMode ? 'on' : 'auto'
|
||||
});
|
||||
// Users who are using screen readers should not have to move focus from
|
||||
// the editor to the description every time they open a challenge.
|
||||
if (props.canFocus && !props.inAccessibilityMode) {
|
||||
if (props.canFocus && !accessibilityMode) {
|
||||
// TODO: only one Editor should be calling for focus at once.
|
||||
editor.focus();
|
||||
} else focusOnHotkeys();
|
||||
|
@ -343,28 +355,18 @@ const Editor = (props: EditorProps): JSX.Element => {
|
|||
editor.addAction({
|
||||
id: 'toggle-accessibility',
|
||||
label: 'Toggle Accessibility Mode',
|
||||
keybindings: [monaco.KeyMod.CtrlCmd | monaco.KeyCode.F1],
|
||||
keybindings: [monaco.KeyMod.CtrlCmd | monaco.KeyCode.KEY_E],
|
||||
run: () => {
|
||||
const currentAccessibility = props.inAccessibilityMode;
|
||||
// The store needs to be updated first, as onDidChangeConfiguration is
|
||||
// called before updateOptions returns
|
||||
props.setAccessibilityMode(!currentAccessibility);
|
||||
const currentAccessibility = storedAccessibilityMode();
|
||||
|
||||
store.set('accessibilityMode', !currentAccessibility);
|
||||
|
||||
editor.updateOptions({
|
||||
accessibilitySupport: currentAccessibility ? 'auto' : 'on'
|
||||
accessibilitySupport: storedAccessibilityMode() ? 'on' : 'auto',
|
||||
});
|
||||
}
|
||||
});
|
||||
editor.onDidFocusEditorWidget(() => props.setEditorFocusability(true));
|
||||
// This is to persist changes caused by the accessibility tooltip.
|
||||
editor.onDidChangeConfiguration(event => {
|
||||
if (
|
||||
event.hasChanged(monaco.editor.EditorOption.accessibilitySupport) &&
|
||||
editor.getRawOptions().accessibilitySupport === 'on' &&
|
||||
!props.inAccessibilityMode
|
||||
) {
|
||||
props.setAccessibilityMode(true);
|
||||
}
|
||||
});
|
||||
|
||||
const editableBoundaries = getEditableRegion();
|
||||
|
||||
|
|
|
@ -53,7 +53,12 @@ function ToolPanel({
|
|||
isMobile ? 'tool-panel-group-mobile' : ''
|
||||
}`}
|
||||
>
|
||||
<Button block={true} bsStyle='primary' onClick={handleRunTests}>
|
||||
<Button
|
||||
aria-label='Run the tests use shortcut Ctrl+enter'
|
||||
block={true}
|
||||
bsStyle='primary'
|
||||
onClick={handleRunTests}
|
||||
>
|
||||
{isMobile ? t('buttons.run') : t('buttons.run-test')}
|
||||
</Button>
|
||||
<Button
|
||||
|
|
|
@ -41,8 +41,7 @@ export const actionTypes = createTypes(
|
|||
'moveToTab',
|
||||
|
||||
'setEditorFocusability',
|
||||
'toggleVisibleEditor',
|
||||
'setAccessibilityMode'
|
||||
'toggleVisibleEditor'
|
||||
],
|
||||
ns
|
||||
);
|
||||
|
|
|
@ -31,7 +31,6 @@ const initialState = {
|
|||
challengeTests: [],
|
||||
consoleOut: [],
|
||||
hasCompletedBlock: false,
|
||||
inAccessibilityMode: false,
|
||||
isCodeLocked: false,
|
||||
isBuildEnabled: true,
|
||||
logsOut: [],
|
||||
|
@ -131,9 +130,6 @@ export const setEditorFocusability = createAction(
|
|||
export const toggleVisibleEditor = createAction(
|
||||
actionTypes.toggleVisibleEditor
|
||||
);
|
||||
export const setAccessibilityMode = createAction(
|
||||
actionTypes.setAccessibilityMode
|
||||
);
|
||||
|
||||
export const currentTabSelector = state => state[ns].currentTab;
|
||||
export const challengeFilesSelector = state => state[ns].challengeFiles;
|
||||
|
@ -211,9 +207,6 @@ export const challengeDataSelector = state => {
|
|||
export const canFocusEditorSelector = state => state[ns].canFocusEditor;
|
||||
export const visibleEditorsSelector = state => state[ns].visibleEditors;
|
||||
|
||||
export const inAccessibilityModeSelector = state =>
|
||||
state[ns].inAccessibilityMode;
|
||||
|
||||
export const reducer = handleActions(
|
||||
{
|
||||
[actionTypes.createFiles]: (state, { payload }) => ({
|
||||
|
@ -361,11 +354,7 @@ export const reducer = handleActions(
|
|||
[payload]: !state.visibleEditors[payload]
|
||||
}
|
||||
};
|
||||
},
|
||||
[actionTypes.setAccessibilityMode]: (state, { payload }) => ({
|
||||
...state,
|
||||
inAccessibilityMode: payload
|
||||
})
|
||||
}
|
||||
},
|
||||
initialState
|
||||
);
|
||||
|
|
Loading…
Reference in New Issue