forked from CIT/Vmeda.Online
		
	MOBILE-3149 module: Add collapsible footer buttons inside activities
This commit is contained in:
		
							parent
							
								
									859230ddf3
								
							
						
					
					
						commit
						3a11cdbfe2
					
				@ -576,7 +576,6 @@
 | 
			
		||||
  "addon.mod_feedback.minimal": "feedback",
 | 
			
		||||
  "addon.mod_feedback.mode": "feedback",
 | 
			
		||||
  "addon.mod_feedback.modulenameplural": "feedback",
 | 
			
		||||
  "addon.mod_feedback.next_page": "feedback",
 | 
			
		||||
  "addon.mod_feedback.non_anonymous": "feedback",
 | 
			
		||||
  "addon.mod_feedback.non_anonymous_entries": "feedback",
 | 
			
		||||
  "addon.mod_feedback.non_respondents_students": "feedback",
 | 
			
		||||
@ -586,7 +585,6 @@
 | 
			
		||||
  "addon.mod_feedback.overview": "feedback",
 | 
			
		||||
  "addon.mod_feedback.page_after_submit": "feedback",
 | 
			
		||||
  "addon.mod_feedback.preview": "moodle",
 | 
			
		||||
  "addon.mod_feedback.previous_page": "feedback",
 | 
			
		||||
  "addon.mod_feedback.questions": "feedback",
 | 
			
		||||
  "addon.mod_feedback.questionscountdescription": "local_moodlemobileapp",
 | 
			
		||||
  "addon.mod_feedback.response_nr": "feedback",
 | 
			
		||||
 | 
			
		||||
@ -60,21 +60,23 @@
 | 
			
		||||
            (onLoading)="setLoadingComments($event)" [showItem]="true">
 | 
			
		||||
        </core-comments>
 | 
			
		||||
 | 
			
		||||
        <ion-grid *ngIf="hasPrevious || hasNext">
 | 
			
		||||
            <ion-row class="ion-align-items-center">
 | 
			
		||||
                <ion-col *ngIf="hasPrevious">
 | 
			
		||||
                    <ion-button expand="block" fill="outline" (click)="gotoEntry(offset! -1)">
 | 
			
		||||
                        <ion-icon name="fas-chevron-left" slot="start" aria-hidden="true"></ion-icon>
 | 
			
		||||
                        {{ 'core.previous' | translate }}
 | 
			
		||||
        <div collapsible-footer *ngIf="entryLoaded && hasPrevious || hasNext" slot="fixed">
 | 
			
		||||
            <ion-row class="ion-justify-content-between ion-align-items-center ion-no-padding ion-wrap">
 | 
			
		||||
                <ion-col class="ion-text-start ion-no-padding core-navigation-arrow" size="auto">
 | 
			
		||||
                    <ion-button [disabled]="!hasPrevious" fill="clear" color="dark" [attr.aria-label]="'core.previous' | translate"
 | 
			
		||||
                        (click)="gotoEntry(offset! -1)">
 | 
			
		||||
                        <ion-icon name="fas-chevron-left" slot="icon-only" aria-hidden="true"></ion-icon>
 | 
			
		||||
                    </ion-button>
 | 
			
		||||
                </ion-col>
 | 
			
		||||
                <ion-col *ngIf="hasNext">
 | 
			
		||||
                    <ion-button expand="block" (click)="gotoEntry(offset! + 1)">
 | 
			
		||||
                        {{ 'core.next' | translate }}
 | 
			
		||||
                        <ion-icon name="fas-chevron-right" slot="end" aria-hidden="true"></ion-icon>
 | 
			
		||||
                <ion-col class="ion-text-center">
 | 
			
		||||
                </ion-col>
 | 
			
		||||
                <ion-col class="ion-text-end ion-no-padding core-navigation-arrow" size="auto">
 | 
			
		||||
                    <ion-button [disabled]="!hasNext" fill="clear" color="dark" [attr.aria-label]=" 'core.next' | translate"
 | 
			
		||||
                        (click)="gotoEntry(offset! + 1)">
 | 
			
		||||
                        <ion-icon name="fas-chevron-right" slot="icon-only" aria-hidden="true"></ion-icon>
 | 
			
		||||
                    </ion-button>
 | 
			
		||||
                </ion-col>
 | 
			
		||||
            </ion-row>
 | 
			
		||||
        </ion-grid>
 | 
			
		||||
        </div>
 | 
			
		||||
    </core-loading>
 | 
			
		||||
</ion-content>
 | 
			
		||||
 | 
			
		||||
@ -18,7 +18,6 @@
 | 
			
		||||
    "minimal": "Minimum",
 | 
			
		||||
    "mode": "Mode",
 | 
			
		||||
    "modulenameplural": "Feedback",
 | 
			
		||||
    "next_page": "Next page",
 | 
			
		||||
    "non_anonymous": "User's name will be logged and shown with answers",
 | 
			
		||||
    "non_anonymous_entries": "Non anonymous entries ({{$a}})",
 | 
			
		||||
    "non_respondents_students": "Non-respondent students ({{$a}})",
 | 
			
		||||
@ -28,7 +27,6 @@
 | 
			
		||||
    "overview": "Overview",
 | 
			
		||||
    "page_after_submit": "Completion message",
 | 
			
		||||
    "preview": "Preview",
 | 
			
		||||
    "previous_page": "Previous page",
 | 
			
		||||
    "questions": "Questions",
 | 
			
		||||
    "questionscountdescription": "There are {{count}} questions.",
 | 
			
		||||
    "response_nr": "Response number",
 | 
			
		||||
 | 
			
		||||
