mirror of
https://github.com/freeCodeCamp/freeCodeCamp.git
synced 2026-06-16 21:06:35 +08:00
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:
parent
3c4f671629
commit
647469a479
@ -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;
|
||||
|
||||
@ -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">✅</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
|
||||
|
||||
Loading…
Reference in New Issue
Block a user