Skip to content

Commit

Permalink
Implemented extensive keyboard and screen reader navigation for explo…
Browse files Browse the repository at this point in the history
…ration editor (oppia#19102)

* made editor page extensively accessible

* fix lint

* fix lint

* fix lint

* fix test

* added a11y for publish exploration

* more accessible navigation

* fix lint

* fix lint

* fix test

* fix lint
  • Loading branch information
Patel-Muhammad authored Nov 11, 2023
1 parent 37c19d6 commit 57607c2
Show file tree
Hide file tree
Showing 58 changed files with 356 additions and 216 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -386,10 +386,6 @@ export class CkEditor4RteComponent implements AfterViewInit, OnChanges,
(
this.elementRef.nativeElement as HTMLElement
).setAttribute('style', 'display: block');
// Focus on the CK editor text box.
(
this.elementRef.nativeElement.children[0].children[1] as HTMLElement
).focus();
// Remove the loading text.
this.elementRef.nativeElement.parentElement.removeChild(loadingDiv);
// Set the css and icons for each toolbar button.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
(change)="this.addAudio($event)"
#fileInput>
</form>
<div class="license-warning">
<div class="license-warning" tabindex="0">
Please only upload audio files that you created yourself and that you are willing to license under the site's
<a href="/license"
[smartRouterLink]="'/' + licenseUrl"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,11 @@
class="form-control display-inline oppia-float-form-input e2e-test-float-form-input"
name="floatValue"
attr.placeholder="{{'I18N_FORMS_TYPE_NUMBER' | translate}}"
[oppiaFocusOn]="labelForFocusTarget"
(keypress)="onKeypress($event)"
applyValidation [validators]="validators"
(blur)="onBlur()" (focus)="onFocus()"
inputmode="numeric">
<span *ngIf="errorStringI18nKey" class="oppia-form-error oppia-numeric-input-error">
<span *ngIf="errorStringI18nKey" class="oppia-form-error oppia-numeric-input-error" tabindex="0">
{{ errorStringI18nKey | translate }}
</span>
<span *ngIf="hasLoaded && !userIsCurrentlyTyping && userHasFocusedAtLeastOnce"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
[disabled]="disabled"
required="!notRequired"
applyValidation [validators]="validators"
[oppiaFocusOn]="labelForFocusTarget"
(blur)="inputBlur.emit()"
(focus)="inputFocus.emit()">
</mat-form-field>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
<div class="h-100">
<!-- For the default answer group, 'rules' is null. Otherwise, 'rules' is a list of rules. -->
<div *ngIf="rules">
<strong class="oppia-answer-group-heading">
<strong class="oppia-answer-group-heading" tabindex="0">
If the learner's answer...
</strong>
<ul class="nav oppia-option-list nav-stacked nav-pills" role="tablist">
<li *ngFor="let rule of rules; let index = index;let last = last;" [ngClass]="{'active': activeRuleIndex === index, 'oppia-answer-rule-block': last}" class="mt-0 oppia-rule-block oppia-sortable-rule-block e2e-test-rule-block">
<a (click)="openRuleEditor(index)" [hidden]="activeRuleIndex === index" class="oppia-rule-tab e2e-test-answer-tab" [ngClass]="{'oppia-rule-tab-disabled': !isEditable}">
<a (click)="openRuleEditor(index)" tabindex="0" (keydown.enter)="openRuleEditor(index)" [hidden]="activeRuleIndex === index" class="oppia-rule-tab e2e-test-answer-tab" [ngClass]="{'oppia-rule-tab-disabled': !isEditable}">
<div class="oppia-rule-header">
<span *ngIf="index > 0">or</span>
<span *ngIf="getCurrentInteractionId() !== 'MultipleChoiceInput' && index !== activeRuleIndex">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,16 @@
<div class="oppia-click-to-start-editing e2e-test-open-hint-editor"
*ngIf="isEditable" (click)="openHintEditor()">
<i *ngIf="isEditable"
tabindex="0"
(keydown.enter)="openHintEditor()"
aria-label="edit hint"
class="fas fa-pen oppia-editor-edit-icon float-right"
title="Edit Hint">
</i>
</div>

<strong>Hint #{{indexPlusOne}} is...</strong>
<span>
<strong tabindex="0">Hint #{{indexPlusOne}} is...</strong>
<span tabindex="0">
<oppia-rte-output-display class="oppia-rte-editor"
[rteString]="hint.hintContent.html">
</oppia-rte-output-display>
Expand All @@ -26,7 +29,7 @@
<div *ngIf="isEditable && hintEditorIsOpen">
<div class="form-inline">
<div class="oppia-rule-details-header">
<strong>Hint # {{indexPlusOne}} is...</strong>
<strong tabindex="0">Hint # {{indexPlusOne}} is...</strong>
<!-- TODO(sll): Find a way to do this without resorting to private properties like _html -->
<schema-based-editor [schema]="getSchema()"
[localValue]="hint.hintContent._html"
Expand All @@ -35,7 +38,7 @@
</div>
</div>

<div *ngIf="isHintLengthExceeded()" class="oppia-length-validation-error">
<div *ngIf="isHintLengthExceeded()" class="oppia-length-validation-error" tabindex="0">
The hint length is too long. Please use at most 500 characters.
</div>

Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<div class="form-inline oppia-form-inline e2e-test-dest-bubble">
<div class="oppia-rule-details-header">
<strong *ngIf="outcomeHasFeedback">And afterwards, directs the learner to...</strong>
<strong *ngIf="!outcomeHasFeedback">Oppia directs the learner to...</strong>
<strong *ngIf="outcomeHasFeedback" tabindex="0">And afterwards, directs the learner to...</strong>
<strong *ngIf="!outcomeHasFeedback" tabindex="0">Oppia directs the learner to...</strong>
</div>
<div class="form-group oppia-form-group">
<span>
Expand All @@ -26,7 +26,7 @@
[attr.aria-invalid]="false" required>
</span>
</form>
<p [hidden]="newStateNameForm.form.valid || outcomeNewStateName === undefined" class="form-text oppia-form-error oppia-form-error-text">Please pick a card name consisting of alphanumeric characters, spaces and/or hyphens.</p>
<p [hidden]="newStateNameForm.form.valid || outcomeNewStateName === undefined" class="form-text oppia-form-error oppia-form-error-text" tabindex="0">Please pick a card name consisting of alphanumeric characters, spaces and/or hyphens.</p>

<div *ngIf="isSelfLoop() && canEditRefresherExplorationId && !!outcome.refresherExplorationId" class="oppia-id-text">
<b>Refresher exploration ID (optional):</b>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,24 +55,25 @@
<!-- Desktop -->
<div class="oppia-click-to-start-editing e2e-test-open-outcome-feedback-editor"
*ngIf="!onMobile && isEditable" (click)="openFeedbackEditor()">
<i *ngIf="isEditable" class="fas fa-pen oppia-editor-edit-icon float-right"
title="Edit Feedback">
<i *ngIf="isEditable" tabindex="0" (keydown.enter)="openFeedbackEditor()"
class="fas fa-pen oppia-editor-edit-icon float-right"
title="Edit Feedback" type="button">
</i>
</div>

<strong class="oppia-outcome-heading">Oppia tells the learner...</strong>
<strong class="oppia-outcome-heading" tabindex="0">Oppia tells the learner...</strong>
<div class="position-relative">
<span *ngIf="isSelfLoopWithNoFeedback(outcome) && !areWarningsSuppressed">
<span class="oppia-confusing-outcome-warning-text">
<span class="oppia-confusing-outcome-warning-text" tabindex="0">
<i class="material-icons">&#xE002;</i>
Please give Oppia something useful to say here.
</span>
</span>
<span *ngIf="(outcome && !isSelfLoopWithNoFeedback(outcome) && !outcome.hasNonemptyFeedback()) || (isSelfLoopWithNoFeedback(outcome) && areWarningsSuppressed)"
class="oppia-nothing-text">
<em>Nothing</em>
<em tabindex="0">Nothing</em>
</span>
<span *ngIf="outcome && outcome.hasNonemptyFeedback()" class="oppia-non-empty-feedback-text">
<span *ngIf="outcome && outcome.hasNonemptyFeedback()" class="oppia-non-empty-feedback-text" tabindex="0">
<oppia-rte-output-display class="oppia-rte-editor" [rteString]="outcome.feedback.html">
</oppia-rte-output-display>
</span>
Expand All @@ -91,7 +92,7 @@
</oppia-outcome-feedback-editor>
</form>

<div *ngIf="isFeedbackLengthExceeded()" class="oppia-length-validation-error">
<div *ngIf="isFeedbackLengthExceeded()" class="oppia-length-validation-error" tabindex="0">
The feedback length is too long. Please use at most 500 characters.
</div>

Expand Down Expand Up @@ -124,25 +125,25 @@
<div class="oppia-rule-preview oppia-transition-200">
<div class="oppia-click-to-start-editing e2e-test-open-outcome-dest-editor"
*ngIf="isEditable" (click)="openDestinationEditor()">
<i *ngIf="isEditable" class="fas fa-pen oppia-editor-edit-icon float-right"
title="Edit Destination">
<i *ngIf="isEditable" tabindex="0" class="fas fa-pen oppia-editor-edit-icon float-right"
title="Edit Destination" (keydown.enter)="openDestinationEditor()">
</i>
</div>

<div>
<strong class="oppia-outcome-heading" *ngIf="displayFeedback">And afterwards, directs the learner
<strong class="oppia-outcome-heading" *ngIf="displayFeedback" tabindex="0">And afterwards, directs the learner
to...</strong>
<strong class="oppia-outcome-heading" *ngIf="!displayFeedback">Oppia directs the learner to...</strong>
<span *ngIf="outcome && !isSelfLoop(outcome)" class="position-relative">
<strong class="oppia-outcome-heading" *ngIf="!displayFeedback" tabindex="0">Oppia directs the learner to...</strong>
<span *ngIf="outcome && !isSelfLoop(outcome)" class="position-relative" tabindex="0">
{{ outcome.dest }}
</span>
<span *ngIf="isSelfLoop(outcome)" class="position-relative">
<span tabindex="0" *ngIf="isSelfLoop(outcome)" class="position-relative">
<span *ngIf="!outcome.refresherExplorationId">(try again)</span>
<span *ngIf="outcome.refresherExplorationId">
(try again, with refresher exploration "{{ outcome.refresherExplorationId }}")
</span>
</span>
<div class="oppia-prerequisite-skill-text" *ngIf="outcome && outcome.missingPrerequisiteSkillId && canAddPrerequisiteSkill">
<div tabindex="0" class="oppia-prerequisite-skill-text" *ngIf="outcome && outcome.missingPrerequisiteSkillId && canAddPrerequisiteSkill">
<strong class="oppia-outcome-heading"> Attached prerequisite skill for the current state: </strong>
{{ outcome.missingPrerequisiteSkillId }}
</div>
Expand Down Expand Up @@ -189,18 +190,18 @@
<div class="oppia-rule-preview oppia-transition-200">
<div class="oppia-click-to-start-editing protractor-test-open-outcome-dest-if-stuck-editor"
*ngIf="isEditable" (click)="openDestinationIfStuckEditor()">
<i *ngIf="isEditable" class="fas fa-pen oppia-editor-edit-icon float-right"
title="Edit If Stuck Destination">
<i *ngIf="isEditable" (keydown.enter)="openDestinationIfStuckEditor()" class="fas fa-pen oppia-editor-edit-icon float-right"
title="Edit If Stuck Destination" tabindex="0">
</i>
</div>

<div>
<strong *ngIf="displayFeedback">(Optional) If the learner is really stuck, direct them to</strong>
<strong *ngIf="!displayFeedback">(Optional) Oppia directs the stuck learner to...</strong>
<span *ngIf="outcome && outcome.destIfReallyStuck !== null" class="position-relative">
<strong *ngIf="displayFeedback" tabindex="0">(Optional) If the learner is really stuck, direct them to</strong>
<strong *ngIf="!displayFeedback" tabindex="0">(Optional) Oppia directs the stuck learner to...</strong>
<span tabindex="0" *ngIf="outcome && outcome.destIfReallyStuck !== null" class="position-relative">
{{ outcome.destIfReallyStuck }}
</span>
<span *ngIf="!outcome || outcome.destIfReallyStuck === null" class="position-relative"></span>
<span tabindex="0" *ngIf="!outcome || outcome.destIfReallyStuck === null" class="position-relative"></span>
</div>
</div>
</div>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
<div class="form-inline oppia-form-inline protractor-test-dest-if-stuck-bubble">
<div class="oppia-rule-details-header">
<strong>(Optional) If the learner is really stuck, direct them to</strong>
<strong tabindex="0">(Optional) If the learner is really stuck, direct them to</strong>
<div ngbTooltip="{{ 'I18N_DEST_IF_STUCK_INFO_TOOLTIP' | translate }}"
tabindex="0"
data-container="body"
placement="right"
class="dest-if-stuck-tooltip">
<strong>&#x24D8;</strong>
Expand Down Expand Up @@ -30,7 +32,7 @@
[attr.aria-invalid]="false" required>
</span>
</form>
<p [hidden]="newStateNameForm.form.valid || outcomeNewStateName === undefined" class="form-text oppia-form-error oppia-form-error-text">Please pick a card name consisting of alphanumeric characters, spaces and/or hyphens.</p>
<p [hidden]="newStateNameForm.form.valid || outcomeNewStateName === undefined" class="form-text oppia-form-error oppia-form-error-text" tabindex="0">Please pick a card name consisting of alphanumeric characters, spaces and/or hyphens.</p>
</div>

<style>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,10 @@

<span class="oppia-delete-response-button oppia-transition-200 e2e-test-delete-response"
*ngIf="editabilityService.isEditable() && !defaultOutcome && !outcome"
(keydown.enter)="deleteResponse($event)"
tabindex="0"
role="button"
aria-label="delete response"
(click)="deleteResponse($event)">
<i class="material-icons md-18">&#xE5CD;</i>
</span>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,17 @@
class="oppia-click-to-start-editing"
(click)="openEditorModal()">
<i class="material-icons oppia-editor-edit-icon float-right"
tabindex="0"
(keydown.enter)="openEditorModal()"
aria-label="Edit Solution"
role="button"
title="Edit Solution">&#xE254;
</i>
</div>
<strong>
<strong tabindex="0">
{{stateSolutionService.savedMemento.answerIsExclusive ? 'The only' : 'One'}} solution is...
</strong>
<span>
<span tabindex="0">
<oppia-interaction-display [htmlData]="getAnswerHtml()">
</oppia-interaction-display>
</span>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,14 @@
<div class="oppia-click-to-start-editing"
*ngIf="isEditable" (click)="openExplanationEditor()">
<i class="material-icons oppia-editor-edit-icon float-right"
(keydown.enter)="openExplanationEditor()"
tabindex="0"
aria-label="Edit Explanation"
title="Edit Explanation">&#xE254;
</i>
</div>
<strong>Explanation:</strong>
<span>
<strong tabindex="0">Explanation:</strong>
<span tabindex="0">
<oppia-rte-output-display class="oppia-rte-editor" [rteString]="stateSolutionService.savedMemento.explanation.html">
</oppia-rte-output-display>
</span>
Expand All @@ -22,15 +25,15 @@

<div *ngIf="isEditable && explanationEditorIsOpen">
<div class="oppia-rule-details-header">
<strong>Explanation:</strong>
<strong tabindex="0">Explanation:</strong>
<!-- TODO(sll): Find a way to do this without resorting to private properties like _html -->
<schema-based-editor [schema]="getSchema()"
[localValue]="stateSolutionService.displayed.explanation._html"
(localValueChange)="updateExplanationHtml($event)">
</schema-based-editor>
</div>

<div *ngIf="isSolutionExplanationLengthExceeded()" class="oppia-length-validation-error">
<div *ngIf="isSolutionExplanationLengthExceeded()" class="oppia-length-validation-error" tabindex="0">
The solution explanation is too long. Please use at most 1000 characters.
</div>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,12 @@
<button class="fas fa-pen oppia-editor-edit-icon oppia-editor-edit-icon-position e2e-test-edit-content-pencil-button" title="Edit Card Content"></button>
<div class="oppia-prevent-selection oppia-state-content-display oppia-transition-200"
title="Card Content">
<span [hidden]="!stateContentService.savedMemento.isEmpty()" class="oppia-placeholder">
<span [hidden]="!stateContentService.savedMemento.isEmpty()" tabindex="0" class="oppia-placeholder">
{{ stateContentPlaceholder }}
</span>
<span>
<oppia-rte-output-display [rteString]="stateContentService.savedMemento.html"
tabindex="0"
class="oppia-rte-editor e2e-test-state-content-display">
</oppia-rte-output-display>
</span>
Expand All @@ -38,6 +39,7 @@
<div *ngIf="!isContentEditable()"
class="e2e-test-edit-content">
<div class="oppia-prevent-selection oppia-state-content-display oppia-transition-200"
tabindex="0"
title="Card Content">
<span [hidden]="!stateContentService.savedMemento.isEmpty()" class="oppia-placeholder">
{{ stateContentPlaceholder }}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,19 +6,19 @@
(click)="toggleHintCard()"
(keydown.enter)="toggleHintCard()">
<div class="state-hints-header">
<h3 class="oppia-exp-hints-card-header">Hints</h3>
<h3 class="oppia-exp-hints-card-header" tabindex="0">Hints</h3>
<i class="fa fa-caret-down"
*ngIf="!hintCardIsShown"
tabindex="0"
role="button"
aria-label="Expand interaction"
aria-label="Expand hint card"
[attr.aria-hidden]="hintCardIsShown ? 'true' : 'false'">
</i>
<i class="fa fa-caret-up"
*ngIf="hintCardIsShown"
tabindex="0"
role="button"
aria-label="collapse interaction"
aria-label="collapse hint card"
[attr.aria-hidden]="hintCardIsShown ? 'false' : 'true'">
</i>
</div>
Expand All @@ -27,6 +27,7 @@ <h3 class="oppia-exp-hints-card-header">Hints</h3>
<div class="oppia-add-hint-button-container">
<div *ngIf="editabilityService.isEditableOutsideTutorialMode() && editabilityService.isEditable()">
<button type="button"
aria-label="Add hint"
class="btn btn-primary oppia-add-hint-button e2e-test-oppia-add-hint-button"
(click)="openAddHintModal()"
[disabled]="stateHintsService.displayed.length >= 5">
Expand All @@ -53,6 +54,8 @@ <h3 class="oppia-exp-hints-card-header">Hints</h3>
</picture>
</span>
<a (click)="changeActiveHintIndex(index)"
tabindex="0"
(keydown.enter)="changeActiveHintIndex(index)"
class="oppia-rule-tab e2e-test-hint-tab"
ngClass="{'oppia-rule-tab-active': stateHintsService.getActiveHintIndex() === index}">
<oppia-response-header class="oppia-response-header-center"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,14 @@ <h3 class="oppia-exp-interaction-card-header">
*ngIf="!interactionEditorIsShown"
tabindex="0"
role="button"
aria-label="Expand interaction"
aria-label="Expand interaction card"
[attr.aria-hidden]="interactionEditorIsShown ? 'true' : 'false'">
</i>
<i class="fa fa-caret-up"
*ngIf="interactionEditorIsShown"
tabindex="0"
role="button"
aria-label="collapse answers and responses"
aria-label="collapse interaction card"
[attr.aria-hidden]="interactionEditorIsShown ? 'false' : 'true'">
</i>
</div>
Expand All @@ -32,6 +32,7 @@ <h3 class="oppia-exp-interaction-card-header">
<button type="button"
class="btn btn-secondary oppia-add-interaction-button e2e-test-open-add-interaction-modal"
(click)="openInteractionCustomizerModal()"
aria-label="Add interaction"
*ngIf="editabilityService.isEditable()">
+ ADD INTERACTION
</button>
Expand Down
Loading

0 comments on commit 57607c2

Please sign in to comment.