@ -109,32 +109,31 @@
 | 
			
		||||
                        </ng-container>
 | 
			
		||||
                    </ng-container>
 | 
			
		||||
                </ng-container>
 | 
			
		||||
                <ion-grid *ngIf="!preview">
 | 
			
		||||
                    <ion-row class="ion-align-items-center">
 | 
			
		||||
                        <ion-col *ngIf="hasPrevPage">
 | 
			
		||||
                            <ion-button expand="block" fill="outline" (click)="gotoPage(true)" class="ion-text-wrap">
 | 
			
		||||
                                <ion-icon name="fas-chevron-left" slot="start" aria-hidden="true"></ion-icon>
 | 
			
		||||
                                {{ 'addon.mod_feedback.previous_page' | translate }}
 | 
			
		||||
                            </ion-button>
 | 
			
		||||
                        </ion-col>
 | 
			
		||||
                        <ion-col *ngIf="hasNextPage">
 | 
			
		||||
                            <ion-button expand="block" (click)="gotoPage(false)" class="ion-text-wrap">
 | 
			
		||||
                                {{ 'addon.mod_feedback.next_page' | translate }}
 | 
			
		||||
                                <ion-icon name="fas-chevron-right" slot="end" aria-hidden="true"></ion-icon>
 | 
			
		||||
                            </ion-button>
 | 
			
		||||
                        </ion-col>
 | 
			
		||||
                        <ion-col *ngIf="!hasNextPage">
 | 
			
		||||
                            <ion-button expand="block" (click)="gotoPage(false)" class="ion-text-wrap">
 | 
			
		||||
                                {{ 'addon.mod_feedback.save_entries' | translate }}
 | 
			
		||||
                            </ion-button>
 | 
			
		||||
                        </ion-col>
 | 
			
		||||
                    </ion-row>
 | 
			
		||||
                </ion-grid>
 | 
			
		||||
 | 
			
		||||
                <ion-row class="ion-align-items-center" *ngIf="!preview">
 | 
			
		||||
                    <ion-col *ngIf="hasPrevPage">
 | 
			
		||||
                        <ion-button expand="block" fill="outline" (click)="gotoPage(true)" class="ion-text-wrap">
 | 
			
		||||
                            <ion-icon name="fas-chevron-left" slot="start" aria-hidden="true"></ion-icon>
 | 
			
		||||
                            {{ 'core.previous' | translate }}
 | 
			
		||||
                        </ion-button>
 | 
			
		||||
                    </ion-col>
 | 
			
		||||
                    <ion-col *ngIf="hasNextPage">
 | 
			
		||||
                        <ion-button expand="block" (click)="gotoPage(false)" class="ion-text-wrap">
 | 
			
		||||
                            {{ 'core.next' | translate }}
 | 
			
		||||
                            <ion-icon name="fas-chevron-right" slot="end" aria-hidden="true"></ion-icon>
 | 
			
		||||
                        </ion-button>
 | 
			
		||||
                    </ion-col>
 | 
			
		||||
                    <ion-col *ngIf="!hasNextPage">
 | 
			
		||||
                        <ion-button expand="block" (click)="gotoPage(false)" class="ion-text-wrap">
 | 
			
		||||
                            {{ 'core.submit' | translate }}
 | 
			
		||||
                        </ion-button>
 | 
			
		||||
                    </ion-col>
 | 
			
		||||
                </ion-row>
 | 
			
		||||
            </ion-list>
 | 
			
		||||
        </ng-container>
 | 
			
		||||
 | 
			
		||||
        <ion-card class="core-success-card" *ngIf="completed">
 | 
			
		||||
            <ion-item>
 | 
			
		||||
            <ion-item class="ion-text-wrap">
 | 
			
		||||
                <ion-icon name="fas-check" slot="start" aria-hidden="true"></ion-icon>
 | 
			
		||||
                <ion-label>
 | 
			
		||||
                    <p *ngIf="!completionPageContents && !completedOffline">
 | 
			
		||||
@ -143,32 +142,25 @@
 | 
			
		||||
                    <p *ngIf="!completionPageContents && completedOffline">
 | 
			
		||||
                        {{ 'addon.mod_feedback.feedback_submitted_offline' | translate }}
 | 
			
		||||
                    </p>
 | 
			
		||||
                    <p *ngIf="completionPageContents">
 | 
			
		||||
                        <core-format-text [component]="component" componentId="componentId" [text]="completionPageContents"
 | 
			
		||||
                            contextLevel="module" [contextInstanceId]="cmId" [courseId]="courseId">
 | 
			
		||||
                        </core-format-text>
 | 
			
		||||
                    </p>
 | 
			
		||||
                    <core-format-text *ngIf="completionPageContents" [component]="component" componentId="componentId"
 | 
			
		||||
                        [text]="completionPageContents" contextLevel="module" [contextInstanceId]="cmId" [courseId]="courseId">
 | 
			
		||||
                    </core-format-text>
 | 
			
		||||
                </ion-label>
 | 
			
		||||
            </ion-item>
 | 
			
		||||
        </ion-card>
 | 
			
		||||
 | 
			
		||||
        <ion-card *ngIf="completed && (access!.canviewanalysis || hasNextPage)">
 | 
			
		||||
            <ion-grid>
 | 
			
		||||
                <ion-row class="ion-align-items-center">
 | 
			
		||||
                    <ion-col *ngIf="access!.canviewanalysis">
 | 
			
		||||
                        <ion-button expand="block" fill="outline" (click)="showAnalysis()" class="ion-text-wrap">
 | 
			
		||||
                            <ion-icon name="fas-chart-bar" slot="start" aria-hidden="true"></ion-icon>
 | 
			
		||||
                            {{ 'addon.mod_feedback.completed_feedbacks' | translate }}
 | 
			
		||||
                        </ion-button>
 | 
			
		||||
                    </ion-col>
 | 
			
		||||
                    <ion-col *ngIf="hasNextPage">
 | 
			
		||||
                        <ion-button expand="block" (click)="continue()" class="ion-text-wrap">
 | 
			
		||||
                            {{ 'core.continue' | translate }}
 | 
			
		||||
                            <ion-icon name="fas-chevron-right" slot="end" aria-hidden="true"></ion-icon>
 | 
			
		||||
                        </ion-button>
 | 
			
		||||
                    </ion-col>
 | 
			
		||||
                </ion-row>
 | 
			
		||||
            </ion-grid>
 | 
			
		||||
        </ion-card>
 | 
			
		||||
        <div collapsible-footer *ngIf="feedbackLoaded && completed" slot="fixed">
 | 
			
		||||
            <div class="list-item-limited-width">
 | 
			
		||||
                <ion-button expand="block" fill="outline" (click)="showAnalysis()" class="ion-text-wrap ion-margin"
 | 
			
		||||
                    *ngIf="access!.canviewanalysis">
 | 
			
		||||
                    <ion-icon name="fas-chart-bar" slot="start" aria-hidden="true"></ion-icon>
 | 
			
		||||
                    {{ 'addon.mod_feedback.completed_feedbacks' | translate }}
 | 
			
		||||
                </ion-button>
 | 
			
		||||
                <ion-button expand="block" (click)="continue()" class="ion-text-wrap ion-margin">
 | 
			
		||||
                    <ng-container *ngIf="!siteAfterSubmit">{{ 'core.continue' | translate }}</ng-container>
 | 
			
		||||
                    <ng-container *ngIf="siteAfterSubmit">{{ 'core.course.gotonextactivity' | translate }}</ng-container>
 | 
			
		||||
                </ion-button>
 | 
			
		||||
            </div>
 | 
			
		||||
        </div>
 | 
			
		||||
    </core-loading>
 | 
			
		||||
