From 6da34f5984d1c731e69f9c893eefc194f37fd4e6 Mon Sep 17 00:00:00 2001 From: Dani Palou <dani@moodle.com> Date: Fri, 17 May 2024 09:53:58 +0200 Subject: [PATCH] MOBILE-3403 core: Avoid performing requests to embedded untreated URLs --- .../pages/issued-badge/issued-badge.html | 2 +- .../badges/pages/user-badges/user-badges.html | 2 +- .../conversation-info/conversation-info.html | 2 +- .../messages/pages/discussion/discussion.html | 2 +- .../group-conversations.html | 2 +- .../addon-mod-data-field-picture.html | 4 +- src/addons/notifications/pages/list/list.html | 6 +- .../pages/notification/notification.html | 6 +- .../components/course-image/course-image.html | 2 +- src/core/components/mod-icon/mod-icon.html | 2 +- .../user-avatar/core-user-avatar.html | 4 +- src/core/directives/external-content.ts | 125 ++++++++++-------- src/core/directives/format-text.ts | 46 ++++--- .../pages/course-summary/course-summary.html | 2 +- .../features/course/pages/index/index.html | 2 +- .../core-courses-course-list-item.html | 4 +- .../global-search-result.html | 2 +- .../viewer/components/image/image.html | 2 +- 18 files changed, 114 insertions(+), 103 deletions(-) diff --git a/src/addons/badges/pages/issued-badge/issued-badge.html b/src/addons/badges/pages/issued-badge/issued-badge.html index 157d7b1f9..5f06dc1d6 100644 --- a/src/addons/badges/pages/issued-badge/issued-badge.html +++ b/src/addons/badges/pages/issued-badge/issued-badge.html @@ -17,7 +17,7 @@ <ion-item-group *ngIf="badge"> <ion-item class="ion-text-wrap ion-text-center"> <ion-label> - <img *ngIf="badge.badgeurl" class="large-avatar" [src]="badge.badgeurl" core-external-content [alt]="badge.name" /> + <img *ngIf="badge.badgeurl" class="large-avatar" [url]="badge.badgeurl" core-external-content [alt]="badge.name" /> <ion-badge color="danger" *ngIf="badge.dateexpire && currentTime >= badge.dateexpire"> {{ 'addon.badges.expired' | translate }} </ion-badge> diff --git a/src/addons/badges/pages/user-badges/user-badges.html b/src/addons/badges/pages/user-badges/user-badges.html index edc263c99..db9110499 100644 --- a/src/addons/badges/pages/user-badges/user-badges.html +++ b/src/addons/badges/pages/user-badges/user-badges.html @@ -20,7 +20,7 @@ <ion-item button class="ion-text-wrap" *ngFor="let badge of badges.items" [attr.aria-label]="badge.name" (click)="badges.select(badge)" [attr.aria-current]="badges.getItemAriaCurrent(badge)" [detail]="true"> <ion-avatar slot="start"> - <img [src]="badge.badgeurl" [alt]="badge.name" core-external-content> + <img [url]="badge.badgeurl" [alt]="badge.name" core-external-content> </ion-avatar> <ion-label> <p class="item-heading">{{ badge.name }}</p> diff --git a/src/addons/messages/components/conversation-info/conversation-info.html b/src/addons/messages/components/conversation-info/conversation-info.html index f18c17a89..33b092794 100644 --- a/src/addons/messages/components/conversation-info/conversation-info.html +++ b/src/addons/messages/components/conversation-info/conversation-info.html @@ -19,7 +19,7 @@ <ion-item class="ion-text-center" *ngIf="conversation"> <ion-label> <div class="large-avatar"> - <img class="avatar" [src]="conversation.imageurl" core-external-content [alt]="conversation.name" + <img class="avatar" [url]="conversation.imageurl" core-external-content [alt]="conversation.name" onError="this.src='assets/img/group-avatar.svg'"> </div> <h2> diff --git a/src/addons/messages/pages/discussion/discussion.html b/src/addons/messages/pages/discussion/discussion.html index 91f99b7b2..0524b379a 100644 --- a/src/addons/messages/pages/discussion/discussion.html +++ b/src/addons/messages/pages/discussion/discussion.html @@ -5,7 +5,7 @@ </ion-buttons> <ion-title> <h1> - <img *ngIf="loaded && !otherMember && conversationImage" class="core-bar-button-image" [src]="conversationImage" alt="" + <img *ngIf="loaded && !otherMember && conversationImage" class="core-bar-button-image" [url]="conversationImage" alt="" onError="this.src='assets/img/group-avatar.svg'" core-external-content role="presentation" [siteId]="siteId"> <core-user-avatar *ngIf="loaded && otherMember" class="core-bar-button-image" [user]="otherMember" [linkProfile]="false" [checkOnline]="otherMember.showonlinestatus" /> diff --git a/src/addons/messages/pages/group-conversations/group-conversations.html b/src/addons/messages/pages/group-conversations/group-conversations.html index db43ceb5c..6bfa58349 100644 --- a/src/addons/messages/pages/group-conversations/group-conversations.html +++ b/src/addons/messages/pages/group-conversations/group-conversations.html @@ -85,7 +85,7 @@ [attr.aria-label]="conversation.name"> <!-- Group conversation image. --> <ion-avatar slot="start" *ngIf="conversation.type === typeGroup"> - <img [src]="conversation.imageurl" [alt]="conversation.name" core-external-content + <img [url]="conversation.imageurl" [alt]="conversation.name" core-external-content onError="this.src='assets/img/group-avatar.svg'"> </ion-avatar> diff --git a/src/addons/mod/data/fields/picture/component/addon-mod-data-field-picture.html b/src/addons/mod/data/fields/picture/component/addon-mod-data-field-picture.html index 36136e9a2..aa506f62f 100644 --- a/src/addons/mod/data/fields/picture/component/addon-mod-data-field-picture.html +++ b/src/addons/mod/data/fields/picture/component/addon-mod-data-field-picture.html @@ -13,8 +13,8 @@ </ng-container> <button class="as-link" *ngIf="listMode && imageUrl" (click)="navigateEntry()"> - <img [src]="imageUrl" [alt]="title" class="core-media-adapt-width listMode_picture" core-external-content /> + <img [url]="imageUrl" [alt]="title" class="core-media-adapt-width listMode_picture" core-external-content /> </button> -<img *ngIf="showMode && imageUrl" [src]="imageUrl" [alt]="title" class="core-media-adapt-width listMode_picture" [attr.width]="width" +<img *ngIf="showMode && imageUrl" [url]="imageUrl" [alt]="title" class="core-media-adapt-width listMode_picture" [attr.width]="width" [attr.height]="height" core-external-content /> diff --git a/src/addons/notifications/pages/list/list.html b/src/addons/notifications/pages/list/list.html index 7dc5ec95c..ec1beac1a 100644 --- a/src/addons/notifications/pages/list/list.html +++ b/src/addons/notifications/pages/list/list.html @@ -41,15 +41,15 @@ [profileUrl]="notification.profileimageurlfrom" [fullname]="notification.userfromfullname" [userId]="notification.useridfrom"> <div class="core-avatar-extra-img" *ngIf="notification.iconurl"> - <img [src]="notification.iconurl" alt="" role="presentation" core-external-content> + <img [url]="notification.iconurl" alt="" role="presentation" core-external-content> </div> </core-user-avatar> <ng-container *ngIf="notification.useridfrom <= 0"> - <img *ngIf="notification.imgUrl" class="core-notification-img" [src]="notification.imgUrl" core-external-content alt="" + <img *ngIf="notification.imgUrl" class="core-notification-img" [url]="notification.imgUrl" core-external-content alt="" role="presentation" slot="start"> <div class="core-notification-icon" *ngIf="!notification.imgUrl" slot="start"> - <img *ngIf="notification.iconurl" [src]="notification.iconurl" core-external-content alt="" role="presentation"> + <img *ngIf="notification.iconurl" [url]="notification.iconurl" core-external-content alt="" role="presentation"> <ion-icon *ngIf="!notification.iconurl" name="fas-bell" aria-hidden="true" /> </div> </ng-container> diff --git a/src/addons/notifications/pages/notification/notification.html b/src/addons/notifications/pages/notification/notification.html index c6305eda8..48c8d4e9d 100644 --- a/src/addons/notifications/pages/notification/notification.html +++ b/src/addons/notifications/pages/notification/notification.html @@ -16,15 +16,15 @@ <core-user-avatar *ngIf="notification.useridfrom > 0" slot="start" [userId]="notification.useridfrom" [profileUrl]="notification.profileimageurlfrom" [fullname]="notification.userfromfullname"> <div class="core-avatar-extra-img" *ngIf="notification.iconurl"> - <img [src]="notification.iconurl" alt="" role="presentation" core-external-content> + <img [url]="notification.iconurl" alt="" role="presentation" core-external-content> </div> </core-user-avatar> <ng-container *ngIf="notification.useridfrom <= 0"> - <img *ngIf="notification.imgUrl" class="core-notification-img" [src]="notification.imgUrl" core-external-content alt="" + <img *ngIf="notification.imgUrl" class="core-notification-img" [url]="notification.imgUrl" core-external-content alt="" role="presentation" slot="start"> <div class="core-notification-icon" *ngIf="!notification.imgUrl" slot="start"> - <img *ngIf="notification.iconurl" [src]="notification.iconurl" core-external-content alt="" role="presentation"> + <img *ngIf="notification.iconurl" [url]="notification.iconurl" core-external-content alt="" role="presentation"> <ion-icon *ngIf="!notification.iconurl" name="fas-bell" aria-hidden="true" /> </div> </ng-container> diff --git a/src/core/components/course-image/course-image.html b/src/core/components/course-image/course-image.html index a9e8d0ead..fee483a9d 100644 --- a/src/core/components/course-image/course-image.html +++ b/src/core/components/course-image/course-image.html @@ -1,4 +1,4 @@ <ion-icon *ngIf="!course.courseimage" name="fas-graduation-cap" slot="start" aria-hidden="true" /> <ion-avatar *ngIf="course.courseimage" slot="start"> - <img [src]="course.courseimage" core-external-content alt="" (error)="loadFallbackCourseIcon()" /> + <img [url]="course.courseimage" core-external-content alt="" (error)="loadFallbackCourseIcon()" /> </ion-avatar> diff --git a/src/core/components/mod-icon/mod-icon.html b/src/core/components/mod-icon/mod-icon.html index 1d5cda1a8..072472df3 100644 --- a/src/core/components/mod-icon/mod-icon.html +++ b/src/core/components/mod-icon/mod-icon.html @@ -1,5 +1,5 @@ <ng-container *ngIf="loaded && !svgLoaded"> - <img *ngIf="!isLocalUrl" [src]="iconUrl" core-external-content alt="" [component]="linkIconWithComponent ? modname : null" + <img *ngIf="!isLocalUrl" [url]="iconUrl" core-external-content alt="" [component]="linkIconWithComponent ? modname : null" [componentId]="linkIconWithComponent ? componentId : null" (error)="loadFallbackIcon()"> <img *ngIf="isLocalUrl" [src]="iconUrl" (error)="loadFallbackIcon()" alt=""> </ng-container> diff --git a/src/core/components/user-avatar/core-user-avatar.html b/src/core/components/user-avatar/core-user-avatar.html index 76c6425ec..671e2c94b 100644 --- a/src/core/components/user-avatar/core-user-avatar.html +++ b/src/core/components/user-avatar/core-user-avatar.html @@ -1,8 +1,8 @@ <ng-container *ngIf="avatarUrl"> - <img class="userpicture" *ngIf="linkProfile" [src]="avatarUrl" [alt]="'core.pictureof' | translate:{$a: fullname}" core-external-content + <img class="userpicture" *ngIf="linkProfile" [url]="avatarUrl" [alt]="'core.pictureof' | translate:{$a: fullname}" core-external-content (error)="loadImageError()" (ariaButtonClick)="gotoProfile($event)" [siteId]="siteId"> - <img class="userpicture" *ngIf="!linkProfile" [src]="avatarUrl" [alt]="'core.pictureof' | translate:{$a: fullname}" + <img class="userpicture" *ngIf="!linkProfile" [url]="avatarUrl" [alt]="'core.pictureof' | translate:{$a: fullname}" core-external-content (error)="loadImageError()" aria-hidden="true" [siteId]="siteId"> </ng-container> <ng-container *ngIf="!avatarUrl && initials"> diff --git a/src/core/directives/external-content.ts b/src/core/directives/external-content.ts index 95c2ecfd1..7170f208d 100644 --- a/src/core/directives/external-content.ts +++ b/src/core/directives/external-content.ts @@ -60,9 +60,19 @@ export class CoreExternalContentDirective implements AfterViewInit, OnChanges, O @Input() siteId?: string; // Site ID to use. @Input() component?: string; // Component to link the file to. @Input() componentId?: string | number; // Component ID to use in conjunction with the component. + @Input() url?: string | null; // The URL to use in the element, either as src or href. + @Input() posterUrl?: string | null; // The poster URL. + /** + * @deprecated since 4.4. Use url instead. + */ @Input() src?: string; + /** + * @deprecated since 4.4. Use url instead. + */ @Input() href?: string; - @Input('target-src') targetSrc?: string; // eslint-disable-line @angular-eslint/no-input-rename + /** + * @deprecated since 4.4. Use posterUrl instead. + */ @Input() poster?: string; @Output() onLoad = new EventEmitter(); // Emitted when content is loaded. Only for images. @@ -142,23 +152,22 @@ export class CoreExternalContentDirective implements AfterViewInit, OnChanges, O if (tagName === 'A' || tagName == 'IMAGE') { targetAttr = 'href'; - url = this.href ?? ''; + url = this.url ?? this.href ?? ''; // eslint-disable-line deprecation/deprecation } else if (tagName === 'IMG') { targetAttr = 'src'; - url = this.src ?? ''; + url = this.url ?? this.src ?? ''; // eslint-disable-line deprecation/deprecation } else if (tagName === 'AUDIO' || tagName === 'VIDEO' || tagName === 'SOURCE' || tagName === 'TRACK') { targetAttr = 'src'; - url = (this.targetSrc || this.src) ?? ''; + url = this.url ?? this.src ?? ''; // eslint-disable-line deprecation/deprecation - if (tagName === 'VIDEO') { - if (this.poster) { - // Handle poster. - this.handleExternalContent('poster', this.poster, siteId).catch(() => { - // Ignore errors. - }); - } + if (tagName === 'VIDEO' && (this.posterUrl || this.poster)) { // eslint-disable-line deprecation/deprecation + // Handle poster. + // eslint-disable-next-line deprecation/deprecation + this.handleExternalContent('poster', this.posterUrl ?? this.poster ?? '', siteId).catch(() => { + // Ignore errors. + }); } } else { @@ -168,32 +177,11 @@ export class CoreExternalContentDirective implements AfterViewInit, OnChanges, O return; } - // Avoid handling data url's. - if (url && url.indexOf('data:') === 0) { - if (tagName === 'SOURCE') { - // Restoring original src. - this.addSource(url); - } - - this.onLoad.emit(); - this.loaded = true; - this.onReadyPromise.resolve(); - - return; - } - try { await this.handleExternalContent(targetAttr, url, siteId); } catch (error) { - // Error handling content. Make sure the loaded event is triggered for images. - if (tagName === 'IMG') { - if (url) { - this.waitForLoad(); - } else { - this.onLoad.emit(); - this.loaded = true; - } - } + // Error handling content. Make sure the original URL is set. + this.setElementUrl(targetAttr, url); } finally { this.onReadyPromise.resolve(); } @@ -221,13 +209,6 @@ export class CoreExternalContentDirective implements AfterViewInit, OnChanges, O (tagName === 'A' && !(isSiteFile || site.isSiteThemeImageUrl(url) || CoreUrlUtils.isGravatarUrl(url)))) { this.logger.debug('Ignoring non-downloadable URL: ' + url); - if (tagName === 'SOURCE') { - // Restoring original src. - this.addSource(url); - } else if (url && !this.element.getAttribute(targetAttr)) { - // By default, Angular inputs aren't added as DOM attributes. Add it now. - this.element.setAttribute(targetAttr, url); - } throw new CoreError('Non-downloadable URL'); } @@ -241,28 +222,56 @@ export class CoreExternalContentDirective implements AfterViewInit, OnChanges, O const finalUrl = await this.getUrlToUse(targetAttr, url, site); this.logger.debug('Using URL ' + finalUrl + ' for ' + url); - if (tagName === 'SOURCE') { - // The browser does not catch changes in SRC, we need to add a new source. - this.addSource(finalUrl); - } else { - if (tagName === 'IMG') { - this.loaded = false; - this.waitForLoad(); - } - if (targetAttr == 'poster') { - // Setting the poster immediately doesn't display it in some cases. Set it to empty and then set the right one. - this.element.setAttribute(targetAttr, ''); - await CoreUtils.nextTick(); - } - - this.element.setAttribute(targetAttr, finalUrl); - this.element.setAttribute('data-original-' + targetAttr, url); - } + this.setElementUrl(targetAttr, finalUrl); this.setListeners(targetAttr, url, site); } + /** + * Set the URL to the element. + * + * @param targetAttr Name of the attribute to set. + * @param url URL to set. + */ + protected setElementUrl(targetAttr: string, url: string): void { + if (!url) { + // Ignore empty URLs. + if (this.element.tagName === 'IMG') { + this.onLoad.emit(); + this.loaded = true; + } + + return; + } + + if (this.element.tagName === 'SOURCE') { + // The WebView does not detect changes in SRC, we need to add a new source. + this.addSource(url); + } else { + this.element.setAttribute(targetAttr, url); + + const originalUrl = targetAttr === 'poster' ? + (this.posterUrl ?? this.poster) : // eslint-disable-line deprecation/deprecation + (this.url ?? this.src ?? this.href); // eslint-disable-line deprecation/deprecation + if (originalUrl && originalUrl !== url) { + this.element.setAttribute('data-original-' + targetAttr, originalUrl); + } + } + + if (this.element.tagName !== 'IMG') { + return; + } + + if (url.startsWith('data:')) { + this.onLoad.emit(); + this.loaded = true; + } else { + this.loaded = false; + this.waitForLoad(); + } + } + /** * Handle inline styles, trying to download referenced files. * diff --git a/src/core/directives/format-text.ts b/src/core/directives/format-text.ts index fbdf733ae..838096107 100644 --- a/src/core/directives/format-text.ts +++ b/src/core/directives/format-text.ts @@ -180,10 +180,14 @@ export class CoreFormatTextDirective implements OnChanges, OnDestroy, AsyncDirec extContent.component = this.component; extContent.componentId = this.componentId; extContent.siteId = this.siteId; - extContent.src = element.getAttribute('src') || undefined; - extContent.href = element.getAttribute('href') || element.getAttribute('xlink:href') || undefined; - extContent.targetSrc = element.getAttribute('target-src') || undefined; - extContent.poster = element.getAttribute('poster') || undefined; + extContent.url = element.getAttribute('src') ?? element.getAttribute('href') ?? element.getAttribute('xlink:href'); + extContent.posterUrl = element.getAttribute('poster'); + + // Remove the original attributes to avoid performing requests to untreated URLs. + element.removeAttribute('src'); + element.removeAttribute('href'); + element.removeAttribute('xlink:href'); + element.removeAttribute('poster'); extContent.ngAfterViewInit(); @@ -721,6 +725,10 @@ export class CoreFormatTextDirective implements OnChanges, OnDestroy, AsyncDirec * @param isVideo Whether it's a video. */ protected treatMedia(element: HTMLElement, isVideo: boolean = false): void { + if (isVideo) { + this.fixVideoSrcPlaceholder(element); + } + this.addMediaAdaptClass(element); this.addExternalContent(element); @@ -738,18 +746,8 @@ export class CoreFormatTextDirective implements OnChanges, OnDestroy, AsyncDirec const sources = Array.from(element.querySelectorAll('source')); const tracks = Array.from(element.querySelectorAll('track')); - const hasPoster = isVideo && !!element.getAttribute('poster'); - - if (isVideo && !hasPoster) { - this.fixVideoSrcPlaceholder(element); - } sources.forEach((source) => { - if (isVideo && !hasPoster) { - this.fixVideoSrcPlaceholder(source); - } - source.setAttribute('target-src', source.getAttribute('src') || ''); - source.removeAttribute('src'); this.addExternalContent(source); }); @@ -766,19 +764,23 @@ export class CoreFormatTextDirective implements OnChanges, OnDestroy, AsyncDirec /** * Try to fix the placeholder displayed when a video doesn't have a poster. * - * @param element Element to fix. + * @param videoElement Element to fix. */ - protected fixVideoSrcPlaceholder(element: HTMLElement): void { - const src = element.getAttribute('src'); - if (!src) { + protected fixVideoSrcPlaceholder(videoElement: HTMLElement): void { + if (videoElement.getAttribute('poster')) { + // Video has a poster, nothing to fix. return; } - if (src.match(/#t=\d/)) { - return; - } + // Fix the video and its sources. + [videoElement].concat(Array.from(videoElement.querySelectorAll('source'))).forEach((element) => { + const src = element.getAttribute('src'); + if (!src || src.match(/#t=\d/)) { + return; + } - element.setAttribute('src', src + '#t=0.001'); + element.setAttribute('src', src + '#t=0.001'); + }); } /** diff --git a/src/core/features/course/pages/course-summary/course-summary.html b/src/core/features/course/pages/course-summary/course-summary.html index 7902ac903..8606f76ec 100644 --- a/src/core/features/course/pages/course-summary/course-summary.html +++ b/src/core/features/course/pages/course-summary/course-summary.html @@ -17,7 +17,7 @@ </ion-refresher> <core-loading [hideUntil]="dataLoaded"> <div *ngIf="course" class="core-course-thumb" #courseThumb> - <img *ngIf="course.courseimage" [src]="course.courseimage" core-external-content alt="" (error)="loadFallbackCourseIcon()" /> + <img *ngIf="course.courseimage" [url]="course.courseimage" core-external-content alt="" (error)="loadFallbackCourseIcon()" /> <ion-icon *ngIf="!course.courseimage" name="fas-graduation-cap" class="course-icon" aria-hidden="true" /> </div> <div *ngIf="course" class="course-container"> diff --git a/src/core/features/course/pages/index/index.html b/src/core/features/course/pages/index/index.html index 5b17a3397..7b094c098 100644 --- a/src/core/features/course/pages/index/index.html +++ b/src/core/features/course/pages/index/index.html @@ -25,7 +25,7 @@ <ion-icon name="fas-graduation-cap" class="course-icon" aria-hidden="true" /> </div> <ion-avatar *ngIf="course.courseimage" slot="start" class="core-course-thumb"> - <img [src]="course.courseimage" core-external-content alt="" /> + <img [url]="course.courseimage" core-external-content alt="" /> </ion-avatar> </ng-container> diff --git a/src/core/features/courses/components/course-list-item/core-courses-course-list-item.html b/src/core/features/courses/components/course-list-item/core-courses-course-list-item.html index 777234016..d2002eda9 100644 --- a/src/core/features/courses/components/course-list-item/core-courses-course-list-item.html +++ b/src/core/features/courses/components/course-list-item/core-courses-course-list-item.html @@ -3,7 +3,7 @@ button [attr.aria-label]="course.displayname || course.fullname"> <div *ngIf="layout === 'card' || layout === 'summarycard'" class="core-course-thumb" [class.core-course-color-img]="course.courseimage"> - <img *ngIf="course.courseimage" [src]="course.courseimage" core-external-content alt="" (error)="loadFallbackCourseIcon()" /> + <img *ngIf="course.courseimage" [url]="course.courseimage" core-external-content alt="" (error)="loadFallbackCourseIcon()" /> <ion-icon *ngIf="!course.courseimage" name="fas-graduation-cap" class="course-icon" aria-hidden="true" /> </div> @@ -32,7 +32,7 @@ <ion-icon *ngIf="!course.courseimage" name="fas-graduation-cap" slot="start" class="course-icon core-course-thumb" aria-hidden="true" /> <ion-avatar *ngIf="course.courseimage" slot="start" class="core-course-thumb"> - <img [src]="course.courseimage" core-external-content alt="" (error)="loadFallbackCourseIcon()" /> + <img [url]="course.courseimage" core-external-content alt="" (error)="loadFallbackCourseIcon()" /> </ion-avatar> </ng-container> diff --git a/src/core/features/search/components/global-search-result/global-search-result.html b/src/core/features/search/components/global-search-result/global-search-result.html index b1cc66ea8..321f4854c 100644 --- a/src/core/features/search/components/global-search-result/global-search-result.html +++ b/src/core/features/search/components/global-search-result/global-search-result.html @@ -6,7 +6,7 @@ <ion-icon *ngIf="renderedIcon" [name]="renderedIcon" aria-hidden="true" /> <core-mod-icon *ngIf="!renderedIcon && result.module" [modicon]="result.module.iconurl" [modname]="result.module.name" [colorize]="false" /> - <img *ngIf="!renderedIcon && !result.module && result.component" [src]="result.component.iconurl" alt="" class="result-icon" + <img *ngIf="!renderedIcon && !result.module && result.component" [url]="result.component.iconurl" alt="" class="result-icon" core-external-content [component]="result.component.name"> <core-format-text [text]="result.title" /> </h3> diff --git a/src/core/features/viewer/components/image/image.html b/src/core/features/viewer/components/image/image.html index b3ba23c73..ef485fcb6 100644 --- a/src/core/features/viewer/components/image/image.html +++ b/src/core/features/viewer/components/image/image.html @@ -2,7 +2,7 @@ <swiper-container #swiperRef> <swiper-slide> <div class="swiper-zoom-container"> - <img [src]="image" [alt]="title" core-external-content [component]="component" [componentId]="componentId"> + <img [url]="image" [alt]="title" core-external-content [component]="component" [componentId]="componentId"> </div> </swiper-slide> </swiper-container>