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

View File

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

View File

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

View File

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

View File

@ -8,7 +8,9 @@
<ng-container *ngIf="filter.course || filter.category || filter.group">
<ion-radio-group [(ngModel)]="courseId" (ionChange)="onChange()">
<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-item>
</ion-radio-group>

View File

@ -18,7 +18,7 @@
</span>
<p class="item-heading">
<core-format-text [text]="event.name" [contextLevel]="event.contextLevel"
[contextInstanceId]="event.contextInstanceId"></core-format-text>
[contextInstanceId]="event.contextInstanceId"></core-format-text>
</p>
<p [innerHTML]="event.formattedtime"></p>
</ion-label>

View File

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

View File

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

View File

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

View File

@ -1,8 +1,8 @@
<ion-item *ngIf="commentsEnabled" class="ion-text-wrap" (click)="showComments($event)" detail="true" button>
<ion-label>
<h2>{{plugin.name}}</h2>
<core-comments contextLevel="module" [instanceId]="assign.cmid" component="assignsubmission_comments"
[itemId]="submission.id" area="submission_comments" [title]="plugin.name" [courseId]="assign.course">
<core-comments contextLevel="module" [instanceId]="assign.cmid" component="assignsubmission_comments" [itemId]="submission.id"
area="submission_comments" [title]="plugin.name" [courseId]="assign.course">
</core-comments>
</ion-label>
</ion-item>

View File

@ -11,7 +11,9 @@
<!-- Edit -->
<div *ngIf="edit">
<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>
<core-attachments [files]="files" [maxSize]="maxSize" [maxSubmissions]="maxSubmissions" [courseId]="assign.course"
[component]="component" [componentId]="assign.cmid" [acceptedTypes]="acceptedTypes" [allowOffline]="allowOffline">

View File

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

View File

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

View File

