Skip to content

Commit 467ec0b

Browse files
[UXP-34] implement carousel support for pagination
1 parent 258f739 commit 467ec0b

7 files changed

Lines changed: 279 additions & 116 deletions

File tree

src/app/shared/carousel/carousel-options.model.ts

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import { SortDirection } from '../../core/cache/models/sort-options.model';
2+
13
export interface CarouselOptions {
24
/**
35
* The title of the item
@@ -58,4 +60,27 @@ export interface CarouselOptions {
5860
* Classes to be applied to the bundle
5961
*/
6062
bundle: string;
63+
64+
/**
65+
* The discovery configuration name for search results
66+
*/
67+
discoveryConfiguration: string;
68+
/**
69+
* The search sortOrder
70+
*/
71+
order: string;
72+
/**
73+
* The search sortField
74+
*/
75+
sortField: string;
76+
77+
/**
78+
* The search sort direction
79+
*/
80+
sortDirection: SortDirection;
81+
82+
/**
83+
* The number of items to be searched
84+
*/
85+
numberOfItems: number;
6186
}
Lines changed: 71 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,41 +1,79 @@
1-
<ngb-carousel #carousel [interval]="2000" (slide)="onSlide($event)" class="ds-carousel">
2-
<ng-template ngbSlide *ngFor="let item of items; let i = index; let last = last">
3-
<ng-container *ngIf="getItemLink(item.indexableObject); let currentLink; else carouselContent">
4-
<a *ngIf="isLinkInternal(currentLink)" [routerLink]="currentLink">
5-
<ng-container *ngTemplateOutlet="carouselContent"></ng-container>
6-
</a>
7-
<a *ngIf="!isLinkInternal(currentLink)" [href]="currentLink" [target]="carouselOptions.targetBlank ? '_blank' : null">
8-
<ng-container *ngTemplateOutlet="carouselContent"></ng-container>
9-
</a>
10-
</ng-container>
11-
<ng-template #carouselContent>
12-
<div class="carousel-content-wrapper"
13-
[ngStyle]="{
1+
<div *ngIf="!(isLoading$ | async) && itemList?.length > 0">
2+
<ngb-carousel #carousel [interval]="2000" (slide)="onSlide($event)" class="ds-carousel">
3+
<ng-template ngbSlide *ngFor="let item of currentPageItems(); let i = index; let last = last">
4+
<ng-container *ngIf="getItemLink(item.indexableObject); let currentLink; else carouselContent">
5+
<a *ngIf="isLinkInternal(currentLink)" [routerLink]="currentLink">
6+
<ng-container *ngTemplateOutlet="carouselContent"></ng-container>
7+
</a>
8+
<a *ngIf="!isLinkInternal(currentLink)" [href]="currentLink" [target]="carouselOptions.targetBlank ? '_blank' : null">
9+
<ng-container *ngTemplateOutlet="carouselContent"></ng-container>
10+
</a>
11+
</ng-container>
12+
<ng-template #carouselContent>
13+
<div class="carousel-content-wrapper"
14+
[ngStyle]="{
1415
'height': carouselOptions.keepAspectRatio ? null : carouselOptions.carouselHeightPx + 'px',
1516
'aspect-ratio': carouselOptions.keepAspectRatio ? carouselOptions.aspectRatio : null
1617
}">
17-
<div class="picsum-img-wrapper" *ngIf="(itemToImageHrefMap$ | async).get(item.indexableObject.uuid); let href">
18-
<img [src]="href" [alt]="item.indexableObject.metadata[title][0].value" class="img-fluid"
19-
[ngClass]="{'w-100': carouselOptions.fitWidth, 'h-100': carouselOptions.fitHeight}">
20-
</div>
21-
<div class="carousel-caption">
22-
<div class="carousel-caption-inner">
23-
<h3 data-test="carouselObjTitle" [class]="carouselOptions.titleStyle"
24-
*ngIf="item.indexableObject.metadata[title]">
25-
{{item.indexableObject.metadata[title][0].value}}</h3>
26-
<div data-test="carouselObjDesc" class="carousel-caption-text pr-3 pl-2" [class]="carouselOptions.captionStyle"
27-
*ngIf="item.indexableObject.metadata[description]; let descriptionObj">
28-
{{descriptionObj[0].value}}
18+
<div class="picsum-img-wrapper" *ngIf="(itemToImageHrefMap$ | async).get(item.indexableObject.uuid); let href">
19+
<img [src]="href" [alt]="item.indexableObject.metadata[title][0].value" class="img-fluid"
20+
[ngClass]="{'w-100': carouselOptions.fitWidth, 'h-100': carouselOptions.fitHeight}">
21+
</div>
22+
<div class="carousel-caption">
23+
<div class="carousel-caption-inner">
24+
<h3 data-test="carouselObjTitle" [class]="carouselOptions.titleStyle"
25+
*ngIf="item.indexableObject.metadata[title]">
26+
{{item.indexableObject.metadata[title][0].value}}</h3>
27+
<div data-test="carouselObjDesc" class="carousel-caption-text pr-3 pl-2" [class]="carouselOptions.captionStyle"
28+
*ngIf="item.indexableObject.metadata[description]; let descriptionObj">
29+
{{descriptionObj[0].value}}
30+
</div>
2931
</div>
3032
</div>
3133
</div>
32-
</div>
34+
</ng-template>
3335
</ng-template>
34-
</ng-template>
35-
</ngb-carousel>
36-
<div class="text-center play-pause-button">
37-
<button type="button" class="btn btn-sm toggle-paused" (click)="togglePaused()">
38-
<i class="fas fa-play" *ngIf="paused"></i>
39-
<i class="fas fa-pause" *ngIf="!paused"></i>
40-
</button>
36+
</ngb-carousel>
37+
<div class="text-center play-pause-button">
38+
<button type="button" class="btn btn-sm toggle-paused" (click)="togglePaused()">
39+
<i class="fas fa-play" *ngIf="paused"></i>
40+
<i class="fas fa-pause" *ngIf="!paused"></i>
41+
</button>
42+
</div>
43+
<div class="mt-4 w-100 d-flex justify-content-center align-items-center" *ngIf="totalPages > 1">
44+
<button (click)="previousPage()" [disabled]="currentPage === 1" class="prev">
45+
<i class="fa fa-arrow-left"></i>
46+
</button>
47+
<button
48+
*ngFor="let page of pages()"
49+
class="number"
50+
(click)="changePage(page)"
51+
style="border: none; background: none; margin: 0 5px"
52+
[style.color]="page === currentPage ? '#000000' : '#7c7c7c'">
53+
{{ page < 10 ? '0' + page : page }}
54+
</button>
55+
<button (click)="nextPage()" [disabled]="currentPage === pages().length" class="next">
56+
<i class="fa fa-arrow-right"></i>
57+
</button>
58+
</div>
59+
</div>
60+
61+
62+
<div
63+
class="carousel-content-wrapper"
64+
[ngStyle]="{
65+
'height': carouselOptions.keepAspectRatio ? null : carouselOptions.carouselHeightPx + 'px',
66+
'aspect-ratio': carouselOptions.keepAspectRatio ? carouselOptions.aspectRatio : null
67+
}"
68+
*ngIf="(isLoading$ | async)"
69+
>
70+
<a
71+
href="#"
72+
target="_blank"
73+
class="img-container-el">
74+
<div class="picsum-img-wrapper flex-column">
75+
<img class="img-fluid" src="assets/images/replacement_image.svg">
76+
{{'loading.default' | translate}}
77+
</div>
78+
</a>
4179
</div>

