MOBILE-2235 h5p: Support and use isEnabled function in file delegate

main
Dani Palou 2019-12-09 15:34:08 +01:00
parent 40fc0e2b00
commit e0849668e3
18 changed files with 160 additions and 70 deletions

View File

@ -47,4 +47,13 @@ export class AddonModFolderPluginFileHandler implements CorePluginFileHandler {
// Component + Filearea + Revision // Component + Filearea + Revision
return '/mod_folder/content/0/'; return '/mod_folder/content/0/';
} }
/**
* Whether or not the handler is enabled on a site level.
*
* @return Whether or not the handler is enabled on a site level.
*/
isEnabled(): boolean | Promise<boolean> {
return true;
}
} }

View File

@ -96,7 +96,7 @@ export class AddonModForumPrefetchHandler extends CoreCourseActivityPrefetchHand
if (getInlineFiles && post.messageinlinefiles && post.messageinlinefiles.length) { if (getInlineFiles && post.messageinlinefiles && post.messageinlinefiles.length) {
files = files.concat(post.messageinlinefiles); files = files.concat(post.messageinlinefiles);
} else if (post.message && !getInlineFiles) { } else if (post.message && !getInlineFiles) {
files = files.concat(this.domUtils.extractDownloadableFilesFromHtmlAsFakeFileObjects(post.message)); files = files.concat(this.filepoolProvider.extractDownloadableFilesFromHtmlAsFakeFileObjects(post.message));
} }
}); });

View File

@ -93,7 +93,7 @@ export class AddonModGlossaryPrefetchHandler extends CoreCourseActivityPrefetchH
if (getInlineFiles && entry.definitioninlinefiles && entry.definitioninlinefiles.length) { if (getInlineFiles && entry.definitioninlinefiles && entry.definitioninlinefiles.length) {
files = files.concat(entry.definitioninlinefiles); files = files.concat(entry.definitioninlinefiles);
} else if (entry.definition && !getInlineFiles) { } else if (entry.definition && !getInlineFiles) {
files = files.concat(this.domUtils.extractDownloadableFilesFromHtmlAsFakeFileObjects(entry.definition)); files = files.concat(this.filepoolProvider.extractDownloadableFilesFromHtmlAsFakeFileObjects(entry.definition));
} }
}); });

View File

@ -54,4 +54,13 @@ export class AddonModImscpPluginFileHandler implements CorePluginFileHandler {
// Component + Filearea + Revision // Component + Filearea + Revision
return '/mod_imscp/' + args[2] + '/0/'; return '/mod_imscp/' + args[2] + '/0/';
} }
/**
* Whether or not the handler is enabled on a site level.
*
* @return Whether or not the handler is enabled on a site level.
*/
isEnabled(): boolean | Promise<boolean> {
return true;
}
} }

View File

@ -419,7 +419,8 @@ export class AddonModLessonPrefetchHandler extends CoreCourseActivityPrefetchHan
return; return;
} }
answerPage.answerdata.answers.forEach((answer) => { answerPage.answerdata.answers.forEach((answer) => {
files.push(...this.domUtils.extractDownloadableFilesFromHtmlAsFakeFileObjects(answer[0])); files.push(...this.filepoolProvider.extractDownloadableFilesFromHtmlAsFakeFileObjects(
answer[0]));
}); });
}); });

View File

@ -47,4 +47,13 @@ export class AddonModPagePluginFileHandler implements CorePluginFileHandler {
// Component + Filearea + Revision // Component + Filearea + Revision
return '/mod_page/content/0/'; return '/mod_page/content/0/';
} }
/**
* Whether or not the handler is enabled on a site level.
*
* @return Whether or not the handler is enabled on a site level.
*/
isEnabled(): boolean | Promise<boolean> {
return true;
}
} }

View File

