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 options Options passed to the filters.
* @param viewContainerRef The ViewContainerRef where the container is.
* @param component Component.
* @param componentId Component ID.
* @param siteId Site ID. If not defined, current site.
* @return If async, promise resolved when done.
*/
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'));
@ -85,6 +88,8 @@ export class AddonFilterDisplayH5PHandler extends CoreFilterDefaultHandler {
componentRef = viewContainerRef.createComponent(factory);
componentRef.instance.src = url;
componentRef.instance.component = component;
componentRef.instance.componentId = componentId;
// Move the component to its right position.
placeholder.parentElement.replaceChild(componentRef.instance.elementRef.nativeElement, placeholder);

View File

@ -162,11 +162,14 @@ export class AddonFilterMathJaxLoaderHandler extends CoreFilterDefaultHandler {
* @param filter The filter.
* @param options Options passed to the filters.
* @param viewContainerRef The ViewContainerRef where the container is.
* @param component Component.
* @param componentId Component ID.
* @param siteId Site ID. If not defined, current site.
* @return If async, promise resolved when done.
*/
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(() => {
this.window.M.filter_mathjaxloader.typeset(container);

View File

@ -32,6 +32,7 @@ import { AddonModAssignSyncProvider } from './assign-sync';
import { AddonModAssignFeedbackDelegate } from './feedback-delegate';
import { AddonModAssignSubmissionDelegate } from './submission-delegate';
import { CoreFilterHelperProvider } from '@core/filter/providers/helper';
import { CorePluginFileDelegate } from '@providers/plugin-file-delegate';
/**
* Handler to prefetch assigns.
@ -51,6 +52,7 @@ export class AddonModAssignPrefetchHandler extends CoreCourseActivityPrefetchHan
sitesProvider: CoreSitesProvider,
domUtils: CoreDomUtilsProvider,
filterHelper: CoreFilterHelperProvider,
pluginFileDelegate: CorePluginFileDelegate,
protected assignProvider: AddonModAssignProvider,
protected textUtils: CoreTextUtilsProvider,
protected feedbackDelegate: AddonModAssignFeedbackDelegate,
@ -62,7 +64,8 @@ export class AddonModAssignPrefetchHandler extends CoreCourseActivityPrefetchHan
protected assignHelper: AddonModAssignHelperProvider,
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 { AddonModBookProvider } from './book';
import { CoreFilterHelperProvider } from '@core/filter/providers/helper';
import { CorePluginFileDelegate } from '@providers/plugin-file-delegate';
/**
* Handler to prefetch books.
@ -42,9 +43,11 @@ export class AddonModBookPrefetchHandler extends CoreCourseResourcePrefetchHandl
sitesProvider: CoreSitesProvider,
domUtils: CoreDomUtilsProvider,
filterHelper: CoreFilterHelperProvider,
pluginFileDelegate: CorePluginFileDelegate,
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 { AddonModChatProvider, AddonModChatChat } from './chat';
import { CoreFilterHelperProvider } from '@core/filter/providers/helper';
import { CorePluginFileDelegate } from '@providers/plugin-file-delegate';
/**
* Handler to prefetch chats.
@ -43,11 +44,13 @@ export class AddonModChatPrefetchHandler extends CoreCourseActivityPrefetchHandl
sitesProvider: CoreSitesProvider,
domUtils: CoreDomUtilsProvider,
filterHelper: CoreFilterHelperProvider,
pluginFileDelegate: CorePluginFileDelegate,
private groupsProvider: CoreGroupsProvider,
private userProvider: CoreUserProvider,
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 { AddonModChoiceProvider } from './choice';
import { CoreFilterHelperProvider } from '@core/filter/providers/helper';
import { CorePluginFileDelegate } from '@providers/plugin-file-delegate';
/**
* Handler to prefetch choices.
@ -46,11 +47,13 @@ export class AddonModChoicePrefetchHandler extends CoreCourseActivityPrefetchHan
sitesProvider: CoreSitesProvider,
domUtils: CoreDomUtilsProvider,
filterHelper: CoreFilterHelperProvider,
pluginFileDelegate: CorePluginFileDelegate,
protected choiceProvider: AddonModChoiceProvider,
protected userProvider: CoreUserProvider,
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 { AddonModDataHelperProvider } from './helper';
import { CoreFilterHelperProvider } from '@core/filter/providers/helper';
import { CorePluginFileDelegate } from '@providers/plugin-file-delegate';
/**
* Handler to prefetch databases.
@ -47,6 +48,7 @@ export class AddonModDataPrefetchHandler extends CoreCourseActivityPrefetchHandl
sitesProvider: CoreSitesProvider,
domUtils: CoreDomUtilsProvider,
filterHelper: CoreFilterHelperProvider,
pluginFileDelegate: CorePluginFileDelegate,
protected dataProvider: AddonModDataProvider,
protected timeUtils: CoreTimeUtilsProvider,
protected dataHelper: AddonModDataHelperProvider,
@ -54,7 +56,8 @@ export class AddonModDataPrefetchHandler extends CoreCourseActivityPrefetchHandl
protected commentsProvider: CoreCommentsProvider,
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 { AddonModFeedbackSyncProvider } from './sync';
import { CoreFilterHelperProvider } from '@core/filter/providers/helper';
import { CorePluginFileDelegate } from '@providers/plugin-file-delegate';
/**
* Handler to prefetch feedbacks.
@ -48,13 +49,15 @@ export class AddonModFeedbackPrefetchHandler extends CoreCourseActivityPrefetchH
sitesProvider: CoreSitesProvider,
domUtils: CoreDomUtilsProvider,
filterHelper: CoreFilterHelperProvider,
pluginFileDelegate: CorePluginFileDelegate,
protected feedbackProvider: AddonModFeedbackProvider,
protected feedbackHelper: AddonModFeedbackHelperProvider,
protected timeUtils: CoreTimeUtilsProvider,
protected groupsProvider: CoreGroupsProvider,
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 { AddonModFolderProvider } from './folder';
import { CoreFilterHelperProvider } from '@core/filter/providers/helper';
import { CorePluginFileDelegate } from '@providers/plugin-file-delegate';
/**
* Handler to prefetch folders.
@ -41,9 +42,11 @@ export class AddonModFolderPrefetchHandler extends CoreCourseResourcePrefetchHan
sitesProvider: CoreSitesProvider,
domUtils: CoreDomUtilsProvider,
filterHelper: CoreFilterHelperProvider,
pluginFileDelegate: CorePluginFileDelegate,
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 { AddonModForumSyncProvider } from './sync';
import { CoreFilterHelperProvider } from '@core/filter/providers/helper';
import { CorePluginFileDelegate } from '@providers/plugin-file-delegate';
/**
* Handler to prefetch forums.
@ -45,12 +46,14 @@ export class AddonModForumPrefetchHandler extends CoreCourseActivityPrefetchHand
sitesProvider: CoreSitesProvider,
domUtils: CoreDomUtilsProvider,
filterHelper: CoreFilterHelperProvider,
pluginFileDelegate: CorePluginFileDelegate,
private userProvider: CoreUserProvider,
private groupsProvider: CoreGroupsProvider,
private forumProvider: AddonModForumProvider,
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 { AddonModGlossarySyncProvider } from './sync';
import { CoreFilterHelperProvider } from '@core/filter/providers/helper';
import { CorePluginFileDelegate } from '@providers/plugin-file-delegate';
/**
* Handler to prefetch forums.
@ -44,11 +45,13 @@ export class AddonModGlossaryPrefetchHandler extends CoreCourseActivityPrefetchH
sitesProvider: CoreSitesProvider,
domUtils: CoreDomUtilsProvider,
filterHelper: CoreFilterHelperProvider,
pluginFileDelegate: CorePluginFileDelegate,
protected glossaryProvider: AddonModGlossaryProvider,
protected commentsProvider: CoreCommentsProvider,
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 { AddonModImscpProvider } from './imscp';
import { CoreFilterHelperProvider } from '@core/filter/providers/helper';
import { CorePluginFileDelegate } from '@providers/plugin-file-delegate';
/**
* Handler to prefetch IMSCPs.
@ -41,9 +42,11 @@ export class AddonModImscpPrefetchHandler extends CoreCourseResourcePrefetchHand
sitesProvider: CoreSitesProvider,
domUtils: CoreDomUtilsProvider,
filterHelper: CoreFilterHelperProvider,
pluginFileDelegate: CorePluginFileDelegate,
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 { AddonModLabelProvider } from './label';
import { CoreFilterHelperProvider } from '@core/filter/providers/helper';
import { CorePluginFileDelegate } from '@providers/plugin-file-delegate';
/**
* Handler to prefetch labels.
@ -43,9 +44,11 @@ export class AddonModLabelPrefetchHandler extends CoreCourseResourcePrefetchHand
sitesProvider: CoreSitesProvider,
domUtils: CoreDomUtilsProvider,
filterHelper: CoreFilterHelperProvider,
pluginFileDelegate: CorePluginFileDelegate,
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 { AddonModLessonSyncProvider } from './lesson-sync';
import { CoreFilterHelperProvider } from '@core/filter/providers/helper';
import { CorePluginFileDelegate } from '@providers/plugin-file-delegate';
/**
* Handler to prefetch lessons.
@ -48,12 +49,14 @@ export class AddonModLessonPrefetchHandler extends CoreCourseActivityPrefetchHan
sitesProvider: CoreSitesProvider,
domUtils: CoreDomUtilsProvider,
filterHelper: CoreFilterHelperProvider,
pluginFileDelegate: CorePluginFileDelegate,
protected modalCtrl: ModalController,
protected groupsProvider: CoreGroupsProvider,
protected lessonProvider: AddonModLessonProvider,
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 || [];
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.
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 { AddonModLtiProvider } from './lti';
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.
@ -41,9 +42,11 @@ export class AddonModLtiPrefetchHandler extends CoreCourseActivityPrefetchHandle
sitesProvider: CoreSitesProvider,
domUtils: CoreDomUtilsProvider,
filterHelper: CoreFilterHelperProvider,
pluginFileDelegate: CorePluginFileDelegate,
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 { AddonModPageHelperProvider } from './helper';
import { CoreFilterHelperProvider } from '@core/filter/providers/helper';
import { CorePluginFileDelegate } from '@providers/plugin-file-delegate';
/**
* Handler to prefetch pages.
@ -43,10 +44,12 @@ export class AddonModPagePrefetchHandler extends CoreCourseResourcePrefetchHandl
sitesProvider: CoreSitesProvider,
domUtils: CoreDomUtilsProvider,
filterHelper: CoreFilterHelperProvider,
pluginFileDelegate: CorePluginFileDelegate,
protected pageProvider: AddonModPageProvider,
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 { CoreConstants } from '@core/constants';
import { CoreFilterHelperProvider } from '@core/filter/providers/helper';
import { CorePluginFileDelegate } from '@providers/plugin-file-delegate';
/**
* Handler to prefetch quizzes.
@ -50,6 +51,7 @@ export class AddonModQuizPrefetchHandler extends CoreCourseActivityPrefetchHandl
sitesProvider: CoreSitesProvider,
domUtils: CoreDomUtilsProvider,
filterHelper: CoreFilterHelperProvider,
pluginFileDelegate: CorePluginFileDelegate,
protected injector: Injector,
protected quizProvider: AddonModQuizProvider,
protected textUtils: CoreTextUtilsProvider,
@ -57,7 +59,8 @@ export class AddonModQuizPrefetchHandler extends CoreCourseActivityPrefetchHandl
protected accessRuleDelegate: AddonModQuizAccessRuleDelegate,
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 { CoreConstants } from '@core/constants';
import { CoreFilterHelperProvider } from '@core/filter/providers/helper';
import { CorePluginFileDelegate } from '@providers/plugin-file-delegate';
/**
* Handler to prefetch resources.
@ -43,10 +44,12 @@ export class AddonModResourcePrefetchHandler extends CoreCourseResourcePrefetchH
sitesProvider: CoreSitesProvider,
domUtils: CoreDomUtilsProvider,
filterHelper: CoreFilterHelperProvider,
pluginFileDelegate: CorePluginFileDelegate,
protected resourceProvider: AddonModResourceProvider,
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 { AddonModScormSyncProvider } from './scorm-sync';
import { CoreFilterHelperProvider } from '@core/filter/providers/helper';
import { CorePluginFileDelegate } from '@providers/plugin-file-delegate';
/**
* Progress event used when downloading a SCORM.
@ -67,12 +68,14 @@ export class AddonModScormPrefetchHandler extends CoreCourseActivityPrefetchHand
sitesProvider: CoreSitesProvider,
domUtils: CoreDomUtilsProvider,
filterHelper: CoreFilterHelperProvider,
pluginFileDelegate: CorePluginFileDelegate,
protected fileProvider: CoreFileProvider,
protected textUtils: CoreTextUtilsProvider,
protected scormProvider: AddonModScormProvider,
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 { AddonModSurveyHelperProvider } from './helper';
import { CoreFilterHelperProvider } from '@core/filter/providers/helper';
import { CorePluginFileDelegate } from '@providers/plugin-file-delegate';
/**
* Handler to prefetch surveys.
@ -46,11 +47,13 @@ export class AddonModSurveyPrefetchHandler extends CoreCourseActivityPrefetchHan
sitesProvider: CoreSitesProvider,
domUtils: CoreDomUtilsProvider,
filterHelper: CoreFilterHelperProvider,
pluginFileDelegate: CorePluginFileDelegate,
protected surveyProvider: AddonModSurveyProvider,
protected surveyHelper: AddonModSurveyHelperProvider,
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 { AddonModUrlProvider } from './url';
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.
@ -40,9 +41,11 @@ export class AddonModUrlPrefetchHandler extends CoreCourseResourcePrefetchHandle
filepoolProvider: CoreFilepoolProvider,
sitesProvider: CoreSitesProvider,
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 { AddonModWikiSyncProvider } from './wiki-sync';
import { CoreFilterHelperProvider } from '@core/filter/providers/helper';
import { CorePluginFileDelegate } from '@providers/plugin-file-delegate';
/**
* Handler to prefetch wikis.
@ -48,6 +49,7 @@ export class AddonModWikiPrefetchHandler extends CoreCourseActivityPrefetchHandl
sitesProvider: CoreSitesProvider,
domUtils: CoreDomUtilsProvider,
filterHelper: CoreFilterHelperProvider,
pluginFileDelegate: CorePluginFileDelegate,
protected wikiProvider: AddonModWikiProvider,
protected userProvider: CoreUserProvider,
protected textUtils: CoreTextUtilsProvider,
@ -56,7 +58,8 @@ export class AddonModWikiPrefetchHandler extends CoreCourseActivityPrefetchHandl
protected gradesHelper: CoreGradesHelperProvider,
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();
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) => {

View File

@ -27,6 +27,7 @@ import { AddonModWorkshopProvider } from './workshop';
import { AddonModWorkshopSyncProvider } from './sync';
import { AddonModWorkshopHelperProvider } from './helper';
import { CoreFilterHelperProvider } from '@core/filter/providers/helper';
import { CorePluginFileDelegate } from '@providers/plugin-file-delegate';
/**
* Handler to prefetch workshops.
@ -47,13 +48,15 @@ export class AddonModWorkshopPrefetchHandler extends CoreCourseActivityPrefetchH
sitesProvider: CoreSitesProvider,
domUtils: CoreDomUtilsProvider,
filterHelper: CoreFilterHelperProvider,
pluginFileDelegate: CorePluginFileDelegate,
private groupsProvider: CoreGroupsProvider,
private userProvider: CoreUserProvider,
private workshopProvider: AddonModWorkshopProvider,
private workshopHelper: AddonModWorkshopHelperProvider,
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 { CoreTextUtilsProvider } from '@providers/utils/text';
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
@ -56,10 +57,16 @@ export class CoreFileComponent implements OnInit, OnDestroy {
protected timemodified: number;
protected observer;
constructor(private sitesProvider: CoreSitesProvider, private utils: CoreUtilsProvider, private domUtils: CoreDomUtilsProvider,
private filepoolProvider: CoreFilepoolProvider, private appProvider: CoreAppProvider,
private fileHelper: CoreFileHelperProvider, private mimeUtils: CoreMimetypeUtilsProvider,
private eventsProvider: CoreEventsProvider, private textUtils: CoreTextUtilsProvider) {
constructor(private sitesProvider: CoreSitesProvider,
private utils: CoreUtilsProvider,
private domUtils: CoreDomUtilsProvider,
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();
}
@ -141,8 +148,6 @@ export class CoreFileComponent implements OnInit, OnDestroy {
e && e.preventDefault();
e && e.stopPropagation();
let promise;
if (this.isDownloading && !openAfterDownload) {
return;
}
@ -177,20 +182,26 @@ export class CoreFileComponent implements OnInit, OnDestroy {
});
} else {
// 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();
promise.then(() => {
// User confirmed, add the file to queue.
return this.filepoolProvider.invalidateFileByUrl(this.siteId, this.fileUrl).finally(() => {
this.isDownloading = true;
this.pluginFileDelegate.getFileSize({fileurl: this.fileUrl, filesize: this.fileSize}, this.siteId).then((size) => {
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();
});
const promise = size ? this.domUtils.confirmDownloadSize({ size: size, total: true }) : Promise.resolve();
return 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,
this.componentId, this.timemodified, undefined, undefined, 0, this.file).catch((error) => {
this.domUtils.showErrorModalDefault(error, 'core.errordownloading', true);
this.calculateState();
});
});
}).catch(() => {
// User cancelled.
});
}).catch(() => {
// Ignore error.
}).catch((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 { CoreCourseModulePrefetchHandler } from '../providers/module-prefetch-delegate';
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
@ -67,7 +68,8 @@ export class CoreCourseModulePrefetchHandlerBase implements CoreCourseModulePref
protected filepoolProvider: CoreFilepoolProvider,
protected sitesProvider: CoreSitesProvider,
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.
@ -137,7 +139,7 @@ export class CoreCourseModulePrefetchHandlerBase implements CoreCourseModulePref
*/
getDownloadSize(module: any, courseId: number, single?: boolean): Promise<{ size: number, total: boolean }> {
return this.getFiles(module, courseId).then((files) => {
return this.utils.sumFileSizes(files);
return this.pluginFileDelegate.getFilesSize(files);
}).catch(() => {
return { size: -1, total: false };
});

View File

@ -51,11 +51,14 @@ export class CoreFilterDefaultHandler implements CoreFilterHandler {
* @param filter The filter.
* @param options Options passed to the filters.
* @param viewContainerRef The ViewContainerRef where the container is.
* @param component Component.
* @param componentId Component ID.
* @param siteId Site ID. If not defined, current site.
* @return If async, promise resolved when done.
*/
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.
}

View File

@ -49,11 +49,14 @@ export interface CoreFilterHandler extends CoreDelegateHandler {
* @param filter The filter.
* @param options Options passed to the filters.
* @param viewContainerRef The ViewContainerRef where the container is.
* @param component Component.
* @param componentId Component ID.
* @param siteId Site ID. If not defined, current site.
* @return If async, promise resolved when done.
*/
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.
@ -160,11 +163,13 @@ export class CoreFilterDelegate extends CoreDelegate {
* @param viewContainerRef The ViewContainerRef where the container is.
* @param options Options passed to the filters.
* @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.
* @return Promise resolved when done.
*/
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.
return this.handlersInitPromise.then(() => {
@ -184,7 +189,7 @@ export class CoreFilterDelegate extends CoreDelegate {
promise = promise.then(() => {
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);
});
});

View File

@ -1,11 +1,9 @@
<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>
</button>
<ion-spinner *ngIf="loading && !errorMessage" class="core-h5p-placeholder-spinner"></ion-spinner>
<div *ngIf="errorMessage" class="core-h5p-placeholder-error">{{ errorMessage }}</div>
<ion-spinner *ngIf="loading" class="core-h5p-placeholder-spinner"></ion-spinner>
<div class="core-h5p-placeholder-download-container">
<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 {
stroke: $core-h5p-placeholder-text-color;
}

View File

@ -12,12 +12,17 @@
// See the License for the specific language governing permissions and
// 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 { CoreDomUtilsProvider } from '@providers/utils/dom';
import { CoreTextUtilsProvider } from '@providers/utils/text';
import { CoreUrlUtilsProvider } from '@providers/utils/url';
import { CoreUtilsProvider } from '@providers/utils/utils';
import { CoreH5PProvider } from '@core/h5p/providers/h5p';
import { CorePluginFileDelegate } from '@providers/plugin-file-delegate';
/**
* Component to render an H5P package.
@ -26,23 +31,38 @@ import { CoreH5PProvider } from '@core/h5p/providers/h5p';
selector: 'core-h5p-player',
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() component?: string; // Component.
@Input() componentId?: string | number; // Component ID to use in conjunction with the component.
playerSrc: string;
showPackage = false;
loading = false;
status: string;
state: string;
canDownload: boolean;
calculating = true;
errorMessage: string;
protected siteId: string;
protected siteCanDownload: boolean;
protected observer;
protected urlParams;
constructor(public elementRef: ElementRef,
protected sitesProvider: CoreSitesProvider,
protected urlUtils: CoreUrlUtilsProvider,
protected utils: CoreUtilsProvider,
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.
@ -85,37 +105,49 @@ export class CoreH5PPlayerComponent implements OnInit {
/**
* Download the package.
*/
download(): void {
// @TODO: Implement package download.
download(e: Event): void {
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.
*/
protected checkCanDownload(): void {
if (this.src && this.h5pProvider.canGetTrustedH5PFileInSite()) {
const params = this.urlUtils.extractUrlParams(this.src);
this.observer && this.observer.off();
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;
const options = {
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.calculateState();
this.h5pProvider.getTrustedH5PFile(params.url, options).then((file) => {
this.canDownload = true;
this.errorMessage = undefined;
}).catch((error) => {
this.canDownload = false;
this.errorMessage = this.textUtils.getErrorMessageFromError(error);
}).finally(() => {
this.calculating = false;
// Listen for changes in the state.
this.filepoolProvider.getFileEventNameByUrl(this.siteId, this.urlParams.url).then((eventName) => {
this.observer = this.eventsProvider.on(eventName, () => {
this.calculateState();
});
});
return;
@ -123,6 +155,29 @@ export class CoreH5PPlayerComponent implements OnInit {
this.calculating = 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 { CoreH5PComponentsModule } from './components/components.module';
import { CoreH5PProvider } from './providers/h5p';
import { CoreH5PPluginFileHandler } from './providers/pluginfile-handler';
import { CorePluginFileDelegate } from '@providers/plugin-file-delegate';
// List of providers (without handlers).
export const CORE_H5P_PROVIDERS: any[] = [
@ -27,8 +29,15 @@ export const CORE_H5P_PROVIDERS: any[] = [
CoreH5PComponentsModule
],
providers: [
CoreH5PProvider
CoreH5PProvider,
CoreH5PPluginFileHandler
],
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 { CoreSite, CoreSiteWSPreSets } from '@classes/site';
import { CoreWSExternalWarning, CoreWSExternalFile } from '@providers/ws';
import { CoreTextUtilsProvider } from '@providers/utils/text';
/**
* Service to provide H5P functionalities.
@ -29,7 +30,8 @@ export class CoreH5PProvider {
protected logger;
constructor(logger: CoreLoggerProvider,
private sitesProvider: CoreSitesProvider) {
private sitesProvider: CoreSitesProvider,
private textUtils: CoreTextUtilsProvider) {
this.logger = logger.getInstance('CoreFilterProvider');
}
@ -69,13 +71,15 @@ export class CoreH5PProvider {
* @param siteId Site ID. If not defined, current site.
* @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> {
options = options || {};
return this.sitesProvider.getSite(siteId).then((site) => {
const data = {
url: url,
url: this.treatH5PUrl(url, site.getURL()),
frame: options.frame ? 1 : 0,
export: options.export ? 1 : 0,
embed: options.embed ? 1 : 0,
@ -124,6 +128,21 @@ export class CoreH5PProvider {
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.
*

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 { CoreCourseActivityPrefetchHandlerBase } from '@core/course/classes/activity-prefetch-handler';
import { CoreFilterHelperProvider } from '@core/filter/providers/helper';
import { CorePluginFileDelegate } from '@providers/plugin-file-delegate';
/**
* Handler to prefetch a module site plugin.
@ -39,13 +40,15 @@ export class CoreSitePluginsModulePrefetchHandler extends CoreCourseActivityPref
sitesProvider: CoreSitesProvider,
domUtils: CoreDomUtilsProvider,
filterHelper: CoreFilterHelperProvider,
pluginFileDelegate: CorePluginFileDelegate,
protected sitePluginsProvider: CoreSitePluginsProvider,
component: string,
name: string,
modName: string,
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.name = name;

View File

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

View File

@ -375,7 +375,7 @@ export class CoreFormatTextDirective implements OnChanges {
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.
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');

View File

@ -21,7 +21,7 @@ import { CoreInitDelegate } from './init';
import { CoreLoggerProvider } from './logger';
import { CorePluginFileDelegate } from './plugin-file-delegate';
import { CoreSitesProvider, CoreSiteSchema } from './sites';
import { CoreWSProvider } from './ws';
import { CoreWSProvider, CoreWSExternalFile } from './ws';
import { CoreDomUtilsProvider } from './utils/dom';
import { CoreMimetypeUtilsProvider } from './utils/mimetype';
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.
*/
addFileLinkByUrl(siteId: string, fileUrl: string, component: string, componentId?: string | number): Promise<any> {
return this.fixPluginfileURL(siteId, fileUrl).then((fileUrl) => {
const fileId = this.getFileIdByUrl(fileUrl);
return this.fixPluginfileURL(siteId, fileUrl).then((file) => {
const fileId = this.getFileIdByUrl(file.fileurl);
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 options Extra options (isexternalfile, repositorytype).
* @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.
*/
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)
: Promise<any> {
filePath?: string, onProgress?: (event: any) => any, priority: number = 0, options: any = {}, revision?: number,
alreadyFixed?: boolean): Promise<any> {
let fileId,
link,
queueDeferred;
@ -623,94 +624,102 @@ export class CoreFilepoolProvider {
return Promise.reject(null);
}
return this.fixPluginfileURL(siteId, fileUrl).then((fileUrl) => {
const primaryKey = { siteId: siteId, fileId: fileId };
if (alreadyFixed) {
// 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);
fileId = this.getFileIdByUrl(fileUrl);
fileUrl = file.fileurl;
timemodified = file.timemodified || timemodified;
revision = revision || this.getRevisionFromUrl(fileUrl);
fileId = this.getFileIdByUrl(fileUrl);
// Set up the component.
if (typeof component != 'undefined') {
link = {
component: component,
componentId: this.fixComponentId(componentId)
};
}
const primaryKey = { siteId: siteId, fileId: fileId };
// Retrieve the queue deferred now if it exists.
// This is to prevent errors if file is removed from queue while we're checking if the file is in queue.
queueDeferred = this.getQueueDeferred(siteId, fileId, false, onProgress);
// Set up the component.
if (typeof component != 'undefined') {
link = {
component: component,
componentId: this.fixComponentId(componentId)
};
}
return this.hasFileInQueue(siteId, fileId).then((entry: CoreFilepoolQueueEntry) => {
const newData: any = {};
let foundLink = false;
// Retrieve the queue deferred now if it exists.
// This is to prevent errors if file is removed from queue while we're checking if the file is in queue.
queueDeferred = this.getQueueDeferred(siteId, fileId, false, onProgress);
if (entry) {
// We already have the file in queue, we update the priority and links.
if (entry.priority < priority) {
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;
}
return this.hasFileInQueue(siteId, fileId).then((entry: CoreFilepoolQueueEntry) => {
const newData: any = {};
let foundLink = false;
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 (entry) {
// We already have the file in queue, we update the priority and links.
if (entry.priority < priority) {
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) {
// 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) {
// 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);
});
if (!foundLink) {
newData.links = entry.links || [];
newData.links.push(link);
newData.links = JSON.stringify(entry.links);
}
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(
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.
*
* @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 componentId An ID to use in conjunction with the component.
* @param timemodified The time this file was modified.
@ -760,18 +769,18 @@ export class CoreFilepoolProvider {
// Check if the file should be downloaded.
if (sizeUnknown) {
if (downloadUnknown && isWifi) {
return this.addToQueueByUrl(
siteId, fileUrl, component, componentId, timemodified, undefined, undefined, 0, options, revision);
return this.addToQueueByUrl(siteId, fileUrl, component, componentId, timemodified, undefined, undefined,
0, options, revision, true);
}
} else if (size <= this.DOWNLOAD_THRESHOLD || (isWifi && size <= this.WIFI_DOWNLOAD_THRESHOLD)) {
return this.addToQueueByUrl(
siteId, fileUrl, component, componentId, timemodified, undefined, undefined, 0, options, revision);
return this.addToQueueByUrl(siteId, fileUrl, component, componentId, timemodified, undefined, undefined, 0,
options, revision, true);
}
});
} else {
// No need to check size, just add it to the queue.
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 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 || {};
data.downloadTime = Date.now();
@ -1157,8 +1172,10 @@ export class CoreFilepoolProvider {
promise;
if (this.fileProvider.isAvailable()) {
return this.fixPluginfileURL(siteId, fileUrl).then((fixedUrl) => {
fileUrl = fixedUrl;
return this.fixPluginfileURL(siteId, fileUrl).then((file) => {
fileUrl = file.fileurl;
timemodified = file.timemodified || timemodified;
options = Object.assign({}, options); // Create a copy to prevent modifying the original object.
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 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> {
return this.sitesProvider.getSite(siteId).then((site) => {
return site.checkAndFixPluginfileURL(fileUrl);
protected fixPluginfileURL(siteId: string, fileUrl: string, timemodified: number = 0): Promise<CoreWSExternalFile> {
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> {
if (this.fileProvider.isAvailable()) {
return this.fixPluginfileURL(siteId, fileUrl).then((fileUrl) => {
const fileId = this.getFileIdByUrl(fileUrl),
return this.fixPluginfileURL(siteId, fileUrl).then((file) => {
const fileId = this.getFileIdByUrl(file.fileurl),
filePath = <string> this.getFilePath(siteId, fileId, ''); // No extension, the function will return a string.
return this.fileProvider.getDir(filePath).then((dirEntry) => {
@ -1394,8 +1420,8 @@ export class CoreFilepoolProvider {
* @return Promise resolved with event name.
*/
getFileEventNameByUrl(siteId: string, fileUrl: string): Promise<string> {
return this.fixPluginfileURL(siteId, fileUrl).then((fileUrl) => {
const fileId = this.getFileIdByUrl(fileUrl);
return this.fixPluginfileURL(siteId, fileUrl).then((file) => {
const fileId = this.getFileIdByUrl(file.fileurl);
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.
*/
getFilePathByUrl(siteId: string, fileUrl: string): Promise<string> {
return this.fixPluginfileURL(siteId, fileUrl).then((fileUrl) => {
const fileId = this.getFileIdByUrl(fileUrl);
return this.fixPluginfileURL(siteId, fileUrl).then((file) => {
const fileId = this.getFileIdByUrl(file.fileurl);
return this.getFilePath(siteId, fileId);
});
@ -1587,8 +1613,10 @@ export class CoreFilepoolProvider {
: Promise<string> {
let fileId;
return this.fixPluginfileURL(siteId, fileUrl).then((fixedUrl) => {
fileUrl = fixedUrl;
return this.fixPluginfileURL(siteId, fileUrl, timemodified).then((file) => {
fileUrl = file.fileurl;
timemodified = file.timemodified || timemodified;
revision = revision || this.getRevisionFromUrl(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) => {
fileUrl = fixedUrl;
return this.fixPluginfileURL(siteId, fileUrl, timemodified).then((file) => {
fileUrl = file.fileurl;
timemodified = file.timemodified || timemodified;
revision = revision || this.getRevisionFromUrl(fileUrl);
fileId = this.getFileIdByUrl(fileUrl);
@ -1779,8 +1811,8 @@ export class CoreFilepoolProvider {
*/
getInternalUrlByUrl(siteId: string, fileUrl: string): Promise<string> {
if (this.fileProvider.isAvailable()) {
return this.fixPluginfileURL(siteId, fileUrl).then((fileUrl) => {
const fileId = this.getFileIdByUrl(fileUrl);
return this.fixPluginfileURL(siteId, fileUrl).then((file) => {
const fileId = this.getFileIdByUrl(file.fileurl);
return this.getInternalUrlById(siteId, fileId);
});
@ -1843,8 +1875,8 @@ export class CoreFilepoolProvider {
* @return Promise resolved with the path of the package.
*/
getPackageDirPathByUrl(siteId: string, url: string): Promise<string> {
return this.fixPluginfileURL(siteId, url).then((fixedUrl) => {
const dirName = this.getPackageDirNameByUrl(fixedUrl);
return this.fixPluginfileURL(siteId, url).then((file) => {
const dirName = this.getPackageDirNameByUrl(file.fileurl);
return this.getFilePath(siteId, dirName, '');
});
@ -1859,8 +1891,8 @@ export class CoreFilepoolProvider {
*/
getPackageDirUrlByUrl(siteId: string, url: string): Promise<string> {
if (this.fileProvider.isAvailable()) {
return this.fixPluginfileURL(siteId, url).then((fixedUrl) => {
const dirName = this.getPackageDirNameByUrl(fixedUrl),
return this.fixPluginfileURL(siteId, url).then((file) => {
const dirName = this.getPackageDirNameByUrl(file.fileurl),
dirPath = <string> this.getFilePath(siteId, dirName, ''); // No extension, the function will return a string.
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.
*/
invalidateFileByUrl(siteId: string, fileUrl: string): Promise<any> {
return this.fixPluginfileURL(siteId, fileUrl).then((fileUrl) => {
const fileId = this.getFileIdByUrl(fileUrl);
return this.fixPluginfileURL(siteId, fileUrl).then((file) => {
const fileId = this.getFileIdByUrl(file.fileurl);
return this.sitesProvider.getSiteDb(siteId).then((db) => {
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.
*/
isFileDownloadingByUrl(siteId: string, fileUrl: string): Promise<any> {
return this.fixPluginfileURL(siteId, fileUrl).then((fileUrl) => {
const fileId = this.getFileIdByUrl(fileUrl);
return this.fixPluginfileURL(siteId, fileUrl).then((file) => {
const fileId = this.getFileIdByUrl(file.fileurl);
return this.hasFileInQueue(siteId, fileId);
});
@ -2667,8 +2699,8 @@ export class CoreFilepoolProvider {
* @return Resolved on success, rejected on failure.
*/
removeFileByUrl(siteId: string, fileUrl: string): Promise<any> {
return this.fixPluginfileURL(siteId, fileUrl).then((fileUrl) => {
const fileId = this.getFileIdByUrl(fileUrl);
return this.fixPluginfileURL(siteId, fileUrl).then((file) => {
const fileId = this.getFileIdByUrl(file.fileurl);
return this.removeFileById(siteId, fileId);
});

View File

@ -14,6 +14,7 @@
import { Injectable } from '@angular/core';
import { CoreLoggerProvider } from './logger';
import { CoreWSExternalFile } from '@providers/ws';
/**
* 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.
* It is used to treat revision from URLs.
*/
component: string;
component?: string;
/**
* 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.
*/
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');
}
/**
* 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.
*
@ -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.
*
@ -92,14 +265,14 @@ export class CorePluginFileDelegate {
* @return True if registered successfully, false otherwise.
*/
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`);
return false;
}
this.logger.log(`Registered handler '${handler.component}'`);
this.handlers[handler.component] = handler;
this.handlers[handler.component || handler.name] = handler;
return true;
}
@ -124,4 +297,22 @@ export class CorePluginFileDelegate {
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 { CoreAppProvider } from '../app';
import { CoreConfigProvider } from '../config';
import { CorePluginFileDelegate } from '../plugin-file-delegate';
import { CoreUrlUtilsProvider } from './url';
import { CoreFileProvider } from '@providers/file';
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 displayedAlerts = {}; // To prevent duplicated alerts.
constructor(private translate: TranslateService, private loadingCtrl: LoadingController, private toastCtrl: ToastController,
private alertCtrl: AlertController, 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) {
constructor(private translate: TranslateService,
private loadingCtrl: LoadingController,
private toastCtrl: ToastController,
private alertCtrl: AlertController,
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.
configProvider.get(CoreConstants.SETTINGS_DEBUG_DISPLAY, false).then((debugDisplay) => {
@ -252,7 +262,7 @@ export class CoreDomUtilsProvider {
* @return List of file urls.
*/
extractDownloadableFilesFromHtml(html: string): string[] {
const urls = [];
let urls = [];
let elements;
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;
}

View File

@ -1287,6 +1287,7 @@ export class CoreUtilsProvider {
*
* @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.
* @deprecated since 3.8.0. Use CorePluginFileDelegate.getFilesSize instead.
*/
sumFileSizes(files: any[]): { size: number, total: boolean } {
const result = {