diff --git a/src/addons/mod/lti/services/handlers/module.ts b/src/addons/mod/lti/services/handlers/module.ts index 574758a90..70c8ce34a 100644 --- a/src/addons/mod/lti/services/handlers/module.ts +++ b/src/addons/mod/lti/services/handlers/module.ts @@ -22,7 +22,6 @@ import { AddonModLtiHelper } from '../lti-helper'; import { AddonModLtiIndexComponent } from '../../components/index'; import { CoreModuleHandlerBase } from '@features/course/classes/module-base-handler'; import { CoreCourse } from '@features/course/services/course'; -import { CoreSites } from '@services/sites'; /** * Handler to support LTI modules. @@ -87,19 +86,6 @@ export class AddonModLtiModuleHandlerService extends CoreModuleHandlerBase imple return module?.modicon ?? modicon ?? CoreCourse.getModuleIconSrc(this.modName); } - /** - * @inheritdoc - */ - iconIsShape(module?: CoreCourseModuleData | undefined, modicon?: string | undefined): boolean | undefined { - const iconUrl = module?.modicon ?? modicon; - - if (!iconUrl) { - return true; - } - - return iconUrl.startsWith(CoreSites.getRequiredCurrentSite().siteUrl); - } - } export const AddonModLtiModuleHandler = makeSingleton(AddonModLtiModuleHandlerService); diff --git a/src/addons/mod/resource/services/handlers/module.ts b/src/addons/mod/resource/services/handlers/module.ts index 55ba7518b..2ffc361f9 100644 --- a/src/addons/mod/resource/services/handlers/module.ts +++ b/src/addons/mod/resource/services/handlers/module.ts @@ -170,14 +170,5 @@ export class AddonModResourceModuleHandlerService extends CoreModuleHandlerBase return AddonModResourceIndexComponent; } - /** - * @inheritdoc - */ - iconIsShape(module?: CoreCourseModuleData | undefined, modicon?: string | undefined): boolean | undefined { - const iconUrl = module?.modicon ?? modicon; - - return !iconUrl?.startsWith('assets/img/files_legacy/') && !iconUrl?.endsWith('.png'); - } - } export const AddonModResourceModuleHandler = makeSingleton(AddonModResourceModuleHandlerService); diff --git a/src/addons/mod/url/services/handlers/module.ts b/src/addons/mod/url/services/handlers/module.ts index 02e9c557f..a67325fdf 100644 --- a/src/addons/mod/url/services/handlers/module.ts +++ b/src/addons/mod/url/services/handlers/module.ts @@ -218,15 +218,6 @@ export class AddonModUrlModuleHandlerService extends CoreModuleHandlerBase imple return this.shouldOpenLink(module); } - /** - * @inheritdoc - */ - iconIsShape(module?: CoreCourseModuleData | undefined, modicon?: string | undefined): boolean | undefined { - const iconUrl = module?.modicon ?? modicon; - - return !iconUrl?.startsWith('assets/img/files_legacy/') && !iconUrl?.endsWith('.png'); - } - /** * Log module viewed. */ diff --git a/src/core/components/mod-icon/mod-icon.ts b/src/core/components/mod-icon/mod-icon.ts index 1f4777f9a..a51788f87 100644 --- a/src/core/components/mod-icon/mod-icon.ts +++ b/src/core/components/mod-icon/mod-icon.ts @@ -17,6 +17,7 @@ import { Component, ElementRef, Input, OnChanges, OnInit, SimpleChange } from '@ import { CoreCourse } from '@features/course/services/course'; import { CoreCourseModuleDelegate } from '@features/course/services/module-delegate'; import { CoreSites } from '@services/sites'; +import { CoreUrlUtils } from '@services/utils/url'; const assetsPath = 'assets/img/'; const fallbackModName = 'external-tool'; @@ -54,12 +55,7 @@ export class CoreModIconComponent implements OnInit, OnChanges { async ngOnInit(): Promise { if (!this.modname && this.modicon) { // Guess module from the icon url. - const matches = this.modicon.match('/theme/image.php/[^/]+/([^/]+)/[-0-9]*/'); - this.modname = (matches && matches[1]) || ''; - - if (this.modname.startsWith('mod_')) { - this.modname = this.modname.substring(4); - } + this.modname = this.getComponentNameFromIconUrl(this.modicon); } this.modNameTranslated = CoreCourse.translateModuleName(this.modname, this.fallbackTranslation); @@ -105,16 +101,15 @@ export class CoreModIconComponent implements OnInit, OnChanges { !!this.modname && !!this.componentId && !this.isLocalUrl && - !this.icon.match('/theme/image.php/[^/]+/' + this.modname + '/[-0-9]*/'); + this.getComponentNameFromIconUrl(this.icon) != this.modname; - const iconIsShape = await CoreCourseModuleDelegate.moduleIconIsShape(this.modname, this.icon); - this.noFilter = iconIsShape === false; + this.noFilter = await this.getIconNoFilter(); } /** * Icon to load on error. */ - loadFallbackIcon(): void { + async loadFallbackIcon(): Promise { this.isLocalUrl = true; const moduleName = !this.modname || CoreCourse.CORE_MODULES.indexOf(this.modname) < 0 ? fallbackModName @@ -127,7 +122,75 @@ export class CoreModIconComponent implements OnInit, OnChanges { } this.icon = path + moduleName + '.svg'; - this.noFilter = false; + this.noFilter = await this.getIconNoFilter(); + } + + /** + * Returns if the icon does not need to be filtered. + * + * @returns wether the icon does not need to be filtered. + */ + protected async getIconNoFilter(): Promise { + // Earlier 4.0, icons were never filtered. + if (this.legacyIcon) { + return true; + } + + // No icon or local icon (not legacy), filter it. + if (!this.icon || this.isLocalUrl) { + return false; + } + + // If it's an Moodle Theme icon, check if filtericon is set and use it. + if (this.icon && CoreUrlUtils.isThemeImageUrl(this.icon)) { + const iconParams = CoreUrlUtils.extractUrlParams(this.icon); + if (iconParams['filtericon'] === '1') { + return false; + } + + // filtericon was introduced in 4.2 and backported to 4.1.3 and 4.0.8. + if (this.modname && !CoreSites.getCurrentSite()?.isVersionGreaterEqualThan(['4.0.8', '4.1.3', '4.2'])) { + // If version is prior to that, check if the url is a module icon and filter it. + if (this.getComponentNameFromIconUrl(this.icon) === this.modname) { + return false; + } + } + } + + // External icons, or non monologo, do not filter. + return true; + } + + /** + * Guesses the mod name form the url. + * + * @param iconUrl Icon url. + * @returns Guessed modname. + */ + protected getComponentNameFromIconUrl(iconUrl: string): string { + if (!CoreUrlUtils.isThemeImageUrl(this.icon)) { + // Cannot be guessed. + return ''; + } + + const iconParams = CoreUrlUtils.extractUrlParams(iconUrl); + let component = iconParams['component']; + + if (!component) { + const matches = iconUrl.match('/theme/image.php/[^/]+/([^/]+)/[-0-9]*/'); + component = (matches && matches[1]) || ''; + } + + // Some invalid components (others may be added later on). + if (component === 'core' || component === 'theme') { + return ''; + } + + if (component.startsWith('mod_')) { + component = component.substring(4); + } + + return component; } } diff --git a/src/core/features/course/services/module-delegate.ts b/src/core/features/course/services/module-delegate.ts index 920734e01..dbd4b224d 100644 --- a/src/core/features/course/services/module-delegate.ts +++ b/src/core/features/course/services/module-delegate.ts @@ -93,6 +93,7 @@ export interface CoreCourseModuleHandler extends CoreDelegateHandler { * @param module Module to get the icon from. * @param modicon The mod icon string. * @returns Whether the icon should be treated as a shape. + * @deprecated since 4.3. Now it uses platform information. This function is not used anymore. */ iconIsShape?(module?: CoreCourseModuleData, modicon?: string): Promise | boolean | undefined; @@ -415,6 +416,7 @@ export class CoreCourseModuleDelegateService extends CoreDelegate { return await this.executeFunctionOnEnabled>(modname, 'iconIsShape', [module, modicon]);