@ -126,7 +126,7 @@ export class AddonModQuizPrefetchHandler extends CoreCourseActivityPrefetchHandl
files = files.concat(feedback.feedbackinlinefiles); files = files.concat(feedback.feedbackinlinefiles);
} else if (feedback.feedbacktext && !getInlineFiles) { } else if (feedback.feedbacktext && !getInlineFiles) {
files = files.concat( files = files.concat(
this.domUtils.extractDownloadableFilesFromHtmlAsFakeFileObjects(feedback.feedbacktext)); this.filepoolProvider.extractDownloadableFilesFromHtmlAsFakeFileObjects(feedback.feedbacktext));
} }
})); }));
} }

View File

@ -47,4 +47,13 @@ export class AddonModResourcePluginFileHandler implements CorePluginFileHandler
// Component + Filearea + Revision // Component + Filearea + Revision
return '/mod_resource/content/0/'; return '/mod_resource/content/0/';
} }
/**
* Whether or not the handler is enabled on a site level.
*
* @return Whether or not the handler is enabled on a site level.
*/
isEnabled(): boolean | Promise<boolean> {
return true;
}
} }

View File

@ -47,4 +47,13 @@ export class AddonModScormPluginFileHandler implements CorePluginFileHandler {
// Component + Filearea + Revision // Component + Filearea + Revision
return '/mod_scorm/content/0/'; return '/mod_scorm/content/0/';
} }
/**
* Whether or not the handler is enabled on a site level.
*
* @return Whether or not the handler is enabled on a site level.
*/
isEnabled(): boolean | Promise<boolean> {
return true;
}
} }

View File

@ -237,14 +237,16 @@ export class CoreDelegate {
* @return True when registered, false if already registered. * @return True when registered, false if already registered.
*/ */
registerHandler(handler: CoreDelegateHandler): boolean { registerHandler(handler: CoreDelegateHandler): boolean {
if (typeof this.handlers[handler[this.handlerNameProperty]] !== 'undefined') { const key = handler[this.handlerNameProperty] || handler.name;
if (typeof this.handlers[key] !== 'undefined') {
this.logger.log(`Handler '${handler[this.handlerNameProperty]}' already registered`); this.logger.log(`Handler '${handler[this.handlerNameProperty]}' already registered`);
return false; return false;
} }
this.logger.log(`Registered handler '${handler[this.handlerNameProperty]}'`); this.logger.log(`Registered handler '${handler[this.handlerNameProperty]}'`);
this.handlers[handler[this.handlerNameProperty]] = handler; this.handlers[key] = handler;
return true; return true;
} }
@ -282,10 +284,12 @@ export class CoreDelegate {
}).then((enabled: boolean) => { }).then((enabled: boolean) => {
// Check that site hasn't changed since the check started. // Check that site hasn't changed since the check started.
if (this.sitesProvider.getCurrentSiteId() === siteId) { if (this.sitesProvider.getCurrentSiteId() === siteId) {
const key = handler[this.handlerNameProperty] || handler.name;
if (enabled) { if (enabled) {
this.enabledHandlers[handler[this.handlerNameProperty]] = handler; this.enabledHandlers[key] = handler;
} else { } else {
delete this.enabledHandlers[handler[this.handlerNameProperty]]; delete this.enabledHandlers[key];
} }
} }
}).finally(() => { }).finally(() => {

View File

@ -195,12 +195,12 @@ export class CoreCourseModulePrefetchHandlerBase implements CoreCourseModulePref
if (typeof instance.introfiles != 'undefined') { if (typeof instance.introfiles != 'undefined') {
return instance.introfiles; return instance.introfiles;
} else if (instance.intro) { } else if (instance.intro) {
return this.domUtils.extractDownloadableFilesFromHtmlAsFakeFileObjects(instance.intro); return this.filepoolProvider.extractDownloadableFilesFromHtmlAsFakeFileObjects(instance.intro);
} }
} }
if (module.description) { if (module.description) {
return this.domUtils.extractDownloadableFilesFromHtmlAsFakeFileObjects(module.description); return this.filepoolProvider.extractDownloadableFilesFromHtmlAsFakeFileObjects(module.description);
} }
return []; return [];

