MOBILE-3744 a11y: Improve some aria roles

main
Pau Ferrer Ocaña 2021-04-28 16:19:50 +02:00
parent 632e7dfc0c
commit 9f42b80b06
31 changed files with 45 additions and 54 deletions

View File

@ -18,7 +18,7 @@
<ion-label> <ion-label>
<div class="large-avatar"> <div class="large-avatar">
<img class="avatar" [src]="conversation!.imageurl" core-external-content [alt]="conversation!.name" <img class="avatar" [src]="conversation!.imageurl" core-external-content [alt]="conversation!.name"
role="presentation" onError="this.src='assets/img/group-avatar.png'"> onError="this.src='assets/img/group-avatar.png'">
</div> </div>
<h2> <h2>
<core-format-text [text]="conversation!.name" contextLevel="system" [contextInstanceId]="0"></core-format-text> <core-format-text [text]="conversation!.name" contextLevel="system" [contextInstanceId]="0"></core-format-text>

View File

@ -6,7 +6,7 @@
<ion-title> <ion-title>
<div class="toolbar-title"> <div class="toolbar-title">
<img *ngIf="loaded && !otherMember && conversationImage" class="core-bar-button-image" [src]="conversationImage" <img *ngIf="loaded && !otherMember && conversationImage" class="core-bar-button-image" [src]="conversationImage"
[alt]="title" onError="this.src='assets/img/group-avatar.png'" core-external-content role="presentation" alt="" onError="this.src='assets/img/group-avatar.png'" core-external-content role="presentation"
[siteId]="siteId || null"> [siteId]="siteId || null">
<core-user-avatar *ngIf="loaded && otherMember" class="core-bar-button-image" [user]="otherMember" <core-user-avatar *ngIf="loaded && otherMember" class="core-bar-button-image" [user]="otherMember"
[linkProfile]="false" [checkOnline]="otherMember.showonlinestatus" (click)="showInfo && viewInfo()"> [linkProfile]="false" [checkOnline]="otherMember.showonlinestatus" (click)="showInfo && viewInfo()">

View File

@ -34,7 +34,7 @@
<!-- Favourite conversations. --> <!-- Favourite conversations. -->
<ion-item-divider class="ion-text-wrap core-expandable" (click)="toggle(favourites)" sticky="true" <ion-item-divider class="ion-text-wrap core-expandable" (click)="toggle(favourites)" sticky="true"
[attr.aria-label]="(favourites.expanded ? 'core.collapse' : 'core.expand') | translate" [attr.aria-label]="(favourites.expanded ? 'core.collapse' : 'core.expand') | translate"
[attr.aria-expanded]="favourites.expanded"> [attr.aria-expanded]="favourites.expanded" role="heading">
<ion-icon *ngIf="!favourites.expanded" name="fas-caret-right" slot="start" aria-hidden="true"></ion-icon> <ion-icon *ngIf="!favourites.expanded" name="fas-caret-right" slot="start" aria-hidden="true"></ion-icon>
<ion-icon *ngIf="favourites.expanded" name="fas-caret-down" slot="start" aria-hidden="true"></ion-icon> <ion-icon *ngIf="favourites.expanded" name="fas-caret-down" slot="start" aria-hidden="true"></ion-icon>
<ion-label>{{ 'core.favourites' | translate }} ({{ favourites.count }})</ion-label> <ion-label>{{ 'core.favourites' | translate }} ({{ favourites.count }})</ion-label>
@ -57,7 +57,7 @@
<!-- Group conversations. --> <!-- Group conversations. -->
<ion-item-divider class="ion-text-wrap core-expandable" (click)="toggle(group)" sticky="true" <ion-item-divider class="ion-text-wrap core-expandable" (click)="toggle(group)" sticky="true"
[attr.aria-label]="(group.expanded ? 'core.collapse' : 'core.expand') | translate" [attr.aria-label]="(group.expanded ? 'core.collapse' : 'core.expand') | translate"
[attr.aria-expanded]="group.expanded"> [attr.aria-expanded]="group.expanded" role="heading">
<ion-icon *ngIf="!group.expanded" name="fas-caret-right" slot="start" aria-hidden="true"></ion-icon> <ion-icon *ngIf="!group.expanded" name="fas-caret-right" slot="start" aria-hidden="true"></ion-icon>
<ion-icon *ngIf="group.expanded" name="fas-caret-down" slot="start" aria-hidden="true"></ion-icon> <ion-icon *ngIf="group.expanded" name="fas-caret-down" slot="start" aria-hidden="true"></ion-icon>
<ion-label>{{ 'addon.messages.groupconversations' | translate }} ({{ group.count }})</ion-label> <ion-label>{{ 'addon.messages.groupconversations' | translate }} ({{ group.count }})</ion-label>
@ -79,7 +79,7 @@
<ion-item-divider class="ion-text-wrap core-expandable" (click)="toggle(individual)" sticky="true" <ion-item-divider class="ion-text-wrap core-expandable" (click)="toggle(individual)" sticky="true"
[attr.aria-label]="(individual.expanded ? 'core.collapse' : 'core.expand') | translate" [attr.aria-label]="(individual.expanded ? 'core.collapse' : 'core.expand') | translate"
[attr.aria-expanded]="individual.expanded"> [attr.aria-expanded]="individual.expanded" role="heading">
<ion-icon *ngIf="!individual.expanded" name="fas-caret-right" slot="start" aria-hidden="true"></ion-icon> <ion-icon *ngIf="!individual.expanded" name="fas-caret-right" slot="start" aria-hidden="true"></ion-icon>
<ion-icon *ngIf="individual.expanded" name="fas-caret-down" slot="start" aria-hidden="true"></ion-icon> <ion-icon *ngIf="individual.expanded" name="fas-caret-down" slot="start" aria-hidden="true"></ion-icon>
<ion-label>{{ 'addon.messages.individualconversations' | translate }} ({{ individual.count }})</ion-label> <ion-label>{{ 'addon.messages.individualconversations' | translate }} ({{ individual.count }})</ion-label>

