diff --git a/libs/ui/elements/src/lib/thumbnail/thumbnail.component.html b/libs/ui/elements/src/lib/thumbnail/thumbnail.component.html index 7f6cb1b07c..58a5e84fb5 100644 --- a/libs/ui/elements/src/lib/thumbnail/thumbnail.component.html +++ b/libs/ui/elements/src/lib/thumbnail/thumbnail.component.html @@ -8,11 +8,12 @@ thumbnail diff --git a/libs/ui/elements/src/lib/thumbnail/thumbnail.component.spec.ts b/libs/ui/elements/src/lib/thumbnail/thumbnail.component.spec.ts index b5aaef911f..6679330e40 100644 --- a/libs/ui/elements/src/lib/thumbnail/thumbnail.component.spec.ts +++ b/libs/ui/elements/src/lib/thumbnail/thumbnail.component.spec.ts @@ -39,7 +39,7 @@ describe('ThumbnailComponent', () => { describe('When no url is given', () => { let img beforeEach(fakeAsync(() => { - component.thumbnailUrl = undefined + component.thumbnailUrl = null fixture.detectChanges() img = de.query(By.css('img')) tick(10) @@ -145,7 +145,7 @@ describe('ThumbnailComponent', () => { let img beforeEach(() => { component.placeholderUrl = placeholderUrl - component.thumbnailUrl = undefined + component.thumbnailUrl = null fixture.detectChanges() img = de.query(By.css('img')) }) @@ -175,4 +175,52 @@ describe('ThumbnailComponent', () => { expect(img.nativeElement.style.objectFit).toEqual('scale-down') }) }) + + describe('thumbnail image url returns 404 and organisation logo exists', () => { + const url = 'http://test.com/img.png' + const orgLogoUrl = 'http://test.com/orgLogo.png' + const placeholderUrl = 'http://localhost/assets/img/placeholder.png' + let img + beforeEach(() => { + component.thumbnailUrl = [url, orgLogoUrl] + component.fit = ['cover', 'contain'] + component.placeholderUrl = placeholderUrl + fixture.detectChanges() + img = de.query(By.css('img')) + img.nativeElement.dispatchEvent(new Event('error')) + fixture.detectChanges() + }) + it('displays organisation logo', () => { + expect(img.nativeElement.src).toEqual(orgLogoUrl) + expect(img.nativeElement.style.objectFit).toEqual('contain') + }) + + describe('if organisation logo also returns 404', () => { + beforeEach(() => { + img.nativeElement.dispatchEvent(new Event('error')) + fixture.detectChanges() + }) + it('displays placeholder', () => { + expect(img.nativeElement.src).toEqual(placeholderUrl) + expect(img.nativeElement.style.objectFit).toEqual('scale-down') + }) + }) + }) + describe('thumbnail image url returns 404 and no organisation logo', () => { + const url = 'http://test.com/img.png' + const placeholderUrl = 'http://localhost/assets/img/placeholder.png' + let img + beforeEach(() => { + component.thumbnailUrl = url + component.placeholderUrl = placeholderUrl + fixture.detectChanges() + img = de.query(By.css('img')) + img.nativeElement.dispatchEvent(new Event('error')) + fixture.detectChanges() + }) + + it('displays placeholder', () => { + expect(img.nativeElement.src).toEqual(placeholderUrl) + }) + }) }) diff --git a/libs/ui/elements/src/lib/thumbnail/thumbnail.component.ts b/libs/ui/elements/src/lib/thumbnail/thumbnail.component.ts index fbc3c5e171..7e0d55ece1 100644 --- a/libs/ui/elements/src/lib/thumbnail/thumbnail.component.ts +++ b/libs/ui/elements/src/lib/thumbnail/thumbnail.component.ts @@ -1,69 +1,95 @@ import { - AfterViewInit, ChangeDetectionStrategy, - ChangeDetectorRef, Component, ElementRef, Inject, InjectionToken, Input, - OnDestroy, + OnChanges, + OnInit, Optional, + SimpleChanges, ViewChild, } from '@angular/core' -import { fromEvent, Subscription } from 'rxjs' export const THUMBNAIL_PLACEHOLDER = new InjectionToken( 'thumbnail-placeholder' ) +type ThumbnailImageObject = { + url: string + fit?: 'cover' | 'contain' | 'scale-down' +} + const DEFAULT_PLACEHOLDER = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGAAAABgCAYAAADimHc4AAAABmJLR0QA/wD/AP+gvaeTAAAACXBIWXMAAA3XAAAN1wFCKJt4AAAAB3RJTUUH5gkNDCUFYjA1nwAAA1pJREFUeNrtnW2TmjAURh8CLlTdrmun///3tZ22+zLuYlehH7jsMGogwRiiec4MM44K6D3x3hAwAIQQQgghhJDYSM5cPwNQAMgBpACUg22GTg2gArAD8A9AKY+9CsgALAF8YRsGALwDeAWw9yGgALCKoKWP+WU8iwxjUsudLBj83sZciIiPSwhoWz7pJ5dUZFQXlEXOZ/DNeTBt3JnhBpc9aacGsOn0BuoIUk3b+5trGnEC4B7Ak4sUlInRU+wB/JbgVxG18KrTBc01EmYmcTFJQUVPy/9zTh/4BthLDOqeenB2DdBtZBN58LsSNpcUoEtTJWM/GIvMhQDde9j6h2OhXAjo6/2Q/lgkLgSQC0IBFEABZEKyiaQv5AAv7fSlS+lPVxRwOXTnEtoTPAs04yfRHGMoz8F/HOiaJfKeggLc78dmOHsVS33y9SUXsDuLlsg6FOAw/fhYhwI0pJ7WoQASpoC9p3UoQEPpaR0K0LCB3fB1e6KfAhxRweAKgQ5PsQxJ+CzCJYC/A7+EWt4TzVCE77GgEsBPHA/G7QBswcE4b+noVRZ2QxkCCqAAQgEUQCiAAggFUAChAAogFEABhAJcfT9FAdOxQuB/ML9lAfdo/qWYy2MK8EiO5mrrliUCvdIudAEzWWzQzWuxwjRnAK9WwAzAWhZTCe3l7cryNQrQBL/txZhKGGrlwc36ogIPfvdzfhuQsDDM80EVZXUFwe+mEJ2EOwBfLfYTTFFWVxL8Qwl3nedSye1jjhEyCjAPflfCWiScU1iDKMrqyoJ/KOFxRDf1sCg/xCxgTPC7EnIHn6GYsiirKw2+ayYryorBn7YoKwb/qCgntywg1OBPdqSsGPyTRXnp07gvPgD8AAl6KIICCAVQAAlLwOg5MSNi9NyqJgKqAHpQoZNZxs5KgG7SDN7AZzgWOxcCtprn5/wVfLb+uWXsrASUPXlvHbmETGKQjBVgMitVJTuaaQS2t/GoEMeE3onEor2jlK4RvwN4G1u9T4n6zp6PMTWAXzCYdCq12OCOhdeYZzT3mIErAW1Fr+HmNOAt82KSesYIAJoRzR2aIVumo+Ms8WwT/HOOZlM0Y+Zzxv2zp/gCTzfzPOyGtdfgp7LEcDvbvSxbWXg/HUIIIYQQQogx/wHLoX7NoCMFPwAAAABJRU5ErkJggg==' +type FitOptions = 'cover' | 'contain' | 'scale-down' + @Component({ selector: 'gn-ui-thumbnail', templateUrl: './thumbnail.component.html', changeDetection: ChangeDetectionStrategy.OnPush, }) -export class ThumbnailComponent implements AfterViewInit, OnDestroy { - @Input() set thumbnailUrl(url: string) { - this.imgUrl = url || this.placeholderUrl - this.isPlaceholder = !url - } - @Input() fit: 'cover' | 'contain' | 'scale-down' = 'cover' +export class ThumbnailComponent implements OnInit, OnChanges { + @Input() thumbnailUrl: string | string[] + @Input() fit: FitOptions | FitOptions[] = 'cover' @ViewChild('imageElement') imgElement: ElementRef @ViewChild('containerElement') containerElement: ElementRef imgUrl: string + imgFit: FitOptions placeholderUrl = this.optionalPlaceholderUrl || DEFAULT_PLACEHOLDER isPlaceholder = false - sub: Subscription - - get objectFit() { - return this.isPlaceholder ? 'scale-down' : this.fit - } + private images: ThumbnailImageObject[] = [] constructor( @Optional() @Inject(THUMBNAIL_PLACEHOLDER) - private optionalPlaceholderUrl: string, - private changeDetector: ChangeDetectorRef + private optionalPlaceholderUrl: string ) {} - ngAfterViewInit() { - this.sub = fromEvent(this.imgElement.nativeElement, 'error').subscribe(() => - this.useFallback() - ) + ngOnInit() { + this.updateImageList() + } + + ngOnChanges(changes: SimpleChanges): void { + if (!('thumbnailUrl' in changes) && !('fit' in changes)) { + return + } + this.updateImageList() + } + + private updateImageList() { + if (!this.thumbnailUrl) { + this.setPlaceholder() + return + } + const urls = Array.isArray(this.thumbnailUrl) + ? this.thumbnailUrl + : [this.thumbnailUrl] + this.images = urls.map((url, index) => ({ + url, + fit: (Array.isArray(this.fit) ? this.fit[index] : this.fit) || 'cover', + })) + this.setNewSrcImage(this.images[0]) + } + + private setNewSrcImage(image: ThumbnailImageObject) { + this.imgFit = image.fit + this.imgUrl = image.url } - ngOnDestroy() { - this.sub.unsubscribe() + private setPlaceholder(): void { + this.isPlaceholder = true + this.setNewSrcImage({ url: this.placeholderUrl, fit: 'scale-down' }) } useFallback() { - if (!this.isPlaceholder) { - this.isPlaceholder = true - this.imgUrl = this.placeholderUrl - this.changeDetector.detectChanges() + if (this.images.length > 1) { + this.images.shift() + this.setNewSrcImage(this.images[0]) + } else { + this.setPlaceholder() } } @@ -74,7 +100,7 @@ export class ThumbnailComponent implements AfterViewInit, OnDestroy { this.imgElement.nativeElement.naturalWidth < cw && this.imgElement.nativeElement.naturalHeight < ch ) { - this.fit = 'scale-down' + this.imgFit = 'scale-down' } } } diff --git a/libs/ui/search/src/lib/record-preview-row/record-preview-row.component.html b/libs/ui/search/src/lib/record-preview-row/record-preview-row.component.html index d4bdc7f9c1..3fdc6362fc 100644 --- a/libs/ui/search/src/lib/record-preview-row/record-preview-row.component.html +++ b/libs/ui/search/src/lib/record-preview-row/record-preview-row.component.html @@ -9,8 +9,8 @@ > diff --git a/libs/ui/search/src/lib/record-preview/record-preview.component.ts b/libs/ui/search/src/lib/record-preview/record-preview.component.ts index 18cfe25ef7..66c2eb38a2 100644 --- a/libs/ui/search/src/lib/record-preview/record-preview.component.ts +++ b/libs/ui/search/src/lib/record-preview/record-preview.component.ts @@ -1,11 +1,11 @@ import { Component, - Input, - Output, + ElementRef, EventEmitter, - OnInit, + Input, OnDestroy, - ElementRef, + OnInit, + Output, TemplateRef, } from '@angular/core' import { diff --git a/libs/util/app-config/src/lib/app-config.ts b/libs/util/app-config/src/lib/app-config.ts index 5013f66fe6..68644108ed 100644 --- a/libs/util/app-config/src/lib/app-config.ts +++ b/libs/util/app-config/src/lib/app-config.ts @@ -50,9 +50,6 @@ let customTranslations: CustomTranslationsAllLanguages = null export function getCustomTranslations(langCode: string): CustomTranslations { if (customTranslations === null) throw new Error(MISSING_CONFIG_ERROR) - console.log( - langCode in customTranslations ? customTranslations[langCode] : {} - ) return langCode in customTranslations ? customTranslations[langCode] : {} }