From 5735bc4ca96a793fdb555f91acde9ca167cc20d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pau=20Ferrer=20Oca=C3=B1a?= Date: Mon, 27 May 2024 16:12:23 +0200 Subject: [PATCH] MOBILE-4470 icon: Fix mod icon loading having a real uniqueId on SVG --- src/core/components/mod-icon/mod-icon.html | 4 +- src/core/components/mod-icon/mod-icon.ts | 48 +++++++++++++++++----- 2 files changed, 39 insertions(+), 13 deletions(-) diff --git a/src/core/components/mod-icon/mod-icon.html b/src/core/components/mod-icon/mod-icon.html index 072472df3..4a2cc5585 100644 --- a/src/core/components/mod-icon/mod-icon.html +++ b/src/core/components/mod-icon/mod-icon.html @@ -1,6 +1,6 @@ - + -
+
diff --git a/src/core/components/mod-icon/mod-icon.ts b/src/core/components/mod-icon/mod-icon.ts index e8a09cdd0..7de508ef2 100644 --- a/src/core/components/mod-icon/mod-icon.ts +++ b/src/core/components/mod-icon/mod-icon.ts @@ -13,7 +13,8 @@ // limitations under the License. import { CoreConstants, ModPurpose } from '@/core/constants'; -import { Component, ElementRef, HostBinding, Input, OnChanges, OnInit, SimpleChange, ViewChild } from '@angular/core'; +import { Component, ElementRef, HostBinding, Input, OnChanges, OnInit, SimpleChange } from '@angular/core'; +import { SafeHtml } from '@angular/platform-browser'; import { CoreCourse } from '@features/course/services/course'; import { CoreCourseModuleDelegate } from '@features/course/services/module-delegate'; import { CoreFile } from '@services/file'; @@ -22,7 +23,7 @@ import { CoreSites } from '@services/sites'; import { CoreTextUtils } from '@services/utils/text'; import { CoreUrlUtils } from '@services/utils/url'; import { CoreUtils } from '@services/utils/utils'; -import { Http } from '@singletons'; +import { DomSanitizer, Http } from '@singletons'; import { firstValueFrom } from 'rxjs'; const assetsPath = 'assets/img/'; @@ -65,13 +66,11 @@ export class CoreModIconComponent implements OnInit, OnChanges { return this.showAlt ? this.modNameTranslated : ''; } - @ViewChild('svg') svgElement!: ElementRef; - iconUrl = ''; modNameTranslated = ''; isLocalUrl = false; - svgLoaded = false; + svgIcon: SafeHtml = ''; linkIconWithComponent = false; loaded = false; @@ -304,7 +303,7 @@ export class CoreModIconComponent implements OnInit, OnChanges { protected async setSVGIcon(): Promise { if (this.iconVersion === IconVersion.LEGACY_VERSION) { this.loaded = true; - this.svgLoaded = false; + this.svgIcon = ''; return; } @@ -347,7 +346,7 @@ export class CoreModIconComponent implements OnInit, OnChanges { } if (mimetype !== 'image/svg+xml' || !fileContents) { - this.svgLoaded = false; + this.svgIcon = ''; return; } @@ -358,7 +357,7 @@ export class CoreModIconComponent implements OnInit, OnChanges { // Safety check. if (doc.documentElement.nodeName !== 'svg') { - this.svgLoaded = false; + this.svgIcon = ''; return; } @@ -397,10 +396,37 @@ export class CoreModIconComponent implements OnInit, OnChanges { } } - this.svgElement.nativeElement.replaceChildren(doc.documentElement); - this.svgLoaded = true; + // Prefix id's on svg DOM to avoid conflicts. + const uniqueId = 'modicon' + CoreUtils.getUniqueId('modicon') + '_'; + const styleTags = Array.from(doc.documentElement.getElementsByTagName('style')); + const styleAttrs = Array.from(doc.documentElement.querySelectorAll('[style]')); + const idTags = Array.from(doc.documentElement.querySelectorAll('[id]')); + idTags.forEach((element) => { + if (!element.id) { + return; + } + const newId = uniqueId + element.id; + // Regexp to replace all ocurrences of the id with workd bondaries. + const oldIdFinder = new RegExp(`#${element.id}\\b`, 'g'); + + element.id = newId; + + // Prefix the elementId on style Tags. + styleTags.forEach((style) => { + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + style.textContent = style.textContent!.replace(oldIdFinder, `#${newId}`); + }); + + // Also change ids on style attributes. + styleAttrs.forEach((attr) => { + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + attr.setAttribute('style', attr.getAttribute('style')!.replace(oldIdFinder, `#${newId}`)); + }); + }); + + this.svgIcon = DomSanitizer.bypassSecurityTrustHtml(doc.documentElement.outerHTML); } catch { - this.svgLoaded = false; + this.svgIcon = ''; } finally { this.loaded = true; }