Skip to content

Commit 68c1c2a

Browse files
[UXP-205] port glam implementation for grid section bg, adapt tests
1 parent 9886cb0 commit 68c1c2a

5 files changed

Lines changed: 112 additions & 13 deletions

File tree

src/app/shared/explore/section-component/grid-section/grid-section.component.html

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,8 @@ <h1 class="text-dark main-content-subtitle">
1414
</div>
1515
<div class="bg-light text-center position-relative border border-dark d-flex flex-column
1616
justify-content-between align-items-center"
17+
[dsBackgroundImage]="(itemToImageHrefMap$ | async).get(item.indexableObject?.uuid)"
1718
*ngFor="let item of searchResults | slice:0:8; index as i">
18-
<ds-thumbnail [thumbnail]="item.indexableObject?.thumbnail | async" [limitWidth]="false"
19-
[defaultImage]="'assets/images/replacement_image.svg'"
20-
[alt]="'menu.header.image.logo' | translate" [keepAspectRatio]="true">
21-
</ds-thumbnail>
2219
<h5 class="text-dark text-truncate position-absolute py-3 px-1">{{item.indexableObject?.firstMetadataValue('dc.title')}}</h5>
2320
</div>
2421
</div>

src/app/shared/explore/section-component/grid-section/grid-section.component.spec.ts

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { CommonModule } from '@angular/common';
2-
import { NO_ERRORS_SCHEMA } from '@angular/core';
2+
import { ChangeDetectorRef, NO_ERRORS_SCHEMA } from '@angular/core';
33
import { ComponentFixture, inject, TestBed, waitForAsync } from '@angular/core/testing';
44
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
55
import { BrowserModule } from '@angular/platform-browser';
@@ -17,6 +17,17 @@ import { createSuccessfulRemoteDataObject$ } from '../../../remote-data.utils';
1717
import { LocaleService } from '../../../../core/locale/locale.service';
1818
import { Site } from '../../../../core/shared/site.model';
1919
import { of } from 'rxjs';
20+
import { ObjectCacheService } from '../../../../core/cache/object-cache.service';
21+
import { getMockObjectCacheService } from '../../../mocks/object-cache.service.mock';
22+
import { UUIDService } from '../../../../core/shared/uuid.service';
23+
import { getMockUUIDService } from '../../../mocks/uuid.service.mock';
24+
import { provideMockStore } from '@ngrx/store/testing';
25+
import { RemoteDataBuildService } from '../../../../core/cache/builders/remote-data-build.service';
26+
import { getMockRemoteDataBuildService } from '../../../mocks/remote-data-build.service.mock';
27+
import { HALEndpointService } from '../../../../core/shared/hal-endpoint.service';
28+
import { DSOChangeAnalyzer } from '../../../../core/data/dso-change-analyzer.service';
29+
import { BitstreamFormatDataService } from '../../../../core/data/bitstream-format-data.service';
30+
import { NotificationsService } from '../../../notifications/notifications.service';
2031

