Skip to content

Commit 3f40127

Browse files
committed
MOBILE-2272 quiz: Support viewing attachments and inline files
1 parent b6ed831 commit 3f40127

File tree

15 files changed

+227
-39
lines changed

15 files changed

+227
-39
lines changed

scripts/langindex.json

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1861,6 +1861,7 @@
18611861
"core.mainmenu.help": "moodle",
18621862
"core.mainmenu.logout": "moodle",
18631863
"core.mainmenu.website": "local_moodlemobileapp",
1864+
"core.maxfilesize": "moodle",
18641865
"core.maxsizeandattachments": "moodle",
18651866
"core.min": "moodle",
18661867
"core.mins": "moodle",
@@ -1944,8 +1945,8 @@
19441945
"core.question.certainty": "qbehaviour_deferredcbm",
19451946
"core.question.complete": "question",
19461947
"core.question.correct": "question",
1947-
"core.question.errorattachmentsnotsupported": "local_moodlemobileapp",
1948-
"core.question.errorinlinefilesnotsupported": "local_moodlemobileapp",
1948+
"core.question.errorattachmentsnotsupportedinsite": "local_moodlemobileapp",
1949+
"core.question.errorembeddedfilesnotsupportedinsite": "local_moodlemobileapp",
19491950
"core.question.errorquestionnotsupported": "local_moodlemobileapp",
19501951
"core.question.feedback": "question",
19511952
"core.question.howtodraganddrop": "local_moodlemobileapp",

src/addon/mod/lesson/providers/lesson-sync.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -411,7 +411,7 @@ export class AddonModLessonSyncProvider extends CoreCourseActivitySyncBaseProvid
411411
const params = this.urlUtils.extractUrlParams(response.data.reviewlesson.value);
412412
if (params && params.pageid) {
413413
// The retake can be reviewed, mark it as finished. Don't block the user for this.
414-
this.setRetakeFinishedInSync(lessonId, retake.retake, params.pageid, siteId);
414+
this.setRetakeFinishedInSync(lessonId, retake.retake, Number(params.pageid), siteId);
415415
}
416416
}
417417
}

src/addon/qtype/essay/component/addon-qtype-essay.html

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5,32 +5,40 @@
55
</ion-item>
66

77
<!-- Textarea. -->
8-
<ion-item *ngIf="question.textarea && !question.hasDraftFiles">
9-
<!-- "Format" hidden input -->
8+
<ion-item *ngIf="question.textarea && (!question.hasDraftFiles || uploadFilesSupported)">
9+
<!-- "Format" and draftid hidden inputs -->
1010
<input item-content *ngIf="question.formatInput" type="hidden" [name]="question.formatInput.name" [value]="question.formatInput.value" >
11+
<input item-content *ngIf="question.answerDraftIdInput" type="hidden" [name]="question.answerDraftIdInput.name" [value]="question.answerDraftIdInput.value" >
1112
<!-- Plain text textarea. -->
1213
<ion-textarea *ngIf="question.isPlainText" class="core-question-textarea" [ngClass]='{"core-monospaced": question.isMonospaced}' placeholder="{{ 'core.question.answer' | translate }}" [attr.name]="question.textarea.name" aria-multiline="true" [ngModel]="question.textarea.text"></ion-textarea>
1314
<!-- Rich text editor. -->
1415
<core-rich-text-editor item-content *ngIf="!question.isPlainText" placeholder="{{ 'core.question.answer' | translate }}" [control]="formControl" [name]="question.textarea.name" [component]="component" [componentId]="componentId" [autoSave]="false"></core-rich-text-editor>
1516
</ion-item>
1617

1718
<!-- Draft files not supported. -->
18-
<ng-container *ngIf="question.textarea && question.hasDraftFiles">
19+
<ng-container *ngIf="question.textarea && question.hasDraftFiles && !uploadFilesSupported">
1920
<ion-item text-wrap class="core-danger-item">
20-
<p class="core-question-warning">{{ 'core.question.errorinlinefilesnotsupported' | translate }}</p>
21+
<p class="core-question-warning">{{ 'core.question.errorinlinefilesnotsupportedinsite' | translate }}</p>
2122
</ion-item>
2223
<ion-item text-wrap>
2324
<p><core-format-text [component]="component" [componentId]="componentId" [text]="question.textarea.text" [contextLevel]="contextLevel" [contextInstanceId]="contextInstanceId" [courseId]="courseId"></core-format-text></p>
2425
</ion-item>
2526
</ng-container>
2627

