Merge pull request #2618 from dpalou/MOBILE-3523

MOBILE-3523 essay: Fix essay text not displayed in review
main
Juan Leyva 2020-11-24 10:48:50 +01:00 committed by GitHub
commit ee8c3a32c4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 144 additions and 121 deletions

View File

@ -58,7 +58,7 @@
</ion-note> </ion-note>
</ion-item-divider> </ion-item-divider>
<!-- Body of the question. --> <!-- Body of the question. -->
<core-question text-wrap [question]="question" [component]="component" [componentId]="quiz.coursemodule" [attemptId]="attempt.id" [usageId]="attempt.uniqueid" [offlineEnabled]="offline" contextLevel="module" [contextInstanceId]="quiz.coursemodule" [courseId]="courseId" (onAbort)="abortQuiz()" (buttonClicked)="behaviourButtonClicked($event)"></core-question> <core-question text-wrap [question]="question" [component]="component" [componentId]="quiz.coursemodule" [attemptId]="attempt.id" [usageId]="attempt.uniqueid" [offlineEnabled]="offline" contextLevel="module" [contextInstanceId]="quiz.coursemodule" [courseId]="courseId" [review]="false" (onAbort)="abortQuiz()" (buttonClicked)="behaviourButtonClicked($event)"></core-question>
</ion-card> </ion-card>
</div> </div>
</form> </form>

View File

@ -77,7 +77,7 @@
</ion-note> </ion-note>
</ion-item-divider> </ion-item-divider>
<!-- Body of the question. --> <!-- Body of the question. -->
<core-question text-wrap [question]="question" [component]="component" [componentId]="componentId" [attemptId]="attempt.id" [usageId]="attempt.uniqueid" [offlineEnabled]="false" contextLevel="module" [contextInstanceId]="quiz.coursemodule" [courseId]="courseId"></core-question> <core-question text-wrap [question]="question" [component]="component" [componentId]="componentId" [attemptId]="attempt.id" [usageId]="attempt.uniqueid" [offlineEnabled]="false" contextLevel="module" [contextInstanceId]="quiz.coursemodule" [courseId]="courseId" [review]="true"></core-question>
</ion-card> </ion-card>
</div> </div>

View File

@ -4,6 +4,8 @@
<p><core-format-text [component]="component" [componentId]="componentId" [text]="question.text" [contextLevel]="contextLevel" [contextInstanceId]="contextInstanceId" [courseId]="courseId"></core-format-text></p> <p><core-format-text [component]="component" [componentId]="componentId" [text]="question.text" [contextLevel]="contextLevel" [contextInstanceId]="contextInstanceId" [courseId]="courseId"></core-format-text></p>
</ion-item> </ion-item>
<!-- Editing the question. -->
<ng-container *ngIf="!review">
<!-- Textarea. --> <!-- Textarea. -->
<ion-item *ngIf="question.textarea && (!question.hasDraftFiles || uploadFilesSupported)"> <ion-item *ngIf="question.textarea && (!question.hasDraftFiles || uploadFilesSupported)">
<!-- "Format" and draftid hidden inputs --> <!-- "Format" and draftid hidden inputs -->
@ -29,8 +31,6 @@
<ng-container *ngIf="question.allowsAttachments"> <ng-container *ngIf="question.allowsAttachments">
<core-attachments *ngIf="uploadFilesSupported && question.attachmentsDraftIdInput" [files]="attachments" [component]="component" [componentId]="componentId" [maxSize]="question.attachmentsMaxBytes" [maxSubmissions]="question.attachmentsMaxFiles" [allowOffline]="offlineEnabled" [acceptedTypes]="question.attachmentsAcceptedTypes"></core-attachments> <core-attachments *ngIf="uploadFilesSupported && question.attachmentsDraftIdInput" [files]="attachments" [component]="component" [componentId]="componentId" [maxSize]="question.attachmentsMaxBytes" [maxSubmissions]="question.attachmentsMaxFiles" [allowOffline]="offlineEnabled" [acceptedTypes]="question.attachmentsAcceptedTypes"></core-attachments>
<core-files *ngIf="uploadFilesSupported && !question.attachmentsDraftIdInput" [files]="attachments" [component]="component" [componentId]="componentId"></core-files>
<input item-content *ngIf="question.attachmentsDraftIdInput" type="hidden" [name]="question.attachmentsDraftIdInput.name" [value]="question.attachmentsDraftIdInput.value" > <input item-content *ngIf="question.attachmentsDraftIdInput" type="hidden" [name]="question.attachmentsDraftIdInput.name" [value]="question.attachmentsDraftIdInput.value" >
<!-- Attachments not supported in this site. --> <!-- Attachments not supported in this site. -->
@ -38,15 +38,16 @@
<p class="core-question-warning">{{ 'core.question.errorattachmentsnotsupportedinsite' | translate }}</p> <p class="core-question-warning">{{ 'core.question.errorattachmentsnotsupportedinsite' | translate }}</p>
</ion-item> </ion-item>
</ng-container> </ng-container>
</ng-container>
<!-- Reviewing the question. -->
<ng-container *ngIf="review">
<!-- Answer to the question and attachments (reviewing). --> <!-- Answer to the question and attachments (reviewing). -->
<ion-item text-wrap *ngIf="!question.textarea && (question.answer || question.answer == '')"> <ion-item text-wrap *ngIf="question.answer || question.answer == ''">
<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> <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>
</ion-item> </ion-item>
<ion-item *ngIf="!question.textarea && question.attachments && question.attachments.length"> <!-- List of attachments when reviewing. -->
<div no-lines> <core-files *ngIf="question.attachments" [files]="question.attachments" [component]="component" [componentId]="componentId"></core-files>
<core-file *ngFor="let attachment of question.attachments" [file]="attachment" [component]="component" [componentId]="componentId"></core-file> </ng-container>
</div>
</ion-item>
</section> </section>