@ -1,12 +1,12 @@
<span *ngIf="editMode && form" [formGroup]="form">
<span [core-mark-required]="field.required" class="core-mark-required"></span>
<core-attachments [files]="files" [maxSize]="maxSizeBytes" maxSubmissions="1" [component]="component"
[componentId]="componentId" [allowOffline]="true" acceptedTypes="image" [courseId]="database?.course">
<core-attachments [files]="files" [maxSize]="maxSizeBytes" maxSubmissions="1" [component]="component" [componentId]="componentId"
[allowOffline]="true" acceptedTypes="image" [courseId]="database?.course">
</core-attachments>
<core-input-errors *ngIf="error" [errorText]="error"></core-input-errors>
<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>
</span>
@ -15,8 +15,8 @@
</span>
<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>
<img *ngIf="showMode && imageUrl" [src]="imageUrl" [alt]="title" class="core-media-adapt-width listMode_picture"
[attr.width]="width" [attr.height]="height" core-external-content/>
<img *ngIf="showMode && imageUrl" [src]="imageUrl" [alt]="title" class="core-media-adapt-width listMode_picture" [attr.width]="width"
[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>
<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"
[name]="'f_'+field.id" [component]="component" [componentId]="componentId" [autoSave]="true"
contextLevel="module" [contextInstanceId]="componentId" [elementId]="'field_'+field.id" ngDefaultControl>
<core-rich-text-editor *ngIf="editMode" [control]="form.controls['f_'+field.id]" [placeholder]="field.name" [name]="'f_'+field.id"
[component]="component" [componentId]="componentId" [autoSave]="true" contextLevel="module" [contextInstanceId]="componentId"
[elementId]="'field_'+field.id" ngDefaultControl>
</core-rich-text-editor>
<core-input-errors *ngIf="error && editMode" [control]="form.controls['f_'+field.id]" [errorText]="error"></core-input-errors>
</span>

View File

@ -8,20 +8,19 @@
<ion-item button class="ion-text-wrap" (click)="deletePost()" *ngIf="offlinePost || (canDelete && isOnline)" detail="false">
<ion-icon name="fas-trash" slot="start" aria-hidden="true"></ion-icon>
<ion-label>
<p class="item-heading" *ngIf="!offlinePost">{{ 'addon.mod_forum.delete' | translate }}</p>
<p class="item-heading" *ngIf="offlinePost">{{ 'core.discard' | translate }}</p>
<p class="item-heading" *ngIf="!offlinePost">{{ 'addon.mod_forum.delete' | translate }}</p>
<p class="item-heading" *ngIf="offlinePost">{{ 'core.discard' | translate }}</p>
</ion-label>
</ion-item>
<ion-item class="ion-text-wrap" *ngIf="wordCount">
<ion-label>
<p class="item-heading">{{ 'core.numwords' | translate: {'$a': wordCount} }}</p>
<p class="item-heading">{{ 'core.numwords' | translate: {'$a': wordCount} }}</p>
</ion-label>
</ion-item>
<ion-item class="ion-text-wrap" [href]="url" *ngIf="url" core-link capture="false" button detail="false"
[showBrowserWarning]="false">
<ion-item class="ion-text-wrap" [href]="url" *ngIf="url" core-link capture="false" button detail="false" [showBrowserWarning]="false">
<ion-icon name="fas-external-link-alt" slot="start" aria-hidden="true"></ion-icon>
<ion-label>
<p class="item-heading">{{ 'core.openinbrowser' | translate }}</p>
<p class="item-heading">{{ 'core.openinbrowser' | translate }}</p>
</ion-label>
</ion-item>
</core-loading>

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,11 +1,11 @@
<ion-list *ngIf="question && (question.text || question.text === '')">
<!-- "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-label>
<core-format-text [component]="component" [componentId]="componentId" [text]="question.text"
[contextLevel]="contextLevel" [contextInstanceId]="contextInstanceId" [courseId]="courseId">
<core-format-text [component]="component" [componentId]="componentId" [text]="question.text" [contextLevel]="contextLevel"
[contextInstanceId]="contextInstanceId" [courseId]="courseId">
</core-format-text>
</ion-label>
</ion-item>

View File

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

View File

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

View File

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

View File

@ -14,10 +14,9 @@
<!-- Checkbox for multiple choice. -->
<ng-container *ngIf="multiQuestion.multi">
<ion-item class="ion-text-wrap answer" *ngFor="let option of multiQuestion.options">
<ion-label [color]='(option.isCorrect === 1 ? "success": "") + (option.isCorrect === 0 ? "danger": "")'
[class]="option.class">
<core-format-text [component]="component" [componentId]="componentId" [text]="option.text"
[contextLevel]="contextLevel" [contextInstanceId]="contextInstanceId" [courseId]="courseId">
<ion-label [color]='(option.isCorrect === 1 ? "success": "") + (option.isCorrect === 0 ? "danger": "")' [class]="option.class">
<core-format-text [component]="component" [componentId]="componentId" [text]="option.text" [contextLevel]="contextLevel"
[contextInstanceId]="contextInstanceId" [courseId]="courseId">
</core-format-text>
<div *ngIf="option.feedback" class="specificfeedback">
<core-format-text [component]="component" [componentId]="componentId" [text]="option.feedback"
@ -41,12 +40,11 @@
</ng-container>
<!-- Radio buttons for single choice. -->
<ion-radio-group *ngIf="!multiQuestion.multi" [(ngModel)]="multiQuestion.singleChoiceModel"
[name]="multiQuestion.optionsName">
<ion-radio-group *ngIf="!multiQuestion.multi" [(ngModel)]="multiQuestion.singleChoiceModel" [name]="multiQuestion.optionsName">
<ion-item class="ion-text-wrap answer" *ngFor="let option of multiQuestion.options">
<ion-label [class]="option.class">
<core-format-text [component]="component" [componentId]="componentId" [text]="option.text"
[contextLevel]="contextLevel" [contextInstanceId]="contextInstanceId" [courseId]="courseId">
<core-format-text [component]="component" [componentId]="componentId" [text]="option.text" [contextLevel]="contextLevel"
[contextInstanceId]="contextInstanceId" [courseId]="courseId">
</core-format-text>
<div *ngIf="option.feedback" class="specificfeedback">
<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-item class="ion-text-wrap addon-qtype-shortanswer-text">
<ion-label>
<core-format-text [component]="component" [componentId]="componentId" [text]="textQuestion.text"
[contextLevel]="contextLevel" [contextInstanceId]="contextInstanceId" [courseId]="courseId">
<core-format-text [component]="component" [componentId]="componentId" [text]="textQuestion.text" [contextLevel]="contextLevel"
[contextInstanceId]="contextInstanceId" [courseId]="courseId">
</core-format-text>
</ion-label>
</ion-item>
@ -13,8 +13,8 @@
[attr.name]="textQuestion.input.name" [value]="textQuestion.input.value" autocorrect="off"
[disabled]="textQuestion.input.readOnly">
</ion-input>
<ion-icon *ngIf="textQuestion.input.correctIcon" class="core-correct-icon" slot="end"
[name]="textQuestion.input.correctIcon" [color]="[textQuestion.input.correctIconColor]">
<ion-icon *ngIf="textQuestion.input.correctIcon" class="core-correct-icon" slot="end" [name]="textQuestion.input.correctIcon"
[color]="[textQuestion.input.correctIconColor]">
</ion-icon>
</ion-item>
</ion-list>

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -9,16 +9,17 @@
<ion-icon *ngIf="item.iconDescription" [name]="item.iconDescription" aria-hidden="true" slot="start">
</ion-icon>
<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>
<ng-container *ngIf="(item.href || item.action) && item.iconAction">
<ion-icon *ngIf="item.iconAction != 'spinner' && item.iconAction != 'toggle'" [name]="item.iconAction"
[class.icon-slash]="item.iconSlash" slot="end" aria-hidden="true">
</ion-icon>
<ion-spinner *ngIf="item.iconAction == 'spinner'" slot="end"
[attr.aria-label]="'core.loading' | translate">
<ion-spinner *ngIf="item.iconAction == 'spinner'" slot="end" [attr.aria-label]="'core.loading' | translate">
</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>
</ng-container>
<ion-badge class="{{item.badgeClass}}" slot="end" *ngIf="item.badge">

View File

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

View File

@ -2,25 +2,19 @@
<core-navbar-buttons slot="end" append *ngIf="initialized && showFullscreenOnToolbar">
<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-compress" slot="icon-only" aria-hidden="true"></ion-icon>
</ion-button>
</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. -->
<iframe #iframe *ngIf="safeUrl" [hidden]="loading" class="core-iframe"
[ngStyle]="{'width': iframeWidth, 'height': iframeHeight}" [src]="safeUrl"
[attr.allowfullscreen]="allowFullscreen ? 'allowfullscreen' : null">
<iframe #iframe *ngIf="safeUrl" [hidden]="loading" class="core-iframe" [ngStyle]="{'width': iframeWidth, 'height': iframeHeight}"
[src]="safeUrl" [attr.allowfullscreen]="allowFullscreen ? 'allowfullscreen' : null">
</iframe>
<ion-button
*ngIf="!loading && displayHelp"
color="dark" expand="block" fill="clear"
(click)="openIframeHelpModal()"
aria-haspopup="dialog"
class="core-button-as-link core-iframe-help"
>
<ion-button *ngIf="!loading && displayHelp" color="dark" expand="block" fill="clear" (click)="openIframeHelpModal()"
aria-haspopup="dialog" class="core-button-as-link core-iframe-help">
{{ 'core.iframehelp' | translate }}
</ion-button>

View File

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

View File

@ -1,19 +1,5 @@
<img
*ngIf="!isLocalUrl"
[src]="icon"
[alt]="showAlt ? modNameTranslated : ''"
[attr.role]="!showAlt ? 'presentation' : null"
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()"
>
<img *ngIf="!isLocalUrl" [src]="icon" [alt]="showAlt ? modNameTranslated : ''" [attr.role]="!showAlt ? 'presentation' : null"
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">
<progress max="100" [value]="progress" role="progressbar" [attr.aria-valuenow]="progress"
[attr.aria-valuetext]="progressBarValueText" [attr.aria-describedby]="ariaDescribedBy">
<progress max="100" [value]="progress" role="progressbar" [attr.aria-valuenow]="progress" [attr.aria-valuetext]="progressBarValueText"
[attr.aria-describedby]="ariaDescribedBy">
</progress>
<div class="core-progress-text">
<span class="sr-only" *ngIf="a11yText">{{ a11yText | translate }}</span>

View File

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

View File

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

View File

@ -9,24 +9,12 @@
<ion-slides (ionSlideDidChange)="slideChanged()" [options]="slidesOpts" [dir]="direction" role="tablist"
[attr.aria-label]="description">
<ng-container *ngFor="let tab of tabs">
<ion-slide
role="presentation"
[id]="tab.id! + '-tab'"
class="tab-slide"
tabindex="-1"
<ion-slide role="presentation" [id]="tab.id! + '-tab'" class="tab-slide" tabindex="-1"
[class.selected]="selected == tab.id">
<ion-tab-button
(ionTabButtonClick)="selectTab(tab.id, $event)"
(keydown)="tabAction.keyDown($event)"
(keyup)="tabAction.keyUp(tab.id, $event)"
[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-tab-button (ionTabButtonClick)="selectTab(tab.id, $event)" (keydown)="tabAction.keyDown($event)"
(keyup)="tabAction.keyUp(tab.id, $event)" [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-label>
{{ tab.title | translate}}

View File

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

View File

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

View File

@ -1,15 +1,6 @@
<img
*ngIf="avatarUrl"
[src]="avatarUrl"
[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]="avatarUrl" [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}"
(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-label><h2>{{ title | translate }}</h2></ion-label>
<ion-label>
<h2>{{ title | translate }}</h2>
</ion-label>
</ion-item>

View File

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

View File

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

View File

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

View File

@ -2,8 +2,7 @@
<ng-container *ngIf="completion.istrackeduser">
<ng-container *ngIf="completion.state">
<ion-button color="success" fill="outline" [attr.aria-label]="accessibleDescription"
(click)="completionClicked($event)">
<ion-button color="success" fill="outline" [attr.aria-label]="accessibleDescription" (click)="completionClicked($event)">
<ion-icon name="fas-check" slot="start" aria-hidden="true"></ion-icon>
{{ 'core.course.completion_manual:done' | translate }}
</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"
button detail="true">
<ion-item class="ion-text-wrap" *ngFor="let item of items" (click)="openCourse(item.courseId)" [attr.aria-label]="item.courseName" button
detail="true">
<ion-icon name="fas-graduation-cap" slot="start" aria-hidden="true"></ion-icon>
<ion-label>
<p class="item-heading">{{ item.courseName }}</p>

View File

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

View File

@ -1,26 +1,38 @@
<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-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 button class="ion-text-wrap" (click)="action('delete')" detail="false"
*ngIf="prefetch.status == 'downloaded' || prefetch.status == 'outdated'">
<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 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-label><h2>{{ 'core.courses.hidecourse' | translate }}</h2></ion-label>
<ion-label>
<h2>{{ 'core.courses.hidecourse' | translate }}</h2>
</ion-label>
</ion-item>
<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-label><h2>{{ 'core.courses.show' | translate }}</h2></ion-label>
<ion-label>
<h2>{{ 'core.courses.show' | translate }}</h2>
</ion-label>
</ion-item>
<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-label><h2>{{ 'core.courses.addtofavourites' | translate }}</h2></ion-label>
<ion-label>
<h2>{{ 'core.courses.addtofavourites' | translate }}</h2>
</ion-label>
</ion-item>
<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-label><h2>{{ 'core.courses.removefromfavourites' | translate }}</h2></ion-label>
<ion-label>
<h2>{{ 'core.courses.removefromfavourites' | translate }}</h2>
</ion-label>
</ion-item>

View File

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

View File

@ -1,4 +1,3 @@
<!-- Question contents. -->
<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. -->
@ -6,7 +5,7 @@
</core-dynamic-component>
<!-- 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. -->
<core-dynamic-component *ngFor="let componentClass of behaviourComponents" [component]="componentClass" [data]="data">
@ -15,7 +14,7 @@
<!-- Question validation error. -->
<ion-item class="ion-text-wrap core-danger-item" *ngIf="validationError">
<ion-label>
<p>{{ validationError }}</p>
<p>{{ validationError }}</p>
</ion-label>
</ion-item>
@ -28,8 +27,8 @@
<!-- Question feedback. -->
<ion-item class="ion-text-wrap core-question-feedback-container" *ngIf="question && question.feedbackHtml">
<ion-label>
<core-format-text [component]="component" [componentId]="componentId" [text]="question.feedbackHtml"
[contextLevel]="contextLevel" [contextInstanceId]="contextInstanceId" [courseId]="courseId">
<core-format-text [component]="component" [componentId]="componentId" [text]="question.feedbackHtml" [contextLevel]="contextLevel"
[contextInstanceId]="contextInstanceId" [courseId]="courseId">
</core-format-text>
</ion-label>
</ion-item>
@ -37,8 +36,8 @@
<!-- Question comment. -->
<ion-item class="ion-text-wrap core-question-comment" *ngIf="question && question.commentHtml">
<ion-label>
<core-format-text [component]="component" [componentId]="componentId" [text]="question.commentHtml"
[contextLevel]="contextLevel" [contextInstanceId]="contextInstanceId" [courseId]="courseId">
<core-format-text [component]="component" [componentId]="componentId" [text]="question.commentHtml" [contextLevel]="contextLevel"
[contextInstanceId]="contextInstanceId" [courseId]="courseId">
</core-format-text>
</ion-label>
</ion-item>

View File

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

View File

@ -9,8 +9,8 @@
<core-loading [hideUntil]="filesLoaded" [fullscreen]="false">
<ion-list *ngIf="files && files.length > 0">
<ng-container *ngFor="let file of files; let idx = index">
<core-local-file *ngIf="file.isFile" [file]="file" [manage]="manage" [overrideClick]="pick"
(onClick)="filePicked(file)" (onDelete)="fileDeleted(idx)" (onRename)="fileRenamed(idx, $event)">
<core-local-file *ngIf="file.isFile" [file]="file" [manage]="manage" [overrideClick]="pick" (onClick)="filePicked(file)"
(onDelete)="fileDeleted(idx)" (onRename)="fileRenamed(idx, $event)">
</core-local-file>
<ion-item button *ngIf="!file.isFile" class="ion-text-wrap item-file" (click)="openFolder(file)" detail="true">
@ -22,8 +22,7 @@
</ng-container>
</ion-list>
<core-empty-box *ngIf="files && !files.length && manage" icon="fas-folder"
[message]="'core.sharedfiles.nosharedfiles' | translate">
<core-empty-box *ngIf="files && !files.length && manage" icon="fas-folder" [message]="'core.sharedfiles.nosharedfiles' | translate">
</core-empty-box>
<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-avatar slot="start" *ngIf="item.avatarUrl">
<img [src]="item.avatarUrl" core-external-content alt="" role="presentation"
onError="this.src='assets/img/user-avatar.png'">
<img [src]="item.avatarUrl" core-external-content alt="" role="presentation" onError="this.src='assets/img/user-avatar.png'">
</ion-avatar>
<core-mod-icon *ngIf="item.iconUrl" [modicon]="item.iconUrl" slot="start" [showAlt]="false">
</core-mod-icon>

View File

@ -3,4 +3,4 @@
<ion-label>
<h2>{{ item.heading }}</h2>
</ion-label>
</ion-item>
</ion-item>

View File

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