2132
describe('GridSectionComponent', () => {
2233
let component: GridSectionComponent;
@@ -81,6 +92,19 @@ describe('GridSectionComponent', () => {
8192
providers: [GridSectionComponent,
8293
{ provide: SearchService, useValue: searchServiceStub },
8394
{ provide: LocaleService, useValue: mockLocaleService },
95+
{ provide: ObjectCacheService, useValue: getMockObjectCacheService() },
96+
{ provide: UUIDService, useValue: getMockUUIDService() },
97+
{ provide: RemoteDataBuildService, useValue: getMockRemoteDataBuildService() },
98+
{ provide: HALEndpointService, useValue: {} },
99+
{ provide: DSOChangeAnalyzer, useValue: {} },
100+
{ provide: BitstreamFormatDataService, useValue: {} },
101+
{ provide: NotificationsService, useValue: {} },
102+
{
103+
provide: ChangeDetectorRef, useValue: {
104+
detectChanges: () => fixture.detectChanges()
105+
}
106+
},
107+
provideMockStore({ core: { auth: { loading: false } } } as any),
84108
],
85109
schemas: [NO_ERRORS_SCHEMA]
86110
}).compileComponents();

src/app/shared/explore/section-component/grid-section/grid-section.component.ts

Lines changed: 50 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
import { LayoutModeEnum, GridSection } from '../../../../core/layout/models/section.model';
2-
import { Component, Input, OnInit } from '@angular/core';
1+
import { GridSection } from '../../../../core/layout/models/section.model';
2+
import { ChangeDetectorRef, Component, Input, OnInit } from '@angular/core';
33

44
import { SortDirection, SortOptions } from '../../../../core/cache/models/sort-options.model';
55
import { PaginationComponentOptions } from '../../../pagination/pagination-component-options.model';
@@ -16,6 +16,12 @@ import { Site } from '../../../../core/shared/site.model';
1616
import { LocaleService } from '../../../../core/locale/locale.service';
1717
import { Router } from '@angular/router';
1818
import { TranslateService } from '@ngx-translate/core';
19+
import { BehaviorSubject, filter, from, map, mergeMap, scan, switchMap, take } from 'rxjs';
20+
import { BitstreamDataService } from 'src/app/core/data/bitstream-data.service';
21+
import { Item } from 'src/app/core/shared/item.model';
22+
import { Bitstream } from 'src/app/core/shared/bitstream.model';
23+
import { BitstreamFormat } from 'src/app/core/shared/bitstream-format.model';
24+
import { hasValue } from 'src/app/shared/empty.util';
1925

2026
/**
2127
* Component representing the Grid component section.
@@ -41,8 +47,6 @@ export class GridSectionComponent implements OnInit {
4147

4248
paginatedSearchOptions: PaginatedSearchOptions;
4349

44-
layoutMode: LayoutModeEnum = LayoutModeEnum.CARD;
45-
4650
maincontentBadge: string;
4751

4852
maincontentTitle: string;
@@ -53,13 +57,17 @@ export class GridSectionComponent implements OnInit {
5357

5458
maincontentLink: string;
5559

56-
searchResults;
60+
searchResults: SearchResult<DSpaceObject>[];
61+
62+
itemToImageHrefMap$ = new BehaviorSubject<Map<string, string>>(new Map<string, string>());
5763

5864
constructor(
5965
private searchService: SearchService,
6066
private locale: LocaleService,
6167
private router: Router,
62-
private translateService: TranslateService
68+
private translateService: TranslateService,
69+
private bitstreamDataService: BitstreamDataService,
70+
private cdr: ChangeDetectorRef
6371
) {
6472
}
6573

@@ -111,11 +119,46 @@ export class GridSectionComponent implements OnInit {
111119
.pipe(getFirstCompletedRemoteData())
112120
.subscribe(
113121
(response: RemoteData<PaginatedList<SearchResult<DSpaceObject>>>) => {
114-
this.searchResults = response.payload.page as any;
122+
this.searchResults = response.payload.page;
123+
this.getAllBitstreams();
115124
}
116125
);
117126
}
118127

128+
private getAllBitstreams() {
129+
from(this.searchResults).pipe(
130+
map((itemSR) => itemSR.indexableObject),
131+
mergeMap((item: Item) => this.bitstreamDataService.showableByItem(
132+
item.uuid, 'ORIGINAL', [], {}, true, true, followLink('format')
133+
).pipe(
134+
getFirstCompletedRemoteData(),
135+
switchMap((rd: RemoteData<PaginatedList<Bitstream>>) => rd.hasSucceeded ? rd.payload.page : []),
136+
mergeMap((bitstream: Bitstream) => bitstream.format.pipe(
137+
getFirstCompletedRemoteData(),
138+
filter((formatRemoteData: RemoteData<BitstreamFormat>) =>
139+
formatRemoteData.hasSucceeded && hasValue(formatRemoteData.payload) && hasValue(bitstream) &&
140+
formatRemoteData.payload.mimetype.includes('image/')
141+
),
142+
map(() => bitstream)
143+
)),
144+
take(1),
145+
map((bitstream: Bitstream) => {
146+
return [item.uuid, bitstream._links.content.href];
147+
})
148+
)
149+
),
150+
scan((acc: Map<string, string>, value: [string, string]) => {
151+
acc.set(value[0], value[1]);
152+
return acc;
153+
}, new Map<string, string>())
154+
).subscribe((res) => {
155+
this.itemToImageHrefMap$.next(res);
156+
this.cdr.detectChanges();
157+
});
158+
159+
}
160+
161+
119162
goToMainContentLink() {
120163
this.router.navigateByUrl(this.maincontentLink);
121164
}

src/app/shared/shared.module.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -364,6 +364,7 @@ import { CardsBrowseElementsComponent } from './browse-most-elements/cards-brows
364364
import {
365365
ThemedCardsBrowseElementsComponent
366366
} from './browse-most-elements/cards-browse-elements/themed-cards-browse-elements.component';
367+
import { BackgroundImageDirective } from './utils/background-image.directive';
367368

368369
const MODULES = [
369370
CommonModule,
@@ -637,7 +638,8 @@ const DIRECTIVES = [
637638
ContextHelpDirective,
638639
EntityIconDirective,
639640
MarkdownDirective,
640-
StickyPopoverDirective
641+
StickyPopoverDirective,
642+
BackgroundImageDirective
641643
];
642644

643645
@NgModule({
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
import { Directive, ElementRef, Input, OnChanges, SimpleChanges } from '@angular/core';
2+
import { Bitstream } from '../../core/shared/bitstream.model';
3+
import { RemoteData } from '../../core/data/remote-data';
4+
5+
@Directive({
6+
selector: '[dsBackgroundImage]'
7+
})
8+
export class BackgroundImageDirective implements OnChanges {
9+
10+
@Input() dsBackgroundImage: Bitstream | RemoteData<Bitstream> | string;
11+
12+
constructor(private el: ElementRef) {
13+
}
14+
15+
ngOnChanges(changes: SimpleChanges) {
16+
this.setBackground();
17+
}
18+
19+
private setBackground() {
20+
let thumbnailSrc: string;
21+
if (this.dsBackgroundImage instanceof Bitstream) {
22+
thumbnailSrc = this.dsBackgroundImage?._links?.content?.href;
23+
} else if (this.dsBackgroundImage instanceof RemoteData) {
24+
thumbnailSrc = this.dsBackgroundImage?.payload?._links?.content?.href;
25+
} else {
26+
thumbnailSrc = this.dsBackgroundImage;
27+
}
28+
this.el.nativeElement.style.backgroundImage = `url("${thumbnailSrc ?? 'assets/images/replacement_image.svg'}")`;
29+
this.el.nativeElement.style.backgroundPosition = `center`;
30+
this.el.nativeElement.style.backgroundSize = `cover`;
31+
this.el.nativeElement.style.backgroundRepeat = `no-repeat`;
32+
}
33+
}

0 commit comments

Comments
 (0)