MOBILE-2235 h5p: Implement H5P download and unzip

main
Dani Palou 2019-11-05 13:00:05 +01:00
parent 9b637fc496
commit c4a58d9ee8
40 changed files with 751 additions and 220 deletions

View File

@ -69,11 +69,14 @@ export class AddonFilterDisplayH5PHandler extends CoreFilterDefaultHandler {
* @param filter The filter. * @param filter The filter.
* @param options Options passed to the filters. * @param options Options passed to the filters.
* @param viewContainerRef The ViewContainerRef where the container is. * @param viewContainerRef The ViewContainerRef where the container is.
* @param component Component.
* @param componentId Component ID.
* @param siteId Site ID. If not defined, current site. * @param siteId Site ID. If not defined, current site.
* @return If async, promise resolved when done. * @return If async, promise resolved when done.
*/ */
handleHtml(container: HTMLElement, filter: CoreFilterFilter, options: CoreFilterFormatTextOptions, handleHtml(container: HTMLElement, filter: CoreFilterFilter, options: CoreFilterFormatTextOptions,
viewContainerRef: ViewContainerRef, siteId?: string): void | Promise<void> { viewContainerRef: ViewContainerRef, component?: string, componentId?: string | number, siteId?: string)
: void | Promise<void> {
const placeholders = <HTMLElement[]> Array.from(container.querySelectorAll('div.core-h5p-tmp-placeholder')); const placeholders = <HTMLElement[]> Array.from(container.querySelectorAll('div.core-h5p-tmp-placeholder'));
@ -85,6 +88,8 @@ export class AddonFilterDisplayH5PHandler extends CoreFilterDefaultHandler {
componentRef = viewContainerRef.createComponent(factory); componentRef = viewContainerRef.createComponent(factory);
componentRef.instance.src = url; componentRef.instance.src = url;
componentRef.instance.component = component;
componentRef.instance.componentId = componentId;
// Move the component to its right position. // Move the component to its right position.
placeholder.parentElement.replaceChild(componentRef.instance.elementRef.nativeElement, placeholder); placeholder.parentElement.replaceChild(componentRef.instance.elementRef.nativeElement, placeholder);

View File

@ -162,11 +162,14 @@ export class AddonFilterMathJaxLoaderHandler extends CoreFilterDefaultHandler {
* @param filter The filter. * @param filter The filter.
* @param options Options passed to the filters. * @param options Options passed to the filters.
* @param viewContainerRef The ViewContainerRef where the container is. * @param viewContainerRef The ViewContainerRef where the container is.
* @param component Component.
* @param componentId Component ID.
* @param siteId Site ID. If not defined, current site. * @param siteId Site ID. If not defined, current site.
* @return If async, promise resolved when done. * @return If async, promise resolved when done.
*/ */
handleHtml(container: HTMLElement, filter: CoreFilterFilter, options: CoreFilterFormatTextOptions, handleHtml(container: HTMLElement, filter: CoreFilterFilter, options: CoreFilterFormatTextOptions,
viewContainerRef: ViewContainerRef, siteId?: string): void | Promise<void> { viewContainerRef: ViewContainerRef, component?: string, componentId?: string | number, siteId?: string)
: void | Promise<void> {
return this.waitForReady().then(() => { return this.waitForReady().then(() => {
this.window.M.filter_mathjaxloader.typeset(container); this.window.M.filter_mathjaxloader.typeset(container);

View File

@ -32,6 +32,7 @@ import { AddonModAssignSyncProvider } from './assign-sync';
import { AddonModAssignFeedbackDelegate } from './feedback-delegate'; import { AddonModAssignFeedbackDelegate } from './feedback-delegate';
import { AddonModAssignSubmissionDelegate } from './submission-delegate'; import { AddonModAssignSubmissionDelegate } from './submission-delegate';
import { CoreFilterHelperProvider } from '@core/filter/providers/helper'; import { CoreFilterHelperProvider } from '@core/filter/providers/helper';
import { CorePluginFileDelegate } from '@providers/plugin-file-delegate';
/** /**
* Handler to prefetch assigns. * Handler to prefetch assigns.
@ -51,6 +52,7 @@ export class AddonModAssignPrefetchHandler extends CoreCourseActivityPrefetchHan
sitesProvider: CoreSitesProvider, sitesProvider: CoreSitesProvider,
domUtils: CoreDomUtilsProvider, domUtils: CoreDomUtilsProvider,
filterHelper: CoreFilterHelperProvider, filterHelper: CoreFilterHelperProvider,
pluginFileDelegate: CorePluginFileDelegate,
protected assignProvider: AddonModAssignProvider, protected assignProvider: AddonModAssignProvider,
protected textUtils: CoreTextUtilsProvider, protected textUtils: CoreTextUtilsProvider,
protected feedbackDelegate: AddonModAssignFeedbackDelegate, protected feedbackDelegate: AddonModAssignFeedbackDelegate,
@ -62,7 +64,8 @@ export class AddonModAssignPrefetchHandler extends CoreCourseActivityPrefetchHan
protected assignHelper: AddonModAssignHelperProvider, protected assignHelper: AddonModAssignHelperProvider,
protected syncProvider: AddonModAssignSyncProvider) { protected syncProvider: AddonModAssignSyncProvider) {
super(translate, appProvider, utils, courseProvider, filepoolProvider, sitesProvider, domUtils, filterHelper); super(translate, appProvider, utils, courseProvider, filepoolProvider, sitesProvider, domUtils, filterHelper,
pluginFileDelegate);
} }
/** /**

View File

@ -23,6 +23,7 @@ import { CoreCourseProvider } from '@core/course/providers/course';
import { CoreCourseResourcePrefetchHandlerBase } from '@core/course/classes/resource-prefetch-handler'; import { CoreCourseResourcePrefetchHandlerBase } from '@core/course/classes/resource-prefetch-handler';
import { AddonModBookProvider } from './book'; import { AddonModBookProvider } from './book';
import { CoreFilterHelperProvider } from '@core/filter/providers/helper'; import { CoreFilterHelperProvider } from '@core/filter/providers/helper';
import { CorePluginFileDelegate } from '@providers/plugin-file-delegate';
/** /**
* Handler to prefetch books. * Handler to prefetch books.
@ -42,9 +43,11 @@ export class AddonModBookPrefetchHandler extends CoreCourseResourcePrefetchHandl
sitesProvider: CoreSitesProvider, sitesProvider: CoreSitesProvider,
domUtils: CoreDomUtilsProvider, domUtils: CoreDomUtilsProvider,
filterHelper: CoreFilterHelperProvider, filterHelper: CoreFilterHelperProvider,
pluginFileDelegate: CorePluginFileDelegate,
protected bookProvider: AddonModBookProvider) { protected bookProvider: AddonModBookProvider) {
super(translate, appProvider, utils, courseProvider, filepoolProvider, sitesProvider, domUtils, filterHelper); super(translate, appProvider, utils, courseProvider, filepoolProvider, sitesProvider, domUtils, filterHelper,
pluginFileDelegate);
} }
/** /**

View File

@ -25,6 +25,7 @@ import { CoreCourseActivityPrefetchHandlerBase } from '@core/course/classes/acti
import { CoreUserProvider } from '@core/user/providers/user'; import { CoreUserProvider } from '@core/user/providers/user';
import { AddonModChatProvider, AddonModChatChat } from './chat'; import { AddonModChatProvider, AddonModChatChat } from './chat';
import { CoreFilterHelperProvider } from '@core/filter/providers/helper'; import { CoreFilterHelperProvider } from '@core/filter/providers/helper';
import { CorePluginFileDelegate } from '@providers/plugin-file-delegate';
/** /**
* Handler to prefetch chats. * Handler to prefetch chats.
@ -43,11 +44,13 @@ export class AddonModChatPrefetchHandler extends CoreCourseActivityPrefetchHandl
sitesProvider: CoreSitesProvider, sitesProvider: CoreSitesProvider,
domUtils: CoreDomUtilsProvider, domUtils: CoreDomUtilsProvider,
filterHelper: CoreFilterHelperProvider, filterHelper: CoreFilterHelperProvider,
pluginFileDelegate: CorePluginFileDelegate,
private groupsProvider: CoreGroupsProvider, private groupsProvider: CoreGroupsProvider,
private userProvider: CoreUserProvider, private userProvider: CoreUserProvider,
private chatProvider: AddonModChatProvider) { private chatProvider: AddonModChatProvider) {
super(translate, appProvider, utils, courseProvider, filepoolProvider, sitesProvider, domUtils, filterHelper); super(translate, appProvider, utils, courseProvider, filepoolProvider, sitesProvider, domUtils, filterHelper,
pluginFileDelegate);
} }
/** /**

View File

@ -25,6 +25,7 @@ import { CoreUserProvider } from '@core/user/providers/user';
import { AddonModChoiceSyncProvider } from './sync'; import { AddonModChoiceSyncProvider } from './sync';
import { AddonModChoiceProvider } from './choice'; import { AddonModChoiceProvider } from './choice';
import { CoreFilterHelperProvider } from '@core/filter/providers/helper'; import { CoreFilterHelperProvider } from '@core/filter/providers/helper';
import { CorePluginFileDelegate } from '@providers/plugin-file-delegate';
/** /**
* Handler to prefetch choices. * Handler to prefetch choices.
@ -46,11 +47,13 @@ export class AddonModChoicePrefetchHandler extends CoreCourseActivityPrefetchHan
sitesProvider: CoreSitesProvider, sitesProvider: CoreSitesProvider,
domUtils: CoreDomUtilsProvider, domUtils: CoreDomUtilsProvider,
filterHelper: CoreFilterHelperProvider, filterHelper: CoreFilterHelperProvider,
pluginFileDelegate: CorePluginFileDelegate,
protected choiceProvider: AddonModChoiceProvider, protected choiceProvider: AddonModChoiceProvider,
protected userProvider: CoreUserProvider, protected userProvider: CoreUserProvider,
protected injector: Injector) { protected injector: Injector) {
super(translate, appProvider, utils, courseProvider, filepoolProvider, sitesProvider, domUtils, filterHelper); super(translate, appProvider, utils, courseProvider, filepoolProvider, sitesProvider, domUtils, filterHelper,
pluginFileDelegate);
} }
/** /**

View File

@ -28,6 +28,7 @@ import { AddonModDataProvider, AddonModDataEntry } from './data';
import { AddonModDataSyncProvider } from './sync'; import { AddonModDataSyncProvider } from './sync';
import { AddonModDataHelperProvider } from './helper'; import { AddonModDataHelperProvider } from './helper';
import { CoreFilterHelperProvider } from '@core/filter/providers/helper'; import { CoreFilterHelperProvider } from '@core/filter/providers/helper';
import { CorePluginFileDelegate } from '@providers/plugin-file-delegate';
/** /**
* Handler to prefetch databases. * Handler to prefetch databases.
@ -47,6 +48,7 @@ export class AddonModDataPrefetchHandler extends CoreCourseActivityPrefetchHandl
sitesProvider: CoreSitesProvider, sitesProvider: CoreSitesProvider,
domUtils: CoreDomUtilsProvider, domUtils: CoreDomUtilsProvider,
filterHelper: CoreFilterHelperProvider, filterHelper: CoreFilterHelperProvider,
pluginFileDelegate: CorePluginFileDelegate,
protected dataProvider: AddonModDataProvider, protected dataProvider: AddonModDataProvider,
protected timeUtils: CoreTimeUtilsProvider, protected timeUtils: CoreTimeUtilsProvider,
protected dataHelper: AddonModDataHelperProvider, protected dataHelper: AddonModDataHelperProvider,
@ -54,7 +56,8 @@ export class AddonModDataPrefetchHandler extends CoreCourseActivityPrefetchHandl
protected commentsProvider: CoreCommentsProvider, protected commentsProvider: CoreCommentsProvider,
protected syncProvider: AddonModDataSyncProvider) { protected syncProvider: AddonModDataSyncProvider) {
super(translate, appProvider, utils, courseProvider, filepoolProvider, sitesProvider, domUtils, filterHelper); super(translate, appProvider, utils, courseProvider, filepoolProvider, sitesProvider, domUtils, filterHelper,
pluginFileDelegate);
} }
/** /**

View File

@ -27,6 +27,7 @@ import { CoreTimeUtilsProvider } from '@providers/utils/time';
import { CoreGroupsProvider } from '@providers/groups'; import { CoreGroupsProvider } from '@providers/groups';
import { AddonModFeedbackSyncProvider } from './sync'; import { AddonModFeedbackSyncProvider } from './sync';
import { CoreFilterHelperProvider } from '@core/filter/providers/helper'; import { CoreFilterHelperProvider } from '@core/filter/providers/helper';
import { CorePluginFileDelegate } from '@providers/plugin-file-delegate';
/** /**
* Handler to prefetch feedbacks. * Handler to prefetch feedbacks.
@ -48,13 +49,15 @@ export class AddonModFeedbackPrefetchHandler extends CoreCourseActivityPrefetchH
sitesProvider: CoreSitesProvider, sitesProvider: CoreSitesProvider,
domUtils: CoreDomUtilsProvider, domUtils: CoreDomUtilsProvider,
filterHelper: CoreFilterHelperProvider, filterHelper: CoreFilterHelperProvider,
pluginFileDelegate: CorePluginFileDelegate,
protected feedbackProvider: AddonModFeedbackProvider, protected feedbackProvider: AddonModFeedbackProvider,
protected feedbackHelper: AddonModFeedbackHelperProvider, protected feedbackHelper: AddonModFeedbackHelperProvider,
protected timeUtils: CoreTimeUtilsProvider, protected timeUtils: CoreTimeUtilsProvider,
protected groupsProvider: CoreGroupsProvider, protected groupsProvider: CoreGroupsProvider,
protected injector: Injector) { protected injector: Injector) {
super(translate, appProvider, utils, courseProvider, filepoolProvider, sitesProvider, domUtils, filterHelper); super(translate, appProvider, utils, courseProvider, filepoolProvider, sitesProvider, domUtils, filterHelper,
pluginFileDelegate);
} }
/** /**

View File

@ -23,6 +23,7 @@ import { CoreCourseProvider } from '@core/course/providers/course';
import { CoreCourseResourcePrefetchHandlerBase } from '@core/course/classes/resource-prefetch-handler'; import { CoreCourseResourcePrefetchHandlerBase } from '@core/course/classes/resource-prefetch-handler';
import { AddonModFolderProvider } from './folder'; import { AddonModFolderProvider } from './folder';
import { CoreFilterHelperProvider } from '@core/filter/providers/helper'; import { CoreFilterHelperProvider } from '@core/filter/providers/helper';
import { CorePluginFileDelegate } from '@providers/plugin-file-delegate';
/** /**
* Handler to prefetch folders. * Handler to prefetch folders.
@ -41,9 +42,11 @@ export class AddonModFolderPrefetchHandler extends CoreCourseResourcePrefetchHan
sitesProvider: CoreSitesProvider, sitesProvider: CoreSitesProvider,
domUtils: CoreDomUtilsProvider, domUtils: CoreDomUtilsProvider,
filterHelper: CoreFilterHelperProvider, filterHelper: CoreFilterHelperProvider,
pluginFileDelegate: CorePluginFileDelegate,
protected folderProvider: AddonModFolderProvider) { protected folderProvider: AddonModFolderProvider) {
super(translate, appProvider, utils, courseProvider, filepoolProvider, sitesProvider, domUtils, filterHelper); super(translate, appProvider, utils, courseProvider, filepoolProvider, sitesProvider, domUtils, filterHelper,
pluginFileDelegate);
} }
/** /**

View File

@ -26,6 +26,7 @@ import { CoreGroupsProvider } from '@providers/groups';
import { AddonModForumProvider } from './forum'; import { AddonModForumProvider } from './forum';
import { AddonModForumSyncProvider } from './sync'; import { AddonModForumSyncProvider } from './sync';
import { CoreFilterHelperProvider } from '@core/filter/providers/helper'; import { CoreFilterHelperProvider } from '@core/filter/providers/helper';
import { CorePluginFileDelegate } from '@providers/plugin-file-delegate';
/** /**
* Handler to prefetch forums. * Handler to prefetch forums.
@ -45,12 +46,14 @@ export class AddonModForumPrefetchHandler extends CoreCourseActivityPrefetchHand
sitesProvider: CoreSitesProvider, sitesProvider: CoreSitesProvider,
domUtils: CoreDomUtilsProvider, domUtils: CoreDomUtilsProvider,
filterHelper: CoreFilterHelperProvider, filterHelper: CoreFilterHelperProvider,
pluginFileDelegate: CorePluginFileDelegate,
private userProvider: CoreUserProvider, private userProvider: CoreUserProvider,
private groupsProvider: CoreGroupsProvider, private groupsProvider: CoreGroupsProvider,
private forumProvider: AddonModForumProvider, private forumProvider: AddonModForumProvider,
private syncProvider: AddonModForumSyncProvider) { private syncProvider: AddonModForumSyncProvider) {
super(translate, appProvider, utils, courseProvider, filepoolProvider, sitesProvider, domUtils, filterHelper); super(translate, appProvider, utils, courseProvider, filepoolProvider, sitesProvider, domUtils, filterHelper,
pluginFileDelegate);
} }
/** /**

View File

@ -25,6 +25,7 @@ import { CoreCourseActivityPrefetchHandlerBase } from '@core/course/classes/acti
import { AddonModGlossaryProvider } from './glossary'; import { AddonModGlossaryProvider } from './glossary';
import { AddonModGlossarySyncProvider } from './sync'; import { AddonModGlossarySyncProvider } from './sync';
import { CoreFilterHelperProvider } from '@core/filter/providers/helper'; import { CoreFilterHelperProvider } from '@core/filter/providers/helper';
import { CorePluginFileDelegate } from '@providers/plugin-file-delegate';
/** /**
* Handler to prefetch forums. * Handler to prefetch forums.
@ -44,11 +45,13 @@ export class AddonModGlossaryPrefetchHandler extends CoreCourseActivityPrefetchH
sitesProvider: CoreSitesProvider, sitesProvider: CoreSitesProvider,
domUtils: CoreDomUtilsProvider, domUtils: CoreDomUtilsProvider,
filterHelper: CoreFilterHelperProvider, filterHelper: CoreFilterHelperProvider,
pluginFileDelegate: CorePluginFileDelegate,
protected glossaryProvider: AddonModGlossaryProvider, protected glossaryProvider: AddonModGlossaryProvider,
protected commentsProvider: CoreCommentsProvider, protected commentsProvider: CoreCommentsProvider,
protected syncProvider: AddonModGlossarySyncProvider) { protected syncProvider: AddonModGlossarySyncProvider) {
super(translate, appProvider, utils, courseProvider, filepoolProvider, sitesProvider, domUtils, filterHelper); super(translate, appProvider, utils, courseProvider, filepoolProvider, sitesProvider, domUtils, filterHelper,
pluginFileDelegate);
} }
/** /**

View File

@ -23,6 +23,7 @@ import { CoreCourseProvider } from '@core/course/providers/course';
import { CoreCourseResourcePrefetchHandlerBase } from '@core/course/classes/resource-prefetch-handler'; import { CoreCourseResourcePrefetchHandlerBase } from '@core/course/classes/resource-prefetch-handler';
import { AddonModImscpProvider } from './imscp'; import { AddonModImscpProvider } from './imscp';
import { CoreFilterHelperProvider } from '@core/filter/providers/helper'; import { CoreFilterHelperProvider } from '@core/filter/providers/helper';
import { CorePluginFileDelegate } from '@providers/plugin-file-delegate';
/** /**
* Handler to prefetch IMSCPs. * Handler to prefetch IMSCPs.
@ -41,9 +42,11 @@ export class AddonModImscpPrefetchHandler extends CoreCourseResourcePrefetchHand
sitesProvider: CoreSitesProvider, sitesProvider: CoreSitesProvider,
domUtils: CoreDomUtilsProvider, domUtils: CoreDomUtilsProvider,
filterHelper: CoreFilterHelperProvider, filterHelper: CoreFilterHelperProvider,
pluginFileDelegate: CorePluginFileDelegate,
protected imscpProvider: AddonModImscpProvider) { protected imscpProvider: AddonModImscpProvider) {
super(translate, appProvider, utils, courseProvider, filepoolProvider, sitesProvider, domUtils, filterHelper); super(translate, appProvider, utils, courseProvider, filepoolProvider, sitesProvider, domUtils, filterHelper,
pluginFileDelegate);
} }
/** /**

View File

@ -23,6 +23,7 @@ import { CoreCourseProvider } from '@core/course/providers/course';
import { CoreCourseResourcePrefetchHandlerBase } from '@core/course/classes/resource-prefetch-handler'; import { CoreCourseResourcePrefetchHandlerBase } from '@core/course/classes/resource-prefetch-handler';
import { AddonModLabelProvider } from './label'; import { AddonModLabelProvider } from './label';
import { CoreFilterHelperProvider } from '@core/filter/providers/helper'; import { CoreFilterHelperProvider } from '@core/filter/providers/helper';
import { CorePluginFileDelegate } from '@providers/plugin-file-delegate';
/** /**
* Handler to prefetch labels. * Handler to prefetch labels.
@ -43,9 +44,11 @@ export class AddonModLabelPrefetchHandler extends CoreCourseResourcePrefetchHand
sitesProvider: CoreSitesProvider, sitesProvider: CoreSitesProvider,
domUtils: CoreDomUtilsProvider, domUtils: CoreDomUtilsProvider,
filterHelper: CoreFilterHelperProvider, filterHelper: CoreFilterHelperProvider,
pluginFileDelegate: CorePluginFileDelegate,
protected labelProvider: AddonModLabelProvider) { protected labelProvider: AddonModLabelProvider) {
super(translate, appProvider, utils, courseProvider, filepoolProvider, sitesProvider, domUtils, filterHelper); super(translate, appProvider, utils, courseProvider, filepoolProvider, sitesProvider, domUtils, filterHelper,
pluginFileDelegate);
} }
/** /**

View File

@ -26,6 +26,7 @@ import { CoreCourseActivityPrefetchHandlerBase } from '@core/course/classes/acti
import { AddonModLessonProvider } from './lesson'; import { AddonModLessonProvider } from './lesson';
import { AddonModLessonSyncProvider } from './lesson-sync'; import { AddonModLessonSyncProvider } from './lesson-sync';
import { CoreFilterHelperProvider } from '@core/filter/providers/helper'; import { CoreFilterHelperProvider } from '@core/filter/providers/helper';
import { CorePluginFileDelegate } from '@providers/plugin-file-delegate';
/** /**
* Handler to prefetch lessons. * Handler to prefetch lessons.
@ -48,12 +49,14 @@ export class AddonModLessonPrefetchHandler extends CoreCourseActivityPrefetchHan
sitesProvider: CoreSitesProvider, sitesProvider: CoreSitesProvider,
domUtils: CoreDomUtilsProvider, domUtils: CoreDomUtilsProvider,
filterHelper: CoreFilterHelperProvider, filterHelper: CoreFilterHelperProvider,
pluginFileDelegate: CorePluginFileDelegate,
protected modalCtrl: ModalController, protected modalCtrl: ModalController,
protected groupsProvider: CoreGroupsProvider, protected groupsProvider: CoreGroupsProvider,
protected lessonProvider: AddonModLessonProvider, protected lessonProvider: AddonModLessonProvider,
protected injector: Injector) { protected injector: Injector) {
super(translate, appProvider, utils, courseProvider, filepoolProvider, sitesProvider, domUtils, filterHelper); super(translate, appProvider, utils, courseProvider, filepoolProvider, sitesProvider, domUtils, filterHelper,
pluginFileDelegate);
} }
/** /**
@ -108,7 +111,9 @@ export class AddonModLessonPrefetchHandler extends CoreCourseActivityPrefetchHan
let files = lesson.mediafiles || []; let files = lesson.mediafiles || [];
files = files.concat(this.getIntroFilesFromInstance(module, lesson)); files = files.concat(this.getIntroFilesFromInstance(module, lesson));
result = this.utils.sumFileSizes(files); return this.pluginFileDelegate.getFilesSize(files);
}).then((res) => {
result = res;
// Get the pages to calculate the size. // Get the pages to calculate the size.
return this.lessonProvider.getPages(lesson.id, password, false, false, siteId); return this.lessonProvider.getPages(lesson.id, password, false, false, siteId);

View File

@ -23,6 +23,7 @@ import { CoreCourseProvider } from '@core/course/providers/course';
import { CoreCourseActivityPrefetchHandlerBase } from '@core/course/classes/activity-prefetch-handler'; import { CoreCourseActivityPrefetchHandlerBase } from '@core/course/classes/activity-prefetch-handler';
import { AddonModLtiProvider } from './lti'; import { AddonModLtiProvider } from './lti';
import { CoreFilterHelperProvider } from '@core/filter/providers/helper'; import { CoreFilterHelperProvider } from '@core/filter/providers/helper';
import { CorePluginFileDelegate } from '@providers/plugin-file-delegate';
/** /**
* Handler to prefetch LTIs. LTIs cannot be prefetched, but the handler will be used to invalidate some data on course PTR. * Handler to prefetch LTIs. LTIs cannot be prefetched, but the handler will be used to invalidate some data on course PTR.
@ -41,9 +42,11 @@ export class AddonModLtiPrefetchHandler extends CoreCourseActivityPrefetchHandle
sitesProvider: CoreSitesProvider, sitesProvider: CoreSitesProvider,
domUtils: CoreDomUtilsProvider, domUtils: CoreDomUtilsProvider,
filterHelper: CoreFilterHelperProvider, filterHelper: CoreFilterHelperProvider,
pluginFileDelegate: CorePluginFileDelegate,
protected ltiProvider: AddonModLtiProvider) { protected ltiProvider: AddonModLtiProvider) {
super(translate, appProvider, utils, courseProvider, filepoolProvider, sitesProvider, domUtils, filterHelper); super(translate, appProvider, utils, courseProvider, filepoolProvider, sitesProvider, domUtils, filterHelper,
pluginFileDelegate);
} }
/** /**

View File

@ -24,6 +24,7 @@ import { CoreCourseResourcePrefetchHandlerBase } from '@core/course/classes/reso
import { AddonModPageProvider } from './page'; import { AddonModPageProvider } from './page';
import { AddonModPageHelperProvider } from './helper'; import { AddonModPageHelperProvider } from './helper';
import { CoreFilterHelperProvider } from '@core/filter/providers/helper'; import { CoreFilterHelperProvider } from '@core/filter/providers/helper';
import { CorePluginFileDelegate } from '@providers/plugin-file-delegate';
/** /**
* Handler to prefetch pages. * Handler to prefetch pages.
@ -43,10 +44,12 @@ export class AddonModPagePrefetchHandler extends CoreCourseResourcePrefetchHandl
sitesProvider: CoreSitesProvider, sitesProvider: CoreSitesProvider,
domUtils: CoreDomUtilsProvider, domUtils: CoreDomUtilsProvider,
filterHelper: CoreFilterHelperProvider, filterHelper: CoreFilterHelperProvider,
pluginFileDelegate: CorePluginFileDelegate,
protected pageProvider: AddonModPageProvider, protected pageProvider: AddonModPageProvider,
protected pageHelper: AddonModPageHelperProvider) { protected pageHelper: AddonModPageHelperProvider) {
super(translate, appProvider, utils, courseProvider, filepoolProvider, sitesProvider, domUtils, filterHelper); super(translate, appProvider, utils, courseProvider, filepoolProvider, sitesProvider, domUtils, filterHelper,
pluginFileDelegate);
} }
/** /**

View File

@ -29,6 +29,7 @@ import { AddonModQuizAccessRuleDelegate } from './access-rules-delegate';
import { AddonModQuizSyncProvider } from './quiz-sync'; import { AddonModQuizSyncProvider } from './quiz-sync';
import { CoreConstants } from '@core/constants'; import { CoreConstants } from '@core/constants';
import { CoreFilterHelperProvider } from '@core/filter/providers/helper'; import { CoreFilterHelperProvider } from '@core/filter/providers/helper';
import { CorePluginFileDelegate } from '@providers/plugin-file-delegate';
/** /**
* Handler to prefetch quizzes. * Handler to prefetch quizzes.
@ -50,6 +51,7 @@ export class AddonModQuizPrefetchHandler extends CoreCourseActivityPrefetchHandl
sitesProvider: CoreSitesProvider, sitesProvider: CoreSitesProvider,
domUtils: CoreDomUtilsProvider, domUtils: CoreDomUtilsProvider,
filterHelper: CoreFilterHelperProvider, filterHelper: CoreFilterHelperProvider,
pluginFileDelegate: CorePluginFileDelegate,
protected injector: Injector, protected injector: Injector,
protected quizProvider: AddonModQuizProvider, protected quizProvider: AddonModQuizProvider,
protected textUtils: CoreTextUtilsProvider, protected textUtils: CoreTextUtilsProvider,
@ -57,7 +59,8 @@ export class AddonModQuizPrefetchHandler extends CoreCourseActivityPrefetchHandl
protected accessRuleDelegate: AddonModQuizAccessRuleDelegate, protected accessRuleDelegate: AddonModQuizAccessRuleDelegate,
protected questionHelper: CoreQuestionHelperProvider) { protected questionHelper: CoreQuestionHelperProvider) {
super(translate, appProvider, utils, courseProvider, filepoolProvider, sitesProvider, domUtils, filterHelper); super(translate, appProvider, utils, courseProvider, filepoolProvider, sitesProvider, domUtils, filterHelper,
pluginFileDelegate);
} }
/** /**

View File

@ -25,6 +25,7 @@ import { AddonModResourceProvider } from './resource';
import { AddonModResourceHelperProvider } from './helper'; import { AddonModResourceHelperProvider } from './helper';
import { CoreConstants } from '@core/constants'; import { CoreConstants } from '@core/constants';
import { CoreFilterHelperProvider } from '@core/filter/providers/helper'; import { CoreFilterHelperProvider } from '@core/filter/providers/helper';
import { CorePluginFileDelegate } from '@providers/plugin-file-delegate';
/** /**
* Handler to prefetch resources. * Handler to prefetch resources.
@ -43,10 +44,12 @@ export class AddonModResourcePrefetchHandler extends CoreCourseResourcePrefetchH
sitesProvider: CoreSitesProvider, sitesProvider: CoreSitesProvider,
domUtils: CoreDomUtilsProvider, domUtils: CoreDomUtilsProvider,
filterHelper: CoreFilterHelperProvider, filterHelper: CoreFilterHelperProvider,
pluginFileDelegate: CorePluginFileDelegate,
protected resourceProvider: AddonModResourceProvider, protected resourceProvider: AddonModResourceProvider,
protected resourceHelper: AddonModResourceHelperProvider) { protected resourceHelper: AddonModResourceHelperProvider) {
super(translate, appProvider, utils, courseProvider, filepoolProvider, sitesProvider, domUtils, filterHelper); super(translate, appProvider, utils, courseProvider, filepoolProvider, sitesProvider, domUtils, filterHelper,
pluginFileDelegate);
} }
/** /**

View File

@ -26,6 +26,7 @@ import { CoreCourseActivityPrefetchHandlerBase } from '@core/course/classes/acti
import { AddonModScormProvider } from './scorm'; import { AddonModScormProvider } from './scorm';
import { AddonModScormSyncProvider } from './scorm-sync'; import { AddonModScormSyncProvider } from './scorm-sync';
import { CoreFilterHelperProvider } from '@core/filter/providers/helper'; import { CoreFilterHelperProvider } from '@core/filter/providers/helper';
import { CorePluginFileDelegate } from '@providers/plugin-file-delegate';
/** /**
* Progress event used when downloading a SCORM. * Progress event used when downloading a SCORM.
@ -67,12 +68,14 @@ export class AddonModScormPrefetchHandler extends CoreCourseActivityPrefetchHand
sitesProvider: CoreSitesProvider, sitesProvider: CoreSitesProvider,
domUtils: CoreDomUtilsProvider, domUtils: CoreDomUtilsProvider,
filterHelper: CoreFilterHelperProvider, filterHelper: CoreFilterHelperProvider,
pluginFileDelegate: CorePluginFileDelegate,
protected fileProvider: CoreFileProvider, protected fileProvider: CoreFileProvider,
protected textUtils: CoreTextUtilsProvider, protected textUtils: CoreTextUtilsProvider,
protected scormProvider: AddonModScormProvider, protected scormProvider: AddonModScormProvider,
protected injector: Injector) { protected injector: Injector) {
super(translate, appProvider, utils, courseProvider, filepoolProvider, sitesProvider, domUtils, filterHelper); super(translate, appProvider, utils, courseProvider, filepoolProvider, sitesProvider, domUtils, filterHelper,
pluginFileDelegate);
} }
/** /**

View File

@ -25,6 +25,7 @@ import { AddonModSurveyProvider } from './survey';
import { AddonModSurveySyncProvider } from './sync'; import { AddonModSurveySyncProvider } from './sync';
import { AddonModSurveyHelperProvider } from './helper'; import { AddonModSurveyHelperProvider } from './helper';
import { CoreFilterHelperProvider } from '@core/filter/providers/helper'; import { CoreFilterHelperProvider } from '@core/filter/providers/helper';
import { CorePluginFileDelegate } from '@providers/plugin-file-delegate';
/** /**
* Handler to prefetch surveys. * Handler to prefetch surveys.
@ -46,11 +47,13 @@ export class AddonModSurveyPrefetchHandler extends CoreCourseActivityPrefetchHan
sitesProvider: CoreSitesProvider, sitesProvider: CoreSitesProvider,
domUtils: CoreDomUtilsProvider, domUtils: CoreDomUtilsProvider,
filterHelper: CoreFilterHelperProvider, filterHelper: CoreFilterHelperProvider,
pluginFileDelegate: CorePluginFileDelegate,
protected surveyProvider: AddonModSurveyProvider, protected surveyProvider: AddonModSurveyProvider,
protected surveyHelper: AddonModSurveyHelperProvider, protected surveyHelper: AddonModSurveyHelperProvider,
protected injector: Injector) { protected injector: Injector) {
super(translate, appProvider, utils, courseProvider, filepoolProvider, sitesProvider, domUtils, filterHelper); super(translate, appProvider, utils, courseProvider, filepoolProvider, sitesProvider, domUtils, filterHelper,
pluginFileDelegate);
} }
/** /**

View File

@ -23,6 +23,7 @@ import { CoreCourseProvider } from '@core/course/providers/course';
import { CoreCourseResourcePrefetchHandlerBase } from '@core/course/classes/resource-prefetch-handler'; import { CoreCourseResourcePrefetchHandlerBase } from '@core/course/classes/resource-prefetch-handler';
import { AddonModUrlProvider } from './url'; import { AddonModUrlProvider } from './url';
import { CoreFilterHelperProvider } from '@core/filter/providers/helper'; import { CoreFilterHelperProvider } from '@core/filter/providers/helper';
import { CorePluginFileDelegate } from '@providers/plugin-file-delegate';
/** /**
* Handler to prefetch URLs. URLs cannot be prefetched, but the handler will be used to invalidate some data on course PTR. * Handler to prefetch URLs. URLs cannot be prefetched, but the handler will be used to invalidate some data on course PTR.
@ -40,9 +41,11 @@ export class AddonModUrlPrefetchHandler extends CoreCourseResourcePrefetchHandle
filepoolProvider: CoreFilepoolProvider, filepoolProvider: CoreFilepoolProvider,
sitesProvider: CoreSitesProvider, sitesProvider: CoreSitesProvider,
domUtils: CoreDomUtilsProvider, domUtils: CoreDomUtilsProvider,
filterHelper: CoreFilterHelperProvider) { filterHelper: CoreFilterHelperProvider,
pluginFileDelegate: CorePluginFileDelegate) {
super(translate, appProvider, utils, courseProvider, filepoolProvider, sitesProvider, domUtils, filterHelper); super(translate, appProvider, utils, courseProvider, filepoolProvider, sitesProvider, domUtils, filterHelper,
pluginFileDelegate);
} }
/** /**

View File

@ -29,6 +29,7 @@ import { CoreUserProvider } from '@core/user/providers/user';
import { AddonModWikiProvider } from './wiki'; import { AddonModWikiProvider } from './wiki';
import { AddonModWikiSyncProvider } from './wiki-sync'; import { AddonModWikiSyncProvider } from './wiki-sync';
import { CoreFilterHelperProvider } from '@core/filter/providers/helper'; import { CoreFilterHelperProvider } from '@core/filter/providers/helper';
import { CorePluginFileDelegate } from '@providers/plugin-file-delegate';
/** /**
* Handler to prefetch wikis. * Handler to prefetch wikis.
@ -48,6 +49,7 @@ export class AddonModWikiPrefetchHandler extends CoreCourseActivityPrefetchHandl
sitesProvider: CoreSitesProvider, sitesProvider: CoreSitesProvider,
domUtils: CoreDomUtilsProvider, domUtils: CoreDomUtilsProvider,
filterHelper: CoreFilterHelperProvider, filterHelper: CoreFilterHelperProvider,
pluginFileDelegate: CorePluginFileDelegate,
protected wikiProvider: AddonModWikiProvider, protected wikiProvider: AddonModWikiProvider,
protected userProvider: CoreUserProvider, protected userProvider: CoreUserProvider,
protected textUtils: CoreTextUtilsProvider, protected textUtils: CoreTextUtilsProvider,
@ -56,7 +58,8 @@ export class AddonModWikiPrefetchHandler extends CoreCourseActivityPrefetchHandl
protected gradesHelper: CoreGradesHelperProvider, protected gradesHelper: CoreGradesHelperProvider,
protected syncProvider: AddonModWikiSyncProvider) { protected syncProvider: AddonModWikiSyncProvider) {
super(translate, appProvider, utils, courseProvider, filepoolProvider, sitesProvider, domUtils, filterHelper); super(translate, appProvider, utils, courseProvider, filepoolProvider, sitesProvider, domUtils, filterHelper,
pluginFileDelegate);
} }
/** /**
@ -96,7 +99,7 @@ export class AddonModWikiPrefetchHandler extends CoreCourseActivityPrefetchHandl
siteId = this.sitesProvider.getCurrentSiteId(); siteId = this.sitesProvider.getCurrentSiteId();
promises.push(this.getFiles(module, courseId, single, siteId).then((files) => { promises.push(this.getFiles(module, courseId, single, siteId).then((files) => {
return this.utils.sumFileSizes(files); return this.pluginFileDelegate.getFilesSize(files);
})); }));
promises.push(this.getAllPages(module, courseId, false, true, siteId).then((pages) => { promises.push(this.getAllPages(module, courseId, false, true, siteId).then((pages) => {

View File

@ -27,6 +27,7 @@ import { AddonModWorkshopProvider } from './workshop';
import { AddonModWorkshopSyncProvider } from './sync'; import { AddonModWorkshopSyncProvider } from './sync';
import { AddonModWorkshopHelperProvider } from './helper'; import { AddonModWorkshopHelperProvider } from './helper';
import { CoreFilterHelperProvider } from '@core/filter/providers/helper'; import { CoreFilterHelperProvider } from '@core/filter/providers/helper';
import { CorePluginFileDelegate } from '@providers/plugin-file-delegate';
/** /**
* Handler to prefetch workshops. * Handler to prefetch workshops.
@ -47,13 +48,15 @@ export class AddonModWorkshopPrefetchHandler extends CoreCourseActivityPrefetchH
sitesProvider: CoreSitesProvider, sitesProvider: CoreSitesProvider,
domUtils: CoreDomUtilsProvider, domUtils: CoreDomUtilsProvider,
filterHelper: CoreFilterHelperProvider, filterHelper: CoreFilterHelperProvider,
pluginFileDelegate: CorePluginFileDelegate,
private groupsProvider: CoreGroupsProvider, private groupsProvider: CoreGroupsProvider,
private userProvider: CoreUserProvider, private userProvider: CoreUserProvider,
private workshopProvider: AddonModWorkshopProvider, private workshopProvider: AddonModWorkshopProvider,
private workshopHelper: AddonModWorkshopHelperProvider, private workshopHelper: AddonModWorkshopHelperProvider,
private syncProvider: AddonModWorkshopSyncProvider) { private syncProvider: AddonModWorkshopSyncProvider) {
super(translate, appProvider, utils, courseProvider, filepoolProvider, sitesProvider, domUtils, filterHelper); super(translate, appProvider, utils, courseProvider, filepoolProvider, sitesProvider, domUtils, filterHelper,
pluginFileDelegate);
} }
/** /**

View File

@ -23,6 +23,7 @@ import { CoreMimetypeUtilsProvider } from '@providers/utils/mimetype';
import { CoreUtilsProvider } from '@providers/utils/utils'; import { CoreUtilsProvider } from '@providers/utils/utils';
import { CoreTextUtilsProvider } from '@providers/utils/text'; import { CoreTextUtilsProvider } from '@providers/utils/text';
import { CoreConstants } from '@core/constants'; import { CoreConstants } from '@core/constants';
import { CorePluginFileDelegate } from '@providers/plugin-file-delegate';
/** /**
* Component to handle a remote file. Shows the file name, icon (depending on mimetype) and a button * Component to handle a remote file. Shows the file name, icon (depending on mimetype) and a button
@ -56,10 +57,16 @@ export class CoreFileComponent implements OnInit, OnDestroy {
protected timemodified: number; protected timemodified: number;
protected observer; protected observer;
constructor(private sitesProvider: CoreSitesProvider, private utils: CoreUtilsProvider, private domUtils: CoreDomUtilsProvider, constructor(private sitesProvider: CoreSitesProvider,
private filepoolProvider: CoreFilepoolProvider, private appProvider: CoreAppProvider, private utils: CoreUtilsProvider,
private fileHelper: CoreFileHelperProvider, private mimeUtils: CoreMimetypeUtilsProvider, private domUtils: CoreDomUtilsProvider,
private eventsProvider: CoreEventsProvider, private textUtils: CoreTextUtilsProvider) { private filepoolProvider: CoreFilepoolProvider,
private appProvider: CoreAppProvider,
private fileHelper: CoreFileHelperProvider,
private mimeUtils: CoreMimetypeUtilsProvider,
private eventsProvider: CoreEventsProvider,
private textUtils: CoreTextUtilsProvider,
private pluginFileDelegate: CorePluginFileDelegate) {
this.onDelete = new EventEmitter(); this.onDelete = new EventEmitter();
} }
@ -141,8 +148,6 @@ export class CoreFileComponent implements OnInit, OnDestroy {
e && e.preventDefault(); e && e.preventDefault();
e && e.stopPropagation(); e && e.stopPropagation();
let promise;
if (this.isDownloading && !openAfterDownload) { if (this.isDownloading && !openAfterDownload) {
return; return;
} }
@ -177,20 +182,26 @@ export class CoreFileComponent implements OnInit, OnDestroy {
}); });
} else { } else {
// File doesn't need to be opened (it's a prefetch). Show confirm modal if file size is defined and it's big. // File doesn't need to be opened (it's a prefetch). Show confirm modal if file size is defined and it's big.
promise = this.fileSize ? this.domUtils.confirmDownloadSize({ size: this.fileSize, total: true }) : Promise.resolve(); this.pluginFileDelegate.getFileSize({fileurl: this.fileUrl, filesize: this.fileSize}, this.siteId).then((size) => {
promise.then(() => {
// User confirmed, add the file to queue.
return this.filepoolProvider.invalidateFileByUrl(this.siteId, this.fileUrl).finally(() => {
this.isDownloading = true;
this.filepoolProvider.addToQueueByUrl(this.siteId, this.fileUrl, this.component, const promise = size ? this.domUtils.confirmDownloadSize({ size: size, total: true }) : Promise.resolve();
this.componentId, this.timemodified, undefined, undefined, 0, this.file).catch((error) => {
this.domUtils.showErrorModalDefault(error, 'core.errordownloading', true); return promise.then(() => {
this.calculateState(); // User confirmed, add the file to queue.
}); return this.filepoolProvider.invalidateFileByUrl(this.siteId, this.fileUrl).finally(() => {
this.isDownloading = true;
this.filepoolProvider.addToQueueByUrl(this.siteId, this.fileUrl, this.component,
this.componentId, this.timemodified, undefined, undefined, 0, this.file).catch((error) => {
this.domUtils.showErrorModalDefault(error, 'core.errordownloading', true);
this.calculateState();
});
});
}).catch(() => {
// User cancelled.
}); });
}).catch(() => { }).catch((error) => {
// Ignore error. this.domUtils.showErrorModalDefault(error, 'core.errordownloading', true);
}); });
} }
} }

View File

@ -21,6 +21,7 @@ import { CoreUtilsProvider } from '@providers/utils/utils';
import { CoreCourseProvider } from '../providers/course'; import { CoreCourseProvider } from '../providers/course';
import { CoreCourseModulePrefetchHandler } from '../providers/module-prefetch-delegate'; import { CoreCourseModulePrefetchHandler } from '../providers/module-prefetch-delegate';
import { CoreFilterHelperProvider } from '@core/filter/providers/helper'; import { CoreFilterHelperProvider } from '@core/filter/providers/helper';
import { CorePluginFileDelegate } from '@providers/plugin-file-delegate';
/** /**
* Base prefetch handler to be registered in CoreCourseModulePrefetchDelegate. Prefetch handlers should inherit either * Base prefetch handler to be registered in CoreCourseModulePrefetchDelegate. Prefetch handlers should inherit either
@ -67,7 +68,8 @@ export class CoreCourseModulePrefetchHandlerBase implements CoreCourseModulePref
protected filepoolProvider: CoreFilepoolProvider, protected filepoolProvider: CoreFilepoolProvider,
protected sitesProvider: CoreSitesProvider, protected sitesProvider: CoreSitesProvider,
protected domUtils: CoreDomUtilsProvider, protected domUtils: CoreDomUtilsProvider,
protected filterHelper: CoreFilterHelperProvider) { } protected filterHelper: CoreFilterHelperProvider,
protected pluginFileDelegate: CorePluginFileDelegate) { }
/** /**
* Add an ongoing download to the downloadPromises list. When the promise finishes it will be removed. * Add an ongoing download to the downloadPromises list. When the promise finishes it will be removed.
@ -137,7 +139,7 @@ export class CoreCourseModulePrefetchHandlerBase implements CoreCourseModulePref
*/ */
getDownloadSize(module: any, courseId: number, single?: boolean): Promise<{ size: number, total: boolean }> { getDownloadSize(module: any, courseId: number, single?: boolean): Promise<{ size: number, total: boolean }> {
return this.getFiles(module, courseId).then((files) => { return this.getFiles(module, courseId).then((files) => {
return this.utils.sumFileSizes(files); return this.pluginFileDelegate.getFilesSize(files);
}).catch(() => { }).catch(() => {
return { size: -1, total: false }; return { size: -1, total: false };
}); });

View File

@ -51,11 +51,14 @@ export class CoreFilterDefaultHandler implements CoreFilterHandler {
* @param filter The filter. * @param filter The filter.
* @param options Options passed to the filters. * @param options Options passed to the filters.
* @param viewContainerRef The ViewContainerRef where the container is. * @param viewContainerRef The ViewContainerRef where the container is.
* @param component Component.
* @param componentId Component ID.
* @param siteId Site ID. If not defined, current site. * @param siteId Site ID. If not defined, current site.
* @return If async, promise resolved when done. * @return If async, promise resolved when done.
*/ */
handleHtml(container: HTMLElement, filter: CoreFilterFilter, options: CoreFilterFormatTextOptions, handleHtml(container: HTMLElement, filter: CoreFilterFilter, options: CoreFilterFormatTextOptions,
viewContainerRef: ViewContainerRef, siteId?: string): void | Promise<void> { viewContainerRef: ViewContainerRef, component?: string, componentId?: string | number, siteId?: string)
: void | Promise<void> {
// To be overridden. // To be overridden.
} }

View File

@ -49,11 +49,14 @@ export interface CoreFilterHandler extends CoreDelegateHandler {
* @param filter The filter. * @param filter The filter.
* @param options Options passed to the filters. * @param options Options passed to the filters.
* @param viewContainerRef The ViewContainerRef where the container is. * @param viewContainerRef The ViewContainerRef where the container is.
* @param component Component.
* @param componentId Component ID.
* @param siteId Site ID. If not defined, current site. * @param siteId Site ID. If not defined, current site.
* @return If async, promise resolved when done. * @return If async, promise resolved when done.
*/ */
handleHtml?(container: HTMLElement, filter: CoreFilterFilter, options: CoreFilterFormatTextOptions, handleHtml?(container: HTMLElement, filter: CoreFilterFilter, options: CoreFilterFormatTextOptions,
viewContainerRef: ViewContainerRef, siteId?: string): void | Promise<void>; viewContainerRef: ViewContainerRef, component?: string, componentId?: string | number, siteId?: string)
: void | Promise<void>;
/** /**
* Check if the filter should be applied in a certain site based on some filter options. * Check if the filter should be applied in a certain site based on some filter options.
@ -160,11 +163,13 @@ export class CoreFilterDelegate extends CoreDelegate {
* @param viewContainerRef The ViewContainerRef where the container is. * @param viewContainerRef The ViewContainerRef where the container is.
* @param options Options passed to the filters. * @param options Options passed to the filters.
* @param skipFilters Names of filters that shouldn't be applied. * @param skipFilters Names of filters that shouldn't be applied.
* @param component Component.
* @param componentId Component ID.
* @param siteId Site ID. If not defined, current site. * @param siteId Site ID. If not defined, current site.
* @return Promise resolved when done. * @return Promise resolved when done.
*/ */
handleHtml(container: HTMLElement, filters: CoreFilterFilter[], viewContainerRef?: ViewContainerRef, options?: any, handleHtml(container: HTMLElement, filters: CoreFilterFilter[], viewContainerRef?: ViewContainerRef, options?: any,
skipFilters?: string[], siteId?: string): Promise<any> { skipFilters?: string[], component?: string, componentId?: string | number, siteId?: string): Promise<any> {
// Wait for filters to be initialized. // Wait for filters to be initialized.
return this.handlersInitPromise.then(() => { return this.handlersInitPromise.then(() => {
@ -184,7 +189,7 @@ export class CoreFilterDelegate extends CoreDelegate {
promise = promise.then(() => { promise = promise.then(() => {
return Promise.resolve(this.executeFunctionOnEnabled(filter.filter, 'handleHtml', return Promise.resolve(this.executeFunctionOnEnabled(filter.filter, 'handleHtml',
[container, filter, options, viewContainerRef, siteId])).catch((error) => { [container, filter, options, viewContainerRef, component, componentId, siteId])).catch((error) => {
this.logger.error('Error handling HTML' + filter.filter, error); this.logger.error('Error handling HTML' + filter.filter, error);
}); });
}); });

View File

@ -1,11 +1,9 @@
<div *ngIf="!showPackage" class="core-h5p-placeholder"> <div *ngIf="!showPackage" class="core-h5p-placeholder">
<button *ngIf="!loading && !errorMessage" class="core-h5p-placeholder-play-button" ion-button icon-only clear (click)="play($event)"> <button *ngIf="!loading" class="core-h5p-placeholder-play-button" ion-button icon-only clear (click)="play($event)">
<core-icon name="fa-play-circle"></core-icon> <core-icon name="fa-play-circle"></core-icon>
</button> </button>
<ion-spinner *ngIf="loading && !errorMessage" class="core-h5p-placeholder-spinner"></ion-spinner> <ion-spinner *ngIf="loading" class="core-h5p-placeholder-spinner"></ion-spinner>
<div *ngIf="errorMessage" class="core-h5p-placeholder-error">{{ errorMessage }}</div>
<div class="core-h5p-placeholder-download-container"> <div class="core-h5p-placeholder-download-container">
<core-download-refresh [status]="state" [enabled]="canDownload" [loading]="calculating" [canTrustDownload]="true" (action)="download()"></core-download-refresh> <core-download-refresh [status]="state" [enabled]="canDownload" [loading]="calculating" [canTrustDownload]="true" (action)="download()"></core-download-refresh>

View File

@ -42,13 +42,6 @@ ion-app.app-root core-h5p-player {
} }
} }
.core-h5p-placeholder-error {
position: absolute;
width: 100%;
text-align: center;
top: 50%;
}
ion-spinner circle { ion-spinner circle {
stroke: $core-h5p-placeholder-text-color; stroke: $core-h5p-placeholder-text-color;
} }

View File

@ -12,12 +12,17 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
import { Component, Input, ElementRef, OnInit, SimpleChange } from '@angular/core'; import { Component, Input, ElementRef, OnInit, OnDestroy, OnChanges, SimpleChange } from '@angular/core';
import { CoreAppProvider } from '@providers/app';
import { CoreEventsProvider } from '@providers/events';
import { CoreFilepoolProvider } from '@providers/filepool';
import { CoreSitesProvider } from '@providers/sites'; import { CoreSitesProvider } from '@providers/sites';
import { CoreDomUtilsProvider } from '@providers/utils/dom';
import { CoreTextUtilsProvider } from '@providers/utils/text'; import { CoreTextUtilsProvider } from '@providers/utils/text';
import { CoreUrlUtilsProvider } from '@providers/utils/url'; import { CoreUrlUtilsProvider } from '@providers/utils/url';
import { CoreUtilsProvider } from '@providers/utils/utils'; import { CoreUtilsProvider } from '@providers/utils/utils';
import { CoreH5PProvider } from '@core/h5p/providers/h5p'; import { CoreH5PProvider } from '@core/h5p/providers/h5p';
import { CorePluginFileDelegate } from '@providers/plugin-file-delegate';
/** /**
* Component to render an H5P package. * Component to render an H5P package.
@ -26,23 +31,38 @@ import { CoreH5PProvider } from '@core/h5p/providers/h5p';
selector: 'core-h5p-player', selector: 'core-h5p-player',
templateUrl: 'core-h5p-player.html' templateUrl: 'core-h5p-player.html'
}) })
export class CoreH5PPlayerComponent implements OnInit { export class CoreH5PPlayerComponent implements OnInit, OnChanges, OnDestroy {
@Input() src: string; // The URL of the player to display the H5P package. @Input() src: string; // The URL of the player to display the H5P package.
@Input() component?: string; // Component.
@Input() componentId?: string | number; // Component ID to use in conjunction with the component.
playerSrc: string; playerSrc: string;
showPackage = false; showPackage = false;
loading = false; loading = false;
status: string; state: string;
canDownload: boolean; canDownload: boolean;
calculating = true; calculating = true;
errorMessage: string;
protected siteId: string;
protected siteCanDownload: boolean;
protected observer;
protected urlParams;
constructor(public elementRef: ElementRef, constructor(public elementRef: ElementRef,
protected sitesProvider: CoreSitesProvider, protected sitesProvider: CoreSitesProvider,
protected urlUtils: CoreUrlUtilsProvider, protected urlUtils: CoreUrlUtilsProvider,
protected utils: CoreUtilsProvider, protected utils: CoreUtilsProvider,
protected textUtils: CoreTextUtilsProvider, protected textUtils: CoreTextUtilsProvider,
protected h5pProvider: CoreH5PProvider) { } protected h5pProvider: CoreH5PProvider,
protected filepoolProvider: CoreFilepoolProvider,
protected eventsProvider: CoreEventsProvider,
protected appProvider: CoreAppProvider,
protected domUtils: CoreDomUtilsProvider,
protected pluginFileDelegate: CorePluginFileDelegate) {
this.siteId = sitesProvider.getCurrentSiteId();
this.siteCanDownload = this.sitesProvider.getCurrentSite().canDownloadFiles();
}
/** /**
* Component being initialized. * Component being initialized.
@ -85,37 +105,49 @@ export class CoreH5PPlayerComponent implements OnInit {
/** /**
* Download the package. * Download the package.
*/ */
download(): void { download(e: Event): void {
// @TODO: Implement package download. e && e.preventDefault();
e && e.stopPropagation();
if (!this.appProvider.isOnline()) {
this.domUtils.showErrorModal('core.networkerrormsg', true);
return;
}
// Get the file size and ask the user to confirm.
this.pluginFileDelegate.getFileSize({fileurl: this.urlParams.url}, this.siteId).then((size) => {
return this.domUtils.confirmDownloadSize({ size: size, total: true }).then(() => {
// User confirmed, add to the queue.
return this.filepoolProvider.addToQueueByUrl(this.siteId, this.urlParams.url, this.component, this.componentId);
}, () => {
// User cancelled.
});
}).catch((error) => {
this.domUtils.showErrorModalDefault(error, 'core.errordownloading', true);
this.calculateState();
});
} }
/** /**
* Check if the package can be downloaded. * Check if the package can be downloaded.
*/ */
protected checkCanDownload(): void { protected checkCanDownload(): void {
if (this.src && this.h5pProvider.canGetTrustedH5PFileInSite()) { this.observer && this.observer.off();
const params = this.urlUtils.extractUrlParams(this.src); this.urlParams = this.urlUtils.extractUrlParams(this.src);
// @todo: Check if H5P offline is disabled in the site. if (this.src && this.siteCanDownload && this.h5pProvider.canGetTrustedH5PFileInSite()) {
// Now check if the package can be played.
this.calculating = true; this.calculating = true;
const options = { this.calculateState();
frame: this.utils.isTrueOrOne(params.frame),
export: this.utils.isTrueOrOne(params.export),
embed: this.utils.isTrueOrOne(params.embed),
copyright: this.utils.isTrueOrOne(params.copyright),
};
this.h5pProvider.getTrustedH5PFile(params.url, options).then((file) => { // Listen for changes in the state.
this.canDownload = true; this.filepoolProvider.getFileEventNameByUrl(this.siteId, this.urlParams.url).then((eventName) => {
this.errorMessage = undefined; this.observer = this.eventsProvider.on(eventName, () => {
}).catch((error) => { this.calculateState();
this.canDownload = false; });
this.errorMessage = this.textUtils.getErrorMessageFromError(error);
}).finally(() => {
this.calculating = false;
}); });
return; return;
@ -123,6 +155,29 @@ export class CoreH5PPlayerComponent implements OnInit {
this.calculating = false; this.calculating = false;
this.canDownload = false; this.canDownload = false;
this.errorMessage = undefined; }
/**
* Calcuñate state of the file.
*
* @param fileUrl The H5P file URL.
*/
protected calculateState(): void {
// Get the status of the file.
this.filepoolProvider.getFileStateByUrl(this.siteId, this.urlParams.url).then((state) => {
this.canDownload = true;
this.state = state;
}).catch((error) => {
this.canDownload = false;
}).finally(() => {
this.calculating = false;
});
}
/**
* Component destroyed.
*/
ngOnDestroy(): void {
this.observer && this.observer.off();
} }
} }

View File

@ -15,6 +15,8 @@
import { NgModule } from '@angular/core'; import { NgModule } from '@angular/core';
import { CoreH5PComponentsModule } from './components/components.module'; import { CoreH5PComponentsModule } from './components/components.module';
import { CoreH5PProvider } from './providers/h5p'; import { CoreH5PProvider } from './providers/h5p';
import { CoreH5PPluginFileHandler } from './providers/pluginfile-handler';
import { CorePluginFileDelegate } from '@providers/plugin-file-delegate';
// List of providers (without handlers). // List of providers (without handlers).
export const CORE_H5P_PROVIDERS: any[] = [ export const CORE_H5P_PROVIDERS: any[] = [
@ -27,8 +29,15 @@ export const CORE_H5P_PROVIDERS: any[] = [
CoreH5PComponentsModule CoreH5PComponentsModule
], ],
providers: [ providers: [
CoreH5PProvider CoreH5PProvider,
CoreH5PPluginFileHandler
], ],
exports: [] exports: []
}) })
export class CoreH5PModule { } export class CoreH5PModule {
constructor(pluginfileDelegate: CorePluginFileDelegate,
pluginfileHandler: CoreH5PPluginFileHandler) {
pluginfileDelegate.registerHandler(pluginfileHandler);
}
}

View File

@ -17,6 +17,7 @@ import { CoreLoggerProvider } from '@providers/logger';
import { CoreSitesProvider } from '@providers/sites'; import { CoreSitesProvider } from '@providers/sites';
import { CoreSite, CoreSiteWSPreSets } from '@classes/site'; import { CoreSite, CoreSiteWSPreSets } from '@classes/site';
import { CoreWSExternalWarning, CoreWSExternalFile } from '@providers/ws'; import { CoreWSExternalWarning, CoreWSExternalFile } from '@providers/ws';
import { CoreTextUtilsProvider } from '@providers/utils/text';
/** /**
* Service to provide H5P functionalities. * Service to provide H5P functionalities.
@ -29,7 +30,8 @@ export class CoreH5PProvider {
protected logger; protected logger;
constructor(logger: CoreLoggerProvider, constructor(logger: CoreLoggerProvider,
private sitesProvider: CoreSitesProvider) { private sitesProvider: CoreSitesProvider,
private textUtils: CoreTextUtilsProvider) {
this.logger = logger.getInstance('CoreFilterProvider'); this.logger = logger.getInstance('CoreFilterProvider');
} }
@ -69,13 +71,15 @@ export class CoreH5PProvider {
* @param siteId Site ID. If not defined, current site. * @param siteId Site ID. If not defined, current site.
* @return Promise resolved with the file data. * @return Promise resolved with the file data.
*/ */
getTrustedH5PFile(url: string, options: CoreH5PGetTrustedFileOptions, ignoreCache?: boolean, siteId?: string) getTrustedH5PFile(url: string, options?: CoreH5PGetTrustedFileOptions, ignoreCache?: boolean, siteId?: string)
: Promise<CoreWSExternalFile> { : Promise<CoreWSExternalFile> {
options = options || {};
return this.sitesProvider.getSite(siteId).then((site) => { return this.sitesProvider.getSite(siteId).then((site) => {
const data = { const data = {
url: url, url: this.treatH5PUrl(url, site.getURL()),
frame: options.frame ? 1 : 0, frame: options.frame ? 1 : 0,
export: options.export ? 1 : 0, export: options.export ? 1 : 0,
embed: options.embed ? 1 : 0, embed: options.embed ? 1 : 0,
@ -124,6 +128,21 @@ export class CoreH5PProvider {
return this.ROOT_CACHE_KEY + 'trustedH5PFile:'; return this.ROOT_CACHE_KEY + 'trustedH5PFile:';
} }
/**
* Treat an H5P url before sending it to WS.
*
* @param url H5P file URL.
* @param siteUrl Site URL.
* @return Treated url.
*/
protected treatH5PUrl(url: string, siteUrl: string): string {
if (url.indexOf(this.textUtils.concatenatePaths(siteUrl, '/webservice/pluginfile.php')) === 0) {
url = url.replace('/webservice/pluginfile', '/pluginfile');
}
return url;
}
/** /**
* Invalidates all trusted H5P file WS calls. * Invalidates all trusted H5P file WS calls.
* *

View File

@ -0,0 +1,121 @@
// (C) Copyright 2015 Moodle Pty Ltd.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
import { Injectable } from '@angular/core';
import { CoreFileProvider } from '@providers/file';
import { CorePluginFileHandler } from '@providers/plugin-file-delegate';
import { CoreMimetypeUtilsProvider } from '@providers/utils/mimetype';
import { CoreTextUtilsProvider } from '@providers/utils/text';
import { CoreUrlUtilsProvider } from '@providers/utils/url';
import { CoreUtilsProvider } from '@providers/utils/utils';
import { CoreH5PProvider } from './h5p';
import { CoreWSExternalFile } from '@providers/ws';
/**
* Handler to treat H5P files.
*/
@Injectable()
export class CoreH5PPluginFileHandler implements CorePluginFileHandler {
name = 'CoreH5PPluginFileHandler';
constructor(protected urlUtils: CoreUrlUtilsProvider,
protected mimeUtils: CoreMimetypeUtilsProvider,
protected textUtils: CoreTextUtilsProvider,
protected utils: CoreUtilsProvider,
protected fileProvider: CoreFileProvider,
protected h5pProvider: CoreH5PProvider) { }
/**
* Check whether a file can be downloaded. If so, return the file to download.
*
* @param file The file data.
* @param siteId Site ID. If not defined, current site.
* @return Promise resolved with the file to use. Rejected if cannot download.
*/
canDownloadFile(file: CoreWSExternalFile, siteId?: string): Promise<CoreWSExternalFile> {
return this.h5pProvider.getTrustedH5PFile(file.fileurl, {}, false, siteId);
}
/**
* Given an HTML element, get the URLs of the files that should be downloaded and weren't treated by
* CoreDomUtilsProvider.extractDownloadableFilesFromHtml.
*
* @param container Container where to get the URLs from.
* @return {string[]} List of URLs.
*/
getDownloadableFiles(container: HTMLElement): string[] {
const iframes = <HTMLIFrameElement[]> Array.from(container.querySelectorAll('iframe.h5p-iframe'));
const urls = [];
for (let i = 0; i < iframes.length; i++) {
const params = this.urlUtils.extractUrlParams(iframes[i].src);
if (params.url) {
urls.push(params.url);
}
}
return urls;
}
/**
* Get a file size.
*
* @param file The file data.
* @param siteId Site ID. If not defined, current site.
* @return Promise resolved with the size.
*/
getFileSize(file: CoreWSExternalFile, siteId?: string): Promise<number> {
return this.h5pProvider.getTrustedH5PFile(file.fileurl, {}, false, siteId).then((file) => {
return file.filesize;
}).catch((error): any => {
if (this.utils.isWebServiceError(error)) {
// WS returned an error, it means it cannot be downloaded.
return 0;
}
return Promise.reject(error);
});
}
/**
* Check whether the file should be treated by this handler. It is used in functions where the component isn't used.
*
* @param file The file data.
* @return Whether the file should be treated by this handler.
*/
shouldHandleFile(file: CoreWSExternalFile): boolean {
return this.mimeUtils.guessExtensionFromUrl(file.fileurl) == 'h5p';
}
/**
* Treat a downloaded file.
*
* @param fileUrl The file URL used to download the file.
* @param file The file entry of the downloaded file.
* @param siteId Site ID. If not defined, current site.
* @return Promise resolved when done.
*/
treatDownloadedFile(fileUrl: string, file: FileEntry, siteId?: string): Promise<any> {
// Unzip the file.
const destFolder = this.textUtils.concatenatePaths(CoreFileProvider.TMPFOLDER,
'h5p/' + this.mimeUtils.removeExtension(file.name));
return this.fileProvider.createDir(destFolder).then(() => {
return this.fileProvider.unzipFile(file.toURL(), destFolder);
}).then(() => {
// @todo: Deploy the package.
});
}
}

View File

@ -22,6 +22,7 @@ import { CoreCourseProvider } from '@core/course/providers/course';
import { CoreSitePluginsProvider } from '../../providers/siteplugins'; import { CoreSitePluginsProvider } from '../../providers/siteplugins';
import { CoreCourseActivityPrefetchHandlerBase } from '@core/course/classes/activity-prefetch-handler'; import { CoreCourseActivityPrefetchHandlerBase } from '@core/course/classes/activity-prefetch-handler';
import { CoreFilterHelperProvider } from '@core/filter/providers/helper'; import { CoreFilterHelperProvider } from '@core/filter/providers/helper';
import { CorePluginFileDelegate } from '@providers/plugin-file-delegate';
/** /**
* Handler to prefetch a module site plugin. * Handler to prefetch a module site plugin.
@ -39,13 +40,15 @@ export class CoreSitePluginsModulePrefetchHandler extends CoreCourseActivityPref
sitesProvider: CoreSitesProvider, sitesProvider: CoreSitesProvider,
domUtils: CoreDomUtilsProvider, domUtils: CoreDomUtilsProvider,
filterHelper: CoreFilterHelperProvider, filterHelper: CoreFilterHelperProvider,
pluginFileDelegate: CorePluginFileDelegate,
protected sitePluginsProvider: CoreSitePluginsProvider, protected sitePluginsProvider: CoreSitePluginsProvider,
component: string, component: string,
name: string, name: string,
modName: string, modName: string,
protected handlerSchema: any) { protected handlerSchema: any) {
super(translate, appProvider, utils, courseProvider, filepoolProvider, sitesProvider, domUtils, filterHelper); super(translate, appProvider, utils, courseProvider, filepoolProvider, sitesProvider, domUtils, filterHelper,
pluginFileDelegate);
this.component = component; this.component = component;
this.name = name; this.name = name;

View File

@ -32,6 +32,7 @@ import { CoreQuestionProvider } from '@core/question/providers/question';
import { CoreCourseProvider } from '@core/course/providers/course'; import { CoreCourseProvider } from '@core/course/providers/course';
import { CoreCoursesProvider } from '@core/courses/providers/courses'; import { CoreCoursesProvider } from '@core/courses/providers/courses';
import { CoreFilterHelperProvider } from '@core/filter/providers/helper'; import { CoreFilterHelperProvider } from '@core/filter/providers/helper';
import { CorePluginFileDelegate } from '@providers/plugin-file-delegate';
// Delegates // Delegates
import { CoreMainMenuDelegate } from '@core/mainmenu/providers/delegate'; import { CoreMainMenuDelegate } from '@core/mainmenu/providers/delegate';
@ -117,7 +118,8 @@ export class CoreSitePluginsHelperProvider {
private workshopAssessmentStrategyDelegate: AddonWorkshopAssessmentStrategyDelegate, private workshopAssessmentStrategyDelegate: AddonWorkshopAssessmentStrategyDelegate,
private courseProvider: CoreCourseProvider, private courseProvider: CoreCourseProvider,
private blockDelegate: CoreBlockDelegate, private blockDelegate: CoreBlockDelegate,
private filterHelper: CoreFilterHelperProvider) { private filterHelper: CoreFilterHelperProvider,
private pluginFileDelegate: CorePluginFileDelegate) {
this.logger = loggerProvider.getInstance('CoreSitePluginsHelperProvider'); this.logger = loggerProvider.getInstance('CoreSitePluginsHelperProvider');
@ -841,7 +843,7 @@ export class CoreSitePluginsHelperProvider {
// Register the prefetch handler. // Register the prefetch handler.
this.prefetchDelegate.registerHandler(new CoreSitePluginsModulePrefetchHandler(this.translate, this.appProvider, this.prefetchDelegate.registerHandler(new CoreSitePluginsModulePrefetchHandler(this.translate, this.appProvider,
this.utils, this.courseProvider, this.filepoolProvider, this.sitesProvider, this.domUtils, this.filterHelper, this.utils, this.courseProvider, this.filepoolProvider, this.sitesProvider, this.domUtils, this.filterHelper,
this.sitePluginsProvider, plugin.component, uniqueName, modName, handlerSchema)); this.pluginFileDelegate, this.sitePluginsProvider, plugin.component, uniqueName, modName, handlerSchema));
} }
return uniqueName; return uniqueName;

View File

@ -375,7 +375,7 @@ export class CoreFormatTextDirective implements OnChanges {
if (result.options.filter) { if (result.options.filter) {
// Let filters hnadle HTML. We do it here because we don't want them to block the render of the text. // Let filters hnadle HTML. We do it here because we don't want them to block the render of the text.
this.filterDelegate.handleHtml(this.element, result.filters, this.viewContainerRef, result.options, [], this.filterDelegate.handleHtml(this.element, result.filters, this.viewContainerRef, result.options, [],
result.siteId); this.component, this.componentId, result.siteId);
} }
this.element.classList.remove('core-disable-media-adapt'); this.element.classList.remove('core-disable-media-adapt');

View File

@ -21,7 +21,7 @@ import { CoreInitDelegate } from './init';
import { CoreLoggerProvider } from './logger'; import { CoreLoggerProvider } from './logger';
import { CorePluginFileDelegate } from './plugin-file-delegate'; import { CorePluginFileDelegate } from './plugin-file-delegate';
import { CoreSitesProvider, CoreSiteSchema } from './sites'; import { CoreSitesProvider, CoreSiteSchema } from './sites';
import { CoreWSProvider } from './ws'; import { CoreWSProvider, CoreWSExternalFile } from './ws';
import { CoreDomUtilsProvider } from './utils/dom'; import { CoreDomUtilsProvider } from './utils/dom';
import { CoreMimetypeUtilsProvider } from './utils/mimetype'; import { CoreMimetypeUtilsProvider } from './utils/mimetype';
import { CoreTextUtilsProvider } from './utils/text'; import { CoreTextUtilsProvider } from './utils/text';
@ -473,8 +473,8 @@ export class CoreFilepoolProvider {
* downloading a file automatically does this. Note that this method does not check if the file exists in the pool. * downloading a file automatically does this. Note that this method does not check if the file exists in the pool.
*/ */
addFileLinkByUrl(siteId: string, fileUrl: string, component: string, componentId?: string | number): Promise<any> { addFileLinkByUrl(siteId: string, fileUrl: string, component: string, componentId?: string | number): Promise<any> {
return this.fixPluginfileURL(siteId, fileUrl).then((fileUrl) => { return this.fixPluginfileURL(siteId, fileUrl).then((file) => {
const fileId = this.getFileIdByUrl(fileUrl); const fileId = this.getFileIdByUrl(file.fileurl);
return this.addFileLink(siteId, fileId, component, componentId); return this.addFileLink(siteId, fileId, component, componentId);
}); });
@ -605,11 +605,12 @@ export class CoreFilepoolProvider {
* @param priority The priority this file should get in the queue (range 0-999). * @param priority The priority this file should get in the queue (range 0-999).
* @param options Extra options (isexternalfile, repositorytype). * @param options Extra options (isexternalfile, repositorytype).
* @param revision File revision. If not defined, it will be calculated using the URL. * @param revision File revision. If not defined, it will be calculated using the URL.
* @param alreadyFixed Whether the URL has already been fixed.
* @return Resolved on success. * @return Resolved on success.
*/ */
addToQueueByUrl(siteId: string, fileUrl: string, component?: string, componentId?: string | number, timemodified: number = 0, addToQueueByUrl(siteId: string, fileUrl: string, component?: string, componentId?: string | number, timemodified: number = 0,
filePath?: string, onProgress?: (event: any) => any, priority: number = 0, options: any = {}, revision?: number) filePath?: string, onProgress?: (event: any) => any, priority: number = 0, options: any = {}, revision?: number,
: Promise<any> { alreadyFixed?: boolean): Promise<any> {
let fileId, let fileId,
link, link,
queueDeferred; queueDeferred;
@ -623,94 +624,102 @@ export class CoreFilepoolProvider {
return Promise.reject(null); return Promise.reject(null);
} }
return this.fixPluginfileURL(siteId, fileUrl).then((fileUrl) => { if (alreadyFixed) {
const primaryKey = { siteId: siteId, fileId: fileId }; // Already fixed, if we reached here it means it can be downloaded.
return <CoreWSExternalFile> {fileurl: fileUrl};
} else {
return this.fixPluginfileURL(siteId, fileUrl);
}
}).then((file) => {
revision = revision || this.getRevisionFromUrl(fileUrl); fileUrl = file.fileurl;
fileId = this.getFileIdByUrl(fileUrl); timemodified = file.timemodified || timemodified;
revision = revision || this.getRevisionFromUrl(fileUrl);
fileId = this.getFileIdByUrl(fileUrl);
// Set up the component. const primaryKey = { siteId: siteId, fileId: fileId };
if (typeof component != 'undefined') {
link = {
component: component,
componentId: this.fixComponentId(componentId)
};
}
// Retrieve the queue deferred now if it exists. // Set up the component.
// This is to prevent errors if file is removed from queue while we're checking if the file is in queue. if (typeof component != 'undefined') {
queueDeferred = this.getQueueDeferred(siteId, fileId, false, onProgress); link = {
component: component,
componentId: this.fixComponentId(componentId)
};
}
return this.hasFileInQueue(siteId, fileId).then((entry: CoreFilepoolQueueEntry) => { // Retrieve the queue deferred now if it exists.
const newData: any = {}; // This is to prevent errors if file is removed from queue while we're checking if the file is in queue.
let foundLink = false; queueDeferred = this.getQueueDeferred(siteId, fileId, false, onProgress);
if (entry) { return this.hasFileInQueue(siteId, fileId).then((entry: CoreFilepoolQueueEntry) => {
// We already have the file in queue, we update the priority and links. const newData: any = {};
if (entry.priority < priority) { let foundLink = false;
newData.priority = priority;
}
if (revision && entry.revision !== revision) {
newData.revision = revision;
}
if (timemodified && entry.timemodified !== timemodified) {
newData.timemodified = timemodified;
}
if (filePath && entry.path !== filePath) {
newData.path = filePath;
}
if (entry.isexternalfile !== options.isexternalfile && (entry.isexternalfile || options.isexternalfile)) {
newData.isexternalfile = options.isexternalfile;
}
if (entry.repositorytype !== options.repositorytype && (entry.repositorytype || options.repositorytype)) {
newData.repositorytype = options.repositorytype;
}
if (link) { if (entry) {
// We need to add the new link if it does not exist yet. // We already have the file in queue, we update the priority and links.
if (entry.links && entry.links.length) { if (entry.priority < priority) {
for (const i in entry.links) { newData.priority = priority;
const fileLink = entry.links[i]; }
if (fileLink.component == link.component && fileLink.componentId == link.componentId) { if (revision && entry.revision !== revision) {
foundLink = true; newData.revision = revision;
break; }
} if (timemodified && entry.timemodified !== timemodified) {
newData.timemodified = timemodified;
}
if (filePath && entry.path !== filePath) {
newData.path = filePath;
}
if (entry.isexternalfile !== options.isexternalfile && (entry.isexternalfile || options.isexternalfile)) {
newData.isexternalfile = options.isexternalfile;
}
if (entry.repositorytype !== options.repositorytype && (entry.repositorytype || options.repositorytype)) {
newData.repositorytype = options.repositorytype;
}
if (link) {
// We need to add the new link if it does not exist yet.
if (entry.links && entry.links.length) {
for (const i in entry.links) {
const fileLink = entry.links[i];
if (fileLink.component == link.component && fileLink.componentId == link.componentId) {
foundLink = true;
break;
} }
} }
if (!foundLink) {
newData.links = entry.links || [];
newData.links.push(link);
newData.links = JSON.stringify(entry.links);
}
} }
if (Object.keys(newData).length) { if (!foundLink) {
// Update only when required. newData.links = entry.links || [];
this.logger.debug(`Updating file ${fileId} which is already in queue`); newData.links.push(link);
newData.links = JSON.stringify(entry.links);
return this.appDB.updateRecords(this.QUEUE_TABLE, newData, primaryKey).then(() => {
return this.getQueuePromise(siteId, fileId, true, onProgress);
});
} }
this.logger.debug(`File ${fileId} already in queue and does not require update`);
if (queueDeferred) {
// If we were able to retrieve the queue deferred before, we use that one.
return queueDeferred.promise;
} else {
// Create a new deferred and return its promise.
return this.getQueuePromise(siteId, fileId, true, onProgress);
}
} else {
return this.addToQueue(
siteId, fileId, fileUrl, priority, revision, timemodified, filePath, onProgress, options, link);
} }
}, () => {
// Unsure why we could not get the record, let's add to the queue anyway. if (Object.keys(newData).length) {
// Update only when required.
this.logger.debug(`Updating file ${fileId} which is already in queue`);
return this.appDB.updateRecords(this.QUEUE_TABLE, newData, primaryKey).then(() => {
return this.getQueuePromise(siteId, fileId, true, onProgress);
});
}
this.logger.debug(`File ${fileId} already in queue and does not require update`);
if (queueDeferred) {
// If we were able to retrieve the queue deferred before, we use that one.
return queueDeferred.promise;
} else {
// Create a new deferred and return its promise.
return this.getQueuePromise(siteId, fileId, true, onProgress);
}
} else {
return this.addToQueue( return this.addToQueue(
siteId, fileId, fileUrl, priority, revision, timemodified, filePath, onProgress, options, link); siteId, fileId, fileUrl, priority, revision, timemodified, filePath, onProgress, options, link);
}); }
}, () => {
// Unsure why we could not get the record, let's add to the queue anyway.
return this.addToQueue(
siteId, fileId, fileUrl, priority, revision, timemodified, filePath, onProgress, options, link);
}); });
}); });
} }
@ -719,7 +728,7 @@ export class CoreFilepoolProvider {
* Adds a file to the queue if the size is allowed to be downloaded. * Adds a file to the queue if the size is allowed to be downloaded.
* *
* @param siteId The site ID. * @param siteId The site ID.
* @param fileUrl The absolute URL to the file. * @param fileUrl The absolute URL to the file, already fixed.
* @param component The component to link the file to. * @param component The component to link the file to.
* @param componentId An ID to use in conjunction with the component. * @param componentId An ID to use in conjunction with the component.
* @param timemodified The time this file was modified. * @param timemodified The time this file was modified.
@ -760,18 +769,18 @@ export class CoreFilepoolProvider {
// Check if the file should be downloaded. // Check if the file should be downloaded.
if (sizeUnknown) { if (sizeUnknown) {
if (downloadUnknown && isWifi) { if (downloadUnknown && isWifi) {
return this.addToQueueByUrl( return this.addToQueueByUrl(siteId, fileUrl, component, componentId, timemodified, undefined, undefined,
siteId, fileUrl, component, componentId, timemodified, undefined, undefined, 0, options, revision); 0, options, revision, true);
} }
} else if (size <= this.DOWNLOAD_THRESHOLD || (isWifi && size <= this.WIFI_DOWNLOAD_THRESHOLD)) { } else if (size <= this.DOWNLOAD_THRESHOLD || (isWifi && size <= this.WIFI_DOWNLOAD_THRESHOLD)) {
return this.addToQueueByUrl( return this.addToQueueByUrl(siteId, fileUrl, component, componentId, timemodified, undefined, undefined, 0,
siteId, fileUrl, component, componentId, timemodified, undefined, undefined, 0, options, revision); options, revision, true);
} }
}); });
} else { } else {
// No need to check size, just add it to the queue. // No need to check size, just add it to the queue.
return this.addToQueueByUrl(siteId, fileUrl, component, componentId, timemodified, undefined, undefined, 0, options, return this.addToQueueByUrl(siteId, fileUrl, component, componentId, timemodified, undefined, undefined, 0, options,
revision); revision, true);
} }
} }
@ -938,7 +947,13 @@ export class CoreFilepoolProvider {
return Promise.reject(null); return Promise.reject(null);
} }
return this.wsProvider.downloadFile(fileUrl, filePath, addExtension, onProgress).then((fileEntry) => { let fileEntry;
return this.wsProvider.downloadFile(fileUrl, filePath, addExtension, onProgress).then((entry) => {
fileEntry = entry;
return this.pluginFileDelegate.treatDownloadedFile(fileUrl, fileEntry, siteId);
}).then(() => {
const data: CoreFilepoolFileEntry = poolFileObject || {}; const data: CoreFilepoolFileEntry = poolFileObject || {};
data.downloadTime = Date.now(); data.downloadTime = Date.now();
@ -1157,8 +1172,10 @@ export class CoreFilepoolProvider {
promise; promise;
if (this.fileProvider.isAvailable()) { if (this.fileProvider.isAvailable()) {
return this.fixPluginfileURL(siteId, fileUrl).then((fixedUrl) => { return this.fixPluginfileURL(siteId, fileUrl).then((file) => {
fileUrl = fixedUrl;
fileUrl = file.fileurl;
timemodified = file.timemodified || timemodified;
options = Object.assign({}, options); // Create a copy to prevent modifying the original object. options = Object.assign({}, options); // Create a copy to prevent modifying the original object.
options.timemodified = timemodified || 0; options.timemodified = timemodified || 0;
@ -1313,15 +1330,24 @@ export class CoreFilepoolProvider {
} }
/** /**
* Add the wstoken url and points to the correct script. * Check whether the file can be downloaded, add the wstoken url and points to the correct script.
* *
* @param siteId The site ID. * @param siteId The site ID.
* @param fileUrl The file URL. * @param fileUrl The file URL.
* @return Resolved with fixed URL on success, rejected otherwise. * @param timemodified The timemodified of the file.
* @return Promise resolved with the file data to use.
*/ */
protected fixPluginfileURL(siteId: string, fileUrl: string): Promise<string> { protected fixPluginfileURL(siteId: string, fileUrl: string, timemodified: number = 0): Promise<CoreWSExternalFile> {
return this.sitesProvider.getSite(siteId).then((site) => {
return site.checkAndFixPluginfileURL(fileUrl); return this.pluginFileDelegate.canDownloadFile({fileurl: fileUrl, timemodified: timemodified}).then((file) => {
return this.sitesProvider.getSite(siteId).then((site) => {
return site.checkAndFixPluginfileURL(file.fileurl);
}).then((fixedUrl) => {
file.fileurl = fixedUrl;
return file;
});
}); });
} }
@ -1351,8 +1377,8 @@ export class CoreFilepoolProvider {
*/ */
getDirectoryUrlByUrl(siteId: string, fileUrl: string): Promise<string> { getDirectoryUrlByUrl(siteId: string, fileUrl: string): Promise<string> {
if (this.fileProvider.isAvailable()) { if (this.fileProvider.isAvailable()) {
return this.fixPluginfileURL(siteId, fileUrl).then((fileUrl) => { return this.fixPluginfileURL(siteId, fileUrl).then((file) => {
const fileId = this.getFileIdByUrl(fileUrl), const fileId = this.getFileIdByUrl(file.fileurl),
filePath = <string> this.getFilePath(siteId, fileId, ''); // No extension, the function will return a string. filePath = <string> this.getFilePath(siteId, fileId, ''); // No extension, the function will return a string.
return this.fileProvider.getDir(filePath).then((dirEntry) => { return this.fileProvider.getDir(filePath).then((dirEntry) => {
@ -1394,8 +1420,8 @@ export class CoreFilepoolProvider {
* @return Promise resolved with event name. * @return Promise resolved with event name.
*/ */
getFileEventNameByUrl(siteId: string, fileUrl: string): Promise<string> { getFileEventNameByUrl(siteId: string, fileUrl: string): Promise<string> {
return this.fixPluginfileURL(siteId, fileUrl).then((fileUrl) => { return this.fixPluginfileURL(siteId, fileUrl).then((file) => {
const fileId = this.getFileIdByUrl(fileUrl); const fileId = this.getFileIdByUrl(file.fileurl);
return this.getFileEventName(siteId, fileId); return this.getFileEventName(siteId, fileId);
}); });
@ -1490,8 +1516,8 @@ export class CoreFilepoolProvider {
* @return Promise resolved with the path to the file relative to storage root. * @return Promise resolved with the path to the file relative to storage root.
*/ */
getFilePathByUrl(siteId: string, fileUrl: string): Promise<string> { getFilePathByUrl(siteId: string, fileUrl: string): Promise<string> {
return this.fixPluginfileURL(siteId, fileUrl).then((fileUrl) => { return this.fixPluginfileURL(siteId, fileUrl).then((file) => {
const fileId = this.getFileIdByUrl(fileUrl); const fileId = this.getFileIdByUrl(file.fileurl);
return this.getFilePath(siteId, fileId); return this.getFilePath(siteId, fileId);
}); });
@ -1587,8 +1613,10 @@ export class CoreFilepoolProvider {
: Promise<string> { : Promise<string> {
let fileId; let fileId;
return this.fixPluginfileURL(siteId, fileUrl).then((fixedUrl) => { return this.fixPluginfileURL(siteId, fileUrl, timemodified).then((file) => {
fileUrl = fixedUrl;
fileUrl = file.fileurl;
timemodified = file.timemodified || timemodified;
revision = revision || this.getRevisionFromUrl(fileUrl); revision = revision || this.getRevisionFromUrl(fileUrl);
fileId = this.getFileIdByUrl(fileUrl); fileId = this.getFileIdByUrl(fileUrl);
@ -1618,6 +1646,8 @@ export class CoreFilepoolProvider {
}); });
}); });
}); });
}, () => {
return CoreConstants.NOT_DOWNLOADABLE;
}); });
} }
@ -1655,8 +1685,10 @@ export class CoreFilepoolProvider {
}); });
}; };
return this.fixPluginfileURL(siteId, fileUrl).then((fixedUrl) => { return this.fixPluginfileURL(siteId, fileUrl, timemodified).then((file) => {
fileUrl = fixedUrl;
fileUrl = file.fileurl;
timemodified = file.timemodified || timemodified;
revision = revision || this.getRevisionFromUrl(fileUrl); revision = revision || this.getRevisionFromUrl(fileUrl);
fileId = this.getFileIdByUrl(fileUrl); fileId = this.getFileIdByUrl(fileUrl);
@ -1779,8 +1811,8 @@ export class CoreFilepoolProvider {
*/ */
getInternalUrlByUrl(siteId: string, fileUrl: string): Promise<string> { getInternalUrlByUrl(siteId: string, fileUrl: string): Promise<string> {
if (this.fileProvider.isAvailable()) { if (this.fileProvider.isAvailable()) {
return this.fixPluginfileURL(siteId, fileUrl).then((fileUrl) => { return this.fixPluginfileURL(siteId, fileUrl).then((file) => {
const fileId = this.getFileIdByUrl(fileUrl); const fileId = this.getFileIdByUrl(file.fileurl);
return this.getInternalUrlById(siteId, fileId); return this.getInternalUrlById(siteId, fileId);
}); });
@ -1843,8 +1875,8 @@ export class CoreFilepoolProvider {
* @return Promise resolved with the path of the package. * @return Promise resolved with the path of the package.
*/ */
getPackageDirPathByUrl(siteId: string, url: string): Promise<string> { getPackageDirPathByUrl(siteId: string, url: string): Promise<string> {
return this.fixPluginfileURL(siteId, url).then((fixedUrl) => { return this.fixPluginfileURL(siteId, url).then((file) => {
const dirName = this.getPackageDirNameByUrl(fixedUrl); const dirName = this.getPackageDirNameByUrl(file.fileurl);
return this.getFilePath(siteId, dirName, ''); return this.getFilePath(siteId, dirName, '');
}); });
@ -1859,8 +1891,8 @@ export class CoreFilepoolProvider {
*/ */
getPackageDirUrlByUrl(siteId: string, url: string): Promise<string> { getPackageDirUrlByUrl(siteId: string, url: string): Promise<string> {
if (this.fileProvider.isAvailable()) { if (this.fileProvider.isAvailable()) {
return this.fixPluginfileURL(siteId, url).then((fixedUrl) => { return this.fixPluginfileURL(siteId, url).then((file) => {
const dirName = this.getPackageDirNameByUrl(fixedUrl), const dirName = this.getPackageDirNameByUrl(file.fileurl),
dirPath = <string> this.getFilePath(siteId, dirName, ''); // No extension, the function will return a string. dirPath = <string> this.getFilePath(siteId, dirName, ''); // No extension, the function will return a string.
return this.fileProvider.getDir(dirPath).then((dirEntry) => { return this.fileProvider.getDir(dirPath).then((dirEntry) => {
@ -2270,8 +2302,8 @@ export class CoreFilepoolProvider {
* Please note that, if a file is stale, the user will be presented the stale file if there is no network access. * Please note that, if a file is stale, the user will be presented the stale file if there is no network access.
*/ */
invalidateFileByUrl(siteId: string, fileUrl: string): Promise<any> { invalidateFileByUrl(siteId: string, fileUrl: string): Promise<any> {
return this.fixPluginfileURL(siteId, fileUrl).then((fileUrl) => { return this.fixPluginfileURL(siteId, fileUrl).then((file) => {
const fileId = this.getFileIdByUrl(fileUrl); const fileId = this.getFileIdByUrl(file.fileurl);
return this.sitesProvider.getSiteDb(siteId).then((db) => { return this.sitesProvider.getSiteDb(siteId).then((db) => {
return db.updateRecords(this.FILES_TABLE, { stale: 1 }, { fileId: fileId }); return db.updateRecords(this.FILES_TABLE, { stale: 1 }, { fileId: fileId });
@ -2318,8 +2350,8 @@ export class CoreFilepoolProvider {
* @param Promise resolved if file is downloading, rejected otherwise. * @param Promise resolved if file is downloading, rejected otherwise.
*/ */
isFileDownloadingByUrl(siteId: string, fileUrl: string): Promise<any> { isFileDownloadingByUrl(siteId: string, fileUrl: string): Promise<any> {
return this.fixPluginfileURL(siteId, fileUrl).then((fileUrl) => { return this.fixPluginfileURL(siteId, fileUrl).then((file) => {
const fileId = this.getFileIdByUrl(fileUrl); const fileId = this.getFileIdByUrl(file.fileurl);
return this.hasFileInQueue(siteId, fileId); return this.hasFileInQueue(siteId, fileId);
}); });
@ -2667,8 +2699,8 @@ export class CoreFilepoolProvider {
* @return Resolved on success, rejected on failure. * @return Resolved on success, rejected on failure.
*/ */
removeFileByUrl(siteId: string, fileUrl: string): Promise<any> { removeFileByUrl(siteId: string, fileUrl: string): Promise<any> {
return this.fixPluginfileURL(siteId, fileUrl).then((fileUrl) => { return this.fixPluginfileURL(siteId, fileUrl).then((file) => {
const fileId = this.getFileIdByUrl(fileUrl); const fileId = this.getFileIdByUrl(file.fileurl);
return this.removeFileById(siteId, fileId); return this.removeFileById(siteId, fileId);
}); });

View File

@ -14,6 +14,7 @@
import { Injectable } from '@angular/core'; import { Injectable } from '@angular/core';
import { CoreLoggerProvider } from './logger'; import { CoreLoggerProvider } from './logger';
import { CoreWSExternalFile } from '@providers/ws';
/** /**
* Interface that all plugin file handlers must implement. * Interface that all plugin file handlers must implement.
@ -26,8 +27,9 @@ export interface CorePluginFileHandler {
/** /**
* The "component" of the handler. It should match the "component" of pluginfile URLs. * The "component" of the handler. It should match the "component" of pluginfile URLs.
* It is used to treat revision from URLs.
*/ */
component: string; component?: string;
/** /**
* Return the RegExp to match the revision on pluginfile URLs. * Return the RegExp to match the revision on pluginfile URLs.
@ -44,6 +46,51 @@ export interface CorePluginFileHandler {
* @return String to remove the revision on pluginfile url. * @return String to remove the revision on pluginfile url.
*/ */
getComponentRevisionReplace?(args: string[]): string; getComponentRevisionReplace?(args: string[]): string;
/**
* Check whether a file can be downloaded. If so, return the file to download.
*
* @param file The file data.
* @param siteId Site ID. If not defined, current site.
* @return Promise resolved with the file to use. Rejected if cannot download.
*/
canDownloadFile?(file: CoreWSExternalFile, siteId?: string): Promise<CoreWSExternalFile>;
/**
* Given an HTML element, get the URLs of the files that should be downloaded and weren't treated by
* CoreDomUtilsProvider.extractDownloadableFilesFromHtml.
*
* @param container Container where to get the URLs from.
* @return {string[]} List of URLs.
*/
getDownloadableFiles?(container: HTMLElement): string[];
/**
* Get a file size.
*
* @param file The file data.
* @param siteId Site ID. If not defined, current site.
* @return Promise resolved with the size.
*/
getFileSize?(file: CoreWSExternalFile, siteId?: string): Promise<number>;
/**
* Check whether the file should be treated by this handler. It is used in functions where the component isn't used.
*
* @param file The file data.
* @return Whether the file should be treated by this handler.
*/
shouldHandleFile?(file: CoreWSExternalFile): boolean;
/**
* Treat a downloaded file.
*
* @param fileUrl The file URL used to download the file.
* @param file The file entry of the downloaded file.
* @param siteId Site ID. If not defined, current site.
* @return Promise resolved when done.
*/
treatDownloadedFile?(fileUrl: string, file: FileEntry, siteId?: string): Promise<any>;
} }
/** /**
@ -58,6 +105,39 @@ export class CorePluginFileDelegate {
this.logger = logger.getInstance('CorePluginFileDelegate'); this.logger = logger.getInstance('CorePluginFileDelegate');
} }
/**
* Check whether a file can be downloaded. If so, return the file to download.
*
* @param file The file data.
* @param siteId Site ID. If not defined, current site.
* @return Promise resolved with the file to use. Rejected if cannot download.
*/
canDownloadFile(file: CoreWSExternalFile, siteId?: string): Promise<CoreWSExternalFile> {
const handler = this.getHandlerForFile(file);
return this.canHandlerDownloadFile(file, handler, siteId);
}
/**
* Check whether a file can be downloaded. If so, return the file to download.
*
* @param file The file data.
* @param handler The handler to use.
* @param siteId Site ID. If not defined, current site.
* @return Promise resolved with the file to use. Rejected if cannot download.
*/
protected canHandlerDownloadFile(file: CoreWSExternalFile, handler: CorePluginFileHandler, siteId?: string)
: Promise<CoreWSExternalFile> {
if (handler && handler.canDownloadFile) {
return handler.canDownloadFile(file, siteId).then((newFile) => {
return newFile || file;
});
}
return Promise.resolve(file);
}
/** /**
* Get the handler for a certain pluginfile url. * Get the handler for a certain pluginfile url.
* *
@ -85,6 +165,99 @@ export class CorePluginFileDelegate {
} }
} }
/**
* Given an HTML element, get the URLs of the files that should be downloaded and weren't treated by
* CoreDomUtilsProvider.extractDownloadableFilesFromHtml.
*
* @param container Container where to get the URLs from.
* @return List of URLs.
*/
getDownloadableFiles(container: HTMLElement): string[] {
let files = [];
for (const component in this.handlers) {
const handler = this.handlers[component];
if (handler && handler.getDownloadableFiles) {
files = files.concat(handler.getDownloadableFiles(container));
}
}
return files;
}
/**
* Sum the filesizes from a list of files checking if the size will be partial or totally calculated.
*
* @param files List of files to sum its filesize.
* @param siteId Site ID. If not defined, current site.
* @return Promise resolved with file size and a boolean to indicate if it is the total size or only partial.
*/
getFilesSize(files: CoreWSExternalFile[], siteId?: string): Promise<{ size: number, total: boolean }> {
const promises = [],
result = {
size: 0,
total: true
};
files.forEach((file) => {
promises.push(this.getFileSize(file, siteId).then((size) => {
if (typeof size == 'undefined') {
// We don't have the file size, cannot calculate its total size.
result.total = false;
} else {
result.size += size;
}
}));
});
return Promise.all(promises).then(() => {
return result;
});
}
/**
* Get a file size.
*
* @param file The file data.
* @param siteId Site ID. If not defined, current site.
* @return Promise resolved with the size.
*/
getFileSize(file: CoreWSExternalFile, siteId?: string): Promise<number> {
const handler = this.getHandlerForFile(file);
// First of all check if file can be downloaded.
return this.canHandlerDownloadFile(file, handler, siteId).then((canDownload) => {
if (!canDownload) {
return 0;
}
if (handler && handler.getFileSize) {
return handler.getFileSize(file, siteId).catch(() => {
return file.filesize;
});
}
return Promise.resolve(file.filesize);
});
}
/**
* Get a handler to treat a certain file.
*
* @param file File data.
* @return Handler.
*/
protected getHandlerForFile(file: CoreWSExternalFile): CorePluginFileHandler {
for (const component in this.handlers) {
const handler = this.handlers[component];
if (handler && handler.shouldHandleFile && handler.shouldHandleFile(file)) {
return handler;
}
}
}
/** /**
* Register a handler. * Register a handler.
* *
@ -92,14 +265,14 @@ export class CorePluginFileDelegate {
* @return True if registered successfully, false otherwise. * @return True if registered successfully, false otherwise.
*/ */
registerHandler(handler: CorePluginFileHandler): boolean { registerHandler(handler: CorePluginFileHandler): boolean {
if (typeof this.handlers[handler.component] !== 'undefined') { if (typeof this.handlers[handler.component || handler.name] !== 'undefined') {
this.logger.log(`Handler '${handler.component}' already registered`); this.logger.log(`Handler '${handler.component}' already registered`);
return false; return false;
} }
this.logger.log(`Registered handler '${handler.component}'`); this.logger.log(`Registered handler '${handler.component}'`);
this.handlers[handler.component] = handler; this.handlers[handler.component || handler.name] = handler;
return true; return true;
} }
@ -124,4 +297,22 @@ export class CorePluginFileDelegate {
return url; return url;
} }
/**
* Treat a downloaded file.
*
* @param fileUrl The file URL used to download the file.
* @param file The file entry of the downloaded file.
* @param siteId Site ID. If not defined, current site.
* @return Promise resolved when done.
*/
treatDownloadedFile(fileUrl: string, file: FileEntry, siteId?: string): Promise<any> {
const handler = this.getHandlerForFile({fileurl: fileUrl});
if (handler && handler.getFileSize) {
return handler.treatDownloadedFile(fileUrl, file, siteId);
}
return Promise.resolve();
}
} }

View File

@ -22,6 +22,7 @@ import { TranslateService } from '@ngx-translate/core';
import { CoreTextUtilsProvider } from './text'; import { CoreTextUtilsProvider } from './text';
import { CoreAppProvider } from '../app'; import { CoreAppProvider } from '../app';
import { CoreConfigProvider } from '../config'; import { CoreConfigProvider } from '../config';
import { CorePluginFileDelegate } from '../plugin-file-delegate';
import { CoreUrlUtilsProvider } from './url'; import { CoreUrlUtilsProvider } from './url';
import { CoreFileProvider } from '@providers/file'; import { CoreFileProvider } from '@providers/file';
import { CoreConstants } from '@core/constants'; import { CoreConstants } from '@core/constants';
@ -62,11 +63,20 @@ export class CoreDomUtilsProvider {
protected debugDisplay = false; // Whether to display debug messages. Store it in a variable to make it synchronous. protected debugDisplay = false; // Whether to display debug messages. Store it in a variable to make it synchronous.
protected displayedAlerts = {}; // To prevent duplicated alerts. protected displayedAlerts = {}; // To prevent duplicated alerts.
constructor(private translate: TranslateService, private loadingCtrl: LoadingController, private toastCtrl: ToastController, constructor(private translate: TranslateService,
private alertCtrl: AlertController, private textUtils: CoreTextUtilsProvider, private appProvider: CoreAppProvider, private loadingCtrl: LoadingController,
private platform: Platform, private configProvider: CoreConfigProvider, private urlUtils: CoreUrlUtilsProvider, private toastCtrl: ToastController,
private modalCtrl: ModalController, private sanitizer: DomSanitizer, private popoverCtrl: PopoverController, private alertCtrl: AlertController,
private fileProvider: CoreFileProvider) { private textUtils: CoreTextUtilsProvider,
private appProvider: CoreAppProvider,
private platform: Platform,
private configProvider: CoreConfigProvider,
private urlUtils: CoreUrlUtilsProvider,
private modalCtrl: ModalController,
private sanitizer: DomSanitizer,
private popoverCtrl: PopoverController,
private fileProvider: CoreFileProvider,
private pluginFileDelegate: CorePluginFileDelegate) {
// Check if debug messages should be displayed. // Check if debug messages should be displayed.
configProvider.get(CoreConstants.SETTINGS_DEBUG_DISPLAY, false).then((debugDisplay) => { configProvider.get(CoreConstants.SETTINGS_DEBUG_DISPLAY, false).then((debugDisplay) => {
@ -252,7 +262,7 @@ export class CoreDomUtilsProvider {
* @return List of file urls. * @return List of file urls.
*/ */
extractDownloadableFilesFromHtml(html: string): string[] { extractDownloadableFilesFromHtml(html: string): string[] {
const urls = []; let urls = [];
let elements; let elements;
const element = this.convertToElement(html); const element = this.convertToElement(html);
@ -275,6 +285,9 @@ export class CoreDomUtilsProvider {
} }
} }
// Now get other files from plugin file handlers.
urls = urls.concat(this.pluginFileDelegate.getDownloadableFiles(element));
return urls; return urls;
} }

View File

@ -1287,6 +1287,7 @@ export class CoreUtilsProvider {
* *
* @param files List of files to sum its filesize. * @param files List of files to sum its filesize.
* @return File size and a boolean to indicate if it is the total size or only partial. * @return File size and a boolean to indicate if it is the total size or only partial.
* @deprecated since 3.8.0. Use CorePluginFileDelegate.getFilesSize instead.
*/ */
sumFileSizes(files: any[]): { size: number, total: boolean } { sumFileSizes(files: any[]): { size: number, total: boolean } {
const result = { const result = {