View File

@ -44,11 +44,11 @@ export class AddonQtypeEssayComponent extends CoreQuestionBaseComponent implemen
*/ */
ngOnInit(): void { ngOnInit(): void {
this.uploadFilesSupported = typeof this.question.responsefileareas != 'undefined'; this.uploadFilesSupported = typeof this.question.responsefileareas != 'undefined';
this.initEssayComponent(); this.initEssayComponent(this.review);
this.formControl = this.fb.control(this.question.textarea && this.question.textarea.text); this.formControl = this.fb.control(this.question.textarea && this.question.textarea.text);
if (this.question.allowsAttachments && this.uploadFilesSupported) { if (this.question.allowsAttachments && this.uploadFilesSupported && !this.review) {
this.loadAttachments(); this.loadAttachments();
} }
} }

View File

@ -32,6 +32,7 @@ export class CoreQuestionBaseComponent {
@Input() contextLevel?: string; // The context level. @Input() contextLevel?: string; // The context level.
@Input() contextInstanceId?: number; // The instance ID related to the context. @Input() contextInstanceId?: number; // The instance ID related to the context.
@Input() courseId?: number; // The course the question belongs to (if any). @Input() courseId?: number; // The course the question belongs to (if any).
@Input() review?: boolean; // Whether the user is in review mode.
@Output() buttonClicked: EventEmitter<any>; // Should emit an event when a behaviour button is clicked. @Output() buttonClicked: EventEmitter<any>; // Should emit an event when a behaviour button is clicked.
@Output() onAbort: EventEmitter<void>; // Should emit an event if the question should be aborted. @Output() onAbort: EventEmitter<void>; // Should emit an event if the question should be aborted.
@ -207,13 +208,16 @@ export class CoreQuestionBaseComponent {
/** /**
* Initialize a question component of type essay. * Initialize a question component of type essay.
* *
* @param review Whether we're in review mode.
* @return Element containing the question HTML, void if the data is not valid. * @return Element containing the question HTML, void if the data is not valid.
*/ */
initEssayComponent(): void | HTMLElement { initEssayComponent(review?: boolean): void | HTMLElement {
const questionEl = this.initComponent(); const questionEl = this.initComponent();
if (questionEl) { if (!questionEl) {
const textarea = <HTMLTextAreaElement> questionEl.querySelector('textarea[name*=_answer]'); return;
}
const answerDraftIdInput = <HTMLInputElement> questionEl.querySelector('input[name*="_answer:itemid"]'); const answerDraftIdInput = <HTMLInputElement> questionEl.querySelector('input[name*="_answer:itemid"]');
if (this.question.settings) { if (this.question.settings) {
@ -221,6 +225,7 @@ export class CoreQuestionBaseComponent {
this.question.allowsAnswerFiles = this.question.settings.responseformat == 'editorfilepicker'; this.question.allowsAnswerFiles = this.question.settings.responseformat == 'editorfilepicker';
this.question.isMonospaced = this.question.settings.responseformat == 'monospaced'; this.question.isMonospaced = this.question.settings.responseformat == 'monospaced';
this.question.isPlainText = this.question.isMonospaced || this.question.settings.responseformat == 'plain'; this.question.isPlainText = this.question.isMonospaced || this.question.settings.responseformat == 'plain';
this.question.hasInlineText = this.question.settings.responseformat != 'noinline';
} else { } else {
this.question.allowsAttachments = !!questionEl.querySelector('div[id*=filemanager]'); this.question.allowsAttachments = !!questionEl.querySelector('div[id*=filemanager]');
this.question.allowsAnswerFiles = !!answerDraftIdInput; this.question.allowsAnswerFiles = !!answerDraftIdInput;
@ -228,11 +233,27 @@ export class CoreQuestionBaseComponent {
this.question.isPlainText = this.question.isMonospaced || !!questionEl.querySelector('.qtype_essay_plain'); this.question.isPlainText = this.question.isMonospaced || !!questionEl.querySelector('.qtype_essay_plain');
} }
if (review) {
// Search the answer and the attachments.
this.question.answer = this.domUtils.getContentsOfElement(questionEl, '.qtype_essay_response');
if (this.question.settings) {
this.question.attachments = Array.from(this.questionHelper.getResponseFileAreaFiles(this.question, 'attachments'));
} else {
this.question.attachments = this.questionHelper.getQuestionAttachmentsFromHtml(
this.domUtils.getContentsOfElement(questionEl, '.attachments'));
}
return;
}
const textarea = <HTMLTextAreaElement> questionEl.querySelector('textarea[name*=_answer]');
this.question.hasDraftFiles = this.question.allowsAnswerFiles && this.question.hasDraftFiles = this.question.allowsAnswerFiles &&
this.questionHelper.hasDraftFileUrls(questionEl.innerHTML); this.questionHelper.hasDraftFileUrls(questionEl.innerHTML);
if (!textarea && !this.question.allowsAttachments) { if (!textarea && (this.question.hasInlineText || !this.question.allowsAttachments)) {
// Textarea and filemanager not found, we might be in review. Search the answer and the attachments. // Textarea not found, we might be in review. Search the answer and the attachments.
this.question.answer = this.domUtils.getContentsOfElement(questionEl, '.qtype_essay_response'); this.question.answer = this.domUtils.getContentsOfElement(questionEl, '.qtype_essay_response');
this.question.attachments = this.questionHelper.getQuestionAttachmentsFromHtml( this.question.attachments = this.questionHelper.getQuestionAttachmentsFromHtml(
this.domUtils.getContentsOfElement(questionEl, '.attachments')); this.domUtils.getContentsOfElement(questionEl, '.attachments'));
@ -300,7 +321,6 @@ export class CoreQuestionBaseComponent {
return questionEl; return questionEl;
} }
}
/** /**
* Initialize a question component that uses the original question text with some basic treatment. * Initialize a question component that uses the original question text with some basic treatment.

View File

@ -39,6 +39,7 @@ export class CoreQuestionComponent implements OnInit {
@Input() contextLevel?: string; // The context level. @Input() contextLevel?: string; // The context level.
@Input() contextInstanceId?: number; // The instance ID related to the context. @Input() contextInstanceId?: number; // The instance ID related to the context.
@Input() courseId?: number; // Course ID the question belongs to (if any). It can be used to improve performance with filters. @Input() courseId?: number; // Course ID the question belongs to (if any). It can be used to improve performance with filters.
@Input() review?: boolean; // Whether the user is in review mode.
@Output() buttonClicked: EventEmitter<any>; // Will emit an event when a behaviour button is clicked. @Output() buttonClicked: EventEmitter<any>; // Will emit an event when a behaviour button is clicked.
@Output() onAbort: EventEmitter<void>; // Will emit an event if the question should be aborted. @Output() onAbort: EventEmitter<void>; // Will emit an event if the question should be aborted.
@ -88,8 +89,9 @@ export class CoreQuestionComponent implements OnInit {
contextLevel: this.contextLevel, contextLevel: this.contextLevel,
contextInstanceId: this.contextInstanceId, contextInstanceId: this.contextInstanceId,
courseId: this.courseId, courseId: this.courseId,
review: this.review,
buttonClicked: this.buttonClicked, buttonClicked: this.buttonClicked,
onAbort: this.onAbort onAbort: this.onAbort,
}; };
// Treat the question. // Treat the question.