27-
<!-- Attachments not supported in the app yet. -->
28-
<ion-item text-wrap *ngIf="question.allowsAttachments" class="core-danger-item">
29-
<p class="core-question-warning">{{ 'core.question.errorattachmentsnotsupported' | translate }}</p>
30-
</ion-item>
28+
<!-- Attachments. -->
29+
<ng-container *ngIf="question.allowsAttachments">
30+
<core-attachments *ngIf="uploadFilesSupported" [files]="attachments" [component]="component" [componentId]="componentId" [maxSize]="question.attachmentsMaxBytes" [maxSubmissions]="question.attachmentsMaxFiles"></core-attachments>
31+
32+
<input item-content *ngIf="uploadFilesSupported" type="hidden" [name]="question.attachmentsDraftIdInput.name" [value]="question.attachmentsDraftIdInput.value" >
33+
34+
<!-- Attachments not supported in this site. -->
35+
<ion-item text-wrap *ngIf="!uploadFilesSupported" class="core-danger-item">
36+
<p class="core-question-warning">{{ 'core.question.errorattachmentsnotsupportedinsite' | translate }}</p>
37+
</ion-item>
38+
</ng-container>
3139

3240
<!-- Answer to the question and attachments (reviewing). -->
33-
<ion-item text-wrap *ngIf="!question.textarea && (question.answer || (!question.attachments.length && !question.allowsAttachments))">
41+
<ion-item text-wrap *ngIf="!question.textarea && (question.answer || question.answer == '')">
3442
<p><core-format-text [ngClass]='{"core-monospaced": question.isMonospaced}' [component]="component" [componentId]="componentId" [text]="question.answer" [contextLevel]="contextLevel" [contextInstanceId]="contextInstanceId" [courseId]="courseId"></core-format-text></p>
3543
</ion-item>
3644

src/addon/qtype/essay/component/essay.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,11 @@
1414

1515
import { Component, OnInit, Injector } from '@angular/core';
1616
import { CoreLoggerProvider } from '@providers/logger';
17+
import { CoreSites } from '@providers/sites';
18+
import { CoreWSExternalFile } from '@providers/ws';
1719
import { CoreQuestionBaseComponent } from '@core/question/classes/base-question-component';
1820
import { FormControl, FormBuilder } from '@angular/forms';
21+
import { CoreFileSession } from '@providers/file-session';
1922

2023
/**
2124
* Component to render an essay question.
@@ -28,6 +31,9 @@ export class AddonQtypeEssayComponent extends CoreQuestionBaseComponent implemen
2831

2932
protected formControl: FormControl;
3033

34+
attachments: CoreWSExternalFile[];
35+
uploadFilesSupported: boolean;
36+
3137
constructor(logger: CoreLoggerProvider, injector: Injector, protected fb: FormBuilder) {
3238
super(logger, 'AddonQtypeEssayComponent', injector);
3339
}
@@ -36,8 +42,14 @@ export class AddonQtypeEssayComponent extends CoreQuestionBaseComponent implemen
3642
* Component being initialized.
3743
*/
3844
ngOnInit(): void {
45+
this.uploadFilesSupported = CoreSites.instance.getCurrentSite().isVersionGreaterEqualThan('3.10');
3946
this.initEssayComponent();
4047

4148
this.formControl = this.fb.control(this.question.textarea && this.question.textarea.text);
49+
50+
if (this.question.allowsAttachments && this.uploadFilesSupported) {
51+
this.attachments = Array.from(this.questionHelper.getResponseFileAreaFiles(this.question, 'attachments'));
52+
CoreFileSession.instance.setFiles(this.component, this.componentId + '_' + this.question.id, this.attachments);
53+
}
4254
}
4355
}

src/addon/qtype/essay/providers/handler.ts

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
// limitations under the License.
1515

1616
import { Injectable, Injector } from '@angular/core';
17+
import { CoreSites } from '@providers/sites';
1718
import { CoreTextUtilsProvider } from '@providers/utils/text';
1819
import { CoreDomUtilsProvider } from '@providers/utils/dom';
1920
import { CoreUtilsProvider } from '@providers/utils/utils';
@@ -68,11 +69,11 @@ export class AddonQtypeEssayHandler implements CoreQuestionHandler {
6869

6970
if (element.querySelector('div[id*=filemanager]')) {
7071
// The question allows attachments. Since the app cannot attach files yet we will prevent submitting the question.
71-
return 'core.question.errorattachmentsnotsupported';
72+
return 'core.question.errorattachmentsnotsupportedinsite';
7273
}
7374

7475
if (this.questionHelper.hasDraftFileUrls(element.innerHTML)) {
75-
return 'core.question.errorinlinefilesnotsupported';
76+
return 'core.question.errorinlinefilesnotsupportedinsite';
7677
}
7778
}
7879

