From f82d3504f6f6ccfba015e4144be4611f1b06a0fa Mon Sep 17 00:00:00 2001 From: Noel De Martin Date: Tue, 14 Mar 2023 18:20:11 +0100 Subject: [PATCH] MOBILE-4193 grades: Avoid filtering rich images --- .../mod/lti/services/handlers/module.ts | 14 +++++++++++++ src/core/components/mod-icon/mod-icon.html | 4 ++-- src/core/components/mod-icon/mod-icon.scss | 5 +++++ src/core/components/mod-icon/mod-icon.ts | 7 ++++++- .../course/services/module-delegate.ts | 21 +++++++++++++++++++ .../features/grades/pages/course/course.html | 3 ++- .../grades/pages/course/course.page.ts | 9 ++++++++ .../features/grades/services/grades-helper.ts | 15 +++++++------ 8 files changed, 68 insertions(+), 10 deletions(-) diff --git a/src/addons/mod/lti/services/handlers/module.ts b/src/addons/mod/lti/services/handlers/module.ts index 1494456b3..545aa262f 100644 --- a/src/addons/mod/lti/services/handlers/module.ts +++ b/src/addons/mod/lti/services/handlers/module.ts @@ -22,6 +22,7 @@ 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. @@ -86,6 +87,19 @@ 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/core/components/mod-icon/mod-icon.html b/src/core/components/mod-icon/mod-icon.html index 58842cb13..46777347a 100644 --- a/src/core/components/mod-icon/mod-icon.html +++ b/src/core/components/mod-icon/mod-icon.html @@ -1,5 +1,5 @@ + class="core-module-icon" [class.no-filter]="noFilter" (error)="loadFallbackIcon()"> diff --git a/src/core/components/mod-icon/mod-icon.scss b/src/core/components/mod-icon/mod-icon.scss index f5f7dbdcb..5ab0db1f0 100644 --- a/src/core/components/mod-icon/mod-icon.scss +++ b/src/core/components/mod-icon/mod-icon.scss @@ -42,6 +42,11 @@ img { white-space: nowrap; overflow: hidden; } + + &.no-filter { + --filter: none; + } + } :host-context(ion-item) { diff --git a/src/core/components/mod-icon/mod-icon.ts b/src/core/components/mod-icon/mod-icon.ts index f2e59c7d7..1d2f018b2 100644 --- a/src/core/components/mod-icon/mod-icon.ts +++ b/src/core/components/mod-icon/mod-icon.ts @@ -13,7 +13,7 @@ // limitations under the License. import { CoreConstants, ModPurpose } from '@/core/constants'; -import { Component, ElementRef, Input, OnChanges, OnInit, SimpleChange } from '@angular/core'; +import { Component, ElementRef, EventEmitter, Input, OnChanges, OnInit, Output, SimpleChange } from '@angular/core'; import { CoreCourse } from '@features/course/services/course'; import { CoreCourseModuleDelegate } from '@features/course/services/module-delegate'; import { CoreSites } from '@services/sites'; @@ -34,9 +34,12 @@ export class CoreModIconComponent implements OnInit, OnChanges { @Input() modname?: string; // The module name. Used also as component if set. @Input() componentId?: number; // Component Id for external icons. @Input() modicon?: string; // Module icon url or local url. + @Input() noFilter?: boolean; // Whether to disable filters. @Input() showAlt = true; // Show alt otherwise it's only presentation icon. @Input() purpose: ModPurpose = ModPurpose.MOD_PURPOSE_OTHER; // Purpose of the module. + @Output() failedLoading = new EventEmitter(); + icon = ''; modNameTranslated = ''; isLocalUrl = true; @@ -122,6 +125,8 @@ export class CoreModIconComponent implements OnInit, OnChanges { } this.icon = path + moduleName + '.svg'; + + this.failedLoading.emit(); } } diff --git a/src/core/features/course/services/module-delegate.ts b/src/core/features/course/services/module-delegate.ts index f8dead8d3..0a6a2af3a 100644 --- a/src/core/features/course/services/module-delegate.ts +++ b/src/core/features/course/services/module-delegate.ts @@ -87,6 +87,15 @@ export interface CoreCourseModuleHandler extends CoreDelegateHandler { */ getIconSrc?(module?: CoreCourseModuleData, modicon?: string): Promise | string | undefined; + /** + * Check whether the icon should be treated as a shape or a rich image. + * + * @param module Module to get the icon from. + * @param modicon The mod icon string. + * @returns Whether the icon should be treated as a shape. + */ + iconIsShape?(module?: CoreCourseModuleData, modicon?: string): Promise | boolean | undefined; + /** * Check if this type of module supports a certain feature. * If this function is implemented, the supportedFeatures object will be ignored. @@ -396,6 +405,18 @@ export class CoreCourseModuleDelegateService extends CoreDelegate { + return await this.executeFunctionOnEnabled>(modname, 'iconIsShape', [module, modicon]); + } + /** * Check if a certain type of module supports a certain feature. * diff --git a/src/core/features/grades/pages/course/course.html b/src/core/features/grades/pages/course/course.html index 70cc02b61..44236689c 100644 --- a/src/core/features/grades/pages/course/course.html +++ b/src/core/features/grades/pages/course/course.html @@ -48,7 +48,8 @@ + [modname]="row.itemmodule" [noFilter]="row.imageIsShape === false" + (failedLoading)="failedLoadingRowImage(row)"> diff --git a/src/core/features/grades/pages/course/course.page.ts b/src/core/features/grades/pages/course/course.page.ts index c70adc1a8..508d99488 100644 --- a/src/core/features/grades/pages/course/course.page.ts +++ b/src/core/features/grades/pages/course/course.page.ts @@ -239,4 +239,13 @@ export class CoreGradesCoursePage implements AfterViewInit, OnDestroy { infiniteComplete && infiniteComplete(); } + /** + * Handle row image failed loading. + * + * @param row Row data. + */ + failedLoadingRowImage(row: CoreGradesFormattedTableRow): void { + delete row.imageIsShape; + } + } diff --git a/src/core/features/grades/services/grades-helper.ts b/src/core/features/grades/services/grades-helper.ts index fb5d4b3f3..96c4ea06e 100644 --- a/src/core/features/grades/services/grades-helper.ts +++ b/src/core/features/grades/services/grades-helper.ts @@ -684,14 +684,16 @@ export class CoreGradesHelperProvider { row.iconAlt = Translate.instant('core.grades.calculatedgrade'); } else if (text.indexOf('/mod/') > -1) { const module = text.match(/mod\/([^/]*)\//); - if (module?.[1] !== undefined) { + const modname = module?.[1]; + + if (modname !== undefined) { + const modicon = CoreDomUtils.convertToElement(text).querySelector('img')?.getAttribute('src') ?? undefined; + row.itemtype = 'mod'; - row.itemmodule = module[1]; + row.itemmodule = modname; row.iconAlt = CoreCourse.translateModuleName(row.itemmodule) || ''; - row.image = await CoreCourseModuleDelegate.getModuleIconSrc( - module[1], - CoreDomUtils.convertToElement(text).querySelector('img')?.getAttribute('src') ?? undefined, - ); + row.image = await CoreCourseModuleDelegate.getModuleIconSrc(modname, modicon); + row.imageIsShape = await CoreCourseModuleDelegate.moduleIconIsShape(modname, modicon); } } else { if (row.rowspan && row.rowspan > 1) { @@ -804,6 +806,7 @@ export type CoreGradesFormattedRowCommonData = { rowclass?: string; itemtype?: string; image?: string; + imageIsShape?: boolean; itemmodule?: string; iconAlt?: string; rowspan?: number;