Merge pull request #2729 from crazyserver/MOBILE-3744

Mobile 3744
main
Noel De Martin 2021-05-03 10:42:00 +02:00 committed by GitHub
commit 136f50ba37
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
267 changed files with 1739 additions and 1063 deletions

View File

@ -15,7 +15,6 @@ const appConfig = {
'eslint:recommended', 'eslint:recommended',
'plugin:@typescript-eslint/recommended', 'plugin:@typescript-eslint/recommended',
'prettier', 'prettier',
'prettier/@typescript-eslint',
'plugin:@angular-eslint/recommended', 'plugin:@angular-eslint/recommended',
'plugin:promise/recommended', 'plugin:promise/recommended',
], ],
@ -90,7 +89,16 @@ const appConfig = {
}, },
}, },
], ],
'@typescript-eslint/member-ordering': 'error', '@typescript-eslint/member-ordering': [
'error',
{
default:
{
order: 'as-written',
},
}
],
'@typescript-eslint/naming-convention': [ '@typescript-eslint/naming-convention': [
'error', 'error',
{ {
@ -276,6 +284,13 @@ module.exports = {
extends: ['plugin:@angular-eslint/template/recommended'], extends: ['plugin:@angular-eslint/template/recommended'],
rules: { rules: {
'max-len': ['warn', { code: 140 }], 'max-len': ['warn', { code: 140 }],
'@angular-eslint/template/accessibility-valid-aria': 'warn',
'@angular-eslint/template/accessibility-alt-text': 'error',
'@angular-eslint/template/accessibility-elements-content': 'error',
'@angular-eslint/template/accessibility-label-for': 'error',
'@angular-eslint/template/no-positive-tabindex': 'error',
'@angular-eslint/template/accessibility-table-scope': 'error',
'@angular-eslint/template/accessibility-valid-aria': 'error',
}, },
}, },
{ {

816
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -126,11 +126,11 @@
"devDependencies": { "devDependencies": {
"@angular-devkit/architect": "^0.1101.2", "@angular-devkit/architect": "^0.1101.2",
"@angular-devkit/build-angular": "~0.1000.0", "@angular-devkit/build-angular": "~0.1000.0",
"@angular-eslint/builder": "0.5.0-beta.2", "@angular-eslint/builder": "^4.2.0",
"@angular-eslint/eslint-plugin": "0.5.0-beta.2", "@angular-eslint/eslint-plugin": "^4.2.0",
"@angular-eslint/eslint-plugin-template": "0.5.0-beta.2", "@angular-eslint/eslint-plugin-template": "^4.2.0",
"@angular-eslint/schematics": "^0.5.0-beta.2", "@angular-eslint/schematics": "^4.2.0",
"@angular-eslint/template-parser": "0.5.0-beta.2", "@angular-eslint/template-parser": "^4.2.0",
"@angular/cli": "~10.0.5", "@angular/cli": "~10.0.5",
"@angular/compiler": "~10.0.0", "@angular/compiler": "~10.0.0",
"@angular/compiler-cli": "~10.0.0", "@angular/compiler-cli": "~10.0.0",
@ -141,17 +141,17 @@
"@types/faker": "^5.1.3", "@types/faker": "^5.1.3",
"@types/node": "^12.12.64", "@types/node": "^12.12.64",
"@types/webpack-env": "^1.16.0", "@types/webpack-env": "^1.16.0",
"@typescript-eslint/eslint-plugin": "4.3.0", "@typescript-eslint/eslint-plugin": "^4.22.0",
"@typescript-eslint/parser": "4.3.0", "@typescript-eslint/parser": "^4.22.0",
"check-es-compat": "^1.1.1", "check-es-compat": "^1.1.1",
"eslint": "^7.21.0", "eslint": "^7.25.0",
"eslint-config-prettier": "^6.12.0", "eslint-config-prettier": "^8.3.0",
"eslint-plugin-header": "^3.1.0", "eslint-plugin-header": "^3.1.1",
"eslint-plugin-import": "^2.22.1", "eslint-plugin-import": "^2.22.1",
"eslint-plugin-jest": "^24.1.0", "eslint-plugin-jest": "^24.3.6",
"eslint-plugin-jsdoc": "^30.6.3", "eslint-plugin-jsdoc": "^32.3.3",
"eslint-plugin-prefer-arrow": "^1.2.2", "eslint-plugin-prefer-arrow": "^1.2.3",
"eslint-plugin-promise": "^4.2.1", "eslint-plugin-promise": "^5.1.0",
"faker": "^5.1.0", "faker": "^5.1.0",
"fs-extra": "^9.1.0", "fs-extra": "^9.1.0",
"gulp": "4.0.2", "gulp": "4.0.2",

View File

@ -1,7 +1,7 @@
<ion-header> <ion-header>
<ion-toolbar> <ion-toolbar>
<ion-buttons slot="start"> <ion-buttons slot="start">
<ion-back-button [attr.aria-label]="'core.back' | translate"></ion-back-button> <ion-back-button [text]="'core.back' | translate"></ion-back-button>
</ion-buttons> </ion-buttons>
<ion-title *ngIf="badge">{{ badge.name }}</ion-title> <ion-title *ngIf="badge">{{ badge.name }}</ion-title>
<ion-title *ngIf="!badge">{{ 'addon.badges.badges' | translate }}</ion-title> <ion-title *ngIf="!badge">{{ 'addon.badges.badges' | translate }}</ion-title>

View File

@ -1,7 +1,7 @@
<ion-header> <ion-header>
<ion-toolbar> <ion-toolbar>
<ion-buttons slot="start"> <ion-buttons slot="start">
<ion-back-button [attr.aria-label]="'core.back' | translate"></ion-back-button> <ion-back-button [text]="'core.back' | translate"></ion-back-button>
</ion-buttons> </ion-buttons>
<ion-title>{{ 'addon.badges.badges' | translate }}</ion-title> <ion-title>{{ 'addon.badges.badges' | translate }}</ion-title>
</ion-toolbar> </ion-toolbar>
@ -17,8 +17,8 @@
</core-empty-box> </core-empty-box>
<ion-list *ngIf="!badges.empty" class="ion-no-margin"> <ion-list *ngIf="!badges.empty" class="ion-no-margin">
<ion-item class="ion-text-wrap" *ngFor="let badge of badges.items" [title]="badge.name" <ion-item button class="ion-text-wrap" *ngFor="let badge of badges.items" [attr.aria-label]="badge.name"
(click)="badges.select(badge)" [class.core-selected-item]="badges.isSelected(badge)"> (click)="badges.select(badge)" [attr.aria-current]="badges.getItemAriaCurrent(badge)">
<ion-avatar slot="start"> <ion-avatar slot="start">
<img [src]="badge.badgeurl" [alt]="badge.name" core-external-content> <img [src]="badge.badgeurl" [alt]="badge.name" core-external-content>
</ion-avatar> </ion-avatar>

View File

@ -4,7 +4,8 @@
</ion-label> </ion-label>
</ion-item-divider> </ion-item-divider>
<core-loading [hideUntil]="loaded" class="core-loading-center"> <core-loading [hideUntil]="loaded" class="core-loading-center">
<ion-item class="ion-text-wrap item-media" *ngFor="let entry of entries" detail="false" (click)="gotoCoureListModType(entry)"> <ion-item class="ion-text-wrap item-media" *ngFor="let entry of entries" detail="false" button
(click)="gotoCoureListModType(entry)">
<img slot="start" [src]="entry.icon" alt="" role="presentation" class="core-module-icon"> <img slot="start" [src]="entry.icon" alt="" role="presentation" class="core-module-icon">
<ion-label>{{ entry.name }}</ion-label> <ion-label>{{ entry.name }}</ion-label>
</ion-item> </ion-item>

View File

@ -5,8 +5,9 @@
<!-- Download all courses. --> <!-- Download all courses. -->
<div *ngIf="downloadCoursesEnabled && downloadEnabled && filteredCourses.length > 1 && !showFilter" class="core-button-spinner" <div *ngIf="downloadCoursesEnabled && downloadEnabled && filteredCourses.length > 1 && !showFilter" class="core-button-spinner"
slot="end"> slot="end">
<ion-button *ngIf="!prefetchCoursesData[selectedFilter].loading" fill="clear" color="dark" (click)="prefetchCourses()"> <ion-button *ngIf="!prefetchCoursesData[selectedFilter].loading" fill="clear" color="dark" (click)="prefetchCourses()"
<ion-icon [name]="prefetchCoursesData[selectedFilter].icon" slot="icon-only"> [attr.aria-label]="'core.courses.downloadcourses' | translate">
<ion-icon [name]="prefetchCoursesData[selectedFilter].icon" slot="icon-only" aria-hidden="true">
</ion-icon> </ion-icon>
</ion-button> </ion-button>
<ion-badge class="core-course-download-courses-progress" *ngIf="prefetchCoursesData[selectedFilter].badge"> <ion-badge class="core-course-download-courses-progress" *ngIf="prefetchCoursesData[selectedFilter].badge">

View File

@ -4,9 +4,8 @@
</ion-label> </ion-label>
<div *ngIf="downloadCoursesEnabled && downloadEnabled && courses && courses.length > 1" class="core-button-spinner" slot="end"> <div *ngIf="downloadCoursesEnabled && downloadEnabled && courses && courses.length > 1" class="core-button-spinner" slot="end">
<ion-button *ngIf="prefetchCoursesData.icon && !prefetchCoursesData.loading" fill="clear" color="dark" <ion-button *ngIf="prefetchCoursesData.icon && !prefetchCoursesData.loading" fill="clear" color="dark"
(click)="prefetchCourses()"> (click)="prefetchCourses()" [attr.aria-label]="'core.courses.downloadcourses' | translate">
<ion-icon [name]="prefetchCoursesData.icon" slot="icon-only"> <ion-icon [name]="prefetchCoursesData.icon" slot="icon-only" aria-hidden="true"></ion-icon>
</ion-icon>
</ion-button> </ion-button>
<ion-badge class="core-course-download-courses-progress" *ngIf="prefetchCoursesData.badge"> <ion-badge class="core-course-download-courses-progress" *ngIf="prefetchCoursesData.badge">
{{prefetchCoursesData.badge}} {{prefetchCoursesData.badge}}

View File

@ -4,9 +4,8 @@
</ion-label> </ion-label>
<div *ngIf="downloadCoursesEnabled && downloadEnabled && courses && courses.length > 1" class="core-button-spinner" slot="end"> <div *ngIf="downloadCoursesEnabled && downloadEnabled && courses && courses.length > 1" class="core-button-spinner" slot="end">
<ion-button *ngIf="prefetchCoursesData.icon && !prefetchCoursesData.loading" fill="clear" color="dark" <ion-button *ngIf="prefetchCoursesData.icon && !prefetchCoursesData.loading" fill="clear" color="dark"
(click)="prefetchCourses()"> (click)="prefetchCourses()" [attr.aria-label]="'core.courses.downloadcourses' | translate">
<ion-icon [name]="prefetchCoursesData.icon" slot="icon-only"> <ion-icon [name]="prefetchCoursesData.icon" slot="icon-only" aria-hidden="true"></ion-icon>
</ion-icon>
</ion-button> </ion-button>
<ion-badge class="core-course-download-courses-progress" *ngIf="prefetchCoursesData.badge"> <ion-badge class="core-course-download-courses-progress" *ngIf="prefetchCoursesData.badge">
{{prefetchCoursesData.badge}} {{prefetchCoursesData.badge}}

View File

@ -4,9 +4,11 @@
</ion-item-divider> </ion-item-divider>
<ng-container *ngFor="let event of dayEvents.events"> <ng-container *ngFor="let event of dayEvents.events">
<ion-item class="ion-text-wrap core-course-module-handler item-media" detail="false" (click)="action($event, event.url)" <ion-item class="ion-text-wrap core-course-module-handler item-media" detail="false" (click)="action($event, event.url)"
[title]="event.name"> [attr.aria-label]="event.name" button>
<img slot="start" [src]="event.iconUrl" alt="" role="presentation" *ngIf="event.iconUrl" class="core-module-icon"> <img slot="start" [src]="event.iconUrl" alt="" role="presentation" *ngIf="event.iconUrl" class="core-module-icon">
<ion-label> <ion-label>
<!-- Add the icon title so accessibility tools read it. -->
<span class="sr-only" *ngIf="event.iconTitle">{{ event.iconTitle }}</span>
<h2> <h2>
<core-format-text [text]="event.name" contextLevel="module" [contextInstanceId]="event.id" <core-format-text [text]="event.name" contextLevel="module" [contextInstanceId]="event.id"
[courseId]="event.course && event.course.id"> [courseId]="event.course && event.course.id">

View File

@ -103,6 +103,7 @@ export class AddonBlockTimelineEventsComponent implements OnChanges {
return start <= event.timesort; return start <= event.timesort;
}).map((event) => { }).map((event) => {
event.iconUrl = CoreCourse.getModuleIconSrc(event.icon.component); event.iconUrl = CoreCourse.getModuleIconSrc(event.icon.component);
event.iconTitle = event.modulename && CoreCourse.translateModuleName(event.modulename);
return event; return event;
}); });
@ -145,6 +146,7 @@ export class AddonBlockTimelineEventsComponent implements OnChanges {
type AddonBlockTimelineEvent = AddonCalendarEvent & { type AddonBlockTimelineEvent = AddonCalendarEvent & {
iconUrl?: string; iconUrl?: string;
iconTitle?: string;
}; };
type AddonBlockTimelineEventFilteredEvent = { type AddonBlockTimelineEventFilteredEvent = {

View File

@ -1,7 +1,7 @@
<ion-header> <ion-header>
<ion-toolbar> <ion-toolbar>
<ion-buttons slot="start"> <ion-buttons slot="start">
<ion-back-button [attr.aria-label]="'core.back' | translate"></ion-back-button> <ion-back-button [text]="'core.back' | translate"></ion-back-button>
</ion-buttons> </ion-buttons>
<ion-title>{{ title | translate }}</ion-title> <ion-title>{{ title | translate }}</ion-title>
<ion-buttons slot="end"></ion-buttons> <ion-buttons slot="end"></ion-buttons>
@ -54,7 +54,7 @@
<core-tag-list [tags]="entry.tags"></core-tag-list> <core-tag-list [tags]="entry.tags"></core-tag-list>
</ion-label> </ion-label>
</ion-item> </ion-item>
<ion-item *ngIf="commentsEnabled" detail> <ion-item *ngIf="commentsEnabled" detail="true">
<ion-label> <ion-label>
<core-comments [component]="this.component" [itemId]="entry.id" area="format_blog" <core-comments [component]="this.component" [itemId]="entry.id" area="format_blog"
[instanceId]="entry.userid" contextLevel="user"> [instanceId]="entry.userid" contextLevel="user">
@ -71,7 +71,8 @@
<ion-row class="ion-text-center"> <ion-row class="ion-text-center">
<ion-col *ngIf="entry.lastmodified > entry.created"> <ion-col *ngIf="entry.lastmodified > entry.created">
<ion-note> <ion-note>
<ion-icon name="fas-clock"></ion-icon> {{entry.lastmodified | coreTimeAgo}} <ion-icon name="fas-clock"
[attr.aria-label]="'core.lastmodified' | translate"></ion-icon> {{entry.lastmodified | coreTimeAgo}}
</ion-note> </ion-note>
</ion-col> </ion-col>
</ion-row> </ion-row>

View File

@ -13,16 +13,16 @@
<ion-grid class="ion-no-padding addon-calendar-navigation"> <ion-grid class="ion-no-padding addon-calendar-navigation">
<ion-row class="ion-align-items-center"> <ion-row class="ion-align-items-center">
<ion-col class="ion-text-start" *ngIf="canNavigate"> <ion-col class="ion-text-start" *ngIf="canNavigate">
<ion-button fill="clear" (click)="loadPrevious()" [title]="'core.previous' | translate"> <ion-button fill="clear" (click)="loadPrevious()" [attr.aria-label]="'core.previous' | translate">
<ion-icon name="fas-chevron-left" slot="icon-only"></ion-icon> <ion-icon name="fas-chevron-left" slot="icon-only" aria-hidden="true"></ion-icon>
</ion-button> </ion-button>
</ion-col> </ion-col>
<ion-col class="ion-text-center addon-calendar-period"> <ion-col class="ion-text-center addon-calendar-period">
<h3>{{ periodName }}</h3> <h3>{{ periodName }}</h3>
</ion-col> </ion-col>
<ion-col class="ion-text-end" *ngIf="canNavigate"> <ion-col class="ion-text-end" *ngIf="canNavigate">
<ion-button fill="clear" (click)="loadNext()" [title]="'core.next' | translate"> <ion-button fill="clear" (click)="loadNext()" [attr.aria-label]="'core.next' | translate">
<ion-icon name="fas-chevron-right" slot="icon-only"></ion-icon> <ion-icon name="fas-chevron-right" slot="icon-only" aria-hidden="true"></ion-icon>
</ion-button> </ion-button>
</ion-col> </ion-col>
</ion-row> </ion-row>
@ -42,8 +42,8 @@
<ion-row *ngFor="let week of weeks" class="addon-calendar-week"> <ion-row *ngFor="let week of weeks" class="addon-calendar-week">
<!-- Empty slots (first week). --> <!-- Empty slots (first week). -->
<ion-col *ngFor="let value of week.prepadding" class="dayblank addon-calendar-day"></ion-col> <ion-col *ngFor="let value of week.prepadding" class="dayblank addon-calendar-day"></ion-col>
<ion-col class="addon-calendar-day ion-text-center" *ngFor="let day of week.days" (click)="dayClicked(day.mday)" <ion-col class="addon-calendar-day ion-text-center" *ngFor="let day of week.days" (click)="dayClicked(day.mday)"
[ngClass]='{"hasevents": day.hasevents, "today": isCurrentMonth && day.istoday, [ngClass]='{"hasevents": day.hasevents, "today": isCurrentMonth && day.istoday,
"weekend": day.isweekend, "duration_finish": day.haslastdayofevent}' "weekend": day.isweekend, "duration_finish": day.haslastdayofevent}'
[class.addon-calendar-event-past-day]="isPastMonth || day.ispast"> [class.addon-calendar-event-past-day]="isPastMonth || day.ispast">
<p class="addon-calendar-day-number"><span>{{ day.mday }}</span></p> <p class="addon-calendar-day-number"><span>{{ day.mday }}</span></p>
@ -55,16 +55,23 @@
<!-- In tablet, display list of events. --> <!-- In tablet, display list of events. -->
<div class="ion-hide-md-down addon-calendar-day-events"> <div class="ion-hide-md-down addon-calendar-day-events">
<ng-container *ngFor="let event of day.filteredEvents | slice:0:4; let index = index"> <ng-container *ngFor="let event of day.filteredEvents | slice:0:4; let index = index">
<p *ngIf="index < 3 || day.filteredEvents.length == 4" class="addon-calendar-event" <div role="button" *ngIf="index < 3 || day.filteredEvents.length == 4" class="addon-calendar-event"
(click)="eventClicked(event, $event)" [class.addon-calendar-event-past]="event.ispast"> (click)="eventClicked(event, $event)" [class.addon-calendar-event-past]="event.ispast">
<span class="calendar_event_type calendar_event_{{event.formattedType}}"></span> <span class="calendar_event_type calendar_event_{{event.formattedType}}"></span>
<ion-icon *ngIf="event.offline && !event.deleted" name="far-clock"></ion-icon> <ion-icon *ngIf="event.offline && !event.deleted" name="fas-clock"
<ion-icon *ngIf="event.deleted" name="fas-trash"></ion-icon> [attr.aria-label]="'core.notsent' | translate"></ion-icon>
<ion-icon *ngIf="event.deleted" name="fas-trash" [attr.aria-label]="'core.deletedoffline' | translate">
</ion-icon>
<span class="addon-calendar-event-time">{{ event.timestart * 1000 | coreFormatDate: timeFormat }}</span> <span class="addon-calendar-event-time">{{ event.timestart * 1000 | coreFormatDate: timeFormat }}</span>
<img *ngIf="event.moduleIcon" src="{{event.moduleIcon}}" alt="" role="presentation" <img *ngIf="event.moduleIcon" src="{{event.moduleIcon}}" alt="" role="presentation"
class="core-module-icon"> class="core-module-icon">
<!-- Add the icon title so accessibility tools read it. -->
<span class="sr-only">
{{ 'addon.calendar.type' + event.formattedType | translate }}
<span class="sr-only" *ngIf="event.moduleIcon && event.iconTitle">{{ event.iconTitle }}</span>
</span>
<span class="addon-calendar-event-name">{{event.name}}</span> <span class="addon-calendar-event-name">{{event.name}}</span>
</p> </div>
</ng-container> </ng-container>
<p *ngIf="day.filteredEvents.length > 4" class="addon-calendar-day-more"> <p *ngIf="day.filteredEvents.length > 4" class="addon-calendar-day-more">
<b>{{ 'core.nummore' | translate:{$a: day.filteredEvents.length - 3} }}</b> <b>{{ 'core.nummore' | translate:{$a: day.filteredEvents.length - 3} }}</b>

View File

@ -70,6 +70,7 @@
margin-bottom: 0.6em; margin-bottom: 0.6em;
overflow: hidden; overflow: hidden;
white-space: nowrap; white-space: nowrap;
color: var(--text-color);
&.addon-calendar-event-past { &.addon-calendar-event-past {
opacity: 0.5; opacity: 0.5;

View File

@ -1,6 +1,6 @@
<ion-list> <ion-list>
<ion-item *ngFor="let type of types" class="addon-calendar-event" [ngClass]="['addon-calendar-eventtype-'+type]"> <ion-item *ngFor="let type of types" class="addon-calendar-event" [ngClass]="['addon-calendar-eventtype-'+type]">
<ion-icon [name]="typeIcons[type]" slot="start"></ion-icon> <ion-icon [name]="typeIcons[type]" slot="start" aria-hidden="true"></ion-icon>
<ion-label>{{ 'addon.calendar.' + type + 'events' | translate}}</ion-label> <ion-label>{{ 'addon.calendar.' + type + 'events' | translate}}</ion-label>
<ion-toggle [(ngModel)]="filter[type]" (ionChange)="onChange()" slot="end"></ion-toggle> <ion-toggle [(ngModel)]="filter[type]" (ionChange)="onChange()" slot="end"></ion-toggle>
</ion-item> </ion-item>

View File

@ -4,22 +4,28 @@
<ion-list *ngIf="filteredEvents && filteredEvents.length" class="ion-no-margin"> <ion-list *ngIf="filteredEvents && filteredEvents.length" class="ion-no-margin">
<ng-container *ngFor="let event of filteredEvents"> <ng-container *ngFor="let event of filteredEvents">
<ion-item class="ion-text-wrap addon-calendar-event" [title]="event.name" (click)="eventClicked(event)" <ion-item class="ion-text-wrap addon-calendar-event" [attr.aria-label]="event.name" (click)="eventClicked(event)" button
[ngClass]="['addon-calendar-eventtype-'+event.eventtype]"> [ngClass]="['addon-calendar-eventtype-'+event.eventtype]">
<img *ngIf="event.moduleIcon" src="{{event.moduleIcon}}" slot="start" class="core-module-icon"> <img *ngIf="event.moduleIcon" src="{{event.moduleIcon}}" slot="start" class="core-module-icon" alt=""
<ion-icon *ngIf="event.eventIcon && !event.moduleIcon" [name]="event.eventIcon" slot="start"> role="presentation">
<ion-icon *ngIf="event.eventIcon && !event.moduleIcon" [name]="event.eventIcon" slot="start" aria-hidden="true">
</ion-icon> </ion-icon>
<ion-label> <ion-label>
<!-- Add the icon title so accessibility tools read it. -->
<span class="sr-only">
{{ 'addon.calendar.type' + event.formattedType | translate }}
<span class="sr-only" *ngIf="event.moduleIcon && event.iconTitle">{{ event.iconTitle }}</span>
</span>
<h2><core-format-text [text]="event.name" [contextLevel]="event.contextLevel" <h2><core-format-text [text]="event.name" [contextLevel]="event.contextLevel"
[contextInstanceId]="event.contextInstanceId"></core-format-text></h2> [contextInstanceId]="event.contextInstanceId"></core-format-text></h2>
<p [innerHTML]="event.formattedtime"></p> <p [innerHTML]="event.formattedtime"></p>
</ion-label> </ion-label>
<ion-note *ngIf="event.offline && !event.deleted" slot="end"> <ion-note *ngIf="event.offline && !event.deleted" slot="end">
<ion-icon name="far-clock"></ion-icon> <ion-icon name="fas-clock" aria-hidden="true"></ion-icon>
<span class="ion-text-wrap">{{ 'core.notsent' | translate }}</span> <span class="ion-text-wrap">{{ 'core.notsent' | translate }}</span>
</ion-note> </ion-note>
<ion-note *ngIf="event.deleted" slot="end"> <ion-note *ngIf="event.deleted" slot="end">
<ion-icon name="fas-trash"></ion-icon> <ion-icon name="fas-trash" aria-hidden="true"></ion-icon>
<span class="ion-text-wrap">{{ 'core.deletedoffline' | translate }}</span> <span class="ion-text-wrap">{{ 'core.deletedoffline' | translate }}</span>
</ion-note> </ion-note>
</ion-item> </ion-item>

View File

@ -1,12 +1,12 @@
<ion-header> <ion-header>
<ion-toolbar> <ion-toolbar>
<ion-buttons slot="start"> <ion-buttons slot="start">
<ion-back-button [attr.aria-label]="'core.back' | translate"></ion-back-button> <ion-back-button [text]="'core.back' | translate"></ion-back-button>
</ion-buttons> </ion-buttons>
<ion-title>{{ 'addon.calendar.calendarevents' | translate }}</ion-title> <ion-title>{{ 'addon.calendar.calendarevents' | translate }}</ion-title>
<ion-buttons slot="end"> <ion-buttons slot="end">
<ion-button (click)="openFilter($event)" [attr.aria-label]="'core.filter' | translate"> <ion-button (click)="openFilter($event)" [attr.aria-label]="'core.filter' | translate">
<ion-icon slot="icon-only" name="fas-filter"></ion-icon> <ion-icon slot="icon-only" name="fas-filter" aria-hidden="true"></ion-icon>
</ion-button> </ion-button>
<core-context-menu> <core-context-menu>
<core-context-menu-item *ngIf="!isCurrentDay" [priority]="900" [content]="'addon.calendar.today' | translate" <core-context-menu-item *ngIf="!isCurrentDay" [priority]="900" [content]="'addon.calendar.today' | translate"
@ -29,26 +29,26 @@
<ion-grid class="ion-no-padding safe-area-page"> <ion-grid class="ion-no-padding safe-area-page">
<ion-row class="ion-align-items-center"> <ion-row class="ion-align-items-center">
<ion-col class="ion-text-start" *ngIf="currentMoment"> <ion-col class="ion-text-start" *ngIf="currentMoment">
<ion-button fill="clear" (click)="loadPrevious()" [title]="'addon.calendar.dayprev' | translate"> <ion-button fill="clear" (click)="loadPrevious()" [attr.aria-label]="'addon.calendar.dayprev' | translate">
<ion-icon name="fas-chevron-left" slot="icon-only"></ion-icon> <ion-icon name="fas-chevron-left" slot="icon-only" aria-hidden="true"></ion-icon>
</ion-button> </ion-button>
</ion-col> </ion-col>
<ion-col class="ion-text-center addon-calendar-period"> <ion-col class="ion-text-center addon-calendar-period">
<h3>{{ periodName }}</h3> <h3>{{ periodName }}</h3>
</ion-col> </ion-col>
<ion-col class="ion-text-end" *ngIf="currentMoment"> <ion-col class="ion-text-end" *ngIf="currentMoment">
<ion-button fill="clear" (click)="loadNext()" [title]="'addon.calendar.daynext' | translate"> <ion-button fill="clear" (click)="loadNext()" [attr.aria-label]="'addon.calendar.daynext' | translate">
<ion-icon name="fas-chevron-right" slot="icon-only"></ion-icon> <ion-icon name="fas-chevron-right" slot="icon-only" aria-hidden="true"></ion-icon>
</ion-button> </ion-button>
</ion-col> </ion-col>
</ion-row> </ion-row>
</ion-grid> </ion-grid>
<core-loading [hideUntil]="loaded" class="safe-area-page"> <core-loading [hideUntil]="loaded" class="safe-area-page">
<!-- There is data to be synchronized --> <!-- There is data to be synchronized --> <!-- There is data to be synchronized -->
<ion-card class="core-warning-card" *ngIf="hasOffline"> <ion-card class="core-warning-card" *ngIf="hasOffline">
<ion-item> <ion-item>
<ion-icon name="fas-exclamation-triangle" slot="start"></ion-icon> <ion-icon name="fas-exclamation-triangle" slot="start" aria-hidden="true"></ion-icon>
<ion-label>{{ 'core.hasdatatosync' | translate:{$a: 'core.day' | translate} }}</ion-label> <ion-label>{{ 'core.hasdatatosync' | translate:{$a: 'core.day' | translate} }}</ion-label>
</ion-item> </ion-item>
</ion-card> </ion-card>
@ -59,22 +59,28 @@
<ion-list *ngIf="filteredEvents && filteredEvents.length" class="ion-no-margin"> <ion-list *ngIf="filteredEvents && filteredEvents.length" class="ion-no-margin">
<ng-container *ngFor="let event of filteredEvents"> <ng-container *ngFor="let event of filteredEvents">
<ion-item class="addon-calendar-event ion-text-wrap" [title]="event.name" (click)="gotoEvent(event.id)" <ion-item class="addon-calendar-event ion-text-wrap" [attr.aria-label]="event.name" (click)="gotoEvent(event.id)"
[class.item-dimmed]="event.ispast" [ngClass]="['addon-calendar-eventtype-'+event.eventtype]"> [class.item-dimmed]="event.ispast" [ngClass]="['addon-calendar-eventtype-'+event.eventtype]" button>
<img *ngIf="event.moduleIcon" src="{{event.moduleIcon}}" slot="start" class="core-module-icon"> <img *ngIf="event.moduleIcon" src="{{event.moduleIcon}}" slot="start" class="core-module-icon" alt=""
<ion-icon *ngIf="event.eventIcon && !event.moduleIcon" [name]="event.eventIcon" slot="start"> role="presentation">
<ion-icon *ngIf="event.eventIcon && !event.moduleIcon" [name]="event.eventIcon" slot="start" aria-hidden="true">
</ion-icon> </ion-icon>
<ion-label> <ion-label>
<!-- Add the icon title so accessibility tools read it. -->
<span class="sr-only">
{{ 'addon.calendar.type' + event.formattedType | translate }}
<span class="sr-only" *ngIf="event.moduleIcon && event.iconTitle">{{ event.iconTitle }}</span>
</span>
<h2><core-format-text [text]="event.name" [contextLevel]="event.contextLevel" <h2><core-format-text [text]="event.name" [contextLevel]="event.contextLevel"
[contextInstanceId]="event.contextInstanceId"></core-format-text></h2> [contextInstanceId]="event.contextInstanceId"></core-format-text></h2>
<p [innerHTML]="event.formattedtime"></p> <p [innerHTML]="event.formattedtime"></p>
</ion-label> </ion-label>
<ion-note *ngIf="event.offline && !event.deleted" slot="end"> <ion-note *ngIf="event.offline && !event.deleted" slot="end">
<ion-icon name="far-clock"></ion-icon> <ion-icon name="fas-clock" aria-hidden="true"></ion-icon>
<span class="ion-text-wrap">{{ 'core.notsent' | translate }}</span> <span class="ion-text-wrap">{{ 'core.notsent' | translate }}</span>
</ion-note> </ion-note>
<ion-note *ngIf="event.deleted" slot="end"> <ion-note *ngIf="event.deleted" slot="end">
<ion-icon name="fas-trash"></ion-icon> <ion-icon name="fas-trash" aria-hidden="true"></ion-icon>
<span class="ion-text-wrap">{{ 'core.deletedoffline' | translate }}</span> <span class="ion-text-wrap">{{ 'core.deletedoffline' | translate }}</span>
</ion-note> </ion-note>
</ion-item> </ion-item>
@ -85,7 +91,7 @@
<!-- Create a calendar event. --> <!-- Create a calendar event. -->
<ion-fab slot="fixed" core-fab vertical="bottom" horizontal="end" *ngIf="canCreate && loaded"> <ion-fab slot="fixed" core-fab vertical="bottom" horizontal="end" *ngIf="canCreate && loaded">
<ion-fab-button (click)="openEdit()" [attr.aria-label]="'addon.calendar.newevent' | translate"> <ion-fab-button (click)="openEdit()" [attr.aria-label]="'addon.calendar.newevent' | translate">
<ion-icon name="fas-plus"></ion-icon> <ion-icon name="fas-plus" aria-hidden="true"></ion-icon>
</ion-fab-button> </ion-fab-button>
</ion-fab> </ion-fab>
</ion-content> </ion-content>

View File

@ -1,7 +1,7 @@
<ion-header> <ion-header>
<ion-toolbar> <ion-toolbar>
<ion-buttons slot="start"> <ion-buttons slot="start">
<ion-back-button [attr.aria-label]="'core.back' | translate"></ion-back-button> <ion-back-button [text]="'core.back' | translate"></ion-back-button>
</ion-buttons> </ion-buttons>
<ion-title>{{ title | translate }}</ion-title> <ion-title>{{ title | translate }}</ion-title>
</ion-toolbar> </ion-toolbar>
@ -120,9 +120,10 @@
</ng-container> </ng-container>
<!-- Advanced options. --> <!-- Advanced options. -->
<ion-item-divider class="ion-text-wrap core-expandable" (click)="toggleAdvanced()"> <ion-item-divider class="ion-text-wrap core-expandable" (click)="toggleAdvanced()"
<ion-icon *ngIf="!advanced" name="fas-caret-right" slot="start"></ion-icon> [attr.aria-label]="(advanced ? 'core.showless' : 'core.showmore') | translate" role="button">
<ion-icon *ngIf="advanced" name="fas-caret-down" slot="start"></ion-icon> <ion-icon *ngIf="!advanced" name="fas-caret-right" slot="start" aria-hidden="true"></ion-icon>
<ion-icon *ngIf="advanced" name="fas-caret-down" slot="start" aria-hidden="true"></ion-icon>
<ion-label> <ion-label>
<span *ngIf="!advanced">{{ 'core.showmore' | translate }}</span> <span *ngIf="!advanced">{{ 'core.showmore' | translate }}</span>
<span *ngIf="advanced">{{ 'core.showless' | translate }}</span> <span *ngIf="advanced">{{ 'core.showless' | translate }}</span>
@ -161,14 +162,14 @@
<ion-radio slot="end" value="0"></ion-radio> <ion-radio slot="end" value="0"></ion-radio>
<ion-label>{{ 'addon.calendar.durationnone' | translate }}</ion-label> <ion-label>{{ 'addon.calendar.durationnone' | translate }}</ion-label>
</ion-item> </ion-item>
<ion-item (click)="selectDuration('1')"> <ion-item button (click)="selectDuration('1')">
<ion-radio slot="end" value="1"></ion-radio> <ion-radio slot="end" value="1"></ion-radio>
<ion-label>{{ 'addon.calendar.durationuntil' | translate }}</ion-label> <ion-label>{{ 'addon.calendar.durationuntil' | translate }}</ion-label>
<ion-datetime formControlName="timedurationuntil" <ion-datetime formControlName="timedurationuntil"
[placeholder]="'addon.calendar.durationuntil' | translate" [placeholder]="'addon.calendar.durationuntil' | translate"
[displayFormat]="dateFormat" [disabled]="form.controls.duration.value != 1"></ion-datetime> [displayFormat]="dateFormat" [disabled]="form.controls.duration.value != 1"></ion-datetime>
</ion-item> </ion-item>
<ion-item (click)="selectDuration('2')"> <ion-item button (click)="selectDuration('2')">
<ion-radio slot="end" value="2"></ion-radio> <ion-radio slot="end" value="2"></ion-radio>
<ion-label>{{ 'addon.calendar.durationminutes' | translate }}</ion-label> <ion-label>{{ 'addon.calendar.durationminutes' | translate }}</ion-label>
<ion-input type="number" name="timedurationminutes" slot="end" <ion-input type="number" name="timedurationminutes" slot="end"

View File

@ -1,11 +1,16 @@
<ion-header> <ion-header>
<ion-toolbar> <ion-toolbar>
<ion-buttons slot="start"> <ion-buttons slot="start">
<ion-back-button [attr.aria-label]="'core.back' | translate"></ion-back-button> <ion-back-button [text]="'core.back' | translate"></ion-back-button>
</ion-buttons> </ion-buttons>
<ion-title *ngIf="event"> <ion-title *ngIf="event">
<img *ngIf="event.moduleIcon" src="{{event.moduleIcon}}" alt="" role="presentation" class="core-module-icon"> <img *ngIf="event.moduleIcon" src="{{event.moduleIcon}}" alt="" role="presentation" class="core-module-icon">
<ion-icon *ngIf="event.eventIcon && !event.moduleIcon" [name]="event.eventIcon"></ion-icon> <ion-icon *ngIf="event.eventIcon && !event.moduleIcon" [name]="event.eventIcon" aria-hidden="true"></ion-icon>
<!-- Add the icon title so accessibility tools read it. -->
<span class="sr-only">
{{ 'addon.calendar.type' + event.formattedType | translate }}
<span class="sr-only" *ngIf="event.moduleIcon && event.iconTitle">{{ event.iconTitle }}</span>
</span>
<core-format-text [text]="event.name" [contextLevel]="event.contextLevel" <core-format-text [text]="event.name" [contextLevel]="event.contextLevel"
[contextInstanceId]="event.contextInstanceId"></core-format-text> [contextInstanceId]="event.contextInstanceId"></core-format-text>
</ion-title> </ion-title>
@ -38,7 +43,7 @@
<!-- There is data to be synchronized --> <!-- There is data to be synchronized -->
<ion-card class="core-warning-card" *ngIf="hasOffline || (event && event.deleted)"> <ion-card class="core-warning-card" *ngIf="hasOffline || (event && event.deleted)">
<ion-item> <ion-item>
<ion-icon name="fas-exclamation-triangle" slot="start"></ion-icon> <ion-icon name="fas-exclamation-triangle" slot="start" aria-hidden="true"></ion-icon>
<ion-label>{{ 'core.hasdatatosync' | translate:{$a: 'addon.calendar.calendarevent' | translate} }}</ion-label> <ion-label>{{ 'core.hasdatatosync' | translate:{$a: 'addon.calendar.calendarevent' | translate} }}</ion-label>
</ion-item> </ion-item>
</ion-card> </ion-card>
@ -48,17 +53,21 @@
<ion-item class="ion-text-wrap" *ngIf="isSplitViewOn"> <ion-item class="ion-text-wrap" *ngIf="isSplitViewOn">
<img *ngIf="event.moduleIcon" src="{{event.moduleIcon}}" slot="start" alt="" role="presentation" <img *ngIf="event.moduleIcon" src="{{event.moduleIcon}}" slot="start" alt="" role="presentation"
class="core-module-icon"> class="core-module-icon">
<ion-icon *ngIf="event.eventIcon && !event.moduleIcon" [name]="event.eventIcon" slot="start"> <ion-icon *ngIf="event.eventIcon && !event.moduleIcon" [name]="event.eventIcon" slot="start" aria-hidden="true">
</ion-icon> </ion-icon>
<ion-label> <ion-label>
<span class="sr-only">
{{ 'addon.calendar.type' + event.formattedType | translate }}
<span class="sr-only" *ngIf="event.moduleIcon && event.iconTitle">{{ event.iconTitle }}</span>
</span>
<h2>{{ 'addon.calendar.eventname' | translate }}</h2> <h2>{{ 'addon.calendar.eventname' | translate }}</h2>
<p> <p>
<core-format-text [text]="event.name" [contextLevel]="event.contextLevel" <core-format-text [text]="event.name" [contextLevel]="event.contextLevel"
[contextInstanceId]="event.contextInstanceId"></core-format-text> [contextInstanceId]="event.contextInstanceId"></core-format-text>
</p> </p>
</ion-label> </ion-label>
<ion-note slot="end" *ngIf="event.deleted"> <ion-note slot="end" *ngIf="event.deleted">
<ion-icon name="fas-trash"></ion-icon> {{ 'core.deletedoffline' | translate }} <ion-icon name="fas-trash" aria-hidden="true"></ion-icon> {{ 'core.deletedoffline' | translate }}
</ion-note> </ion-note>
</ion-item> </ion-item>
<ion-item> <ion-item>
@ -67,7 +76,7 @@
<p [innerHTML]="event.formattedtime"></p> <p [innerHTML]="event.formattedtime"></p>
</ion-label> </ion-label>
<ion-note slot="end" *ngIf="!isSplitViewOn && event.deleted"> <ion-note slot="end" *ngIf="!isSplitViewOn && event.deleted">
<ion-icon name="fas-trash"></ion-icon> {{ 'core.deletedoffline' | translate }} <ion-icon name="fas-trash" aria-hidden="true"></ion-icon> {{ 'core.deletedoffline' | translate }}
</ion-note> </ion-note>
</ion-item> </ion-item>
<ion-item> <ion-item>
@ -144,9 +153,9 @@
<p *ngIf="reminder.time > 0">{{ reminder.time * 1000 | coreFormatDate }}</p> <p *ngIf="reminder.time > 0">{{ reminder.time * 1000 | coreFormatDate }}</p>
</ion-label> </ion-label>
<ion-button fill="clear" (click)="cancelNotification(reminder.id, $event)" <ion-button fill="clear" (click)="cancelNotification(reminder.id, $event)"
[attr.aria-label]=" 'core.delete' | translate" slot="end" [attr.aria-label]="'core.delete' | translate" slot="end"
*ngIf="(reminder.time == -1 ? (event.timestart - defaultTime) : reminder.time) > currentTime!"> *ngIf="(reminder.time == -1 ? (event.timestart - defaultTime) : reminder.time) > currentTime!">
<ion-icon name="fas-trash" color="danger" slot="icon-only"></ion-icon> <ion-icon name="fas-trash" color="danger" slot="icon-only" aria-hidden="true"></ion-icon>
</ion-button> </ion-button>
</ion-item> </ion-item>
</ng-container> </ng-container>

View File

@ -1,12 +1,12 @@
<ion-header> <ion-header>
<ion-toolbar> <ion-toolbar>
<ion-buttons slot="start"> <ion-buttons slot="start">
<ion-back-button [attr.aria-label]="'core.back' | translate"></ion-back-button> <ion-back-button [text]="'core.back' | translate"></ion-back-button>
</ion-buttons> </ion-buttons>
<ion-title>{{ (showCalendar ? 'addon.calendar.calendarevents' : 'addon.calendar.upcomingevents') | translate }}</ion-title> <ion-title>{{ (showCalendar ? 'addon.calendar.calendarevents' : 'addon.calendar.upcomingevents') | translate }}</ion-title>
<ion-buttons slot="end"> <ion-buttons slot="end">
<ion-button (click)="openFilter($event)" [attr.aria-label]="'core.filter' | translate"> <ion-button (click)="openFilter($event)" [attr.aria-label]="'core.filter' | translate">
<ion-icon slot="icon-only" name="fas-filter"></ion-icon> <ion-icon slot="icon-only" name="fas-filter" aria-hidden="true"></ion-icon>
</ion-button> </ion-button>
<core-context-menu> <core-context-menu>
<core-context-menu-item *ngIf="showCalendar" [priority]="800" <core-context-menu-item *ngIf="showCalendar" [priority]="800"
@ -33,7 +33,7 @@
<!-- There is data to be synchronized --> <!-- There is data to be synchronized -->
<ion-card class="core-warning-card" *ngIf="hasOffline"> <ion-card class="core-warning-card" *ngIf="hasOffline">
<ion-item> <ion-item>
<ion-icon name="fas-exclamation-triangle" slot="start"></ion-icon> <ion-icon name="fas-exclamation-triangle" slot="start" aria-hidden="true"></ion-icon>
<ion-label>{{ 'core.hasdatatosync' | translate:{$a: 'addon.calendar.calendar' | translate} }}</ion-label> <ion-label>{{ 'core.hasdatatosync' | translate:{$a: 'addon.calendar.calendar' | translate} }}</ion-label>
</ion-item> </ion-item>
</ion-card> </ion-card>
@ -49,7 +49,7 @@
<!-- Create a calendar event. --> <!-- Create a calendar event. -->
<ion-fab slot="fixed" core-fab vertical="bottom" horizontal="end" *ngIf="canCreate"> <ion-fab slot="fixed" core-fab vertical="bottom" horizontal="end" *ngIf="canCreate">
<ion-fab-button (click)="openEdit()" [attr.aria-label]="'addon.calendar.newevent' | translate"> <ion-fab-button (click)="openEdit()" [attr.aria-label]="'addon.calendar.newevent' | translate">
<ion-icon name="fas-plus"></ion-icon> <ion-icon name="fas-plus" aria-hidden="true"></ion-icon>
</ion-fab-button> </ion-fab-button>
</ion-fab> </ion-fab>
</ion-content> </ion-content>

View File

@ -1,12 +1,12 @@
<ion-header> <ion-header>
<ion-toolbar> <ion-toolbar>
<ion-buttons slot="start"> <ion-buttons slot="start">
<ion-back-button [attr.aria-label]="'core.back' | translate"></ion-back-button> <ion-back-button [text]="'core.back' | translate"></ion-back-button>
</ion-buttons> </ion-buttons>
<ion-title>{{ 'addon.calendar.calendarevents' | translate }}</ion-title> <ion-title>{{ 'addon.calendar.calendarevents' | translate }}</ion-title>
<ion-buttons slot="end"> <ion-buttons slot="end">
<ion-button (click)="openFilter($event)" [attr.aria-label]="'core.filter' | translate"> <ion-button (click)="openFilter($event)" [attr.aria-label]="'core.filter' | translate">
<ion-icon slot="icon-only" name="fas-filter"></ion-icon> <ion-icon slot="icon-only" name="fas-filter" aria-hidden="true"></ion-icon>
</ion-button> </ion-button>
<core-context-menu> <core-context-menu>
<core-context-menu-item [hidden]="!notificationsEnabled" [priority]="600" <core-context-menu-item [hidden]="!notificationsEnabled" [priority]="600"
@ -28,7 +28,7 @@
<!-- There is data to be synchronized --> <!-- There is data to be synchronized -->
<ion-card class="core-warning-card" *ngIf="hasOffline"> <ion-card class="core-warning-card" *ngIf="hasOffline">
<ion-item> <ion-item>
<ion-icon name="fas-exclamation-triangle" slot="start"></ion-icon> <ion-icon name="fas-exclamation-triangle" slot="start" aria-hidden="true"></ion-icon>
<ion-label>{{ 'core.hasdatatosync' | translate:{$a: 'addon.calendar.calendar' | translate} }}</ion-label> <ion-label>{{ 'core.hasdatatosync' | translate:{$a: 'addon.calendar.calendar' | translate} }}</ion-label>
</ion-item> </ion-item>
</ion-card> </ion-card>
@ -42,13 +42,21 @@
<ion-item-divider *ngIf="event.showDate"> <ion-item-divider *ngIf="event.showDate">
<ion-label>{{ event.timestart * 1000 | coreFormatDate: "strftimedayshort" }}</ion-label> <ion-label>{{ event.timestart * 1000 | coreFormatDate: "strftimedayshort" }}</ion-label>
</ion-item-divider> </ion-item-divider>
<ion-item class="addon-calendar-event ion-text-wrap" [title]="event.name" (click)="gotoEvent(event.id)" <ion-item class="addon-calendar-event ion-text-wrap" [attr.aria-label]="event.name" (click)="gotoEvent(event.id)"
[class.core-selected-item]="event.id == eventId" [ngClass]="['addon-calendar-eventtype-'+event.eventtype]"> [attr.aria-current]="event.id == eventId ? 'page' : 'false'"
<img *ngIf="event.moduleIcon" src="{{event.moduleIcon}}" slot="start" class="core-module-icon"> [ngClass]="['addon-calendar-eventtype-'+event.eventtype]" button>
<ion-icon *ngIf="event.eventIcon && !event.moduleIcon" [name]="event.eventIcon" slot="start"> <img *ngIf="event.moduleIcon" src="{{event.moduleIcon}}" slot="start" class="core-module-icon" alt=""
role="presentation">
<ion-icon *ngIf="event.eventIcon && !event.moduleIcon" [name]="event.eventIcon" slot="start"
aria-hidden="true">
</ion-icon> </ion-icon>
<ion-label> <ion-label>
<h2> <h2>
<!-- Add the icon title so accessibility tools read it. -->
<span class="sr-only">
{{ 'addon.calendar.type' + event.formattedType | translate }}
<span class="sr-only" *ngIf="event.moduleIcon && event.iconTitle">{{ event.iconTitle }}</span>
</span>
<core-format-text [text]="event.name" [contextLevel]="event.contextLevel" <core-format-text [text]="event.name" [contextLevel]="event.contextLevel"
[contextInstanceId]="event.contextInstanceId"> [contextInstanceId]="event.contextInstanceId">
</core-format-text> </core-format-text>
@ -64,11 +72,11 @@
</p> </p>
</ion-label> </ion-label>
<ion-note *ngIf="event.offline && !event.deleted" slot="end"> <ion-note *ngIf="event.offline && !event.deleted" slot="end">
<ion-icon name="far-clock"></ion-icon> <ion-icon name="fas-clock" aria-hidden="true"></ion-icon>
<span class="ion-text-wrap">{{ 'core.notsent' | translate }}</span> <span class="ion-text-wrap">{{ 'core.notsent' | translate }}</span>
</ion-note> </ion-note>
<ion-note *ngIf="event.deleted" slot="end"> <ion-note *ngIf="event.deleted" slot="end">
<ion-icon name="fas-trash"></ion-icon> <ion-icon name="fas-trash" aria-hidden="true"></ion-icon>
<span class="ion-text-wrap">{{ 'core.deletedoffline' | translate }}</span> <span class="ion-text-wrap">{{ 'core.deletedoffline' | translate }}</span>
</ion-note> </ion-note>
</ion-item> </ion-item>
@ -82,7 +90,7 @@
<!-- Create a calendar event. --> <!-- Create a calendar event. -->
<ion-fab slot="fixed" core-fab vertical="bottom" horizontal="end" *ngIf="canCreate"> <ion-fab slot="fixed" core-fab vertical="bottom" horizontal="end" *ngIf="canCreate">
<ion-fab-button (click)="openEdit()" [attr.aria-label]="'addon.calendar.newevent' | translate"> <ion-fab-button (click)="openEdit()" [attr.aria-label]="'addon.calendar.newevent' | translate">
<ion-icon name="fas-plus"></ion-icon> <ion-icon name="fas-plus" aria-hidden="true"></ion-icon>
</ion-fab-button> </ion-fab-button>
</ion-fab> </ion-fab>
</core-split-view> </core-split-view>

View File

@ -1,7 +1,7 @@
<ion-header> <ion-header>
<ion-toolbar> <ion-toolbar>
<ion-buttons slot="start"> <ion-buttons slot="start">
<ion-back-button [attr.aria-label]="'core.back' | translate"></ion-back-button> <ion-back-button [text]="'core.back' | translate"></ion-back-button>
</ion-buttons> </ion-buttons>
<ion-title>{{ 'core.settings.settings' | translate }}</ion-title> <ion-title>{{ 'core.settings.settings' | translate }}</ion-title>
</ion-toolbar> </ion-toolbar>

View File

@ -189,6 +189,7 @@ export class AddonCalendarHelperProvider {
if (event.modulename) { if (event.modulename) {
eventFormatted.eventIcon = CoreCourse.getModuleIconSrc(event.modulename); eventFormatted.eventIcon = CoreCourse.getModuleIconSrc(event.modulename);
eventFormatted.moduleIcon = eventFormatted.eventIcon; eventFormatted.moduleIcon = eventFormatted.eventIcon;
eventFormatted.iconTitle = CoreCourse.translateModuleName(event.modulename);
} }
eventFormatted.formattedType = AddonCalendar.getEventType(event); eventFormatted.formattedType = AddonCalendar.getEventType(event);

View File

@ -2250,6 +2250,7 @@ export type AddonCalendarEventToDisplay = Partial<AddonCalendarCalendarEvent> &
deleted?: boolean; // Calculated in the app. Whether it has been deleted in offline. deleted?: boolean; // Calculated in the app. Whether it has been deleted in offline.
encodedLocation?: SafeUrl; // Calculated in the app. Sanitized location link. encodedLocation?: SafeUrl; // Calculated in the app. Sanitized location link.
eventIcon?: string; // Calculated in the app. Event icon. eventIcon?: string; // Calculated in the app. Event icon.
iconTitle?: string;
moduleIcon?: string; // Calculated in the app. Module icon. moduleIcon?: string; // Calculated in the app. Module icon.
formattedType: string; // Calculated in the app. Formatted type. formattedType: string; // Calculated in the app. Formatted type.
duration?: number; // Calculated in the app. Duration of offline event. duration?: number; // Calculated in the app. Duration of offline event.

View File

@ -1,7 +1,7 @@
<ion-header> <ion-header>
<ion-toolbar> <ion-toolbar>
<ion-buttons slot="start"> <ion-buttons slot="start">
<ion-back-button [attr.aria-label]="'core.back' | translate"></ion-back-button> <ion-back-button [text]="'core.back' | translate"></ion-back-button>
</ion-buttons> </ion-buttons>
<ion-title>{{ title }}</ion-title> <ion-title>{{ title }}</ion-title>
</ion-toolbar> </ion-toolbar>
@ -14,8 +14,8 @@
<core-loading [hideUntil]="competencies.loaded"> <core-loading [hideUntil]="competencies.loaded">
<ion-list> <ion-list>
<ion-item class="ion-text-wrap" *ngFor="let competency of competencies.items" <ion-item class="ion-text-wrap" *ngFor="let competency of competencies.items"
[title]="competency.competency.shortname" (click)="competencies.select(competency)" [attr.aria-label]="competency.competency.shortname" (click)="competencies.select(competency)"
[class.core-selected-item]="competencies.isSelected(competency)"> [attr.aria-current]="competencies.getItemAriaCurrent(competency)" button>
<ion-label> <ion-label>
<h2>{{ competency.competency.shortname }} <em>{{competency.competency.idnumber}}</em></h2> <h2>{{ competency.competency.shortname }} <em>{{competency.competency.idnumber}}</em></h2>
</ion-label> </ion-label>

View File

@ -1,7 +1,7 @@
<ion-header> <ion-header>
<ion-toolbar> <ion-toolbar>
<ion-buttons slot="start"> <ion-buttons slot="start">
<ion-back-button [attr.aria-label]="'core.back' | translate"></ion-back-button> <ion-back-button [text]="'core.back' | translate"></ion-back-button>
</ion-buttons> </ion-buttons>
<ion-title *ngIf="competency"> <ion-title *ngIf="competency">
{{ competency.competency.competency.shortname }} <small>{{ competency.competency.competency.idnumber }}</small> {{ competency.competency.competency.shortname }} <small>{{ competency.competency.competency.idnumber }}</small>
@ -73,9 +73,9 @@
<p *ngIf="coursemodules.length == 0"> <p *ngIf="coursemodules.length == 0">
{{ 'addon.competency.noactivities' | translate }} {{ 'addon.competency.noactivities' | translate }}
</p> </p>
<ion-item class="ion-text-wrap" *ngFor="let activity of coursemodules" [href]="activity.url" [title]="activity.name" <ion-item class="ion-text-wrap" *ngFor="let activity of coursemodules" [href]="activity.url"
core-link capture="true"> [attr.aria-label]="activity.name" core-link capture="true">
<img slot="start" core-external-content [src]="activity.iconurl" alt="" role="presentation" *ngIf="activity.iconurl" <img slot="start" core-external-content [src]="activity.iconurl" alt="" *ngIf="activity.iconurl"
class="core-module-icon"> class="core-module-icon">
<ion-label> <ion-label>
<core-format-text [text]="activity.name" contextLevel="module" [contextInstanceId]="activity.id" <core-format-text [text]="activity.name" contextLevel="module" [contextInstanceId]="activity.id"

View File

@ -1,7 +1,7 @@
<ion-header> <ion-header>
<ion-toolbar> <ion-toolbar>
<ion-buttons slot="start"> <ion-buttons slot="start">
<ion-back-button [attr.aria-label]="'core.back' | translate"></ion-back-button> <ion-back-button [text]="'core.back' | translate"></ion-back-button>
</ion-buttons> </ion-buttons>
<ion-title *ngIf="competency"> <ion-title *ngIf="competency">
{{ competency.competency.shortname }} <small>{{ competency.competency.idnumber }}</small> {{ competency.competency.shortname }} <small>{{ competency.competency.idnumber }}</small>

View File

@ -1,7 +1,7 @@
<ion-header> <ion-header>
<ion-toolbar> <ion-toolbar>
<ion-buttons slot="start"> <ion-buttons slot="start">
<ion-back-button [attr.aria-label]="'core.back' | translate"></ion-back-button> <ion-back-button [text]="'core.back' | translate"></ion-back-button>
</ion-buttons> </ion-buttons>
<ion-title>{{ 'addon.competency.coursecompetencies' | translate }}</ion-title> <ion-title>{{ 'addon.competency.coursecompetencies' | translate }}</ion-title>
</ion-toolbar> </ion-toolbar>
@ -56,7 +56,7 @@
<div *ngIf="competencies"> <div *ngIf="competencies">
<ion-card *ngFor="let competency of competencies.competencies"> <ion-card *ngFor="let competency of competencies.competencies">
<ion-item class="ion-text-wrap" (click)="openCompetency(competency.competency.id)" <ion-item class="ion-text-wrap" (click)="openCompetency(competency.competency.id)"
[title]="competency.competency.shortname" detail="true"> [attr.aria-label]="competency.competency.shortname" detail="true" button>
<ion-label> <ion-label>
<h2><strong>{{competency.competency.shortname}} <em>{{competency.competency.idnumber}}</em></strong></h2> <h2><strong>{{competency.competency.shortname}} <em>{{competency.competency.idnumber}}</em></strong></h2>
</ion-label> </ion-label>
@ -103,9 +103,9 @@
<p *ngIf="competency.coursemodules.length == 0"> <p *ngIf="competency.coursemodules.length == 0">
{{ 'addon.competency.noactivities' | translate }} {{ 'addon.competency.noactivities' | translate }}
</p> </p>
<ion-item class="ion-text-wrap core-course-module-handler item-media" [title]="activity.name" core-link <ion-item class="ion-text-wrap core-course-module-handler item-media" [attr.aria-label]="activity.name"
*ngFor="let activity of competency.coursemodules" [href]="activity.url" capture="true"> core-link *ngFor="let activity of competency.coursemodules" [href]="activity.url" capture="true">
<img slot="start" [src]="activity.iconurl" core-external-content alt="" role="presentation" <img slot="start" [src]="activity.iconurl" core-external-content alt=""
*ngIf="activity.iconurl" class="core-module-icon"> *ngIf="activity.iconurl" class="core-module-icon">
<ion-label> <ion-label>
<core-format-text [text]="activity.name" contextLevel="module" [contextInstanceId]="activity.id" <core-format-text [text]="activity.name" contextLevel="module" [contextInstanceId]="activity.id"
@ -120,7 +120,7 @@
{{ 'addon.competency.nouserplanswithcompetency' | translate }} {{ 'addon.competency.nouserplanswithcompetency' | translate }}
</p> </p>
<ion-item class="ion-text-wrap" *ngFor="let plan of competency.plans" [href]="plan.url" <ion-item class="ion-text-wrap" *ngFor="let plan of competency.plans" [href]="plan.url"
[title]="plan.name" core-link capture="true"> [attr.aria-label]="plan.name" core-link capture="true">
<ion-label> <ion-label>
<core-format-text [text]="plan.name" contextLevel="user" [contextInstanceId]="plan.userid"> <core-format-text [text]="plan.name" contextLevel="user" [contextInstanceId]="plan.userid">
</core-format-text> </core-format-text>

View File

@ -1,7 +1,7 @@
<ion-header> <ion-header>
<ion-toolbar> <ion-toolbar>
<ion-buttons slot="start"> <ion-buttons slot="start">
<ion-back-button [attr.aria-label]="'core.back' | translate"></ion-back-button> <ion-back-button [text]="'core.back' | translate"></ion-back-button>
</ion-buttons> </ion-buttons>
<ion-title *ngIf="plan">{{plan.plan.name}}</ion-title> <ion-title *ngIf="plan">{{plan.plan.name}}</ion-title>
</ion-toolbar> </ion-toolbar>
@ -75,7 +75,7 @@
</ion-item> </ion-item>
<ion-item class="ion-text-wrap" *ngFor="let competency of plan.competencies" <ion-item class="ion-text-wrap" *ngFor="let competency of plan.competencies"
(click)="openCompetency(competency.competency.id)" (click)="openCompetency(competency.competency.id)"
[title]="competency.competency.shortname" detail="true"> [attr.aria-label]="competency.competency.shortname" detail="true" button>
<ion-label><h2>{{competency.competency.shortname}} <em>{{competency.competency.idnumber}}</em></h2></ion-label> <ion-label><h2>{{competency.competency.shortname}} <em>{{competency.competency.idnumber}}</em></h2></ion-label>
<ion-badge *ngIf="competency.usercompetencyplan" slot="end" <ion-badge *ngIf="competency.usercompetencyplan" slot="end"
[color]="competency.usercompetencyplan.proficiency ? 'success' : 'danger'"> [color]="competency.usercompetencyplan.proficiency ? 'success' : 'danger'">

View File

@ -1,7 +1,7 @@
<ion-header> <ion-header>
<ion-toolbar> <ion-toolbar>
<ion-buttons slot="start"> <ion-buttons slot="start">
<ion-back-button [attr.aria-label]="'core.back' | translate"></ion-back-button> <ion-back-button [text]="'core.back' | translate"></ion-back-button>
</ion-buttons> </ion-buttons>
<ion-title>{{ 'addon.competency.userplans' | translate }}</ion-title> <ion-title>{{ 'addon.competency.userplans' | translate }}</ion-title>
</ion-toolbar> </ion-toolbar>
@ -16,8 +16,8 @@
</core-empty-box> </core-empty-box>
<ion-list *ngIf="!plans.empty" class="ion-no-margin"> <ion-list *ngIf="!plans.empty" class="ion-no-margin">
<ion-item class="ion-text-wrap" *ngFor="let plan of plans.items" [title]="plan.name" (click)="plans.select(plan)" <ion-item class="ion-text-wrap" *ngFor="let plan of plans.items" [attr.aria-label]="plan.name"
[class.core-selected-item]="plans.isSelected(plan)"> (click)="plans.select(plan)" [attr.aria-current]="plans.getItemAriaCurrent(plan)" button>
<ion-label> <ion-label>
<h2>{{ plan.name }}</h2> <h2>{{ plan.name }}</h2>
<p *ngIf="plan.duedate > 0"> <p *ngIf="plan.duedate > 0">

View File

@ -1,7 +1,7 @@
<ion-header> <ion-header>
<ion-toolbar> <ion-toolbar>
<ion-buttons slot="start"> <ion-buttons slot="start">
<ion-back-button [attr.aria-label]="'core.back' | translate"></ion-back-button> <ion-back-button [text]="'core.back' | translate"></ion-back-button>
</ion-buttons> </ion-buttons>
<ion-title>{{ 'addon.coursecompletion.coursecompletion' | translate }}</ion-title> <ion-title>{{ 'addon.coursecompletion.coursecompletion' | translate }}</ion-title>
</ion-toolbar> </ion-toolbar>
@ -84,7 +84,7 @@
<ion-card class="core-warning-card" *ngIf="!tracked"> <ion-card class="core-warning-card" *ngIf="!tracked">
<ion-item> <ion-item>
<ion-icon name="fas-exclamation-triangle" slot="start"></ion-icon> <ion-icon name="fas-exclamation-triangle" slot="start" aria-hidden="true"></ion-icon>
<ion-label>{{ 'addon.coursecompletion.nottracked' | translate }}</ion-label> <ion-label>{{ 'addon.coursecompletion.nottracked' | translate }}</ion-label>
</ion-item> </ion-item>
</ion-card> </ion-card>

View File

@ -1,7 +1,7 @@
<ion-header> <ion-header>
<ion-toolbar> <ion-toolbar>
<ion-buttons slot="start"> <ion-buttons slot="start">
<ion-back-button [attr.aria-label]="'core.back' | translate"></ion-back-button> <ion-back-button [text]="'core.back' | translate"></ion-back-button>
</ion-buttons> </ion-buttons>
<ion-title>{{ 'addon.messageoutput_airnotifier.processorsettingsdesc' | translate }}</ion-title> <ion-title>{{ 'addon.messageoutput_airnotifier.processorsettingsdesc' | translate }}</ion-title>
</ion-toolbar> </ion-toolbar>

View File

@ -3,7 +3,7 @@
<ion-title>{{ 'addon.messages.groupinfo' | translate }}</ion-title> <ion-title>{{ 'addon.messages.groupinfo' | translate }}</ion-title>
<ion-buttons slot="end"> <ion-buttons slot="end">
<ion-button (click)="closeModal()" [attr.aria-label]="'core.close' | translate"> <ion-button (click)="closeModal()" [attr.aria-label]="'core.close' | translate">
<ion-icon name="fas-times" slot="icon-only"></ion-icon> <ion-icon name="fas-times" slot="icon-only" aria-hidden="true"></ion-icon>
</ion-button> </ion-button>
</ion-buttons> </ion-buttons>
</ion-toolbar> </ion-toolbar>
@ -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>
@ -33,13 +33,14 @@
</ion-item> </ion-item>
<ion-item class="ion-text-wrap addon-messages-conversation-item" *ngFor="let member of members" <ion-item class="ion-text-wrap addon-messages-conversation-item" *ngFor="let member of members"
(click)="closeModal(member.id)" detail> (click)="closeModal(member.id)" detail="true" button>
<core-user-avatar [user]="member" [linkProfile]="false" [checkOnline]="member.showonlinestatus" slot="start"> <core-user-avatar [user]="member" [linkProfile]="false" [checkOnline]="member.showonlinestatus" slot="start">
</core-user-avatar> </core-user-avatar>
<ion-label> <ion-label>
<h2> <h2>
{{ member.fullname }} {{ member.fullname }}
<ion-icon name="fas-user-slash" *ngIf="member.isblocked" [title]="'addon.messages.contactblocked' | translate"> <ion-icon name="fas-user-slash" *ngIf="member.isblocked"
[attr.aria-label]="'addon.messages.contactblocked' | translate">
</ion-icon> </ion-icon>
</h2> </h2>
</ion-label> </ion-label>

View File

@ -1,7 +1,7 @@
<ion-header> <ion-header>
<ion-toolbar> <ion-toolbar>
<ion-buttons slot="start"> <ion-buttons slot="start">
<ion-back-button [attr.aria-label]="'core.back' | translate"></ion-back-button> <ion-back-button [text]="'core.back' | translate"></ion-back-button>
</ion-buttons> </ion-buttons>
<ion-title>{{ 'addon.messages.contacts' | translate }}</ion-title> <ion-title>{{ 'addon.messages.contacts' | translate }}</ion-title>
<ion-buttons slot="end"> <ion-buttons slot="end">
@ -38,8 +38,8 @@
<!-- Don't show deleted users --> <!-- Don't show deleted users -->
<ion-item class="ion-text-wrap addon-messages-conversation-item" <ion-item class="ion-text-wrap addon-messages-conversation-item"
*ngIf="contact.profileimageurl || contact.profileimageurlsmall" *ngIf="contact.profileimageurl || contact.profileimageurlsmall"
[title]="contact.fullname" (click)="gotoDiscussion(contact.id)" detail [attr.aria-label]="contact.fullname" (click)="gotoDiscussion(contact.id)" detail="true" button
[class.core-selected-item]="contact.id == discussionUserId"> [attr.aria-current]="contact.id == discussionUserId ? 'page' : 'false'">
<core-user-avatar [user]="contact" slot="start" [checkOnline]="contact.showonlinestatus"></core-user-avatar> <core-user-avatar [user]="contact" slot="start" [checkOnline]="contact.showonlinestatus"></core-user-avatar>
<ion-label><h2>{{ contact.fullname }}</h2></ion-label> <ion-label><h2>{{ contact.fullname }}</h2></ion-label>
</ion-item> </ion-item>

View File

@ -1,12 +1,12 @@
<ion-header> <ion-header>
<ion-toolbar> <ion-toolbar>
<ion-buttons slot="start"> <ion-buttons slot="start">
<ion-back-button [attr.aria-label]="'core.back' | translate"></ion-back-button> <ion-back-button [text]="'core.back' | translate"></ion-back-button>
</ion-buttons> </ion-buttons>
<ion-title>{{ 'addon.messages.contacts' | translate }}</ion-title> <ion-title>{{ 'addon.messages.contacts' | translate }}</ion-title>
<ion-buttons slot="end"> <ion-buttons slot="end">
<ion-button (click)="gotoSearch()" [attr.aria-label]="'addon.messages.search' | translate"> <ion-button (click)="gotoSearch()" [attr.aria-label]="'addon.messages.searchcombined' | translate">
<ion-icon name="fas-search" slot="icon-only"></ion-icon> <ion-icon name="fas-search" slot="icon-only" aria-hidden="true"></ion-icon>
</ion-button> </ion-button>
<!-- Add an empty context menu so discussion page can add items in split view, otherwise the menu <!-- Add an empty context menu so discussion page can add items in split view, otherwise the menu
disappears in some cases. --> disappears in some cases. -->
@ -26,9 +26,9 @@
</ion-refresher> </ion-refresher>
<core-loading [hideUntil]="confirmedLoaded" class="core-loading-center"> <core-loading [hideUntil]="confirmedLoaded" class="core-loading-center">
<ion-list class="ion-no-margin"> <ion-list class="ion-no-margin">
<ion-item class="ion-text-wrap addon-messages-conversation-item" <ion-item class="ion-text-wrap addon-messages-conversation-item" (click)="selectUser(contact.id)" button
*ngFor="let contact of confirmedContacts" [title]="contact.fullname" detail *ngFor="let contact of confirmedContacts" [attr.aria-label]="contact.fullname" detail="true"
(click)="selectUser(contact.id)" [class.core-selected-item]="contact.id == selectedUserId"> [attr.aria-current]="contact.id == selectedUserId ? 'page' : 'false'">
<core-user-avatar slot="start" [user]="contact" <core-user-avatar slot="start" [user]="contact"
[checkOnline]="contact.showonlinestatus" [linkProfile]="false"> [checkOnline]="contact.showonlinestatus" [linkProfile]="false">
</core-user-avatar> </core-user-avatar>
@ -36,7 +36,8 @@
<h2> <h2>
<core-format-text [text]="contact.fullname" contextLevel="system" [contextInstanceId]="0"> <core-format-text [text]="contact.fullname" contextLevel="system" [contextInstanceId]="0">
</core-format-text> </core-format-text>
<ion-icon *ngIf="contact.isblocked" name="fas-user-slash" slot="end"> <ion-icon *ngIf="contact.isblocked" name="fas-user-slash" slot="end"
[attr.aria-label]="'addon.messages.contactblocked' | translate">
</ion-icon> </ion-icon>
</h2> </h2>
</ion-label> </ion-label>
@ -63,8 +64,8 @@
<core-loading [hideUntil]="requestsLoaded" class="core-loading-center"> <core-loading [hideUntil]="requestsLoaded" class="core-loading-center">
<ion-list class="ion-no-margin"> <ion-list class="ion-no-margin">
<ion-item class="ion-text-wrap addon-messages-conversation-item" *ngFor="let request of requests" <ion-item class="ion-text-wrap addon-messages-conversation-item" *ngFor="let request of requests"
[title]="request.fullname" (click)="selectUser(request.id)" [attr.aria-label]="request.fullname" (click)="selectUser(request.id)" button
[class.core-selected-item]="request.id == selectedUserId" detail> [attr.aria-current]="request.id == selectedUserId ? 'page' : 'false'" detail="true">
<core-user-avatar slot="start" [user]="request" [linkProfile]="false"></core-user-avatar> <core-user-avatar slot="start" [user]="request" [linkProfile]="false"></core-user-avatar>
<ion-label> <ion-label>
<core-format-text [text]="request.fullname" contextLevel="system" [contextInstanceId]="0"> <core-format-text [text]="request.fullname" contextLevel="system" [contextInstanceId]="0">

View File

@ -1,29 +1,30 @@
<ion-header> <ion-header>
<ion-toolbar> <ion-toolbar>
<ion-buttons slot="start"> <ion-buttons slot="start">
<ion-back-button [attr.aria-label]="'core.back' | translate"></ion-back-button> <ion-back-button [text]="'core.back' | translate"></ion-back-button>
</ion-buttons> </ion-buttons>
<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()">
</core-user-avatar> </core-user-avatar>
<core-format-text [text]="title" contextLevel="system" [contextInstanceId]="0" <core-format-text [text]="title" contextLevel="system" [contextInstanceId]="0"
(click)="showInfo && !isGroup && viewInfo()"></core-format-text> (click)="showInfo && !isGroup && viewInfo()"></core-format-text>
<ion-icon *ngIf="conversation && conversation.isfavourite" name="fas-star" [title]="'core.favourites' | translate"> <ion-icon *ngIf="conversation && conversation.isfavourite" name="fas-star"
[attr.aria-label]="'core.favourites' | translate">
</ion-icon> </ion-icon>
<ion-icon *ngIf="conversation && conversation.ismuted" name="fas-bell-slash" <ion-icon *ngIf="conversation && conversation.ismuted" name="fas-bell-slash"
[title]="'addon.messages.mutedconversation' | translate"> [attr.aria-label]="'addon.messages.mutedconversation' | translate">
</ion-icon> </ion-icon>
</div> </div>
</ion-title> </ion-title>
<ion-buttons slot="end"></ion-buttons> <ion-buttons slot="end"></ion-buttons>
</ion-toolbar> </ion-toolbar>
<core-navbar-buttons slot="end"> <core-navbar-buttons slot="end">
<core-context-menu [aria-label]="'addon.messages.conversationactions' | translate"> <core-context-menu [attr.aria-label]="'addon.messages.conversationactions' | translate">
<core-context-menu-item [hidden]="isSelf || !showInfo || isGroup" [priority]="1000" <core-context-menu-item [hidden]="isSelf || !showInfo || isGroup" [priority]="1000"
[content]="'addon.messages.info' | translate" (action)="viewInfo()" [content]="'addon.messages.info' | translate" (action)="viewInfo()"
iconAction="fas-info-circle"></core-context-menu-item> iconAction="fas-info-circle"></core-context-menu-item>
@ -82,7 +83,7 @@
<ion-chip class="addon-messages-unreadfrom" *ngIf="unreadMessageFrom && message.id == unreadMessageFrom" <ion-chip class="addon-messages-unreadfrom" *ngIf="unreadMessageFrom && message.id == unreadMessageFrom"
color="light"> color="light">
<ion-label>{{ 'addon.messages.newmessages' | translate }}</ion-label> <ion-label>{{ 'addon.messages.newmessages' | translate }}</ion-label>
<ion-icon name="arrow-round-down"></ion-icon> <ion-icon name="fas-arrow-down" aria-hidden="true"></ion-icon>
</ion-chip> </ion-chip>
<ion-item class="ion-text-wrap addon-message" (longPress)="copyMessage(message)" <ion-item class="ion-text-wrap addon-message" (longPress)="copyMessage(message)"
@ -99,7 +100,9 @@
<div *ngIf="message.showUserData">{{ members[message.useridfrom].fullname }}</div> <div *ngIf="message.showUserData">{{ members[message.useridfrom].fullname }}</div>
<ion-note *ngIf="!message.pending">{{ message.timecreated | coreFormatDate: "strftimetime" }}</ion-note> <ion-note *ngIf="!message.pending">{{ message.timecreated | coreFormatDate: "strftimetime" }}</ion-note>
<ion-note *ngIf="message.pending"><ion-icon name="far-clock"></ion-icon></ion-note> <ion-note *ngIf="message.pending">
<ion-icon name="fas-clock" [attr.aria-label]="'core.notsent' | translate "></ion-icon>
</ion-note>
</h2> </h2>
<!-- Some messages have <p> and some others don't. Add a <p> so they all have same styles. --> <!-- Some messages have <p> and some others don't. Add a <p> so they all have same styles. -->
@ -111,7 +114,7 @@
<ion-button fill="clear" *ngIf="!message.sending && showDelete" (click)="deleteMessage(message, index)" <ion-button fill="clear" *ngIf="!message.sending && showDelete" (click)="deleteMessage(message, index)"
class="addon-messages-delete-button" [@coreSlideInOut]="'fromRight'" class="addon-messages-delete-button" [@coreSlideInOut]="'fromRight'"
[attr.aria-label]=" 'addon.messages.deletemessage' | translate" slot="end"> [attr.aria-label]=" 'addon.messages.deletemessage' | translate" slot="end">
<ion-icon name="fas-trash" color="danger" slot="icon-only"></ion-icon> <ion-icon name="fas-trash" color="danger" slot="icon-only" aria-hidden="true"></ion-icon>
</ion-button> </ion-button>
<div class="tail" *ngIf="message.showTail"></div> <div class="tail" *ngIf="message.showTail"></div>
@ -126,7 +129,7 @@
<ion-fab slot="fixed" core-fab vertical="bottom" horizontal="end" *ngIf="loaded && newMessages > 0"> <ion-fab slot="fixed" core-fab vertical="bottom" horizontal="end" *ngIf="loaded && newMessages > 0">
<ion-fab-button size="small" (click)="scrollToFirstUnreadMessage()" color="light" <ion-fab-button size="small" (click)="scrollToFirstUnreadMessage()" color="light"
[attr.aria-label]="'addon.messages.newmessages' | translate"> [attr.aria-label]="'addon.messages.newmessages' | translate">
<ion-icon name="fas-arrow-down"></ion-icon> <ion-icon name="fas-arrow-down" aria-hidden="true"></ion-icon>
<span class="core-discussion-messages-badge">{{ newMessages }}</span> <span class="core-discussion-messages-badge">{{ newMessages }}</span>
</ion-fab-button> </ion-fab-button>
</ion-fab> </ion-fab>

View File

@ -1,7 +1,7 @@
<ion-header> <ion-header>
<ion-toolbar> <ion-toolbar>
<ion-buttons slot="start"> <ion-buttons slot="start">
<ion-back-button [attr.aria-label]="'core.back' | translate"></ion-back-button> <ion-back-button [text]="'core.back' | translate"></ion-back-button>
</ion-buttons> </ion-buttons>
<ion-title>{{ 'addon.messages.messages' | translate }}</ion-title> <ion-title>{{ 'addon.messages.messages' | translate }}</ion-title>
<ion-buttons slot="end"> <ion-buttons slot="end">
@ -26,8 +26,8 @@
<ion-list class="ion-no-margin"> <ion-list class="ion-no-margin">
<ion-item class="ion-text-wrap addon-message-discussion" (click)="gotoContacts()" <ion-item class="ion-text-wrap addon-message-discussion" (click)="gotoContacts()"
[attr.aria-label]="'addon.messages.contacts' | translate" detail> [attr.aria-label]="'addon.messages.contacts' | translate" detail="true" button>
<ion-icon name="fas-address-book" slot="start"></ion-icon> <ion-icon name="fas-address-book" slot="start" aria-hidden="true"></ion-icon>
<ion-label><h2>{{ 'addon.messages.contacts' | translate }}</h2></ion-label> <ion-label><h2>{{ 'addon.messages.contacts' | translate }}</h2></ion-label>
</ion-item> </ion-item>
@ -38,9 +38,9 @@
</ion-label> </ion-label>
<ion-note slot="end" class="ion-padding-end"><ion-badge>{{ search.results.length }}</ion-badge></ion-note> <ion-note slot="end" class="ion-padding-end"><ion-badge>{{ search.results.length }}</ion-badge></ion-note>
</ion-item-divider> </ion-item-divider>
<ion-item class="ion-text-wrap addon-message-discussion" *ngFor="let result of search.results" [title]="result.fullname" <ion-item class="ion-text-wrap addon-message-discussion" *ngFor="let result of search.results" button
(click)="gotoDiscussion(result.userid, result.messageid)" [attr.aria-label]="result.fullname" (click)="gotoDiscussion(result.userid, result.messageid)"
[class.core-selected-item]="result.userid == discussionUserId"> [attr.aria-current]="result.userid == discussionUserId ? 'page' : 'false'">
<core-user-avatar [user]="result" slot="start" [checkOnline]="result.showonlinestatus"></core-user-avatar> <core-user-avatar [user]="result" slot="start" [checkOnline]="result.showonlinestatus"></core-user-avatar>
<ion-label> <ion-label>
<h2>{{ result.fullname }}</h2> <h2>{{ result.fullname }}</h2>
@ -50,9 +50,9 @@
</ion-item> </ion-item>
</ng-container> </ng-container>
<ng-container *ngIf="!search.showResults"> <ng-container *ngIf="!search.showResults">
<ion-item class="ion-text-wrap addon-message-discussion" *ngFor="let discussion of discussions" <ion-item class="ion-text-wrap addon-message-discussion" *ngFor="let discussion of discussions" button
[title]="discussion.fullname" (click)="gotoDiscussion(discussion.message!.user)" [attr.aria-label]="discussion.fullname" (click)="gotoDiscussion(discussion.message!.user)"
[class.core-selected-item]="discussion.message!.user == discussionUserId"> [attr.aria-current]="discussion.message!.user == discussionUserId ? 'page' : 'false'">
<core-user-avatar [user]="discussion" slot="start" checkOnline="false"></core-user-avatar> <core-user-avatar [user]="discussion" slot="start" checkOnline="false"></core-user-avatar>
<ion-label> <ion-label>
<h2>{{ discussion.fullname }}</h2> <h2>{{ discussion.fullname }}</h2>

View File

@ -1,15 +1,15 @@
<ion-header> <ion-header>
<ion-toolbar> <ion-toolbar>
<ion-buttons slot="start"> <ion-buttons slot="start">
<ion-back-button [attr.aria-label]="'core.back' | translate"></ion-back-button> <ion-back-button [text]="'core.back' | translate"></ion-back-button>
</ion-buttons> </ion-buttons>
<ion-title>{{ 'addon.messages.messages' | translate }}</ion-title> <ion-title>{{ 'addon.messages.messages' | translate }}</ion-title>
<ion-buttons slot="end"> <ion-buttons slot="end">
<ion-button (click)="gotoSearch()" [attr.aria-label]="'addon.messages.search' | translate"> <ion-button (click)="gotoSearch()" [attr.aria-label]="'addon.messages.searchcombined' | translate">
<ion-icon name="fas-search" slot="icon-only"></ion-icon> <ion-icon name="fas-search" slot="icon-only" aria-hidden="true"></ion-icon>
</ion-button> </ion-button>
<ion-button (click)="gotoSettings()" [attr.aria-label]="'addon.messages.messagepreferences' | translate"> <ion-button (click)="gotoSettings()" [attr.aria-label]="'addon.messages.messagepreferences' | translate">
<ion-icon name="fas-cog" slot="icon-only"></ion-icon> <ion-icon name="fas-cog" slot="icon-only" aria-hidden="true"></ion-icon>
</ion-button> </ion-button>
<!-- Add an empty context menu so discussion page can add items in split view, <!-- Add an empty context menu so discussion page can add items in split view,
otherwise the menu disappears in some cases. --> otherwise the menu disappears in some cases. -->
@ -26,15 +26,17 @@
<core-loading [hideUntil]="loaded" [message]="loadingMessage"> <core-loading [hideUntil]="loaded" [message]="loadingMessage">
<ion-list> <ion-list>
<ion-item class="ion-text-wrap addon-message-discussion" (click)="gotoContacts()" <ion-item class="ion-text-wrap addon-message-discussion" (click)="gotoContacts()"
[attr.aria-label]="'addon.messages.contacts' | translate" detail> [attr.aria-label]="'addon.messages.contacts' | translate" detail="true" button>
<ion-icon name="fas-address-book" slot="start"></ion-icon> <ion-icon name="fas-address-book" slot="start" aria-hidden="true"></ion-icon>
<ion-label><h2>{{ 'addon.messages.contacts' | translate }}</h2></ion-label> <ion-label><h2>{{ 'addon.messages.contacts' | translate }}</h2></ion-label>
<ion-badge *ngIf="contactRequestsCount > 0" slot="end">{{contactRequestsCount}}</ion-badge> <ion-badge *ngIf="contactRequestsCount > 0" slot="end">{{contactRequestsCount}}</ion-badge>
</ion-item> </ion-item>
<!-- 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"
<ion-icon *ngIf="!favourites.expanded" name="fas-caret-right" slot="start"></ion-icon> [attr.aria-label]="(favourites.expanded ? 'core.collapse' : 'core.expand') | translate"
<ion-icon *ngIf="favourites.expanded" name="fas-caret-down" slot="start"></ion-icon> [attr.aria-expanded]="favourites.expanded" role="heading button">
<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-label>{{ 'core.favourites' | translate }} ({{ favourites.count }})</ion-label> <ion-label>{{ 'core.favourites' | translate }} ({{ favourites.count }})</ion-label>
<ion-badge slot="end" *ngIf="favourites.unread">{{ favourites.unread }}</ion-badge> <ion-badge slot="end" *ngIf="favourites.unread">{{ favourites.unread }}</ion-badge>
</ion-item-divider> </ion-item-divider>
@ -53,9 +55,11 @@
</ion-item> </ion-item>
<!-- 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"
<ion-icon *ngIf="!group.expanded" name="fas-caret-right" slot="start"></ion-icon> [attr.aria-label]="(group.expanded ? 'core.collapse' : 'core.expand') | translate"
<ion-icon *ngIf="group.expanded" name="fas-caret-down" slot="start"></ion-icon> [attr.aria-expanded]="group.expanded" role="heading button">
<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-label>{{ 'addon.messages.groupconversations' | translate }} ({{ group.count }})</ion-label> <ion-label>{{ 'addon.messages.groupconversations' | translate }} ({{ group.count }})</ion-label>
<ion-badge slot="end" *ngIf="group.unread">{{ group.unread }}</ion-badge> <ion-badge slot="end" *ngIf="group.unread">{{ group.unread }}</ion-badge>
</ion-item-divider> </ion-item-divider>
@ -73,9 +77,11 @@
<ion-label><ion-spinner></ion-spinner></ion-label> <ion-label><ion-spinner></ion-spinner></ion-label>
</ion-item> </ion-item>
<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"
<ion-icon *ngIf="!individual.expanded" name="fas-caret-right" slot="start"></ion-icon> [attr.aria-label]="(individual.expanded ? 'core.collapse' : 'core.expand') | translate"
<ion-icon *ngIf="individual.expanded" name="fas-caret-down" slot="start"></ion-icon> [attr.aria-expanded]="individual.expanded" role="heading button">
<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-label>{{ 'addon.messages.individualconversations' | translate }} ({{ individual.count }})</ion-label> <ion-label>{{ 'addon.messages.individualconversations' | translate }} ({{ individual.count }})</ion-label>
<ion-badge slot="end" *ngIf="individual.unread">{{ individual.unread }}</ion-badge> <ion-badge slot="end" *ngIf="individual.unread">{{ individual.unread }}</ion-badge>
</ion-item-divider> </ion-item-divider>
@ -100,10 +106,10 @@
<!-- Template to render a list of conversations. --> <!-- Template to render a list of conversations. -->
<ng-template #conversationsTemplate let-conversations="conversations"> <ng-template #conversationsTemplate let-conversations="conversations">
<ion-item class="ion-text-wrap addon-message-discussion" *ngFor="let conversation of conversations" [title]="conversation.name" <ion-item class="ion-text-wrap addon-message-discussion" *ngFor="let conversation of conversations" button
(click)="gotoConversation(conversation.id, conversation.userid)" [attr.aria-label]="conversation.name" (click)="gotoConversation(conversation.id, conversation.userid)"
[class.core-selected-item]="(conversation.id && conversation.id == selectedConversationId) || [attr.aria-current]="((conversation.id && conversation.id == selectedConversationId) ||
(conversation.userid && conversation.userid == selectedUserId)" (conversation.userid && conversation.userid == selectedUserId)) ? 'page': 'false'"
id="addon-message-conversation-{{ conversation.id ? conversation.id : 'user-' + conversation.userid }}"> id="addon-message-conversation-{{ conversation.id ? conversation.id : 'user-' + conversation.userid }}">
<!-- Group conversation image. --> <!-- Group conversation image. -->
<ion-avatar slot="start" *ngIf="conversation.type == typeGroup"> <ion-avatar slot="start" *ngIf="conversation.type == typeGroup">

View File

@ -1,7 +1,7 @@
<ion-header> <ion-header>
<ion-toolbar> <ion-toolbar>
<ion-buttons slot="start"> <ion-buttons slot="start">
<ion-back-button [attr.aria-label]="'core.back' | translate"></ion-back-button> <ion-back-button [text]="'core.back' | translate"></ion-back-button>
</ion-buttons> </ion-buttons>
<ion-title>{{ 'addon.messages.searchcombined' | translate }}</ion-title> <ion-title>{{ 'addon.messages.searchcombined' | translate }}</ion-title>
<ion-buttons slot="end"> <ion-buttons slot="end">
@ -42,13 +42,16 @@
</ion-item-divider> </ion-item-divider>
<!-- List of results --> <!-- List of results -->
<ion-item class="addon-message-discussion ion-text-wrap" *ngFor="let result of item.results" [title]="result.fullname" <ion-item class="addon-message-discussion ion-text-wrap" *ngFor="let result of item.results" [attr.aria-label]="result.fullname"
(click)="openConversation(result)" [class.core-selected-item]="result == selectedResult" detail> (click)="openConversation(result)" [attr.aria-current]="result == selectedResult ? 'page' : 'false'" detail="true"
button>
<core-user-avatar slot="start" [user]="result" [checkOnline]="true" [linkProfile]="false"></core-user-avatar> <core-user-avatar slot="start" [user]="result" [checkOnline]="true" [linkProfile]="false"></core-user-avatar>
<ion-label> <ion-label>
<h2> <h2>
<core-format-text [text]="result.fullname" [highlight]="result.highlightName" [filter]="false"></core-format-text> <core-format-text [text]="result.fullname" [highlight]="result.highlightName" [filter]="false">
<ion-icon name="fa-ban" *ngIf="result.isblocked" [title]="'addon.messages.contactblocked' | translate"> </core-format-text>
<ion-icon name="fa-ban" *ngIf="result.isblocked"
[attr.aria-label]="'addon.messages.contactblocked' | translate">
</ion-icon> </ion-icon>
</h2> </h2>
<ion-note *ngIf="result.lastmessagedate > 0"> <ion-note *ngIf="result.lastmessagedate > 0">

View File

@ -1,7 +1,7 @@
<ion-header> <ion-header>
<ion-toolbar> <ion-toolbar>
<ion-buttons slot="start"> <ion-buttons slot="start">
<ion-back-button [attr.aria-label]="'core.back' | translate"></ion-back-button> <ion-back-button [text]="'core.back' | translate"></ion-back-button>
</ion-buttons> </ion-buttons>
<ion-title>{{ 'addon.messages.messages' | translate }}</ion-title> <ion-title>{{ 'addon.messages.messages' | translate }}</ion-title>
</ion-toolbar> </ion-toolbar>

View File

@ -3,7 +3,7 @@
<ion-title>{{ plugin.name }}</ion-title> <ion-title>{{ plugin.name }}</ion-title>
<ion-buttons slot="end"> <ion-buttons slot="end">
<ion-button (click)="closeModal()" [attr.aria-label]="'core.close' | translate"> <ion-button (click)="closeModal()" [attr.aria-label]="'core.close' | translate">
<ion-icon slot="icon-only" name="fas-times"></ion-icon> <ion-icon slot="icon-only" name="fas-times" aria-hidden="true"></ion-icon>
</ion-button> </ion-button>
</ion-buttons> </ion-buttons>
</ion-toolbar> </ion-toolbar>

View File

@ -49,7 +49,7 @@
<!-- Assign has something offline. --> <!-- Assign has something offline. -->
<ion-card class="core-warning-card" *ngIf="hasOffline"> <ion-card class="core-warning-card" *ngIf="hasOffline">
<ion-item> <ion-item>
<ion-icon name="fas-exclamation-triangle" slot="start"></ion-icon> <ion-icon name="fas-exclamation-triangle" slot="start" aria-hidden="true"></ion-icon>
<ion-label>{{ 'core.hasdatatosync' | translate: {$a: moduleName} }}</ion-label> <ion-label>{{ 'core.hasdatatosync' | translate: {$a: moduleName} }}</ion-label>
</ion-item> </ion-item>
</ion-card> </ion-card>
@ -84,7 +84,8 @@
</ion-item> </ion-item>
<!-- Summary of all submissions. --> <!-- Summary of all submissions. -->
<ion-item class="ion-text-wrap" *ngIf="summary && summary.participantcount" (click)="goToSubmissionList()" detail> <ion-item class="ion-text-wrap" *ngIf="summary && summary.participantcount" (click)="goToSubmissionList()" detail="true"
button>
<ion-label> <ion-label>
<h2 *ngIf="assign.teamsubmission">{{ 'addon.mod_assign.numberofteams' | translate }}</h2> <h2 *ngIf="assign.teamsubmission">{{ 'addon.mod_assign.numberofteams' | translate }}</h2>
<h2 *ngIf="!assign.teamsubmission">{{ 'addon.mod_assign.numberofparticipants' | translate }}</h2> <h2 *ngIf="!assign.teamsubmission">{{ 'addon.mod_assign.numberofparticipants' | translate }}</h2>
@ -97,6 +98,7 @@
<!-- Summary of submissions with draft status. --> <!-- Summary of submissions with draft status. -->
<ion-item class="ion-text-wrap" *ngIf="assign.submissiondrafts && summary && summary.submissionsenabled" <ion-item class="ion-text-wrap" *ngIf="assign.submissiondrafts && summary && summary.submissionsenabled"
[detail]="!showNumbers || summary.submissiondraftscount" [detail]="!showNumbers || summary.submissiondraftscount"
[button]="!showNumbers || summary.submissiondraftscount"
(click)="goToSubmissionList(submissionStatusDraft, !!summary.submissiondraftscount)"> (click)="goToSubmissionList(submissionStatusDraft, !!summary.submissiondraftscount)">
<ion-label><h2>{{ 'addon.mod_assign.numberofdraftsubmissions' | translate }}</h2></ion-label> <ion-label><h2>{{ 'addon.mod_assign.numberofdraftsubmissions' | translate }}</h2></ion-label>
<ion-badge slot="end" *ngIf="showNumbers" color="primary"> <ion-badge slot="end" *ngIf="showNumbers" color="primary">
@ -107,6 +109,7 @@
<!-- Summary of submissions with submitted status. --> <!-- Summary of submissions with submitted status. -->
<ion-item class="ion-text-wrap" *ngIf="summary && summary.submissionsenabled" <ion-item class="ion-text-wrap" *ngIf="summary && summary.submissionsenabled"
[detail]="!showNumbers || summary.submissionssubmittedcount" [detail]="!showNumbers || summary.submissionssubmittedcount"
[button]="!showNumbers || summary.submissionssubmittedcount"
(click)="goToSubmissionList(submissionStatusSubmitted, !!summary.submissionssubmittedcount)"> (click)="goToSubmissionList(submissionStatusSubmitted, !!summary.submissionssubmittedcount)">
<ion-label><h2>{{ 'addon.mod_assign.numberofsubmittedassignments' | translate }}</h2></ion-label> <ion-label><h2>{{ 'addon.mod_assign.numberofsubmittedassignments' | translate }}</h2></ion-label>
<ion-badge slot="end" *ngIf="showNumbers" color="primary"> <ion-badge slot="end" *ngIf="showNumbers" color="primary">
@ -116,7 +119,7 @@
<!-- Summary of submissions that need grading. --> <!-- Summary of submissions that need grading. -->
<ion-item class="ion-text-wrap" *ngIf="summary && summary.submissionsenabled && !assign.teamsubmission && showNumbers" <ion-item class="ion-text-wrap" *ngIf="summary && summary.submissionsenabled && !assign.teamsubmission && showNumbers"
[detail]="needsGradingAvalaible" [detail]="needsGradingAvalaible" [button]="needsGradingAvalaible"
(click)="goToSubmissionList(needGrading, needsGradingAvalaible)"> (click)="goToSubmissionList(needGrading, needsGradingAvalaible)">
<ion-label><h2>{{ 'addon.mod_assign.numberofsubmissionsneedgrading' | translate }}</h2></ion-label> <ion-label><h2>{{ 'addon.mod_assign.numberofsubmissionsneedgrading' | translate }}</h2></ion-label>
<ion-badge slot="end" color="primary"> <ion-badge slot="end" color="primary">
@ -128,7 +131,7 @@
<!-- Ungrouped users. --> <!-- Ungrouped users. -->
<ion-card *ngIf="assign.teamsubmission && summary && summary.warnofungroupedusers" class="core-info-card"> <ion-card *ngIf="assign.teamsubmission && summary && summary.warnofungroupedusers" class="core-info-card">
<ion-item> <ion-item>
<ion-icon name="fas-question-circle" slot="start"></ion-icon> <ion-icon name="fas-question-circle" slot="start" aria-hidden="true"></ion-icon>
<ion-label>{{ 'addon.mod_assign.'+summary.warnofungroupedusers | translate }}</ion-label> <ion-label>{{ 'addon.mod_assign.'+summary.warnofungroupedusers | translate }}</ion-label>
</ion-item> </ion-item>
</ion-card> </ion-card>

View File

@ -2,7 +2,7 @@
<!-- User and status of the submission. --> <!-- User and status of the submission. -->
<ion-item class="ion-text-wrap" *ngIf="!blindMarking && user" core-user-link [userId]="submitId" [courseId]="courseId" <ion-item class="ion-text-wrap" *ngIf="!blindMarking && user" core-user-link [userId]="submitId" [courseId]="courseId"
[title]="user!.fullname"> [attr.aria-label]="user!.fullname">
<core-user-avatar [user]="user" slot="start"></core-user-avatar> <core-user-avatar [user]="user" slot="start"></core-user-avatar>
<ion-label> <ion-label>
<h2>{{ user!.fullname }}</h2> <h2>{{ user!.fullname }}</h2>
@ -183,7 +183,7 @@
<ng-container *ngIf="membersToSubmit && membersToSubmit.length > 0 && !blindMarking"> <ng-container *ngIf="membersToSubmit && membersToSubmit.length > 0 && !blindMarking">
<ng-container *ngFor="let user of membersToSubmit"> <ng-container *ngFor="let user of membersToSubmit">
<ion-item class="ion-text-wrap" core-user-link [userId]="user.id" <ion-item class="ion-text-wrap" core-user-link [userId]="user.id"
[courseId]="courseId" [title]="user.fullname"> [courseId]="courseId" [attr.aria-label]="user.fullname">
<core-user-avatar [user]="user" slot="start"></core-user-avatar> <core-user-avatar [user]="user" slot="start"></core-user-avatar>
<ion-label><h2>{{ user.fullname }}</h2></ion-label> <ion-label><h2>{{ user.fullname }}</h2></ion-label>
</ion-item> </ion-item>
@ -225,8 +225,9 @@
<h2>{{ 'addon.mod_assign.currentgrade' | translate }}</h2> <h2>{{ 'addon.mod_assign.currentgrade' | translate }}</h2>
<p><core-format-text [text]="feedback!.gradefordisplay" [filter]="false"></core-format-text></p> <p><core-format-text [text]="feedback!.gradefordisplay" [filter]="false"></core-format-text></p>
</ion-label> </ion-label>
<ion-button slot="end" *ngIf="feedback!.advancedgrade" (click)="showAdvancedGrade()"> <ion-button slot="end" *ngIf="feedback!.advancedgrade" (click)="showAdvancedGrade()"
<ion-icon name="fas-search" slot="icon-only"></ion-icon> [attr.aria-label]="'core.showadvanced' |translate">
<ion-icon name="fas-search" slot="icon-only" aria-hidden="true"></ion-icon>
</ion-button> </ion-button>
</ion-item> </ion-item>
@ -328,7 +329,7 @@
<!-- Data about the grader (teacher who graded). --> <!-- Data about the grader (teacher who graded). -->
<ion-item class="ion-text-wrap" *ngIf="grader" core-user-link [userId]="grader!.id" [courseId]="courseId" <ion-item class="ion-text-wrap" *ngIf="grader" core-user-link [userId]="grader!.id" [courseId]="courseId"
[title]="grader!.fullname" detail="true"> [attr.aria-label]="grader!.fullname" detail="true">
<core-user-avatar [user]="grader" slot="start"></core-user-avatar> <core-user-avatar [user]="grader" slot="start"></core-user-avatar>
<ion-label> <ion-label>
<h2>{{ 'addon.mod_assign.gradedby' | translate }}</h2> <h2>{{ 'addon.mod_assign.gradedby' | translate }}</h2>
@ -348,12 +349,12 @@
<!-- Warning message if cannot save grades. --> <!-- Warning message if cannot save grades. -->
<ion-card *ngIf="isGrading && !canSaveGrades" class="core-warning-card"> <ion-card *ngIf="isGrading && !canSaveGrades" class="core-warning-card">
<ion-item> <ion-item>
<ion-icon name="fas-exclamation-triangle" slot="start"></ion-icon> <ion-icon name="fas-exclamation-triangle" slot="start" aria-hidden="true"></ion-icon>
<ion-label> <ion-label>
<p>{{ 'addon.mod_assign.cannotgradefromapp' | translate }}</p> <p>{{ 'addon.mod_assign.cannotgradefromapp' | translate }}</p>
<ion-button expand="block" *ngIf="gradeUrl" [href]="gradeUrl" core-link > <ion-button expand="block" *ngIf="gradeUrl" [href]="gradeUrl" core-link >
{{ 'core.openinbrowser' | translate }} {{ 'core.openinbrowser' | translate }}
<ion-icon name="fas-external-link-alt" slot="end"></ion-icon> <ion-icon name="fas-external-link-alt" slot="end" aria-hidden="true"></ion-icon>
</ion-button> </ion-button>
</ion-label> </ion-label>
</ion-item> </ion-item>

View File

@ -11,13 +11,13 @@
</ion-label> </ion-label>
<div slot="end"> <div slot="end">
<div class="ion-text-end"> <div class="ion-text-end">
<ion-button fill="clear" *ngIf="canEdit" (click)="editComment()" color="dark"> <ion-button fill="clear" *ngIf="canEdit" (click)="editComment()" color="dark"
<ion-icon name="fas-pen" slot="icon-only"></ion-icon> [attr.aria-label]="'core.edit' | translate">
<ion-icon name="fas-pen" slot="icon-only" aria-hidden="true"></ion-icon>
</ion-button> </ion-button>
</div> </div>
<ion-note *ngIf="!isSent" color="dark"> <ion-note *ngIf="!isSent" color="dark">
<ion-icon name="far-clock"></ion-icon> <ion-icon name="fas-clock" aria-hidden="true"></ion-icon> {{ 'core.notsent' | translate }}
{{ 'core.notsent' | translate }}
</ion-note> </ion-note>
</div> </div>
</ion-item> </ion-item>

View File

@ -1,7 +1,7 @@
<ion-header> <ion-header>
<ion-toolbar> <ion-toolbar>
<ion-buttons slot="start"> <ion-buttons slot="start">
<ion-back-button [attr.aria-label]="'core.back' | translate"></ion-back-button> <ion-back-button [text]="'core.back' | translate"></ion-back-button>
</ion-buttons> </ion-buttons>
<ion-title> <ion-title>
<core-format-text [text]="title" contextLevel="module" [contextInstanceId]="moduleId" [courseId]="courseId"> <core-format-text [text]="title" contextLevel="module" [contextInstanceId]="moduleId" [courseId]="courseId">

View File

@ -1,7 +1,7 @@
<ion-header> <ion-header>
<ion-toolbar> <ion-toolbar>
<ion-buttons slot="start"> <ion-buttons slot="start">
<ion-back-button [attr.aria-label]="'core.back' | translate"></ion-back-button> <ion-back-button [text]="'core.back' | translate"></ion-back-button>
</ion-buttons> </ion-buttons>
<ion-title> <ion-title>
<core-format-text [text]="title" contextLevel="module" [contextInstanceId]="module?.id" [courseId]="courseId"> <core-format-text [text]="title" contextLevel="module" [contextInstanceId]="module?.id" [courseId]="courseId">

View File

@ -1,7 +1,7 @@
<ion-header> <ion-header>
<ion-toolbar> <ion-toolbar>
<ion-buttons slot="start"> <ion-buttons slot="start">
<ion-back-button [attr.aria-label]="'core.back' | translate"></ion-back-button> <ion-back-button [text]="'core.back' | translate"></ion-back-button>
</ion-buttons> </ion-buttons>
<ion-title> <ion-title>
<core-format-text [text]="title" contextLevel="module" [contextInstanceId]="moduleId" [courseId]="courseId"> <core-format-text [text]="title" contextLevel="module" [contextInstanceId]="moduleId" [courseId]="courseId">
@ -39,8 +39,8 @@
</ion-item> </ion-item>
<!-- List of submissions. --> <!-- List of submissions. -->
<ng-container *ngFor="let submission of submissions.items"> <ng-container *ngFor="let submission of submissions.items">
<ion-item class="ion-text-wrap" (click)="submissions.select(submission)" <ion-item class="ion-text-wrap" (click)="submissions.select(submission)" button
[class.core-selected-item]="submissions.isSelected(submission)"> [attr.aria-current]="submissions.getItemAriaCurrent(submission)">
<core-user-avatar [user]="submission" [linkProfile]="false" slot="start"></core-user-avatar> <core-user-avatar [user]="submission" [linkProfile]="false" slot="start"></core-user-avatar>
<ion-label> <ion-label>
<h2 *ngIf="submission.userfullname">{{submission.userfullname}}</h2> <h2 *ngIf="submission.userfullname">{{submission.userfullname}}</h2>
@ -75,7 +75,7 @@
<ion-card class="ion-text-wrap core-warning-card" *ngIf="!haveAllParticipants"> <ion-card class="ion-text-wrap core-warning-card" *ngIf="!haveAllParticipants">
<ion-item> <ion-item>
<ion-icon name="fas-exclamation-triangle" slot="start"></ion-icon> <ion-icon name="fas-exclamation-triangle" slot="start" aria-hidden="true"></ion-icon>
<ion-label>{{ 'addon.mod_assign.notallparticipantsareshown' | translate }}</ion-label> <ion-label>{{ 'addon.mod_assign.notallparticipantsareshown' | translate }}</ion-label>
</ion-item> </ion-item>
</ion-card> </ion-card>

View File

@ -1,7 +1,7 @@
<ion-header> <ion-header>
<ion-toolbar> <ion-toolbar>
<ion-buttons slot="start"> <ion-buttons slot="start">
<ion-back-button [attr.aria-label]="'core.back' | translate"></ion-back-button> <ion-back-button [text]="'core.back' | translate"></ion-back-button>
</ion-buttons> </ion-buttons>
<ion-title> <ion-title>
<core-format-text [text]="title" contextLevel="module" [contextInstanceId]="moduleId" [courseId]="courseId"> <core-format-text [text]="title" contextLevel="module" [contextInstanceId]="moduleId" [courseId]="courseId">

View File

@ -1,4 +1,4 @@
<ion-item *ngIf="commentsEnabled" class="ion-text-wrap" (click)="showComments($event)" detail="false"> <ion-item *ngIf="commentsEnabled" class="ion-text-wrap" (click)="showComments($event)" detail="false" button>
<ion-label> <ion-label>
<h2>{{plugin.name}}</h2> <h2>{{plugin.name}}</h2>
<core-comments contextLevel="module" [instanceId]="assign.cmid" component="assignsubmission_comments" <core-comments contextLevel="module" [instanceId]="assign.cmid" component="assignsubmission_comments"

View File

@ -1,7 +1,7 @@
<!-- Buttons to add to the header. --> <!-- Buttons to add to the header. -->
<core-navbar-buttons slot="end"> <core-navbar-buttons slot="end">
<ion-button (click)="showToc()" [attr.aria-label]="'addon.mod_book.toc' | translate" aria-haspopup="true" *ngIf="loaded"> <ion-button (click)="showToc()" [attr.aria-label]="'addon.mod_book.toc' | translate" aria-haspopup="true" *ngIf="loaded">
<ion-icon name="fas-bookmark" slot="icon-only"></ion-icon> <ion-icon name="fas-bookmark" slot="icon-only" aria-hidden="true"></ion-icon>
</ion-button> </ion-button>
<core-context-menu> <core-context-menu>
<core-context-menu-item *ngIf="externalUrl" [priority]="900" [content]="'core.openinbrowser' | translate" <core-context-menu-item *ngIf="externalUrl" [priority]="900" [content]="'core.openinbrowser' | translate"
@ -27,8 +27,10 @@
contextLevel="module" [contextInstanceId]="module.id" [courseId]="courseId"></core-course-module-description> contextLevel="module" [contextInstanceId]="module.id" [courseId]="courseId"></core-course-module-description>
<ion-card class="core-warning-card" *ngIf="warning"> <ion-card class="core-warning-card" *ngIf="warning">
<ion-icon name="fas-exclamation-triangle" slot="start"></ion-icon> <ion-item>
<span [innerHTML]="warning"></span> <ion-icon name="fas-exclamation-triangle" slot="start" aria-hidden="true"></ion-icon>
<ion-label><span [innerHTML]="warning"></span></ion-label>
</ion-item>
</ion-card> </ion-card>
<div class="ion-padding safe-padding-horizontal"> <div class="ion-padding safe-padding-horizontal">

View File

@ -3,7 +3,7 @@
<ion-title>{{ 'addon.mod_book.toc' | translate }}</ion-title> <ion-title>{{ 'addon.mod_book.toc' | translate }}</ion-title>
<ion-buttons slot="end"> <ion-buttons slot="end">
<ion-button (click)="closeModal()" [attr.aria-label]="'core.close' | translate"> <ion-button (click)="closeModal()" [attr.aria-label]="'core.close' | translate">
<ion-icon name="fas-times" slot="icon-only"></ion-icon> <ion-icon name="fas-times" slot="icon-only" aria-hidden=true></ion-icon>
</ion-button> </ion-button>
</ion-buttons> </ion-buttons>
</ion-toolbar> </ion-toolbar>
@ -12,7 +12,7 @@
<nav> <nav>
<ion-list> <ion-list>
<ion-item class="ion-text-wrap" *ngFor="let chapter of chapters" (click)="loadChapter(chapter.id)" <ion-item class="ion-text-wrap" *ngFor="let chapter of chapters" (click)="loadChapter(chapter.id)"
[class.core-selected-item]="selected == chapter.id" [attr.aria-current]="selected == chapter.id ? 'page' : 'false'" button
[class.item-dimmed]="chapter.hidden"> [class.item-dimmed]="chapter.hidden">
<ion-label> <ion-label>
<p [class.ion-padding-left]="addPadding && chapter.level == 1 ? true : null"> <p [class.ion-padding-left]="addPadding && chapter.level == 1 ? true : null">

View File

@ -1,7 +1,7 @@
<ion-header> <ion-header>
<ion-toolbar> <ion-toolbar>
<ion-buttons slot="start"> <ion-buttons slot="start">
<ion-back-button [attr.aria-label]="'core.back' | translate"></ion-back-button> <ion-back-button [text]="'core.back' | translate"></ion-back-button>
</ion-buttons> </ion-buttons>
<ion-title> <ion-title>
<core-format-text [text]="title" contextLevel="module" [contextInstanceId]="module?.id" [courseId]="courseId"> <core-format-text [text]="title" contextLevel="module" [contextInstanceId]="module?.id" [courseId]="courseId">

View File

@ -32,7 +32,7 @@
<ion-card *ngIf="chatInfo" class="core-info-card"> <ion-card *ngIf="chatInfo" class="core-info-card">
<ion-item> <ion-item>
<ion-icon name="fas-clock" slot="start"></ion-icon> <ion-icon name="fas-clock" slot="start" aria-hidden="true"></ion-icon>
<ion-label>{{ 'addon.mod_chat.sessionstart' | translate:{$a: chatInfo} }}</ion-label> <ion-label>{{ 'addon.mod_chat.sessionstart' | translate:{$a: chatInfo} }}</ion-label>
</ion-item> </ion-item>
</ion-card> </ion-card>

View File

@ -1,12 +1,12 @@
<ion-header> <ion-header>
<ion-toolbar> <ion-toolbar>
<ion-buttons slot="start"> <ion-buttons slot="start">
<ion-back-button [attr.aria-label]="'core.back' | translate"></ion-back-button> <ion-back-button [text]="'core.back' | translate"></ion-back-button>
</ion-buttons> </ion-buttons>
<ion-title>{{ 'addon.mod_chat.currentusers' | translate }}</ion-title> <ion-title>{{ 'addon.mod_chat.currentusers' | translate }}</ion-title>
<ion-buttons slot="end"> <ion-buttons slot="end">
<ion-button (click)="closeModal()" [attr.aria-label]="'core.close' | translate"> <ion-button (click)="closeModal()" [attr.aria-label]="'core.close' | translate">
<ion-icon slot="icon-only" name="fas-times"></ion-icon> <ion-icon slot="icon-only" name="fas-times" aria-hidden="true"></ion-icon>
</ion-button> </ion-button>
</ion-buttons> </ion-buttons>
</ion-toolbar> </ion-toolbar>
@ -21,11 +21,11 @@
<h2>{{ user.fullname }}</h2> <h2>{{ user.fullname }}</h2>
<ng-container *ngIf="currentUserId != user.id && isOnline"> <ng-container *ngIf="currentUserId != user.id && isOnline">
<ion-button fill="clear" (click)="talkTo(user)"> <ion-button fill="clear" (click)="talkTo(user)">
<ion-icon name="fas-comments" slot="start"></ion-icon> <ion-icon name="fas-comments" slot="start" aria-hidden="true"></ion-icon>
{{ 'addon.mod_chat.talk' | translate }} {{ 'addon.mod_chat.talk' | translate }}
</ion-button> </ion-button>
<ion-button fill="clear" (click)="beepTo(user)"> <ion-button fill="clear" (click)="beepTo(user)">
<ion-icon name="fas-bell" slot="start"></ion-icon> <ion-icon name="fas-bell" slot="start" aria-hidden="true"></ion-icon>
{{ 'addon.mod_chat.beep' | translate }} {{ 'addon.mod_chat.beep' | translate }}
</ion-button> </ion-button>
</ng-container> </ng-container>

View File

@ -1,7 +1,7 @@
<ion-header> <ion-header>
<ion-toolbar> <ion-toolbar>
<ion-buttons slot="start"> <ion-buttons slot="start">
<ion-back-button [attr.aria-label]="'core.back' | translate"></ion-back-button> <ion-back-button [text]="'core.back' | translate"></ion-back-button>
</ion-buttons> </ion-buttons>
<ion-title> <ion-title>
<core-format-text [text]="title" contextLevel="module" [contextInstanceId]="cmId" [courseId]="courseId"> <core-format-text [text]="title" contextLevel="module" [contextInstanceId]="cmId" [courseId]="courseId">
@ -9,7 +9,7 @@
</ion-title> </ion-title>
<ion-buttons slot="end"> <ion-buttons slot="end">
<ion-button *ngIf="loaded" (click)="showChatUsers()" [attr.aria-label]="'core.users' | translate"> <ion-button *ngIf="loaded" (click)="showChatUsers()" [attr.aria-label]="'core.users' | translate">
<ion-icon name="fas-users" slot="icon-only"></ion-icon> <ion-icon name="fas-users" slot="icon-only" aria-hidden="true"></ion-icon>
</ion-button> </ion-button>
</ion-buttons> </ion-buttons>
</ion-toolbar> </ion-toolbar>
@ -26,7 +26,7 @@
<div class="ion-text-center addon-mod_chat-notice" *ngIf="message.special"> <div class="ion-text-center addon-mod_chat-notice" *ngIf="message.special">
<ion-badge class="ion-text-wrap" color="success" *ngIf="message.system && message.message == 'enter'"> <ion-badge class="ion-text-wrap" color="success" *ngIf="message.system && message.message == 'enter'">
<span> <span>
<ion-icon name="fas-sign-in-alt"></ion-icon> <ion-icon name="fas-sign-in-alt" aria-hidden="true"></ion-icon>
{{ message.timestamp * 1000 | coreFormatDate:"strftimetime" }} {{ message.timestamp * 1000 | coreFormatDate:"strftimetime" }}
{{ 'addon.mod_chat.messageenter' | translate:{$a: message.userfullname} }} {{ 'addon.mod_chat.messageenter' | translate:{$a: message.userfullname} }}
</span> </span>
@ -34,7 +34,7 @@
<ion-badge class="ion-text-wrap" color="danger" *ngIf="message.system && message.message == 'exit'"> <ion-badge class="ion-text-wrap" color="danger" *ngIf="message.system && message.message == 'exit'">
<span> <span>
<ion-icon name="fas-sign-out-alt"></ion-icon> <ion-icon name="fas-sign-out-alt" aria-hidden="true"></ion-icon>
{{ message.timestamp * 1000 | coreFormatDate:"strftimetime" }} {{ message.timestamp * 1000 | coreFormatDate:"strftimetime" }}
{{ 'addon.mod_chat.messageexit' | translate:{$a: message.userfullname} }} {{ 'addon.mod_chat.messageexit' | translate:{$a: message.userfullname} }}
</span> </span>
@ -42,7 +42,7 @@
<ion-badge class="ion-text-wrap" color="primary" *ngIf="message.beep == 'all'"> <ion-badge class="ion-text-wrap" color="primary" *ngIf="message.beep == 'all'">
<span> <span>
<ion-icon name="fas-bell"></ion-icon> <ion-icon name="fas-bell" aria-hidden="true"></ion-icon>
{{ message.timestamp * 1000 | coreFormatDate:"strftimetime" }} {{ message.timestamp * 1000 | coreFormatDate:"strftimetime" }}
{{ 'addon.mod_chat.messagebeepseveryone' | translate:{$a: message.userfullname} }} {{ 'addon.mod_chat.messagebeepseveryone' | translate:{$a: message.userfullname} }}
</span> </span>
@ -51,7 +51,7 @@
<ion-badge class="ion-text-wrap" color="primary" <ion-badge class="ion-text-wrap" color="primary"
*ngIf="message.userid != currentUserId && message.beep == currentUserId"> *ngIf="message.userid != currentUserId && message.beep == currentUserId">
<span> <span>
<ion-icon name="fas-bell"></ion-icon> <ion-icon name="fas-bell" aria-hidden="true"></ion-icon>
{{ message.timestamp * 1000 | coreFormatDate:"strftimetime" }} {{ message.timestamp * 1000 | coreFormatDate:"strftimetime" }}
{{ 'addon.mod_chat.messagebeepsyou' | translate:{$a: message.userfullname} }} {{ 'addon.mod_chat.messagebeepsyou' | translate:{$a: message.userfullname} }}
</span> </span>
@ -60,7 +60,7 @@
<ion-badge class="ion-text-wrap" color="light" <ion-badge class="ion-text-wrap" color="light"
*ngIf="message.userid == currentUserId && message.beep && message.beep != 'all'"> *ngIf="message.userid == currentUserId && message.beep && message.beep != 'all'">
<span> <span>
<ion-icon name="fas-bell"></ion-icon> <ion-icon name="fas-bell" aria-hidden="true"></ion-icon>
{{ message.timestamp * 1000 | coreFormatDate:"strftimetime" }} {{ message.timestamp * 1000 | coreFormatDate:"strftimetime" }}
{{ 'addon.mod_chat.messageyoubeep' | translate:{$a: message.beepWho} }} {{ 'addon.mod_chat.messageyoubeep' | translate:{$a: message.beepWho} }}
</span> </span>
@ -68,7 +68,7 @@
<ion-badge class="ion-text-wrap" color="info" *ngIf="!message.system && !message.beep"> <ion-badge class="ion-text-wrap" color="info" *ngIf="!message.system && !message.beep">
<span> <span>
<ion-icon name="fas-asterisk"></ion-icon> <ion-icon name="fas-asterisk" aria-hidden="true"></ion-icon>
{{ message.timestamp * 1000 | coreFormatDate:"strftimetime" }} {{ message.timestamp * 1000 | coreFormatDate:"strftimetime" }}
<strong> <strong>
{{ message.userfullname }} <core-format-text [text]="message.message" contextLevel="module" {{ message.userfullname }} <core-format-text [text]="message.message" contextLevel="module"

View File

@ -1,7 +1,7 @@
<ion-header> <ion-header>
<ion-toolbar> <ion-toolbar>
<ion-buttons slot="start"> <ion-buttons slot="start">
<ion-back-button [attr.aria-label]="'core.back' | translate"></ion-back-button> <ion-back-button [text]="'core.back' | translate"></ion-back-button>
</ion-buttons> </ion-buttons>
<ion-title> <ion-title>
<core-format-text [text]="title" contextLevel="module" [contextInstanceId]="module?.id" [courseId]="courseId"> <core-format-text [text]="title" contextLevel="module" [contextInstanceId]="module?.id" [courseId]="courseId">

View File

@ -1,7 +1,7 @@
<ion-header> <ion-header>
<ion-toolbar> <ion-toolbar>
<ion-buttons slot="start"> <ion-buttons slot="start">
<ion-back-button [attr.aria-label]="'core.back' | translate"></ion-back-button> <ion-back-button [text]="'core.back' | translate"></ion-back-button>
</ion-buttons> </ion-buttons>
<ion-title>{{ 'addon.mod_chat.messages' | translate }}</ion-title> <ion-title>{{ 'addon.mod_chat.messages' | translate }}</ion-title>
</ion-toolbar> </ion-toolbar>
@ -21,7 +21,7 @@
<div class="ion-text-center addon-mod_chat-notice" *ngIf="message.special"> <div class="ion-text-center addon-mod_chat-notice" *ngIf="message.special">
<ion-badge class="ion-text-wrap" color="success" *ngIf="message.issystem && message.message == 'enter'"> <ion-badge class="ion-text-wrap" color="success" *ngIf="message.issystem && message.message == 'enter'">
<span> <span>
<ion-icon name="fas-sign-in-alt"></ion-icon> <ion-icon name="fas-sign-in-alt" aria-hidden="true"></ion-icon>
{{ message.timestamp * 1000 | coreFormatDate:"strftimetime" }} {{ message.timestamp * 1000 | coreFormatDate:"strftimetime" }}
{{ 'addon.mod_chat.messageenter' | translate:{$a: message.userfullname} }} {{ 'addon.mod_chat.messageenter' | translate:{$a: message.userfullname} }}
</span> </span>
@ -29,7 +29,7 @@
<ion-badge class="ion-text-wrap" color="danger" *ngIf="message.issystem && message.message == 'exit'"> <ion-badge class="ion-text-wrap" color="danger" *ngIf="message.issystem && message.message == 'exit'">
<span> <span>
<ion-icon name="fas-sign-out-alt"></ion-icon> <ion-icon name="fas-sign-out-alt" aria-hidden="true"></ion-icon>
{{ message.timestamp * 1000 | coreFormatDate:"strftimetime" }} {{ message.timestamp * 1000 | coreFormatDate:"strftimetime" }}
{{ 'addon.mod_chat.messageexit' | translate:{$a: message.userfullname} }} {{ 'addon.mod_chat.messageexit' | translate:{$a: message.userfullname} }}
</span> </span>
@ -37,7 +37,7 @@
<ion-badge class="ion-text-wrap" color="primary" *ngIf="message.beep == 'all'"> <ion-badge class="ion-text-wrap" color="primary" *ngIf="message.beep == 'all'">
<span> <span>
<ion-icon name="fas-bell"></ion-icon> <ion-icon name="fas-bell" aria-hidden="true"></ion-icon>
{{ message.timestamp * 1000 | coreFormatDate:"strftimetime" }} {{ message.timestamp * 1000 | coreFormatDate:"strftimetime" }}
{{ 'addon.mod_chat.messagebeepseveryone' | translate:{$a: message.userfullname} }} {{ 'addon.mod_chat.messagebeepseveryone' | translate:{$a: message.userfullname} }}
</span> </span>
@ -46,7 +46,7 @@
<ion-badge class="ion-text-wrap" color="primary" <ion-badge class="ion-text-wrap" color="primary"
*ngIf="message.userid != currentUserId && message.beep == currentUserId"> *ngIf="message.userid != currentUserId && message.beep == currentUserId">
<span> <span>
<ion-icon name="fas-bell"></ion-icon> <ion-icon name="fas-bell" aria-hidden="true"></ion-icon>
{{ message.timestamp * 1000 | coreFormatDate:"strftimetime" }} {{ message.timestamp * 1000 | coreFormatDate:"strftimetime" }}
{{ 'addon.mod_chat.messagebeepsyou' | translate:{$a: message.userfullname} }} {{ 'addon.mod_chat.messagebeepsyou' | translate:{$a: message.userfullname} }}
</span> </span>
@ -55,7 +55,7 @@
<ion-badge class="ion-text-wrap" color="light" <ion-badge class="ion-text-wrap" color="light"
*ngIf="message.userid == currentUserId && message.beep && message.beep != 'all'"> *ngIf="message.userid == currentUserId && message.beep && message.beep != 'all'">
<span> <span>
<ion-icon name="fas-bell"></ion-icon> <ion-icon name="fas-bell" aria-hidden="true"></ion-icon>
{{ message.timestamp * 1000 | coreFormatDate:"strftimetime" }} {{ message.timestamp * 1000 | coreFormatDate:"strftimetime" }}
{{ 'addon.mod_chat.messageyoubeep' | translate:{$a: message.beepWho} }} {{ 'addon.mod_chat.messageyoubeep' | translate:{$a: message.beepWho} }}
</span> </span>
@ -63,7 +63,7 @@
<ion-badge class="ion-text-wrap" color="info" *ngIf="!message.issystem && !message.beep"> <ion-badge class="ion-text-wrap" color="info" *ngIf="!message.issystem && !message.beep">
<span> <span>
<ion-icon name="fas-asterisk"></ion-icon> <ion-icon name="fas-asterisk" aria-hidden="true"></ion-icon>
{{ message.timestamp * 1000 | coreFormatDate:"strftimetime" }} {{ message.timestamp * 1000 | coreFormatDate:"strftimetime" }}
<strong> <strong>
{{ message.userfullname }} <core-format-text [text]="message.message" contextLevel="module" {{ message.userfullname }} <core-format-text [text]="message.message" contextLevel="module"

View File

@ -1,7 +1,7 @@
<ion-header> <ion-header>
<ion-toolbar> <ion-toolbar>
<ion-buttons slot="start"> <ion-buttons slot="start">
<ion-back-button [attr.aria-label]="'core.back' | translate"></ion-back-button> <ion-back-button [text]="'core.back' | translate"></ion-back-button>
</ion-buttons> </ion-buttons>
<ion-title>{{ 'addon.mod_chat.chatreport' | translate }}</ion-title> <ion-title>{{ 'addon.mod_chat.chatreport' | translate }}</ion-title>
</ion-toolbar> </ion-toolbar>
@ -31,7 +31,7 @@
</ion-item> </ion-item>
<ion-card *ngFor="let session of sessions.items" (click)="sessions.select(session)" <ion-card *ngFor="let session of sessions.items" (click)="sessions.select(session)"
[class.core-selected-item]="sessions.isSelected(session)" [attr.aria-current]="sessions.getItemAriaCurrent(session)"
[class.addon-mod-chat-session-show-more]="session.sessionusers.length < session.allsessionusers.length"> [class.addon-mod-chat-session-show-more]="session.sessionusers.length < session.allsessionusers.length">
<ion-item class="ion-text-wrap"> <ion-item class="ion-text-wrap">

View File

@ -35,7 +35,7 @@
<!-- Activity availability messages --> <!-- Activity availability messages -->
<ion-card class="core-info-card" *ngIf="choiceNotOpenYet"> <ion-card class="core-info-card" *ngIf="choiceNotOpenYet">
<ion-item> <ion-item>
<ion-icon name="fas-info-circle" slot="start"></ion-icon> <ion-icon name="fas-info-circle" slot="start" aria-hidden="true"></ion-icon>
<ion-label> <ion-label>
<p *ngIf="options.length">{{ 'addon.mod_choice.previewonly' | translate:{$a: openTimeReadable} }}</p> <p *ngIf="options.length">{{ 'addon.mod_choice.previewonly' | translate:{$a: openTimeReadable} }}</p>
<p *ngIf="!options.length">{{ 'addon.mod_choice.notopenyet' | translate:{$a: openTimeReadable} }}</p> <p *ngIf="!options.length">{{ 'addon.mod_choice.notopenyet' | translate:{$a: openTimeReadable} }}</p>
@ -45,7 +45,7 @@
<ion-card class="core-info-card" *ngIf="choiceClosed"> <ion-card class="core-info-card" *ngIf="choiceClosed">
<ion-item> <ion-item>
<ion-icon name="fas-info-circle" slot="start"></ion-icon> <ion-icon name="fas-info-circle" slot="start" aria-hidden="true"></ion-icon>
<ion-label> <ion-label>
<p *ngIf="options.length"> <p *ngIf="options.length">
{{ 'addon.mod_choice.yourselection' | translate }} {{ 'addon.mod_choice.yourselection' | translate }}
@ -61,7 +61,7 @@
<!-- Choice done in offline but not synchronized --> <!-- Choice done in offline but not synchronized -->
<ion-card class="core-warning-card" *ngIf="hasOffline"> <ion-card class="core-warning-card" *ngIf="hasOffline">
<ion-item> <ion-item>
<ion-icon name="fas-exclamation-triangle" slot="start"></ion-icon> <ion-icon name="fas-exclamation-triangle" slot="start" aria-hidden="true"></ion-icon>
<ion-label>{{ 'core.hasdatatosync' | translate:{$a: moduleName} }}</ion-label> <ion-label>{{ 'core.hasdatatosync' | translate:{$a: moduleName} }}</ion-label>
</ion-item> </ion-item>
</ion-card> </ion-card>
@ -69,7 +69,7 @@
<!-- Inform what will happen with the choices. --> <!-- Inform what will happen with the choices. -->
<ion-card class="core-info-card" *ngIf="canEdit && publishInfo && options.length"> <ion-card class="core-info-card" *ngIf="canEdit && publishInfo && options.length">
<ion-item> <ion-item>
<ion-icon name="fas-info-circle" slot="start"></ion-icon> <ion-icon name="fas-info-circle" slot="start" aria-hidden="true"></ion-icon>
<ion-label>{{ publishInfo | translate }}</ion-label> <ion-label>{{ publishInfo | translate }}</ion-label>
</ion-item> </ion-item>
</ion-card> </ion-card>
@ -111,7 +111,7 @@
<ion-row> <ion-row>
<ion-col size="12" size-lg="5"> <ion-col size="12" size-lg="5">
<ion-item class="ion-text-wrap core-warning-item" *ngIf="hasOffline"> <ion-item class="ion-text-wrap core-warning-item" *ngIf="hasOffline">
<ion-icon slot="start" name="fas-exclamation-triangle" color="warning"></ion-icon> <ion-icon slot="start" name="fas-exclamation-triangle" color="warning" aria-hidden="true"></ion-icon>
<ion-label>{{ 'addon.mod_choice.resultsnotsynced' | translate }}</ion-label> <ion-label>{{ 'addon.mod_choice.resultsnotsynced' | translate }}</ion-label>
</ion-item> </ion-item>
<ion-item> <ion-item>
@ -141,7 +141,7 @@
</ion-label> </ion-label>
</ion-item-divider> </ion-item-divider>
<ion-item *ngFor="let user of result.userresponses" core-user-link [courseId]="courseId" <ion-item *ngFor="let user of result.userresponses" core-user-link [courseId]="courseId"
[userId]="user.userid" [title]="user.fullname" class="ion-text-wrap"> [userId]="user.userid" [attr.aria-label]="user.fullname" class="ion-text-wrap">
<core-user-avatar [user]="user" slot="start" [courseId]="courseId"></core-user-avatar> <core-user-avatar [user]="user" slot="start" [courseId]="courseId"></core-user-avatar>
<ion-label><p>{{user.fullname}}</p></ion-label> <ion-label><p>{{user.fullname}}</p></ion-label>
</ion-item> </ion-item>
@ -153,7 +153,7 @@
<ion-card class="core-info-card" *ngIf="!canSeeResults && !choiceNotOpenYet"> <ion-card class="core-info-card" *ngIf="!canSeeResults && !choiceNotOpenYet">
<ion-item> <ion-item>
<ion-icon name="fas-info-circle" slot="start"></ion-icon> <ion-icon name="fas-info-circle" slot="start" aria-hidden="true"></ion-icon>
<ion-label><p>{{ 'addon.mod_choice.noresultsviewable' | translate }}</p></ion-label> <ion-label><p>{{ 'addon.mod_choice.noresultsviewable' | translate }}</p></ion-label>
</ion-item> </ion-item>
</ion-card> </ion-card>

View File

@ -1,7 +1,7 @@
<ion-header> <ion-header>
<ion-toolbar> <ion-toolbar>
<ion-buttons slot="start"> <ion-buttons slot="start">
<ion-back-button [attr.aria-label]="'core.back' | translate"></ion-back-button> <ion-back-button [text]="'core.back' | translate"></ion-back-button>
</ion-buttons> </ion-buttons>
<ion-title> <ion-title>
<core-format-text [text]="title" contextLevel="module" [contextInstanceId]="module?.id" [courseId]="courseId"> <core-format-text [text]="title" contextLevel="module" [contextInstanceId]="module?.id" [courseId]="courseId">

View File

@ -1,26 +1,26 @@
<ion-button *ngIf="action == 'more'" fill="clear" (click)="viewEntry()" [title]="'addon.mod_data.more' | translate"> <ion-button *ngIf="action == 'more'" fill="clear" (click)="viewEntry()" [attr.aria-label]="'addon.mod_data.more' | translate">
<ion-icon name="fas-search" slot="icon-only"></ion-icon> <ion-icon name="fas-search" slot="icon-only" aria-hidden="true"></ion-icon>
</ion-button> </ion-button>
<ion-button *ngIf="action == 'edit'" fill="clear" (click)="editEntry()" [title]="'core.edit' | translate"> <ion-button *ngIf="action == 'edit'" fill="clear" (click)="editEntry()" [attr.aria-label]="'core.edit' | translate">
<ion-icon name="fas-cog" slot="icon-only"></ion-icon> <ion-icon name="fas-cog" slot="icon-only" aria-hidden="true"></ion-icon>
</ion-button> </ion-button>
<ion-button *ngIf="action == 'delete' && !entry.deleted" fill="clear" (click)="deleteEntry()" [title]="'core.delete' | translate"> <ion-button *ngIf="action == 'delete' && !entry.deleted" fill="clear" (click)="deleteEntry()" [attr.aria-label]="'core.delete' | translate">
<ion-icon name="fas-trash" slot="icon-only"></ion-icon> <ion-icon name="fas-trash" slot="icon-only" aria-hidden="true"></ion-icon>
</ion-button> </ion-button>
<ion-button *ngIf="action == 'delete' && entry.deleted" fill="clear" (click)="undoDelete()" [title]="'core.restore' | translate"> <ion-button *ngIf="action == 'delete' && entry.deleted" fill="clear" (click)="undoDelete()" [attr.aria-label]="'core.restore' | translate">
<ion-icon name="fas-undo-alt" slot="icon-only"></ion-icon> <ion-icon name="fas-undo-alt" slot="icon-only" aria-hidden="true"></ion-icon>
</ion-button> </ion-button>
<ion-button *ngIf="action == 'approve'" fill="clear" (click)="approveEntry()" [title]="'addon.mod_data.approve' | translate"> <ion-button *ngIf="action == 'approve'" fill="clear" (click)="approveEntry()" [attr.aria-label]="'addon.mod_data.approve' | translate">
<ion-icon name="fas-thumbs-up" slot="icon-only"></ion-icon> <ion-icon name="fas-thumbs-up" slot="icon-only" aria-hidden="true"></ion-icon>
</ion-button> </ion-button>
<ion-button *ngIf="action == 'disapprove'" fill="clear" (click)="disapproveEntry()" <ion-button *ngIf="action == 'disapprove'" fill="clear" (click)="disapproveEntry()"
[title]="'addon.mod_data.disapprove' | translate"> [attr.aria-label]="'addon.mod_data.disapprove' | translate">
<ion-icon name="far-thumbs-down" slot="icon-only"></ion-icon> <ion-icon name="far-thumbs-down" slot="icon-only" aria-hidden="true"></ion-icon>
</ion-button> </ion-button>
<core-comments *ngIf="action == 'comments' && mode == 'list'" contextLevel="module" [instanceId]="database.coursemodule" <core-comments *ngIf="action == 'comments' && mode == 'list'" contextLevel="module" [instanceId]="database.coursemodule"
@ -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

@ -1,7 +1,7 @@
<!-- Buttons to add to the header. --> <!-- Buttons to add to the header. -->
<core-navbar-buttons slot="end"> <core-navbar-buttons slot="end">
<ion-button *ngIf="canSearch" (click)="showSearch()" [attr.aria-label]="'addon.mod_data.search' | translate"> <ion-button *ngIf="canSearch" (click)="showSearch()" [attr.aria-label]="'addon.mod_data.search' | translate">
<ion-icon name="fas-search" slot="icon-only"></ion-icon> <ion-icon name="fas-search" slot="icon-only" aria-hidden="true"></ion-icon>
</ion-button> </ion-button>
<core-context-menu> <core-context-menu>
<core-context-menu-item *ngIf="externalUrl" [priority]="900" [content]="'core.openinbrowser' | translate" <core-context-menu-item *ngIf="externalUrl" [priority]="900" [content]="'core.openinbrowser' | translate"
@ -46,7 +46,7 @@
<!-- Data done in offline but not synchronized --> <!-- Data done in offline but not synchronized -->
<ion-card class="core-warning-card" *ngIf="hasOffline || hasOfflineRatings"> <ion-card class="core-warning-card" *ngIf="hasOffline || hasOfflineRatings">
<ion-item> <ion-item>
<ion-icon name="fas-exclamation-triangle" slot="start"></ion-icon> <ion-icon name="fas-exclamation-triangle" slot="start" aria-hidden="true"></ion-icon>
<ion-label>{{ 'core.hasdatatosync' | translate: {$a: moduleName} }}</ion-label> <ion-label>{{ 'core.hasdatatosync' | translate: {$a: moduleName} }}</ion-label>
</ion-item> </ion-item>
</ion-card> </ion-card>
@ -66,21 +66,21 @@
<ion-card class="core-info-card" *ngIf="!access?.timeavailable && timeAvailableFrom"> <ion-card class="core-info-card" *ngIf="!access?.timeavailable && timeAvailableFrom">
<ion-item> <ion-item>
<ion-icon name="fas-info-circle" slot="start"></ion-icon> <ion-icon name="fas-info-circle" slot="start" aria-hidden="true"></ion-icon>
<ion-label>{{ 'addon.mod_data.notopenyet' | translate:{$a: timeAvailableFromReadable} }}</ion-label> <ion-label>{{ 'addon.mod_data.notopenyet' | translate:{$a: timeAvailableFromReadable} }}</ion-label>
</ion-item> </ion-item>
</ion-card> </ion-card>
<ion-card class="core-info-card" *ngIf="!access?.timeavailable && timeAvailableTo"> <ion-card class="core-info-card" *ngIf="!access?.timeavailable && timeAvailableTo">
<ion-item> <ion-item>
<ion-icon name="fas-info-circle" slot="start"></ion-icon> <ion-icon name="fas-info-circle" slot="start" aria-hidden="true"></ion-icon>
<ion-label>{{ 'addon.mod_data.expired' | translate:{$a: timeAvailableToReadable} }}</ion-label> <ion-label>{{ 'addon.mod_data.expired' | translate:{$a: timeAvailableToReadable} }}</ion-label>
</ion-item> </ion-item>
</ion-card> </ion-card>
<ion-card class="core-info-card" *ngIf="access && access.entrieslefttoview">> <ion-card class="core-info-card" *ngIf="access && access.entrieslefttoview">>
<ion-item> <ion-item>
<ion-icon name="fas-info-circle" slot="start"></ion-icon> <ion-icon name="fas-info-circle" slot="start" aria-hidden="true"></ion-icon>
<ion-label> <ion-label>
{{ 'addon.mod_data.entrieslefttoaddtoview' | translate:{$a: {entrieslefttoview: access.entrieslefttoview} } }} {{ 'addon.mod_data.entrieslefttoaddtoview' | translate:{$a: {entrieslefttoview: access.entrieslefttoview} } }}
</ion-label> </ion-label>
@ -89,7 +89,7 @@
<ion-card class="core-info-card" *ngIf="access && access.entrieslefttoadd">> <ion-card class="core-info-card" *ngIf="access && access.entrieslefttoadd">>
<ion-item> <ion-item>
<ion-icon name="fas-info-circle" slot="start"></ion-icon> <ion-icon name="fas-info-circle" slot="start" aria-hidden="true"></ion-icon>
<ion-label> <ion-label>
{{ 'addon.mod_data.entrieslefttoadd' | translate:{$a: {entriesleft: access.entrieslefttoadd} } }} {{ 'addon.mod_data.entrieslefttoadd' | translate:{$a: {entriesleft: access.entrieslefttoadd} } }}
</ion-label> </ion-label>
@ -121,14 +121,14 @@
<ion-row class="ion-align-items-center"> <ion-row class="ion-align-items-center">
<ion-col *ngIf="search.page > 0"> <ion-col *ngIf="search.page > 0">
<ion-button expand="block" fill="outline" (click)="searchEntries(search.page - 1)"> <ion-button expand="block" fill="outline" (click)="searchEntries(search.page - 1)">
<ion-icon name="fas-chevron-left" slot="start"></ion-icon> <ion-icon name="fas-chevron-left" slot="start" aria-hidden="true"></ion-icon>
{{ 'core.previous' | translate }} {{ 'core.previous' | translate }}
</ion-button> </ion-button>
</ion-col> </ion-col>
<ion-col *ngIf="hasNextPage"> <ion-col *ngIf="hasNextPage">
<ion-button expand="block" (click)="searchEntries(search.page + 1)"> <ion-button expand="block" (click)="searchEntries(search.page + 1)">
{{ 'core.next' | translate }} {{ 'core.next' | translate }}
<ion-icon name="fas-chevron-right" slot="end"></ion-icon> <ion-icon name="fas-chevron-right" slot="end" aria-hidden="true"></ion-icon>
</ion-button> </ion-button>
</ion-col> </ion-col>
</ion-row> </ion-row>
@ -146,6 +146,6 @@
<ion-fab slot="fixed" core-fab vertical="bottom" horizontal="end" *ngIf="canAdd"> <ion-fab slot="fixed" core-fab vertical="bottom" horizontal="end" *ngIf="canAdd">
<ion-fab-button (click)="gotoAddEntries()" [attr.aria-label]="'addon.mod_data.addentries' | translate"> <ion-fab-button (click)="gotoAddEntries()" [attr.aria-label]="'addon.mod_data.addentries' | translate">
<ion-icon name="fas-plus"></ion-icon> <ion-icon name="fas-plus" aria-hidden="true"></ion-icon>
</ion-fab-button> </ion-fab-button>
</ion-fab> </ion-fab>

View File

@ -90,7 +90,7 @@ export class AddonModDataIndexComponent extends CoreCourseModuleMainActivityComp
entriesRendered = ''; entriesRendered = '';
extraImports: Type<unknown>[] = [AddonModDataComponentsCompileModule]; extraImports: Type<unknown>[] = [AddonModDataComponentsCompileModule];
jsData? : { jsData?: {
fields: Record<number, AddonModDataField>; fields: Record<number, AddonModDataField>;
entries: Record<number, AddonModDataEntry>; entries: Record<number, AddonModDataEntry>;
database: AddonModDataData; database: AddonModDataData;
@ -100,7 +100,7 @@ export class AddonModDataIndexComponent extends CoreCourseModuleMainActivityComp
}; };
// Data for found records translation. // Data for found records translation.
foundRecordsTranslationData? : { foundRecordsTranslationData?: {
num: number; num: number;
max: number; max: number;
reseturl: string; reseturl: string;

View File

@ -1,12 +1,12 @@
<ion-header> <ion-header>
<ion-toolbar> <ion-toolbar>
<ion-buttons slot="start"> <ion-buttons slot="start">
<ion-back-button [attr.aria-label]="'core.back' | translate"></ion-back-button> <ion-back-button [text]="'core.back' | translate"></ion-back-button>
</ion-buttons> </ion-buttons>
<ion-title>{{ 'addon.mod_data.search' | translate }}</ion-title> <ion-title>{{ 'addon.mod_data.search' | translate }}</ion-title>
<ion-buttons slot="end"> <ion-buttons slot="end">
<ion-button (click)="closeModal()" [attr.aria-label]="'core.close' | translate"> <ion-button (click)="closeModal()" [attr.aria-label]="'core.close' | translate">
<ion-icon name="fas-times" slot="icon-only"></ion-icon> <ion-icon name="fas-times" slot="icon-only" aria-hidden=true></ion-icon>
</ion-button> </ion-button>
</ion-buttons> </ion-buttons>
</ion-toolbar> </ion-toolbar>
@ -60,7 +60,7 @@
</ion-list> </ion-list>
<div class="ion-padding"> <div class="ion-padding">
<ion-button expand="block" type="submit"> <ion-button expand="block" type="submit">
<ion-icon name="fas-search" slot="start"></ion-icon> <ion-icon name="fas-search" slot="start" aria-hidden="true"></ion-icon>
{{ 'addon.mod_data.search' | translate }} {{ 'addon.mod_data.search' | translate }}
</ion-button> </ion-button>
</div> </div>

View File

@ -52,7 +52,7 @@ export class AddonModDataSearchComponent implements OnInit {
extraImports: Type<unknown>[] = [AddonModDataComponentsCompileModule]; extraImports: Type<unknown>[] = [AddonModDataComponentsCompileModule];
searchForm: FormGroup; searchForm: FormGroup;
jsData? : { jsData?: {
fields: Record<number, AddonModDataField>; fields: Record<number, AddonModDataField>;
form: FormGroup; form: FormGroup;
search: CoreFormFields; search: CoreFormFields;

View File

@ -13,7 +13,7 @@
</div> </div>
<div class="addon-data-latlong" *ngIf="locationServicesEnabled"> <div class="addon-data-latlong" *ngIf="locationServicesEnabled">
<ion-button (click)="getLocation($event)"> <ion-button (click)="getLocation($event)">
<ion-icon name="fas-crosshairs" slot="start"></ion-icon> <ion-icon name="fas-crosshairs" slot="start" aria-hidden="true"></ion-icon>
{{ 'addon.mod_data.mylocation' | translate }} {{ 'addon.mod_data.mylocation' | translate }}
</ion-button> </ion-button>
</div> </div>

View File

@ -1,7 +1,7 @@
<ion-header> <ion-header>
<ion-toolbar> <ion-toolbar>
<ion-buttons slot="start"> <ion-buttons slot="start">
<ion-back-button [attr.aria-label]="'core.back' | translate"></ion-back-button> <ion-back-button [text]="'core.back' | translate"></ion-back-button>
</ion-buttons> </ion-buttons>
<ion-title> <ion-title>
<core-format-text [text]="title" contextLevel="module" [contextInstanceId]="module.id" [courseId]="courseId"> <core-format-text [text]="title" contextLevel="module" [contextInstanceId]="module.id" [courseId]="courseId">

View File

@ -77,7 +77,7 @@ export class AddonModDataEditPage implements OnInit {
editFormRender = ''; editFormRender = '';
editForm: FormGroup; editForm: FormGroup;
extraImports: Type<unknown>[] = [AddonModDataComponentsCompileModule]; extraImports: Type<unknown>[] = [AddonModDataComponentsCompileModule];
jsData? : { jsData?: {
fields: Record<number, AddonModDataField>; fields: Record<number, AddonModDataField>;
database?: AddonModDataData; database?: AddonModDataData;
contents: AddonModDataEntryFields; contents: AddonModDataEntryFields;

View File

@ -1,7 +1,7 @@
<ion-header> <ion-header>
<ion-toolbar> <ion-toolbar>
<ion-buttons slot="start"> <ion-buttons slot="start">
<ion-back-button [attr.aria-label]="'core.back' | translate"></ion-back-button> <ion-back-button [text]="'core.back' | translate"></ion-back-button>
</ion-buttons> </ion-buttons>
<ion-title> <ion-title>
<core-format-text [text]="title" contextLevel="module" [contextInstanceId]="module.id" [courseId]="courseId"> <core-format-text [text]="title" contextLevel="module" [contextInstanceId]="module.id" [courseId]="courseId">
@ -19,7 +19,7 @@
<!-- Database entries found to be synchronized --> <!-- Database entries found to be synchronized -->
<ion-card class="core-warning-card" *ngIf="entry && entry.hasOffline"> <ion-card class="core-warning-card" *ngIf="entry && entry.hasOffline">
<ion-item> <ion-item>
<ion-icon name="fas-exclamation-triangle" slot="start"></ion-icon> <ion-icon name="fas-exclamation-triangle" slot="start" aria-hidden="true"></ion-icon>
<ion-label>{{ 'core.hasdatatosync' | translate: {$a: moduleName} }}</ion-label> <ion-label>{{ 'core.hasdatatosync' | translate: {$a: moduleName} }}</ion-label>
</ion-item> </ion-item>
</ion-card> </ion-card>
@ -66,14 +66,14 @@
<ion-row class="ion-align-items-center"> <ion-row class="ion-align-items-center">
<ion-col *ngIf="hasPrevious"> <ion-col *ngIf="hasPrevious">
<ion-button expand="block" fill="outline" (click)="gotoEntry(offset! -1)"> <ion-button expand="block" fill="outline" (click)="gotoEntry(offset! -1)">
<ion-icon name="fas-chevron-left" slot="start"></ion-icon> <ion-icon name="fas-chevron-left" slot="start" aria-hidden="true"></ion-icon>
{{ 'core.previous' | translate }} {{ 'core.previous' | translate }}
</ion-button> </ion-button>
</ion-col> </ion-col>
<ion-col *ngIf="hasNext"> <ion-col *ngIf="hasNext">
<ion-button expand="block" (click)="gotoEntry(offset! + 1)"> <ion-button expand="block" (click)="gotoEntry(offset! + 1)">
{{ 'core.next' | translate }} {{ 'core.next' | translate }}
<ion-icon name="fas-chevron-right" slot="end"></ion-icon> <ion-icon name="fas-chevron-right" slot="end" aria-hidden="true"></ion-icon>
</ion-button> </ion-button>
</ion-col> </ion-col>
</ion-row> </ion-row>

View File

@ -78,7 +78,7 @@ export class AddonModDataEntryPage implements OnInit, OnDestroy {
entryHtml = ''; entryHtml = '';
siteId: string; siteId: string;
extraImports: Type<unknown>[] = [AddonModDataComponentsCompileModule]; extraImports: Type<unknown>[] = [AddonModDataComponentsCompileModule];
jsData? : { jsData?: {
fields: Record<number, AddonModDataField>; fields: Record<number, AddonModDataField>;
entries: Record<number, AddonModDataEntry>; entries: Record<number, AddonModDataEntry>;
database: AddonModDataData; database: AddonModDataData;

View File

@ -1,7 +1,7 @@
<ion-header> <ion-header>
<ion-toolbar> <ion-toolbar>
<ion-buttons slot="start"> <ion-buttons slot="start">
<ion-back-button [attr.aria-label]="'core.back' | translate"></ion-back-button> <ion-back-button [text]="'core.back' | translate"></ion-back-button>
</ion-buttons> </ion-buttons>
<ion-title> <ion-title>
<core-format-text [text]="title" contextLevel="module" [contextInstanceId]="module.id" [courseId]="courseId"> <core-format-text [text]="title" contextLevel="module" [contextInstanceId]="module.id" [courseId]="courseId">

View File

@ -68,14 +68,15 @@
</ion-select-option> </ion-select-option>
</ion-select> </ion-select>
</ion-item> </ion-item>
<ion-item class="ion-text-wrap" (click)="openRespondents()" [detail]="access.canviewreports && completedCount > 0"> <ion-item class="ion-text-wrap" (click)="openRespondents()" [detail]="access.canviewreports && completedCount > 0"
button>
<ion-label> <ion-label>
<h2>{{ 'addon.mod_feedback.completed_feedbacks' | translate }}</h2> <h2>{{ 'addon.mod_feedback.completed_feedbacks' | translate }}</h2>
</ion-label> </ion-label>
<ion-badge slot="end">{{completedCount}}</ion-badge> <ion-badge slot="end">{{completedCount}}</ion-badge>
</ion-item> </ion-item>
<ion-item class="ion-text-wrap" *ngIf="!access.isanonymous && access.canviewreports" (click)="openNonRespondents()" <ion-item class="ion-text-wrap" *ngIf="!access.isanonymous && access.canviewreports" (click)="openNonRespondents()"
detail="true" tappable="true"> detail="true" button>
<ion-label> <ion-label>
<h2>{{ 'addon.mod_feedback.show_nonrespondents' | translate }}</h2> <h2>{{ 'addon.mod_feedback.show_nonrespondents' | translate }}</h2>
</ion-label> </ion-label>
@ -97,21 +98,21 @@
<!-- Feedback done in offline but not synchronized --> <!-- Feedback done in offline but not synchronized -->
<ion-card class="core-warning-card" *ngIf="hasOffline"> <ion-card class="core-warning-card" *ngIf="hasOffline">
<ion-item> <ion-item>
<ion-icon name="fas-exclamation-triangle" slot="start"></ion-icon> <ion-icon name="fas-exclamation-triangle" slot="start" aria-hidden="true"></ion-icon>
<ion-label>{{ 'core.hasdatatosync' | translate:{$a: moduleName} }}</ion-label> <ion-label>{{ 'core.hasdatatosync' | translate:{$a: moduleName} }}</ion-label>
</ion-item> </ion-item>
</ion-card> </ion-card>
<ion-card class="core-info-card" *ngIf="access && access.cancomplete && !access.isopen"> <ion-card class="core-info-card" *ngIf="access && access.cancomplete && !access.isopen">
<ion-item> <ion-item>
<ion-icon name="fas-question-circle" slot="start"></ion-icon> <ion-icon name="fas-question-circle" slot="start" aria-hidden="true"></ion-icon>
<ion-label>{{ 'addon.mod_feedback.feedback_is_not_open' | translate }}</ion-label> <ion-label>{{ 'addon.mod_feedback.feedback_is_not_open' | translate }}</ion-label>
</ion-item> </ion-item>
</ion-card> </ion-card>
<ion-card class="core-success-card" *ngIf="access && access.cancomplete && access.isopen && !access.cansubmit"> <ion-card class="core-success-card" *ngIf="access && access.cancomplete && access.isopen && !access.cansubmit">
<ion-item> <ion-item>
<ion-icon name="fas-check" slot="start"></ion-icon> <ion-icon name="fas-check" slot="start" aria-hidden="true"></ion-icon>
<ion-label>{{ 'addon.mod_feedback.this_feedback_is_already_submitted' | translate }}</ion-label> <ion-label>{{ 'addon.mod_feedback.this_feedback_is_already_submitted' | translate }}</ion-label>
</ion-item> </ion-item>
</ion-card> </ion-card>
@ -149,7 +150,7 @@
<ion-row class="ion-align-items-center"> <ion-row class="ion-align-items-center">
<ion-col> <ion-col>
<ion-button expand="block" fill="outline" (click)="gotoAnswerQuestions(true)" class="ion-text-wrap"> <ion-button expand="block" fill="outline" (click)="gotoAnswerQuestions(true)" class="ion-text-wrap">
<ion-icon name="fas-search" slot="start"></ion-icon> <ion-icon name="fas-search" slot="start" aria-hidden="true"></ion-icon>
{{ 'addon.mod_feedback.preview' | translate }} {{ 'addon.mod_feedback.preview' | translate }}
</ion-button> </ion-button>
</ion-col> </ion-col>
@ -161,7 +162,7 @@
<ng-container *ngIf="goPage"> <ng-container *ngIf="goPage">
{{ 'addon.mod_feedback.continue_the_form' | translate }} {{ 'addon.mod_feedback.continue_the_form' | translate }}
</ng-container> </ng-container>
<ion-icon name="fas-chevron-right" slot="end"></ion-icon> <ion-icon name="fas-chevron-right" slot="end" aria-hidden="true"></ion-icon>
</ion-button> </ion-button>
</ion-col> </ion-col>
</ion-row> </ion-row>
@ -180,7 +181,7 @@
<ng-container *ngIf="access && (access.canedititems || !access.isempty)"> <ng-container *ngIf="access && (access.canedititems || !access.isempty)">
<ion-card class="core-info-card" *ngIf="warning"> <ion-card class="core-info-card" *ngIf="warning">
<ion-item> <ion-item>
<ion-icon name="fas-question-circle" slot="start"></ion-icon> <ion-icon name="fas-question-circle" slot="start" aria-hidden="true"></ion-icon>
<ion-label>{{ warning }}</ion-label> <ion-label>{{ warning }}</ion-label>
</ion-item> </ion-item>
</ion-card> </ion-card>

View File

@ -1,7 +1,7 @@
<ion-header> <ion-header>
<ion-toolbar> <ion-toolbar>
<ion-buttons slot="start"> <ion-buttons slot="start">
<ion-back-button [attr.aria-label]="'core.back' | translate"></ion-back-button> <ion-back-button [text]="'core.back' | translate"></ion-back-button>
</ion-buttons> </ion-buttons>
<ion-title> <ion-title>
<ng-container *ngIf="attempt">{{ attempt.fullname }}</ng-container> <ng-container *ngIf="attempt">{{ attempt.fullname }}</ng-container>
@ -15,7 +15,7 @@
<core-loading [hideUntil]="loaded"> <core-loading [hideUntil]="loaded">
<ion-list class="ion-no-margin" *ngIf="attempt || anonAttempt"> <ion-list class="ion-no-margin" *ngIf="attempt || anonAttempt">
<ion-item *ngIf="attempt" class="ion-text-wrap" core-user-link [userId]="attempt.userid" <ion-item *ngIf="attempt" class="ion-text-wrap" core-user-link [userId]="attempt.userid"
[attr.aria-label]=" 'core.user.viewprofile' | translate" [courseId]="attempt.courseid" [title]="attempt.fullname"> [attr.aria-label]=" 'core.user.viewprofile' | translate" [courseId]="attempt.courseid">
<core-user-avatar [user]="attempt" slot="start"></core-user-avatar> <core-user-avatar [user]="attempt" slot="start"></core-user-avatar>
<ion-label> <ion-label>
<h2>{{attempt.fullname}}</h2> <h2>{{attempt.fullname}}</h2>

View File

@ -1,7 +1,7 @@
<ion-header> <ion-header>
<ion-toolbar> <ion-toolbar>
<ion-buttons slot="start"> <ion-buttons slot="start">
<ion-back-button [attr.aria-label]="'core.back' | translate"></ion-back-button> <ion-back-button [text]="'core.back' | translate"></ion-back-button>
</ion-buttons> </ion-buttons>
<ion-title> <ion-title>
<core-format-text [text]="title" contextLevel="module" [contextInstanceId]="cmId" [courseId]="courseId"> <core-format-text [text]="title" contextLevel="module" [contextInstanceId]="cmId" [courseId]="courseId">
@ -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"
@ -106,7 +106,7 @@
</core-recaptcha> </core-recaptcha>
<div *ngIf="!preview && (!item.captcha || offline)" class="core-warning-card"> <div *ngIf="!preview && (!item.captcha || offline)" class="core-warning-card">
<ion-item> <ion-item>
<ion-icon name="fas-exclamation-triangle" slot="start"></ion-icon> <ion-icon name="fas-exclamation-triangle" slot="start" aria-hidden="true"></ion-icon>
<ion-label>{{ 'addon.mod_feedback.captchaofflinewarning' | translate }}</ion-label> <ion-label>{{ 'addon.mod_feedback.captchaofflinewarning' | translate }}</ion-label>
</ion-item> </ion-item>
</div> </div>
@ -117,14 +117,14 @@
<ion-row class="ion-align-items-center"> <ion-row class="ion-align-items-center">
<ion-col *ngIf="hasPrevPage"> <ion-col *ngIf="hasPrevPage">
<ion-button expand="block" fill="outline" (click)="gotoPage(true)" class="ion-text-wrap"> <ion-button expand="block" fill="outline" (click)="gotoPage(true)" class="ion-text-wrap">
<ion-icon name="fas-chevron-left" slot="start"></ion-icon> <ion-icon name="fas-chevron-left" slot="start" aria-hidden="true"></ion-icon>
{{ 'addon.mod_feedback.previous_page' | translate }} {{ 'addon.mod_feedback.previous_page' | translate }}
</ion-button> </ion-button>
</ion-col> </ion-col>
<ion-col *ngIf="hasNextPage"> <ion-col *ngIf="hasNextPage">
<ion-button expand="block" (click)="gotoPage(false)" class="ion-text-wrap"> <ion-button expand="block" (click)="gotoPage(false)" class="ion-text-wrap">
{{ 'addon.mod_feedback.next_page' | translate }} {{ 'addon.mod_feedback.next_page' | translate }}
<ion-icon name="fas-chevron-right" slot="end"></ion-icon> <ion-icon name="fas-chevron-right" slot="end" aria-hidden="true"></ion-icon>
</ion-button> </ion-button>
</ion-col> </ion-col>
<ion-col *ngIf="!hasNextPage"> <ion-col *ngIf="!hasNextPage">
@ -139,7 +139,7 @@
<ion-card class="core-success-card" *ngIf="completed"> <ion-card class="core-success-card" *ngIf="completed">
<ion-item> <ion-item>
<ion-icon name="fas-check" slot="start"></ion-icon> <ion-icon name="fas-check" slot="start" aria-hidden="true"></ion-icon>
<ion-label> <ion-label>
<p *ngIf="!completionPageContents && !completedOffline"> <p *ngIf="!completionPageContents && !completedOffline">
{{ 'addon.mod_feedback.this_feedback_is_already_submitted' | translate }} {{ 'addon.mod_feedback.this_feedback_is_already_submitted' | translate }}
@ -161,14 +161,14 @@
<ion-row class="ion-align-items-center"> <ion-row class="ion-align-items-center">
<ion-col *ngIf="access!.canviewanalysis"> <ion-col *ngIf="access!.canviewanalysis">
<ion-button expand="block" fill="outline" (click)="showAnalysis()" class="ion-text-wrap"> <ion-button expand="block" fill="outline" (click)="showAnalysis()" class="ion-text-wrap">
<ion-icon name="fas-chart-bar" slot="start"></ion-icon> <ion-icon name="fas-chart-bar" slot="start" aria-hidden="true"></ion-icon>
{{ 'addon.mod_feedback.completed_feedbacks' | translate }} {{ 'addon.mod_feedback.completed_feedbacks' | translate }}
</ion-button> </ion-button>
</ion-col> </ion-col>
<ion-col *ngIf="hasNextPage"> <ion-col *ngIf="hasNextPage">
<ion-button expand="block" (click)="continue()" class="ion-text-wrap"> <ion-button expand="block" (click)="continue()" class="ion-text-wrap">
{{ 'core.continue' | translate }} {{ 'core.continue' | translate }}
<ion-icon name="fas-chevron-right" slot="end"></ion-icon> <ion-icon name="fas-chevron-right" slot="end" aria-hidden="true"></ion-icon>
</ion-button> </ion-button>
</ion-col> </ion-col>
</ion-row> </ion-row>

View File

@ -1,7 +1,7 @@
<ion-header> <ion-header>
<ion-toolbar> <ion-toolbar>
<ion-buttons slot="start"> <ion-buttons slot="start">
<ion-back-button [attr.aria-label]="'core.back' | translate"></ion-back-button> <ion-back-button [text]="'core.back' | translate"></ion-back-button>
</ion-buttons> </ion-buttons>
<ion-title> <ion-title>
<core-format-text [text]="title" contextLevel="module" [contextInstanceId]="module?.id" [courseId]="courseId"> <core-format-text [text]="title" contextLevel="module" [contextInstanceId]="module?.id" [courseId]="courseId">

View File

@ -1,7 +1,7 @@
<ion-header> <ion-header>
<ion-toolbar> <ion-toolbar>
<ion-buttons slot="start"> <ion-buttons slot="start">
<ion-back-button [attr.aria-label]="'core.back' | translate"></ion-back-button> <ion-back-button [text]="'core.back' | translate"></ion-back-button>
</ion-buttons> </ion-buttons>
<ion-title>{{ 'addon.mod_feedback.responses' |translate }}</ion-title> <ion-title>{{ 'addon.mod_feedback.responses' |translate }}</ion-title>
</ion-toolbar> </ion-toolbar>

View File

@ -1,7 +1,7 @@
<ion-header> <ion-header>
<ion-toolbar> <ion-toolbar>
<ion-buttons slot="start"> <ion-buttons slot="start">
<ion-back-button [attr.aria-label]="'core.back' | translate"></ion-back-button> <ion-back-button [text]="'core.back' | translate"></ion-back-button>
</ion-buttons> </ion-buttons>
<ion-title>{{ 'addon.mod_feedback.responses' |translate }}</ion-title> <ion-title>{{ 'addon.mod_feedback.responses' |translate }}</ion-title>
</ion-toolbar> </ion-toolbar>
@ -32,8 +32,8 @@
{{ 'addon.mod_feedback.non_anonymous_entries' | translate : {$a: responses.responses.total } }} {{ 'addon.mod_feedback.non_anonymous_entries' | translate : {$a: responses.responses.total } }}
</ion-label> </ion-label>
</ion-item-divider> </ion-item-divider>
<ion-item *ngFor="let attempt of responses.responses.attempts" class="ion-text-wrap" tappable detail="true" <ion-item *ngFor="let attempt of responses.responses.attempts" class="ion-text-wrap" button detail="true"
(click)="responses.select(attempt)" [class.core-selected-item]="responses.isSelected(attempt)"> (click)="responses.select(attempt)" [attr.aria-current]="responses.getItemAriaCurrent(attempt)">
<core-user-avatar [user]="attempt" slot="start"></core-user-avatar> <core-user-avatar [user]="attempt" slot="start"></core-user-avatar>
<ion-label> <ion-label>
<h2>{{ attempt.fullname }}</h2> <h2>{{ attempt.fullname }}</h2>
@ -57,8 +57,8 @@
{{ 'addon.mod_feedback.anonymous_entries' |translate : {$a: responses.anonResponses.total } }} {{ 'addon.mod_feedback.anonymous_entries' |translate : {$a: responses.anonResponses.total } }}
</ion-label> </ion-label>
</ion-item-divider> </ion-item-divider>
<ion-item *ngFor="let attempt of responses.anonResponses.attempts" class="ion-text-wrap" tappable detail="true" <ion-item *ngFor="let attempt of responses.anonResponses.attempts" class="ion-text-wrap" button detail="true"
(click)="responses.select(attempt)" [class.core-selected-item]="responses.isSelected(attempt)"> (click)="responses.select(attempt)" [attr.aria-current]="responses.getItemAriaCurrent(attempt)">
<ion-label> <ion-label>
<h2>{{ 'addon.mod_feedback.response_nr' |translate }}: {{attempt.number}}</h2> <h2>{{ 'addon.mod_feedback.response_nr' |translate }}: {{attempt.number}}</h2>
</ion-label> </ion-label>

View File

@ -32,7 +32,7 @@
<ion-list *ngIf="subfolder && (subfolder!.files.length + subfolder!.folders.length > 0)"> <ion-list *ngIf="subfolder && (subfolder!.files.length + subfolder!.folders.length > 0)">
<ng-container *ngFor="let folder of subfolder!.folders"> <ng-container *ngFor="let folder of subfolder!.folders">
<ion-item class="item-file" (click)="openFolder(folder)" detail="true" button> <ion-item class="item-file" (click)="openFolder(folder)" detail="true" button>
<ion-icon name="fas-folder" slot="start"></ion-icon> <ion-icon name="fas-folder" slot="start" [attr.aria-label]="'core.folder' | translate"></ion-icon>
<ion-label> <ion-label>
<h2>{{folder.filename}}</h2> <h2>{{folder.filename}}</h2>
</ion-label> </ion-label>

View File

@ -1,7 +1,7 @@
<ion-header> <ion-header>
<ion-toolbar> <ion-toolbar>
<ion-buttons slot="start"> <ion-buttons slot="start">
<ion-back-button [attr.aria-label]="'core.back' | translate"></ion-back-button> <ion-back-button [text]="'core.back' | translate"></ion-back-button>
</ion-buttons> </ion-buttons>
<ion-title> <ion-title>
<core-format-text [text]="title" contextLevel="module" [contextInstanceId]="module?.id" [courseId]="courseId"> <core-format-text [text]="title" contextLevel="module" [contextInstanceId]="module?.id" [courseId]="courseId">

View File

@ -1,35 +1,35 @@
<ion-item class="ion-text-wrap" (click)="setLockState(true)" *ngIf="discussion.canlock && !discussion.locked"> <ion-item class="ion-text-wrap" (click)="setLockState(true)" *ngIf="discussion.canlock && !discussion.locked">
<ion-icon name="fa-lock" slot="start"></ion-icon> <ion-icon name="fa-lock" slot="start" aria-hidden="true"></ion-icon>
<ion-label> <ion-label>
<h2>{{ 'addon.mod_forum.lockdiscussion' | translate }}</h2> <h2>{{ 'addon.mod_forum.lockdiscussion' | translate }}</h2>
</ion-label> </ion-label>
</ion-item> </ion-item>
<ion-item class="ion-text-wrap" (click)="setLockState(false)" *ngIf="discussion.canlock && discussion.locked"> <ion-item class="ion-text-wrap" (click)="setLockState(false)" *ngIf="discussion.canlock && discussion.locked">
<ion-icon name="fa-unlock" slot="start"></ion-icon> <ion-icon name="fa-unlock" slot="start" aria-hidden="true"></ion-icon>
<ion-label> <ion-label>
<h2>{{ 'addon.mod_forum.unlockdiscussion' | translate }}</h2> <h2>{{ 'addon.mod_forum.unlockdiscussion' | translate }}</h2>
</ion-label> </ion-label>
</ion-item> </ion-item>
<ion-item class="ion-text-wrap" (click)="setPinState(true)" *ngIf="canPin && !discussion.pinned"> <ion-item class="ion-text-wrap" (click)="setPinState(true)" *ngIf="canPin && !discussion.pinned">
<ion-icon name="fa-map-pin" slot="start"></ion-icon> <ion-icon name="fa-map-pin" slot="start" aria-hidden="true"></ion-icon>
<ion-label> <ion-label>
<h2>{{ 'addon.mod_forum.pindiscussion' | translate }}</h2> <h2>{{ 'addon.mod_forum.pindiscussion' | translate }}</h2>
</ion-label> </ion-label>
</ion-item> </ion-item>
<ion-item class="ion-text-wrap" (click)="setPinState(false)" *ngIf="canPin && discussion.pinned"> <ion-item class="ion-text-wrap" (click)="setPinState(false)" *ngIf="canPin && discussion.pinned">
<ion-icon name="fa-map-pin" slot="start" class="icon-slash"></ion-icon> <ion-icon name="fa-map-pin" slot="start" class="icon-slash" aria-hidden="true"></ion-icon>
<ion-label> <ion-label>
<h2>{{ 'addon.mod_forum.unpindiscussion' | translate }}</h2> <h2>{{ 'addon.mod_forum.unpindiscussion' | translate }}</h2>
</ion-label> </ion-label>
</ion-item> </ion-item>
<ion-item class="ion-text-wrap" (click)="toggleFavouriteState(true)" *ngIf="discussion.canfavourite && !discussion.starred"> <ion-item class="ion-text-wrap" (click)="toggleFavouriteState(true)" *ngIf="discussion.canfavourite && !discussion.starred">
<ion-icon name="fa-star" slot="start"></ion-icon> <ion-icon name="fa-star" slot="start" aria-hidden="true"></ion-icon>
<ion-label> <ion-label>
<h2>{{ 'addon.mod_forum.addtofavourites' | translate }}</h2> <h2>{{ 'addon.mod_forum.addtofavourites' | translate }}</h2>
</ion-label> </ion-label>
</ion-item> </ion-item>
<ion-item class="ion-text-wrap" (click)="toggleFavouriteState(false)" *ngIf="discussion.canfavourite && discussion.starred"> <ion-item class="ion-text-wrap" (click)="toggleFavouriteState(false)" *ngIf="discussion.canfavourite && discussion.starred">
<ion-icon name="fa-star" slot="start" class="icon-slash"></ion-icon> <ion-icon name="fa-star" slot="start" class="icon-slash" aria-hidden="true"></ion-icon>
<ion-label> <ion-label>
<h2>{{ 'addon.mod_forum.removefromfavourites' | translate }}</h2> <h2>{{ 'addon.mod_forum.removefromfavourites' | translate }}</h2>
</ion-label> </ion-label>

View File

@ -3,7 +3,7 @@
<ion-title>{{ 'addon.mod_forum.yourreply' | translate }}</ion-title> <ion-title>{{ 'addon.mod_forum.yourreply' | translate }}</ion-title>
<ion-buttons slot="end"> <ion-buttons slot="end">
<ion-button (click)="closeModal()" [attr.aria-label]="'core.close' | translate"> <ion-button (click)="closeModal()" [attr.aria-label]="'core.close' | translate">
<ion-icon name="close" slot="icon-only"></ion-icon> <ion-icon name="fas-times" slot="icon-only" aria-hidden="true"></ion-icon>
</ion-button> </ion-button>
</ion-buttons> </ion-buttons>
</ion-toolbar> </ion-toolbar>
@ -25,9 +25,10 @@
(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 button"
<ion-icon *ngIf="!advanced" name="fa-caret-right" slot="start"></ion-icon> [attr.aria-expanded]="advanced" [attr.aria-label]="(advanced ? 'core.hideadvanced' : 'core.showadvanced') | translate">
<ion-icon *ngIf="advanced" name="fa-caret-down" slot="start"></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-label>{{ 'addon.mod_forum.advanced' | translate }}</ion-label> <ion-label>{{ 'addon.mod_forum.advanced' | translate }}</ion-label>
</ion-item-divider> </ion-item-divider>
<ng-container *ngIf="advanced"> <ng-container *ngIf="advanced">

View File

@ -50,7 +50,7 @@
<!-- Forum discussions found to be synchronized --> <!-- Forum discussions found to be synchronized -->
<ion-card class="core-warning-card" *ngIf="hasOffline || hasOfflineRatings"> <ion-card class="core-warning-card" *ngIf="hasOffline || hasOfflineRatings">
<ion-item> <ion-item>
<ion-icon name="fas-exclamation-triangle" slot="start"></ion-icon> <ion-icon name="fas-exclamation-triangle" slot="start" aria-hidden="true"></ion-icon>
<ion-label>{{ 'core.hasdatatosync' | translate:{$a: moduleName} }}</ion-label> <ion-label>{{ 'core.hasdatatosync' | translate:{$a: moduleName} }}</ion-label>
</ion-item> </ion-item>
</ion-card> </ion-card>
@ -58,7 +58,7 @@
<!-- Cut-off date or due date message --> <!-- Cut-off date or due date message -->
<ion-card class="core-info-card" *ngIf="availabilityMessage"> <ion-card class="core-info-card" *ngIf="availabilityMessage">
<ion-item> <ion-item>
<ion-icon name="fas-info-circle" slot="start"></ion-icon> <ion-icon name="fas-info-circle" slot="start" aria-hidden="true"></ion-icon>
<ion-label>{{ availabilityMessage }}</ion-label> <ion-label>{{ availabilityMessage }}</ion-label>
</ion-item> </ion-item>
</ion-card> </ion-card>
@ -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>
@ -80,13 +80,15 @@
<ion-item *ngFor="let discussion of discussions.items" <ion-item *ngFor="let discussion of discussions.items"
class="addon-mod-forum-discussion" detail="true" class="addon-mod-forum-discussion" detail="true"
[lines]="discussion.groupname && 'none'" [class.core-selected-item]="discussions.isSelected(discussion)" [lines]="discussion.groupname && 'none'" [attr.aria-current]="discussions.getItemAriaCurrent(discussion)"
(click)="discussions.select(discussion)"> (click)="discussions.select(discussion)">
<ion-label> <ion-label>
<div class="addon-mod-forum-discussion-title"> <div class="addon-mod-forum-discussion-title">
<h2 class="ion-text-wrap"> <h2 class="ion-text-wrap">
<ion-icon name="fa-map-pin" *ngIf="discussion.pinned"></ion-icon> <ion-icon name="fa-map-pin" *ngIf="discussion.pinned"
<ion-icon name="fa-star" class="addon-forum-star" *ngIf="!discussion.pinned && discussion.starred"></ion-icon> [attr.aria-label]="'addon.mod_forum.discussionpinned' | translate"></ion-icon>
<ion-icon name="fa-star" class="addon-forum-star" *ngIf="!discussion.pinned && discussion.starred"
[attr.aria-label]="'addon.mod_forum.favourites' | translate"></ion-icon>
<core-format-text <core-format-text
[text]="discussion.subject" [text]="discussion.subject"
contextLevel="module" [contextInstanceId]="module && module.id" [courseId]="courseId"> contextLevel="module" [contextInstanceId]="module && module.id" [courseId]="courseId">
@ -96,7 +98,7 @@
fill="clear" color="dark" fill="clear" color="dark"
[attr.aria-label]="('core.displayoptions' | translate)" [attr.aria-label]="('core.displayoptions' | translate)"
(click)="showOptionsMenu($event, discussion)"> (click)="showOptionsMenu($event, discussion)">
<ion-icon name="ellipsis-vertical" slot="icon-only"> <ion-icon name="ellipsis-vertical" slot="icon-only" aria-hidden="true">
</ion-icon> </ion-icon>
</ion-button> </ion-button>
</div> </div>
@ -105,12 +107,15 @@
</core-user-avatar> </core-user-avatar>
<div class="addon-mod-forum-discussion-author"> <div class="addon-mod-forum-discussion-author">
<h3 *ngIf="discussion.userfullname">{{discussion.userfullname}}</h3> <h3 *ngIf="discussion.userfullname">{{discussion.userfullname}}</h3>
<p *ngIf="discussion.groupname"><ion-icon name="people"></ion-icon> {{ discussion.groupname }}</p> <p *ngIf="discussion.groupname">
<ion-icon name="fas-users" [attr.aria-label]="'addon.mod_forum.group' | translate">
</ion-icon> {{ discussion.groupname }}
</p>
<p *ngIf="discussions.isOnlineDiscussion(discussion)"> <p *ngIf="discussions.isOnlineDiscussion(discussion)">
{{discussion.created * 1000 | coreFormatDate: "strftimerecentfull"}} {{discussion.created * 1000 | coreFormatDate: "strftimerecentfull"}}
</p> </p>
<p *ngIf="discussions.isOfflineDiscussion(discussion)"> <p *ngIf="discussions.isOfflineDiscussion(discussion)">
<ion-icon name="fas-clock"></ion-icon> <ion-icon name="fas-clock" aria-hidden="true"></ion-icon>
{{ 'core.notsent' | translate }} {{ 'core.notsent' | translate }}
</p> </p>
</div> </div>
@ -119,7 +124,7 @@
class="ion-text-center addon-mod-forum-discussion-more-info"> class="ion-text-center addon-mod-forum-discussion-more-info">
<ion-col class="ion-text-start"> <ion-col class="ion-text-start">
<ion-note> <ion-note>
<ion-icon name="fas-clock"></ion-icon> {{ 'addon.mod_forum.lastpost' | translate }} <ion-icon name="fas-clock" aria-hidden="true"></ion-icon> {{ 'addon.mod_forum.lastpost' | translate }}
<ng-container *ngIf="discussion.timemodified > discussion.created"> <ng-container *ngIf="discussion.timemodified > discussion.created">
{{ discussion.timemodified | coreTimeAgo }} {{ discussion.timemodified | coreTimeAgo }}
</ng-container> </ng-container>
@ -130,7 +135,7 @@
</ion-col> </ion-col>
<ion-col class="ion-text-end"> <ion-col class="ion-text-end">
<ion-note> <ion-note>
<ion-icon name="fas-comments"></ion-icon> <ion-icon name="fas-comments" aria-hidden="true"></ion-icon>
{{ 'addon.mod_forum.numreplies' | translate:{numreplies: discussion.numreplies} }} {{ 'addon.mod_forum.numreplies' | translate:{numreplies: discussion.numreplies} }}
<ion-badge *ngIf="discussion.numunread" class="ion-text-center" <ion-badge *ngIf="discussion.numunread" class="ion-text-center"
[attr.aria-label]="'addon.mod_forum.unreadpostsnumber' | translate:{ '$a' : discussion.numunread}"> [attr.aria-label]="'addon.mod_forum.unreadpostsnumber' | translate:{ '$a' : discussion.numunread}">
@ -151,7 +156,7 @@
<ion-fab slot="fixed" core-fab vertical="bottom" horizontal="end" *ngIf="forum && canAddDiscussion"> <ion-fab slot="fixed" core-fab vertical="bottom" horizontal="end" *ngIf="forum && canAddDiscussion">
<ion-fab-button (click)="openNewDiscussion()" [attr.aria-label]="addDiscussionText"> <ion-fab-button (click)="openNewDiscussion()" [attr.aria-label]="addDiscussionText">
<ion-icon name="fas-plus"></ion-icon> <ion-icon name="fas-plus" aria-hidden="true"></ion-icon>
</ion-fab-button> </ion-fab-button>
</ion-fab> </ion-fab>
</core-split-view> </core-split-view>

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;
@ -635,14 +634,10 @@ export class AddonModForumIndexComponent extends CoreCourseModuleMainActivityCom
}, },
}); });
modal.present(); await 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;
@ -673,7 +668,7 @@ export class AddonModForumIndexComponent extends CoreCourseModuleMainActivityCom
event, event,
}); });
popover.present(); await popover.present();
const result = await popover.onDidDismiss<{ action?: string; value: boolean }>(); const result = await popover.onDidDismiss<{ action?: string; value: boolean }>();

View File

@ -1,12 +1,12 @@
<core-loading [hideUntil]="loaded" class="core-loading-center"> <core-loading [hideUntil]="loaded" class="core-loading-center">
<ion-item class="ion-text-wrap" (click)="editPost()" *ngIf="offlinePost || (canEdit && isOnline)"> <ion-item class="ion-text-wrap" (click)="editPost()" *ngIf="offlinePost || (canEdit && isOnline)">
<ion-icon name="create" slot="start"></ion-icon> <ion-icon name="fas-pen" slot="start" aria-hidden="true"></ion-icon>
<ion-label> <ion-label>
<h2>{{ 'addon.mod_forum.edit' | translate }}</h2> <h2>{{ 'addon.mod_forum.edit' | translate }}</h2>
</ion-label> </ion-label>
</ion-item> </ion-item>
<ion-item class="ion-text-wrap" (click)="deletePost()" *ngIf="offlinePost || (canDelete && isOnline)"> <ion-item class="ion-text-wrap" (click)="deletePost()" *ngIf="offlinePost || (canDelete && isOnline)">
<ion-icon name="fas-trash" slot="start"></ion-icon> <ion-icon name="fas-trash" slot="start" aria-hidden="true"></ion-icon>
<ion-label> <ion-label>
<h2 *ngIf="!offlinePost">{{ 'addon.mod_forum.delete' | translate }}</h2> <h2 *ngIf="!offlinePost">{{ 'addon.mod_forum.delete' | translate }}</h2>
<h2 *ngIf="offlinePost">{{ 'core.discard' | translate }}</h2> <h2 *ngIf="offlinePost">{{ 'core.discard' | translate }}</h2>
@ -18,7 +18,7 @@
</ion-label> </ion-label>
</ion-item> </ion-item>
<ion-item class="ion-text-wrap" [href]="url" *ngIf="url" core-link capture="false"> <ion-item class="ion-text-wrap" [href]="url" *ngIf="url" core-link capture="false">
<ion-icon name="open" slot="start"></ion-icon> <ion-icon name="fas-external-link-alt" slot="start" aria-hidden="true"></ion-icon>
<ion-label> <ion-label>
<h2>{{ 'core.openinbrowser' | translate }}</h2> <h2>{{ 'core.openinbrowser' | translate }}</h2>
</ion-label> </ion-label>

View File

@ -4,9 +4,11 @@
<ion-label> <ion-label>
<div class="addon-mod-forum-post-title" *ngIf="displaySubject"> <div class="addon-mod-forum-post-title" *ngIf="displaySubject">
<h2 class="ion-text-wrap"> <h2 class="ion-text-wrap">
<ion-icon name="fa-map-pin" *ngIf="discussion && !post.parentid && discussion.pinned"> <ion-icon name="fa-map-pin" *ngIf="discussion && !post.parentid && discussion.pinned"
[attr.aria-label]="'addon.mod_forum.discussionpinned' | translate">
</ion-icon> </ion-icon>
<ion-icon name="fa-star" class="addon-forum-star" <ion-icon name="fa-star" class="addon-forum-star"
[attr.aria-label]="'addon.mod_forum.favourites' | translate"
*ngIf="discussion && !post.parentid && !discussion.pinned && discussion.starred"> *ngIf="discussion && !post.parentid && !discussion.pinned && discussion.starred">
</ion-icon> </ion-icon>
<core-format-text <core-format-text
@ -16,13 +18,12 @@
</h2> </h2>
<ion-note *ngIf="trackPosts && post.unread" <ion-note *ngIf="trackPosts && post.unread"
class="ion-float-end ion-padding-left ion-text-end" [attr.aria-label]="'addon.mod_forum.unread' | translate"> class="ion-float-end ion-padding-left ion-text-end" [attr.aria-label]="'addon.mod_forum.unread' | translate">
<ion-icon name="fa-circle" color="primary"> <ion-icon name="fa-circle" color="primary" aria-hidden="true"></ion-icon>
</ion-icon>
</ion-note> </ion-note>
<ion-button *ngIf="optionsMenuEnabled" <ion-button *ngIf="optionsMenuEnabled"
fill="clear" color="dark" [attr.aria-label]="('core.displayoptions' | translate)" fill="clear" color="dark" [attr.aria-label]="('core.displayoptions' | translate)"
(click)="showOptionsMenu($event)"> (click)="showOptionsMenu($event)">
<ion-icon name="ellipsis-vertical" slot="icon-only"> <ion-icon name="ellipsis-vertical" slot="icon-only" aria-hidden="true">
</ion-icon> </ion-icon>
</ion-button> </ion-button>
</div> </div>
@ -33,23 +34,24 @@
<h3 *ngIf="post.author && post.author.fullname">{{post.author.fullname}}</h3> <h3 *ngIf="post.author && post.author.fullname">{{post.author.fullname}}</h3>
<p *ngIf="post.author && post.author.groups"> <p *ngIf="post.author && post.author.groups">
<ng-container *ngFor="let group of post.author.groups"> <ng-container *ngFor="let group of post.author.groups">
<ion-icon name="people"></ion-icon> {{ group.name }} <ion-icon name="fas-users" [attr.aria-label]="'addon.mod_forum.group' | translate">
</ion-icon> {{ group.name }}
</ng-container> </ng-container>
</p> </p>
<p *ngIf="post.timecreated">{{post.timecreated * 1000 | coreFormatDate: "strftimerecentfull"}}</p> <p *ngIf="post.timecreated">{{post.timecreated * 1000 | coreFormatDate: "strftimerecentfull"}}</p>
<p *ngIf="!post.timecreated"><ion-icon name="fas-clock"></ion-icon> {{ 'core.notsent' | translate }}</p> <p *ngIf="!post.timecreated">
<ion-icon name="fas-clock" aria-hidden="true"></ion-icon> {{ 'core.notsent' | translate }}
</p>
</div> </div>
<ng-container *ngIf="!displaySubject"> <ng-container *ngIf="!displaySubject">
<ion-note *ngIf="trackPosts && post.unread" <ion-note *ngIf="trackPosts && post.unread"
class="ion-float-end ion-padding-left ion-text-end" [attr.aria-label]="'addon.mod_forum.unread' | translate"> class="ion-float-end ion-padding-left ion-text-end" [attr.aria-label]="'addon.mod_forum.unread' | translate">
<ion-icon name="fa-circle" color="primary"> <ion-icon name="fa-circle" color="primary" aria-hidden="true"></ion-icon>
</ion-icon>
</ion-note> </ion-note>
<ion-button *ngIf="optionsMenuEnabled" <ion-button *ngIf="optionsMenuEnabled"
fill="clear" color="dark" [attr.aria-label]="('core.displayoptions' | translate)" fill="clear" color="dark" [attr.aria-label]="('core.displayoptions' | translate)"
(click)="showOptionsMenu($event)"> (click)="showOptionsMenu($event)">
<ion-icon name="ellipsis-vertical" slot="icon-only"> <ion-icon name="ellipsis-vertical" slot="icon-only" aria-hidden="true"></ion-icon>
</ion-icon>
</ion-button> </ion-button>
</ng-container> </ng-container>
</div> </div>
@ -92,7 +94,7 @@
[attr.aria-controls]="'addon-forum-reply-edit-form-' + uniqueId" [attr.aria-controls]="'addon-forum-reply-edit-form-' + uniqueId"
[attr.aria-expanded]="replyData.replyingTo === post.id" [attr.aria-expanded]="replyData.replyingTo === post.id"
(click)="showReplyForm()"> (click)="showReplyForm()">
<ion-icon name="fa-reply" slot="start"> <ion-icon name="fa-reply" slot="start" aria-hidden="true">
</ion-icon> {{ 'addon.mod_forum.reply' | translate }} </ion-icon> {{ 'addon.mod_forum.reply' | translate }}
</ion-button> </ion-button>
</ion-label> </ion-label>
@ -120,12 +122,11 @@
<ion-checkbox slot="end" [(ngModel)]="replyData.isprivatereply" name="isprivatereply"></ion-checkbox> <ion-checkbox slot="end" [(ngModel)]="replyData.isprivatereply" name="isprivatereply"></ion-checkbox>
</ion-item> </ion-item>
<ng-container *ngIf="forum.id && forum.maxattachments > 0"> <ng-container *ngIf="forum.id && forum.maxattachments > 0">
<ion-item-divider class="core-expandable ion-text-wrap" (click)="toggleAdvanced()"> <ion-item-divider class="core-expandable ion-text-wrap" (click)="toggleAdvanced()" [attr.aria-expanded]="advanced"
[attr.aria-label]="(advanced ? 'core.hideadvanced' : 'core.showadvanced') |translate" role="button">
<ion-label> <ion-label>
<ion-icon *ngIf="!advanced" name="fa-caret-right" slot="start"> <ion-icon *ngIf="!advanced" name="fa-caret-right" slot="start" aria-hidden="true"></ion-icon>
</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">
</ion-icon>
{{ 'addon.mod_forum.advanced' | translate }} {{ 'addon.mod_forum.advanced' | translate }}
</ion-label> </ion-label>
</ion-item-divider> </ion-item-divider>

View File

@ -228,7 +228,7 @@ export class AddonModForumPostComponent implements OnInit, OnDestroy, OnChanges
event, event,
}); });
popover.present(); await popover.present();
const result = await popover.onDidDismiss<{ action?: string }>(); const result = await popover.onDidDismiss<{ action?: string }>();
@ -265,7 +265,7 @@ export class AddonModForumPostComponent implements OnInit, OnDestroy, OnChanges
backdropDismiss: false, backdropDismiss: false,
}); });
modal.present(); await modal.present();
const result = await modal.onDidDismiss<AddonModForumReply>(); const result = await modal.onDidDismiss<AddonModForumReply>();
const data = result.data; const data = result.data;

View File

@ -3,7 +3,7 @@
<ion-title>{{ 'core.sort' | translate }}</ion-title> <ion-title>{{ 'core.sort' | translate }}</ion-title>
<ion-buttons slot="end"> <ion-buttons slot="end">
<ion-button (click)="closeModal()" [attr.aria-label]="'core.close' | translate"> <ion-button (click)="closeModal()" [attr.aria-label]="'core.close' | translate">
<ion-icon name="close" slot="icon-only"></ion-icon> <ion-icon name="fas-times" slot="icon-only" aria-hidden="true"></ion-icon>
</ion-button> </ion-button>
</ion-buttons> </ion-buttons>
</ion-toolbar> </ion-toolbar>
@ -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"
[class.core-selected-item]="selected == sortOrder.value" [attr.aria-label]="sortOrder.label | translate" [attr.aria-current]="selected == sortOrder.value ? 'page' : 'false'" [attr.aria-label]="sortOrder.label | translate"
(click)="selectSortOrder(sortOrder)"> (click)="selectSortOrder(sortOrder)" button aria-haspopup="dialog">
<ion-label> <ion-label>
<h2>{{ sortOrder.label | translate }}</h2> <h2>{{ sortOrder.label | translate }}</h2>
</ion-label> </ion-label>

View File

@ -29,6 +29,7 @@
"errorgetforum": "Error getting forum data.", "errorgetforum": "Error getting forum data.",
"errorgetgroups": "Error getting group settings.", "errorgetgroups": "Error getting group settings.",
"errorposttoallgroups": "Could not create new discussion in all groups.", "errorposttoallgroups": "Could not create new discussion in all groups.",
"favourites": "Starred",
"favouriteupdated": "Your star option has been updated.", "favouriteupdated": "Your star option has been updated.",
"forumnodiscussionsyet": "There are no discussions yet in this forum.", "forumnodiscussionsyet": "There are no discussions yet in this forum.",
"group": "Group", "group": "Group",

View File

@ -1,7 +1,7 @@
<ion-header> <ion-header>
<ion-toolbar> <ion-toolbar>
<ion-buttons slot="start"> <ion-buttons slot="start">
<ion-back-button [attr.aria-label]="'core.back' | translate"></ion-back-button> <ion-back-button [text]="'core.back' | translate"></ion-back-button>
</ion-buttons> </ion-buttons>
<ion-title *ngIf="startingPost"> <ion-title *ngIf="startingPost">
<core-format-text contextLevel="module" [text]="startingPost.subject" [contextInstanceId]="cmId" [courseId]="courseId"> <core-format-text contextLevel="module" [text]="startingPost.subject" [contextInstanceId]="cmId" [courseId]="courseId">
@ -69,7 +69,7 @@
<!-- Discussion replies found to be synchronized --> <!-- Discussion replies found to be synchronized -->
<ion-card class="core-warning-card" *ngIf="postHasOffline || hasOfflineRatings"> <ion-card class="core-warning-card" *ngIf="postHasOffline || hasOfflineRatings">
<ion-item> <ion-item>
<ion-icon name="fas-exclamation-triangle" slot="start"></ion-icon> <ion-icon name="fas-exclamation-triangle" slot="start" aria-hidden="true"></ion-icon>
<ion-label>{{ 'core.hasdatatosync' | translate:{$a: discussionStr} }}</ion-label> <ion-label>{{ 'core.hasdatatosync' | translate:{$a: discussionStr} }}</ion-label>
</ion-item> </ion-item>
</ion-card> </ion-card>
@ -77,14 +77,14 @@
<!-- Cut-off date or due date message --> <!-- Cut-off date or due date message -->
<ion-card class="core-info-card" *ngIf="availabilityMessage"> <ion-card class="core-info-card" *ngIf="availabilityMessage">
<ion-item> <ion-item>
<ion-icon name="information-circle" slot="start"></ion-icon> <ion-icon name="fas-info-circle" slot="start" aria-hidden="true"></ion-icon>
<ion-label>{{ availabilityMessage }}</ion-label> <ion-label>{{ availabilityMessage }}</ion-label>
</ion-item> </ion-item>
</ion-card> </ion-card>
<ion-card class="core-info-card" *ngIf="discussion && discussion.locked"> <ion-card class="core-info-card" *ngIf="discussion && discussion.locked">
<ion-item> <ion-item>
<ion-icon name="fa-lock" slot="start"></ion-icon> <ion-icon name="fa-lock" slot="start" aria-hidden="true"></ion-icon>
<ion-label>{{ 'addon.mod_forum.discussionlocked' | translate }}</ion-label> <ion-label>{{ 'addon.mod_forum.discussionlocked' | translate }}</ion-label>
</ion-item> </ion-item>
</ion-card> </ion-card>

View File

@ -1,7 +1,7 @@
<ion-header> <ion-header>
<ion-toolbar> <ion-toolbar>
<ion-buttons slot="start"> <ion-buttons slot="start">
<ion-back-button [attr.aria-label]="'core.back' | translate"></ion-back-button> <ion-back-button [text]="'core.back' | translate"></ion-back-button>
</ion-buttons> </ion-buttons>
<ion-title> <ion-title>
<core-format-text [text]="title" contextLevel="module" [contextInstanceId]="module.id" [courseId]="courseId"> <core-format-text [text]="title" contextLevel="module" [contextInstanceId]="module.id" [courseId]="courseId">

View File

@ -1,7 +1,7 @@
<ion-header> <ion-header>
<ion-toolbar> <ion-toolbar>
<ion-buttons slot="start"> <ion-buttons slot="start">
<ion-back-button [attr.aria-label]="'core.back' | translate"></ion-back-button> <ion-back-button [text]="'core.back' | translate"></ion-back-button>
</ion-buttons> </ion-buttons>
<ion-title>{{ 'addon.mod_forum.addanewdiscussion' | translate }}</ion-title> <ion-title>{{ 'addon.mod_forum.addanewdiscussion' | translate }}</ion-title>
<ion-buttons slot="end"> <ion-buttons slot="end">
@ -31,11 +31,10 @@
(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()" [attr.aria-expanded]="advanced"
<ion-icon *ngIf="!advanced" name="fa-caret-right" slot="start"> [attr.aria-label]="(advanced ? 'core.hideadvanced' : 'core.showadvanced') |translate" role="heading button">
</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"> <ion-icon *ngIf="advanced" name="fa-caret-down" slot="start" aria-hidden="true"></ion-icon>
</ion-icon>
<ion-label>{{ 'addon.mod_forum.advanced' | translate }}</ion-label> <ion-label>{{ 'addon.mod_forum.advanced' | translate }}</ion-label>
</ion-item-divider> </ion-item-divider>
<ng-container *ngIf="advanced"> <ng-container *ngIf="advanced">

View File

@ -2,11 +2,11 @@
<core-navbar-buttons slot="end"> <core-navbar-buttons slot="end">
<ion-button *ngIf="glossary && glossary.browsemodes && glossary.browsemodes.length > 1" (click)="openModePicker($event)" <ion-button *ngIf="glossary && glossary.browsemodes && glossary.browsemodes.length > 1" (click)="openModePicker($event)"
[attr.aria-label]="'addon.mod_glossary.browsemode' | translate"> [attr.aria-label]="'addon.mod_glossary.browsemode' | translate">
<ion-icon name="fas-sort"></ion-icon> <ion-icon name="fas-sort" aria-hidden="true"></ion-icon>
</ion-button> </ion-button>
<ion-button *ngIf="glossary" (click)="toggleSearch()" [attr.aria-label]="'addon.mod_glossary.bysearch' | translate"> <ion-button *ngIf="glossary" (click)="toggleSearch()" [attr.aria-label]="'addon.mod_glossary.bysearch' | translate">
<ion-icon name="fas-search"></ion-icon> <ion-icon name="fas-search" aria-hidden="true"></ion-icon>
</ion-button> </ion-button>
<core-context-menu> <core-context-menu>
@ -57,7 +57,7 @@
<!-- Has offline data to be synchronized --> <!-- Has offline data to be synchronized -->
<ion-card class="core-warning-card" *ngIf="hasOffline || hasOfflineRatings"> <ion-card class="core-warning-card" *ngIf="hasOffline || hasOfflineRatings">
<ion-item> <ion-item>
<ion-icon name="fas-exclamation-triangle" slot="start"></ion-icon> <ion-icon name="fas-exclamation-triangle" slot="start" aria-hidden="true"></ion-icon>
<ion-label>{{ 'core.hasdatatosync' | translate:{$a: moduleName} }}</ion-label> <ion-label>{{ 'core.hasdatatosync' | translate:{$a: moduleName} }}</ion-label>
</ion-item> </ion-item>
</ion-card> </ion-card>
@ -66,8 +66,8 @@
<ion-item-divider> <ion-item-divider>
<ion-label>{{ 'addon.mod_glossary.entriestobesynced' | translate }}</ion-label> <ion-label>{{ 'addon.mod_glossary.entriestobesynced' | translate }}</ion-label>
</ion-item-divider> </ion-item-divider>
<ion-item *ngFor="let entry of entries.offlineEntries" (click)="entries.select(entry)" detail="false" <ion-item *ngFor="let entry of entries.offlineEntries" (click)="entries.select(entry)" detail="false" button
[class.core-selected-item]="entries.isSelected(entry)"> [attr.aria-current]="entries.getItemAriaCurrent(entry)">
<ion-label> <ion-label>
<core-format-text [text]="entry.concept" contextLevel="module" [contextInstanceId]="glossary!.coursemodule" <core-format-text [text]="entry.concept" contextLevel="module" [contextInstanceId]="glossary!.coursemodule"
[courseId]="courseId"> [courseId]="courseId">
@ -82,7 +82,8 @@
{{ getDivider!(entry) }} {{ getDivider!(entry) }}
</ion-item-divider> </ion-item-divider>
<ion-item (click)="entries.select(entry)" [class.core-selected-item]="entries.isSelected(entry)" detail="false"> <ion-item button (click)="entries.select(entry)" [attr.aria-current]="entries.getItemAriaCurrent(entry)"
detail="false">
<ion-label> <ion-label>
<core-format-text [text]="entry.concept" contextLevel="module" [contextInstanceId]="glossary!.coursemodule" <core-format-text [text]="entry.concept" contextLevel="module" [contextInstanceId]="glossary!.coursemodule"
[courseId]="courseId"> [courseId]="courseId">
@ -101,7 +102,7 @@
<ion-fab slot="fixed" core-fab vertical="bottom" horizontal="end" *ngIf="canAdd"> <ion-fab slot="fixed" core-fab vertical="bottom" horizontal="end" *ngIf="canAdd">
<ion-fab-button (click)="openNewEntry()" [attr.aria-label]="'addon.mod_glossary.addentry' | translate"> <ion-fab-button (click)="openNewEntry()" [attr.aria-label]="'addon.mod_glossary.addentry' | translate">
<ion-icon name="fas-plus"></ion-icon> <ion-icon name="fas-plus" aria-hidden="true"></ion-icon>
</ion-fab-button> </ion-fab-button>
</ion-fab> </ion-fab>
</core-split-view> </core-split-view>

View File

@ -414,7 +414,7 @@ export class AddonModGlossaryIndexComponent extends CoreCourseModuleMainActivity
event, event,
}); });
popover.present(); await popover.present();
const result = await popover.onDidDismiss<AddonModGlossaryFetchMode>(); const result = await popover.onDidDismiss<AddonModGlossaryFetchMode>();

View File

@ -1,7 +1,7 @@
<ion-header> <ion-header>
<ion-toolbar> <ion-toolbar>
<ion-buttons slot="start"> <ion-buttons slot="start">
<ion-back-button [attr.aria-label]="'core.back' | translate"></ion-back-button> <ion-back-button [text]="'core.back' | translate"></ion-back-button>
</ion-buttons> </ion-buttons>
<ion-title *ngIf="glossary"> <ion-title *ngIf="glossary">
<core-format-text [text]="glossary.name" contextLevel="module" [contextInstanceId]="cmId" [courseId]="courseId"> <core-format-text [text]="glossary.name" contextLevel="module" [contextInstanceId]="cmId" [courseId]="courseId">

View File

@ -1,7 +1,7 @@
<ion-header> <ion-header>
<ion-toolbar> <ion-toolbar>
<ion-buttons slot="start"> <ion-buttons slot="start">
<ion-back-button [attr.aria-label]="'core.back' | translate"></ion-back-button> <ion-back-button [text]="'core.back' | translate"></ion-back-button>
</ion-buttons> </ion-buttons>
<ion-title *ngIf="entry"> <ion-title *ngIf="entry">
<core-format-text [text]="entry.concept" contextLevel="module" [contextInstanceId]="componentId" [courseId]="courseId"> <core-format-text [text]="entry.concept" contextLevel="module" [contextInstanceId]="componentId" [courseId]="courseId">

View File

@ -1,7 +1,7 @@
<ion-header> <ion-header>
<ion-toolbar> <ion-toolbar>
<ion-buttons slot="start"> <ion-buttons slot="start">
<ion-back-button [attr.aria-label]="'core.back' | translate"></ion-back-button> <ion-back-button [text]="'core.back' | translate"></ion-back-button>
</ion-buttons> </ion-buttons>
<ion-title> <ion-title>
<core-format-text [text]="title" contextLevel="module" [contextInstanceId]="module?.id" [courseId]="courseId"> <core-format-text [text]="title" contextLevel="module" [contextInstanceId]="module?.id" [courseId]="courseId">

View File

@ -39,7 +39,7 @@
<!-- Offline data stored. --> <!-- Offline data stored. -->
<ion-card class="core-warning-card" *ngIf="hasOffline"> <ion-card class="core-warning-card" *ngIf="hasOffline">
<ion-item> <ion-item>
<ion-icon name="fas-exclamation-triangle" slot="start"></ion-icon> <ion-icon name="fas-exclamation-triangle" slot="start" aria-hidden="true"></ion-icon>
<ion-label>{{ 'core.hasdatatosync' | translate: {$a: moduleName} }}</ion-label> <ion-label>{{ 'core.hasdatatosync' | translate: {$a: moduleName} }}</ion-label>
</ion-item> </ion-item>
</ion-card> </ion-card>
@ -47,7 +47,7 @@
<!-- Offline disabled. --> <!-- Offline disabled. -->
<ion-card class="core-warning-card" *ngIf="!siteCanDownload && playing"> <ion-card class="core-warning-card" *ngIf="!siteCanDownload && playing">
<ion-item> <ion-item>
<ion-icon name="fas-exclamation-triangle" slot="start"></ion-icon> <ion-icon name="fas-exclamation-triangle" slot="start" aria-hidden="true"></ion-icon>
<ion-label> <ion-label>
{{ 'core.h5p.offlinedisabled' | translate }} {{ 'addon.mod_h5pactivity.offlinedisabledwarning' | translate }} {{ 'core.h5p.offlinedisabled' | translate }} {{ 'addon.mod_h5pactivity.offlinedisabledwarning' | translate }}
</ion-label> </ion-label>
@ -57,7 +57,7 @@
<!-- Preview mode. --> <!-- Preview mode. -->
<ion-card class="core-warning-card" *ngIf="accessInfo && !trackComponent"> <ion-card class="core-warning-card" *ngIf="accessInfo && !trackComponent">
<ion-item> <ion-item>
<ion-icon name="fas-exclamation-triangle" slot="start"></ion-icon> <ion-icon name="fas-exclamation-triangle" slot="start" aria-hidden="true"></ion-icon>
<ion-label> <ion-label>
{{ 'addon.mod_h5pactivity.previewmode' | translate }} {{ 'addon.mod_h5pactivity.previewmode' | translate }}
</ion-label> </ion-label>

View File

@ -1,7 +1,7 @@
<ion-header> <ion-header>
<ion-toolbar> <ion-toolbar>
<ion-buttons slot="start"> <ion-buttons slot="start">
<ion-back-button [attr.aria-label]="'core.back' | translate"></ion-back-button> <ion-back-button [text]="'core.back' | translate"></ion-back-button>
</ion-buttons> </ion-buttons>
<ion-title> <ion-title>
<core-format-text *ngIf="h5pActivity" [text]="h5pActivity.name" contextLevel="module" <core-format-text *ngIf="h5pActivity" [text]="h5pActivity.name" contextLevel="module"
@ -18,7 +18,7 @@
<ng-container *ngIf="attempt"> <ng-container *ngIf="attempt">
<!-- Attempt number and user that did the attempt. --> <!-- Attempt number and user that did the attempt. -->
<ion-item class="ion-text-wrap" *ngIf="user" core-user-link [userId]="user.id" [courseId]="courseId" <ion-item class="ion-text-wrap" *ngIf="user" core-user-link [userId]="user.id" [courseId]="courseId"
[title]="user.fullname"> [attr.aria-label]="user.fullname">
<core-user-avatar [user]="user" slot="start" [courseId]="courseId"></core-user-avatar> <core-user-avatar [user]="user" slot="start" [courseId]="courseId"></core-user-avatar>
<ion-label> <ion-label>
<h2>{{ 'addon.mod_h5pactivity.attempt' | translate }} #{{attempt.attempt}}: {{user.fullname}}</h2> <h2>{{ 'addon.mod_h5pactivity.attempt' | translate }} #{{attempt.attempt}}: {{user.fullname}}</h2>
@ -63,11 +63,11 @@
<ion-label> <ion-label>
<h2>{{ 'addon.mod_h5pactivity.outcome' | translate }}</h2> <h2>{{ 'addon.mod_h5pactivity.outcome' | translate }}</h2>
<p *ngIf="attempt.success !== null && attempt.success" > <p *ngIf="attempt.success !== null && attempt.success" >
<ion-icon name="fa-check-circle"></ion-icon> <ion-icon name="fa-check-circle" aria-hidden="true"></ion-icon>
{{ 'addon.mod_h5pactivity.attempt_success_pass' | translate }} {{ 'addon.mod_h5pactivity.attempt_success_pass' | translate }}
</p> </p>
<p *ngIf="attempt.success !== null && !attempt.success" > <p *ngIf="attempt.success !== null && !attempt.success" >
<ion-icon name="far-circle"></ion-icon> <ion-icon name="far-circle" aria-hidden="true"></ion-icon>
{{ 'addon.mod_h5pactivity.attempt_success_fail' | translate }} {{ 'addon.mod_h5pactivity.attempt_success_fail' | translate }}
</p> </p>
<p *ngIf="attempt.success === null" > <p *ngIf="attempt.success === null" >
@ -152,7 +152,7 @@
<!-- Result doesn't support tracking. --> <!-- Result doesn't support tracking. -->
<ion-item class="ion-text-wrap core-warning-item" *ngIf="!result.track" lines="none"> <ion-item class="ion-text-wrap core-warning-item" *ngIf="!result.track" lines="none">
<ion-icon slot="start" name="fas-exclamation-triangle" color="warning"></ion-icon> <ion-icon slot="start" name="fas-exclamation-triangle" color="warning" aria-hidden="true"></ion-icon>
<ion-label> <ion-label>
{{ 'addon.mod_h5pactivity.no_compatible_track' | translate:{$a: result.interactiontype} }} {{ 'addon.mod_h5pactivity.no_compatible_track' | translate:{$a: result.interactiontype} }}
</ion-label> </ion-label>

View File

@ -1,7 +1,7 @@
<ion-header> <ion-header>
<ion-toolbar> <ion-toolbar>
<ion-buttons slot="start"> <ion-buttons slot="start">
<ion-back-button [attr.aria-label]="'core.back' | translate"></ion-back-button> <ion-back-button [text]="'core.back' | translate"></ion-back-button>
</ion-buttons> </ion-buttons>
<ion-title> <ion-title>
<core-format-text [text]="title" contextLevel="module" [contextInstanceId]="module.id" [courseId]="courseId"> <core-format-text [text]="title" contextLevel="module" [contextInstanceId]="module.id" [courseId]="courseId">

View File

@ -1,7 +1,7 @@
<ion-header> <ion-header>
<ion-toolbar> <ion-toolbar>
<ion-buttons slot="start"> <ion-buttons slot="start">
<ion-back-button [attr.aria-label]="'core.back' | translate"></ion-back-button> <ion-back-button [text]="'core.back' | translate"></ion-back-button>
</ion-buttons> </ion-buttons>
<ion-title> <ion-title>
<core-format-text *ngIf="h5pActivity" [text]="h5pActivity.name" contextLevel="module" <core-format-text *ngIf="h5pActivity" [text]="h5pActivity.name" contextLevel="module"
@ -17,7 +17,7 @@
<core-loading [hideUntil]="loaded"> <core-loading [hideUntil]="loaded">
<!-- User viewed. --> <!-- User viewed. -->
<ion-item class="ion-text-wrap" *ngIf="user && !isCurrentUser" core-user-link [userId]="user.id" [courseId]="courseId" <ion-item class="ion-text-wrap" *ngIf="user && !isCurrentUser" core-user-link [userId]="user.id" [courseId]="courseId"
[title]="user.fullname"> [attr.aria-label]="user.fullname">
<core-user-avatar [user]="user" slot="start" [courseId]="courseId"></core-user-avatar> <core-user-avatar [user]="user" slot="start" [courseId]="courseId"></core-user-avatar>
<ion-label> <ion-label>
<h2>{{ user.fullname }}</h2> <h2>{{ user.fullname }}</h2>

Some files were not shown because too many files have changed in this diff Show More