diff --git a/src/addon/qtype/ddmarker/providers/handler.ts b/src/addon/qtype/ddmarker/providers/handler.ts index 3971da112..a3c2bd01e 100644 --- a/src/addon/qtype/ddmarker/providers/handler.ts +++ b/src/addon/qtype/ddmarker/providers/handler.ts @@ -18,6 +18,7 @@ import { CoreQuestionProvider } from '@core/question/providers/question'; import { CoreQuestionHandler } from '@core/question/providers/delegate'; import { CoreQuestionHelperProvider } from '@core/question/providers/helper'; import { AddonQtypeDdMarkerComponent } from '../component/ddmarker'; +import { CoreWSExternalFile } from '@providers/ws'; /** * Handler to support drag-and-drop markers question type. @@ -119,9 +120,9 @@ export class AddonQtypeDdMarkerHandler implements CoreQuestionHandler { * * @param question Question. * @param usageId Usage ID. - * @return List of URLs. + * @return List of files or URLs. */ - getAdditionalDownloadableFiles(question: any, usageId: number): string[] { + getAdditionalDownloadableFiles(question: any, usageId: number): (string | CoreWSExternalFile)[] { this.questionHelper.extractQuestionScripts(question, usageId); if (question.amdArgs && typeof question.amdArgs[1] == 'string') { diff --git a/src/addon/qtype/essay/providers/handler.ts b/src/addon/qtype/essay/providers/handler.ts index 54c45ebd0..834850ca4 100644 --- a/src/addon/qtype/essay/providers/handler.ts +++ b/src/addon/qtype/essay/providers/handler.ts @@ -24,6 +24,7 @@ import { CoreQuestionHandler } from '@core/question/providers/delegate'; import { CoreQuestionHelperProvider } from '@core/question/providers/helper'; import { CoreQuestion } from '@core/question/providers/question'; import { AddonQtypeEssayComponent } from '../component/essay'; +import { CoreWSExternalFile } from '@providers/ws'; /** * Handler to support essay question type. @@ -67,6 +68,23 @@ export class AddonQtypeEssayHandler implements CoreQuestionHandler { return this.questionHelper.deleteStoredQuestionFiles(question, component, componentId, siteId); } + /** + * Get the list of files that needs to be downloaded in addition to the files embedded in the HTML. + * + * @param question Question. + * @param usageId Usage ID. + * @return List of files or URLs. + */ + getAdditionalDownloadableFiles(question: any, usageId: number): (string | CoreWSExternalFile)[] { + if (!question.responsefileareas) { + return []; + } + + return question.responsefileareas.reduce((urlsList, area) => { + return urlsList.concat(area.files || []); + }, []); + } + /** * Check whether the question allows text and/or attachments. * diff --git a/src/core/question/providers/delegate.ts b/src/core/question/providers/delegate.ts index 6caa7eb2b..7a0cd7675 100644 --- a/src/core/question/providers/delegate.ts +++ b/src/core/question/providers/delegate.ts @@ -18,6 +18,7 @@ import { CoreEventsProvider } from '@providers/events'; import { CoreSitesProvider } from '@providers/sites'; import { CoreDelegate, CoreDelegateHandler } from '@classes/delegate'; import { CoreQuestionDefaultHandler } from './default-question-handler'; +import { CoreWSExternalFile } from '@providers/ws'; /** * Interface that all question type handlers must implement. @@ -119,9 +120,9 @@ export interface CoreQuestionHandler extends CoreDelegateHandler { * * @param question Question. * @param usageId Usage ID. - * @return List of URLs. + * @return List of files or URLs. */ - getAdditionalDownloadableFiles?(question: any, usageId: number): string[]; + getAdditionalDownloadableFiles?(question: any, usageId: number): (string | CoreWSExternalFile)[]; /** * Clear temporary data after the data has been saved. @@ -324,9 +325,9 @@ export class CoreQuestionDelegate extends CoreDelegate { * * @param question Question. * @param usageId Usage ID. - * @return List of URLs. + * @return List of files or URLs. */ - getAdditionalDownloadableFiles(question: any, usageId: number): string[] { + getAdditionalDownloadableFiles(question: any, usageId: number): (string | CoreWSExternalFile)[] { const type = this.getTypeName(question); return this.executeFunctionOnEnabled(type, 'getAdditionalDownloadableFiles', [question, usageId]) || []; diff --git a/src/core/question/providers/helper.ts b/src/core/question/providers/helper.ts index 9c6570858..b90274929 100644 --- a/src/core/question/providers/helper.ts +++ b/src/core/question/providers/helper.ts @@ -590,29 +590,39 @@ export class CoreQuestionHelperProvider { */ prefetchQuestionFiles(question: any, component?: string, componentId?: string | number, siteId?: string, usageId?: number) : Promise { - const urls = this.filepoolProvider.extractDownloadableFilesFromHtml(question.html); if (!component) { component = CoreQuestionProvider.COMPONENT; componentId = question.number; } - urls.push(...this.questionDelegate.getAdditionalDownloadableFiles(question, usageId)); + const files = this.questionDelegate.getAdditionalDownloadableFiles(question, usageId) || []; + + files.push(...this.filepoolProvider.extractDownloadableFilesFromHtml(question.html)); return this.sitesProvider.getSite(siteId).then((site) => { const promises = []; + const treated = {}; - urls.forEach((url) => { - if (!site.canDownloadFiles() && this.urlUtils.isPluginFileUrl(url)) { + files.forEach((file) => { + const fileUrl = typeof file == 'string' ? file : file.fileurl; + const timemodified = (typeof file != 'string' && file.timemodified) || 0; + + if (treated[fileUrl]) { + return; + } + treated[fileUrl] = true; + + if (!site.canDownloadFiles() && this.urlUtils.isPluginFileUrl(fileUrl)) { return; } - if (url.indexOf('theme/image.php') > -1 && url.indexOf('flagged') > -1) { + if (fileUrl.indexOf('theme/image.php') > -1 && fileUrl.indexOf('flagged') > -1) { // Ignore flag images. return; } - promises.push(this.filepoolProvider.addToQueueByUrl(siteId, url, component, componentId)); + promises.push(this.filepoolProvider.addToQueueByUrl(siteId, fileUrl, component, componentId, timemodified)); }); return Promise.all(promises);