mirror of
https://github.com/DSpace/dspace-angular.git
synced 2025-10-07 01:54:15 +00:00
Merge pull request #1552 from 4Science/CST-5449
[CST-5449] "Browse by" pages are missing "Now showing" contextual information
This commit is contained in:
@@ -31,7 +31,6 @@
|
|||||||
[sortConfig]="(currentSort$ |async)"
|
[sortConfig]="(currentSort$ |async)"
|
||||||
[type]="startsWithType"
|
[type]="startsWithType"
|
||||||
[startsWithOptions]="startsWithOptions"
|
[startsWithOptions]="startsWithOptions"
|
||||||
[enableArrows]="true"
|
|
||||||
(prev)="goPrev()"
|
(prev)="goPrev()"
|
||||||
(next)="goNext()">
|
(next)="goNext()">
|
||||||
</ds-browse-by>
|
</ds-browse-by>
|
||||||
|
@@ -1,38 +1,15 @@
|
|||||||
<ng-container *ngVar="(objects$ | async) as objects">
|
<ng-container *ngVar="(objects$ | async) as objects">
|
||||||
<h3 [ngClass]="{'sr-only': parentname }" >{{title | translate}}</h3>
|
<h3 [ngClass]="{'sr-only': parentname }">{{title | translate}}</h3>
|
||||||
<ng-container *ngComponentOutlet="getStartsWithComponent(); injector: objectInjector;"></ng-container>
|
<ng-container *ngComponentOutlet="getStartsWithComponent(); injector: objectInjector;"></ng-container>
|
||||||
<div *ngIf="objects?.hasSucceeded && !objects?.isLoading && objects?.payload?.page.length > 0" @fadeIn>
|
<div *ngIf="objects?.hasSucceeded && !objects?.isLoading && objects?.payload?.page.length > 0" @fadeIn>
|
||||||
<div *ngIf="!enableArrows">
|
<ds-viewable-collection
|
||||||
<ds-viewable-collection
|
[config]="paginationConfig"
|
||||||
[config]="paginationConfig"
|
[sortConfig]="sortConfig"
|
||||||
[sortConfig]="sortConfig"
|
[showPaginator]="showPaginator"
|
||||||
[objects]="objects">
|
[objects]="objects"
|
||||||
</ds-viewable-collection>
|
(prev)="goPrev()"
|
||||||
</div>
|
(next)="goNext()">
|
||||||
<div *ngIf="enableArrows">
|
</ds-viewable-collection>
|
||||||
<div class="row">
|
|
||||||
<div class="col-12">
|
|
||||||
<div *ngIf="!hideGear" ngbDropdown #paginationControls="ngbDropdown" placement="bottom-right" class="d-inline-block float-right">
|
|
||||||
<button class="btn btn-secondary" id="paginationControls" [title]="'pagination.options.description' | translate" [attr.aria-label]="'pagination.options.description' | translate" ngbDropdownToggle><i class="fas fa-cog" aria-hidden="true"></i></button>
|
|
||||||
<div id="paginationControlsDropdownMenu" aria-labelledby="paginationControls" ngbDropdownMenu>
|
|
||||||
<h6 class="dropdown-header">{{ 'pagination.results-per-page' | translate}}</h6>
|
|
||||||
<button class="dropdown-item page-size-change" *ngFor="let item of paginationConfig?.pageSizeOptions" (click)="doPageSizeChange(item)"><i [ngClass]="{'invisible': item != paginationConfig?.pageSize}" class="fas fa-check" aria-hidden="true"></i> {{item}} </button>
|
|
||||||
<h6 class="dropdown-header">{{ 'pagination.sort-direction' | translate}}</h6>
|
|
||||||
<button class="dropdown-item sort-direction-change" *ngFor="let direction of (sortDirections | dsKeys)" (click)="doSortDirectionChange(direction.value)"><i [ngClass]="{'invisible': direction.value !== sortConfig?.direction}" class="fas fa-check" aria-hidden="true"></i> {{'sorting.' + direction.key | translate}} </button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<ul class="list-unstyled">
|
|
||||||
<li *ngFor="let object of objects?.payload?.page" class="mt-4 mb-4">
|
|
||||||
<ds-listable-object-component-loader [object]="object" [viewMode]="viewMode"></ds-listable-object-component-loader>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
<div>
|
|
||||||
<button id="nav-prev" type="button" class="btn btn-outline-primary float-left" (click)="goPrev()" [disabled]="objects?.payload?.currentPage <= 1"><i class="fas fa-angle-left"></i> {{'browse.previous.button' |translate}}</button>
|
|
||||||
<button id="nav-next" type="button" class="btn btn-outline-primary float-right" (click)="goNext()" [disabled]="objects?.payload?.currentPage >= objects?.payload?.totalPages"><i class="fas fa-angle-right"></i> {{'browse.next.button' |translate}}</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
<ds-loading *ngIf="!objects || objects?.isLoading" message="{{'loading.browse-by' | translate}}"></ds-loading>
|
<ds-loading *ngIf="!objects || objects?.isLoading" message="{{'loading.browse-by' | translate}}"></ds-loading>
|
||||||
<ds-error *ngIf="objects?.hasFailed" message="{{'error.browse-by' | translate}}"></ds-error>
|
<ds-error *ngIf="objects?.hasFailed" message="{{'error.browse-by' | translate}}"></ds-error>
|
||||||
@@ -40,3 +17,4 @@
|
|||||||
{{'browse.empty' | translate}}
|
{{'browse.empty' | translate}}
|
||||||
</div>
|
</div>
|
||||||
</ng-container>
|
</ng-container>
|
||||||
|
|
||||||
|
@@ -4,20 +4,17 @@ import { TranslateLoader, TranslateModule } from '@ngx-translate/core';
|
|||||||
import { By } from '@angular/platform-browser';
|
import { By } from '@angular/platform-browser';
|
||||||
import { Component, NO_ERRORS_SCHEMA } from '@angular/core';
|
import { Component, NO_ERRORS_SCHEMA } from '@angular/core';
|
||||||
import { of as observableOf } from 'rxjs';
|
import { of as observableOf } from 'rxjs';
|
||||||
import { SharedModule } from '../shared.module';
|
|
||||||
import { CommonModule } from '@angular/common';
|
import { CommonModule } from '@angular/common';
|
||||||
import { Item } from '../../core/shared/item.model';
|
import { Item } from '../../core/shared/item.model';
|
||||||
import { buildPaginatedList } from '../../core/data/paginated-list.model';
|
import { buildPaginatedList } from '../../core/data/paginated-list.model';
|
||||||
import { PageInfo } from '../../core/shared/page-info.model';
|
import { PageInfo } from '../../core/shared/page-info.model';
|
||||||
import { NgbModule } from '@ng-bootstrap/ng-bootstrap';
|
import { NgbModule } from '@ng-bootstrap/ng-bootstrap';
|
||||||
import { StoreModule } from '@ngrx/store';
|
|
||||||
import { TranslateLoaderMock } from '../mocks/translate-loader.mock';
|
import { TranslateLoaderMock } from '../mocks/translate-loader.mock';
|
||||||
import { RouterTestingModule } from '@angular/router/testing';
|
import { RouterTestingModule } from '@angular/router/testing';
|
||||||
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
|
import { NoopAnimationsModule } from '@angular/platform-browser/animations';
|
||||||
import { PaginationComponentOptions } from '../pagination/pagination-component-options.model';
|
import { PaginationComponentOptions } from '../pagination/pagination-component-options.model';
|
||||||
import { SortDirection, SortOptions } from '../../core/cache/models/sort-options.model';
|
import { SortDirection, SortOptions } from '../../core/cache/models/sort-options.model';
|
||||||
import { createSuccessfulRemoteDataObject$ } from '../remote-data.utils';
|
import { createSuccessfulRemoteDataObject$ } from '../remote-data.utils';
|
||||||
import { storeModuleConfig } from '../../app.reducer';
|
|
||||||
import { PaginationService } from '../../core/pagination/pagination.service';
|
import { PaginationService } from '../../core/pagination/pagination.service';
|
||||||
import { PaginationServiceStub } from '../testing/pagination-service.stub';
|
import { PaginationServiceStub } from '../testing/pagination-service.stub';
|
||||||
import { ListableObjectComponentLoaderComponent } from '../object-collection/shared/listable-object/listable-object-component-loader.component';
|
import { ListableObjectComponentLoaderComponent } from '../object-collection/shared/listable-object/listable-object-component-loader.component';
|
||||||
@@ -30,6 +27,9 @@ import {
|
|||||||
import { BrowseEntry } from '../../core/shared/browse-entry.model';
|
import { BrowseEntry } from '../../core/shared/browse-entry.model';
|
||||||
import { ITEM } from '../../core/shared/item.resource-type';
|
import { ITEM } from '../../core/shared/item.resource-type';
|
||||||
import { ThemeService } from '../theme-support/theme.service';
|
import { ThemeService } from '../theme-support/theme.service';
|
||||||
|
import { SelectableListService } from '../object-list/selectable-list/selectable-list.service';
|
||||||
|
import { HostWindowServiceStub } from '../testing/host-window-service.stub';
|
||||||
|
import { HostWindowService } from '../host-window.service';
|
||||||
import SpyObj = jasmine.SpyObj;
|
import SpyObj = jasmine.SpyObj;
|
||||||
|
|
||||||
@listableObjectComponent(BrowseEntry, ViewMode.ListElement, DEFAULT_CONTEXT, 'custom')
|
@listableObjectComponent(BrowseEntry, ViewMode.ListElement, DEFAULT_CONTEXT, 'custom')
|
||||||
@@ -37,7 +37,8 @@ import SpyObj = jasmine.SpyObj;
|
|||||||
selector: 'ds-browse-entry-list-element',
|
selector: 'ds-browse-entry-list-element',
|
||||||
template: ''
|
template: ''
|
||||||
})
|
})
|
||||||
class MockThemedBrowseEntryListElementComponent {}
|
class MockThemedBrowseEntryListElementComponent {
|
||||||
|
}
|
||||||
|
|
||||||
describe('BrowseByComponent', () => {
|
describe('BrowseByComponent', () => {
|
||||||
let comp: BrowseByComponent;
|
let comp: BrowseByComponent;
|
||||||
@@ -83,10 +84,7 @@ describe('BrowseByComponent', () => {
|
|||||||
TestBed.configureTestingModule({
|
TestBed.configureTestingModule({
|
||||||
imports: [
|
imports: [
|
||||||
CommonModule,
|
CommonModule,
|
||||||
TranslateModule.forRoot(),
|
|
||||||
SharedModule,
|
|
||||||
NgbModule,
|
NgbModule,
|
||||||
StoreModule.forRoot({}, storeModuleConfig),
|
|
||||||
TranslateModule.forRoot({
|
TranslateModule.forRoot({
|
||||||
loader: {
|
loader: {
|
||||||
provide: TranslateLoader,
|
provide: TranslateLoader,
|
||||||
@@ -94,13 +92,15 @@ describe('BrowseByComponent', () => {
|
|||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
RouterTestingModule,
|
RouterTestingModule,
|
||||||
BrowserAnimationsModule
|
NoopAnimationsModule
|
||||||
],
|
],
|
||||||
declarations: [],
|
declarations: [],
|
||||||
providers: [
|
providers: [
|
||||||
{provide: PaginationService, useValue: paginationService},
|
{ provide: PaginationService, useValue: paginationService },
|
||||||
{provide: MockThemedBrowseEntryListElementComponent},
|
{ provide: MockThemedBrowseEntryListElementComponent },
|
||||||
{ provide: ThemeService, useValue: themeService },
|
{ provide: ThemeService, useValue: themeService },
|
||||||
|
{ provide: SelectableListService, useValue: {} },
|
||||||
|
{ provide: HostWindowService, useValue: new HostWindowServiceStub(800) },
|
||||||
],
|
],
|
||||||
schemas: [NO_ERRORS_SCHEMA]
|
schemas: [NO_ERRORS_SCHEMA]
|
||||||
}).compileComponents();
|
}).compileComponents();
|
||||||
@@ -129,66 +129,7 @@ describe('BrowseByComponent', () => {
|
|||||||
expect(fixture.debugElement.query(By.css('ds-viewable-collection'))).toBeDefined();
|
expect(fixture.debugElement.query(By.css('ds-viewable-collection'))).toBeDefined();
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('when enableArrows is true and objects are defined', () => {
|
describe('when showPaginator is true and browseEntries are provided', () => {
|
||||||
beforeEach(() => {
|
|
||||||
comp.enableArrows = true;
|
|
||||||
comp.objects$ = mockItemsRD$;
|
|
||||||
|
|
||||||
comp.paginationConfig = paginationConfig;
|
|
||||||
comp.sortConfig = Object.assign(new SortOptions('dc.title', SortDirection.ASC));
|
|
||||||
fixture.detectChanges();
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('when clicking the previous arrow button', () => {
|
|
||||||
beforeEach(() => {
|
|
||||||
spyOn(comp.prev, 'emit');
|
|
||||||
fixture.debugElement.query(By.css('#nav-prev')).triggerEventHandler('click', null);
|
|
||||||
fixture.detectChanges();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should emit a signal to the EventEmitter', () => {
|
|
||||||
expect(comp.prev.emit).toHaveBeenCalled();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('when clicking the next arrow button', () => {
|
|
||||||
beforeEach(() => {
|
|
||||||
spyOn(comp.next, 'emit');
|
|
||||||
fixture.debugElement.query(By.css('#nav-next')).triggerEventHandler('click', null);
|
|
||||||
fixture.detectChanges();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should emit a signal to the EventEmitter', () => {
|
|
||||||
expect(comp.next.emit).toHaveBeenCalled();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('when clicking a different page size', () => {
|
|
||||||
beforeEach(() => {
|
|
||||||
spyOn(comp.pageSizeChange, 'emit');
|
|
||||||
fixture.debugElement.query(By.css('.page-size-change')).triggerEventHandler('click', null);
|
|
||||||
fixture.detectChanges();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should call the updateRoute method from the paginationService', () => {
|
|
||||||
expect(paginationService.updateRoute).toHaveBeenCalledWith('test-pagination', {pageSize: paginationConfig.pageSizeOptions[0]});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('when clicking a different sort direction', () => {
|
|
||||||
beforeEach(() => {
|
|
||||||
spyOn(comp.sortDirectionChange, 'emit');
|
|
||||||
fixture.debugElement.query(By.css('.sort-direction-change')).triggerEventHandler('click', null);
|
|
||||||
fixture.detectChanges();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should call the updateRoute method from the paginationService', () => {
|
|
||||||
expect(paginationService.updateRoute).toHaveBeenCalledWith('test-pagination', {sortDirection: 'ASC'});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('when enableArrows is true and browseEntries are provided', () => {
|
|
||||||
let browseEntries;
|
let browseEntries;
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
@@ -209,7 +150,7 @@ describe('BrowseByComponent', () => {
|
|||||||
}),
|
}),
|
||||||
];
|
];
|
||||||
|
|
||||||
comp.enableArrows = true;
|
comp.showPaginator = true;
|
||||||
comp.objects$ = createSuccessfulRemoteDataObject$(buildPaginatedList(new PageInfo(), browseEntries));
|
comp.objects$ = createSuccessfulRemoteDataObject$(buildPaginatedList(new PageInfo(), browseEntries));
|
||||||
comp.paginationConfig = paginationConfig;
|
comp.paginationConfig = paginationConfig;
|
||||||
comp.sortConfig = Object.assign(new SortOptions('dc.title', SortDirection.ASC));
|
comp.sortConfig = Object.assign(new SortOptions('dc.title', SortDirection.ASC));
|
||||||
|
@@ -67,30 +67,30 @@ export class BrowseByComponent implements OnInit {
|
|||||||
/**
|
/**
|
||||||
* Whether or not the pagination should be rendered as simple previous and next buttons instead of the normal pagination
|
* Whether or not the pagination should be rendered as simple previous and next buttons instead of the normal pagination
|
||||||
*/
|
*/
|
||||||
@Input() enableArrows = false;
|
@Input() showPaginator = false;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If enableArrows is set to true, should it hide the options gear?
|
* It is used to hide or show gear
|
||||||
*/
|
*/
|
||||||
@Input() hideGear = false;
|
@Input() hideGear = false;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If enableArrows is set to true, emit when the previous button is clicked
|
* Emits event when prev button clicked
|
||||||
*/
|
*/
|
||||||
@Output() prev = new EventEmitter<boolean>();
|
@Output() prev = new EventEmitter<boolean>();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If enableArrows is set to true, emit when the next button is clicked
|
* Emits event when next button clicked
|
||||||
*/
|
*/
|
||||||
@Output() next = new EventEmitter<boolean>();
|
@Output() next = new EventEmitter<boolean>();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If enableArrows is set to true, emit when the page size is changed
|
* Emits event when page size is changed
|
||||||
*/
|
*/
|
||||||
@Output() pageSizeChange = new EventEmitter<number>();
|
@Output() pageSizeChange = new EventEmitter<number>();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If enableArrows is set to true, emit when the sort direction is changed
|
* Emits event when page sort direction is changed
|
||||||
*/
|
*/
|
||||||
@Output() sortDirectionChange = new EventEmitter<SortDirection>();
|
@Output() sortDirectionChange = new EventEmitter<SortDirection>();
|
||||||
|
|
||||||
|
@@ -6,6 +6,7 @@
|
|||||||
[linkType]="linkType"
|
[linkType]="linkType"
|
||||||
[context]="context"
|
[context]="context"
|
||||||
[hidePaginationDetail]="hidePaginationDetail"
|
[hidePaginationDetail]="hidePaginationDetail"
|
||||||
|
[showPaginator]="showPaginator"
|
||||||
(paginationChange)="onPaginationChange($event)"
|
(paginationChange)="onPaginationChange($event)"
|
||||||
(pageChange)="onPageChange($event)"
|
(pageChange)="onPageChange($event)"
|
||||||
(pageSizeChange)="onPageSizeChange($event)"
|
(pageSizeChange)="onPageSizeChange($event)"
|
||||||
@@ -19,6 +20,8 @@
|
|||||||
[importConfig]="importConfig"
|
[importConfig]="importConfig"
|
||||||
(importObject)="importObject.emit($event)"
|
(importObject)="importObject.emit($event)"
|
||||||
(contentChange)="contentChange.emit()"
|
(contentChange)="contentChange.emit()"
|
||||||
|
(prev)="goPrev()"
|
||||||
|
(next)="goNext()"
|
||||||
*ngIf="(currentMode$ | async) === viewModeEnum.ListElement">
|
*ngIf="(currentMode$ | async) === viewModeEnum.ListElement">
|
||||||
</ds-object-list>
|
</ds-object-list>
|
||||||
|
|
||||||
@@ -29,6 +32,7 @@
|
|||||||
[linkType]="linkType"
|
[linkType]="linkType"
|
||||||
[context]="context"
|
[context]="context"
|
||||||
[hidePaginationDetail]="hidePaginationDetail"
|
[hidePaginationDetail]="hidePaginationDetail"
|
||||||
|
[showPaginator]="showPaginator"
|
||||||
(paginationChange)="onPaginationChange($event)"
|
(paginationChange)="onPaginationChange($event)"
|
||||||
(pageChange)="onPageChange($event)"
|
(pageChange)="onPageChange($event)"
|
||||||
(pageSizeChange)="onPageSizeChange($event)"
|
(pageSizeChange)="onPageSizeChange($event)"
|
||||||
@@ -44,6 +48,7 @@
|
|||||||
[linkType]="linkType"
|
[linkType]="linkType"
|
||||||
[context]="context"
|
[context]="context"
|
||||||
[hidePaginationDetail]="hidePaginationDetail"
|
[hidePaginationDetail]="hidePaginationDetail"
|
||||||
|
[showPaginator]="showPaginator"
|
||||||
*ngIf="(currentMode$ | async) === viewModeEnum.DetailedListElement">
|
*ngIf="(currentMode$ | async) === viewModeEnum.DetailedListElement">
|
||||||
</ds-object-detail>
|
</ds-object-detail>
|
||||||
|
|
||||||
|
@@ -88,6 +88,11 @@ export class ObjectCollectionComponent implements OnInit {
|
|||||||
*/
|
*/
|
||||||
@Input() hidePaginationDetail = false;
|
@Input() hidePaginationDetail = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether or not the pagination should be rendered as simple previous and next buttons instead of the normal pagination
|
||||||
|
*/
|
||||||
|
@Input() showPaginator = true;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* the page info of the list
|
* the page info of the list
|
||||||
*/
|
*/
|
||||||
@@ -122,6 +127,16 @@ export class ObjectCollectionComponent implements OnInit {
|
|||||||
*/
|
*/
|
||||||
@Output() sortFieldChange: EventEmitter<string> = new EventEmitter<string>();
|
@Output() sortFieldChange: EventEmitter<string> = new EventEmitter<string>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If showPaginator is set to true, emit when the previous button is clicked
|
||||||
|
*/
|
||||||
|
@Output() prev = new EventEmitter<boolean>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If showPaginator is set to true, emit when the next button is clicked
|
||||||
|
*/
|
||||||
|
@Output() next = new EventEmitter<boolean>();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Emits the current view mode
|
* Emits the current view mode
|
||||||
*/
|
*/
|
||||||
@@ -192,4 +207,18 @@ export class ObjectCollectionComponent implements OnInit {
|
|||||||
this.paginationChange.emit(event);
|
this.paginationChange.emit(event);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Go to the previous page
|
||||||
|
*/
|
||||||
|
goPrev() {
|
||||||
|
this.prev.emit(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Go to the next page
|
||||||
|
*/
|
||||||
|
goNext() {
|
||||||
|
this.next.emit(true);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -3,14 +3,19 @@
|
|||||||
[pageInfoState]="objects?.payload"
|
[pageInfoState]="objects?.payload"
|
||||||
[collectionSize]="objects?.payload?.totalElements"
|
[collectionSize]="objects?.payload?.totalElements"
|
||||||
[sortOptions]="sortConfig"
|
[sortOptions]="sortConfig"
|
||||||
|
[objects]="objects"
|
||||||
[hideGear]="hideGear"
|
[hideGear]="hideGear"
|
||||||
[hidePaginationDetail]="hidePaginationDetail"
|
[hidePaginationDetail]="hidePaginationDetail"
|
||||||
[hidePagerWhenSinglePage]="hidePagerWhenSinglePage"
|
[hidePagerWhenSinglePage]="hidePagerWhenSinglePage"
|
||||||
|
[showPaginator]="showPaginator"
|
||||||
(pageChange)="onPageChange($event)"
|
(pageChange)="onPageChange($event)"
|
||||||
(pageSizeChange)="onPageSizeChange($event)"
|
(pageSizeChange)="onPageSizeChange($event)"
|
||||||
(sortDirectionChange)="onSortDirectionChange($event)"
|
(sortDirectionChange)="onSortDirectionChange($event)"
|
||||||
(sortFieldChange)="onSortFieldChange($event)"
|
(sortFieldChange)="onSortFieldChange($event)"
|
||||||
(paginationChange)="onPaginationChange($event)">
|
(paginationChange)="onPaginationChange($event)"
|
||||||
|
(prev)="goPrev()"
|
||||||
|
(next)="goNext()"
|
||||||
|
>
|
||||||
<div class="row mt-2" *ngIf="objects?.hasSucceeded" @fadeIn>
|
<div class="row mt-2" *ngIf="objects?.hasSucceeded" @fadeIn>
|
||||||
<div class="col"
|
<div class="col"
|
||||||
*ngFor="let object of objects?.payload?.page">
|
*ngFor="let object of objects?.payload?.page">
|
||||||
|
@@ -66,6 +66,21 @@ export class ObjectDetailComponent {
|
|||||||
*/
|
*/
|
||||||
@Input() context: Context;
|
@Input() context: Context;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether or not the pagination should be rendered as simple previous and next buttons instead of the normal pagination
|
||||||
|
*/
|
||||||
|
@Input() showPaginator = true;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If showPaginator is set to true, emit when the previous button is clicked
|
||||||
|
*/
|
||||||
|
@Output() prev = new EventEmitter<boolean>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If showPaginator is set to true, emit when the next button is clicked
|
||||||
|
*/
|
||||||
|
@Output() next = new EventEmitter<boolean>();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The list of objects to paginate
|
* The list of objects to paginate
|
||||||
*/
|
*/
|
||||||
@@ -168,4 +183,18 @@ export class ObjectDetailComponent {
|
|||||||
this.paginationChange.emit(event);
|
this.paginationChange.emit(event);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Go to the previous page
|
||||||
|
*/
|
||||||
|
goPrev() {
|
||||||
|
this.prev.emit(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Go to the next page
|
||||||
|
*/
|
||||||
|
goNext() {
|
||||||
|
this.next.emit(true);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -4,13 +4,18 @@
|
|||||||
[collectionSize]="objects?.payload?.totalElements"
|
[collectionSize]="objects?.payload?.totalElements"
|
||||||
[sortOptions]="sortConfig"
|
[sortOptions]="sortConfig"
|
||||||
[hideGear]="hideGear"
|
[hideGear]="hideGear"
|
||||||
|
[objects]="objects"
|
||||||
[hidePagerWhenSinglePage]="hidePagerWhenSinglePage"
|
[hidePagerWhenSinglePage]="hidePagerWhenSinglePage"
|
||||||
[hidePaginationDetail]="hidePaginationDetail"
|
[hidePaginationDetail]="hidePaginationDetail"
|
||||||
|
[showPaginator]="showPaginator"
|
||||||
(pageChange)="onPageChange($event)"
|
(pageChange)="onPageChange($event)"
|
||||||
(pageSizeChange)="onPageSizeChange($event)"
|
(pageSizeChange)="onPageSizeChange($event)"
|
||||||
(sortDirectionChange)="onSortDirectionChange($event)"
|
(sortDirectionChange)="onSortDirectionChange($event)"
|
||||||
(sortFieldChange)="onSortFieldChange($event)"
|
(sortFieldChange)="onSortFieldChange($event)"
|
||||||
(paginationChange)="onPaginationChange($event)">
|
(paginationChange)="onPaginationChange($event)"
|
||||||
|
(prev)="goPrev()"
|
||||||
|
(next)="goNext()"
|
||||||
|
>
|
||||||
<div class="card-columns row" *ngIf="objects?.hasSucceeded">
|
<div class="card-columns row" *ngIf="objects?.hasSucceeded">
|
||||||
<div class="card-column col col-sm-6 col-lg-4" *ngFor="let column of (columns$ | async)" @fadeIn>
|
<div class="card-column col col-sm-6 col-lg-4" *ngFor="let column of (columns$ | async)" @fadeIn>
|
||||||
<div class="card-element" *ngFor="let object of column" data-test="grid-object">
|
<div class="card-element" *ngFor="let object of column" data-test="grid-object">
|
||||||
@@ -22,3 +27,4 @@
|
|||||||
<ds-loading *ngIf="objects.isLoading" message="{{'loading.objects' | translate}}"></ds-loading>
|
<ds-loading *ngIf="objects.isLoading" message="{{'loading.objects' | translate}}"></ds-loading>
|
||||||
</ds-pagination>
|
</ds-pagination>
|
||||||
|
|
||||||
|
|
||||||
|
@@ -49,6 +49,11 @@ export class ObjectGridComponent implements OnInit {
|
|||||||
*/
|
*/
|
||||||
@Input() sortConfig: SortOptions;
|
@Input() sortConfig: SortOptions;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether or not the pagination should be rendered as simple previous and next buttons instead of the normal pagination
|
||||||
|
*/
|
||||||
|
@Input() showPaginator = true;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The whether or not the gear is hidden
|
* The whether or not the gear is hidden
|
||||||
*/
|
*/
|
||||||
@@ -134,6 +139,17 @@ export class ObjectGridComponent implements OnInit {
|
|||||||
* Event's payload equals to the newly selected sort field.
|
* Event's payload equals to the newly selected sort field.
|
||||||
*/
|
*/
|
||||||
@Output() sortFieldChange: EventEmitter<string> = new EventEmitter<string>();
|
@Output() sortFieldChange: EventEmitter<string> = new EventEmitter<string>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If showPaginator is set to true, emit when the previous button is clicked
|
||||||
|
*/
|
||||||
|
@Output() prev = new EventEmitter<boolean>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If showPaginator is set to true, emit when the next button is clicked
|
||||||
|
*/
|
||||||
|
@Output() next = new EventEmitter<boolean>();
|
||||||
|
|
||||||
data: any = {};
|
data: any = {};
|
||||||
columns$: Observable<ListableObject[]>;
|
columns$: Observable<ListableObject[]>;
|
||||||
|
|
||||||
@@ -225,4 +241,18 @@ export class ObjectGridComponent implements OnInit {
|
|||||||
this.paginationChange.emit(event);
|
this.paginationChange.emit(event);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Go to the previous page
|
||||||
|
*/
|
||||||
|
goPrev() {
|
||||||
|
this.prev.emit(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Go to the next page
|
||||||
|
*/
|
||||||
|
goNext() {
|
||||||
|
this.next.emit(true);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -2,15 +2,20 @@
|
|||||||
[paginationOptions]="config"
|
[paginationOptions]="config"
|
||||||
[pageInfoState]="objects?.payload"
|
[pageInfoState]="objects?.payload"
|
||||||
[collectionSize]="objects?.payload?.totalElements"
|
[collectionSize]="objects?.payload?.totalElements"
|
||||||
|
[objects]="objects"
|
||||||
[sortOptions]="sortConfig"
|
[sortOptions]="sortConfig"
|
||||||
[hideGear]="hideGear"
|
[hideGear]="hideGear"
|
||||||
[hidePagerWhenSinglePage]="hidePagerWhenSinglePage"
|
[hidePagerWhenSinglePage]="hidePagerWhenSinglePage"
|
||||||
[hidePaginationDetail]="hidePaginationDetail"
|
[hidePaginationDetail]="hidePaginationDetail"
|
||||||
|
[showPaginator]="showPaginator"
|
||||||
(pageChange)="onPageChange($event)"
|
(pageChange)="onPageChange($event)"
|
||||||
(pageSizeChange)="onPageSizeChange($event)"
|
(pageSizeChange)="onPageSizeChange($event)"
|
||||||
(sortDirectionChange)="onSortDirectionChange($event)"
|
(sortDirectionChange)="onSortDirectionChange($event)"
|
||||||
(sortFieldChange)="onSortFieldChange($event)"
|
(sortFieldChange)="onSortFieldChange($event)"
|
||||||
(paginationChange)="onPaginationChange($event)">
|
(paginationChange)="onPaginationChange($event)"
|
||||||
|
(prev)="goPrev()"
|
||||||
|
(next)="goNext()"
|
||||||
|
>
|
||||||
<ul *ngIf="objects?.hasSucceeded" class="list-unstyled" [ngClass]="{'ml-4': selectable}">
|
<ul *ngIf="objects?.hasSucceeded" class="list-unstyled" [ngClass]="{'ml-4': selectable}">
|
||||||
<li *ngFor="let object of objects?.payload?.page; let i = index; let last = last" class="mt-4 mb-4 d-flex" [class.border-bottom]="hasBorder && !last" data-test="list-object">
|
<li *ngFor="let object of objects?.payload?.page; let i = index; let last = last" class="mt-4 mb-4 d-flex" [class.border-bottom]="hasBorder && !last" data-test="list-object">
|
||||||
<ds-selectable-list-item-control *ngIf="selectable" [index]="i"
|
<ds-selectable-list-item-control *ngIf="selectable" [index]="i"
|
||||||
|
@@ -76,11 +76,26 @@ export class ObjectListComponent {
|
|||||||
*/
|
*/
|
||||||
@Input() importConfig: { importLabel: string };
|
@Input() importConfig: { importLabel: string };
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether or not the pagination should be rendered as simple previous and next buttons instead of the normal pagination
|
||||||
|
*/
|
||||||
|
@Input() showPaginator = true;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Emit when one of the listed object has changed.
|
* Emit when one of the listed object has changed.
|
||||||
*/
|
*/
|
||||||
@Output() contentChange = new EventEmitter<any>();
|
@Output() contentChange = new EventEmitter<any>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If showPaginator is set to true, emit when the previous button is clicked
|
||||||
|
*/
|
||||||
|
@Output() prev = new EventEmitter<boolean>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If showPaginator is set to true, emit when the next button is clicked
|
||||||
|
*/
|
||||||
|
@Output() next = new EventEmitter<boolean>();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The current listable objects
|
* The current listable objects
|
||||||
*/
|
*/
|
||||||
@@ -192,4 +207,18 @@ export class ObjectListComponent {
|
|||||||
onPaginationChange(event) {
|
onPaginationChange(event) {
|
||||||
this.paginationChange.emit(event);
|
this.paginationChange.emit(event);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Go to the previous page
|
||||||
|
*/
|
||||||
|
goPrev() {
|
||||||
|
this.prev.emit(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Go to the next page
|
||||||
|
*/
|
||||||
|
goNext() {
|
||||||
|
this.next.emit(true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -20,16 +20,32 @@
|
|||||||
</div>
|
</div>
|
||||||
<ng-content></ng-content>
|
<ng-content></ng-content>
|
||||||
|
|
||||||
<div *ngIf="shouldShowBottomPager |async" class="pagination justify-content-center clearfix bottom">
|
<div *ngIf="shouldShowBottomPager | async">
|
||||||
<ngb-pagination [boundaryLinks]="paginationOptions.boundaryLinks"
|
<div *ngIf="showPaginator" class="pagination justify-content-center clearfix bottom">
|
||||||
[collectionSize]="collectionSize"
|
<ngb-pagination [boundaryLinks]="paginationOptions.boundaryLinks"
|
||||||
[disabled]="paginationOptions.disabled"
|
[collectionSize]="collectionSize"
|
||||||
[ellipses]="paginationOptions.ellipses"
|
[disabled]="paginationOptions.disabled"
|
||||||
[maxSize]="(isXs)?5:paginationOptions.maxSize"
|
[ellipses]="paginationOptions.ellipses"
|
||||||
[page]="(currentPage$|async)"
|
[maxSize]="(isXs)?5:paginationOptions.maxSize"
|
||||||
(pageChange)="doPageChange($event)"
|
[page]="(currentPage$|async)"
|
||||||
[pageSize]="(pageSize$ |async)"
|
(pageChange)="doPageChange($event)"
|
||||||
[rotate]="paginationOptions.rotate"
|
[pageSize]="(pageSize$ |async)"
|
||||||
[size]="(isXs)?'sm':paginationOptions.size"></ngb-pagination>
|
[rotate]="paginationOptions.rotate"
|
||||||
|
[size]="(isXs)?'sm':paginationOptions.size">
|
||||||
|
</ngb-pagination>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div *ngIf="!showPaginator" class="d-flex justify-content-between">
|
||||||
|
<button id="nav-prev" type="button" class="btn btn-outline-primary float-left"
|
||||||
|
(click)="goPrev()"
|
||||||
|
[disabled]="objects?.payload?.currentPage <= 1">
|
||||||
|
<i class="fas fa-angle-left"></i> {{'pagination.previous.button' |translate}}
|
||||||
|
</button>
|
||||||
|
<button id="nav-next" type="button" class="btn btn-outline-primary float-right"
|
||||||
|
(click)="goNext()"
|
||||||
|
[disabled]="objects?.payload?.currentPage >= objects?.payload?.totalPages">
|
||||||
|
<i class="fas fa-angle-right"></i> {{'pagination.next.button' |translate}}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@@ -177,132 +177,206 @@ describe('Pagination component', () => {
|
|||||||
|
|
||||||
}));
|
}));
|
||||||
|
|
||||||
// synchronous beforeEach
|
describe('when showPaginator is false', () => {
|
||||||
beforeEach(() => {
|
// synchronous beforeEach
|
||||||
html = `
|
beforeEach(() => {
|
||||||
<ds-pagination #p='paginationComponent'
|
html = `
|
||||||
[paginationOptions]='paginationOptions'
|
<ds-pagination #p='paginationComponent'
|
||||||
[sortOptions]='sortOptions'
|
[paginationOptions]='paginationOptions'
|
||||||
[collectionSize]='collectionSize'
|
[sortOptions]='sortOptions'
|
||||||
(pageChange)='pageChanged($event)'
|
[collectionSize]='collectionSize'
|
||||||
(pageSizeChange)='pageSizeChanged($event)'>
|
(pageChange)='pageChanged($event)'
|
||||||
<ul>
|
(pageSizeChange)='pageSizeChanged($event)'
|
||||||
<li *ngFor='let item of collection | paginate: { itemsPerPage: paginationOptions.pageSize,
|
>
|
||||||
currentPage: paginationOptions.currentPage, totalItems: collectionSize }'> {{item}} </li>
|
<ul>
|
||||||
</ul>
|
<li *ngFor='let item of collection | paginate: { itemsPerPage: paginationOptions.pageSize,
|
||||||
</ds-pagination>`;
|
currentPage: paginationOptions.currentPage, totalItems: collectionSize }'> {{item}} </li>
|
||||||
|
</ul>
|
||||||
|
</ds-pagination>`;
|
||||||
|
testFixture = createTestComponent(html, TestComponent) as ComponentFixture<TestComponent>;
|
||||||
|
testComp = testFixture.componentInstance;
|
||||||
|
});
|
||||||
|
|
||||||
testFixture = createTestComponent(html, TestComponent) as ComponentFixture<TestComponent>;
|
it('should create Pagination Component', inject([PaginationComponent], (app: PaginationComponent) => {
|
||||||
testComp = testFixture.componentInstance;
|
expect(app).toBeDefined();
|
||||||
|
}));
|
||||||
|
|
||||||
});
|
it('should render', () => {
|
||||||
|
expect(testComp.paginationOptions.id).toEqual('test');
|
||||||
|
expect(testComp.paginationOptions.currentPage).toEqual(1);
|
||||||
|
expect(testComp.paginationOptions.pageSize).toEqual(10);
|
||||||
|
expectPages(testFixture, ['-« Previous', '+1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '» Next']);
|
||||||
|
});
|
||||||
|
|
||||||
it('should create Pagination Component', inject([PaginationComponent], (app: PaginationComponent) => {
|
it('should render and respond to page change', () => {
|
||||||
expect(app).toBeDefined();
|
testComp.collectionSize = 30;
|
||||||
}));
|
|
||||||
|
|
||||||
it('should render', () => {
|
|
||||||
expect(testComp.paginationOptions.id).toEqual('test');
|
|
||||||
expect(testComp.paginationOptions.currentPage).toEqual(1);
|
|
||||||
expect(testComp.paginationOptions.pageSize).toEqual(10);
|
|
||||||
expectPages(testFixture, ['-« Previous', '+1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '» Next']);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should render and respond to page change', () => {
|
|
||||||
testComp.collectionSize = 30;
|
|
||||||
testFixture.detectChanges();
|
|
||||||
|
|
||||||
|
|
||||||
currentPagination.next(Object.assign(new PaginationComponentOptions(), pagination, {currentPage: 3}));
|
|
||||||
testFixture.detectChanges();
|
|
||||||
|
|
||||||
expectPages(testFixture, ['« Previous', '1', '2', '+3', '-» Next']);
|
|
||||||
|
|
||||||
currentPagination.next(Object.assign(new PaginationComponentOptions(), pagination, {currentPage: 2}));
|
|
||||||
testFixture.detectChanges();
|
|
||||||
|
|
||||||
expectPages(testFixture, ['« Previous', '1', '+2', '3', '» Next']);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should render and respond to collectionSize change', () => {
|
|
||||||
|
|
||||||
testComp.collectionSize = 30;
|
|
||||||
testFixture.detectChanges();
|
|
||||||
expectPages(testFixture, ['-« Previous', '+1', '2', '3', '» Next']);
|
|
||||||
|
|
||||||
testComp.collectionSize = 40;
|
|
||||||
testFixture.detectChanges();
|
|
||||||
expectPages(testFixture, ['-« Previous', '+1', '2', '3', '4', '» Next']);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should render and respond to pageSize change', () => {
|
|
||||||
const paginationComponent: PaginationComponent = testFixture.debugElement.query(By.css('ds-pagination')).references.p;
|
|
||||||
|
|
||||||
testComp.collectionSize = 30;
|
|
||||||
testFixture.detectChanges();
|
|
||||||
expectPages(testFixture, ['-« Previous', '+1', '2', '3', '» Next']);
|
|
||||||
|
|
||||||
currentPagination.next(Object.assign(new PaginationComponentOptions(), pagination, {pageSize: 5}));
|
|
||||||
testFixture.detectChanges();
|
|
||||||
|
|
||||||
expectPages(testFixture, ['-« Previous', '+1', '2', '3', '4', '5', '6', '» Next']);
|
|
||||||
|
|
||||||
currentPagination.next(Object.assign(new PaginationComponentOptions(), pagination, {pageSize: 10}));
|
|
||||||
testFixture.detectChanges();
|
|
||||||
expectPages(testFixture, ['-« Previous', '+1', '2', '3', '» Next']);
|
|
||||||
|
|
||||||
currentPagination.next(Object.assign(new PaginationComponentOptions(), pagination, {pageSize: 20}));
|
|
||||||
testFixture.detectChanges();
|
|
||||||
expectPages(testFixture, ['-« Previous', '+1', '2', '» Next']);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should emit pageSizeChange event with correct value', fakeAsync(() => {
|
|
||||||
const paginationComponent: PaginationComponent = testFixture.debugElement.query(By.css('ds-pagination')).references.p;
|
|
||||||
|
|
||||||
spyOn(testComp, 'pageSizeChanged');
|
|
||||||
|
|
||||||
testComp.pageSizeChanged(5);
|
|
||||||
tick();
|
|
||||||
|
|
||||||
expect(testComp.pageSizeChanged).toHaveBeenCalledWith(5);
|
|
||||||
}));
|
|
||||||
|
|
||||||
it('should call the updateRoute method on the paginationService with the correct params', fakeAsync(() => {
|
|
||||||
testComp.collectionSize = 60;
|
|
||||||
|
|
||||||
changePage(testFixture, 3);
|
|
||||||
tick();
|
|
||||||
expect(paginationService.updateRoute).toHaveBeenCalledWith('test', Object.assign({ page: '3'}), {}, false);
|
|
||||||
|
|
||||||
changePage(testFixture, 0);
|
|
||||||
tick();
|
|
||||||
expect(paginationService.updateRoute).toHaveBeenCalledWith('test', Object.assign({ page: '2'}), {}, false);
|
|
||||||
}));
|
|
||||||
|
|
||||||
it('should set correct pageSize route parameters', fakeAsync(() => {
|
|
||||||
routerStub = testFixture.debugElement.injector.get(Router) as any;
|
|
||||||
|
|
||||||
testComp.collectionSize = 60;
|
|
||||||
|
|
||||||
changePageSize(testFixture, '20');
|
|
||||||
tick();
|
|
||||||
expect(paginationService.updateRoute).toHaveBeenCalledWith('test', Object.assign({ pageId: 'test', page: 1, pageSize: 20}), {}, false);
|
|
||||||
}));
|
|
||||||
|
|
||||||
it('should respond to windows resize', () => {
|
|
||||||
const paginationComponent: PaginationComponent = testFixture.debugElement.query(By.css('ds-pagination')).references.p;
|
|
||||||
hostWindowServiceStub = testFixture.debugElement.injector.get(HostWindowService) as any;
|
|
||||||
|
|
||||||
hostWindowServiceStub.setWidth(400);
|
|
||||||
|
|
||||||
hostWindowServiceStub.isXs().subscribe((status) => {
|
|
||||||
paginationComponent.isXs = status;
|
|
||||||
testFixture.detectChanges();
|
testFixture.detectChanges();
|
||||||
expectPages(testFixture, ['-« Previous', '+1', '2', '3', '4', '5', '-...', '10', '» Next']);
|
|
||||||
de = testFixture.debugElement.query(By.css('ul.pagination'));
|
|
||||||
expect(de.nativeElement.classList.contains('pagination-sm')).toBeTruthy();
|
currentPagination.next(Object.assign(new PaginationComponentOptions(), pagination, {currentPage: 3}));
|
||||||
|
testFixture.detectChanges();
|
||||||
|
|
||||||
|
expectPages(testFixture, ['« Previous', '1', '2', '+3', '-» Next']);
|
||||||
|
|
||||||
|
currentPagination.next(Object.assign(new PaginationComponentOptions(), pagination, {currentPage: 2}));
|
||||||
|
testFixture.detectChanges();
|
||||||
|
|
||||||
|
expectPages(testFixture, ['« Previous', '1', '+2', '3', '» Next']);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should render and respond to collectionSize change', () => {
|
||||||
|
|
||||||
|
testComp.collectionSize = 30;
|
||||||
|
testFixture.detectChanges();
|
||||||
|
expectPages(testFixture, ['-« Previous', '+1', '2', '3', '» Next']);
|
||||||
|
|
||||||
|
testComp.collectionSize = 40;
|
||||||
|
testFixture.detectChanges();
|
||||||
|
expectPages(testFixture, ['-« Previous', '+1', '2', '3', '4', '» Next']);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should render and respond to pageSize change', () => {
|
||||||
|
const paginationComponent: PaginationComponent = testFixture.debugElement.query(By.css('ds-pagination')).references.p;
|
||||||
|
|
||||||
|
testComp.collectionSize = 30;
|
||||||
|
testFixture.detectChanges();
|
||||||
|
expectPages(testFixture, ['-« Previous', '+1', '2', '3', '» Next']);
|
||||||
|
|
||||||
|
currentPagination.next(Object.assign(new PaginationComponentOptions(), pagination, {pageSize: 5}));
|
||||||
|
testFixture.detectChanges();
|
||||||
|
|
||||||
|
expectPages(testFixture, ['-« Previous', '+1', '2', '3', '4', '5', '6', '» Next']);
|
||||||
|
|
||||||
|
currentPagination.next(Object.assign(new PaginationComponentOptions(), pagination, {pageSize: 10}));
|
||||||
|
testFixture.detectChanges();
|
||||||
|
expectPages(testFixture, ['-« Previous', '+1', '2', '3', '» Next']);
|
||||||
|
|
||||||
|
currentPagination.next(Object.assign(new PaginationComponentOptions(), pagination, {pageSize: 20}));
|
||||||
|
testFixture.detectChanges();
|
||||||
|
expectPages(testFixture, ['-« Previous', '+1', '2', '» Next']);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should emit pageSizeChange event with correct value', fakeAsync(() => {
|
||||||
|
const paginationComponent: PaginationComponent = testFixture.debugElement.query(By.css('ds-pagination')).references.p;
|
||||||
|
|
||||||
|
spyOn(testComp, 'pageSizeChanged');
|
||||||
|
|
||||||
|
testComp.pageSizeChanged(5);
|
||||||
|
tick();
|
||||||
|
|
||||||
|
expect(testComp.pageSizeChanged).toHaveBeenCalledWith(5);
|
||||||
|
}));
|
||||||
|
|
||||||
|
it('should call the updateRoute method on the paginationService with the correct params', fakeAsync(() => {
|
||||||
|
testComp.collectionSize = 60;
|
||||||
|
|
||||||
|
changePage(testFixture, 3);
|
||||||
|
tick();
|
||||||
|
expect(paginationService.updateRoute).toHaveBeenCalledWith('test', Object.assign({ page: '3'}), {}, false);
|
||||||
|
|
||||||
|
changePage(testFixture, 0);
|
||||||
|
tick();
|
||||||
|
expect(paginationService.updateRoute).toHaveBeenCalledWith('test', Object.assign({ page: '2'}), {}, false);
|
||||||
|
}));
|
||||||
|
|
||||||
|
it('should set correct pageSize route parameters', fakeAsync(() => {
|
||||||
|
routerStub = testFixture.debugElement.injector.get(Router) as any;
|
||||||
|
|
||||||
|
testComp.collectionSize = 60;
|
||||||
|
|
||||||
|
changePageSize(testFixture, '20');
|
||||||
|
tick();
|
||||||
|
expect(paginationService.updateRoute).toHaveBeenCalledWith('test', Object.assign({ pageId: 'test', page: 1, pageSize: 20}), {}, false);
|
||||||
|
}));
|
||||||
|
|
||||||
|
it('should respond to windows resize', () => {
|
||||||
|
const paginationComponent: PaginationComponent = testFixture.debugElement.query(By.css('ds-pagination')).references.p;
|
||||||
|
hostWindowServiceStub = testFixture.debugElement.injector.get(HostWindowService) as any;
|
||||||
|
|
||||||
|
hostWindowServiceStub.setWidth(400);
|
||||||
|
|
||||||
|
hostWindowServiceStub.isXs().subscribe((status) => {
|
||||||
|
paginationComponent.isXs = status;
|
||||||
|
testFixture.detectChanges();
|
||||||
|
expectPages(testFixture, ['-« Previous', '+1', '2', '3', '4', '5', '-...', '10', '» Next']);
|
||||||
|
de = testFixture.debugElement.query(By.css('ul.pagination'));
|
||||||
|
expect(de.nativeElement.classList.contains('pagination-sm')).toBeTruthy();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('when showPaginator is true', () => {
|
||||||
|
// synchronous beforeEach
|
||||||
|
beforeEach(() => {
|
||||||
|
html = `
|
||||||
|
<ds-pagination #p='paginationComponent'
|
||||||
|
[paginationOptions]='paginationOptions'
|
||||||
|
[sortOptions]='sortOptions'
|
||||||
|
[collectionSize]='collectionSize'
|
||||||
|
(pageChange)='pageChanged($event)'
|
||||||
|
(pageSizeChange)='pageSizeChanged($event)'
|
||||||
|
[showPaginator]='false'
|
||||||
|
[objects]='objects'
|
||||||
|
(prev)="goPrev()"
|
||||||
|
(next)="goNext()"
|
||||||
|
>
|
||||||
|
<ul>
|
||||||
|
<li *ngFor='let item of collection | paginate: { itemsPerPage: paginationOptions.pageSize,
|
||||||
|
currentPage: paginationOptions.currentPage, totalItems: collectionSize }'> {{item}} </li>
|
||||||
|
</ul>
|
||||||
|
</ds-pagination>`;
|
||||||
|
testFixture = createTestComponent(html, TestComponent) as ComponentFixture<TestComponent>;
|
||||||
|
testComp = testFixture.componentInstance;
|
||||||
|
});
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
testComp.showPaginator = false;
|
||||||
|
testFixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('when clicking the previous arrow button', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
spyOn(testComp, 'goPrev');
|
||||||
|
testFixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should call goPrev method', () => {
|
||||||
|
const prev = testFixture.debugElement.query(By.css('#nav-prev'));
|
||||||
|
testFixture.detectChanges();
|
||||||
|
prev.triggerEventHandler('click', null);
|
||||||
|
expect(testComp.goPrev).toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('when clicking the next arrow button', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
spyOn(testComp, 'goNext');
|
||||||
|
testFixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should call goNext method', () => {
|
||||||
|
const next = testFixture.debugElement.query(By.css('#nav-next'));
|
||||||
|
testFixture.detectChanges();
|
||||||
|
next.triggerEventHandler('click', null);
|
||||||
|
expect(testComp.goNext).toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('check for prev and next button', () => {
|
||||||
|
it('shoud have a previous button', () => {
|
||||||
|
const prev = testFixture.debugElement.query(By.css('#nav-prev'));
|
||||||
|
testFixture.detectChanges();
|
||||||
|
expect(prev).toBeTruthy();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('shoud have a next button', () => {
|
||||||
|
const next = testFixture.debugElement.query(By.css('#nav-next'));
|
||||||
|
testFixture.detectChanges();
|
||||||
|
expect(next).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// declare a test component
|
// declare a test component
|
||||||
@@ -313,11 +387,19 @@ class TestComponent {
|
|||||||
collectionSize: number;
|
collectionSize: number;
|
||||||
paginationOptions = new PaginationComponentOptions();
|
paginationOptions = new PaginationComponentOptions();
|
||||||
sortOptions = new SortOptions('dc.title', SortDirection.ASC);
|
sortOptions = new SortOptions('dc.title', SortDirection.ASC);
|
||||||
|
showPaginator: boolean;
|
||||||
|
objects = {
|
||||||
|
payload: {
|
||||||
|
currentPage: 2,
|
||||||
|
totalPages: 100
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
this.collection = Array.from(new Array(100), (x, i) => `item ${i + 1}`);
|
this.collection = Array.from(new Array(100), (x, i) => `item ${i + 1}`);
|
||||||
this.collectionSize = 100;
|
this.collectionSize = 100;
|
||||||
this.paginationOptions.id = 'test';
|
this.paginationOptions.id = 'test';
|
||||||
|
this.showPaginator = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
pageChanged(page) {
|
pageChanged(page) {
|
||||||
@@ -327,4 +409,12 @@ class TestComponent {
|
|||||||
pageSizeChanged(pageSize) {
|
pageSizeChanged(pageSize) {
|
||||||
this.paginationOptions.pageSize = pageSize;
|
this.paginationOptions.pageSize = pageSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
goPrev() {
|
||||||
|
this.objects.payload.currentPage --;
|
||||||
|
}
|
||||||
|
|
||||||
|
goNext() {
|
||||||
|
this.objects.payload.currentPage ++;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -19,7 +19,11 @@ import { SortDirection, SortOptions } from '../../core/cache/models/sort-options
|
|||||||
import { hasValue } from '../empty.util';
|
import { hasValue } from '../empty.util';
|
||||||
import { PageInfo } from '../../core/shared/page-info.model';
|
import { PageInfo } from '../../core/shared/page-info.model';
|
||||||
import { PaginationService } from '../../core/pagination/pagination.service';
|
import { PaginationService } from '../../core/pagination/pagination.service';
|
||||||
import { map } from 'rxjs/operators';
|
import { map, take } from 'rxjs/operators';
|
||||||
|
import { RemoteData } from '../../core/data/remote-data';
|
||||||
|
import { PaginatedList } from '../../core/data/paginated-list.model';
|
||||||
|
import { ListableObject } from '../object-collection/shared/listable-object.model';
|
||||||
|
import { ViewMode } from '../../core/shared/view-mode.model';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The default pagination controls component.
|
* The default pagination controls component.
|
||||||
@@ -33,6 +37,11 @@ import { map } from 'rxjs/operators';
|
|||||||
encapsulation: ViewEncapsulation.Emulated
|
encapsulation: ViewEncapsulation.Emulated
|
||||||
})
|
})
|
||||||
export class PaginationComponent implements OnDestroy, OnInit {
|
export class PaginationComponent implements OnDestroy, OnInit {
|
||||||
|
/**
|
||||||
|
* ViewMode that should be passed to {@link ListableObjectComponentLoaderComponent}.
|
||||||
|
*/
|
||||||
|
viewMode: ViewMode = ViewMode.ListElement;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Number of items in collection.
|
* Number of items in collection.
|
||||||
*/
|
*/
|
||||||
@@ -53,6 +62,26 @@ export class PaginationComponent implements OnDestroy, OnInit {
|
|||||||
*/
|
*/
|
||||||
@Input() sortOptions: SortOptions;
|
@Input() sortOptions: SortOptions;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether or not the pagination should be rendered as simple previous and next buttons instead of the normal pagination
|
||||||
|
*/
|
||||||
|
@Input() showPaginator = true;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The current pagination configuration
|
||||||
|
*/
|
||||||
|
@Input() config?: PaginationComponentOptions;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The list of listable objects to render in this component
|
||||||
|
*/
|
||||||
|
@Input() objects: RemoteData<PaginatedList<ListableObject>>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The current sorting configuration
|
||||||
|
*/
|
||||||
|
@Input() sortConfig: SortOptions;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An event fired when the page is changed.
|
* An event fired when the page is changed.
|
||||||
* Event's payload equals to the newly selected page.
|
* Event's payload equals to the newly selected page.
|
||||||
@@ -163,6 +192,15 @@ export class PaginationComponent implements OnDestroy, OnInit {
|
|||||||
*/
|
*/
|
||||||
private subs: Subscription[] = [];
|
private subs: Subscription[] = [];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If showPaginator is set to true, emit when the previous button is clicked
|
||||||
|
*/
|
||||||
|
@Output() prev = new EventEmitter<boolean>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If showPaginator is set to true, emit when the next button is clicked
|
||||||
|
*/
|
||||||
|
@Output() next = new EventEmitter<boolean>();
|
||||||
/**
|
/**
|
||||||
* Method provided by Angular. Invoked after the constructor.
|
* Method provided by Angular. Invoked after the constructor.
|
||||||
*/
|
*/
|
||||||
@@ -347,4 +385,31 @@ export class PaginationComponent implements OnDestroy, OnInit {
|
|||||||
map((hasMultiplePages) => hasMultiplePages || !this.hidePagerWhenSinglePage)
|
map((hasMultiplePages) => hasMultiplePages || !this.hidePagerWhenSinglePage)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Go to the previous page
|
||||||
|
*/
|
||||||
|
goPrev() {
|
||||||
|
this.prev.emit(true);
|
||||||
|
this.updatePagination(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Go to the next page
|
||||||
|
*/
|
||||||
|
goNext() {
|
||||||
|
this.next.emit(true);
|
||||||
|
this.updatePagination(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update page when next or prev button is clicked
|
||||||
|
* @param value
|
||||||
|
*/
|
||||||
|
updatePagination(value: number) {
|
||||||
|
this.paginationService.getCurrentPagination(this.id, this.paginationOptions).pipe(take(1)).subscribe((currentPaginationOptions) => {
|
||||||
|
this.updateParams({page: (currentPaginationOptions.currentPage + value).toString()});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -678,9 +678,9 @@
|
|||||||
|
|
||||||
"browse.metadata.title.breadcrumbs": "Browse by Title",
|
"browse.metadata.title.breadcrumbs": "Browse by Title",
|
||||||
|
|
||||||
"browse.next.button": "Next",
|
"pagination.next.button": "Next",
|
||||||
|
|
||||||
"browse.previous.button": "Previous",
|
"pagination.previous.button": "Previous",
|
||||||
|
|
||||||
"browse.startsWith.choose_start": "(Choose start)",
|
"browse.startsWith.choose_start": "(Choose start)",
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user