src/app/shared/carousel/carousel.component.spec.ts

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,9 @@ import { createPaginatedList } from '../testing/utils.test';
3535
import { ItemSearchResult } from '../object-collection/shared/item-search-result.model';
3636
import { BitstreamFormat } from '../../core/shared/bitstream-format.model';
3737
import { CarouselOptions } from './carousel-options.model';
38+
import { SortDirection } from '../../core/cache/models/sort-options.model';
39+
import { SearchManager } from '../../core/browse/search-manager';
40+
import { toRemoteData } from '../../browse-by/browse-by-metadata-page/browse-by-metadata-page.component.spec';
3841

3942
describe('CarouselComponent', () => {
4043
let component: CarouselComponent;
@@ -63,7 +66,12 @@ describe('CarouselComponent', () => {
6366
aspectRatio: 1,
6467
captionStyle: '',
6568
titleStyle: '',
66-
bundle: 'ORIGINAL'
69+
bundle: 'ORIGINAL',
70+
discoveryConfiguration: 'person',
71+
sortField: 'testField',
72+
sortDirection: SortDirection.DESC,
73+
numberOfItems: 5,
74+
order: 'testOrder'
6775
};
6876

6977
const firstItemResult = Object.assign(new ItemSearchResult(), {
@@ -153,6 +161,10 @@ describe('CarouselComponent', () => {
153161
}))
154162
});
155163

164+
const mockSearchManager = {
165+
search: (options: any) => toRemoteData([firstItemResult])
166+
};
167+
156168
beforeEach(waitForAsync(() => {
157169
notificationService = new NotificationsServiceStub();
158170
TestBed.configureTestingModule({
@@ -178,6 +190,7 @@ describe('CarouselComponent', () => {
178190
{ provide: DefaultChangeAnalyzer, useValue: {} },
179191
{ provide: BitstreamDataService, useValue: mockBitstreamDataService },
180192
{ provide: NativeWindowService, useValue: new NativeWindowRef() },
193+
{ provide: SearchManager, useValue: mockSearchManager },
181194
],
182195
schemas: [NO_ERRORS_SCHEMA]
183196
}).compileComponents();
@@ -188,7 +201,6 @@ describe('CarouselComponent', () => {
188201
fixture = TestBed.createComponent(CarouselComponent);
189202
component = fixture.componentInstance;
190203
mockBitstreamDataService.findAllByItemAndBundleName.and.returnValue(createSuccessfulRemoteDataObject$(createPaginatedList([mockBitstream1])));
191-
component.items = [firstItemResult];
192204
component.carouselOptions = carouselOptions;
193205

194206
fixture.detectChanges();
@@ -222,7 +234,6 @@ describe('CarouselComponent', () => {
222234
fixture = TestBed.createComponent(CarouselComponent);
223235
component = fixture.componentInstance;
224236
mockBitstreamDataService.findAllByItemAndBundleName.and.returnValue(createSuccessfulRemoteDataObject$(createPaginatedList([mockBitstream2])));
225-
component.items = [secondItemResult];
226237
component.carouselOptions = carouselOptions;
227238

228239
fixture.detectChanges();

0 commit comments

Comments
 (0)