@@ -139,13 +140,21 @@ export class AddonQtypeEssayHandler implements CoreQuestionHandler {
139140
* @param siteId Site ID. If not defined, current site.
140141
* @return Return a promise resolved when done if async, void if sync.
141142
*/
142-
prepareAnswers(question: any, answers: any, offline: boolean, siteId?: string): void | Promise<any> {
143+
async prepareAnswers(question: any, answers: any, offline: boolean, siteId?: string): Promise<void> {
143144
const element = this.domUtils.convertToElement(question.html);
144145

145146
// Search the textarea to get its name.
146147
const textarea = <HTMLTextAreaElement> element.querySelector('textarea[name*=_answer]');
147148

148149
if (textarea && typeof answers[textarea.name] != 'undefined') {
150+
if (this.questionHelper.hasDraftFileUrls(question.html) && question.responsefileareas) {
151+
// Restore draftfile URLs.
152+
const site = await CoreSites.instance.getSite(siteId);
153+
154+
answers[textarea.name] = this.textUtils.restoreDraftfileUrls(site.getURL(), answers[textarea.name],
155+
question.html, this.questionHelper.getResponseFileAreaFiles(question, 'answer'));
156+
}
157+
149158
// Add some HTML to the text if needed.
150159
answers[textarea.name] = this.textUtils.formatHtmlLines(answers[textarea.name]);
151160
}

src/assets/lang/en.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1945,8 +1945,8 @@
19451945
"core.question.certainty": "Certainty",
19461946
"core.question.complete": "Complete",
19471947
"core.question.correct": "Correct",
1948-
"core.question.errorattachmentsnotsupported": "The application doesn't support attaching files to answers yet.",
1949-
"core.question.errorinlinefilesnotsupported": "The application doesn't support editing inline files yet.",
1948+
"core.question.errorattachmentsnotsupportedinsite": "Your site doesn't support attaching files to answers yet.",
1949+
"core.question.errorinlinefilesnotsupportedinsite": "Your site doesn't support editing inline files yet.",
19501950
"core.question.errorquestionnotsupported": "This question type is not supported by the app: {{$a}}.",
19511951
"core.question.feedback": "Feedback",
19521952
"core.question.howtodraganddrop": "Tap to select then tap to drop.",

src/classes/site.ts

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -221,13 +221,16 @@ export class CoreSite {
221221

222222
// Versions of Moodle releases.
223223
protected MOODLE_RELEASES = {
224-
3.1: 2016052300,
225-
3.2: 2016120500,
226-
3.3: 2017051503,
227-
3.4: 2017111300,
228-
3.5: 2018051700,
229-
3.6: 2018120300,
230-
3.7: 2019052000
224+
'3.1': 2016052300,
225+
'3.2': 2016120500,
226+
'3.3': 2017051503,
227+
'3.4': 2017111300,
228+
'3.5': 2018051700,
229+
'3.6': 2018120300,
230+
'3.7': 2019052000,
231+
'3.8': 2019111800,
232+
'3.9': 2020061500,
233+
'3.10': 2020092400, // @todo: Replace with the right value once 3.10 is released.
231234
};
232235
static MINIMUM_MOODLE_VERSION = '3.1';
233236

src/core/editor/components/rich-text-editor/rich-text-editor.scss

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ ion-app.app-root core-rich-text-editor {
5656
img {
5757
@include padding(null, null, null, 2px);
5858
max-width: 95%;
59+
width: auto;
5960
}
6061
&:empty:before {
6162
content: attr(data-placeholder-text);

src/core/grades/providers/helper.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -407,7 +407,7 @@ export class CoreGradesHelperProvider {
407407
if (matches && matches.length) {
408408
const hrefParams = this.urlUtils.extractUrlParams(matches[1]);
409409

410-
return hrefParams && hrefParams.id == moduleId;
410+
return hrefParams && Number(hrefParams.id) == moduleId;
411411
}
412412
}
413413

src/core/login/providers/helper.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1152,7 +1152,7 @@ export class CoreLoginHelperProvider {
11521152
const providerToUse = identityProviders.find((provider) => {
11531153
const params = this.urlUtils.extractUrlParams(provider.url);
11541154

1155-
return params.id == currentSite.getOAuthId();
1155+
return Number(params.id) == currentSite.getOAuthId();
11561156
});
11571157

11581158
if (providerToUse) {

0 commit comments

Comments
 (0)