From 767e8ab38fe076e1d2f0dd68831fb11ef781498b Mon Sep 17 00:00:00 2001 From: Dani Palou Date: Mon, 13 Jul 2020 09:30:31 +0200 Subject: [PATCH] MOBILE-3480 core: Treat SVG images and links in format-text --- src/directives/external-content.ts | 10 +++---- src/directives/format-text.ts | 43 +++++++++++++++--------------- src/directives/link.ts | 8 +++--- src/directives/user-link.ts | 3 +-- src/providers/utils/dom.ts | 2 +- 5 files changed, 32 insertions(+), 34 deletions(-) diff --git a/src/directives/external-content.ts b/src/directives/external-content.ts index a4809cef5..c425c9d8c 100644 --- a/src/directives/external-content.ts +++ b/src/directives/external-content.ts @@ -47,7 +47,7 @@ export class CoreExternalContentDirective implements AfterViewInit, OnChanges { @Output() onLoad = new EventEmitter(); // Emitted when content is loaded. Only for images. loaded = false; - protected element: HTMLElement; + protected element: Element; protected logger; protected initialized = false; @@ -62,8 +62,8 @@ export class CoreExternalContentDirective implements AfterViewInit, OnChanges { protected urlUtils: CoreUrlUtilsProvider, protected appProvider: CoreAppProvider, protected utils: CoreUtilsProvider) { - // This directive can be added dynamically. In that case, the first param is the HTMLElement. - this.element = element.nativeElement || element; + + this.element = element.nativeElement; this.logger = logger.getInstance('CoreExternalContentDirective'); } @@ -120,7 +120,7 @@ export class CoreExternalContentDirective implements AfterViewInit, OnChanges { protected checkAndHandleExternalContent(): void { const currentSite = this.sitesProvider.getCurrentSite(), siteId = this.siteId || (currentSite && currentSite.getId()), - tagName = this.element.tagName; + tagName = this.element.tagName.toUpperCase(); let targetAttr, url; @@ -129,7 +129,7 @@ export class CoreExternalContentDirective implements AfterViewInit, OnChanges { this.logger.error('Error treating inline styles.', this.element); }); - if (tagName === 'A') { + if (tagName === 'A' || tagName == 'IMAGE') { targetAttr = 'href'; url = this.href; diff --git a/src/directives/format-text.ts b/src/directives/format-text.ts index 329619c4a..9b3563629 100644 --- a/src/directives/format-text.ts +++ b/src/directives/format-text.ts @@ -121,16 +121,16 @@ export class CoreFormatTextDirective implements OnChanges { * @param element Element to add the attributes to. * @return External content instance. */ - protected addExternalContent(element: HTMLElement): CoreExternalContentDirective { + protected addExternalContent(element: Element): CoreExternalContentDirective { // Angular 2 doesn't let adding directives dynamically. Create the CoreExternalContentDirective manually. - const extContent = new CoreExternalContentDirective( element, this.loggerProvider, this.filepoolProvider, + const extContent = new CoreExternalContentDirective(new ElementRef(element), this.loggerProvider, this.filepoolProvider, this.platform, this.sitesProvider, this.domUtils, this.urlUtils, this.appProvider, this.utils); extContent.component = this.component; extContent.componentId = this.componentId; extContent.siteId = this.siteId; extContent.src = element.getAttribute('src'); - extContent.href = element.getAttribute('href'); + extContent.href = element.getAttribute('href') || element.getAttribute('xlink:href'); extContent.targetSrc = element.getAttribute('target-src'); extContent.poster = element.getAttribute('poster'); @@ -452,32 +452,27 @@ export class CoreFormatTextDirective implements OnChanges { const div = document.createElement('div'), canTreatVimeo = site && site.isVersionGreaterEqualThan(['3.3.4', '3.4']), navCtrl = this.svComponent ? this.svComponent.getMasterNav() : this.navCtrl; - let images, - anchors, - audios, - videos, - iframes, - buttons, - elementsWithInlineStyles, - stopClicksElements, - frames; div.innerHTML = formatted; - images = Array.from(div.querySelectorAll('img')); - anchors = Array.from(div.querySelectorAll('a')); - audios = Array.from(div.querySelectorAll('audio')); - videos = Array.from(div.querySelectorAll('video')); - iframes = Array.from(div.querySelectorAll('iframe')); - buttons = Array.from(div.querySelectorAll('.button')); - elementsWithInlineStyles = Array.from(div.querySelectorAll('*[style]')); - stopClicksElements = Array.from(div.querySelectorAll('button,input,select,textarea')); - frames = Array.from(div.querySelectorAll(CoreIframeUtilsProvider.FRAME_TAGS.join(',').replace(/iframe,?/, ''))); + + const images = Array.from(div.querySelectorAll('img')); + const anchors = Array.from(div.querySelectorAll('a')); + const audios = Array.from(div.querySelectorAll('audio')); + const videos = Array.from(div.querySelectorAll('video')); + const iframes = Array.from(div.querySelectorAll('iframe')); + const buttons = Array.from(div.querySelectorAll('.button')); + const elementsWithInlineStyles = Array.from(div.querySelectorAll('*[style]')); + const stopClicksElements = Array.from(div.querySelectorAll('button,input,select,textarea')); + const frames = Array.from(div.querySelectorAll(CoreIframeUtilsProvider.FRAME_TAGS.join(',').replace(/iframe,?/, ''))); + const svgImages = Array.from(div.querySelectorAll('image')); // Walk through the content to find the links and add our directive to it. // Important: We need to look for links first because in 'img' we add new links without core-link. anchors.forEach((anchor) => { // Angular 2 doesn't let adding directives dynamically. Create the CoreLinkDirective manually. - const linkDir = new CoreLinkDirective(anchor, this.domUtils, this.utils, this.sitesProvider, this.urlUtils, + const elementRef = new ElementRef(anchor); + + const linkDir = new CoreLinkDirective(elementRef, this.domUtils, this.utils, this.sitesProvider, this.urlUtils, this.contentLinksHelper, this.navCtrl, this.content, this.svComponent, this.textUtils, this.urlSchemesProvider); linkDir.capture = true; linkDir.ngOnInit(); @@ -514,6 +509,10 @@ export class CoreFormatTextDirective implements OnChanges { this.treatIframe(iframe, site, canTreatVimeo, navCtrl); }); + svgImages.forEach((image) => { + this.addExternalContent(image); + }); + // Handle buttons with inner links. buttons.forEach((button: HTMLElement) => { // Check if it has a link inside. diff --git a/src/directives/link.ts b/src/directives/link.ts index bea6e6910..2384bbefa 100644 --- a/src/directives/link.ts +++ b/src/directives/link.ts @@ -37,7 +37,7 @@ export class CoreLinkDirective implements OnInit { // "no" -> Never auto-login. // "check" -> Auto-login only if it points to the current site. Default value. - protected element: HTMLElement; + protected element: Element; constructor(element: ElementRef, protected domUtils: CoreDomUtilsProvider, @@ -50,8 +50,8 @@ export class CoreLinkDirective implements OnInit { @Optional() protected svComponent: CoreSplitViewComponent, protected textUtils: CoreTextUtilsProvider, protected urlSchemesProvider: CoreCustomURLSchemesProvider) { - // This directive can be added dynamically. In that case, the first param is the anchor HTMLElement. - this.element = element.nativeElement || element; + + this.element = element.nativeElement; } /** @@ -70,7 +70,7 @@ export class CoreLinkDirective implements OnInit { this.element.addEventListener('click', (event) => { // If the event prevented default action, do nothing. if (!event.defaultPrevented) { - let href = this.element.getAttribute('href'); + let href = this.element.getAttribute('href') || this.element.getAttribute('xlink:href'); if (href && this.urlUtils.getUrlScheme(href) != 'javascript') { event.preventDefault(); event.stopPropagation(); diff --git a/src/directives/user-link.ts b/src/directives/user-link.ts index 7359ee3f8..79764b816 100644 --- a/src/directives/user-link.ts +++ b/src/directives/user-link.ts @@ -32,8 +32,7 @@ export class CoreUserLinkDirective implements OnInit { @Optional() private navCtrl: NavController, @Optional() private svComponent: CoreSplitViewComponent) { - // This directive can be added dynamically. In that case, the first param is the anchor HTMLElement. - this.element = element.nativeElement || element; + this.element = element.nativeElement; } /** diff --git a/src/providers/utils/dom.ts b/src/providers/utils/dom.ts index cdc652f3e..1a7291ed6 100644 --- a/src/providers/utils/dom.ts +++ b/src/providers/utils/dom.ts @@ -99,7 +99,7 @@ export class CoreDomUtilsProvider { * @param selector Selector to search. * @return Closest ancestor. */ - closest(element: HTMLElement, selector: string): Element { + closest(element: Element, selector: string): Element { // Try to use closest if the browser supports it. if (typeof element.closest == 'function') { return element.closest(selector);