</ion-content>
 | 
			
		||||
 | 
			
		||||
@ -16,7 +16,7 @@ import { Component, OnDestroy, OnInit, ViewChild } from '@angular/core';
 | 
			
		||||
import { CoreSite } from '@classes/site';
 | 
			
		||||
import { CoreContentLinksHelper } from '@features/contentlinks/services/contentlinks-helper';
 | 
			
		||||
import { CoreCourse, CoreCourseCommonModWSOptions } from '@features/course/services/course';
 | 
			
		||||
import { CoreCourseHelper, CoreCourseModuleData } from '@features/course/services/course-helper';
 | 
			
		||||
import { CoreCourseModuleData } from '@features/course/services/course-helper';
 | 
			
		||||
import { CanLeave } from '@guards/can-leave';
 | 
			
		||||
import { IonContent } from '@ionic/angular';
 | 
			
		||||
import { CoreApp } from '@services/app';
 | 
			
		||||
@ -53,7 +53,6 @@ export class AddonModFeedbackFormPage implements OnInit, OnDestroy, CanLeave {
 | 
			
		||||
 | 
			
		||||
    protected module?: CoreCourseModuleData;
 | 
			
		||||
    protected currentPage?: number;
 | 
			
		||||
    protected siteAfterSubmit?: string;
 | 
			
		||||
    protected onlineObserver: Subscription;
 | 
			
		||||
    protected originalData?: Record<string, AddonModFeedbackResponseValue>;
 | 
			
		||||
    protected currentSite: CoreSite;
 | 
			
		||||
@ -75,6 +74,7 @@ export class AddonModFeedbackFormPage implements OnInit, OnDestroy, CanLeave {
 | 
			
		||||
    hasNextPage = false;
 | 
			
		||||
    completed = false;
 | 
			
		||||
    completedOffline = false;
 | 
			
		||||
    siteAfterSubmit?: string;
 | 
			
		||||
 | 
			
		||||
    constructor() {
 | 
			
		||||
        this.currentSite = CoreSites.getRequiredCurrentSite();
 | 
			
		||||
@ -409,7 +409,7 @@ export class AddonModFeedbackFormPage implements OnInit, OnDestroy, CanLeave {
 | 
			
		||||
     */
 | 
			
		||||
    async continue(): Promise<void> {
 | 
			
		||||
        if (!this.siteAfterSubmit) {
 | 
			
		||||
            return CoreCourseHelper.getAndOpenCourse(this.courseId, {}, this.currentSite.getId());
 | 
			
		||||
            return CoreNavigator.back();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        const modal = await CoreDomUtils.showModalLoading();
 | 
			
		||||
 | 
			
		||||
@ -21,7 +21,7 @@
 | 
			
		||||
    <core-loading [hideUntil]="loaded">
 | 
			
		||||
        <!-- Info messages. Only show the first one. -->
 | 
			
		||||
        <ion-card class="core-info-card" *ngIf="lesson && messages?.length">
 | 
			
		||||
            <ion-item>
 | 
			
		||||
            <ion-item class="ion-text-wrap">
 | 
			
		||||
                <ion-icon name="fas-info-circle" slot="start" aria-hidden="true"></ion-icon>
 | 
			
		||||
                <ion-label>{{ messages[0].message }}</ion-label>
 | 
			
		||||
            </ion-item>
 | 
			
		||||
@ -86,13 +86,12 @@
 | 
			
		||||
                        <!-- Essay. -->
 | 
			
		||||
                        <ng-container *ngSwitchCase="'essay'">
 | 
			
		||||
                            <ion-item *ngIf="question.textarea">
 | 
			
		||||
                                <ion-label>
 | 
			
		||||
                                    <core-rich-text-editor placeholder="{{ 'addon.mod_lesson.youranswer' | translate }}"
 | 
			
		||||
                                        [control]="question.control" [component]="component" [componentId]="lesson?.coursemodule"
 | 
			
		||||
                                        [autoSave]="true" contextLevel="module" [contextInstanceId]="lesson?.coursemodule"
 | 
			
		||||
                                        elementId="answer_editor">
 | 
			
		||||
                                    </core-rich-text-editor>
 | 
			
		||||
                                </ion-label>
 | 
			
		||||
                                <ion-label class="sr-only">{{ 'core.content' | translate }}</ion-label>
 | 
			
		||||
                                <core-rich-text-editor placeholder="{{ 'addon.mod_lesson.youranswer' | translate }}"
 | 
			
		||||
                                    [control]="question.control" [component]="component" [componentId]="lesson?.coursemodule"
 | 
			
		||||
                                    [autoSave]="true" contextLevel="module" [contextInstanceId]="lesson?.coursemodule"
 | 
			
		||||
                                    elementId="answer_editor">
 | 
			
		||||
                                </core-rich-text-editor>
 | 
			
		||||
                            </ion-item>
 | 
			
		||||
                            <ion-item class="ion-text-wrap" *ngIf="!question.textarea && question.useranswer">
 | 
			
		||||
                                <ion-label>
 | 
			
		||||
@ -185,12 +184,12 @@
 | 
			
		||||
                        </core-progress-bar>
 | 
			
		||||
                    </ion-label>
 | 
			
		||||
                </ion-item>
 | 
			
		||||
                <div class="core-info-card" *ngIf="lesson?.progressbar && canManage">
 | 
			
		||||
                    <ion-item>
 | 
			
		||||
                <ion-card class="core-info-card" *ngIf="lesson?.progressbar && canManage">
 | 
			
		||||
                    <ion-item class="ion-text-wrap">
 | 
			
		||||
                        <ion-icon name="fas-info-circle" slot="start" aria-hidden="true"></ion-icon>
 | 
			
		||||
                        <ion-label>{{ 'addon.mod_lesson.progressbarteacherwarning2' | translate }}</ion-label>
 | 
			
		||||
                    </ion-item>
 | 
			
		||||
                </div>
 | 
			
		||||
                </ion-card>
 | 
			
		||||
            </ion-list>
 | 
			
		||||
 | 
			
		||||
            <!-- End of lesson reached. -->
 | 
			
		||||
@ -254,8 +253,8 @@
 | 
			
		||||
                    <ion-label>{{ eolData.modattemptsnoteacher.message }}</ion-label>
 | 
			
		||||
                </ion-item>
 | 
			
		||||
                <!-- If activity link was successfully formatted, render the button. -->
 | 
			
		||||
                <ion-button *ngIf="activityLink && activityLink.formatted" expand="block" color="light" [href]="activityLink.href" core-link
 | 
			
		||||
                    [capture]="true" class="ion-text-wrap ion-margin button-no-uppercase">
 | 
			
		||||
                <ion-button *ngIf="activityLink && activityLink.formatted" expand="block" fill="outline" [href]="activityLink.href"
 | 
			
		||||
                    core-link [capture]="true" class="ion-text-wrap ion-margin button-no-uppercase">
 | 
			
		||||
                    <core-format-text [text]="activityLink.label" contextLevel="module" [contextInstanceId]="lesson?.coursemodule"
 | 
			
		||||
                        [courseId]="courseId">
 | 
			
		||||
                    </core-format-text>
 | 
			
		||||
@ -290,10 +289,10 @@
 | 
			
		||||
                    </ion-label>
 | 
			
		||||
                </ion-item>
 | 
			
		||||
 | 
			
		||||
                <ion-button expand="block" class="ion-text-wrap ion-margin" color="light" *ngIf="review" (click)="changePage(LESSON_EOL)">
 | 
			
		||||
                <ion-button expand="block" class="ion-text-wrap ion-margin" *ngIf="review" (click)="changePage(LESSON_EOL)">
 | 
			
		||||
                    {{ 'addon.mod_lesson.finish' | translate }}
 | 
			
		||||
                </ion-button>
 | 
			
		||||
                <ion-button expand="block" class="ion-text-wrap ion-margin" color="light" *ngFor="let button of processDataButtons"
 | 
			
		||||
                <ion-button expand="block" class="ion-text-wrap ion-margin" fill="outline" *ngFor="let button of processDataButtons"
 | 
			
		||||
                    (click)="changePage(button.pageId, true)">
 | 
			
		||||
                    {{ button.label | translate }}
 | 
			
		||||
                </ion-button>
 | 
			
		||||
 | 
			
		||||
@ -557,7 +557,7 @@ export class AddonModLessonHelperProvider {
 | 
			
		||||
 | 
			
		||||
            // Add some HTML to the answer if needed.
 | 
			
		||||
            if (textarea) {
 | 
			
		||||
                data[textarea.name] = CoreTextUtils.formatHtmlLines(<string> data[textarea.name]);
 | 
			
		||||
                data[textarea.name] = CoreTextUtils.formatHtmlLines(<string> data[textarea.name] || '');
 | 
			
		||||
            }
 | 
			
		||||
        } else if (question.template == 'multichoice' && (<AddonModLessonMultichoiceQuestion> question).multi) {
 | 
			
		||||
            // Only send the options with value set to true.
 | 
			
		||||
 | 
			
		||||
@ -13,19 +13,6 @@
 | 
			
		||||
<ion-content class="addon-mod_quiz-navigation-modal">
 | 
			
		||||
    <nav>
 | 
			
		||||
        <ion-list>
 | 
			
		||||
            <!-- In player, show button to finish attempt. -->
 | 
			
		||||
            <ion-item button class="ion-text-wrap" *ngIf="!isReview" (click)="loadPage(-1)" detail="true">
 | 
			
		||||
                <ion-label>{{ 'addon.mod_quiz.finishattemptdots' | translate }}</ion-label>
 | 
			
		||||
            </ion-item>
 | 
			
		||||
 | 
			
		||||
            <!-- In review we can toggle between all questions in same page or one page at a time. -->
 | 
			
		||||
            <ion-item button class="ion-text-wrap" *ngIf="isReview && numPages > 1" (click)="switchMode()" detail="true">
 | 
			
		||||
                <ion-label>
 | 
			
		||||
                    <span *ngIf="!showAll">{{ 'addon.mod_quiz.showall' | translate }}</span>
 | 
			
		||||
                    <span *ngIf="showAll">{{ 'addon.mod_quiz.showeachpage' | translate }}</span>
 | 
			
		||||
                </ion-label>
 | 
			
		||||
            </ion-item>
 | 
			
		||||
 | 
			
		||||
            <ion-item button class="ion-text-wrap {{question.stateClass}}" *ngFor="let question of navigation"
 | 
			
		||||
                [attr.aria-current]="!summaryShown && currentPage == question.page ? 'page' : 'false'"
 | 
			
		||||
                (click)="loadPage(question.page, question.slot)" detail="false">
 | 
			
		||||
@ -50,19 +37,12 @@
 | 
			
		||||
                    slot="end">
 | 
			
		||||
                </ion-icon>
 | 
			
		||||
            </ion-item>
 | 
			
		||||
 | 
			
		||||
            <!-- In player, show button to finish attempt. -->
 | 
			
		||||
            <ion-item button class="ion-text-wrap" *ngIf="!isReview" (click)="loadPage(-1)" detail="true">
 | 
			
		||||
                <ion-label>{{ 'addon.mod_quiz.finishattemptdots' | translate }}</ion-label>
 | 
			
		||||
            </ion-item>
 | 
			
		||||
 | 
			
		||||
            <!-- In review we can toggle between all questions in same page or one page at a time. -->
 | 
			
		||||
            <ion-item button class="ion-text-wrap" *ngIf="isReview && numPages > 1" (click)="switchMode()" detail="true">
 | 
			
		||||
                <ion-label>
 | 
			
		||||
                    <span *ngIf="!showAll">{{ 'addon.mod_quiz.showall' | translate }}</span>
 | 
			
		||||
                    <span *ngIf="showAll">{{ 'addon.mod_quiz.showeachpage' | translate }}</span>
 | 
			
		||||
                </ion-label>
 | 
			
		||||
            </ion-item>
 | 
			
		||||
        </ion-list>
 | 
			
		||||
    </nav>
 | 
			
		||||
</ion-content>
 | 
			
		||||
<ion-footer *ngIf="!isReview">
 | 
			
		||||
    <!-- In player, show button to finish attempt. -->
 | 
			
		||||
    <ion-button class="ion-text-wrap ion-margin" expand="block" (click)="loadPage(-1)">
 | 
			
		||||
        {{ 'addon.mod_quiz.finishattemptdots' | translate }}
 | 
			
		||||
    </ion-button>
 | 
			
		||||
</ion-footer>
 | 
			
		||||
 | 
			
		||||
@ -26,15 +26,10 @@ import { ModalController } from '@singletons';
 | 
			
		||||
})
 | 
			
		||||
export class AddonModQuizNavigationModalComponent {
 | 
			
		||||
 | 
			
		||||
    static readonly CHANGE_PAGE = 1;
 | 
			
		||||
    static readonly SWITCH_MODE = 2;
 | 
			
		||||
 | 
			
		||||
    @Input() navigation?: AddonModQuizNavigationQuestion[]; // Whether the user is reviewing the attempt.
 | 
			
		||||
    @Input() summaryShown?: boolean; // Whether summary is currently being shown.
 | 
			
		||||
    @Input() currentPage?: number; // Current page.
 | 
			
		||||
    @Input() isReview?: boolean; // Whether the user is reviewing the attempt.
 | 
			
		||||
    @Input() numPages = 0; // Num of pages for review mode.
 | 
			
		||||
    @Input() showAll?: boolean; // Whether to show all questions in same page or not for review mode.
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Close modal.
 | 
			
		||||
@ -51,21 +46,11 @@ export class AddonModQuizNavigationModalComponent {
 | 
			
		||||
     */
 | 
			
		||||
    loadPage(page: number, slot?: number): void {
 | 
			
		||||
        ModalController.dismiss(<AddonModQuizNavigationModalReturn>{
 | 
			
		||||
            action: AddonModQuizNavigationModalComponent.CHANGE_PAGE,
 | 
			
		||||
            page,
 | 
			
		||||
            slot,
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Switch mode in review.
 | 
			
		||||
     */
 | 
			
		||||
    switchMode(): void {
 | 
			
		||||
        ModalController.dismiss(<AddonModQuizNavigationModalReturn>{
 | 
			
		||||
            action: AddonModQuizNavigationModalComponent.SWITCH_MODE,
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
@ -76,7 +61,6 @@ export type AddonModQuizNavigationQuestion = CoreQuestionQuestionParsed & {
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export type AddonModQuizNavigationModalReturn = {
 | 
			
		||||
    action: number;
 | 
			
		||||
    page?: number;
 | 
			
		||||
    slot?: number;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
@ -53,15 +53,21 @@
 | 
			
		||||
                    </p>
 | 
			
		||||
                </ion-label>
 | 
			
		||||
            </ion-item>
 | 
			
		||||
            <ion-button *ngIf="showReviewColumn && attempt.finished" class="ion-margin" expand="block" (click)="reviewAttempt()">
 | 
			
		||||
                <ion-icon name="fas-search" slot="start" aria-hidden="true"></ion-icon>
 | 
			
		||||
                {{ 'addon.mod_quiz.review' | translate }}
 | 
			
		||||
            </ion-button>
 | 
			
		||||
 | 
			
		||||
            <ion-item class="ion-text-wrap core-danger-item" *ngIf="!showReviewColumn">
 | 
			
		||||
                <ion-label>
 | 
			
		||||
                    <p>{{ 'addon.mod_quiz.noreviewattempt' | translate }}</p>
 | 
			
		||||
                </ion-label>
 | 
			
		||||
            </ion-item>
 | 
			
		||||
        </ion-list>
 | 
			
		||||
 | 
			
		||||
        <div collapsible-footer *ngIf="loaded && attempt && showReviewColumn && attempt.finished" slot="fixed">
 | 
			
		||||
            <div class="list-item-limited-width">
 | 
			
		||||
                <ion-button class="ion-margin ion-text-wrap" expand="block" (click)="reviewAttempt()">
 | 
			
		||||
                    <ion-icon name="fas-search" slot="start" aria-hidden="true"></ion-icon>
 | 
			
		||||
                    {{ 'addon.mod_quiz.review' | translate }}
 | 
			
		||||
                </ion-button>
 | 
			
		||||
            </div>
 | 
			
		||||
        </div>
 | 
			
		||||
    </core-loading>
 | 
			
		||||
</ion-content>
 | 
			
		||||
 | 
			
		||||
@ -28,32 +28,10 @@
 | 
			
		||||
            <core-timer [endTime]="endTime" (finished)="timeUp()" [timerText]="'addon.mod_quiz.timeleft' | translate" [align]="'center'">
 | 
			
		||||
            </core-timer>
 | 
			
		||||
        </ion-title>
 | 
			
		||||
        <ion-buttons slot="end">
 | 
			
		||||
            <ion-button fill="clear" *ngIf="previousPage >= 0" (click)="changePage(previousPage)"
 | 
			
		||||
                [attr.aria-label]="'core.previous' | translate">
 | 
			
		||||
                <ion-icon name="fas-chevron-left" slot="icon-only" aria-hidden="true"></ion-icon>
 | 
			
		||||
            </ion-button>
 | 
			
		||||
            <ion-button *ngIf="nextPage >= -1" (click)="changePage(nextPage)" [attr.aria-label]="'core.next' | translate">
 | 
			
		||||
                <ion-icon name="fas-chevron-right" slot="icon-only" aria-hidden="true"></ion-icon>
 | 
			
		||||
            </ion-button>
 | 
			
		||||
        </ion-buttons>
 | 
			
		||||
    </ion-toolbar>
 | 
			
		||||
</ion-header>
 | 
			
		||||
<ion-content>
 | 
			
		||||
    <core-loading [hideUntil]="loaded">
 | 
			
		||||
        <!-- Navigation arrows if there's no timer. -->
 | 
			
		||||
        <ion-toolbar *ngIf="!endTime && questions.length && !quizAborted && !showSummary" color="light">
 | 
			
		||||
            <ion-buttons slot="end">
 | 
			
		||||
                <ion-button fill="clear" *ngIf="previousPage >= 0" (click)="changePage(previousPage)"
 | 
			
		||||
                    [attr.aria-label]="'core.previous' | translate">
 | 
			
		||||
                    <ion-icon name="fas-chevron-left" slot="icon-only" aria-hidden="true"></ion-icon>
 | 
			
		||||
                </ion-button>
 | 
			
		||||
                <ion-button *ngIf="nextPage >= -1" (click)="changePage(nextPage)" [attr.aria-label]="'core.next' | translate">
 | 
			
		||||
                    <ion-icon name="fas-chevron-right" slot="icon-only" aria-hidden="true"></ion-icon>
 | 
			
		||||
                </ion-button>
 | 
			
		||||
            </ion-buttons>
 | 
			
		||||
        </ion-toolbar>
 | 
			
		||||
 | 
			
		||||
        <!-- Button to start attempting. -->
 | 
			
		||||
        <ion-button *ngIf="!attempt" expand="block" class="ion-margin" (click)="start()">
 | 
			
		||||
            {{ 'addon.mod_quiz.startattempt' | translate }}
 | 
			
		||||
@ -89,22 +67,23 @@
 | 
			
		||||
        </form>
 | 
			
		||||
 | 
			
		||||
        <!-- Go to next or previous page. -->
 | 
			
		||||
        <ion-grid class="ion-text-wrap" *ngIf="questions.length && !quizAborted && !showSummary">
 | 
			
		||||
            <ion-row>
 | 
			
		||||
                <ion-col *ngIf="previousPage >= 0">
 | 
			
		||||
                    <ion-button expand="block" color="light" (click)="changePage(previousPage)">
 | 
			
		||||
                        <ion-icon name="fas-chevron-left" slot="start" aria-hidden="true"></ion-icon>
 | 
			
		||||
                        {{ 'core.previous' | translate }}
 | 
			
		||||
                    </ion-button>
 | 
			
		||||
                </ion-col>
 | 
			
		||||
                <ion-col *ngIf="nextPage >= -1">
 | 
			
		||||
                    <ion-button expand="block" (click)="changePage(nextPage)">
 | 
			
		||||
                        {{ 'core.next' | translate }}
 | 
			
		||||
                        <ion-icon name="fas-chevron-right" slot="end" aria-hidden="true"></ion-icon>
 | 
			
		||||
                    </ion-button>
 | 
			
		||||
                </ion-col>
 | 
			
		||||
            </ion-row>
 | 
			
		||||
        </ion-grid>
 | 
			
		||||
        <ion-row *ngIf="questions.length && !quizAborted && !showSummary">
 | 
			
		||||
            <ion-col *ngIf="previousPage >= 0">
 | 
			
		||||
                <ion-button expand="block" fill="outline" (click)="changePage(previousPage)" class="ion-text-wrap">
 | 
			
		||||
                    <ion-icon name="fas-chevron-left" slot="start" aria-hidden="true"></ion-icon>
 | 
			
		||||
                    {{ 'core.previous' | translate }}
 | 
			
		||||
                </ion-button>
 | 
			
		||||
            </ion-col>
 | 
			
		||||
            <ion-col *ngIf="nextPage >= -1">
 | 
			
		||||
                <ion-button expand="block" (click)="changePage(nextPage)" class="ion-text-wrap" *ngIf="nextPage > 0">
 | 
			
		||||
                    {{ 'core.next' | translate }}
 | 
			
		||||
                    <ion-icon name="fas-chevron-right" slot="end" aria-hidden="true"></ion-icon>
 | 
			
		||||
                </ion-button>
 | 
			
		||||
                <ion-button expand="block" (click)="changePage(nextPage)" class="ion-text-wrap" *ngIf="nextPage == -1">
 | 
			
		||||
                    {{ 'core.submit' | translate }}
 | 
			
		||||
                </ion-button>
 | 
			
		||||
            </ion-col>
 | 
			
		||||
        </ion-row>
 | 
			
		||||
 | 
			
		||||
        <!-- Summary -->
 | 
			
		||||
        <ion-card *ngIf="!quizAborted && showSummary && summaryQuestions.length" class="addon-mod_quiz-table">
 | 
			
		||||
@ -141,11 +120,6 @@
 | 
			
		||||
                </ion-item>
 | 
			
		||||
            </ng-container>
 | 
			
		||||
 | 
			
		||||
            <!-- Button to return to last page seen. -->
 | 
			
		||||
            <ion-button *ngIf="canReturn" expand="block" class="ion-margin" (click)="changePage(attempt!.currentpage!)">
 | 
			
		||||
                {{ 'addon.mod_quiz.returnattempt' | translate }}
 | 
			
		||||
            </ion-button>
 | 
			
		||||
 | 
			
		||||
            <!-- Due date warning. -->
 | 
			
		||||
            <ion-item class="ion-text-wrap" *ngIf="dueDateWarning">
 | 
			
		||||
                <ion-label>{{ dueDateWarning }}</ion-label>
 | 
			
		||||
@ -162,17 +136,6 @@
 | 
			
		||||
                    <p *ngFor="let message of preventSubmitMessages">{{message}}</p>
 | 
			
		||||
                </ion-label>
 | 
			
		||||
            </ion-item>
 | 
			
		||||
 | 
			
		||||
            <ion-button *ngIf="preventSubmitMessages.length" expand="block" [href]="moduleUrl" core-link [showBrowserWarning]="false">
 | 
			
		||||
                {{ 'core.openinbrowser' | translate }}
 | 
			
		||||
                <ion-icon name="fas-external-link-alt" slot="end" aria-hidden="true"></ion-icon>
 | 
			
		||||
            </ion-button>
 | 
			
		||||
 | 
			
		||||
            <!-- Button to submit the quiz. -->
 | 
			
		||||
            <ion-button *ngIf="!attempt!.finishedOffline && !preventSubmitMessages.length" expand="block" class="ion-margin"
 | 
			
		||||
                (click)="finishAttempt(true)">
 | 
			
		||||
                {{ 'addon.mod_quiz.submitallandfinish' | translate }}
 | 
			
		||||
            </ion-button>
 | 
			
		||||
        </ion-card>
 | 
			
		||||
 | 
			
		||||
        <!-- Quiz aborted -->
 | 
			
		||||
@ -180,10 +143,25 @@
 | 
			
		||||
            <ion-item class="ion-text-wrap">
 | 
			
		||||
                <ion-label>{{ 'addon.mod_quiz.errorparsequestions' | translate }}</ion-label>
 | 
			
		||||
            </ion-item>
 | 
			
		||||
            <ion-button expand="block" class="ion-margin" [href]="moduleUrl" core-link [showBrowserWarning]="false">
 | 
			
		||||
            <ion-button *ngIf="canReturn" expand="block" class="ion-margin ion-text-wrap" fill="outline"
 | 
			
		||||
                (click)="changePage(attempt!.currentpage!)">
 | 
			
		||||
                {{ 'addon.mod_quiz.returnattempt' | translate }}
 | 
			
		||||
            </ion-button>
 | 
			
		||||
        </ion-card>
 | 
			
		||||
 | 
			
		||||
        <div collapsible-footer *ngIf="!quizAborted && showSummary && summaryQuestions.length && loaded" slot="fixed"
 | 
			
		||||
            class="list-item-limited-width">
 | 
			
		||||
            <ion-button *ngIf="preventSubmitMessages.length" expand="block" class="ion-margin ion-text-wrap" [href]="moduleUrl" core-link
 | 
			
		||||
                [showBrowserWarning]="false">
 | 
			
		||||
                {{ 'core.openinbrowser' | translate }}
 | 
			
		||||
                <ion-icon name="fas-external-link-alt" slot="end" aria-hidden="true"></ion-icon>
 | 
			
		||||
            </ion-button>
 | 
			
		||||
        </ion-card>
 | 
			
		||||
 | 
			
		||||
            <!-- Button to submit the quiz. -->
 | 
			
		||||
            <ion-button *ngIf="!attempt!.finishedOffline && !preventSubmitMessages.length" expand="block" class="ion-margin ion-text-wrap"
 | 
			
		||||
                (click)="finishAttempt(true)">
 | 
			
		||||
                {{ 'addon.mod_quiz.submitallandfinish' | translate }}
 | 
			
		||||
            </ion-button>
 | 
			
		||||
        </div>
 | 
			
		||||
    </core-loading>
 | 
			
		||||
</ion-content>
 | 
			
		||||
 | 
			
		||||
@ -602,9 +602,11 @@ export class AddonModQuizPlayerPage implements OnInit, OnDestroy, CanLeave {
 | 
			
		||||
            },
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        if (modalData && modalData.action == AddonModQuizNavigationModalComponent.CHANGE_PAGE) {
 | 
			
		||||
            this.changePage(modalData.page!, true, modalData.slot);
 | 
			
		||||
        if (!modalData) {
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        this.changePage(modalData.page!, true, modalData.slot);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
 | 
			
		||||
@ -87,8 +87,6 @@
 | 
			
		||||
 | 
			
		||||
        <!-- Questions -->
 | 
			
		||||
        <div *ngIf="attempt && questions.length">
 | 
			
		||||
            <!-- Arrows to go to next/previous. -->
 | 
			
		||||
            <ng-container *ngTemplateOutlet="navArrows"></ng-container>
 | 
			
		||||
 | 
			
		||||
            <!-- Questions. -->
 | 
			
		||||
            <div *ngFor="let question of questions">
 | 
			
		||||
@ -113,28 +111,30 @@
 | 
			
		||||
                    </core-question>
 | 
			
		||||
                </ion-card>
 | 
			
		||||
            </div>
 | 
			
		||||
        </div>
 | 
			
		||||
 | 
			
		||||
            <!-- Arrows to go to next/previous. -->
 | 
			
		||||
            <ng-container *ngTemplateOutlet="navArrows"></ng-container>
 | 
			
		||||
        <div collapsible-footer *ngIf="loaded && numPages > 1" slot="fixed">
 | 
			
		||||
            <ion-row class="ion-justify-content-between ion-align-items-center ion-no-padding ion-wrap">
 | 
			
		||||
                <ion-col class="ion-text-start ion-no-padding core-navigation-arrow" size="auto" *ngIf="!showAll">
 | 
			
		||||
                    <ion-button [disabled]="previousPage < 0" fill="clear" color="dark" [attr.aria-label]="'core.previous' | translate"
 | 
			
		||||
                        (click)="changePage(previousPage)">
 | 
			
		||||
                        <ion-icon name="fas-chevron-left" slot="icon-only" aria-hidden="true"></ion-icon>
 | 
			
		||||
                    </ion-button>
 | 
			
		||||
                </ion-col>
 | 
			
		||||
                <ion-col class="ion-text-center">
 | 
			
		||||
                    <!-- In review we can toggle between all questions in same page or one page at a time. -->
 | 
			
		||||
                    <ion-button class="ion-text-wrap" *ngIf="numPages > 1" (click)="switchMode()" fill="outline">
 | 
			
		||||
                        <span *ngIf="!showAll">{{ 'addon.mod_quiz.showall' | translate }}</span>
 | 
			
		||||
                        <span *ngIf="showAll">{{ 'addon.mod_quiz.showeachpage' | translate }}</span>
 | 
			
		||||
                    </ion-button>
 | 
			
		||||
                </ion-col>
 | 
			
		||||
                <ion-col class="ion-text-end ion-no-padding core-navigation-arrow" size="auto" *ngIf="!showAll">
 | 
			
		||||
                    <ion-button [disabled]="nextPage >= numPages" fill="clear" color="dark" [attr.aria-label]="'core.next' | translate"
 | 
			
		||||
                        (click)="changePage(nextPage)">
 | 
			
		||||
                        <ion-icon name="fas-chevron-right" slot="icon-only" aria-hidden="true"></ion-icon>
 | 
			
		||||
                    </ion-button>
 | 
			
		||||
                </ion-col>
 | 
			
		||||
            </ion-row>
 | 
			
		||||
        </div>
 | 
			
		||||
    </core-loading>
 | 
			
		||||
</ion-content>
 | 
			
		||||
 | 
			
		||||
<!-- Arrows to go to next/previous. -->
 | 
			
		||||
<ng-template #navArrows>
 | 
			
		||||
    <ion-grid>
 | 
			
		||||
        <ion-row class="ion-align-items-center">
 | 
			
		||||
            <ion-col class="ion-text-start">
 | 
			
		||||
                <ion-button fill="outline" *ngIf="previousPage >= 0" (click)="changePage(previousPage)"
 | 
			
		||||
                    [title]="'core.previous' | translate">
 | 
			
		||||
                    <ion-icon name="fas-chevron-left" slot="icon-only" aria-hidden="true"></ion-icon>
 | 
			
		||||
                </ion-button>
 | 
			
		||||
            </ion-col>
 | 
			
		||||
            <ion-col class="ion-text-end">
 | 
			
		||||
                <ion-button *ngIf="nextPage >= -1" (click)="changePage(nextPage)" [attr.aria-label]="'core.next' | translate">
 | 
			
		||||
                    <ion-icon name="fas-chevron-right" slot="icon-only" aria-hidden="true"></ion-icon>
 | 
			
		||||
                </ion-button>
 | 
			
		||||
            </ion-col>
 | 
			
		||||
        </ion-row>
 | 
			
		||||
    </ion-grid>
 | 
			
		||||
</ng-template>
 | 
			
		||||
 | 
			
		||||
@ -53,7 +53,7 @@ export class AddonModQuizReviewPage implements OnInit {
 | 
			
		||||
    attempt?: AddonModQuizAttemptWSData; // The attempt being reviewed.
 | 
			
		||||
    component = AddonModQuizProvider.COMPONENT; // Component to link the files to.
 | 
			
		||||
    showAll = false; // Whether to view all questions in the same page.
 | 
			
		||||
    numPages?: number; // Number of pages.
 | 
			
		||||
    numPages = 1; // Number of pages.
 | 
			
		||||
    showCompleted = false; // Whether to show completed time.
 | 
			
		||||
    additionalData?: AddonModQuizWSAdditionalData[]; // Additional data to display for the attempt.
 | 
			
		||||
    loaded = false; // Whether data has been loaded.
 | 
			
		||||
@ -112,10 +112,9 @@ export class AddonModQuizReviewPage implements OnInit {
 | 
			
		||||
     * Change the current page. If slot is supplied, try to scroll to that question.
 | 
			
		||||
     *
 | 
			
		||||
     * @param page Page to load. -1 means all questions in same page.
 | 
			
		||||
     * @param fromModal Whether the page was selected using the navigation modal.
 | 
			
		||||
     * @param slot Slot of the question to scroll to.
 | 
			
		||||
     */
 | 
			
		||||
    async changePage(page: number, fromModal?: boolean, slot?: number): Promise<void> {
 | 
			
		||||
    async changePage(page: number, slot?: number): Promise<void> {
 | 
			
		||||
        if (slot !== undefined && (this.attempt!.currentpage == -1 || page == this.currentPage)) {
 | 
			
		||||
            // Scrol to a certain question in the current page.
 | 
			
		||||
            this.scrollToQuestion(slot);
 | 
			
		||||
@ -183,7 +182,7 @@ export class AddonModQuizReviewPage implements OnInit {
 | 
			
		||||
        this.setSummaryCalculatedData(data);
 | 
			
		||||
 | 
			
		||||
        this.questions = data.questions;
 | 
			
		||||
        this.nextPage = page == -1 ? -2 : page + 1;
 | 
			
		||||
        this.nextPage = page + 1;
 | 
			
		||||
        this.previousPage = page - 1;
 | 
			
		||||
 | 
			
		||||
        this.questions.forEach((question) => {
 | 
			
		||||
@ -341,8 +340,6 @@ export class AddonModQuizReviewPage implements OnInit {
 | 
			
		||||
                summaryShown: false,
 | 
			
		||||
                currentPage: this.attempt?.currentpage,
 | 
			
		||||
                isReview: true,
 | 
			
		||||
                numPages: this.numPages,
 | 
			
		||||
                showAll: this.showAll,
 | 
			
		||||
            },
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
@ -350,11 +347,7 @@ export class AddonModQuizReviewPage implements OnInit {
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (modalData.action == AddonModQuizNavigationModalComponent.CHANGE_PAGE) {
 | 
			
		||||
            this.changePage(modalData.page!, true, modalData.slot);
 | 
			
		||||
        } else if (modalData.action == AddonModQuizNavigationModalComponent.SWITCH_MODE) {
 | 
			
		||||
            this.switchMode();
 | 
			
		||||
        }
 | 
			
		||||
        this.changePage(modalData.page!, modalData.slot);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -516,7 +516,7 @@ export class AddonQtypeEssayHandlerService implements CoreQuestionHandler {
 | 
			
		||||
 | 
			
		||||
        if (!isPlainText) {
 | 
			
		||||
            // Add some HTML to the text if needed.
 | 
			
		||||
            answers[textarea.name] = CoreTextUtils.formatHtmlLines(<string> answers[textarea.name]);
 | 
			
		||||
            answers[textarea.name] = CoreTextUtils.formatHtmlLines(<string> answers[textarea.name] || '');
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -6,6 +6,7 @@ $core-timer-iterations: 15 !default;
 | 
			
		||||
:host {
 | 
			
		||||
    .core-timer {
 | 
			
		||||
        --background: transparent !important;
 | 
			
		||||
        border-radius: var(--big-radius);
 | 
			
		||||
 | 
			
		||||
        .core-timer-time-left, .core-timesup {
 | 
			
		||||
            font-weight: bold;
 | 
			
		||||
 | 
			
		||||
@ -35,9 +35,9 @@
 | 
			
		||||
    "errordownloadingsection": "Error downloading section.",
 | 
			
		||||
    "errorgetmodule": "Error getting activity data.",
 | 
			
		||||
    "failed": "Failed",
 | 
			
		||||
    "gotonextactivity": "Continue to next activity",
 | 
			
		||||
    "gotonextactivity": "Go to next activity",
 | 
			
		||||
    "gotonextactivitynotfound": "Next activity not found. It's possible that it has been hidden or deleted.",
 | 
			
		||||
    "gotopreviousactivity": "Continue to previous activity",
 | 
			
		||||
    "gotopreviousactivity": "Go to previous activity",
 | 
			
		||||
    "gotopreviousactivitynotfound": "Previous activity not found. It's possible that it has been hidden or deleted.",
 | 
			
		||||
    "hiddenfromstudents": "Hidden from students",
 | 
			
		||||
    "hiddenoncoursepage": "Available but not shown on course page",
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user