Skip to content

Commit 8c5b648

Browse files
[DSC-2309] refactor solution to common util
1 parent 1cf62ae commit 8c5b648

5 files changed

Lines changed: 64 additions & 35 deletions

File tree

src/app/core/shared/image.utils.ts

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
import { Observable, of } from 'rxjs';
2+
import { map } from 'rxjs/operators';
3+
4+
export const getDefaultImageUrlByEntityType = (entityType: string): Observable<string> => {
5+
const fallbackImage = 'assets/images/file-placeholder.svg';
6+
7+
if (!entityType) {
8+
return of(fallbackImage);
9+
}
10+
11+
const defaultImage = `assets/images/${entityType.toLowerCase()}-placeholder.svg`;
12+
return checkImageExists(defaultImage).pipe(map((exists) => exists ? defaultImage : fallbackImage));
13+
};
14+
15+
const checkImageExists = (url: string): Observable<boolean> => {
16+
return new Observable<boolean>((observer) => {
17+
const img = new Image();
18+
19+
img.onload = () => {
20+
observer.next(true);
21+
observer.complete();
22+
};
23+
24+
img.onerror = () => {
25+
observer.next(false);
26+
observer.complete();
27+
};
28+
29+
img.src = url;
30+
});
31+
};

src/app/cris-layout/cris-layout-matrix/cris-layout-box-container/boxes/metadata/rendering-types/thumbnail/thumbnail.component.ts

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import {
1515
import {
1616
map,
1717
switchMap,
18+
take
1819
} from 'rxjs/operators';
1920

2021
import { BitstreamDataService } from '../../../../../../../core/data/bitstream-data.service';
@@ -30,6 +31,7 @@ import {
3031
} from '../../../../../../../shared/empty.util';
3132
import { ThemedThumbnailComponent } from '../../../../../../../thumbnail/themed-thumbnail.component';
3233
import { BitstreamRenderingModelComponent } from '../bitstream-rendering-model';
34+
import { getDefaultImageUrlByEntityType } from '../../../../../../../core/shared/image.utils';
3335

3436
@Component({
3537
// eslint-disable-next-line @angular-eslint/component-selector, dspace-angular-ts/themed-component-selectors
@@ -119,13 +121,8 @@ export class ThumbnailRenderingComponent extends BitstreamRenderingModelComponen
119121
*/
120122
setDefaultImage(): void {
121123
const eType = this.item.firstMetadataValue('dspace.entity.type');
122-
this.default = 'assets/images/file-placeholder.svg';
123-
if (hasValue(eType) && eType.toUpperCase() === 'PROJECT') {
124-
this.default = 'assets/images/project-placeholder.svg';
125-
} else if (hasValue(eType) && eType.toUpperCase() === 'ORGUNIT') {
126-
this.default = 'assets/images/orgunit-placeholder.svg';
127-
} else if (hasValue(eType) && eType.toUpperCase() === 'PERSON') {
128-
this.default = 'assets/images/person-placeholder.svg';
129-
}
124+
getDefaultImageUrlByEntityType(eType).pipe(take(1)).subscribe((url) => {
125+
this.default = url;
126+
});
130127
}
131128
}

src/app/shared/metadata-link-view/metadata-link-view-avatar-popover/metadata-link-view-avatar-popover.component.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,6 @@
1010
<img *ngIf="src !== null" class="thumbnail-content img-fluid" [ngClass]="{'d-none': isLoading}"
1111
[src]="src | dsSafeUrl" [alt]="alt | translate" (error)="errorHandler()" (load)="successHandler()">
1212
<div *ngIf="src === null && !isLoading" class="thumbnail-content outer" #thumbnailBox>
13-
<img [src]="placeholderImageUrl" [alt]="placeholder | translate" (error)="onImageError($event)">
13+
<img [src]="placeholderImageUrl$ | async" [alt]="placeholder | translate">
1414
</div>
1515
</div>

src/app/shared/metadata-link-view/metadata-link-view-avatar-popover/metadata-link-view-avatar-popover.component.spec.ts

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -63,9 +63,29 @@ describe('MetadataLinkViewAvatarPopoverComponent', () => {
6363
expect(component).toBeTruthy();
6464
});
6565

66-
it('should set placeholder image based on entity type', () => {
67-
component.entityType = 'testEntityType';
66+
it('should set fallback image if no entity type', (done) => {
6867
component.ngOnInit();
69-
expect(component.placeholderImageUrl).toBe('assets/images/testentitytype-placeholder.svg');
68+
component.placeholderImageUrl$.subscribe((url) => {
69+
expect(url).toBe('assets/images/file-placeholder.svg');
70+
done();
71+
});
72+
});
73+
74+
it('should set correct placeholder image based on entity type if image exists', (done) => {
75+
component.entityType = 'OrgUnit';
76+
component.ngOnInit();
77+
component.placeholderImageUrl$.subscribe((url) => {
78+
expect(url).toBe('assets/images/orgunit-placeholder.svg');
79+
done();
80+
});
81+
});
82+
83+
it('should set correct fallback image if image does not exists', (done) => {
84+
component.entityType = 'missingEntityType';
85+
component.ngOnInit();
86+
component.placeholderImageUrl$.subscribe((url) => {
87+
expect(url).toBe('assets/images/file-placeholder.svg');
88+
done();
89+
});
7090
});
7191
});

src/app/shared/metadata-link-view/metadata-link-view-avatar-popover/metadata-link-view-avatar-popover.component.ts

Lines changed: 4 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ import {
1010
} from '@angular/core';
1111
import { TranslateModule } from '@ngx-translate/core';
1212
import { ThumbnailComponent } from 'src/app/thumbnail/thumbnail.component';
13+
import { getDefaultImageUrlByEntityType } from '../../../core/shared/image.utils';
14+
import { Observable } from 'rxjs';
1315

1416
import { ThemedLoadingComponent } from '../../loading/themed-loading.component';
1517
import { SafeUrlPipe } from '../../utils/safe-url-pipe';
@@ -32,39 +34,18 @@ import { VarDirective } from '../../utils/var.directive';
3234
})
3335
export class MetadataLinkViewAvatarPopoverComponent extends ThumbnailComponent implements OnInit {
3436

35-
/**
36-
* The fallback image to use when the thumbnail is not available
37-
*/
38-
fallbackImageUrl = 'assets/images/replacement_image.svg';
3937

4038
/**
4139
* Placeholder image url that changes based on entity type
4240
*/
43-
placeholderImageUrl: string;
41+
placeholderImageUrl$: Observable<string>;
4442

4543
/**
4644
* The entity type of the item which the avatar belong
4745
*/
4846
@Input() entityType: string;
4947

5048
ngOnInit() {
51-
this.placeholderImageUrl = this.entityType ? `assets/images/${this.entityType.toLowerCase()}-placeholder.svg` : this.fallbackImageUrl;
52-
}
53-
54-
/**
55-
* Handle error loading image placeholder, e.g. missing placeholder image for specific entity type.
56-
* @param event
57-
*/
58-
onImageError(event: Event) {
59-
const target = event.target as HTMLImageElement;
60-
target.src = this.fallbackImageUrl;
61-
}
62-
63-
/**
64-
* set loading to true to prevent glitch of img with null src
65-
*/
66-
errorHandler() {
67-
this.isLoading = true;
68-
super.errorHandler();
49+
this.placeholderImageUrl$ = getDefaultImageUrlByEntityType(this.entityType);
6950
}
7051
}

0 commit comments

Comments
 (0)