View File

@ -32,7 +32,7 @@ component="mod_data" [itemId]="entry.id" area="database_entry" [courseId]="datab
<a *ngIf="action == 'userpicture'" core-user-link [courseId]="database.course" [userId]="entry.userid" [title]="entry.fullname"> <a *ngIf="action == 'userpicture'" core-user-link [courseId]="database.course" [userId]="entry.userid" [title]="entry.fullname">
<img class="avatar-round" [src]="userPicture" [alt]="'core.pictureof' | translate:{$a: entry.fullname}" core-external-content <img class="avatar-round" [src]="userPicture" [alt]="'core.pictureof' | translate:{$a: entry.fullname}" core-external-content
onError="this.src='assets/img/user-avatar.png'" role="presentation"> onError="this.src='assets/img/user-avatar.png'">
</a> </a>
<a *ngIf="action == 'user' && entry" core-user-link [courseId]="database.course" [userId]="entry.userid" [title]="entry.fullname"> <a *ngIf="action == 'user' && entry" core-user-link [courseId]="database.course" [userId]="entry.userid" [title]="entry.fullname">

View File

@ -59,7 +59,7 @@
</ng-container> </ng-container>
<ion-textarea *ngIf="item.templateName == 'textarea'" [required]="item.required" <ion-textarea *ngIf="item.templateName == 'textarea'" [required]="item.required"
name="{{item.typ}}_{{item.id}}" [attr.aria-multiline]="true" [(ngModel)]="item.value"> name="{{item.typ}}_{{item.id}}" [(ngModel)]="item.value">
</ion-textarea> </ion-textarea>
<ion-select *ngIf="item.templateName == 'multichoice-d'" [required]="item.required" <ion-select *ngIf="item.templateName == 'multichoice-d'" [required]="item.required"

View File

@ -25,8 +25,8 @@
(contentChanged)="onMessageChange($event)"> (contentChanged)="onMessageChange($event)">
</core-rich-text-editor> </core-rich-text-editor>
</ion-item> </ion-item>
<ion-item-divider class="ion-text-wrap core-expandable" (click)="toggleAdvanced()" <ion-item-divider class="ion-text-wrap core-expandable" (click)="toggleAdvanced()" role="heading"
[attr.aria-expanded]="advanced" [attr.aria-label]="(advanced ? 'core.hideadvanced' : 'core.showadvanced') |translate"> [attr.aria-expanded]="advanced" [attr.aria-label]="(advanced ? 'core.hideadvanced' : 'core.showadvanced') | translate">
<ion-icon *ngIf="!advanced" name="fa-caret-right" slot="start" aria-hidden="true"></ion-icon> <ion-icon *ngIf="!advanced" name="fa-caret-right" slot="start" aria-hidden="true"></ion-icon>
<ion-icon *ngIf="advanced" name="fa-caret-down" slot="start" aria-hidden="true"></ion-icon> <ion-icon *ngIf="advanced" name="fa-caret-down" slot="start" aria-hidden="true"></ion-icon>
<ion-label>{{ 'addon.mod_forum.advanced' | translate }}</ion-label> <ion-label>{{ 'addon.mod_forum.advanced' | translate }}</ion-label>

