Merge pull request #3011 from NoelDeMartin/MOBILE-3833

MOBILE-3833: Configure formatting & implement privacy provider for behat
main
Pau Ferrer Ocaña 2021-12-01 16:09:23 +01:00 committed by GitHub
commit 683c5f4e5a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
71 changed files with 415 additions and 498 deletions

18
.vscode/settings.json vendored
View File

@ -1,5 +1,23 @@
{ {
/**
* Formatting.
*/
"editor.defaultFormatter": "dbaeumer.vscode-eslint",
"[html]": {
"editor.defaultFormatter": "vscode.html-language-features",
},
"editor.formatOnSave": true,
"eslint.format.enable": true,
"html.format.endWithNewline": true,
"html.format.wrapLineLength": 140,
"files.trimFinalNewlines": true,
"files.insertFinalNewline": true,
"files.trimTrailingWhitespace": true,
/**
* Config files.
*/
"files.associations": { "files.associations": {
"moodle.config.json": "jsonc", "moodle.config.json": "jsonc",
"moodle.config.*.json": "jsonc", "moodle.config.*.json": "jsonc",

View File

@ -0,0 +1,32 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
namespace local_moodleappbehat\privacy;
use core_privacy\local\metadata\null_provider;
defined('MOODLE_INTERNAL') || die();
class provider implements null_provider {
/**
* @inheritdoc
*/
public static function get_reason() : string {
return 'privacy_metadata';
}
}

View File

@ -1,3 +1,4 @@
<?php <?php
$string['pluginname'] = 'Moodle App Behat (auto-generated)'; $string['pluginname'] = 'Moodle App Behat (auto-generated)';
$string['privacy_metadata'] = 'This plugin should only be used in development environments, and it does not store any user data.';

View File

@ -4,8 +4,7 @@
</ion-label> </ion-label>
</ion-item-divider> </ion-item-divider>
<core-loading [hideUntil]="loaded" [fullscreen]="false"> <core-loading [hideUntil]="loaded" [fullscreen]="false">
<ion-item class="ion-text-wrap item-media" *ngFor="let entry of entries" detail="true" button <ion-item class="ion-text-wrap item-media" *ngFor="let entry of entries" detail="true" button (click)="gotoCoureListModType(entry)">
(click)="gotoCoureListModType(entry)">
<core-mod-icon slot="start" [modicon]="entry.icon" [modname]="entry.modName" [showAlt]="false"> <core-mod-icon slot="start" [modicon]="entry.icon" [modname]="entry.modName" [showAlt]="false">
</core-mod-icon> </core-mod-icon>
<ion-label>{{ entry.name }}</ion-label> <ion-label>{{ entry.name }}</ion-label>

View File

@ -1,25 +1,23 @@
<ion-item-divider sticky="true"> <ion-item-divider sticky="true">
<ion-label><h2>{{ 'addon.block_recentlyaccesseditems.pluginname' | translate }}</h2></ion-label> <ion-label>
<h2>{{ 'addon.block_recentlyaccesseditems.pluginname' | translate }}</h2>
</ion-label>
<div slot="end"> <div slot="end">
<core-horizontal-scroll-controls #scrollControls [aria-controls]="scrollElementId"> <core-horizontal-scroll-controls #scrollControls [aria-controls]="scrollElementId">
</core-horizontal-scroll-controls> </core-horizontal-scroll-controls>
</div> </div>
</ion-item-divider> </ion-item-divider>
<core-loading [hideUntil]="loaded" [fullscreen]="false"> <core-loading [hideUntil]="loaded" [fullscreen]="false">
<div <div [id]="scrollElementId" [hidden]="!items || items.length === 0" class="core-horizontal-scroll"
[id]="scrollElementId" (scroll)="scrollControls.updateScrollPosition()">
[hidden]="!items || items.length === 0"
class="core-horizontal-scroll"
(scroll)="scrollControls.updateScrollPosition()"
>
<div *ngIf="items" (onResize)="scrollControls.updateScrollPosition()" class="flex-row"> <div *ngIf="items" (onResize)="scrollControls.updateScrollPosition()" class="flex-row">
<div class="safe-area-pseudo-padding-start"></div> <div class="safe-area-pseudo-padding-start"></div>
<div *ngFor="let item of items" class="core-horizontal-scroll-item"> <div *ngFor="let item of items" class="core-horizontal-scroll-item">
<ion-card> <ion-card>
<ion-item class="core-course-module-handler item-media ion-text-wrap" detail="false" (click)="action($event, item)" <ion-item class="core-course-module-handler item-media ion-text-wrap" detail="false" (click)="action($event, item)"
button> button>
<core-mod-icon slot="start" *ngIf="item.iconUrl" [modicon]="item.iconUrl" <core-mod-icon slot="start" *ngIf="item.iconUrl" [modicon]="item.iconUrl" [modname]="item.modname"
[modname]="item.modname" [componentId]="item.cmid" [showAlt]="false"> [componentId]="item.cmid" [showAlt]="false">
</core-mod-icon> </core-mod-icon>
<ion-label> <ion-label>
<!-- Add the icon title so accessibility tools read it. --> <!-- Add the icon title so accessibility tools read it. -->

View File

@ -7,8 +7,8 @@
<ng-container *ngIf="mainMenuBlock"> <ng-container *ngIf="mainMenuBlock">
<ion-item class="ion-text-wrap" *ngIf="mainMenuBlock.summary"> <ion-item class="ion-text-wrap" *ngIf="mainMenuBlock.summary">
<ion-label> <ion-label>
<core-format-text [text]="mainMenuBlock.summary" [component]="component" [componentId]="siteHomeId" <core-format-text [text]="mainMenuBlock.summary" [component]="component" [componentId]="siteHomeId" contextLevel="course"
contextLevel="course" [contextInstanceId]="siteHomeId"></core-format-text> [contextInstanceId]="siteHomeId"></core-format-text>
</ion-label> </ion-label>
</ion-item> </ion-item>

View File

@ -1,10 +1,9 @@
<!-- Add buttons to the nav bar. --> <!-- Add buttons to the nav bar. -->
<core-navbar-buttons slot="end" prepend> <core-navbar-buttons slot="end" prepend>
<core-context-menu> <core-context-menu>
<core-context-menu-item *ngIf="canNavigate && !isCurrentMonth && displayNavButtons" [priority]="900" <core-context-menu-item *ngIf="canNavigate && !isCurrentMonth && displayNavButtons" [priority]="900"
[content]="'addon.calendar.currentmonth' | translate" iconAction="fas-calendar-day" [content]="'addon.calendar.currentmonth' | translate" iconAction="fas-calendar-day" (action)="goToCurrentMonth()">
(action)="goToCurrentMonth()"></core-context-menu-item> </core-context-menu-item>
</core-context-menu> </core-context-menu>
</core-navbar-buttons> </core-navbar-buttons>
@ -46,20 +45,13 @@
<ion-row *ngFor="let week of weeks" class="addon-calendar-week" role="row"> <ion-row *ngFor="let week of weeks" class="addon-calendar-week" role="row">
<!-- Empty slots (first week). --> <!-- Empty slots (first week). -->
<ion-col *ngFor="let value of week.prepadding" class="dayblank addon-calendar-day" role="cell"></ion-col> <ion-col *ngFor="let value of week.prepadding" class="dayblank addon-calendar-day" role="cell"></ion-col>
<ion-col <ion-col *ngFor="let day of week.days" class="addon-calendar-day ion-text-center" [ngClass]='{
*ngFor="let day of week.days"
class="addon-calendar-day ion-text-center"
[ngClass]='{
"hasevents": day.hasevents, "hasevents": day.hasevents,
"today": isCurrentMonth && day.istoday, "today": isCurrentMonth && day.istoday,
"weekend": day.isweekend, "weekend": day.isweekend,
"duration_finish": day.haslastdayofevent "duration_finish": day.haslastdayofevent
}' }' [class.addon-calendar-event-past-day]="isPastMonth || day.ispast" role="cell" tabindex="0"
[class.addon-calendar-event-past-day]="isPastMonth || day.ispast" (ariaButtonClick)="dayClicked(day.mday)">
role="cell"
tabindex="0"
(ariaButtonClick)="dayClicked(day.mday)"
>
<p class="addon-calendar-day-number" role="button"> <p class="addon-calendar-day-number" role="button">
<span aria-hidden="true">{{ day.mday }}</span> <span aria-hidden="true">{{ day.mday }}</span>
<span class="sr-only">{{ day.periodName | translate }}</span> <span class="sr-only">{{ day.periodName | translate }}</span>
@ -72,19 +64,14 @@
<!-- 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">
<div <div *ngIf="index < 3 || day.filteredEvents.length == 4" class="addon-calendar-event"
*ngIf="index < 3 || day.filteredEvents.length == 4" [class.addon-calendar-event-past]="event.ispast" role="button" tabindex="0"
class="addon-calendar-event" (ariaButtonClick)="eventClicked(event, $event)">
[class.addon-calendar-event-past]="event.ispast"
role="button"
tabindex="0"
(ariaButtonClick)="eventClicked(event, $event)"
>
<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="fas-clock" <ion-icon *ngIf="event.offline && !event.deleted" name="fas-clock"
[attr.aria-label]="'core.notsent' | translate"></ion-icon> [attr.aria-label]="'core.notsent' | translate"></ion-icon>
<ion-icon *ngIf="event.deleted" name="fas-trash" <ion-icon *ngIf="event.deleted" name="fas-trash" [attr.aria-label]="'core.deletedoffline' | translate">
[attr.aria-label]="'core.deletedoffline' | translate"></ion-icon> </ion-icon>
<span class="addon-calendar-event-time"> <span class="addon-calendar-event-time">
{{ event.timestart * 1000 | coreFormatDate: timeFormat }} {{ event.timestart * 1000 | coreFormatDate: timeFormat }}
</span> </span>

View File

@ -8,7 +8,9 @@
<ng-container *ngIf="filter.course || filter.category || filter.group"> <ng-container *ngIf="filter.course || filter.category || filter.group">
<ion-radio-group [(ngModel)]="courseId" (ionChange)="onChange()"> <ion-radio-group [(ngModel)]="courseId" (ionChange)="onChange()">
<ion-item class="ion-text-wrap" *ngFor="let course of courses"> <ion-item class="ion-text-wrap" *ngFor="let course of courses">
<ion-label><core-format-text [text]="course.fullname"></core-format-text></ion-label> <ion-label>
<core-format-text [text]="course.fullname"></core-format-text>
</ion-label>
<ion-radio slot="end" [value]="course.id"></ion-radio> <ion-radio slot="end" [value]="course.id"></ion-radio>
</ion-item> </ion-item>
</ion-radio-group> </ion-radio-group>

View File

@ -31,8 +31,8 @@
<!-- View the submission tab. --> <!-- View the submission tab. -->
<core-tab [title]="'addon.mod_assign.submission' | translate" id="submission"> <core-tab [title]="'addon.mod_assign.submission' | translate" id="submission">
<ng-template> <ng-template>
<addon-mod-assign-submission-plugin *ngFor="let plugin of submissionPlugins" <addon-mod-assign-submission-plugin *ngFor="let plugin of submissionPlugins" [assign]="assign" [submission]="userSubmission"
[assign]="assign" [submission]="userSubmission" [plugin]="plugin"> [plugin]="plugin">
</addon-mod-assign-submission-plugin> </addon-mod-assign-submission-plugin>
<!-- Render some data about the submission. --> <!-- Render some data about the submission. -->
@ -56,8 +56,7 @@
<p *ngIf="assign!.intro" <p *ngIf="assign!.intro"
[innerHTML]="'addon.mod_assign.allowsubmissionsfromdatesummary' | translate: {'$a': fromDate}"> [innerHTML]="'addon.mod_assign.allowsubmissionsfromdatesummary' | translate: {'$a': fromDate}">
</p> </p>
<p *ngIf="!assign!.intro" <p *ngIf="!assign!.intro" [innerHTML]="'addon.mod_assign.allowsubmissionsanddescriptionfromdatesummary' | translate:
[innerHTML]="'addon.mod_assign.allowsubmissionsanddescriptionfromdatesummary' | translate:
{'$a': fromDate}"> {'$a': fromDate}">
</p> </p>
</ion-label> </ion-label>
@ -66,8 +65,8 @@
<ion-item class="ion-text-wrap" *ngIf="showDates && assign!.duedate && !isSubmittedForGrading"> <ion-item class="ion-text-wrap" *ngIf="showDates && assign!.duedate && !isSubmittedForGrading">
<ion-label> <ion-label>
<h2>{{ 'addon.mod_assign.duedate' | translate }}</h2> <h2>{{ 'addon.mod_assign.duedate' | translate }}</h2>
<p *ngIf="assign!.duedate" >{{ assign!.duedate * 1000 | coreFormatDate }}</p> <p *ngIf="assign!.duedate">{{ assign!.duedate * 1000 | coreFormatDate }}</p>
<p *ngIf="!assign!.duedate" >{{ 'addon.mod_assign.duedateno' | translate }}</p> <p *ngIf="!assign!.duedate">{{ 'addon.mod_assign.duedateno' | translate }}</p>
</ion-label> </ion-label>
</ion-item> </ion-item>
@ -78,8 +77,7 @@
</ion-label> </ion-label>
</ion-item> </ion-item>
<ion-item class="ion-text-wrap" <ion-item class="ion-text-wrap" *ngIf="assign!.duedate && lastAttempt?.extensionduedate && !isSubmittedForGrading">
*ngIf="assign!.duedate && lastAttempt?.extensionduedate && !isSubmittedForGrading">
<ion-label> <ion-label>
<h2>{{ 'addon.mod_assign.extensionduedate' | translate }}</h2> <h2>{{ 'addon.mod_assign.extensionduedate' | translate }}</h2>
<p>{{ lastAttempt!.extensionduedate * 1000 | coreFormatDate }}</p> <p>{{ lastAttempt!.extensionduedate * 1000 | coreFormatDate }}</p>
@ -105,13 +103,11 @@
<ion-label> <ion-label>
<div *ngIf="!unsupportedEditPlugins.length && !showErrorStatementEdit"> <div *ngIf="!unsupportedEditPlugins.length && !showErrorStatementEdit">
<!-- If has offline data, show edit. --> <!-- If has offline data, show edit. -->
<ion-button expand="block" class="ion-text-wrap" color="primary" *ngIf="hasOffline" <ion-button expand="block" class="ion-text-wrap" color="primary" *ngIf="hasOffline" (click)="goToEdit()">
(click)="goToEdit()">
{{ 'addon.mod_assign.editsubmission' | translate }} {{ 'addon.mod_assign.editsubmission' | translate }}
</ion-button> </ion-button>
<!-- If no submission or is new, show add submission. --> <!-- If no submission or is new, show add submission. -->
<ion-button expand="block" class="ion-text-wrap" color="primary" <ion-button expand="block" class="ion-text-wrap" color="primary" *ngIf="!hasOffline &&
*ngIf="!hasOffline &&
(!userSubmission || !userSubmission!.status || userSubmission!.status == statusNew)" (!userSubmission || !userSubmission!.status || userSubmission!.status == statusNew)"
(click)="goToEdit()"> (click)="goToEdit()">
{{ 'addon.mod_assign.addsubmission' | translate }} {{ 'addon.mod_assign.addsubmission' | translate }}
@ -127,8 +123,7 @@
</ion-button> </ion-button>
</ng-container> </ng-container>
<!-- Else show editsubmission. --> <!-- Else show editsubmission. -->
<ion-button expand="block" class="ion-text-wrap" color="primary" <ion-button expand="block" class="ion-text-wrap" color="primary" *ngIf="!hasOffline && userSubmission && userSubmission!.status &&
*ngIf="!hasOffline && userSubmission && userSubmission!.status &&
userSubmission!.status != statusNew && userSubmission!.status != statusNew &&
userSubmission!.status != statusReopened" (click)="goToEdit()"> userSubmission!.status != statusReopened" (click)="goToEdit()">
{{ 'addon.mod_assign.editsubmission' | translate }} {{ 'addon.mod_assign.editsubmission' | translate }}
@ -156,8 +151,7 @@
<!-- Submit button. --> <!-- Submit button. -->
<ion-item class="ion-text-wrap" *ngIf="!showErrorStatementSubmit"> <ion-item class="ion-text-wrap" *ngIf="!showErrorStatementSubmit">
<ion-label> <ion-label>
<ion-button expand="block" class="ion-text-wrap" <ion-button expand="block" class="ion-text-wrap" (click)="submitForGrading(acceptStatement)">
(click)="submitForGrading(acceptStatement)">
{{ 'addon.mod_assign.submitassignment' | translate }} {{ 'addon.mod_assign.submitassignment' | translate }}
</ion-button> </ion-button>
<p>{{ 'addon.mod_assign.submitassignment_help' | translate }}</p> <p>{{ 'addon.mod_assign.submitassignment_help' | translate }}</p>
@ -175,14 +169,18 @@
<!-- Team members that need to submit it too. --> <!-- Team members that need to submit it too. -->
<ion-item-divider class="ion-text-wrap" *ngIf="membersToSubmit && membersToSubmit.length > 0"> <ion-item-divider class="ion-text-wrap" *ngIf="membersToSubmit && membersToSubmit.length > 0">
<ion-label><h2>{{ 'addon.mod_assign.userswhoneedtosubmit' | translate: {$a: ''} }}</h2></ion-label> <ion-label>
<h2>{{ 'addon.mod_assign.userswhoneedtosubmit' | translate: {$a: ''} }}</h2>
</ion-label>
</ion-item-divider> </ion-item-divider>
<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"
[courseId]="courseId" [attr.aria-label]="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><h2>{{ user.fullname }}</h2></ion-label> <ion-label>
<h2>{{ user.fullname }}</h2>
</ion-label>
</ion-item> </ion-item>
</ng-container> </ng-container>
</ng-container> </ng-container>
@ -196,12 +194,13 @@
<!-- Submission is locked. --> <!-- Submission is locked. -->
<ion-item class="ion-text-wrap" *ngIf="lastAttempt?.locked"> <ion-item class="ion-text-wrap" *ngIf="lastAttempt?.locked">
<ion-label><h2>{{ 'addon.mod_assign.submissionslocked' | translate }}</h2></ion-label> <ion-label>
<h2>{{ 'addon.mod_assign.submissionslocked' | translate }}</h2>
</ion-label>
</ion-item> </ion-item>
<!-- Editing status. --> <!-- Editing status. -->
<ion-item class="ion-text-wrap" <ion-item class="ion-text-wrap" *ngIf="lastAttempt && isSubmittedForGrading && lastAttempt!.caneditowner !== undefined"
*ngIf="lastAttempt && isSubmittedForGrading && lastAttempt!.caneditowner !== undefined"
[ngClass]="{submissioneditable: lastAttempt!.caneditowner, submissionnoteditable: !lastAttempt!.caneditowner}"> [ngClass]="{submissioneditable: lastAttempt!.caneditowner, submissionnoteditable: !lastAttempt!.caneditowner}">
<ion-label> <ion-label>
<h2>{{ 'addon.mod_assign.editingstatus' | translate }}</h2> <h2>{{ 'addon.mod_assign.editingstatus' | translate }}</h2>
@ -220,7 +219,9 @@
*ngIf="feedback?.gradefordisplay && (!isGrading || grade.method != 'simple')"> *ngIf="feedback?.gradefordisplay && (!isGrading || grade.method != 'simple')">
<ion-label> <ion-label>
<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()"
[attr.aria-label]="'core.showadvanced' |translate"> [attr.aria-label]="'core.showadvanced' |translate">
@ -243,7 +244,9 @@
<!-- Grade using a scale. --> <!-- Grade using a scale. -->
<ion-item class="ion-text-wrap" *ngIf="grade.method == 'simple' && grade.scale"> <ion-item class="ion-text-wrap" *ngIf="grade.method == 'simple' && grade.scale">
<ion-label><h2>{{ 'addon.mod_assign.grade' | translate }}</h2></ion-label> <ion-label>
<h2>{{ 'addon.mod_assign.grade' | translate }}</h2>
</ion-label>
<ion-select [(ngModel)]="grade.grade" interface="action-sheet" [disabled]="grade.disabled" <ion-select [(ngModel)]="grade.grade" interface="action-sheet" [disabled]="grade.disabled"
[interfaceOptions]="{header: 'addon.mod_assign.grade' | translate}"> [interfaceOptions]="{header: 'addon.mod_assign.grade' | translate}">
<ion-select-option *ngFor="let grade of grade.scale" [value]="grade.value"> <ion-select-option *ngFor="let grade of grade.scale" [value]="grade.value">
@ -254,10 +257,11 @@
<!-- Outcomes. --> <!-- Outcomes. -->
<ion-item class="ion-text-wrap" *ngFor="let outcome of gradeInfo!.outcomes"> <ion-item class="ion-text-wrap" *ngFor="let outcome of gradeInfo!.outcomes">
<ion-label><h2>{{ outcome.name }}</h2></ion-label> <ion-label>
<ion-select *ngIf="canSaveGrades && outcome.itemNumber" [(ngModel)]="outcome.selectedId" <h2>{{ outcome.name }}</h2>
interface="action-sheet" [disabled]="gradeInfo!.disabled" </ion-label>
[interfaceOptions]="{header: outcome.name }"> <ion-select *ngIf="canSaveGrades && outcome.itemNumber" [(ngModel)]="outcome.selectedId" interface="action-sheet"
[disabled]="gradeInfo!.disabled" [interfaceOptions]="{header: outcome.name }">
<ion-select-option *ngFor="let grade of outcome.options" [value]="grade.value"> <ion-select-option *ngFor="let grade of outcome.options" [value]="grade.value">
{{grade.label}} {{grade.label}}
</ion-select-option> </ion-select-option>
@ -322,7 +326,7 @@
</p> </p>
</ion-label> </ion-label>
</ion-item> </ion-item>
<ion-item *ngIf="canSaveGrades && allowAddAttempt" > <ion-item *ngIf="canSaveGrades && allowAddAttempt">
<ion-label>{{ 'addon.mod_assign.addattempt' | translate }}</ion-label> <ion-label>{{ 'addon.mod_assign.addattempt' | translate }}</ion-label>
<ion-toggle [(ngModel)]="grade.addAttempt"></ion-toggle> <ion-toggle [(ngModel)]="grade.addAttempt"></ion-toggle>
</ion-item> </ion-item>

View File

@ -3,8 +3,7 @@
<ion-label> <ion-label>
<h2>{{plugin.name}}</h2> <h2>{{plugin.name}}</h2>
<ng-container> <ng-container>
<core-file *ngFor="let file of files" [file]="file" [component]="component" [componentId]="assign.cmid" <core-file *ngFor="let file of files" [file]="file" [component]="component" [componentId]="assign.cmid" [alwaysDownload]="true">
[alwaysDownload]="true">
</core-file> </core-file>
</ng-container> </ng-container>
</ion-label> </ion-label>

View File

@ -3,8 +3,7 @@
<ion-label> <ion-label>
<h2>{{plugin.name}}</h2> <h2>{{plugin.name}}</h2>
<ng-container> <ng-container>
<core-file *ngFor="let file of files" [file]="file" [component]="component" [componentId]="assign.cmid" <core-file *ngFor="let file of files" [file]="file" [component]="component" [componentId]="assign.cmid" [alwaysDownload]="true">
[alwaysDownload]="true">
</core-file> </core-file>
</ng-container> </ng-container>
</ion-label> </ion-label>

View File

@ -1,8 +1,8 @@
<ion-item *ngIf="commentsEnabled" class="ion-text-wrap" (click)="showComments($event)" detail="true" button> <ion-item *ngIf="commentsEnabled" class="ion-text-wrap" (click)="showComments($event)" detail="true" 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" [itemId]="submission.id"
[itemId]="submission.id" area="submission_comments" [title]="plugin.name" [courseId]="assign.course"> area="submission_comments" [title]="plugin.name" [courseId]="assign.course">
</core-comments> </core-comments>
</ion-label> </ion-label>
</ion-item> </ion-item>

View File

@ -11,7 +11,9 @@
<!-- Edit --> <!-- Edit -->
<div *ngIf="edit"> <div *ngIf="edit">
<ion-item-divider class="ion-text-wrap" sticky="true"> <ion-item-divider class="ion-text-wrap" sticky="true">
<ion-label><h2>{{ plugin.name }}</h2></ion-label> <ion-label>
<h2>{{ plugin.name }}</h2>
</ion-label>
</ion-item-divider> </ion-item-divider>
<core-attachments [files]="files" [maxSize]="maxSize" [maxSubmissions]="maxSubmissions" [courseId]="assign.course" <core-attachments [files]="files" [maxSize]="maxSize" [maxSubmissions]="maxSubmissions" [courseId]="assign.course"
[component]="component" [componentId]="assign.cmid" [acceptedTypes]="acceptedTypes" [allowOffline]="allowOffline"> [component]="component" [componentId]="assign.cmid" [acceptedTypes]="acceptedTypes" [allowOffline]="allowOffline">

View File

@ -24,7 +24,7 @@
</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"
component="mod_data" [itemId]="entry.id" area="database_entry" [courseId]="database.course"> component="mod_data" [itemId]="entry.id" area="database_entry" [courseId]="database.course">
</core-comments> </core-comments>
<span *ngIf="action == 'timeadded'">{{ entry.timecreated * 1000 | coreFormatDate }}</span> <span *ngIf="action == 'timeadded'">{{ entry.timecreated * 1000 | coreFormatDate }}</span>

View File

@ -1,7 +1,7 @@
<span *ngIf="editMode && form"> <span *ngIf="editMode && form">
<span [core-mark-required]="field.required" class="core-mark-required"></span> <span [core-mark-required]="field.required" class="core-mark-required"></span>
<core-attachments [files]="files" [maxSize]="maxSizeBytes" maxSubmissions="1" [component]="component" <core-attachments [files]="files" [maxSize]="maxSizeBytes" maxSubmissions="1" [component]="component" [componentId]="componentId"
[componentId]="componentId" [allowOffline]="true" [courseId]="database?.course"> [allowOffline]="true" [courseId]="database?.course">
</core-attachments> </core-attachments>
<core-input-errors *ngIf="error" [errorText]="error"></core-input-errors> <core-input-errors *ngIf="error" [errorText]="error"></core-input-errors>
</span> </span>

View File

@ -1,12 +1,12 @@
<span *ngIf="editMode && form" [formGroup]="form"> <span *ngIf="editMode && form" [formGroup]="form">
<span [core-mark-required]="field.required" class="core-mark-required"></span> <span [core-mark-required]="field.required" class="core-mark-required"></span>
<core-attachments [files]="files" [maxSize]="maxSizeBytes" maxSubmissions="1" [component]="component" <core-attachments [files]="files" [maxSize]="maxSizeBytes" maxSubmissions="1" [component]="component" [componentId]="componentId"
[componentId]="componentId" [allowOffline]="true" acceptedTypes="image" [courseId]="database?.course"> [allowOffline]="true" acceptedTypes="image" [courseId]="database?.course">
</core-attachments> </core-attachments>
<core-input-errors *ngIf="error" [errorText]="error"></core-input-errors> <core-input-errors *ngIf="error" [errorText]="error"></core-input-errors>
<ion-label position="stacked">{{ 'addon.mod_data.alttext' | translate }}</ion-label> <ion-label position="stacked">{{ 'addon.mod_data.alttext' | translate }}</ion-label>
<ion-input type="text" [formControlName]="'f_'+field.id+'_alttext'" [placeholder]=" 'addon.mod_data.alttext' | translate" > <ion-input type="text" [formControlName]="'f_'+field.id+'_alttext'" [placeholder]=" 'addon.mod_data.alttext' | translate">
</ion-input> </ion-input>
</span> </span>
@ -15,8 +15,8 @@
</span> </span>
<button class="as-link" *ngIf="listMode && imageUrl" (click)="navigateEntry()"> <button class="as-link" *ngIf="listMode && imageUrl" (click)="navigateEntry()">
<img [src]="imageUrl" [alt]="title" class="core-media-adapt-width listMode_picture" core-external-content/> <img [src]="imageUrl" [alt]="title" class="core-media-adapt-width listMode_picture" core-external-content />
</button> </button>
<img *ngIf="showMode && imageUrl" [src]="imageUrl" [alt]="title" class="core-media-adapt-width listMode_picture" <img *ngIf="showMode && imageUrl" [src]="imageUrl" [alt]="title" class="core-media-adapt-width listMode_picture" [attr.width]="width"
[attr.width]="width" [attr.height]="height" core-external-content/> [attr.height]="height" core-external-content />

View File

@ -2,9 +2,9 @@
<ion-input *ngIf="searchMode" type="text" [placeholder]="field.name" [formControlName]="'f_'+field.id"></ion-input> <ion-input *ngIf="searchMode" type="text" [placeholder]="field.name" [formControlName]="'f_'+field.id"></ion-input>
<span *ngIf="editMode" [core-mark-required]="field.required" class="core-mark-required"></span> <span *ngIf="editMode" [core-mark-required]="field.required" class="core-mark-required"></span>
<core-rich-text-editor *ngIf="editMode" [control]="form.controls['f_'+field.id]" [placeholder]="field.name" <core-rich-text-editor *ngIf="editMode" [control]="form.controls['f_'+field.id]" [placeholder]="field.name" [name]="'f_'+field.id"
[name]="'f_'+field.id" [component]="component" [componentId]="componentId" [autoSave]="true" [component]="component" [componentId]="componentId" [autoSave]="true" contextLevel="module" [contextInstanceId]="componentId"
contextLevel="module" [contextInstanceId]="componentId" [elementId]="'field_'+field.id" ngDefaultControl> [elementId]="'field_'+field.id" ngDefaultControl>
</core-rich-text-editor> </core-rich-text-editor>
<core-input-errors *ngIf="error && editMode" [control]="form.controls['f_'+field.id]" [errorText]="error"></core-input-errors> <core-input-errors *ngIf="error && editMode" [control]="form.controls['f_'+field.id]" [errorText]="error"></core-input-errors>
</span> </span>

View File

@ -17,8 +17,7 @@
<p class="item-heading">{{ 'core.numwords' | translate: {'$a': wordCount} }}</p> <p class="item-heading">{{ 'core.numwords' | translate: {'$a': wordCount} }}</p>
</ion-label> </ion-label>
</ion-item> </ion-item>
<ion-item class="ion-text-wrap" [href]="url" *ngIf="url" core-link capture="false" button detail="false" <ion-item class="ion-text-wrap" [href]="url" *ngIf="url" core-link capture="false" button detail="false" [showBrowserWarning]="false">
[showBrowserWarning]="false">
<ion-icon name="fas-external-link-alt" slot="start" aria-hidden="true"></ion-icon> <ion-icon name="fas-external-link-alt" slot="start" aria-hidden="true"></ion-icon>
<ion-label> <ion-label>
<p class="item-heading">{{ 'core.openinbrowser' | translate }}</p> <p class="item-heading">{{ 'core.openinbrowser' | translate }}</p>

View File

@ -8,22 +8,19 @@
<ion-icon name="fas-map-pin" *ngIf="discussion && !post.parentid && discussion.pinned" <ion-icon name="fas-map-pin" *ngIf="discussion && !post.parentid && discussion.pinned"
[attr.aria-label]="'addon.mod_forum.discussionpinned' | translate"> [attr.aria-label]="'addon.mod_forum.discussionpinned' | translate">
</ion-icon> </ion-icon>
<ion-icon name="fas-star" class="addon-forum-star" <ion-icon name="fas-star" class="addon-forum-star" [attr.aria-label]="'addon.mod_forum.favourites' | translate"
[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 [text]="post.subject" contextLevel="module" [contextInstanceId]="forum && forum.cmid"
[text]="post.subject" [courseId]="courseId">
contextLevel="module" [contextInstanceId]="forum && forum.cmid" [courseId]="courseId">
</core-format-text> </core-format-text>
</h2> </h2>
<ion-note *ngIf="trackPosts && post.unread" class="ion-float-end ion-padding-start ion-text-end" <ion-note *ngIf="trackPosts && post.unread" class="ion-float-end ion-padding-start ion-text-end"
[attr.aria-label]="'addon.mod_forum.unread' | translate"> [attr.aria-label]="'addon.mod_forum.unread' | translate">
<ion-icon name="fas-circle" color="primary" aria-hidden="true"></ion-icon> <ion-icon name="fas-circle" color="primary" aria-hidden="true"></ion-icon>
</ion-note> </ion-note>
<ion-button *ngIf="optionsMenuEnabled" <ion-button *ngIf="optionsMenuEnabled" fill="clear" color="dark"
fill="clear" color="dark" [attr.aria-label]="('core.displayoptions' | translate)" [attr.aria-label]="('core.displayoptions' | translate)" (click)="showOptionsMenu($event)">
(click)="showOptionsMenu($event)">
<ion-icon name="ellipsis-vertical" slot="icon-only" aria-hidden="true"> <ion-icon name="ellipsis-vertical" slot="icon-only" aria-hidden="true">
</ion-icon> </ion-icon>
</ion-button> </ion-button>
@ -50,9 +47,8 @@
[attr.aria-label]="'addon.mod_forum.unread' | translate"> [attr.aria-label]="'addon.mod_forum.unread' | translate">
<ion-icon name="fas-circle" color="primary" aria-hidden="true"></ion-icon> <ion-icon name="fas-circle" color="primary" aria-hidden="true"></ion-icon>
</ion-note> </ion-note>
<ion-button *ngIf="optionsMenuEnabled" <ion-button *ngIf="optionsMenuEnabled" fill="clear" color="dark"
fill="clear" color="dark" [attr.aria-label]="('core.displayoptions' | translate)" [attr.aria-label]="('core.displayoptions' | translate)" (click)="showOptionsMenu($event)">
(click)="showOptionsMenu($event)">
<ion-icon name="ellipsis-vertical" slot="icon-only" aria-hidden="true"></ion-icon> <ion-icon name="ellipsis-vertical" slot="icon-only" aria-hidden="true"></ion-icon>
</ion-button> </ion-button>
</ng-container> </ng-container>
@ -64,8 +60,8 @@
<div class="ion-padding-bottom" *ngIf="post.isprivatereply"> <div class="ion-padding-bottom" *ngIf="post.isprivatereply">
<ion-note color="danger">{{ 'addon.mod_forum.postisprivatereply' | translate }}</ion-note> <ion-note color="danger">{{ 'addon.mod_forum.postisprivatereply' | translate }}</ion-note>
</div> </div>
<core-format-text [component]="component" [componentId]="componentId" [text]="post.message" <core-format-text [component]="component" [componentId]="componentId" [text]="post.message" contextLevel="module"
contextLevel="module" [contextInstanceId]="forum && forum.cmid" [courseId]="courseId"> [contextInstanceId]="forum && forum.cmid" [courseId]="courseId">
</core-format-text> </core-format-text>
<div lines="none" *ngIf="post.attachments && post.attachments.length > 0"> <div lines="none" *ngIf="post.attachments && post.attachments.length > 0">
<core-files [files]="post.attachments" [component]="component" [componentId]="componentId" showInline="true"> <core-files [files]="post.attachments" [component]="component" [componentId]="componentId" showInline="true">
@ -79,23 +75,19 @@
<core-tag-list [tags]="post.tags"></core-tag-list> <core-tag-list [tags]="post.tags"></core-tag-list>
</ion-label> </ion-label>
</ion-item> </ion-item>
<core-rating-rate *ngIf="forum && ratingInfo" <core-rating-rate *ngIf="forum && ratingInfo" [ratingInfo]="ratingInfo" contextLevel="module" [instanceId]="componentId"
[ratingInfo]="ratingInfo" contextLevel="module" [instanceId]="componentId" [itemId]="post.id" [itemId]="post.id" [itemSetId]="discussionId" [courseId]="courseId" [aggregateMethod]="forum.assessed"
[itemSetId]="discussionId" [courseId]="courseId" [aggregateMethod]="forum.assessed" [scaleId]="forum.scale" [scaleId]="forum.scale" [userId]="post.author.id" (onUpdate)="ratingUpdated()">
[userId]="post.author.id" (onUpdate)="ratingUpdated()">
</core-rating-rate> </core-rating-rate>
<core-rating-aggregate *ngIf="forum && ratingInfo" <core-rating-aggregate *ngIf="forum && ratingInfo" [ratingInfo]="ratingInfo" contextLevel="module" [instanceId]="componentId"
[ratingInfo]="ratingInfo" contextLevel="module" [instanceId]="componentId" [itemId]="post.id" [itemId]="post.id" [courseId]="courseId" [aggregateMethod]="forum.assessed" [scaleId]="forum.scale">
[courseId]="courseId" [aggregateMethod]="forum.assessed" [scaleId]="forum.scale">
</core-rating-aggregate> </core-rating-aggregate>
<ion-item *ngIf="post.id > 0 && post.capabilities.reply && !post.isprivatereply" <ion-item *ngIf="post.id > 0 && post.capabilities.reply && !post.isprivatereply"
class="ion-no-padding ion-text-end addon-forum-reply-button"> class="ion-no-padding ion-text-end addon-forum-reply-button">
<ion-label> <ion-label>
<ion-button fill="clear" size="small" <ion-button fill="clear" size="small" [attr.aria-controls]="'addon-forum-reply-edit-form-' + uniqueId"
[attr.aria-controls]="'addon-forum-reply-edit-form-' + uniqueId" [attr.aria-expanded]="formData.replyingTo === post.id" (click)="showReplyForm($event)">
[attr.aria-expanded]="formData.replyingTo === post.id"
(click)="showReplyForm($event)">
<ion-icon name="fas-reply" slot="start" aria-hidden="true"></ion-icon> <ion-icon name="fas-reply" slot="start" aria-hidden="true"></ion-icon>
{{ 'addon.mod_forum.reply' | translate }} {{ 'addon.mod_forum.reply' | translate }}
</ion-button> </ion-button>
@ -104,21 +96,18 @@
</div> </div>
</ng-container> </ng-container>
<form *ngIf="showForm" <form *ngIf="showForm" [id]="'addon-forum-reply-edit-form-' + uniqueId" #replyFormEl>
[id]="'addon-forum-reply-edit-form-' + uniqueId" #replyFormEl>
<ion-item> <ion-item>
<ion-label position="stacked">{{ 'addon.mod_forum.subject' | translate }}</ion-label> <ion-label position="stacked">{{ 'addon.mod_forum.subject' | translate }}</ion-label>
<ion-input type="text" [placeholder]="'addon.mod_forum.subject' | translate" [(ngModel)]="formData.subject" <ion-input type="text" [placeholder]="'addon.mod_forum.subject' | translate" [(ngModel)]="formData.subject" name="subject">
name="subject">
</ion-input> </ion-input>
</ion-item> </ion-item>
<ion-item> <ion-item>
<ion-label position="stacked">{{ 'addon.mod_forum.message' | translate }}</ion-label> <ion-label position="stacked">{{ 'addon.mod_forum.message' | translate }}</ion-label>
<core-rich-text-editor elementId="message" contextLevel="module" <core-rich-text-editor elementId="message" contextLevel="module" [control]="messageControl"
[control]="messageControl" [placeholder]="'addon.mod_forum.replyplaceholder' | translate" [placeholder]="'addon.mod_forum.replyplaceholder' | translate" [name]="'mod_forum_reply_' + post.id" [component]="component"
[name]="'mod_forum_reply_' + post.id" [component]="component" [componentId]="componentId" [autoSave]="true" [componentId]="componentId" [autoSave]="true" [contextInstanceId]="forum && forum.cmid"
[contextInstanceId]="forum && forum.cmid" [draftExtraParams]="{reply: post.id}" [draftExtraParams]="{reply: post.id}" (contentChanged)="onMessageChange($event)">
(contentChanged)="onMessageChange($event)">
</core-rich-text-editor> </core-rich-text-editor>
</ion-item> </ion-item>
<ion-item class="ion-text-wrap" *ngIf="accessInfo.canpostprivatereply"> <ion-item class="ion-text-wrap" *ngIf="accessInfo.canpostprivatereply">
@ -126,14 +115,9 @@
<ion-checkbox slot="end" [(ngModel)]="formData.isprivatereply" name="isprivatereply"></ion-checkbox> <ion-checkbox slot="end" [(ngModel)]="formData.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 <ion-item button class="divider ion-text-wrap" (click)="toggleAdvanced()" detail="false" [attr.aria-expanded]="advanced"
button
class="divider ion-text-wrap"
(click)="toggleAdvanced()" detail="false"
[attr.aria-expanded]="advanced"
[attr.aria-controls]="'addon-forum-reply-edit-form-advanced-' + uniqueId" [attr.aria-controls]="'addon-forum-reply-edit-form-advanced-' + uniqueId"
[attr.aria-label]="(advanced ? 'core.hideadvanced' : 'core.showadvanced') | translate" [attr.aria-label]="(advanced ? 'core.hideadvanced' : 'core.showadvanced') | translate">
>
<ion-icon *ngIf="!advanced" name="fas-caret-right" flip-rtl slot="start" aria-hidden="true"></ion-icon> <ion-icon *ngIf="!advanced" name="fas-caret-right" flip-rtl slot="start" aria-hidden="true"></ion-icon>
<ion-icon *ngIf="advanced" name="fas-caret-down" 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>
@ -141,8 +125,7 @@
</ion-label> </ion-label>
</ion-item> </ion-item>
<div *ngIf="advanced" [id]="'addon-forum-reply-edit-form-advanced-' + uniqueId"> <div *ngIf="advanced" [id]="'addon-forum-reply-edit-form-advanced-' + uniqueId">
<core-attachments <core-attachments [files]="formData.files" [maxSize]="forum.maxbytes" [maxSubmissions]="forum.maxattachments"
[files]="formData.files" [maxSize]="forum.maxbytes" [maxSubmissions]="forum.maxattachments"
[component]="component" [componentId]="forum.cmid" [allowOffline]="true" [courseId]="courseId"> [component]="component" [componentId]="forum.cmid" [allowOffline]="true" [courseId]="courseId">
</core-attachments> </core-attachments>
</div> </div>

View File

@ -1,11 +1,12 @@
<ion-list> <ion-list>
<ng-container *ngFor="let group of subwikis"> <ng-container *ngFor="let group of subwikis">
<ion-item-divider *ngIf="group.label"> <ion-item-divider *ngIf="group.label">
<ion-label><h2>{{ group.label }}</h2></ion-label> <ion-label>
<h2>{{ group.label }}</h2>
</ion-label>
</ion-item-divider> </ion-item-divider>
<ion-item class="ion-text-wrap" *ngFor="let subwiki of group.subwikis" (click)="openSubwiki(subwiki)" <ion-item class="ion-text-wrap" *ngFor="let subwiki of group.subwikis" (click)="openSubwiki(subwiki)"
[attr.disabled]="!subwiki.canedit && subwiki.id <= 0" [attr.disabled]="!subwiki.canedit && subwiki.id <= 0" [button]="subwiki.canedit || subwiki.id > 0"
[button]="subwiki.canedit || subwiki.id > 0"
[attr.aria-current]="isSubwikiSelected(subwiki) ? 'page' : 'false'" detail="false"> [attr.aria-current]="isSubwikiSelected(subwiki) ? 'page' : 'false'" detail="false">
<ion-label>{{ subwiki.name }}</ion-label> <ion-label>{{ subwiki.name }}</ion-label>
<ion-icon *ngIf="isSubwikiSelected(subwiki)" name="fas-check" slot="end" aria-hidden="true"></ion-icon> <ion-icon *ngIf="isSubwikiSelected(subwiki)" name="fas-check" slot="end" aria-hidden="true"></ion-icon>

View File

@ -3,8 +3,7 @@
<ion-item class="ion-text-wrap"> <ion-item class="ion-text-wrap">
<ion-label> <ion-label>
<h2>{{ field.dimtitle }}</h2> <h2>{{ field.dimtitle }}</h2>
<core-format-text [text]="field.description" contextLevel="module" [contextInstanceId]="moduleId" <core-format-text [text]="field.description" contextLevel="module" [contextInstanceId]="moduleId" [courseId]="courseId">
[courseId]="courseId">
</core-format-text> </core-format-text>
</ion-label> </ion-label>
</ion-item> </ion-item>
@ -14,8 +13,7 @@
{{ 'addon.mod_workshop_assessment_accumulative.dimensiongradefor' | translate : {'$a': field.dimtitle } }} {{ 'addon.mod_workshop_assessment_accumulative.dimensiongradefor' | translate : {'$a': field.dimtitle } }}
</span> </span>
</ion-label> </ion-label>
<ion-select [(ngModel)]="selectedValues[n].grade" interface="action-sheet" <ion-select [(ngModel)]="selectedValues[n].grade" interface="action-sheet" [interfaceOptions]="{header: 'addon.mod_workshop_assessment_accumulative.dimensiongradefor' |
[interfaceOptions]="{header: 'addon.mod_workshop_assessment_accumulative.dimensiongradefor' |
translate : {'$a': field.dimtitle }}"> translate : {'$a': field.dimtitle }}">
<ion-select-option *ngFor="let grade of field.grades" [value]="grade.value">{{grade.label}}</ion-select-option> <ion-select-option *ngFor="let grade of field.grades" [value]="grade.value">{{grade.label}}</ion-select-option>
</ion-select> </ion-select>

View File

@ -3,8 +3,7 @@
<ion-item class="ion-text-wrap"> <ion-item class="ion-text-wrap">
<ion-label> <ion-label>
<h2>{{ field.dimtitle }}</h2> <h2>{{ field.dimtitle }}</h2>
<core-format-text [text]="field.description" contextLevel="module" [contextInstanceId]="moduleId" <core-format-text [text]="field.description" contextLevel="module" [contextInstanceId]="moduleId" [courseId]="courseId">
[courseId]="courseId">
</core-format-text> </core-format-text>
</ion-label> </ion-label>
</ion-item> </ion-item>
@ -22,9 +21,11 @@
<ion-item *ngIf="!edit" class="ion-text-wrap"> <ion-item *ngIf="!edit" class="ion-text-wrap">
<ion-label> <ion-label>
<h2>{{ 'addon.mod_workshop_assessment_comments.dimensioncommentfor' | translate : {'$a': field.dimtitle } }}</h2> <h2>{{ 'addon.mod_workshop_assessment_comments.dimensioncommentfor' | translate : {'$a': field.dimtitle } }}</h2>
<p><core-format-text [text]="selectedValues[n].peercomment" contextLevel="module" [contextInstanceId]="moduleId" <p>
<core-format-text [text]="selectedValues[n].peercomment" contextLevel="module" [contextInstanceId]="moduleId"
[courseId]="courseId"> [courseId]="courseId">
</core-format-text></p> </core-format-text>
</p>
</ion-label> </ion-label>
</ion-item> </ion-item>
</ion-card> </ion-card>

View File

@ -3,8 +3,7 @@
<ion-item class="ion-text-wrap"> <ion-item class="ion-text-wrap">
<ion-label> <ion-label>
<h2>{{ field.dimtitle }}</h2> <h2>{{ field.dimtitle }}</h2>
<core-format-text [text]="field.description" contextLevel="module" [contextInstanceId]="moduleId" <core-format-text [text]="field.description" contextLevel="module" [contextInstanceId]="moduleId" [courseId]="courseId">
[courseId]="courseId">
</core-format-text> </core-format-text>
</ion-label> </ion-label>
</ion-item> </ion-item>
@ -26,7 +25,9 @@
<ion-radio slot="start" [value]="-1" [disabled]="!edit"></ion-radio> <ion-radio slot="start" [value]="-1" [disabled]="!edit"></ion-radio>
</ion-item> </ion-item>
<ion-item> <ion-item>
<ion-label><core-format-text [text]="field.grade1" [filter]="false"></core-format-text></ion-label> <ion-label>
<core-format-text [text]="field.grade1" [filter]="false"></core-format-text>
</ion-label>
<ion-radio slot="start" [value]="1" [disabled]="!edit"></ion-radio> <ion-radio slot="start" [value]="1" [disabled]="!edit"></ion-radio>
</ion-item> </ion-item>
</ion-radio-group> </ion-radio-group>

View File

@ -3,8 +3,7 @@
<ion-item class="ion-text-wrap"> <ion-item class="ion-text-wrap">
<ion-label> <ion-label>
<h2 [core-mark-required]="edit">{{ field.dimtitle }}</h2> <h2 [core-mark-required]="edit">{{ field.dimtitle }}</h2>
<core-format-text [text]="field.description" contextLevel="module" [contextInstanceId]="moduleId" <core-format-text [text]="field.description" contextLevel="module" [contextInstanceId]="moduleId" [courseId]="courseId">
[courseId]="courseId">
</core-format-text> </core-format-text>
</ion-label> </ion-label>
<core-input-errors *ngIf="edit && fieldErrors['chosenlevelid_' + n]" [errorText]="fieldErrors['chosenlevelid_' + n]"> <core-input-errors *ngIf="edit && fieldErrors['chosenlevelid_' + n]" [errorText]="fieldErrors['chosenlevelid_' + n]">
@ -14,9 +13,11 @@
<ion-radio-group [(ngModel)]="selectedValues[n].chosenlevelid" [name]="'chosenlevelid_' + n"> <ion-radio-group [(ngModel)]="selectedValues[n].chosenlevelid" [name]="'chosenlevelid_' + n">
<ion-item *ngFor="let subfield of field.fields"> <ion-item *ngFor="let subfield of field.fields">
<ion-label> <ion-label>
<p><core-format-text [text]="subfield.definition" contextLevel="module" <p>
[contextInstanceId]="moduleId" [courseId]="courseId"> <core-format-text [text]="subfield.definition" contextLevel="module" [contextInstanceId]="moduleId"
</core-format-text></p> [courseId]="courseId">
</core-format-text>
</p>
</ion-label> </ion-label>
<ion-radio slot="start" [value]="subfield.levelid" [disabled]="!edit"></ion-radio> <ion-radio slot="start" [value]="subfield.levelid" [disabled]="!edit"></ion-radio>
</ion-item> </ion-item>

View File

@ -17,7 +17,9 @@
<ion-card *ngIf="assessmentStrategyLoaded && overallFeedkback && <ion-card *ngIf="assessmentStrategyLoaded && overallFeedkback &&
(edit || data.assessment?.feedbackauthor || data.assessment?.feedbackattachmentfiles?.length) "> (edit || data.assessment?.feedbackauthor || data.assessment?.feedbackattachmentfiles?.length) ">
<ion-item class="ion-text-wrap"> <ion-item class="ion-text-wrap">
<ion-label><h2>{{ 'addon.mod_workshop.overallfeedback' | translate }}</h2></ion-label> <ion-label>
<h2>{{ 'addon.mod_workshop.overallfeedback' | translate }}</h2>
</ion-label>
</ion-item> </ion-item>
<ion-item position="stacked" *ngIf="edit"> <ion-item position="stacked" *ngIf="edit">
<ion-label position="stacked"> <ion-label position="stacked">
@ -25,19 +27,17 @@
{{ 'addon.mod_workshop.feedbackauthor' | translate }} {{ 'addon.mod_workshop.feedbackauthor' | translate }}
</span> </span>
</ion-label> </ion-label>
<core-rich-text-editor [control]="feedbackControl" [component]="component" <core-rich-text-editor [control]="feedbackControl" [component]="component" [componentId]="workshop.coursemodule"
[componentId]="workshop.coursemodule" [autoSave]="true" contextLevel="module" [autoSave]="true" contextLevel="module" [contextInstanceId]="workshop.coursemodule" elementId="feedbackauthor_editor"
[contextInstanceId]="workshop.coursemodule" elementId="feedbackauthor_editor"
[draftExtraParams]="{asid: assessmentId}" (contentChanged)="onFeedbackChange($event)"> [draftExtraParams]="{asid: assessmentId}" (contentChanged)="onFeedbackChange($event)">
</core-rich-text-editor> </core-rich-text-editor>
<core-input-errors <core-input-errors *ngIf="overallFeedkbackRequired && data.fieldErrors && data.fieldErrors['feedbackauthor']"
*ngIf="overallFeedkbackRequired && data.fieldErrors && data.fieldErrors['feedbackauthor']"
[errorText]="data.fieldErrors['feedbackauthor']"> [errorText]="data.fieldErrors['feedbackauthor']">
</core-input-errors> </core-input-errors>
</ion-item> </ion-item>
<core-attachments *ngIf="edit && workshop.overallfeedbackfiles" [files]="data.assessment?.feedbackattachmentfiles" <core-attachments *ngIf="edit && workshop.overallfeedbackfiles" [files]="data.assessment?.feedbackattachmentfiles"
[maxSize]="workshop.overallfeedbackmaxbytes" [maxSubmissions]="workshop.overallfeedbackfiles" [maxSize]="workshop.overallfeedbackmaxbytes" [maxSubmissions]="workshop.overallfeedbackfiles" [component]="component"
[component]="component" [componentId]="componentId" [allowOffline]="true" [courseId]="workshop.course"> [componentId]="componentId" [allowOffline]="true" [courseId]="workshop.course">
</core-attachments> </core-attachments>
<ion-item *ngIf="edit && access && access.canallocate"> <ion-item *ngIf="edit && access && access.canallocate">
<ion-label position="stacked"> <ion-label position="stacked">
@ -57,11 +57,10 @@
</core-format-text> </core-format-text>
</ion-label> </ion-label>
</ion-item> </ion-item>
<ion-item *ngIf="!edit && workshop.overallfeedbackfiles && data.assessment?.feedbackattachmentfiles?.length" <ion-item *ngIf="!edit && workshop.overallfeedbackfiles && data.assessment?.feedbackattachmentfiles?.length" lines="none">
lines="none">
<ion-label> <ion-label>
<core-files [files]="data.assessment?.feedbackattachmentfiles" [component]="component" <core-files [files]="data.assessment?.feedbackattachmentfiles" [component]="component" [componentId]="componentId">
[componentId]="componentId"></core-files> </core-files>
</ion-label> </ion-label>
</ion-item> </ion-item>
</ion-card> </ion-card>

View File

@ -5,13 +5,11 @@
</core-user-avatar> </core-user-avatar>
<ion-label> <ion-label>
<h2> <h2>
<core-format-text [text]="submission.title" contextLevel="module" [contextInstanceId]="module.id" <core-format-text [text]="submission.title" contextLevel="module" [contextInstanceId]="module.id" [courseId]="courseId">
[courseId]="courseId">
</core-format-text> </core-format-text>
</h2> </h2>
<p *ngIf="profile && profile?.fullname">{{profile.fullname}}</p> <p *ngIf="profile && profile?.fullname">{{profile.fullname}}</p>
<p *ngIf="showGrade(submission.grade)" <p *ngIf="showGrade(submission.grade)" [class.addon-has-overriden-grade]="showGrade(submission.gradeover)">
[class.addon-has-overriden-grade]="showGrade(submission.gradeover)">
{{ 'addon.mod_workshop.submissiongradeof' | translate:{$a: workshop.grade } }}: {{submission.grade}} {{ 'addon.mod_workshop.submissiongradeof' | translate:{$a: workshop.grade } }}: {{submission.grade}}
</p> </p>
<p *ngIf="showGrade(submission.gradeover)" class="addon-overriden-grade"> <p *ngIf="showGrade(submission.gradeover)" class="addon-overriden-grade">
@ -36,8 +34,8 @@
</ion-item> </ion-item>
<ion-item class="ion-text-wrap" *ngIf="submission.content"> <ion-item class="ion-text-wrap" *ngIf="submission.content">
<ion-label> <ion-label>
<core-format-text [component]="component" [componentId]="componentId" [text]="submission.content" <core-format-text [component]="component" [componentId]="componentId" [text]="submission.content" contextLevel="module"
contextLevel="module" [contextInstanceId]="module.id" [courseId]="courseId"> [contextInstanceId]="module.id" [courseId]="courseId">
</core-format-text> </core-format-text>
</ion-label> </ion-label>
</ion-item> </ion-item>
@ -71,8 +69,7 @@
</core-user-avatar> </core-user-avatar>
<ion-label> <ion-label>
<h2> <h2>
<core-format-text [text]="submission.title" contextLevel="module" [contextInstanceId]="module.id" <core-format-text [text]="submission.title" contextLevel="module" [contextInstanceId]="module.id" [courseId]="courseId">
[courseId]="courseId">
</core-format-text> </core-format-text>
</h2> </h2>
<p *ngIf="profile && profile.fullname">{{profile.fullname}}</p> <p *ngIf="profile && profile.fullname">{{profile.fullname}}</p>
@ -92,19 +89,19 @@
{{ 'addon.mod_workshop.gradinggradeof' | translate:{$a: workshop.gradinggrade } }}: {{submission.gradinggrade}} {{ 'addon.mod_workshop.gradinggradeof' | translate:{$a: workshop.gradinggrade } }}: {{submission.gradinggrade}}
</p> </p>
<ion-badge *ngIf="assessment && (showGrade(assessment.grade) || assessment.offline)" color="success" <ion-badge *ngIf="assessment && (showGrade(assessment.grade) || assessment.offline)" color="success" class="ion-text-wrap">
class="ion-text-wrap">
{{ 'addon.mod_workshop.assessedsubmission' | translate }} {{ 'addon.mod_workshop.assessedsubmission' | translate }}
</ion-badge> </ion-badge>
<ion-badge *ngIf="assessment && !showGrade(assessment.grade) && !assessment.offline" color="danger" <ion-badge *ngIf="assessment && !showGrade(assessment.grade) && !assessment.offline" color="danger" class="ion-text-wrap">
class="ion-text-wrap">
{{ 'addon.mod_workshop.notassessed' | translate }} {{ 'addon.mod_workshop.notassessed' | translate }}
</ion-badge> </ion-badge>
</ion-label> </ion-label>
<ion-note slot="end" *ngIf="submission.timemodified"> <ion-note slot="end" *ngIf="submission.timemodified">
{{submission.timemodified | coreDateDayOrTime}} {{submission.timemodified | coreDateDayOrTime}}
<div *ngIf="offline"><ion-icon name="fas-clock" aria-hidden="true"></ion-icon> {{ 'core.notsent' | translate }}</div> <div *ngIf="offline">
<ion-icon name="fas-clock" aria-hidden="true"></ion-icon> {{ 'core.notsent' | translate }}
</div>
<div *ngIf="submission.deleted"> <div *ngIf="submission.deleted">
<ion-icon name="fas-trash" aria-hidden="true"></ion-icon> {{ 'core.deletedoffline' | translate }} <ion-icon name="fas-trash" aria-hidden="true"></ion-icon> {{ 'core.deletedoffline' | translate }}
</div> </div>

View File

@ -1,6 +1,8 @@
<div *ngIf="question && question.behaviourCertaintyOptions && question.behaviourCertaintyOptions.length"> <div *ngIf="question && question.behaviourCertaintyOptions && question.behaviourCertaintyOptions.length">
<ion-item class="ion-text-wrap addon-qbehaviour-deferredcbm-certainty-title" > <ion-item class="ion-text-wrap addon-qbehaviour-deferredcbm-certainty-title">
<ion-label><p>{{ 'core.question.certainty' | translate }}</p></ion-label> <ion-label>
<p>{{ 'core.question.certainty' | translate }}</p>
</ion-label>
</ion-item> </ion-item>
<ion-radio-group [(ngModel)]="question.behaviourCertaintySelected" [name]="question.behaviourCertaintyOptions[0].name"> <ion-radio-group [(ngModel)]="question.behaviourCertaintySelected" [name]="question.behaviourCertaintyOptions[0].name">

View File

@ -1,8 +1,8 @@
<ion-list class="addon-qtype-calculated-container" *ngIf="calcQuestion && (calcQuestion.text || calcQuestion.text === '')"> <ion-list class="addon-qtype-calculated-container" *ngIf="calcQuestion && (calcQuestion.text || calcQuestion.text === '')">
<ion-item class="ion-text-wrap"> <ion-item class="ion-text-wrap">
<ion-label> <ion-label>
<core-format-text [component]="component" [componentId]="componentId" [text]="calcQuestion.text" <core-format-text [component]="component" [componentId]="componentId" [text]="calcQuestion.text" [contextLevel]="contextLevel"
[contextLevel]="contextLevel" [contextInstanceId]="contextInstanceId" [courseId]="courseId"> [contextInstanceId]="contextInstanceId" [courseId]="courseId">
</core-format-text> </core-format-text>
</ion-label> </ion-label>
</ion-item> </ion-item>
@ -23,8 +23,8 @@
<!-- Input to enter the answer. --> <!-- Input to enter the answer. -->
<ion-input type="text" [attr.name]="calcQuestion.input.name" <ion-input type="text" [attr.name]="calcQuestion.input.name"
[placeholder]="calcQuestion.input.readOnly ? '' : 'core.question.answer' | translate" [placeholder]="calcQuestion.input.readOnly ? '' : 'core.question.answer' | translate" [value]="calcQuestion.input.value"
[value]="calcQuestion.input.value" [disabled]="calcQuestion.input.readOnly" autocorrect="off"> [disabled]="calcQuestion.input.readOnly" autocorrect="off">
</ion-input> </ion-input>
<!-- Display unit select after the answer input. --> <!-- Display unit select after the answer input. -->
@ -48,9 +48,9 @@
<label *ngIf="calcQuestion!.select!.accessibilityLabel" class="accesshide" for="{{calcQuestion!.select!.id}}"> <label *ngIf="calcQuestion!.select!.accessibilityLabel" class="accesshide" for="{{calcQuestion!.select!.id}}">
{{ calcQuestion!.select!.accessibilityLabel }} {{ calcQuestion!.select!.accessibilityLabel }}
</label> </label>
<ion-select id="{{calcQuestion!.select!.id}}" [name]="calcQuestion!.select!.name" <ion-select id="{{calcQuestion!.select!.id}}" [name]="calcQuestion!.select!.name" [(ngModel)]="calcQuestion!.select!.selected"
[(ngModel)]="calcQuestion!.select!.selected" interface="action-sheet" [disabled]="calcQuestion!.select!.disabled" interface="action-sheet" [disabled]="calcQuestion!.select!.disabled" [slot]="calcQuestion?.selectFirst ? 'start' : 'end'"
[slot]="calcQuestion?.selectFirst ? 'start' : 'end'" [interfaceOptions]="{header: 'addon.mod_quiz.unit' | translate}"> [interfaceOptions]="{header: 'addon.mod_quiz.unit' | translate}">
<ion-select-option *ngFor="let option of calcQuestion!.select!.options" [value]="option.value"> <ion-select-option *ngFor="let option of calcQuestion!.select!.options" [value]="option.value">
{{option.label}} {{option.label}}
</ion-select-option> </ion-select-option>

View File

@ -11,9 +11,8 @@
</ion-item> </ion-item>
</ion-card> </ion-card>
<core-format-text [component]="component" [componentId]="componentId" [text]="ddQuestion.text" <core-format-text [component]="component" [componentId]="componentId" [text]="ddQuestion.text" [contextLevel]="contextLevel"
[contextLevel]="contextLevel" [contextInstanceId]="contextInstanceId" [courseId]="courseId" [contextInstanceId]="contextInstanceId" [courseId]="courseId" (afterRender)="textRendered()">
(afterRender)="textRendered()">
</core-format-text> </core-format-text>
</ion-label> </ion-label>
</ion-item> </ion-item>

View File

@ -11,8 +11,7 @@
</ion-item> </ion-item>
</ion-card> </ion-card>
<core-format-text [component]="component" [componentId]="componentId" [text]="ddQuestion.text" #questiontext <core-format-text [component]="component" [componentId]="componentId" [text]="ddQuestion.text" #questiontext
[contextLevel]="contextLevel" [contextInstanceId]="contextInstanceId" [courseId]="courseId" [contextLevel]="contextLevel" [contextInstanceId]="contextInstanceId" [courseId]="courseId" (afterRender)="textRendered()">
(afterRender)="textRendered()">
</core-format-text> </core-format-text>
</ion-label> </ion-label>
</ion-item> </ion-item>

View File

@ -10,13 +10,12 @@
</ion-item> </ion-item>
</ion-card> </ion-card>
<div class="addon-qtype-ddwtos-container"> <div class="addon-qtype-ddwtos-container">
<core-format-text [component]="component" [componentId]="componentId" [text]="ddQuestion.text" <core-format-text [component]="component" [componentId]="componentId" [text]="ddQuestion.text" [contextLevel]="contextLevel"
[contextLevel]="contextLevel" [contextInstanceId]="contextInstanceId" [courseId]="courseId" #questiontext [contextInstanceId]="contextInstanceId" [courseId]="courseId" #questiontext (afterRender)="textRendered()">
(afterRender)="textRendered()">
</core-format-text> </core-format-text>
<core-format-text *ngIf="ddQuestion.answers" [component]="component" [componentId]="componentId" <core-format-text *ngIf="ddQuestion.answers" [component]="component" [componentId]="componentId" [text]="ddQuestion.answers"
[text]="ddQuestion.answers" [filter]="false" (afterRender)="answersRendered()"> [filter]="false" (afterRender)="answersRendered()">
</core-format-text> </core-format-text>
<div class="drags"></div> <div class="drags"></div>

View File

@ -1,11 +1,11 @@
<ion-list *ngIf="question && (question.text || question.text === '')"> <ion-list *ngIf="question && (question.text || question.text === '')">
<!-- "Seen" hidden input --> <!-- "Seen" hidden input -->
<input *ngIf="seenInput" type="hidden" [name]="seenInput.name" [value]="seenInput.value" > <input *ngIf="seenInput" type="hidden" [name]="seenInput.name" [value]="seenInput.value">
<ion-item class="ion-text-wrap"> <ion-item class="ion-text-wrap">
<ion-label> <ion-label>
<core-format-text [component]="component" [componentId]="componentId" [text]="question.text" <core-format-text [component]="component" [componentId]="componentId" [text]="question.text" [contextLevel]="contextLevel"
[contextLevel]="contextLevel" [contextInstanceId]="contextInstanceId" [courseId]="courseId"> [contextInstanceId]="contextInstanceId" [courseId]="courseId">
</core-format-text> </core-format-text>
</ion-label> </ion-label>
</ion-item> </ion-item>

View File

@ -2,8 +2,8 @@
<!-- Question text. --> <!-- Question text. -->
<ion-item class="ion-text-wrap"> <ion-item class="ion-text-wrap">
<ion-label> <ion-label>
<core-format-text [component]="component" [componentId]="componentId" [text]="essayQuestion.text" <core-format-text [component]="component" [componentId]="componentId" [text]="essayQuestion.text" [contextLevel]="contextLevel"
[contextLevel]="contextLevel" [contextInstanceId]="contextInstanceId" [courseId]="courseId"> [contextInstanceId]="contextInstanceId" [courseId]="courseId">
</core-format-text> </core-format-text>
</ion-label> </ion-label>
</ion-item> </ion-item>
@ -15,13 +15,12 @@
<ion-label class="sr-only">{{ 'core.question.answer' | translate }}</ion-label> <ion-label class="sr-only">{{ 'core.question.answer' | translate }}</ion-label>
<!-- "Format" and draftid hidden inputs --> <!-- "Format" and draftid hidden inputs -->
<input *ngIf="essayQuestion.formatInput" type="hidden" [name]="essayQuestion.formatInput.name" <input *ngIf="essayQuestion.formatInput" type="hidden" [name]="essayQuestion.formatInput.name"
[value]="essayQuestion.formatInput.value" > [value]="essayQuestion.formatInput.value">
<input *ngIf="essayQuestion.answerDraftIdInput" type="hidden" [name]="essayQuestion.answerDraftIdInput.name" <input *ngIf="essayQuestion.answerDraftIdInput" type="hidden" [name]="essayQuestion.answerDraftIdInput.name"
[value]="essayQuestion.answerDraftIdInput.value" > [value]="essayQuestion.answerDraftIdInput.value">
<!-- Plain text textarea. --> <!-- Plain text textarea. -->
<ion-textarea *ngIf="essayQuestion.isPlainText" class="core-question-textarea" <ion-textarea *ngIf="essayQuestion.isPlainText" class="core-question-textarea"
[ngClass]='{"core-monospaced": essayQuestion.isMonospaced}' [ngClass]='{"core-monospaced": essayQuestion.isMonospaced}' placeholder="{{ 'core.question.answer' | translate }}"
placeholder="{{ 'core.question.answer' | translate }}"
[attr.name]="essayQuestion.textarea.name" [ngModel]="essayQuestion.textarea.text"> [attr.name]="essayQuestion.textarea.name" [ngModel]="essayQuestion.textarea.text">
</ion-textarea> </ion-textarea>
<!-- Rich text editor. --> <!-- Rich text editor. -->
@ -56,7 +55,7 @@
</core-attachments> </core-attachments>
<input *ngIf="essayQuestion.attachmentsDraftIdInput" type="hidden" [name]="essayQuestion.attachmentsDraftIdInput.name" <input *ngIf="essayQuestion.attachmentsDraftIdInput" type="hidden" [name]="essayQuestion.attachmentsDraftIdInput.name"
[value]="essayQuestion.attachmentsDraftIdInput.value" > [value]="essayQuestion.attachmentsDraftIdInput.value">
<!-- Attachments not supported in this site. --> <!-- Attachments not supported in this site. -->
<ion-item *ngIf="!uploadFilesSupported" class="ion-text-wrap core-danger-item"> <ion-item *ngIf="!uploadFilesSupported" class="ion-text-wrap core-danger-item">

View File

@ -1,9 +1,8 @@
<ion-list class="addon-qtype-gapselect-container" *ngIf="question && (question.text || question.text === '')"> <ion-list class="addon-qtype-gapselect-container" *ngIf="question && (question.text || question.text === '')">
<ion-item class="ion-text-wrap"> <ion-item class="ion-text-wrap">
<ion-label> <ion-label>
<core-format-text [component]="component" [componentId]="componentId" [text]="question.text" <core-format-text [component]="component" [componentId]="componentId" [text]="question.text" [contextLevel]="contextLevel"
[contextLevel]="contextLevel" [contextInstanceId]="contextInstanceId" [courseId]="courseId" [contextInstanceId]="contextInstanceId" [courseId]="courseId" (afterRender)="questionRendered()">
(afterRender)="questionRendered()">
</core-format-text> </core-format-text>
</ion-label> </ion-label>
</ion-item> </ion-item>

View File

@ -1,16 +1,15 @@
<section class="addon-qtype-match-container" *ngIf="matchQuestion && matchQuestion.loaded"> <section class="addon-qtype-match-container" *ngIf="matchQuestion && matchQuestion.loaded">
<ion-item class="ion-text-wrap"> <ion-item class="ion-text-wrap">
<ion-label> <ion-label>
<core-format-text [component]="component" [componentId]="componentId" [text]="matchQuestion.text" <core-format-text [component]="component" [componentId]="componentId" [text]="matchQuestion.text" [contextLevel]="contextLevel"
[contextLevel]="contextLevel" [contextInstanceId]="contextInstanceId" [courseId]="courseId"> [contextInstanceId]="contextInstanceId" [courseId]="courseId">
</core-format-text> </core-format-text>
</ion-label> </ion-label>
</ion-item> </ion-item>
<ion-item class="ion-text-wrap" *ngFor="let row of matchQuestion.rows"> <ion-item class="ion-text-wrap" *ngFor="let row of matchQuestion.rows">
<ion-label> <ion-label>
<core-format-text id="addon-qtype-match-question-{{row.id}}" [component]="component" <core-format-text id="addon-qtype-match-question-{{row.id}}" [component]="component" [componentId]="componentId"
[componentId]="componentId" [text]="row.text" [contextLevel]="contextLevel" [text]="row.text" [contextLevel]="contextLevel" [contextInstanceId]="contextInstanceId" [courseId]="courseId">
[contextInstanceId]="contextInstanceId" [courseId]="courseId">
</core-format-text> </core-format-text>
<label class="accesshide" for="{{row.id}}" *ngIf="row.accessibilityLabel"> <label class="accesshide" for="{{row.id}}" *ngIf="row.accessibilityLabel">
{{ row.accessibilityLabel }} {{ row.accessibilityLabel }}

View File

@ -1,8 +1,7 @@
<ion-list class="addon-qtype-multianswer-container" *ngIf="question && (question.text || question.text === '')"> <ion-list class="addon-qtype-multianswer-container" *ngIf="question && (question.text || question.text === '')">
<div class="fake-ion-item ion-text-wrap"> <div class="fake-ion-item ion-text-wrap">
<core-format-text [component]="component" [componentId]="componentId" [text]="question.text" <core-format-text [component]="component" [componentId]="componentId" [text]="question.text" [contextLevel]="contextLevel"
[contextLevel]="contextLevel" [contextInstanceId]="contextInstanceId" [courseId]="courseId" [contextInstanceId]="contextInstanceId" [courseId]="courseId" (afterRender)="questionRendered()">
(afterRender)="questionRendered()">
</core-format-text> </core-format-text>
</div> </div>
</ion-list> </ion-list>

View File

@ -14,10 +14,9 @@
<!-- Checkbox for multiple choice. --> <!-- Checkbox for multiple choice. -->
<ng-container *ngIf="multiQuestion.multi"> <ng-container *ngIf="multiQuestion.multi">
<ion-item class="ion-text-wrap answer" *ngFor="let option of multiQuestion.options"> <ion-item class="ion-text-wrap answer" *ngFor="let option of multiQuestion.options">
<ion-label [color]='(option.isCorrect === 1 ? "success": "") + (option.isCorrect === 0 ? "danger": "")' <ion-label [color]='(option.isCorrect === 1 ? "success": "") + (option.isCorrect === 0 ? "danger": "")' [class]="option.class">
[class]="option.class"> <core-format-text [component]="component" [componentId]="componentId" [text]="option.text" [contextLevel]="contextLevel"
<core-format-text [component]="component" [componentId]="componentId" [text]="option.text" [contextInstanceId]="contextInstanceId" [courseId]="courseId">
[contextLevel]="contextLevel" [contextInstanceId]="contextInstanceId" [courseId]="courseId">
</core-format-text> </core-format-text>
<div *ngIf="option.feedback" class="specificfeedback"> <div *ngIf="option.feedback" class="specificfeedback">
<core-format-text [component]="component" [componentId]="componentId" [text]="option.feedback" <core-format-text [component]="component" [componentId]="componentId" [text]="option.feedback"
@ -41,12 +40,11 @@
</ng-container> </ng-container>
<!-- Radio buttons for single choice. --> <!-- Radio buttons for single choice. -->
<ion-radio-group *ngIf="!multiQuestion.multi" [(ngModel)]="multiQuestion.singleChoiceModel" <ion-radio-group *ngIf="!multiQuestion.multi" [(ngModel)]="multiQuestion.singleChoiceModel" [name]="multiQuestion.optionsName">
[name]="multiQuestion.optionsName">
<ion-item class="ion-text-wrap answer" *ngFor="let option of multiQuestion.options"> <ion-item class="ion-text-wrap answer" *ngFor="let option of multiQuestion.options">
<ion-label [class]="option.class"> <ion-label [class]="option.class">
<core-format-text [component]="component" [componentId]="componentId" [text]="option.text" <core-format-text [component]="component" [componentId]="componentId" [text]="option.text" [contextLevel]="contextLevel"
[contextLevel]="contextLevel" [contextInstanceId]="contextInstanceId" [courseId]="courseId"> [contextInstanceId]="contextInstanceId" [courseId]="courseId">
</core-format-text> </core-format-text>
<div *ngIf="option.feedback" class="specificfeedback"> <div *ngIf="option.feedback" class="specificfeedback">
<core-format-text [component]="component" [componentId]="componentId" [text]="option.feedback" <core-format-text [component]="component" [componentId]="componentId" [text]="option.feedback"

View File

@ -1,8 +1,8 @@
<ion-list *ngIf="textQuestion && (textQuestion.text || textQuestion.text === '')"> <ion-list *ngIf="textQuestion && (textQuestion.text || textQuestion.text === '')">
<ion-item class="ion-text-wrap addon-qtype-shortanswer-text"> <ion-item class="ion-text-wrap addon-qtype-shortanswer-text">
<ion-label> <ion-label>
<core-format-text [component]="component" [componentId]="componentId" [text]="textQuestion.text" <core-format-text [component]="component" [componentId]="componentId" [text]="textQuestion.text" [contextLevel]="contextLevel"
[contextLevel]="contextLevel" [contextInstanceId]="contextInstanceId" [courseId]="courseId"> [contextInstanceId]="contextInstanceId" [courseId]="courseId">
</core-format-text> </core-format-text>
</ion-label> </ion-label>
</ion-item> </ion-item>
@ -13,8 +13,8 @@
[attr.name]="textQuestion.input.name" [value]="textQuestion.input.value" autocorrect="off" [attr.name]="textQuestion.input.name" [value]="textQuestion.input.value" autocorrect="off"
[disabled]="textQuestion.input.readOnly"> [disabled]="textQuestion.input.readOnly">
</ion-input> </ion-input>
<ion-icon *ngIf="textQuestion.input.correctIcon" class="core-correct-icon" slot="end" <ion-icon *ngIf="textQuestion.input.correctIcon" class="core-correct-icon" slot="end" [name]="textQuestion.input.correctIcon"
[name]="textQuestion.input.correctIcon" [color]="[textQuestion.input.correctIconColor]"> [color]="[textQuestion.input.correctIconColor]">
</ion-icon> </ion-icon>
</ion-item> </ion-item>
</ion-list> </ion-list>

View File

@ -11,8 +11,8 @@
<ion-label position="stacked"> <ion-label position="stacked">
<span [core-mark-required]="required">{{ field.name }}</span> <span [core-mark-required]="required">{{ field.name }}</span>
</ion-label> </ion-label>
<ion-datetime [formControlName]="modelName" [placeholder]="'core.choosedots' | translate" [displayFormat]="format" <ion-datetime [formControlName]="modelName" [placeholder]="'core.choosedots' | translate" [displayFormat]="format" [max]="max"
[max]="max" [min]="min" [monthNames]="monthNames"> [min]="min" [monthNames]="monthNames">
</ion-datetime> </ion-datetime>
<core-input-errors [control]="form.controls[modelName]"></core-input-errors> <core-input-errors [control]="form.controls[modelName]"></core-input-errors>
</ion-item> </ion-item>

View File

@ -2,9 +2,10 @@
<ion-item *ngIf="!edit && field && field.name"> <ion-item *ngIf="!edit && field && field.name">
<ion-label> <ion-label>
<h2>{{ field.name }}</h2> <h2>{{ field.name }}</h2>
<p><core-format-text [text]="value" [contextLevel]="contextLevel" [contextInstanceId]="contextInstanceId" <p>
[courseId]="courseId"> <core-format-text [text]="value" [contextLevel]="contextLevel" [contextInstanceId]="contextInstanceId" [courseId]="courseId">
</core-format-text></p> </core-format-text>
</p>
</ion-label> </ion-label>
</ion-item> </ion-item>

View File

@ -2,9 +2,10 @@
<ion-item *ngIf="!edit && field && field.name"> <ion-item *ngIf="!edit && field && field.name">
<ion-label> <ion-label>
<h2>{{ field.name }}</h2> <h2>{{ field.name }}</h2>
<p><core-format-text [text]="value" [contextLevel]="contextLevel" [contextInstanceId]="contextInstanceId" <p>
[courseId]="courseId"> <core-format-text [text]="value" [contextLevel]="contextLevel" [contextInstanceId]="contextInstanceId" [courseId]="courseId">
</core-format-text></p> </core-format-text>
</p>
</ion-label> </ion-label>
</ion-item> </ion-item>

View File

@ -2,9 +2,10 @@
<ion-item *ngIf="!edit && field && field.name"> <ion-item *ngIf="!edit && field && field.name">
<ion-label> <ion-label>
<h2>{{ field.name }}</h2> <h2>{{ field.name }}</h2>
<p><core-format-text [text]="value" [contextLevel]="contextLevel" [contextInstanceId]="contextInstanceId" <p>
[courseId]="courseId"> <core-format-text [text]="value" [contextLevel]="contextLevel" [contextInstanceId]="contextInstanceId" [courseId]="courseId">
</core-format-text></p> </core-format-text>
</p>
</ion-label> </ion-label>
</ion-item> </ion-item>
@ -14,7 +15,7 @@
<span [core-mark-required]="required">{{ field.name }}</span> <span [core-mark-required]="required">{{ field.name }}</span>
<core-input-errors [control]="control"></core-input-errors> <core-input-errors [control]="control"></core-input-errors>
</ion-label> </ion-label>
<core-rich-text-editor [control]="control" [placeholder]="field.name" [autoSave]="true" <core-rich-text-editor [control]="control" [placeholder]="field.name" [autoSave]="true" [contextLevel]="contextLevel"
[contextLevel]="contextLevel" [contextInstanceId]="contextInstanceId" [elementId]="modelName"> [contextInstanceId]="contextInstanceId" [elementId]="modelName">
</core-rich-text-editor> </core-rich-text-editor>
</ion-item> </ion-item>

View File

@ -19,13 +19,12 @@
</ion-item> </ion-item>
<div *ngFor="let file of files; let index=index"> <div *ngFor="let file of files; let index=index">
<!-- Files already attached to the submission, either in online or in offline. --> <!-- Files already attached to the submission, either in online or in offline. -->
<core-file *ngIf="!file.name" [file]="file" [component]="component" [componentId]="componentId" <core-file *ngIf="!file.name" [file]="file" [component]="component" [componentId]="componentId" [canDelete]="true"
[canDelete]="true" (onDelete)="delete(index, true)" [canDownload]="!file.offline"> (onDelete)="delete(index, true)" [canDownload]="!file.offline">
</core-file> </core-file>
<!-- Files added to draft but not attached to submission yet. --> <!-- Files added to draft but not attached to submission yet. -->
<core-local-file *ngIf="file.name" [file]="file" [manage]="true" (onDelete)="delete(index, false)" <core-local-file *ngIf="file.name" [file]="file" [manage]="true" (onDelete)="delete(index, false)" (onRename)="renamed(index, $event)">
(onRename)="renamed(index, $event)">
</core-local-file> </core-local-file>
</div> </div>

View File

@ -9,14 +9,15 @@
<ion-icon *ngIf="item.iconDescription" [name]="item.iconDescription" aria-hidden="true" slot="start"> <ion-icon *ngIf="item.iconDescription" [name]="item.iconDescription" aria-hidden="true" slot="start">
</ion-icon> </ion-icon>
<ion-label> <ion-label>
<p class="item-heading"><core-format-text [clean]="true" [text]="item.content" [filter]="false"></core-format-text></p> <p class="item-heading">
<core-format-text [clean]="true" [text]="item.content" [filter]="false"></core-format-text>
</p>
</ion-label> </ion-label>
<ng-container *ngIf="(item.href || item.action) && item.iconAction"> <ng-container *ngIf="(item.href || item.action) && item.iconAction">
<ion-icon *ngIf="item.iconAction != 'spinner' && item.iconAction != 'toggle'" [name]="item.iconAction" <ion-icon *ngIf="item.iconAction != 'spinner' && item.iconAction != 'toggle'" [name]="item.iconAction"
[class.icon-slash]="item.iconSlash" slot="end" aria-hidden="true"> [class.icon-slash]="item.iconSlash" slot="end" aria-hidden="true">
</ion-icon> </ion-icon>
<ion-spinner *ngIf="item.iconAction == 'spinner'" slot="end" <ion-spinner *ngIf="item.iconAction == 'spinner'" slot="end" [attr.aria-label]="'core.loading' | translate">
[attr.aria-label]="'core.loading' | translate">
</ion-spinner> </ion-spinner>
<ion-toggle *ngIf="item.iconAction == 'toggle'" [(ngModel)]="item.toggle" (ionChange)="item.toggleChanged($event)" slot="end"> <ion-toggle *ngIf="item.iconAction == 'toggle'" [(ngModel)]="item.toggle" (ionChange)="item.toggleChanged($event)" slot="end">
</ion-toggle> </ion-toggle>

View File

@ -8,8 +8,8 @@
<p *ngIf="showTime">{{ timemodified * 1000 | coreFormatDate }}</p> <p *ngIf="showTime">{{ timemodified * 1000 | coreFormatDate }}</p>
</ion-label> </ion-label>
<div slot="end" class="flex-row"> <div slot="end" class="flex-row">
<core-download-refresh [status]="state" [enabled]="canDownload" [loading]="isDownloading" <core-download-refresh [status]="state" [enabled]="canDownload" [loading]="isDownloading" [canTrustDownload]="!alwaysDownload"
[canTrustDownload]="!alwaysDownload" (action)="download()" size="small"> (action)="download()" size="small">
</core-download-refresh> </core-download-refresh>
<ion-button fill="clear" *ngIf="isDownloaded && isIOS" (click)="openFile($event, true)" color="dark" <ion-button fill="clear" *ngIf="isDownloaded && isIOS" (click)="openFile($event, true)" color="dark"
@ -17,8 +17,8 @@
<ion-icon slot="icon-only" [name]="openButtonIcon" aria-hidden="true"></ion-icon> <ion-icon slot="icon-only" [name]="openButtonIcon" aria-hidden="true"></ion-icon>
</ion-button> </ion-button>
<ion-button fill="clear" *ngIf="!isDownloading && canDelete" (click)="delete($event)" <ion-button fill="clear" *ngIf="!isDownloading && canDelete" (click)="delete($event)" [attr.aria-label]="'core.delete' | translate"
[attr.aria-label]="'core.delete' | translate" color="danger" size="small"> color="danger" size="small">
<ion-icon slot="icon-only" name="fas-trash" aria-hidden="true"></ion-icon> <ion-icon slot="icon-only" name="fas-trash" aria-hidden="true"></ion-icon>
</ion-button> </ion-button>
</div> </div>

View File

@ -2,25 +2,19 @@
<core-navbar-buttons slot="end" append *ngIf="initialized && showFullscreenOnToolbar"> <core-navbar-buttons slot="end" append *ngIf="initialized && showFullscreenOnToolbar">
<ion-button fill="clear" (click)="toggleFullscreen()" <ion-button fill="clear" (click)="toggleFullscreen()"
[attr.aria-label]="(fullscreen ? 'core.disablefullscreen' : 'core.fullscreen') | translate" > [attr.aria-label]="(fullscreen ? 'core.disablefullscreen' : 'core.fullscreen') | translate">
<ion-icon *ngIf="!fullscreen" name="fas-expand" slot="icon-only" aria-hidden="true"></ion-icon> <ion-icon *ngIf="!fullscreen" name="fas-expand" slot="icon-only" aria-hidden="true"></ion-icon>
<ion-icon *ngIf="fullscreen" name="fas-compress" slot="icon-only" aria-hidden="true"></ion-icon> <ion-icon *ngIf="fullscreen" name="fas-compress" slot="icon-only" aria-hidden="true"></ion-icon>
</ion-button> </ion-button>
</core-navbar-buttons> </core-navbar-buttons>
<!-- Don't add the iframe until safeUrl is set, adding an iframe with null as src causes the iframe to load the whole app. --> <!-- Don't add the iframe until safeUrl is set, adding an iframe with null as src causes the iframe to load the whole app. -->
<iframe #iframe *ngIf="safeUrl" [hidden]="loading" class="core-iframe" <iframe #iframe *ngIf="safeUrl" [hidden]="loading" class="core-iframe" [ngStyle]="{'width': iframeWidth, 'height': iframeHeight}"
[ngStyle]="{'width': iframeWidth, 'height': iframeHeight}" [src]="safeUrl" [src]="safeUrl" [attr.allowfullscreen]="allowFullscreen ? 'allowfullscreen' : null">
[attr.allowfullscreen]="allowFullscreen ? 'allowfullscreen' : null">
</iframe> </iframe>
<ion-button <ion-button *ngIf="!loading && displayHelp" color="dark" expand="block" fill="clear" (click)="openIframeHelpModal()"
*ngIf="!loading && displayHelp" aria-haspopup="dialog" class="core-button-as-link core-iframe-help">
color="dark" expand="block" fill="clear"
(click)="openIframeHelpModal()"
aria-haspopup="dialog"
class="core-button-as-link core-iframe-help"
>
{{ 'core.iframehelp' | translate }} {{ 'core.iframehelp' | translate }}
</ion-button> </ion-button>

View File

@ -18,8 +18,7 @@
</ion-input> </ion-input>
<div class="buttons" slot="end"> <div class="buttons" slot="end">
<ion-button fill="clear" *ngIf="isIOS" (click)="openFile($event, true)" <ion-button fill="clear" *ngIf="isIOS" (click)="openFile($event, true)" [attr.aria-label]="openButtonLabel | translate">
[attr.aria-label]="openButtonLabel | translate">
<ion-icon slot="icon-only" [name]="openButtonIcon" aria-hidden="true"></ion-icon> <ion-icon slot="icon-only" [name]="openButtonIcon" aria-hidden="true"></ion-icon>
</ion-button> </ion-button>

View File

@ -1,19 +1,5 @@
<img <img *ngIf="!isLocalUrl" [src]="icon" [alt]="showAlt ? modNameTranslated : ''" [attr.role]="!showAlt ? 'presentation' : null"
*ngIf="!isLocalUrl" class="core-module-icon" core-external-content [component]="linkIconWithComponent ? modname : null"
[src]="icon" [componentId]="linkIconWithComponent ? componentId : null" (error)="loadFallbackIcon()">
[alt]="showAlt ? modNameTranslated : ''" <img *ngIf="isLocalUrl" [src]="icon" [alt]="showAlt ? modNameTranslated : ''" [attr.role]="!showAlt ? 'presentation' : null"
[attr.role]="!showAlt ? 'presentation' : null" class="core-module-icon" (error)="loadFallbackIcon()">
class="core-module-icon"
core-external-content
[component]="linkIconWithComponent ? modname : null"
[componentId]="linkIconWithComponent ? componentId : null"
(error)="loadFallbackIcon()"
>
<img
*ngIf="isLocalUrl"
[src]="icon"
[alt]="showAlt ? modNameTranslated : ''"
[attr.role]="!showAlt ? 'presentation' : null"
class="core-module-icon"
(error)="loadFallbackIcon()"
>

View File

@ -1,6 +1,6 @@
<ng-container *ngIf="progress >= 0"> <ng-container *ngIf="progress >= 0">
<progress max="100" [value]="progress" role="progressbar" [attr.aria-valuenow]="progress" <progress max="100" [value]="progress" role="progressbar" [attr.aria-valuenow]="progress" [attr.aria-valuetext]="progressBarValueText"
[attr.aria-valuetext]="progressBarValueText" [attr.aria-describedby]="ariaDescribedBy"> [attr.aria-describedby]="ariaDescribedBy">
</progress> </progress>
<div class="core-progress-text"> <div class="core-progress-text">
<span class="sr-only" *ngIf="a11yText">{{ a11yText | translate }}</span> <span class="sr-only" *ngIf="a11yText">{{ a11yText | translate }}</span>

View File

@ -1,24 +1,12 @@
<form #messageForm> <form #messageForm>
<textarea <textarea class="core-send-message-input" [attr.aria-label]="placeholder" [core-auto-focus]="showKeyboard" [placeholder]="placeholder"
class="core-send-message-input" rows="1" [core-auto-rows]="message" [(ngModel)]="message" name="message" (onResize)="textareaResized()"
[attr.aria-label]="placeholder" (keyup.enter)="enterKeyUp($event)" (keyup.control.enter)="enterKeyUp($event, 'control')"
[core-auto-focus]="showKeyboard" (keyup.meta.enter)="enterKeyUp($event, 'meta')" (keydown.enter)="enterKeyDown($event)"
[placeholder]="placeholder" (keydown.control.enter)="enterKeyDown($event, 'control')" (keydown.meta.enter)="enterKeyDown($event, 'meta')">
rows="1"
[core-auto-rows]="message"
[(ngModel)]="message"
name="message"
(onResize)="textareaResized()"
(keyup.enter)="enterKeyUp($event)"
(keyup.control.enter)="enterKeyUp($event, 'control')"
(keyup.meta.enter)="enterKeyUp($event, 'meta')"
(keydown.enter)="enterKeyDown($event)"
(keydown.control.enter)="enterKeyDown($event, 'control')"
(keydown.meta.enter)="enterKeyDown($event, 'meta')"
>
</textarea> </textarea>
<ion-button fill="clear" size="large" type="submit" [disabled]="!message || sendDisabled" <ion-button fill="clear" size="large" type="submit" [disabled]="!message || sendDisabled" [attr.aria-label]="'core.send' | translate"
[attr.aria-label]="'core.send' | translate" [core-suppress-events] (onClick)="submitForm($event)"> [core-suppress-events] (onClick)="submitForm($event)">
<ion-icon name="send" color="dark" slot="icon-only" aria-hidden="true" flip-rtl></ion-icon> <ion-icon name="send" color="dark" slot="icon-only" aria-hidden="true" flip-rtl></ion-icon>
</ion-button> </ion-button>
</form> </form>

View File

@ -2,6 +2,5 @@
<ng-content></ng-content> <ng-content></ng-content>
</ion-content> </ion-content>
<ion-router-outlet class="content-outlet"></ion-router-outlet> <ion-router-outlet class="content-outlet"></ion-router-outlet>
<core-empty-box class="content-placeholder" icon="fas-arrow-circle-left" [message]="placeholderText | translate" <core-empty-box class="content-placeholder" icon="fas-arrow-circle-left" [message]="placeholderText | translate" [flipIconRtl]="true">
[flipIconRtl]="true">
</core-empty-box> </core-empty-box>

View File

@ -9,24 +9,12 @@
<ion-slides (ionSlideDidChange)="slideChanged()" [options]="slidesOpts" [dir]="direction" role="tablist" <ion-slides (ionSlideDidChange)="slideChanged()" [options]="slidesOpts" [dir]="direction" role="tablist"
[attr.aria-label]="description"> [attr.aria-label]="description">
<ng-container *ngFor="let tab of tabs"> <ng-container *ngFor="let tab of tabs">
<ion-slide <ion-slide role="presentation" [id]="tab.id! + '-tab'" class="tab-slide" tabindex="-1"
role="presentation"
[id]="tab.id! + '-tab'"
class="tab-slide"
tabindex="-1"
[class.selected]="selected == tab.id"> [class.selected]="selected == tab.id">
<ion-tab-button <ion-tab-button (ionTabButtonClick)="selectTab(tab.id, $event)" (keydown)="tabAction.keyDown($event)"
(ionTabButtonClick)="selectTab(tab.id, $event)" (keyup)="tabAction.keyUp(tab.id, $event)" [tab]="tab.page" [layout]="layout" class="{{tab.class}}"
(keydown)="tabAction.keyDown($event)" role="tab" [attr.aria-controls]="tab.id" [attr.aria-selected]="selected == tab.id"
(keyup)="tabAction.keyUp(tab.id, $event)" [tabindex]="selected == tab.id ? 0 : -1">
[tab]="tab.page"
[layout]="layout"
class="{{tab.class}}"
role="tab"
[attr.aria-controls]="tab.id"
[attr.aria-selected]="selected == tab.id"
[tabindex]="selected == tab.id ? 0 : -1"
>
<ion-icon *ngIf="tab.icon" [name]="tab.icon" aria-hidden="true"></ion-icon> <ion-icon *ngIf="tab.icon" [name]="tab.icon" aria-hidden="true"></ion-icon>
<ion-label> <ion-label>
{{ tab.title | translate}} {{ tab.title | translate}}

View File

@ -8,24 +8,12 @@
<ion-slides (ionSlideDidChange)="slideChanged()" [options]="slidesOpts" [dir]="direction" role="tablist" <ion-slides (ionSlideDidChange)="slideChanged()" [options]="slidesOpts" [dir]="direction" role="tablist"
[attr.aria-label]="description"> [attr.aria-label]="description">
<ng-container *ngFor="let tab of tabs"> <ng-container *ngFor="let tab of tabs">
<ion-slide <ion-slide *ngIf="tab.enabled" role="presentation" [hidden]="!hideUntil" class="tab-slide" [id]="tab.id! + '-tab'"
*ngIf="tab.enabled"
role="presentation"
[hidden]="!hideUntil"
class="tab-slide"
[id]="tab.id! + '-tab'"
[class.selected]="selected == tab.id"> [class.selected]="selected == tab.id">
<ion-tab-button <ion-tab-button (click)="selectTab(tab.id, $event)" (keydown)="tabAction.keyDown($event)"
(click)="selectTab(tab.id, $event)" (keyup)="tabAction.keyUp(tab.id, $event)" class="{{tab.class}}" [layout]="layout" role="tab"
(keydown)="tabAction.keyDown($event)" [attr.aria-controls]="tab.id" [attr.aria-selected]="selected == tab.id"
(keyup)="tabAction.keyUp(tab.id, $event)" [tabindex]="selected == tab.id ? 0 : -1">
class="{{tab.class}}"
[layout]="layout"
role="tab"
[attr.aria-controls]="tab.id"
[attr.aria-selected]="selected == tab.id"
[tabindex]="selected == tab.id ? 0 : -1"
>
<ion-icon *ngIf="tab.icon" [name]="tab.icon" aria-hidden="true"></ion-icon> <ion-icon *ngIf="tab.icon" [name]="tab.icon" aria-hidden="true"></ion-icon>
<ion-label> <ion-label>
{{ tab.title | translate}} {{ tab.title | translate}}

View File

@ -1,5 +1,4 @@
<ion-item lines="none" class="core-timer" role="timer" <ion-item lines="none" class="core-timer" role="timer" [ngClass]="{'ion-text-center': align == 'center', 'ion-text-end': align == 'right'}">
[ngClass]="{'ion-text-center': align == 'center', 'ion-text-end': align == 'right'}">
<ion-icon name="fas-clock" slot="start" aria-hidden="true"></ion-icon> <ion-icon name="fas-clock" slot="start" aria-hidden="true"></ion-icon>
<ion-label> <ion-label>
<span *ngIf="timeLeft && timeLeft > 0 && timerText" class="core-timer-text">{{ timerText }}</span> <span *ngIf="timeLeft && timeLeft > 0 && timerText" class="core-timer-text">{{ timerText }}</span>

View File

@ -1,15 +1,6 @@
<img <img *ngIf="avatarUrl" [src]="avatarUrl" [alt]="'core.pictureof' | translate:{$a: fullname}" core-external-content
*ngIf="avatarUrl" onError="this.src='assets/img/user-avatar.png'" (ariaButtonClick)="gotoProfile($event)" [attr.aria-hidden]="!linkProfile"
[src]="avatarUrl" [attr.role]="linkProfile ? 'button' : null" [attr.tabindex]="linkProfile ? 0 : null" [class.clickable]="linkProfile">
[alt]="'core.pictureof' | translate:{$a: fullname}"
core-external-content
onError="this.src='assets/img/user-avatar.png'"
(ariaButtonClick)="gotoProfile($event)"
[attr.aria-hidden]="!linkProfile"
[attr.role]="linkProfile ? 'button' : null"
[attr.tabindex]="linkProfile ? 0 : null"
[class.clickable]="linkProfile"
>
<img *ngIf="!avatarUrl" src="assets/img/user-avatar.png" [alt]="'core.pictureof' | translate:{$a: fullname}" <img *ngIf="!avatarUrl" src="assets/img/user-avatar.png" [alt]="'core.pictureof' | translate:{$a: fullname}"
(ariaButtonClick)="gotoProfile($event)" [attr.aria-hidden]="!linkProfile" [attr.role]="linkProfile ? 'button' : null" (ariaButtonClick)="gotoProfile($event)" [attr.aria-hidden]="!linkProfile" [attr.role]="linkProfile ? 'button' : null"

View File

@ -1,3 +1,5 @@
<ion-item button class="ion-text-wrap divider" (click)="gotoBlock()" detail="true"> <ion-item button class="ion-text-wrap divider" (click)="gotoBlock()" detail="true">
<ion-label><h2>{{ title | translate }}</h2></ion-label> <ion-label>
<h2>{{ title | translate }}</h2>
</ion-label>
</ion-item> </ion-item>

View File

@ -1,8 +1,7 @@
<ion-item-divider class="ion-text-wrap" *ngIf="title" sticky="true"> <ion-item-divider class="ion-text-wrap" *ngIf="title" sticky="true">
<ion-label> <ion-label>
<h2> <h2>
<core-format-text [text]="title | translate" contextLevel="block" [contextInstanceId]="block.instanceid" <core-format-text [text]="title | translate" contextLevel="block" [contextInstanceId]="block.instanceid" [courseId]="courseId">
[courseId]="courseId">
</core-format-text> </core-format-text>
</h2> </h2>
</ion-label> </ion-label>

View File

@ -7,12 +7,7 @@
{{ 'core.comments.commentsnotworking' | translate }} {{ 'core.comments.commentsnotworking' | translate }}
</div> </div>
</core-loading> </core-loading>
<ion-item <ion-item *ngIf="showItem" button [detail]="!countError && commentsLoaded" (click)="openComments($event)" [disabled]="countError">
*ngIf="showItem"
button
[detail]="!countError && commentsLoaded"
(click)="openComments($event)"
[disabled]="countError">
<ion-label> <ion-label>
<core-loading [hideUntil]="commentsLoaded" [fullscreen]="false"> <core-loading [hideUntil]="commentsLoaded" [fullscreen]="false">
<p *ngIf="!countError" class="item-heading"> <p *ngIf="!countError" class="item-heading">

View File

@ -3,18 +3,15 @@
<ng-container *ngIf="completion.istrackeduser"> <ng-container *ngIf="completion.istrackeduser">
<ng-container *ngFor="let rule of details"> <ng-container *ngFor="let rule of details">
<ion-badge *ngIf="rule.statuscomplete" color="success" role="listitem" <ion-badge *ngIf="rule.statuscomplete" color="success" role="listitem" [attr.aria-label]="rule.accessibleDescription">
[attr.aria-label]="rule.accessibleDescription">
<strong>{{ 'core.course.completion_automatic:done' | translate }}</strong> {{ rule.rulevalue.description }} <strong>{{ 'core.course.completion_automatic:done' | translate }}</strong> {{ rule.rulevalue.description }}
</ion-badge> </ion-badge>
<ion-badge *ngIf="rule.statuscompletefail" color="danger" role="listitem" <ion-badge *ngIf="rule.statuscompletefail" color="danger" role="listitem" [attr.aria-label]="rule.accessibleDescription">
[attr.aria-label]="rule.accessibleDescription">
<strong>{{ 'core.course.completion_automatic:failed' | translate }}</strong> {{ rule.rulevalue.description }} <strong>{{ 'core.course.completion_automatic:failed' | translate }}</strong> {{ rule.rulevalue.description }}
</ion-badge> </ion-badge>
<ion-badge *ngIf="rule.statusincomplete" color="medium" role="listitem" <ion-badge *ngIf="rule.statusincomplete" color="medium" role="listitem" [attr.aria-label]="rule.accessibleDescription">
[attr.aria-label]="rule.accessibleDescription">
<strong>{{ 'core.course.completion_automatic:todo' | translate }}</strong> {{ rule.rulevalue.description }} <strong>{{ 'core.course.completion_automatic:todo' | translate }}</strong> {{ rule.rulevalue.description }}
</ion-badge> </ion-badge>
</ng-container> </ng-container>

View File

@ -2,8 +2,7 @@
<ng-container *ngIf="completion.istrackeduser"> <ng-container *ngIf="completion.istrackeduser">
<ng-container *ngIf="completion.state"> <ng-container *ngIf="completion.state">
<ion-button color="success" fill="outline" [attr.aria-label]="accessibleDescription" <ion-button color="success" fill="outline" [attr.aria-label]="accessibleDescription" (click)="completionClicked($event)">
(click)="completionClicked($event)">
<ion-icon name="fas-check" slot="start" aria-hidden="true"></ion-icon> <ion-icon name="fas-check" slot="start" aria-hidden="true"></ion-icon>
{{ 'core.course.completion_manual:done' | translate }} {{ 'core.course.completion_manual:done' | translate }}
</ion-button> </ion-button>

View File

@ -1,5 +1,5 @@
<ion-item class="ion-text-wrap" *ngFor="let item of items" (click)="openCourse(item.courseId)" [attr.aria-label]="item.courseName" <ion-item class="ion-text-wrap" *ngFor="let item of items" (click)="openCourse(item.courseId)" [attr.aria-label]="item.courseName" button
button detail="true"> detail="true">
<ion-icon name="fas-graduation-cap" slot="start" aria-hidden="true"></ion-icon> <ion-icon name="fas-graduation-cap" slot="start" aria-hidden="true"></ion-icon>
<ion-label> <ion-label>
<p class="item-heading">{{ item.courseName }}</p> <p class="item-heading">{{ item.courseName }}</p>

View File

@ -4,8 +4,8 @@
[content]="'core.settings.showdownloadoptions' | translate" (action)="toggleDownload()"> [content]="'core.settings.showdownloadoptions' | translate" (action)="toggleDownload()">
</core-context-menu-item> </core-context-menu-item>
<core-context-menu-item [hidden]="!downloadCourseEnabled" [priority]="1900" <core-context-menu-item [hidden]="!downloadCourseEnabled" [priority]="1900"
[content]="prefetchCourseData.statusTranslatable | translate" (action)="prefetchCourse()" [content]="prefetchCourseData.statusTranslatable | translate" (action)="prefetchCourse()" [iconAction]="prefetchCourseData.icon"
[iconAction]="prefetchCourseData.icon" [closeOnClick]="false"> [closeOnClick]="false">
</core-context-menu-item> </core-context-menu-item>
<core-context-menu-item [priority]="1800" [content]="'core.course.coursesummary' | translate" (action)="openCourseSummary()" <core-context-menu-item [priority]="1800" [content]="'core.course.coursesummary' | translate" (action)="openCourseSummary()"
iconAction="fas-graduation-cap"> iconAction="fas-graduation-cap">
@ -21,9 +21,9 @@
</ion-refresher> </ion-refresher>
<core-loading [hideUntil]="dataLoaded"> <core-loading [hideUntil]="dataLoaded">
<core-course-format [course]="course" [sections]="sections" [initialSectionId]="sectionId" <core-course-format [course]="course" [sections]="sections" [initialSectionId]="sectionId" [initialSectionNumber]="sectionNumber"
[initialSectionNumber]="sectionNumber" [downloadEnabled]="downloadEnabled" [moduleId]="moduleId" [downloadEnabled]="downloadEnabled" [moduleId]="moduleId" (completionChanged)="onCompletionChange($event)"
(completionChanged)="onCompletionChange($event)" class="core-course-format-{{course.format}}"> class="core-course-format-{{course.format}}">
</core-course-format> </core-course-format>
</core-loading> </core-loading>
</ion-content> </ion-content>

View File

@ -1,26 +1,38 @@
<ion-item button class="ion-text-wrap" (click)="action('download')" *ngIf="downloadCourseEnabled" detail="false"> <ion-item button class="ion-text-wrap" (click)="action('download')" *ngIf="downloadCourseEnabled" detail="false">
<ion-icon *ngIf="!prefetch.loading" [name]="prefetch.icon" slot="start" aria-hidden="true"></ion-icon> <ion-icon *ngIf="!prefetch.loading" [name]="prefetch.icon" slot="start" aria-hidden="true"></ion-icon>
<ion-spinner *ngIf="prefetch.loading" slot="start" [attr.aria-label]="'core.loading' | translate"></ion-spinner> <ion-spinner *ngIf="prefetch.loading" slot="start" [attr.aria-label]="'core.loading' | translate"></ion-spinner>
<ion-label><h2>{{ prefetch.statusTranslatable | translate }}</h2></ion-label> <ion-label>
<h2>{{ prefetch.statusTranslatable | translate }}</h2>
</ion-label>
</ion-item> </ion-item>
<ion-item button class="ion-text-wrap" (click)="action('delete')" detail="false" <ion-item button class="ion-text-wrap" (click)="action('delete')" detail="false"
*ngIf="prefetch.status == 'downloaded' || prefetch.status == 'outdated'"> *ngIf="prefetch.status == 'downloaded' || prefetch.status == 'outdated'">
<ion-icon name="fas-trash" slot="start" aria-hidden="true"></ion-icon> <ion-icon name="fas-trash" slot="start" aria-hidden="true"></ion-icon>
<ion-label><h2>{{ 'addon.storagemanager.deletecourse' | translate }}</h2></ion-label> <ion-label>
<h2>{{ 'addon.storagemanager.deletecourse' | translate }}</h2>
</ion-label>
</ion-item> </ion-item>
<ion-item button class="ion-text-wrap" (click)="action('hide')" *ngIf="!course.hidden" detail="false"> <ion-item button class="ion-text-wrap" (click)="action('hide')" *ngIf="!course.hidden" detail="false">
<ion-icon name="fas-eye" slot="start" aria-hidden="true"></ion-icon> <ion-icon name="fas-eye" slot="start" aria-hidden="true"></ion-icon>
<ion-label><h2>{{ 'core.courses.hidecourse' | translate }}</h2></ion-label> <ion-label>
<h2>{{ 'core.courses.hidecourse' | translate }}</h2>
</ion-label>
</ion-item> </ion-item>
<ion-item button class="ion-text-wrap" (click)="action('show')" *ngIf="course.hidden" detail="false"> <ion-item button class="ion-text-wrap" (click)="action('show')" *ngIf="course.hidden" detail="false">
<ion-icon name="fas-eye-slash" slot="start" aria-hidden="true"></ion-icon> <ion-icon name="fas-eye-slash" slot="start" aria-hidden="true"></ion-icon>
<ion-label><h2>{{ 'core.courses.show' | translate }}</h2></ion-label> <ion-label>
<h2>{{ 'core.courses.show' | translate }}</h2>
</ion-label>
</ion-item> </ion-item>
<ion-item button class="ion-text-wrap" (click)="action('favourite')" *ngIf="!course.isfavourite" detail="false"> <ion-item button class="ion-text-wrap" (click)="action('favourite')" *ngIf="!course.isfavourite" detail="false">
<ion-icon name="fas-star" slot="start" aria-hidden="true"></ion-icon> <ion-icon name="fas-star" slot="start" aria-hidden="true"></ion-icon>
<ion-label><h2>{{ 'core.courses.addtofavourites' | translate }}</h2></ion-label> <ion-label>
<h2>{{ 'core.courses.addtofavourites' | translate }}</h2>
</ion-label>
</ion-item> </ion-item>
<ion-item button class="ion-text-wrap" (click)="action('unfavourite')" *ngIf="course.isfavourite" detail="false"> <ion-item button class="ion-text-wrap" (click)="action('unfavourite')" *ngIf="course.isfavourite" detail="false">
<ion-icon name="far-star" slot="start" aria-hidden="true"></ion-icon> <ion-icon name="far-star" slot="start" aria-hidden="true"></ion-icon>
<ion-label><h2>{{ 'core.courses.removefromfavourites' | translate }}</h2></ion-label> <ion-label>
<h2>{{ 'core.courses.removefromfavourites' | translate }}</h2>
</ion-label>
</ion-item> </ion-item>

View File

@ -1,29 +1,11 @@
<div class="core-rte-editor-container" (click)="focusRTE()" [class.toolbar-hidden]="toolbarHidden"> <div class="core-rte-editor-container" (click)="focusRTE()" [class.toolbar-hidden]="toolbarHidden">
<div <div [hidden]="!rteEnabled" #editor class="core-rte-editor" role="textbox" contenteditable="true"
[hidden]="!rteEnabled" [attr.aria-labelledby]="ariaLabelledBy" [attr.data-placeholder-text]="placeholder" (focus)="showToolbar($event)"
#editor (blur)="hideToolbar($event)">
class="core-rte-editor"
role="textbox"
contenteditable="true"
[attr.aria-labelledby]="ariaLabelledBy"
[attr.data-placeholder-text]="placeholder"
(focus)="showToolbar($event)"
(blur)="hideToolbar($event)"
>
</div> </div>
<ion-textarea <ion-textarea [hidden]="rteEnabled" #textarea class="core-textarea" role="textbox" [attr.name]="name" ngControl="control"
[hidden]="rteEnabled" [placeholder]="placeholder" (ionChange)="onChange()" (ionFocus)="showToolbar($event)" (ionBlur)="hideToolbar($event)">
#textarea
class="core-textarea"
role="textbox"
[attr.name]="name"
ngControl="control"
[placeholder]="placeholder"
(ionChange)="onChange()"
(ionFocus)="showToolbar($event)"
(ionBlur)="hideToolbar($event)"
>
</ion-textarea> </ion-textarea>
<div class="core-rte-info-message" *ngIf="infoMessage"> <div class="core-rte-info-message" *ngIf="infoMessage">
@ -33,9 +15,8 @@
</div> </div>
<div #toolbar class="core-rte-toolbar" [class.toolbar-hidden]="toolbarHidden"> <div #toolbar class="core-rte-toolbar" [class.toolbar-hidden]="toolbarHidden">
<button *ngIf="toolbarArrows" class="toolbar-arrow" [class.toolbar-arrow-hidden]="toolbarPrevHidden" <button *ngIf="toolbarArrows" class="toolbar-arrow" [class.toolbar-arrow-hidden]="toolbarPrevHidden" (click)="toolbarPrev($event)"
(click)="toolbarPrev($event)" (keyup)="toolbarPrev($event)" (keyup)="toolbarPrev($event)" (mousedown)="downAction($event)" (keydown)="downAction($event)"
(mousedown)="downAction($event)" (keydown)="downAction($event)"
[attr.aria-label]="'core.previous' | translate"> [attr.aria-label]="'core.previous' | translate">
<ion-icon name="fas-chevron-left" aria-hidden="true"></ion-icon> <ion-icon name="fas-chevron-left" aria-hidden="true"></ion-icon>
</button> </button>
@ -58,8 +39,7 @@
<ion-slide> <ion-slide>
<button [disabled]="!rteEnabled" [attr.aria-pressed]="toolbarStyles.u" [title]="'core.editor.underline' | translate" <button [disabled]="!rteEnabled" [attr.aria-pressed]="toolbarStyles.u" [title]="'core.editor.underline' | translate"
(click)="buttonAction($event, 'underline', 'u')" (keyup)="buttonAction($event, 'underline', 'u')" (click)="buttonAction($event, 'underline', 'u')" (keyup)="buttonAction($event, 'underline', 'u')"
(mousedown)="downAction($event)" (keydown)="downAction($event)" (mousedown)="downAction($event)" (keydown)="downAction($event)">
>
<ion-icon name="fas-underline" aria-hidden="true"></ion-icon> <ion-icon name="fas-underline" aria-hidden="true"></ion-icon>
</button> </button>
</ion-slide> </ion-slide>
@ -72,35 +52,34 @@
</ion-slide> </ion-slide>
<ion-slide> <ion-slide>
<button [disabled]="!rteEnabled" [attr.aria-pressed]="toolbarStyles.p" [title]="'core.editor.p' | translate" <button [disabled]="!rteEnabled" [attr.aria-pressed]="toolbarStyles.p" [title]="'core.editor.p' | translate"
(click)="buttonAction($event, 'p', 'block')" (keyup)="buttonAction($event, 'p', 'block')" (click)="buttonAction($event, 'p', 'block')" (keyup)="buttonAction($event, 'p', 'block')" (mousedown)="downAction($event)"
(mousedown)="downAction($event)" (keydown)="downAction($event)"> (keydown)="downAction($event)">
<ion-icon name="fas-paragraph" aria-hidden="true"></ion-icon> <ion-icon name="fas-paragraph" aria-hidden="true"></ion-icon>
</button> </button>
</ion-slide> </ion-slide>
<ion-slide> <ion-slide>
<button [disabled]="!rteEnabled" [attr.aria-pressed]="toolbarStyles.h3" [title]="'core.editor.h3' | translate" <button [disabled]="!rteEnabled" [attr.aria-pressed]="toolbarStyles.h3" [title]="'core.editor.h3' | translate"
(click)="buttonAction($event, 'h3', 'block')" (keyup)="buttonAction($event, 'h3', 'block')" (click)="buttonAction($event, 'h3', 'block')" (keyup)="buttonAction($event, 'h3', 'block')" (mousedown)="downAction($event)"
(mousedown)="downAction($event)" (keydown)="downAction($event)" > (keydown)="downAction($event)">
<ion-icon name="fas-heading" aria-hidden="true"></ion-icon><span aria-hidden="true">3</span> <ion-icon name="fas-heading" aria-hidden="true"></ion-icon><span aria-hidden="true">3</span>
</button> </button>
</ion-slide> </ion-slide>
<ion-slide> <ion-slide>
<button [disabled]="!rteEnabled" [attr.aria-pressed]="toolbarStyles.h4" [title]="'core.editor.h4' | translate" <button [disabled]="!rteEnabled" [attr.aria-pressed]="toolbarStyles.h4" [title]="'core.editor.h4' | translate"
(click)="buttonAction($event, 'h4', 'block')" (keyup)="buttonAction($event, 'h4', 'block')" (click)="buttonAction($event, 'h4', 'block')" (keyup)="buttonAction($event, 'h4', 'block')" (mousedown)="downAction($event)"
(mousedown)="downAction($event)" (keydown)="downAction($event)"> (keydown)="downAction($event)">
<ion-icon name="fas-heading" aria-hidden="true"></ion-icon><span aria-hidden="true">4</span> <ion-icon name="fas-heading" aria-hidden="true"></ion-icon><span aria-hidden="true">4</span>
</button> </button>
</ion-slide> </ion-slide>
<ion-slide> <ion-slide>
<button [disabled]="!rteEnabled" [attr.aria-pressed]="toolbarStyles.h5" [title]="'core.editor.h5' | translate" <button [disabled]="!rteEnabled" [attr.aria-pressed]="toolbarStyles.h5" [title]="'core.editor.h5' | translate"
(click)="buttonAction($event, 'h5', 'block')" (keyup)="buttonAction($event, 'h5', 'block')" (click)="buttonAction($event, 'h5', 'block')" (keyup)="buttonAction($event, 'h5', 'block')" (mousedown)="downAction($event)"
(mousedown)="downAction($event)" (keydown)="downAction($event)"> (keydown)="downAction($event)">
<ion-icon name="fas-heading" aria-hidden="true"></ion-icon><span aria-hidden="true">5</span> <ion-icon name="fas-heading" aria-hidden="true"></ion-icon><span aria-hidden="true">5</span>
</button> </button>
</ion-slide> </ion-slide>
<ion-slide> <ion-slide>
<button [disabled]="!rteEnabled" [attr.aria-pressed]="toolbarStyles.ul" <button [disabled]="!rteEnabled" [attr.aria-pressed]="toolbarStyles.ul" [title]="'core.editor.unorderedlist' | translate"
[title]="'core.editor.unorderedlist' | translate"
(click)="buttonAction($event, 'insertUnorderedList')" (click)="buttonAction($event, 'insertUnorderedList')" (click)="buttonAction($event, 'insertUnorderedList')" (click)="buttonAction($event, 'insertUnorderedList')"
(mousedown)="downAction($event)" (keydown)="downAction($event)"> (mousedown)="downAction($event)" (keydown)="downAction($event)">
<ion-icon name="fas-list-ul" aria-hidden="true"></ion-icon> <ion-icon name="fas-list-ul" aria-hidden="true"></ion-icon>
@ -114,40 +93,33 @@
</button> </button>
</ion-slide> </ion-slide>
<ion-slide> <ion-slide>
<button [disabled]="!rteEnabled" <button [disabled]="!rteEnabled" (click)="buttonAction($event, 'removeFormat')" (keyup)="buttonAction($event, 'removeFormat')"
(click)="buttonAction($event, 'removeFormat')" (keyup)="buttonAction($event, 'removeFormat')" (mousedown)="downAction($event)" (keydown)="downAction($event)" [title]="'core.editor.clear' | translate">
(mousedown)="downAction($event)" (keydown)="downAction($event)"
[title]="'core.editor.clear' | translate">
<ion-icon name="fas-eraser" aria-hidden="true"></ion-icon> <ion-icon name="fas-eraser" aria-hidden="true"></ion-icon>
</button> </button>
</ion-slide> </ion-slide>
<ion-slide *ngIf="canScanQR"> <ion-slide *ngIf="canScanQR">
<button [disabled]="!rteEnabled" <button [disabled]="!rteEnabled" (click)="scanQR($event)" (keyup)="scanQR($event)" (mousedown)="stopBubble($event)"
(click)="scanQR($event)" (keyup)="scanQR($event)" (keydown)="stopBubble($event)" [title]="'core.scanqr' | translate">
(mousedown)="stopBubble($event)" (keydown)="stopBubble($event)"
[title]="'core.scanqr' | translate">
<ion-icon name="fas-qrcode" aria-hidden="true"></ion-icon> <ion-icon name="fas-qrcode" aria-hidden="true"></ion-icon>
</button> </button>
</ion-slide> </ion-slide>
<ion-slide> <ion-slide>
<button [attr.aria-pressed]="!rteEnabled" [title]="'core.editor.toggle' | translate" <button [attr.aria-pressed]="!rteEnabled" [title]="'core.editor.toggle' | translate" (click)="toggleEditor($event)"
(click)="toggleEditor($event)" (keyup)="toggleEditor($event)" (keyup)="toggleEditor($event)" (mousedown)="downAction($event)" (keydown)="downAction($event)">
(mousedown)="downAction($event)" (keydown)="downAction($event)">
<ion-icon name="fas-code" aria-hidden="true"></ion-icon> <ion-icon name="fas-code" aria-hidden="true"></ion-icon>
</button> </button>
</ion-slide> </ion-slide>
<ion-slide *ngIf="isPhone"> <ion-slide *ngIf="isPhone">
<button [title]="'core.editor.hidetoolbar' | translate" <button [title]="'core.editor.hidetoolbar' | translate" (click)="hideToolbar($event)" (keyup)="hideToolbar($event)"
(click)="hideToolbar($event)" (keyup)="hideToolbar($event)"
(mousedown)="downAction($event)" (keydown)="downAction($event)"> (mousedown)="downAction($event)" (keydown)="downAction($event)">
<ion-icon name="fas-times" aria-hidden="true"></ion-icon> <ion-icon name="fas-times" aria-hidden="true"></ion-icon>
</button> </button>
</ion-slide> </ion-slide>
</ion-slides> </ion-slides>
<button *ngIf="toolbarArrows" class="toolbar-arrow" [class.toolbar-arrow-hidden]="toolbarNextHidden" <button *ngIf="toolbarArrows" class="toolbar-arrow" [class.toolbar-arrow-hidden]="toolbarNextHidden"
[attr.aria-label]="'core.next' | translate" [attr.aria-label]="'core.next' | translate" (click)="toolbarNext($event)" (keyup)="toolbarNext($event)"
(click)="toolbarNext($event)" (keyup)="toolbarNext($event)" (mousedown)="downAction($event)" (keydown)="downAction($event)">
(mousedown)="downAction($event)" (keydown)="downAction($event)" >
<ion-icon name="fas-chevron-right" aria-hidden="true"></ion-icon> <ion-icon name="fas-chevron-right" aria-hidden="true"></ion-icon>
</button> </button>
</div> </div>

View File

@ -1,4 +1,3 @@
<!-- Question contents. --> <!-- Question contents. -->
<core-dynamic-component *ngIf="loaded" [component]="componentClass" [data]="data" class="core-question-{{question?.slot}}"> <core-dynamic-component *ngIf="loaded" [component]="componentClass" [data]="data" class="core-question-{{question?.slot}}">
<!-- This content will only be shown if there's no component to render the question. --> <!-- This content will only be shown if there's no component to render the question. -->
@ -6,7 +5,7 @@
</core-dynamic-component> </core-dynamic-component>
<!-- Sequence check input. --> <!-- Sequence check input. -->
<input *ngIf="seqCheck" type="hidden" name="{{seqCheck.name}}" value="{{seqCheck.value}}" > <input *ngIf="seqCheck" type="hidden" name="{{seqCheck.name}}" value="{{seqCheck.value}}">
<!-- Question behaviour components. --> <!-- Question behaviour components. -->
<core-dynamic-component *ngFor="let componentClass of behaviourComponents" [component]="componentClass" [data]="data"> <core-dynamic-component *ngFor="let componentClass of behaviourComponents" [component]="componentClass" [data]="data">
@ -28,8 +27,8 @@
<!-- Question feedback. --> <!-- Question feedback. -->
<ion-item class="ion-text-wrap core-question-feedback-container" *ngIf="question && question.feedbackHtml"> <ion-item class="ion-text-wrap core-question-feedback-container" *ngIf="question && question.feedbackHtml">
<ion-label> <ion-label>
<core-format-text [component]="component" [componentId]="componentId" [text]="question.feedbackHtml" <core-format-text [component]="component" [componentId]="componentId" [text]="question.feedbackHtml" [contextLevel]="contextLevel"
[contextLevel]="contextLevel" [contextInstanceId]="contextInstanceId" [courseId]="courseId"> [contextInstanceId]="contextInstanceId" [courseId]="courseId">
</core-format-text> </core-format-text>
</ion-label> </ion-label>
</ion-item> </ion-item>
@ -37,8 +36,8 @@
<!-- Question comment. --> <!-- Question comment. -->
<ion-item class="ion-text-wrap core-question-comment" *ngIf="question && question.commentHtml"> <ion-item class="ion-text-wrap core-question-comment" *ngIf="question && question.commentHtml">
<ion-label> <ion-label>
<core-format-text [component]="component" [componentId]="componentId" [text]="question.commentHtml" <core-format-text [component]="component" [componentId]="componentId" [text]="question.commentHtml" [contextLevel]="contextLevel"
[contextLevel]="contextLevel" [contextInstanceId]="contextInstanceId" [courseId]="courseId"> [contextInstanceId]="contextInstanceId" [courseId]="courseId">
</core-format-text> </core-format-text>
</ion-label> </ion-label>
</ion-item> </ion-item>

View File

@ -2,23 +2,21 @@
<form (ngSubmit)="submitForm($event)" role="search" #searchForm> <form (ngSubmit)="submitForm($event)" role="search" #searchForm>
<ion-item> <ion-item>
<ion-label class="sr-only">{{ placeholder }}</ion-label> <ion-label class="sr-only">{{ placeholder }}</ion-label>
<ion-input type="search" name="search" [(ngModel)]="searchText" [placeholder]="placeholder" <ion-input type="search" name="search" [(ngModel)]="searchText" [placeholder]="placeholder" [autocorrect]="autocorrect"
[autocorrect]="autocorrect" [spellcheck]="spellcheck" [core-auto-focus]="autoFocus" [spellcheck]="spellcheck" [core-auto-focus]="autoFocus" [disabled]="disabled" role="searchbox" (ionFocus)="focus($event)">
[disabled]="disabled" role="searchbox" (ionFocus)="focus($event)">
</ion-input> </ion-input>
<ion-button slot="end" fill="clear" type="submit" [attr.aria-label]="searchLabel" <ion-button slot="end" fill="clear" type="submit" [attr.aria-label]="searchLabel"
[disabled]="disabled || !searchText || (searchText.length < lengthCheck)"> [disabled]="disabled || !searchText || (searchText.length < lengthCheck)">
<ion-icon name="fas-search" slot="icon-only" aria-hidden="true"></ion-icon> <ion-icon name="fas-search" slot="icon-only" aria-hidden="true"></ion-icon>
</ion-button> </ion-button>
<ion-button *ngIf="showClear" slot="end" fill="clear" <ion-button *ngIf="showClear" slot="end" fill="clear" [attr.aria-label]="'core.clearsearch' | translate"
[attr.aria-label]="'core.clearsearch' | translate" [disabled]="searched == '' || disabled" [disabled]="searched == '' || disabled" (click)="clearForm()">
(click)="clearForm()">
<ion-icon name="fas-backspace" slot="icon-only" aria-hidden="true" flip-rtl></ion-icon> <ion-icon name="fas-backspace" slot="icon-only" aria-hidden="true" flip-rtl></ion-icon>
</ion-button> </ion-button>
</ion-item> </ion-item>
<ion-list class="core-search-history" [hidden]="!historyShown"> <ion-list class="core-search-history" [hidden]="!historyShown">
<ion-item button class="ion-text-wrap" *ngFor="let item of history" <ion-item button class="ion-text-wrap" *ngFor="let item of history" (click)="historyClicked($event, item.searchedtext)"
(click)="historyClicked($event, item.searchedtext)" tabindex="0" detail="true"> tabindex="0" detail="true">
<ion-icon name="fas-history" slot="start" aria-hidden="true"> <ion-icon name="fas-history" slot="start" aria-hidden="true">
</ion-icon> </ion-icon>
<ion-label>{{item.searchedtext}}</ion-label> <ion-label>{{item.searchedtext}}</ion-label>

View File

@ -9,8 +9,8 @@
<core-loading [hideUntil]="filesLoaded" [fullscreen]="false"> <core-loading [hideUntil]="filesLoaded" [fullscreen]="false">
<ion-list *ngIf="files && files.length > 0"> <ion-list *ngIf="files && files.length > 0">
<ng-container *ngFor="let file of files; let idx = index"> <ng-container *ngFor="let file of files; let idx = index">
<core-local-file *ngIf="file.isFile" [file]="file" [manage]="manage" [overrideClick]="pick" <core-local-file *ngIf="file.isFile" [file]="file" [manage]="manage" [overrideClick]="pick" (onClick)="filePicked(file)"
(onClick)="filePicked(file)" (onDelete)="fileDeleted(idx)" (onRename)="fileRenamed(idx, $event)"> (onDelete)="fileDeleted(idx)" (onRename)="fileRenamed(idx, $event)">
</core-local-file> </core-local-file>
<ion-item button *ngIf="!file.isFile" class="ion-text-wrap item-file" (click)="openFolder(file)" detail="true"> <ion-item button *ngIf="!file.isFile" class="ion-text-wrap item-file" (click)="openFolder(file)" detail="true">
@ -22,8 +22,7 @@
</ng-container> </ng-container>
</ion-list> </ion-list>
<core-empty-box *ngIf="files && !files.length && manage" icon="fas-folder" <core-empty-box *ngIf="files && !files.length && manage" icon="fas-folder" [message]="'core.sharedfiles.nosharedfiles' | translate">
[message]="'core.sharedfiles.nosharedfiles' | translate">
</core-empty-box> </core-empty-box>
<core-empty-box *ngIf="files && !files.length && !manage" icon="fas-folder" <core-empty-box *ngIf="files && !files.length && !manage" icon="fas-folder"

View File

@ -1,7 +1,6 @@
<ion-item class="ion-text-wrap" *ngFor="let item of items" [href]="item.url" core-link [capture]="true"> <ion-item class="ion-text-wrap" *ngFor="let item of items" [href]="item.url" core-link [capture]="true">
<ion-avatar slot="start" *ngIf="item.avatarUrl"> <ion-avatar slot="start" *ngIf="item.avatarUrl">
<img [src]="item.avatarUrl" core-external-content alt="" role="presentation" <img [src]="item.avatarUrl" core-external-content alt="" role="presentation" onError="this.src='assets/img/user-avatar.png'">
onError="this.src='assets/img/user-avatar.png'">
</ion-avatar> </ion-avatar>
<core-mod-icon *ngIf="item.iconUrl" [modicon]="item.iconUrl" slot="start" [showAlt]="false"> <core-mod-icon *ngIf="item.iconUrl" [modicon]="item.iconUrl" slot="start" [showAlt]="false">
</core-mod-icon> </core-mod-icon>

View File

@ -6,15 +6,12 @@
<ion-content> <ion-content>
<core-split-view> <core-split-view>
<ion-refresher slot="fixed" [disabled]="!participants.loaded || searchInProgress" <ion-refresher slot="fixed" [disabled]="!participants.loaded || searchInProgress" (ionRefresh)="refreshParticipants($event.target)">
(ionRefresh)="refreshParticipants($event.target)">
<ion-refresher-content pullingText="{{ 'core.pulltorefresh' | translate }}"></ion-refresher-content> <ion-refresher-content pullingText="{{ 'core.pulltorefresh' | translate }}"></ion-refresher-content>
</ion-refresher> </ion-refresher>
<core-search-box *ngIf="showSearchBox" <core-search-box *ngIf="showSearchBox" [disabled]="searchInProgress" [spellcheck]="false" [autoFocus]="true" [lengthCheck]="1"
[disabled]="searchInProgress" [spellcheck]="false" [autoFocus]="true" [lengthCheck]="1" autocorrect="off" searchArea="CoreUserParticipants" (onSubmit)="search($event)" (onClear)="clearSearch()">
autocorrect="off" searchArea="CoreUserParticipants"
(onSubmit)="search($event)" (onClear)="clearSearch()">
</core-search-box> </core-search-box>
<core-loading [hideUntil]="participants.loaded"> <core-loading [hideUntil]="participants.loaded">
@ -27,9 +24,9 @@
</core-empty-box> </core-empty-box>
<ion-list *ngIf="!participants.empty"> <ion-list *ngIf="!participants.empty">
<ion-item *ngFor="let participant of participants.items" <ion-item *ngFor="let participant of participants.items" class="ion-text-wrap"
class="ion-text-wrap" [attr.aria-current]="participants.getItemAriaCurrent(participant)" [attr.aria-current]="participants.getItemAriaCurrent(participant)" [attr.aria-label]="participant.fullname"
[attr.aria-label]="participant.fullname" (click)="participants.select(participant)" button detail="true"> (click)="participants.select(participant)" button detail="true">
<core-user-avatar [user]="participant" [linkProfile]="false" [checkOnline]="true" slot="start"> <core-user-avatar [user]="participant" [linkProfile]="false" [checkOnline]="true" slot="start">
</core-user-avatar> </core-user-avatar>
@ -57,8 +54,8 @@
</ion-item> </ion-item>
</ion-list> </ion-list>
<core-infinite-loading [enabled]="participants.loaded && !participants.completed" <core-infinite-loading [enabled]="participants.loaded && !participants.completed" (action)="fetchMoreParticipants($event)"
(action)="fetchMoreParticipants($event)" [error]="fetchMoreParticipantsFailed"> [error]="fetchMoreParticipantsFailed">
</core-infinite-loading> </core-infinite-loading>
</core-loading> </core-loading>
</core-split-view> </core-split-view>