diff --git a/src/addons/qtype/essay/component/addon-qtype-essay.html b/src/addons/qtype/essay/component/addon-qtype-essay.html
index 85cf617cc..829c6fdc5 100644
--- a/src/addons/qtype/essay/component/addon-qtype-essay.html
+++ b/src/addons/qtype/essay/component/addon-qtype-essay.html
@@ -79,9 +79,18 @@
+
+
+
+
+
+
+
+
+ [componentId]="componentId" [extraHtml]="essayQuestion.attachmentsPlagiarisms">
diff --git a/src/core/components/files/core-files.html b/src/core/components/files/core-files.html
index d16b3f24c..be8580a72 100644
--- a/src/core/components/files/core-files.html
+++ b/src/core/components/files/core-files.html
@@ -1,7 +1,7 @@
-
+
@@ -9,4 +9,11 @@
+
+
+
+
+
+
+
diff --git a/src/core/components/files/files.ts b/src/core/components/files/files.ts
index b17358e65..a17b1587e 100644
--- a/src/core/components/files/files.ts
+++ b/src/core/components/files/files.ts
@@ -38,6 +38,7 @@ export class CoreFilesComponent implements OnInit, DoCheck {
@Input() showSize?: boolean | string = true; // Whether show filesize.
@Input() showTime?: boolean | string = true; // Whether show file time modified.
@Input() showInline = false; // If true, it will reorder and try to show inline files first.
+ @Input() extraHtml?: string[]; // Extra HTML for each attachment. Each HTML should be at the same position as the attachment.
contentText?: string;
diff --git a/src/core/features/question/classes/base-question-component.ts b/src/core/features/question/classes/base-question-component.ts
index 7be8ed33f..dcb5f9458 100644
--- a/src/core/features/question/classes/base-question-component.ts
+++ b/src/core/features/question/classes/base-question-component.ts
@@ -13,6 +13,7 @@
// limitations under the License.
import { Input, Output, EventEmitter, Component, Optional, Inject, ElementRef } from '@angular/core';
+import { CoreFileHelper } from '@services/file-helper';
import { CoreSites } from '@services/sites';
import { CoreDomUtils } from '@services/utils/dom';
@@ -274,6 +275,9 @@ export class CoreQuestionBaseComponent {
);
}
+ // Treat plagiarism.
+ this.handleEssayPlagiarism(questionEl);
+
return questionEl;
}
@@ -353,6 +357,40 @@ export class CoreQuestionBaseComponent {
return questionEl;
}
+ /**
+ * Handle plagiarism in an essay question.
+ *
+ * @param questionEl Element with the question html.
+ */
+ protected handleEssayPlagiarism(questionEl: HTMLElement): void {
+ const question = this.question!;
+ const answerPlagiarism = questionEl.querySelector('.answer .core_plagiarism_links');
+ if (answerPlagiarism) {
+ question.answerPlagiarism = answerPlagiarism.innerHTML;
+ }
+
+ if (!question.attachments?.length) {
+ return;
+ }
+
+ const attachmentsPlagiarisms = questionEl.querySelectorAll('.attachments .core_plagiarism_links');
+ question.attachmentsPlagiarisms = [];
+
+ Array.from(attachmentsPlagiarisms).forEach((plagiarism) => {
+ // Search the URL of the attachment it affects.
+ const attachmentUrl = plagiarism.parentElement?.querySelector('a')?.href;
+ if (!attachmentUrl) {
+ return;
+ }
+
+ const position = question.attachments!.findIndex((file) => CoreFileHelper.getFileUrl(file) == attachmentUrl);
+
+ if (position >= 0) {
+ question.attachmentsPlagiarisms![position] = plagiarism.innerHTML;
+ }
+ });
+ }
+
/**
* Initialize a question component that uses the original question text with some basic treatment.
*
@@ -724,6 +762,8 @@ export type AddonModQuizEssayQuestion = AddonModQuizQuestionBasicData & {
attachmentsMaxFiles?: number; // Max number of attachments.
attachmentsAcceptedTypes?: string; // Attachments accepted file types.
attachmentsMaxBytes?: number; // Max bytes for attachments.
+ answerPlagiarism?: string; // Plagiarism HTML for the answer.
+ attachmentsPlagiarisms?: string[]; // Plagiarism HTML for each attachment.
};
/**