View File

@ -71,7 +71,7 @@
<ion-button *ngIf="sortingAvailable" id="addon-mod-forum-sort-order-button" <ion-button *ngIf="sortingAvailable" id="addon-mod-forum-sort-order-button"
class="core-button-select button-no-uppercase" class="core-button-select button-no-uppercase"
aria-haspopup="true" aria-controls="addon-mod-forum-sort-order-selector" aria-haspopup="true" aria-controls="addon-mod-forum-sort-order-selector"
[attr.aria-label]="('core.sort' | translate)" [attr.aria-expanded]="sortOrderSelectorExpanded" [attr.aria-label]="('core.sort' | translate)"
(click)="showSortOrderSelector()"> (click)="showSortOrderSelector()">
<span class="core-button-select-text">{{ selectedSortOrder.label | translate }}</span> <span class="core-button-select-text">{{ selectedSortOrder.label | translate }}</span>
<div class="select-icon" slot="end"><div class="select-icon-inner"></div></div> <div class="select-icon" slot="end"><div class="select-icon-inner"></div></div>

View File

@ -79,7 +79,6 @@ export class AddonModForumIndexComponent extends CoreCourseModuleMainActivityCom
sortingAvailable!: boolean; sortingAvailable!: boolean;
sortOrders: AddonModForumSortOrder[] = []; sortOrders: AddonModForumSortOrder[] = [];
selectedSortOrder: AddonModForumSortOrder | null = null; selectedSortOrder: AddonModForumSortOrder | null = null;
sortOrderSelectorExpanded = false;
canPin = false; canPin = false;
protected syncEventName = AddonModForumSyncProvider.AUTO_SYNCED; protected syncEventName = AddonModForumSyncProvider.AUTO_SYNCED;
@ -637,12 +636,8 @@ export class AddonModForumIndexComponent extends CoreCourseModuleMainActivityCom
modal.present(); modal.present();
this.sortOrderSelectorExpanded = true;
const result = await modal.onDidDismiss<AddonModForumSortOrder>(); const result = await modal.onDidDismiss<AddonModForumSortOrder>();
this.sortOrderSelectorExpanded = false;
if (result.data && result.data.value != this.selectedSortOrder?.value) { if (result.data && result.data.value != this.selectedSortOrder?.value) {
this.selectedSortOrder = result.data; this.selectedSortOrder = result.data;
this.page = 0; this.page = 0;

View File

@ -11,9 +11,9 @@
<ion-content> <ion-content>
<ion-list id="addon-mod-forum-sort-selector" role="menu" aria-labelledby="addon-mod-forum-sort-order-button"> <ion-list id="addon-mod-forum-sort-selector" role="menu" aria-labelledby="addon-mod-forum-sort-order-button">
<ng-container *ngFor="let sortOrder of sortOrders"> <ng-container *ngFor="let sortOrder of sortOrders">
<ion-item class="ion-text-wrap" detail="false" role="menuitem" <ion-item class="ion-text-wrap" detail="false" role="combobox" button aria-haspopup="dialog"
[class.core-selected-item]="selected == sortOrder.value" [attr.aria-label]="sortOrder.label | translate" [attr.aria-current]="selected == sortOrder.value ? 'page' : 'false'"
(click)="selectSortOrder(sortOrder)"> [attr.aria-label]="sortOrder.label | translate" (click)="selectSortOrder(sortOrder)">
<ion-label> <ion-label>
<h2>{{ sortOrder.label | translate }}</h2> <h2>{{ sortOrder.label | translate }}</h2>
</ion-label> </ion-label>

View File

@ -32,7 +32,7 @@
</core-rich-text-editor> </core-rich-text-editor>
</ion-item> </ion-item>
<ion-item-divider class="ion-text-wrap core-expandable" (click)="toggleAdvanced()" [attr.aria-expanded]="advanced" <ion-item-divider class="ion-text-wrap core-expandable" (click)="toggleAdvanced()" [attr.aria-expanded]="advanced"
[attr.aria-label]="(advanced ? 'core.hideadvanced' : 'core.showadvanced') |translate"> [attr.aria-label]="(advanced ? 'core.hideadvanced' : 'core.showadvanced') |translate" role="heading">
<ion-icon *ngIf="!advanced" name="fa-caret-right" slot="start" aria-hidden="true"></ion-icon> <ion-icon *ngIf="!advanced" name="fa-caret-right" slot="start" aria-hidden="true"></ion-icon>
<ion-icon *ngIf="advanced" name="fa-caret-down" slot="start" aria-hidden="true"></ion-icon> <ion-icon *ngIf="advanced" name="fa-caret-down" slot="start" aria-hidden="true"></ion-icon>
<ion-label>{{ 'addon.mod_forum.advanced' | translate }}</ion-label> <ion-label>{{ 'addon.mod_forum.advanced' | translate }}</ion-label>

View File

@ -11,7 +11,7 @@
<ion-buttons slot="end"> <ion-buttons slot="end">
<ion-button id="addon-mod_quiz-connection-error-button" [hidden]="!autoSaveError" (click)="showConnectionError($event)" <ion-button id="addon-mod_quiz-connection-error-button" [hidden]="!autoSaveError" (click)="showConnectionError($event)"
[attr.aria-label]="'addon.mod_quiz.connectionerror' | translate" aria-haspopup="true"> [attr.aria-label]="'addon.mod_quiz.connectionerror' | translate" aria-haspopup="dialog">
<ion-icon name="fas-exclamation-circle" slot="icon-only" aria-hidden="true"></ion-icon> <ion-icon name="fas-exclamation-circle" slot="icon-only" aria-hidden="true"></ion-icon>
</ion-button> </ion-button>
<ion-button *ngIf="navigation.length" [attr.aria-label]="'addon.mod_quiz.opentoc' | translate" <ion-button *ngIf="navigation.length" [attr.aria-label]="'addon.mod_quiz.opentoc' | translate"

View File

@ -32,7 +32,7 @@
<ion-label position="stacked"> <ion-label position="stacked">
{{ 'addon.mod_workshop_assessment_accumulative.dimensioncommentfor' | translate : {'$a': field.dimtitle } }} {{ 'addon.mod_workshop_assessment_accumulative.dimensioncommentfor' | translate : {'$a': field.dimtitle } }}
</ion-label> </ion-label>
<ion-textarea aria-multiline="true" [(ngModel)]="selectedValues[n].peercomment" core-auto-rows></ion-textarea> <ion-textarea [(ngModel)]="selectedValues[n].peercomment" core-auto-rows></ion-textarea>
</ion-item> </ion-item>
<ion-item *ngIf="!edit" class="ion-text-wrap"> <ion-item *ngIf="!edit" class="ion-text-wrap">
<ion-label> <ion-label>

View File

@ -14,7 +14,7 @@
{{ 'addon.mod_workshop_assessment_comments.dimensioncommentfor' | translate : {'$a': field.dimtitle } }} {{ 'addon.mod_workshop_assessment_comments.dimensioncommentfor' | translate : {'$a': field.dimtitle } }}
</span> </span>
</ion-label> </ion-label>
<ion-textarea aria-multiline="true" [(ngModel)]="selectedValues[n].peercomment" core-auto-rows></ion-textarea> <ion-textarea [(ngModel)]="selectedValues[n].peercomment" core-auto-rows></ion-textarea>
<core-input-errors *ngIf="fieldErrors['peercomment_' + n]" [errorText]="fieldErrors['peercomment_' + n]"> <core-input-errors *ngIf="fieldErrors['peercomment_' + n]" [errorText]="fieldErrors['peercomment_' + n]">
</core-input-errors> </core-input-errors>
</ion-item> </ion-item>

View File

@ -35,7 +35,7 @@
<ion-label position="stacked"> <ion-label position="stacked">
{{ 'addon.mod_workshop_assessment_numerrors.dimensioncommentfor' | translate : {'$a': field.dimtitle } }} {{ 'addon.mod_workshop_assessment_numerrors.dimensioncommentfor' | translate : {'$a': field.dimtitle } }}
</ion-label> </ion-label>
<ion-textarea aria-multiline="true" [(ngModel)]="selectedValues[n].peercomment" [name]="'peercomment_' + n" <ion-textarea [(ngModel)]="selectedValues[n].peercomment" [name]="'peercomment_' + n"
core-auto-rows> core-auto-rows>
</ion-textarea> </ion-textarea>
</ion-item> </ion-item>

View File

@ -22,7 +22,7 @@
<ion-textarea *ngIf="essayQuestion.isPlainText" class="core-question-textarea" <ion-textarea *ngIf="essayQuestion.isPlainText" class="core-question-textarea"
[ngClass]='{"core-monospaced": essayQuestion.isMonospaced}' [ngClass]='{"core-monospaced": essayQuestion.isMonospaced}'
placeholder="{{ 'core.question.answer' | translate }}" placeholder="{{ 'core.question.answer' | translate }}"
[attr.name]="essayQuestion.textarea.name" aria-multiline="true" [ngModel]="essayQuestion.textarea.text"> [attr.name]="essayQuestion.textarea.name" [ngModel]="essayQuestion.textarea.text">
</ion-textarea> </ion-textarea>
<!-- Rich text editor. --> <!-- Rich text editor. -->
<core-rich-text-editor *ngIf="!essayQuestion.isPlainText" placeholder="{{ 'core.question.answer' | translate }}" <core-rich-text-editor *ngIf="!essayQuestion.isPlainText" placeholder="{{ 'core.question.answer' | translate }}"

View File

@ -35,7 +35,6 @@ export class CoreContextMenuComponent implements OnInit, OnDestroy {
@Input('aria-label') ariaLabel?: string; // Aria label to be shown on the top of the popover. @Input('aria-label') ariaLabel?: string; // Aria label to be shown on the top of the popover.
hideMenu = true; // It will be unhidden when items are added. hideMenu = true; // It will be unhidden when items are added.
expanded = false;
uniqueId: string; uniqueId: string;
protected items: CoreContextMenuItemComponent[] = []; protected items: CoreContextMenuItemComponent[] = [];
@ -43,6 +42,7 @@ export class CoreContextMenuComponent implements OnInit, OnDestroy {
protected itemsChangedStream: Subject<void>; // Stream to update the hideMenu boolean when items change. protected itemsChangedStream: Subject<void>; // Stream to update the hideMenu boolean when items change.
protected instanceId: string; protected instanceId: string;
protected parentContextMenu?: CoreContextMenuComponent; protected parentContextMenu?: CoreContextMenuComponent;
protected expanded = false;
constructor( constructor(
elementRef: ElementRef, elementRef: ElementRef,

View File

@ -1,5 +1,5 @@
<ion-button [hidden]="hideMenu" fill="clear" [attr.aria-label]="ariaLabel" <ion-button [hidden]="hideMenu" fill="clear" [attr.aria-label]="ariaLabel" (click)="showContextMenu($event)" aria-haspopup="true"
(click)="showContextMenu($event)" aria-haspopup="true" [attr.aria-expanded]="expanded" [attr.aria-controls]="uniqueId"> [attr.aria-controls]="uniqueId">
<ion-icon [name]="icon" slot="icon-only" aria-hidden="true"> <ion-icon [name]="icon" slot="icon-only" aria-hidden="true">
</ion-icon> </ion-icon>
</ion-button> </ion-button>

View File

@ -1,8 +1,7 @@
<div class="core-empty-box ion-padding" [class.core-empty-box-inline]="(!image && !icon) || inline"> <div class="core-empty-box ion-padding" [class.core-empty-box-inline]="(!image && !icon) || inline">
<div class="core-empty-box-content"> <div class="core-empty-box-content">
<img *ngIf="image && !icon" [src]="image" role="presentation" aria-hidden="true"> <img *ngIf="image && !icon" [src]="image" role="presentation" alt="">
<ion-icon *ngIf="icon" [name]="icon" [class.icon-flip-rtl]="flipIconRtl" role="presentation" aria-hidden="true"> <ion-icon *ngIf="icon" [name]="icon" [class.icon-flip-rtl]="flipIconRtl" aria-hidden="true"></ion-icon>
</ion-icon>
<p *ngIf="message" [class.ion-padding-top]="image || icon">{{ message }}</p> <p *ngIf="message" [class.ion-padding-top]="image || icon">{{ message }}</p>
<ng-content></ng-content> <ng-content></ng-content>
</div> </div>

View File

@ -1,8 +1,7 @@
<form #messageForm> <form #messageForm>
<textarea class="core-send-message-input" [autofocus]="showKeyboard" [placeholder]="placeholder" rows="1" core-auto-rows <textarea class="core-send-message-input" [autofocus]="showKeyboard" [placeholder]="placeholder" rows="1" core-auto-rows
[(ngModel)]="message" name="message" (onResize)="textareaResized()" (keydown.enter)="enterClicked($event)" [(ngModel)]="message" name="message" (onResize)="textareaResized()" (keydown.enter)="enterClicked($event)"
(keydown.control.enter)="enterClicked($event, 'control')" (keydown.meta.enter)="enterClicked($event, 'meta')" (keydown.control.enter)="enterClicked($event, 'control')" (keydown.meta.enter)="enterClicked($event, 'meta')"></textarea>
aria-multiline="true"></textarea>
<ion-buttons> <ion-buttons>
<ion-button fill="clear" type="submit" [disabled]="!message || sendDisabled" <ion-button fill="clear" type="submit" [disabled]="!message || sendDisabled"
[attr.aria-label]="'core.send' | translate" [core-suppress-events] (onClick)="submitForm($event)"> [attr.aria-label]="'core.send' | translate" [core-suppress-events] (onClick)="submitForm($event)">

View File

@ -1,7 +1,7 @@
<img *ngIf="avatarUrl" [src]="avatarUrl" [alt]="'core.pictureof' | translate:{$a: fullname}" core-external-content <img *ngIf="avatarUrl" [src]="avatarUrl" [alt]="'core.pictureof' | translate:{$a: fullname}" core-external-content
onError="this.src='assets/img/user-avatar.png'" role="presentation" (click)="gotoProfile($event)"> onError="this.src='assets/img/user-avatar.png'" (click)="gotoProfile($event)">
<img *ngIf="!avatarUrl" src="assets/img/user-avatar.png" [alt]="'core.pictureof' | translate:{$a: fullname}" role="presentation" <img *ngIf="!avatarUrl" src="assets/img/user-avatar.png" [alt]="'core.pictureof' | translate:{$a: fullname}"
(click)="gotoProfile($event)"> (click)="gotoProfile($event)">
<span *ngIf="checkOnline && isOnline()" class="contact-status online"></span> <span *ngIf="checkOnline && isOnline()" class="contact-status online"></span>

View File

@ -18,7 +18,7 @@
<ion-item *ngFor="let site of sites" (click)="siteClicked(site.id)" detail="false"> <ion-item *ngFor="let site of sites" (click)="siteClicked(site.id)" detail="false">
<ion-avatar slot="start"> <ion-avatar slot="start">
<img [src]="site.avatar" core-external-content [siteId]="site.id" <img [src]="site.avatar" core-external-content [siteId]="site.id"
alt="{{ 'core.pictureof' | translate:{$a: site.fullName} }}" role="presentation" alt="{{ 'core.pictureof' | translate:{$a: site.fullName} }}"
onError="this.src='assets/img/user-avatar.png'"> onError="this.src='assets/img/user-avatar.png'">
</ion-avatar> </ion-avatar>
<ion-label> <ion-label>

View File

@ -20,8 +20,7 @@
class="ion-text-wrap clearfix ion-justify-content-between core-button-selector-row" class="ion-text-wrap clearfix ion-justify-content-between core-button-selector-row"
[class.core-section-download]="downloadEnabled"> [class.core-section-download]="downloadEnabled">
<ion-button class="core-button-select button-no-uppercase" (click)="showSectionSelector()" <ion-button class="core-button-select button-no-uppercase" (click)="showSectionSelector()"
aria-haspopup="true" [attr.aria-expanded]="sectionSelectorExpanded" aria-haspopup="listbox" id="core-course-section-button" expand="block">
id="core-course-section-button" expand="block">
<ion-icon name="fas-folder" slot="start" aria-hidden="true"></ion-icon> <ion-icon name="fas-folder" slot="start" aria-hidden="true"></ion-icon>
<span class="sr-only" *ngIf="selectedSection">{{ 'core.course.sections' | translate }}:</span> <span class="sr-only" *ngIf="selectedSection">{{ 'core.course.sections' | translate }}:</span>
<span class="core-button-select-text"> <span class="core-button-select-text">

View File

@ -91,7 +91,6 @@ export class CoreCourseFormatComponent implements OnInit, OnChanges, OnDestroy {
canLoadMore = false; canLoadMore = false;
showSectionId = 0; showSectionId = 0;
sectionSelectorExpanded = false;
data: Record<string, unknown> = {}; // Data to pass to the components. data: Record<string, unknown> = {}; // Data to pass to the components.
displaySectionSelector?: boolean; displaySectionSelector?: boolean;
@ -109,6 +108,7 @@ export class CoreCourseFormatComponent implements OnInit, OnChanges, OnDestroy {
protected sectionStatusObserver?: CoreEventObserver; protected sectionStatusObserver?: CoreEventObserver;
protected selectTabObserver?: CoreEventObserver; protected selectTabObserver?: CoreEventObserver;
protected lastCourseFormat?: string; protected lastCourseFormat?: string;
protected sectionSelectorExpanded = false;
constructor( constructor(
protected content: IonContent, protected content: IonContent,

View File

@ -1,3 +1,3 @@
<button *ngIf="completion" (click)="completionClicked($event)"> <button *ngIf="completion" (click)="completionClicked($event)" [title]="completionDescription">
<img [src]="completionImage" [alt]="completionDescription"> <img [src]="completionImage" role="presentation" alt="">
</button> </button>

View File

@ -16,7 +16,7 @@
<ion-content class="ion-padding"> <ion-content class="ion-padding">
<div> <div>
<div class="ion-text-center ion-padding core-login-site-logo"> <div class="ion-text-center ion-padding core-login-site-logo">
<img src="assets/img/login_logo.png" class="avatar-full login-logo" role="presentation"> <img src="assets/img/login_logo.png" class="avatar-full login-logo" role="presentation" alt="">
</div> </div>
<h3 class="core-login-onboarding-step"> <h3 class="core-login-onboarding-step">

View File

@ -19,8 +19,8 @@
<div class="ion-text-wrap ion-text-center ion-margin-bottom"> <div class="ion-text-wrap ion-text-center ion-margin-bottom">
<div class="core-login-site-logo"> <div class="core-login-site-logo">
<!-- Show site logo or a default image. --> <!-- Show site logo or a default image. -->
<img *ngIf="logoUrl" [src]="logoUrl" role="presentation" onError="this.src='assets/img/login_logo.png'"> <img *ngIf="logoUrl" [src]="logoUrl" role="presentation" alt="" onError="this.src='assets/img/login_logo.png'">
<img *ngIf="!logoUrl" src="assets/img/login_logo.png" role="presentation"> <img *ngIf="!logoUrl" src="assets/img/login_logo.png" role="presentation" alt="">
</div> </div>
<h3 *ngIf="siteName" class="ion-padding core-sitename"> <h3 *ngIf="siteName" class="ion-padding core-sitename">

View File

@ -11,13 +11,12 @@
<div class="ion-text-wrap ion-text-center ion-margin-bottom" [ngClass]="{'item-avatar-center': showSiteAvatar}"> <div class="ion-text-wrap ion-text-center ion-margin-bottom" [ngClass]="{'item-avatar-center': showSiteAvatar}">
<!-- Show user avatar. --> <!-- Show user avatar. -->
<img *ngIf="showSiteAvatar" [src]="userAvatar" class="large-avatar" core-external-content [siteId]="siteId" <img *ngIf="showSiteAvatar" [src]="userAvatar" class="large-avatar" core-external-content [siteId]="siteId"
role="presentation"
alt="{{ 'core.pictureof' | translate:{$a: userFullName} }}" onError="this.src='assets/img/user-avatar.png'"> alt="{{ 'core.pictureof' | translate:{$a: userFullName} }}" onError="this.src='assets/img/user-avatar.png'">
<div class="core-login-site-logo" *ngIf="!showSiteAvatar"> <div class="core-login-site-logo" *ngIf="!showSiteAvatar">
<!-- Show site logo or a default image. --> <!-- Show site logo or a default image. -->
<img *ngIf="logoUrl" [src]="logoUrl" role="presentation" onError="this.src='assets/img/login_logo.png'"> <img *ngIf="logoUrl" [src]="logoUrl" role="presentation" onError="this.src='assets/img/login_logo.png'" alt="">
<img *ngIf="!logoUrl" src="assets/img/login_logo.png" role="presentation"> <img *ngIf="!logoUrl" src="assets/img/login_logo.png" role="presentation" alt="">
</div> </div>
<h6 *ngIf="siteName" class="ion-padding core-sitename"> <h6 *ngIf="siteName" class="ion-padding core-sitename">

View File

@ -17,7 +17,7 @@
<ion-content class="ion-padding"> <ion-content class="ion-padding">
<div class="ion-text-center ion-padding ion-margin-bottom core-login-site-logo" <div class="ion-text-center ion-padding ion-margin-bottom core-login-site-logo"
[class.hidden]="hasSites || enteredSiteUrl"> [class.hidden]="hasSites || enteredSiteUrl">
<img src="assets/img/login_logo.png" class="avatar-full login-logo" role="presentation"> <img src="assets/img/login_logo.png" class="avatar-full login-logo" role="presentation" alt="">
</div> </div>
<form [formGroup]="siteForm" (ngSubmit)="connect($event, siteForm.value.siteUrl)" *ngIf="!fixedSites" #siteFormEl> <form [formGroup]="siteForm" (ngSubmit)="connect($event, siteForm.value.siteUrl)" *ngIf="!fixedSites" #siteFormEl>
<!-- Form to input the site URL if there are no fixed sites. --> <!-- Form to input the site URL if there are no fixed sites. -->
@ -102,7 +102,7 @@
<ng-container *ngIf="showScanQR && !hasSites && !enteredSiteUrl"> <ng-container *ngIf="showScanQR && !hasSites && !enteredSiteUrl">
<div class="ion-text-center ion-padding ion-margin-top">{{ 'core.login.or' | translate }}</div> <div class="ion-text-center ion-padding ion-margin-top">{{ 'core.login.or' | translate }}</div>
<ion-button expand="block" color="light" class="ion-margin" lines="none" (click)="showInstructionsAndScanQR()" <ion-button expand="block" color="light" class="ion-margin" lines="none" (click)="showInstructionsAndScanQR()"
aria-haspopup="true"> aria-haspopup="dialog">
<ion-icon slot="start" name="fas-qrcode" aria-hidden="true"></ion-icon> <ion-icon slot="start" name="fas-qrcode" aria-hidden="true"></ion-icon>
<ion-label>{{ 'core.scanqr' | translate }}</ion-label> <ion-label>{{ 'core.scanqr' | translate }}</ion-label>
</ion-button> </ion-button>
@ -111,7 +111,7 @@
<!-- Help. --> <!-- Help. -->
<ion-list lines="none" class="ion-margin-top"> <ion-list lines="none" class="ion-margin-top">
<ion-item button class="ion-text-center ion-text-wrap core-login-need-help" (click)="showHelp()" detail="false" <ion-item button class="ion-text-center ion-text-wrap core-login-need-help" (click)="showHelp()" detail="false"
aria-haspopup="true"> aria-haspopup="dialog">
<ion-label>{{ 'core.needhelp' | translate }}</ion-label> <ion-label>{{ 'core.needhelp' | translate }}</ion-label>
</ion-item> </ion-item>
</ion-list> </ion-list>

View File

@ -21,7 +21,7 @@
<ion-list> <ion-list>
<ion-item button (click)="login(site.id)" *ngFor="let site of sites"> <ion-item button (click)="login(site.id)" *ngFor="let site of sites">
<ion-avatar slot="start"> <ion-avatar slot="start">
<img [src]="site.avatar" core-external-content [siteId]="site.id" role="presentation" <img [src]="site.avatar" core-external-content [siteId]="site.id"
alt="{{ 'core.pictureof' | translate:{$a: site.fullName} }}" onError="this.src='assets/img/user-avatar.png'"> alt="{{ 'core.pictureof' | translate:{$a: site.fullName} }}" onError="this.src='assets/img/user-avatar.png'">
</ion-avatar> </ion-avatar>
<ion-label> <ion-label>

View File

@ -48,8 +48,8 @@ export class CoreLoginHelperProvider {
static readonly OPEN_COURSE = 'open_course'; static readonly OPEN_COURSE = 'open_course';
static readonly ONBOARDING_DONE = 'onboarding_done'; static readonly ONBOARDING_DONE = 'onboarding_done';
static readonly FAQ_URL_IMAGE_HTML = '<img src="assets/img/login/faq_url.png" role="presentation">'; static readonly FAQ_URL_IMAGE_HTML = '<img src="assets/img/login/faq_url.png" role="presentation" alt="">';
static readonly FAQ_QRCODE_IMAGE_HTML = '<img src="assets/img/login/faq_qrcode.png" role="presentation">'; static readonly FAQ_QRCODE_IMAGE_HTML = '<img src="assets/img/login/faq_qrcode.png" role="presentation" alt="">';
protected logger: CoreLogger; protected logger: CoreLogger;
protected isSSOConfirmShown = false; protected isSSOConfirmShown = false;

View File

@ -18,7 +18,7 @@
<ion-item *ngFor="let site of sites" (click)="storeInSite(site.id)" detail="false"> <ion-item *ngFor="let site of sites" (click)="storeInSite(site.id)" detail="false">
<ion-avatar slot="start" aria-hidden="true"> <ion-avatar slot="start" aria-hidden="true">
<img [src]="site.avatar" core-external-content [siteId]="site.id" <img [src]="site.avatar" core-external-content [siteId]="site.id"
alt="{{ 'core.pictureof' | translate:{$a: site.fullname} }}" role="presentation" alt="{{ 'core.pictureof' | translate:{$a: site.fullname} }}"
onError="this.src='assets/img/user-avatar.png'"> onError="this.src='assets/img/user-avatar.png'">
</ion-avatar> </ion-avatar>
<ion-label> <ion-label>