MOBILE-3759 a11y: Fix a11y of progress bars
parent
55b270f6b5
commit
cf59c2203f
|
@ -1452,6 +1452,7 @@
|
|||
"core.course.activitynotyetviewableremoteaddon": "local_moodlemobileapp",
|
||||
"core.course.activitynotyetviewablesiteupgradeneeded": "local_moodlemobileapp",
|
||||
"core.course.allsections": "local_moodlemobileapp",
|
||||
"core.course.aria:sectionprogress": "local_moodlemobileapp",
|
||||
"core.course.askadmintosupport": "local_moodlemobileapp",
|
||||
"core.course.availablespace": "local_moodlemobileapp",
|
||||
"core.course.cannotdeletewhiledownloading": "local_moodlemobileapp",
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
</ion-icon>
|
||||
</ion-button>
|
||||
<ion-badge class="core-course-download-courses-progress" *ngIf="prefetchCoursesData[selectedFilter].badge"
|
||||
role="progressbar" aria-valuemin="0" [attr.aria-valuemax]="prefetchCoursesData[selectedFilter].total"
|
||||
role="progressbar" [attr.aria-valuemax]="prefetchCoursesData[selectedFilter].total"
|
||||
[attr.aria-valuenow]="prefetchCoursesData[selectedFilter].count"
|
||||
[attr.aria-valuetext]="prefetchCoursesData[selectedFilter].badgeA11yText">
|
||||
{{prefetchCoursesData[selectedFilter].badge}}
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
<ion-icon [name]="prefetchCoursesData.icon" slot="icon-only" aria-hidden="true"></ion-icon>
|
||||
</ion-button>
|
||||
<ion-badge class="core-course-download-courses-progress" *ngIf="prefetchCoursesData.badge"
|
||||
role="progressbar" aria-valuemin="0" [attr.aria-valuemax]="prefetchCoursesData.total"
|
||||
role="progressbar" [attr.aria-valuemax]="prefetchCoursesData.total"
|
||||
[attr.aria-valuenow]="prefetchCoursesData.count" [attr.aria-valuetext]="prefetchCoursesData.badgeA11yText">
|
||||
{{prefetchCoursesData.badge}}
|
||||
</ion-badge>
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
<ion-icon [name]="prefetchCoursesData.icon" slot="icon-only" aria-hidden="true"></ion-icon>
|
||||
</ion-button>
|
||||
<ion-badge class="core-course-download-courses-progress" *ngIf="prefetchCoursesData.badge"
|
||||
role="progressbar" aria-valuemin="0" [attr.aria-valuemax]="prefetchCoursesData.total"
|
||||
role="progressbar" [attr.aria-valuemax]="prefetchCoursesData.total"
|
||||
[attr.aria-valuenow]="prefetchCoursesData.count" [attr.aria-valuetext]="prefetchCoursesData.badgeA11yText">
|
||||
{{prefetchCoursesData.badge}}
|
||||
</ion-badge>
|
||||
|
|
|
@ -22,9 +22,13 @@
|
|||
</ng-container>
|
||||
<ion-item class="ion-text-wrap" *ngIf="competencies.statistics.canbegradedincourse">
|
||||
<ion-label>
|
||||
{{ 'addon.competency.xcompetenciesproficientoutofyincourse' | translate: {$a:
|
||||
{x: competencies.statistics.proficientcompetencycount, y: competencies.statistics.competencycount} } }}
|
||||
<core-progress-bar [progress]="competencies.statistics.proficientcompetencypercentage"></core-progress-bar>
|
||||
<span id="addon-competency-course-{{courseId}}-progress">
|
||||
{{ 'addon.competency.xcompetenciesproficientoutofyincourse' | translate: {$a:
|
||||
{x: competencies.statistics.proficientcompetencycount, y: competencies.statistics.competencycount} } }}
|
||||
</span>
|
||||
<core-progress-bar [progress]="competencies.statistics.proficientcompetencypercentage"
|
||||
ariaDescribedBy="addon-competency-course-{{courseId}}-progress">
|
||||
</core-progress-bar>
|
||||
</ion-label>
|
||||
</ion-item>
|
||||
<ion-item class="ion-text-wrap"
|
||||
|
|
|
@ -52,13 +52,15 @@
|
|||
</ion-item>
|
||||
<ion-item class="ion-text-wrap" lines="none">
|
||||
<ion-label>
|
||||
<p>
|
||||
<p id="addon-competency-plan-{{plan.plan.id}}-progress">
|
||||
<strong>{{ 'addon.competency.progress' | translate }}</strong>:
|
||||
{{ 'addon.competency.xcompetenciesproficientoutofy' | translate:
|
||||
{$a: {x: plan.proficientcompetencycount, y: plan.competencycount} } }}
|
||||
</p>
|
||||
<core-progress-bar [progress]="plan.proficientcompetencypercentage"
|
||||
[text]="plan.proficientcompetencypercentageformatted"></core-progress-bar>
|
||||
[text]="plan.proficientcompetencypercentageformatted"
|
||||
ariaDescribedBy="addon-competency-plan-{{plan.plan.id}}-progress">
|
||||
</core-progress-bar>
|
||||
</ion-label>
|
||||
</ion-item>
|
||||
</ion-list>
|
||||
|
|
|
@ -85,7 +85,7 @@
|
|||
<ion-label>
|
||||
<ion-spinner></ion-spinner>
|
||||
<h2 *ngIf="progressMessage">{{ progressMessage | translate }}</h2>
|
||||
<core-progress-bar *ngIf="showPercentage" [progress]="percentage"></core-progress-bar>
|
||||
<core-progress-bar *ngIf="showPercentage" [progress]="percentage" [a11yText]="progressMessage"></core-progress-bar>
|
||||
</ion-label>
|
||||
</ion-item>
|
||||
</ion-list>
|
||||
|
|
|
@ -301,7 +301,8 @@
|
|||
</core-user-avatar>
|
||||
<ion-label>
|
||||
<h2>{{ student.fullname }}</h2>
|
||||
<core-progress-bar [progress]="student.bestgrade"></core-progress-bar>
|
||||
<core-progress-bar [progress]="student.bestgrade" a11yText="addon.mod_lesson.grade">
|
||||
</core-progress-bar>
|
||||
</ion-label>
|
||||
</ion-item>
|
||||
</ion-card>
|
||||
|
|
|
@ -170,8 +170,11 @@
|
|||
</ion-grid>
|
||||
<ion-item class="ion-text-wrap" *ngIf="lesson?.progressbar && !canManage && pageData">
|
||||
<ion-label>
|
||||
{{ 'addon.mod_lesson.progresscompleted' | translate:{$a: pageData.progress} }}
|
||||
<core-progress-bar [progress]="pageData.progress"></core-progress-bar>
|
||||
<span id="addon-mod_lesson-{{cmId}}-progress">
|
||||
{{ 'addon.mod_lesson.progresscompleted' | translate:{$a: pageData.progress} }}
|
||||
</span>
|
||||
<core-progress-bar [progress]="pageData.progress" ariaDescribedBy="addon-mod_lesson-{{cmId}}-progress">
|
||||
</core-progress-bar>
|
||||
</ion-label>
|
||||
</ion-item>
|
||||
<div class="core-info-card" *ngIf="lesson?.progressbar && canManage">
|
||||
|
@ -224,8 +227,12 @@
|
|||
</ion-item>
|
||||
<ion-item class="ion-text-wrap" *ngIf="lesson.progressbar && eolData.progresscompleted" lines="none">
|
||||
<ion-label>
|
||||
{{ 'addon.mod_lesson.progresscompleted' | translate:{$a: eolData.progresscompleted.value} }}
|
||||
<core-progress-bar [progress]="eolData.progresscompleted.value"></core-progress-bar>
|
||||
<span id="addon-mod_lesson-{{cmId}}-progress-end">
|
||||
{{ 'addon.mod_lesson.progresscompleted' | translate:{$a: eolData.progresscompleted.value} }}
|
||||
</span>
|
||||
<core-progress-bar [progress]="eolData.progresscompleted.value"
|
||||
ariaDescribedBy="addon-mod_lesson-{{cmId}}-progress-end">
|
||||
</core-progress-bar>
|
||||
</ion-label>
|
||||
</ion-item>
|
||||
<ion-item class="ion-text-wrap" *ngIf="eolData.displayofgrade" lines="none">
|
||||
|
|
|
@ -98,8 +98,8 @@ export class AddonModLessonPlayerPage implements OnInit, OnDestroy, CanLeave {
|
|||
loadingMenu?: boolean; // Whether the lesson menu is being loaded.
|
||||
mediaFile?: CoreWSExternalFile; // Media file of the lesson.
|
||||
activityLink?: AddonModLessonActivityLink; // Next activity link data.
|
||||
cmId!: number; // Course module ID.
|
||||
|
||||
protected cmId!: number; // Course module ID.
|
||||
protected password?: string; // Lesson password (if any).
|
||||
protected forceLeave = false; // If true, don't perform any check when leaving the view.
|
||||
protected offline?: boolean; // Whether we are in offline mode.
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
</core-user-avatar>
|
||||
<ion-label>
|
||||
<h2>{{student.fullname}}</h2>
|
||||
<core-progress-bar [progress]="student.bestgrade"></core-progress-bar>
|
||||
<core-progress-bar [progress]="student.bestgrade" a11yText="addon.mod_lesson.grade"></core-progress-bar>
|
||||
</ion-label>
|
||||
</ion-item>
|
||||
|
||||
|
|
|
@ -242,7 +242,8 @@
|
|||
<ion-label>
|
||||
<ion-spinner></ion-spinner>
|
||||
<h2 *ngIf="progressMessage">{{ progressMessage | translate }}</h2>
|
||||
<core-progress-bar *ngIf="showPercentage" [progress]="percentage"></core-progress-bar>
|
||||
<core-progress-bar *ngIf="showPercentage" [progress]="percentage" [a11yText]="progressMessage">
|
||||
</core-progress-bar>
|
||||
</ion-label>
|
||||
</ion-item>
|
||||
</ion-list>
|
||||
|
|
|
@ -1,5 +1,9 @@
|
|||
<ng-container *ngIf="progress >= 0">
|
||||
<progress max="100" [value]="progress" role="progressbar" [attr.aria-valuenow]="progress">
|
||||
<progress max="100" [value]="progress" role="progressbar" [attr.aria-valuenow]="progress"
|
||||
[attr.aria-valuetext]="progressBarValueText" [attr.aria-describedby]="ariaDescribedBy">
|
||||
</progress>
|
||||
<div class="core-progress-text">{{ 'core.percentagenumber' | translate: {$a: text} }}</div>
|
||||
<div class="core-progress-text">
|
||||
<span class="sr-only" *ngIf="a11yText">{{ a11yText | translate }}</span>
|
||||
{{ 'core.percentagenumber' | translate: {$a: text} }}
|
||||
</div>
|
||||
</ng-container>
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
|
||||
import { Component, Input, OnChanges, SimpleChange, ChangeDetectionStrategy } from '@angular/core';
|
||||
import { DomSanitizer, SafeStyle } from '@angular/platform-browser';
|
||||
import { Translate } from '@singletons';
|
||||
|
||||
/**
|
||||
* Component to show a progress bar and its value.
|
||||
|
@ -31,7 +32,12 @@ export class CoreProgressBarComponent implements OnChanges {
|
|||
|
||||
@Input() progress!: number | string; // Percentage from 0 to 100.
|
||||
@Input() text?: string; // Percentage in text to be shown at the right. If not defined, progress will be used.
|
||||
@Input() a11yText?: string; // Accessibility text to read before the percentage.
|
||||
@Input() ariaDescribedBy?: string; // ID of the element that described the progress, if any.
|
||||
|
||||
width?: SafeStyle;
|
||||
progressBarValueText?: string;
|
||||
|
||||
protected textSupplied = false;
|
||||
|
||||
constructor(private sanitizer: DomSanitizer) { }
|
||||
|
@ -66,6 +72,11 @@ export class CoreProgressBarComponent implements OnChanges {
|
|||
this.width = this.sanitizer.bypassSecurityTrustStyle(this.progress + '%');
|
||||
}
|
||||
}
|
||||
|
||||
if (changes.text || changes.progress || changes.a11yText) {
|
||||
this.progressBarValueText = (this.a11yText ? Translate.instant(this.a11yText) + ' ' : '') +
|
||||
Translate.instant('core.percentagenumber', { $a: this.text });
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -45,7 +45,8 @@
|
|||
<ng-container *ngIf="selectedSection">
|
||||
<ion-item class="core-course-progress"
|
||||
*ngIf="selectedSection?.id == allSectionsId && progress !== undefined">
|
||||
<core-progress-bar [progress]="progress"></core-progress-bar>
|
||||
<core-progress-bar [progress]="progress" a11yText="core.course.aria:sectionprogress">
|
||||
</core-progress-bar>
|
||||
</ion-item>
|
||||
<ion-item *ngIf="selectedSection && selectedSection.id != allSectionsId &&
|
||||
(selectedSection.availabilityinfo || selectedSection.visible === 0)">
|
||||
|
@ -159,7 +160,7 @@
|
|||
<!-- Download progress. -->
|
||||
<ion-badge class="core-course-download-section-progress"
|
||||
*ngIf="section.isDownloading && section.total > 0 && section.count < section.total" role="progressbar"
|
||||
aria-valuemin="0" [attr.aria-valuemax]="section.total" [attr.aria-valuenow]="section.count"
|
||||
[attr.aria-valuemax]="section.total" [attr.aria-valuenow]="section.count"
|
||||
[attr.aria-valuetext]="'core.course.downloadsectionprogressdescription' | translate:section">
|
||||
{{section.count}} / {{section.total}}
|
||||
</ion-badge>
|
||||
|
|
|
@ -105,6 +105,7 @@ export class CoreCourseFormatComponent implements OnInit, OnChanges, OnDestroy {
|
|||
progress?: number;
|
||||
sectionSelectorModalOptions: ModalOptions = {
|
||||
component: CoreCourseSectionSelectorComponent,
|
||||
componentProps: {},
|
||||
};
|
||||
|
||||
protected sectionStatusObserver?: CoreEventObserver;
|
||||
|
@ -124,12 +125,6 @@ export class CoreCourseFormatComponent implements OnInit, OnChanges, OnDestroy {
|
|||
* Component being initialized.
|
||||
*/
|
||||
ngOnInit(): void {
|
||||
|
||||
this.sectionSelectorModalOptions.componentProps = {
|
||||
course: this.course,
|
||||
sections: this.sections,
|
||||
};
|
||||
|
||||
// Listen for section status changes.
|
||||
this.sectionStatusObserver = CoreEvents.on(
|
||||
CoreEvents.SECTION_STATUS_CHANGED,
|
||||
|
@ -187,6 +182,8 @@ export class CoreCourseFormatComponent implements OnInit, OnChanges, OnDestroy {
|
|||
*/
|
||||
ngOnChanges(changes: { [name: string]: SimpleChange }): void {
|
||||
this.setInputData();
|
||||
this.sectionSelectorModalOptions.componentProps!.course = this.course;
|
||||
this.sectionSelectorModalOptions.componentProps!.sections = this.sections;
|
||||
|
||||
if (changes.course && this.course) {
|
||||
// Course has changed, try to get the components.
|
||||
|
|
|
@ -20,7 +20,9 @@
|
|||
<ion-label>
|
||||
<h2><core-format-text [text]="section.name" contextLevel="course" [contextInstanceId]="course?.id">
|
||||
</core-format-text></h2>
|
||||
<core-progress-bar *ngIf="section.progress >= 0" [progress]="section.progress"></core-progress-bar>
|
||||
<core-progress-bar *ngIf="section.progress >= 0" [progress]="section.progress"
|
||||
a11yText="core.course.aria:sectionprogress">
|
||||
</core-progress-bar>
|
||||
|
||||
<ion-badge color="info" *ngIf="section.visible === 0 && section.uservisible !== false"
|
||||
class="ion-text-wrap">
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
"activitynotyetviewableremoteaddon": "Your organisation installed a plugin that is not yet supported.",
|
||||
"activitynotyetviewablesiteupgradeneeded": "Your organisation's Moodle installation needs to be updated.",
|
||||
"allsections": "All sections",
|
||||
"aria:sectionprogress": "Section progress:",
|
||||
"askadmintosupport": "Contact the site administrator and tell them you want to use this activity with the Moodle Mobile app.",
|
||||
"availablespace": " You currently have about {{available}} free space.",
|
||||
"cannotdeletewhiledownloading": "Files cannot be deleted while the activity is being downloaded. Please wait for the download to finish.",
|
||||
|
|
|
@ -24,7 +24,7 @@
|
|||
</core-format-text>
|
||||
</h2>
|
||||
<p *ngIf="isEnrolled && course.progress! >= 0 && course.completionusertracked !== false">
|
||||
<core-progress-bar [progress]="course.progress"></core-progress-bar>
|
||||
<core-progress-bar [progress]="course.progress" a11yText="core.courses.aria:courseprogress"></core-progress-bar>
|
||||
</p>
|
||||
</ion-label>
|
||||
<ng-container *ngIf="!isEnrolled">
|
||||
|
|
|
@ -56,7 +56,7 @@
|
|||
</ion-item>
|
||||
<ion-item *ngIf="showAll && course.progress! >= 0 && course.completionusertracked !== false" lines="none">
|
||||
<ion-label>
|
||||
<core-progress-bar [progress]="course.progress"></core-progress-bar>
|
||||
<core-progress-bar [progress]="course.progress" a11yText="core.courses.aria:courseprogress"></core-progress-bar>
|
||||
</ion-label>
|
||||
</ion-item>
|
||||
<ng-content></ng-content>
|
||||
|
|
|
@ -20,7 +20,7 @@
|
|||
[attr.aria-label]="'core.loading' | translate"></ion-spinner>
|
||||
<ion-badge [hidden]="!downloadAllCoursesEnabled || !courses || courses.length < 2 || !downloadAllCoursesLoading ||
|
||||
downloadAllCoursesBadge == '' || !downloadAllCoursesLoading"
|
||||
role="progressbar" aria-valuemin="0" [attr.aria-valuemax]="downloadAllCoursesTotal"
|
||||
role="progressbar" [attr.aria-valuemax]="downloadAllCoursesTotal"
|
||||
[attr.aria-valuenow]="downloadAllCoursesCount" [attr.aria-valuetext]="downloadAllCoursesBadgeA11yText">
|
||||
{{downloadAllCoursesBadge}}
|
||||
</ion-badge>
|
||||
|
|
Loading…
Reference in New Issue