fix(a11y): beta RWD feedback for code check (#45579)

* fix: beta RWD feedback for code check

* cleaned up comments

* move colon on hint heading to CSS

* fix: keep status message box size consistent
This commit is contained in:
Bruce B 2022-04-19 04:34:15 -07:00 committed by GitHub
parent 3c4f671629
commit 647469a479
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 82 additions and 29 deletions

View File

@ -62,6 +62,10 @@
animation-delay: 0.5s;
}
.action-row-container button[aria-hidden='true'] {
display: none;
}
@keyframes example {
from {
background-color: var(--highlight-background);
@ -80,6 +84,27 @@
padding-top: 5px;
}
#test-status .status {
font-family: revert;
}
#test-status p {
margin: 0.5rem 0 0;
}
#test-status h2.hint {
font-size: 1rem;
line-height: 1.5;
padding-right: 0.5rem;
/* using float instead of inline display so screen readers recognize h2 as a block element */
float: left;
margin: 0;
}
#test-status h2.hint::after {
content: ':';
}
.myEditableLineDecoration {
background-color: var(--gray-45);
width: 15px !important;

View File

@ -405,6 +405,7 @@ const Editor = (props: EditorProps): JSX.Element => {
if (challengeIsComplete()) {
props.submitChallenge();
} else {
clearTestFeedback();
props.executeChallenge();
}
} else {
@ -593,25 +594,40 @@ const Editor = (props: EditorProps): JSX.Element => {
return domNode;
}
function clearTestFeedback() {
const testStatus = document.getElementById('test-status');
if (testStatus && testStatus.innerHTML) {
const currentHeight = `${testStatus.offsetHeight}px`;
// Height will be cleared after status message has been displayed
testStatus.style.height = currentHeight;
testStatus.innerHTML = '';
}
}
function createOutputNode(editor: editor.IStandaloneCodeEditor) {
if (dataRef.current.outputNode) return dataRef.current.outputNode;
const outputNode = document.createElement('div');
const statusNode = document.createElement('div');
const hintNode = document.createElement('div');
const editorActionRow = document.createElement('div');
editorActionRow.classList.add('action-row-container');
outputNode.classList.add('editor-lower-jaw');
outputNode.appendChild(editorActionRow);
hintNode.setAttribute('id', 'test-output');
statusNode.setAttribute('id', 'test-status');
statusNode.setAttribute('aria-live', 'assertive');
const button = document.createElement('button');
button.setAttribute('id', 'test-button');
button.classList.add('btn-block');
button.innerHTML = 'Check Your Code (Ctrl + Enter)';
const submitButton = document.createElement('button');
submitButton.setAttribute('id', 'submit-button');
submitButton.setAttribute('aria-hidden', 'true');
submitButton.innerHTML = 'Submit your code (Ctrl + Enter)';
submitButton.classList.add('btn-block');
editorActionRow.appendChild(button);
editorActionRow.appendChild(submitButton);
editorActionRow.appendChild(statusNode);
editorActionRow.appendChild(hintNode);
button.onclick = () => {
clearTestFeedback();
const { executeChallenge } = props;
executeChallenge();
};
@ -630,17 +646,12 @@ const Editor = (props: EditorProps): JSX.Element => {
if (testButton) {
testButton.innerHTML = 'Check Your Code (Ctrl + Enter)';
testButton.onclick = () => {
clearTestFeedback();
props.executeChallenge();
};
}
const testStatus = document.getElementById('test-status');
if (testStatus) {
testStatus.innerHTML = '';
}
const testOutput = document.getElementById('test-output');
if (testOutput) {
testOutput.innerHTML = '';
}
clearTestFeedback();
// Resetting margin decorations
const range = model?.getDecorationRange(insideEditDecId);
@ -1019,18 +1030,32 @@ const Editor = (props: EditorProps): JSX.Element => {
const { output } = props;
const { model, insideEditDecId } = dataRef.current;
const editableRegion = getEditableRegionFromRedux();
const isEditorInFocus = document.activeElement?.tagName === 'TEXTAREA';
if (editableRegion.length === 2) {
const testOutput = document.getElementById('test-output');
const testStatus = document.getElementById('test-status');
if (challengeIsComplete()) {
const testButton = document.getElementById('test-button');
if (testButton) {
testButton.innerHTML =
'Submit your code and go to next challenge (Ctrl + Enter)';
testButton.onclick = () => {
// In case test button has focus, only visually hide it for now so we
// don't lose the focus before we set it on submit button.
testButton?.classList.add('sr-only');
const submitButton = document.getElementById('submit-button');
if (submitButton) {
submitButton.removeAttribute('aria-hidden');
submitButton.onclick = () => {
clearTestFeedback();
const { submitChallenge } = props;
submitChallenge();
};
// Delay setting focus on submit button to ensure aria-live status
// message is announced first by screen reader.
setTimeout(() => {
// Must set focus on submit button before removing test button from
// accessibility API since test button might have focus.
if (!isEditorInFocus) {
submitButton.focus();
}
testButton?.setAttribute('aria-hidden', 'true');
}, 500);
}
const range = model?.getDecorationRange(insideEditDecId);
@ -1044,23 +1069,26 @@ const Editor = (props: EditorProps): JSX.Element => {
);
}
if (testOutput && testStatus) {
testOutput.innerHTML = '';
testStatus.innerHTML = '✅ Step completed.';
const submitKeyboardInstructions = isEditorInFocus
? '<span class="sr-only">Use Ctrl + Enter to submit.</span>'
: '';
if (testStatus) {
testStatus.innerHTML = `<p class="status"><span aria-hidden="true">&#9989;</span> Congratulations, your code passes. Submit your code to complete this step and move on to the next one. ${submitKeyboardInstructions}</p>`;
testStatus.style.height = '';
}
} else if (challengeHasErrors() && testStatus && testOutput) {
} else if (challengeHasErrors() && testStatus) {
const wordsArray = [
"Not quite. Here's a hint:",
'Try again. This might help:',
'Keep trying. A quick hint for you:',
"You're getting there. This may help:",
"Hang in there. You'll get there. A hint:",
"Don't give up. Here's a hint to get you thinking:"
'Try again.',
'Keep trying.',
"You're getting there.",
'Hang in there.',
"Don't give up."
];
testStatus.innerHTML = `✖️ ${
testStatus.innerHTML = `<p class="status"><span aria-hidden="true">✖️</span> Sorry, your code does not pass. ${
wordsArray[Math.floor(Math.random() * wordsArray.length)]
}`;
testOutput.innerHTML = `${output[1]}`;
}</p><div><h2 class="hint">Hint</h2> ${output[1]}</div>`;
testStatus.style.height = '';
}
}
// eslint-disable-next-line react-hooks/exhaustive-deps