View File

@ -438,7 +438,7 @@ export class CoreCourseHelperProvider {
sizePromise = this.prefetchDelegate.getDownloadSize(section.modules, courseId); sizePromise = this.prefetchDelegate.getDownloadSize(section.modules, courseId);
// Check if the section has embedded files in the description. // Check if the section has embedded files in the description.
haveEmbeddedFiles = this.domUtils.extractDownloadableFilesFromHtml(section.summary).length > 0; haveEmbeddedFiles = this.filepoolProvider.extractDownloadableFilesFromHtml(section.summary).length > 0;
} else { } else {
const promises = [], const promises = [],
results = { results = {
@ -454,7 +454,7 @@ export class CoreCourseHelperProvider {
})); }));
// Check if the section has embedded files in the description. // Check if the section has embedded files in the description.
if (!haveEmbeddedFiles && this.domUtils.extractDownloadableFilesFromHtml(s.summary).length > 0) { if (!haveEmbeddedFiles && this.filepoolProvider.extractDownloadableFilesFromHtml(s.summary).length > 0) {
haveEmbeddedFiles = true; haveEmbeddedFiles = true;
} }
} }
@ -1449,7 +1449,7 @@ export class CoreCourseHelperProvider {
})); }));
// Download the files in the section description. // Download the files in the section description.
const introFiles = this.domUtils.extractDownloadableFilesFromHtmlAsFakeFileObjects(section.summary), const introFiles = this.filepoolProvider.extractDownloadableFilesFromHtmlAsFakeFileObjects(section.summary),
siteId = this.sitesProvider.getCurrentSiteId(); siteId = this.sitesProvider.getCurrentSiteId();
promises.push(this.filepoolProvider.addFilesToQueue(siteId, introFiles, CoreCourseProvider.COMPONENT, courseId) promises.push(this.filepoolProvider.addFilesToQueue(siteId, introFiles, CoreCourseProvider.COMPONENT, courseId)

View File

@ -63,7 +63,7 @@ export class CoreH5PPluginFileHandler implements CorePluginFileHandler {
/** /**
* Given an HTML element, get the URLs of the files that should be downloaded and weren't treated by * Given an HTML element, get the URLs of the files that should be downloaded and weren't treated by
* CoreDomUtilsProvider.extractDownloadableFilesFromHtml. * CoreFilepoolProvider.extractDownloadableFilesFromHtml.
* *
* @param container Container where to get the URLs from. * @param container Container where to get the URLs from.
* @return {string[]} List of URLs. * @return {string[]} List of URLs.
@ -103,6 +103,15 @@ export class CoreH5PPluginFileHandler implements CorePluginFileHandler {
}); });
} }
/**
* Whether or not the handler is enabled on a site level.
*
* @return Whether or not the handler is enabled on a site level.
*/
isEnabled(): boolean | Promise<boolean> {
return this.h5pProvider.canGetTrustedH5PFileInSite();
}
/** /**
* Check whether the file should be treated by this handler. It is used in functions where the component isn't used. * Check whether the file should be treated by this handler. It is used in functions where the component isn't used.
* *

View File

@ -516,7 +516,7 @@ export class CoreQuestionHelperProvider {
*/ */
prefetchQuestionFiles(question: any, component?: string, componentId?: string | number, siteId?: string, usageId?: number) prefetchQuestionFiles(question: any, component?: string, componentId?: string | number, siteId?: string, usageId?: number)
: Promise<any> { : Promise<any> {
const urls = this.domUtils.extractDownloadableFilesFromHtml(question.html); const urls = this.filepoolProvider.extractDownloadableFilesFromHtml(question.html);
if (!component) { if (!component) {
component = CoreQuestionProvider.COMPONENT; component = CoreQuestionProvider.COMPONENT;

View File

@ -1239,6 +1239,59 @@ export class CoreFilepoolProvider {
} }
} }
/**
* Extract the downloadable URLs from an HTML code.
*
* @param html HTML code.
* @return List of file urls.
*/
extractDownloadableFilesFromHtml(html: string): string[] {
let urls = [],
elements;
const element = this.domUtils.convertToElement(html);
elements = element.querySelectorAll('a, img, audio, video, source, track');
for (let i = 0; i < elements.length; i++) {
const element = elements[i];
let url = element.tagName === 'A' ? element.href : element.src;
if (url && this.urlUtils.isDownloadableUrl(url) && urls.indexOf(url) == -1) {
urls.push(url);
}
// Treat video poster.
if (element.tagName == 'VIDEO' && element.getAttribute('poster')) {
url = element.getAttribute('poster');
if (url && this.urlUtils.isDownloadableUrl(url) && urls.indexOf(url) == -1) {
urls.push(url);
}
}
}
// Now get other files from plugin file handlers.
urls = urls.concat(this.pluginFileDelegate.getDownloadableFilesFromHTML(element));
return urls;
}
/**
* Extract the downloadable URLs from an HTML code and returns them in fake file objects.
*
* @param html HTML code.
* @return List of fake file objects with file URLs.
*/
extractDownloadableFilesFromHtmlAsFakeFileObjects(html: string): any[] {
const urls = this.extractDownloadableFilesFromHtml(html);
// Convert them to fake file objects.
return urls.map((url) => {
return {
fileurl: url
};
});
}
/** /**
* Fill Missing Extension In the File Object if needed. * Fill Missing Extension In the File Object if needed.
* This is to migrate from old versions. * This is to migrate from old versions.

View File

@ -13,18 +13,17 @@
// limitations under the License. // limitations under the License.
import { Injectable } from '@angular/core'; import { Injectable } from '@angular/core';
import { CoreEventsProvider } from './events';
import { CoreLoggerProvider } from './logger'; import { CoreLoggerProvider } from './logger';
import { CoreSitesProvider } from './sites';
import { CoreWSExternalFile } from '@providers/ws'; import { CoreWSExternalFile } from '@providers/ws';
import { FileEntry } from '@ionic-native/file'; import { FileEntry } from '@ionic-native/file';
import { CoreDelegate, CoreDelegateHandler } from '@classes/delegate';
/** /**
* Interface that all plugin file handlers must implement. * Interface that all plugin file handlers must implement.
*/ */
export interface CorePluginFileHandler { export interface CorePluginFileHandler extends CoreDelegateHandler {
/**
* A name to identify the handler.
*/
name: string;
/** /**
* 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.
@ -69,7 +68,7 @@ export interface CorePluginFileHandler {
/** /**
* Given an HTML element, get the URLs of the files that should be downloaded and weren't treated by * Given an HTML element, get the URLs of the files that should be downloaded and weren't treated by
* CoreDomUtilsProvider.extractDownloadableFilesFromHtml. * CoreFilepoolProvider.extractDownloadableFilesFromHtml.
* *
* @param container Container where to get the URLs from. * @param container Container where to get the URLs from.
* @return {string[]} List of URLs. * @return {string[]} List of URLs.
@ -108,12 +107,13 @@ export interface CorePluginFileHandler {
* Delegate to register pluginfile information handlers. * Delegate to register pluginfile information handlers.
*/ */
@Injectable() @Injectable()
export class CorePluginFileDelegate { export class CorePluginFileDelegate extends CoreDelegate {
protected logger; protected handlerNameProperty = 'component';
protected handlers: { [s: string]: CorePluginFileHandler } = {};
constructor(logger: CoreLoggerProvider) { constructor(loggerProvider: CoreLoggerProvider,
this.logger = logger.getInstance('CorePluginFileDelegate'); sitesProvider: CoreSitesProvider,
eventsProvider: CoreEventsProvider) {
super('CorePluginFileDelegate', loggerProvider, sitesProvider, eventsProvider);
} }
/** /**
@ -167,18 +167,6 @@ export class CorePluginFileDelegate {
return Promise.resolve(file); return Promise.resolve(file);
} }
/**
* Get the handler for a certain pluginfile url.
*
* @param component Component of the plugin.
* @return Handler. Undefined if no handler found for the plugin.
*/
protected getPluginHandler(component: string): CorePluginFileHandler {
if (typeof this.handlers[component] != 'undefined') {
return this.handlers[component];
}
}
/** /**
* Get the RegExp of the component and filearea described in the URL. * Get the RegExp of the component and filearea described in the URL.
* *
@ -187,7 +175,7 @@ export class CorePluginFileDelegate {
*/ */
getComponentRevisionRegExp(args: string[]): RegExp { getComponentRevisionRegExp(args: string[]): RegExp {
// Get handler based on component (args[1]). // Get handler based on component (args[1]).
const handler = this.getPluginHandler(args[1]); const handler = <CorePluginFileHandler> this.getHandler(args[1], true);
if (handler && handler.getComponentRevisionRegExp) { if (handler && handler.getComponentRevisionRegExp) {
return handler.getComponentRevisionRegExp(args); return handler.getComponentRevisionRegExp(args);
@ -196,7 +184,7 @@ export class CorePluginFileDelegate {
/** /**
* Given an HTML element, get the URLs of the files that should be downloaded and weren't treated by * Given an HTML element, get the URLs of the files that should be downloaded and weren't treated by
* CoreDomUtilsProvider.extractDownloadableFilesFromHtml. * CoreFilepoolProvider.extractDownloadableFilesFromHtml.
* *
* @param container Container where to get the URLs from. * @param container Container where to get the URLs from.
* @return List of URLs. * @return List of URLs.
@ -204,8 +192,8 @@ export class CorePluginFileDelegate {
getDownloadableFilesFromHTML(container: HTMLElement): string[] { getDownloadableFilesFromHTML(container: HTMLElement): string[] {
let files = []; let files = [];
for (const component in this.handlers) { for (const component in this.enabledHandlers) {
const handler = this.handlers[component]; const handler = <CorePluginFileHandler> this.enabledHandlers[component];
if (handler && handler.getDownloadableFilesFromHTML) { if (handler && handler.getDownloadableFilesFromHTML) {
files = files.concat(handler.getDownloadableFilesFromHTML(container)); files = files.concat(handler.getDownloadableFilesFromHTML(container));
@ -278,8 +266,8 @@ export class CorePluginFileDelegate {
* @return Handler. * @return Handler.
*/ */
protected getHandlerForFile(file: CoreWSExternalFile): CorePluginFileHandler { protected getHandlerForFile(file: CoreWSExternalFile): CorePluginFileHandler {
for (const component in this.handlers) { for (const component in this.enabledHandlers) {
const handler = this.handlers[component]; const handler = <CorePluginFileHandler> this.enabledHandlers[component];
if (handler && handler.shouldHandleFile && handler.shouldHandleFile(file)) { if (handler && handler.shouldHandleFile && handler.shouldHandleFile(file)) {
return handler; return handler;
@ -287,25 +275,6 @@ export class CorePluginFileDelegate {
} }
} }
/**
* Register a handler.
*
* @param handler The handler to register.
* @return True if registered successfully, false otherwise.
*/
registerHandler(handler: CorePluginFileHandler): boolean {
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.name] = handler;
return true;
}
/** /**
* Removes the revision number from a file URL. * Removes the revision number from a file URL.
* *
@ -315,7 +284,7 @@ export class CorePluginFileDelegate {
*/ */
removeRevisionFromUrl(url: string, args: string[]): string { removeRevisionFromUrl(url: string, args: string[]): string {
// Get handler based on component (args[1]). // Get handler based on component (args[1]).
const handler = this.getPluginHandler(args[1]); const handler = <CorePluginFileHandler> this.getHandler(args[1], true);
if (handler && handler.getComponentRevisionRegExp && handler.getComponentRevisionReplace) { if (handler && handler.getComponentRevisionRegExp && handler.getComponentRevisionReplace) {
const revisionRegex = handler.getComponentRevisionRegExp(args); const revisionRegex = handler.getComponentRevisionRegExp(args);

View File

@ -22,7 +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 { CoreLoggerProvider } from '../logger';
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,6 +62,7 @@ export class CoreDomUtilsProvider {
protected lastInstanceId = 0; protected lastInstanceId = 0;
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.
protected logger;
constructor(private translate: TranslateService, constructor(private translate: TranslateService,
private loadingCtrl: LoadingController, private loadingCtrl: LoadingController,
@ -76,7 +77,9 @@ export class CoreDomUtilsProvider {
private sanitizer: DomSanitizer, private sanitizer: DomSanitizer,
private popoverCtrl: PopoverController, private popoverCtrl: PopoverController,
private fileProvider: CoreFileProvider, private fileProvider: CoreFileProvider,
private pluginFileDelegate: CorePluginFileDelegate) { loggerProvider: CoreLoggerProvider) {
this.logger = loggerProvider.getInstance('CoreDomUtilsProvider');
// 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) => {
@ -260,9 +263,13 @@ export class CoreDomUtilsProvider {
* *
* @param html HTML code. * @param html HTML code.
* @return List of file urls. * @return List of file urls.
* @deprecated since 3.8. Use CoreFilepoolProvider.extractDownloadableFilesFromHtml instead.
*/ */
extractDownloadableFilesFromHtml(html: string): string[] { extractDownloadableFilesFromHtml(html: string): string[] {
let urls = []; this.logger.error('The function extractDownloadableFilesFromHtml has been moved to CoreFilepoolProvider.' +
' Please use that function instead of this one.');
const urls = [];
let elements; let elements;
const element = this.convertToElement(html); const element = this.convertToElement(html);
@ -285,9 +292,6 @@ export class CoreDomUtilsProvider {
} }
} }
// Now get other files from plugin file handlers.
urls = urls.concat(this.pluginFileDelegate.getDownloadableFilesFromHTML(element));
return urls; return urls;
} }
@ -296,6 +300,7 @@ export class CoreDomUtilsProvider {
* *
* @param html HTML code. * @param html HTML code.
* @return List of fake file objects with file URLs. * @return List of fake file objects with file URLs.
* @deprecated since 3.8. Use CoreFilepoolProvider.extractDownloadableFilesFromHtmlAsFakeFileObjects instead.
*/ */
extractDownloadableFilesFromHtmlAsFakeFileObjects(html: string): any[] { extractDownloadableFilesFromHtmlAsFakeFileObjects(html: string): any[] {
const urls = this.extractDownloadableFilesFromHtml(html); const urls = this.extractDownloadableFilesFromHtml(html);

View File

@ -1,6 +1,10 @@
This files describes API changes in the Moodle Mobile app, This files describes API changes in the Moodle Mobile app,
information provided here is intended especially for developers. information provided here is intended especially for developers.
=== 3.8.0 ===
- CoreDomUtilsProvider.extractDownloadableFilesFromHtml and CoreDomUtilsProvider.extractDownloadableFilesFromHtmlAsFakeFileObjects have been deprecated. Please use CoreFilepoolProvider.extractDownloadableFilesFromHtml and CoreFilepoolProvider.extractDownloadableFilesFromHtmlAsFakeFileObjects. We had to move them to prevent a circular dependency.
=== 3.7.1 === === 3.7.1 ===
- CoreGroupsProvider.getActivityAllowedGroups and CoreGroupsProvider.getActivityAllowedGroupsIfEnabled now return the full response of core_group_get_activity_allowed_groups instead of just the groups. - CoreGroupsProvider.getActivityAllowedGroups and CoreGroupsProvider.getActivityAllowedGroupsIfEnabled now return the full response of core_group_get_activity_allowed_groups instead of just the groups.