diff --git a/src/app/+item-page/edit-item-page/edit-item-page.module.ts b/src/app/+item-page/edit-item-page/edit-item-page.module.ts index 076e13582b..1d379cccf8 100644 --- a/src/app/+item-page/edit-item-page/edit-item-page.module.ts +++ b/src/app/+item-page/edit-item-page/edit-item-page.module.ts @@ -27,6 +27,7 @@ import { ItemEditBitstreamBundleComponent } from './item-bitstreams/item-edit-bi import { BundleDataService } from '../../core/data/bundle-data.service'; import { DragDropModule } from '@angular/cdk/drag-drop'; import { ItemEditBitstreamDragHandleComponent } from './item-bitstreams/item-edit-bitstream-drag-handle/item-edit-bitstream-drag-handle.component'; +import { PaginatedDragAndDropBitstreamListComponent } from './item-bitstreams/item-edit-bitstream-bundle/paginated-drag-and-drop-bitstream-list/paginated-drag-and-drop-bitstream-list.component'; /** * Module that contains all components related to the Edit Item page administrator functionality @@ -57,6 +58,7 @@ import { ItemEditBitstreamDragHandleComponent } from './item-bitstreams/item-edi EditInPlaceFieldComponent, ItemEditBitstreamComponent, ItemEditBitstreamBundleComponent, + PaginatedDragAndDropBitstreamListComponent, EditInPlaceFieldComponent, EditRelationshipComponent, EditRelationshipListComponent, diff --git a/src/app/+item-page/edit-item-page/item-bitstreams/item-edit-bitstream-bundle/item-edit-bitstream-bundle.component.html b/src/app/+item-page/edit-item-page/item-bitstreams/item-edit-bitstream-bundle/item-edit-bitstream-bundle.component.html index 97d1bcb391..05e48cb9b3 100644 --- a/src/app/+item-page/edit-item-page/item-bitstreams/item-edit-bitstream-bundle/item-edit-bitstream-bundle.component.html +++ b/src/app/+item-page/edit-item-page/item-bitstreams/item-edit-bitstream-bundle/item-edit-bitstream-bundle.component.html @@ -17,29 +17,5 @@ - -
-
- -
- -
-
-
-
-
+ diff --git a/src/app/+item-page/edit-item-page/item-bitstreams/item-edit-bitstream-bundle/item-edit-bitstream-bundle.component.ts b/src/app/+item-page/edit-item-page/item-bitstreams/item-edit-bitstream-bundle/item-edit-bitstream-bundle.component.ts index 906bebc6c7..c8e12d53b9 100644 --- a/src/app/+item-page/edit-item-page/item-bitstreams/item-edit-bitstream-bundle/item-edit-bitstream-bundle.component.ts +++ b/src/app/+item-page/edit-item-page/item-bitstreams/item-edit-bitstream-bundle/item-edit-bitstream-bundle.component.ts @@ -7,7 +7,7 @@ import { toBitstreamsArray } from '../../../../core/shared/item-bitstreams-utils import { map, switchMap, take, tap } from 'rxjs/operators'; import { Bitstream } from '../../../../core/shared/bitstream.model'; import { Item } from '../../../../core/shared/item.model'; -import { CdkDragDrop } from '@angular/cdk/drag-drop'; +import { CdkDragDrop, CdkDragStart } from '@angular/cdk/drag-drop'; import { RemoteData } from '../../../../core/data/remote-data'; import { PaginatedList } from '../../../../core/data/paginated-list'; import { BundleDataService } from '../../../../core/data/bundle-data.service'; @@ -42,85 +42,10 @@ export class ItemEditBitstreamBundleComponent implements OnInit { */ @Input() item: Item; - /** - * The bitstreams within this bundle retrieved from the REST API - */ - bitstreamsRD$: Observable>>; - - /** - * The updates to the current bundle - */ - updates$: Observable; - - /** - * The amount of one bitstreams one "batch" resembles - * The user is able to increase the amount of bitstreams displayed per bundle by this batch size until all are shown - */ - batchSize = 2; - - /** - * The page options to use for fetching the bitstreams - */ - bitstreamsOptions = Object.assign(new PaginationComponentOptions(),{ - id: 'bitstreams-pagination-options', - currentPage: 1, - pageSize: this.batchSize - }); - - /** - * The current page we're displaying for this bundle - */ - currentPage$ = new BehaviorSubject(1); - - /** - * A list of pages that have been initialized in the field-update store - */ - initializedPages: number[] = []; - - constructor(private objectUpdatesService: ObjectUpdatesService, - private bundleService: BundleDataService, - private viewContainerRef: ViewContainerRef) { + constructor(private viewContainerRef: ViewContainerRef) { } ngOnInit(): void { - this.bitstreamsRD$ = this.currentPage$.pipe( - switchMap((page: number) => this.bundleService.getBitstreams(this.bundle.id, - new PaginatedSearchOptions({pagination: Object.assign({}, this.bitstreamsOptions, { currentPage: page })}))) - ); - this.updates$ = this.bitstreamsRD$.pipe( - toBitstreamsArray(), - tap((bitstreams: Bitstream[]) => { - // Pages in the field-update store are indexed starting at 0 (because they're stored in an array of pages) - const updatesPage = this.currentPage$.value - 1; - if (isEmpty(this.initializedPages)) { - // No updates have been initialized yet for this bundle, initialize the first page - this.objectUpdatesService.initializeWithCustomOrder(this.bundle.self, bitstreams, new Date(), this.batchSize, updatesPage); - this.initializedPages.push(updatesPage); - } else if (this.initializedPages.indexOf(updatesPage) < 0) { - // Updates were initialized for this bundle, but not the page we're on. Add the current page to the field-update store for this bundle - this.objectUpdatesService.addPageToCustomOrder(this.bundle.self, bitstreams, updatesPage); - this.initializedPages.push(updatesPage); - } - }), - switchMap((bitstreams: Bitstream[]) => this.objectUpdatesService.getFieldUpdatesByCustomOrder(this.bundle.self, bitstreams, this.currentPage$.value - 1)) - ); - this.viewContainerRef.createEmbeddedView(this.bundleView); } - - /** - * Update the current page - * @param page - */ - switchPage(page: number) { - this.currentPage$.next(page); - } - - /** - * A bitstream was moved, send updates to the store - * @param event - */ - drop(event: CdkDragDrop) { - this.objectUpdatesService.saveMoveFieldUpdate(this.bundle.self, event.previousIndex, event.currentIndex, this.currentPage$.value - 1, this.currentPage$.value - 1); - } } diff --git a/src/app/+item-page/edit-item-page/item-bitstreams/item-edit-bitstream-bundle/paginated-drag-and-drop-bitstream-list/paginated-drag-and-drop-bitstream-list.component.html b/src/app/+item-page/edit-item-page/item-bitstreams/item-edit-bitstream-bundle/paginated-drag-and-drop-bitstream-list/paginated-drag-and-drop-bitstream-list.component.html new file mode 100644 index 0000000000..d46fffae18 --- /dev/null +++ b/src/app/+item-page/edit-item-page/item-bitstreams/item-edit-bitstream-bundle/paginated-drag-and-drop-bitstream-list/paginated-drag-and-drop-bitstream-list.component.html @@ -0,0 +1,28 @@ + +
+
+ +
+ +
+
+
+
+
diff --git a/src/app/+item-page/edit-item-page/item-bitstreams/item-edit-bitstream-bundle/paginated-drag-and-drop-bitstream-list/paginated-drag-and-drop-bitstream-list.component.ts b/src/app/+item-page/edit-item-page/item-bitstreams/item-edit-bitstream-bundle/paginated-drag-and-drop-bitstream-list/paginated-drag-and-drop-bitstream-list.component.ts new file mode 100644 index 0000000000..6e96d2eb9e --- /dev/null +++ b/src/app/+item-page/edit-item-page/item-bitstreams/item-edit-bitstream-bundle/paginated-drag-and-drop-bitstream-list/paginated-drag-and-drop-bitstream-list.component.ts @@ -0,0 +1,40 @@ +import { AbstractPaginatedDragAndDropListComponent } from '../../../../../shared/pagination-drag-and-drop/abstract-paginated-drag-and-drop-list.component'; +import { Component, Input, OnInit } from '@angular/core'; +import { Bundle } from '../../../../../core/shared/bundle.model'; +import { Bitstream } from '../../../../../core/shared/bitstream.model'; +import { ObjectUpdatesService } from '../../../../../core/data/object-updates/object-updates.service'; +import { BundleDataService } from '../../../../../core/data/bundle-data.service'; +import { switchMap } from 'rxjs/operators'; +import { PaginatedSearchOptions } from '../../../../../shared/search/paginated-search-options.model'; + +@Component({ + selector: 'ds-paginated-drag-and-drop-bitstream-list', + styleUrls: ['../../item-bitstreams.component.scss'], + templateUrl: './paginated-drag-and-drop-bitstream-list.component.html', +}) +export class PaginatedDragAndDropBitstreamListComponent extends AbstractPaginatedDragAndDropListComponent implements OnInit { + /** + * The bundle to display bitstreams for + */ + @Input() bundle: Bundle; + + constructor(protected objectUpdatesService: ObjectUpdatesService, + protected bundleService: BundleDataService) { + super(objectUpdatesService); + } + + ngOnInit() { + super.ngOnInit(); + } + + initializeObjectsRD(): void { + this.objectsRD$ = this.currentPage$.pipe( + switchMap((page: number) => this.bundleService.getBitstreams(this.bundle.id, + new PaginatedSearchOptions({pagination: Object.assign({}, this.options, { currentPage: page })}))) + ); + } + + initializeURL(): void { + this.url = this.bundle.self; + } +} diff --git a/src/app/core/shared/operators.ts b/src/app/core/shared/operators.ts index eb8c57b2d2..af927c3d46 100644 --- a/src/app/core/shared/operators.ts +++ b/src/app/core/shared/operators.ts @@ -137,3 +137,13 @@ export const getFirstSucceededRemoteDataPayload = () => hasValueOperator(), take(1) ); + +/** + * Operator for turning the current page of bitstreams into an array + */ +export const paginatedListToArray = () => + (source: Observable>>): Observable => + source.pipe( + hasValueOperator(), + map((objectRD: RemoteData>) => objectRD.payload.page.filter((object: T) => hasValue(object))) + ); diff --git a/src/app/shared/pagination-drag-and-drop/abstract-paginated-drag-and-drop-list.component.ts b/src/app/shared/pagination-drag-and-drop/abstract-paginated-drag-and-drop-list.component.ts new file mode 100644 index 0000000000..140bd84e0c --- /dev/null +++ b/src/app/shared/pagination-drag-and-drop/abstract-paginated-drag-and-drop-list.component.ts @@ -0,0 +1,124 @@ +import { FieldUpdates } from '../../core/data/object-updates/object-updates.reducer'; +import { Observable } from 'rxjs/internal/Observable'; +import { RemoteData } from '../../core/data/remote-data'; +import { PaginatedList } from '../../core/data/paginated-list'; +import { PaginationComponentOptions } from '../pagination/pagination-component-options.model'; +import { BehaviorSubject } from 'rxjs/internal/BehaviorSubject'; +import { ObjectUpdatesService } from '../../core/data/object-updates/object-updates.service'; +import { switchMap, tap } from 'rxjs/operators'; +import { Bitstream } from '../../core/shared/bitstream.model'; +import { isEmpty } from '../empty.util'; +import { paginatedListToArray } from '../../core/shared/operators'; +import { DSpaceObject } from '../../core/shared/dspace-object.model'; +import { CdkDragDrop, CdkDragStart } from '@angular/cdk/drag-drop'; + +export abstract class AbstractPaginatedDragAndDropListComponent { + /** + * The URL to use for accessing the object updates from this list + */ + url: string; + + /** + * The objects to retrieve data for and transform into field updates + */ + objectsRD$: Observable>>; + + /** + * The updates to the current list + */ + updates$: Observable; + + /** + * The amount of objects to display per page + */ + pageSize = 2; + + /** + * The page options to use for fetching the objects + * Start at page 1 and always use the set page size + */ + options = Object.assign(new PaginationComponentOptions(),{ + id: 'paginated-drag-and-drop-options', + currentPage: 1, + pageSize: this.pageSize + }); + + /** + * The current page being displayed + */ + currentPage$ = new BehaviorSubject(1); + + /** + * The last page we were on when we started dragging an item + * This is used to keep track of the original page the drag started from + */ + lastPage$ = new BehaviorSubject(1); + + /** + * A list of pages that have been initialized in the field-update store + */ + initializedPages: number[] = []; + + protected constructor(protected objectUpdatesService: ObjectUpdatesService) { + } + + ngOnInit() { + this.initializeObjectsRD(); + this.initializeURL(); + this.initializeUpdates(); + } + + /** + * Overwrite this method to define how the list of objects is initialized and updated + */ + abstract initializeObjectsRD(): void; + + /** + * Overwrite this method to define how the URL is set + */ + abstract initializeURL(): void; + + /** + * Initialize the field-updates in the store + * This method ensures (new) pages displayed are automatically added to the field-update store when the objectsRD updates + */ + initializeUpdates(): void { + this.updates$ = this.objectsRD$.pipe( + paginatedListToArray(), + tap((objects: DSpaceObject[]) => { + // Pages in the field-update store are indexed starting at 0 (because they're stored in an array of pages) + const updatesPage = this.currentPage$.value - 1; + if (isEmpty(this.initializedPages)) { + // No updates have been initialized yet for this list, initialize the first page + this.objectUpdatesService.initializeWithCustomOrder(this.url, objects, new Date(), this.pageSize, updatesPage); + this.initializedPages.push(updatesPage); + } else if (this.initializedPages.indexOf(updatesPage) < 0) { + // Updates were initialized for this list, but not the page we're on. Add the current page to the field-update store for this list + this.objectUpdatesService.addPageToCustomOrder(this.url, objects, updatesPage); + this.initializedPages.push(updatesPage); + } + }), + switchMap((bitstreams: Bitstream[]) => this.objectUpdatesService.getFieldUpdatesByCustomOrder(this.url, bitstreams, this.currentPage$.value - 1)) + ); + } + + /** + * Update the current page + * @param page + */ + switchPage(page: number) { + this.currentPage$.next(page); + } + + /** + * A bitstream was moved, send updates to the store + * @param event + */ + drop(event: CdkDragDrop) { + this.objectUpdatesService.saveMoveFieldUpdate(this.url, event.previousIndex, event.currentIndex, this.lastPage$.value - 1, this.currentPage$.value - 1); + } + + dragStarted(event: CdkDragStart) { + this.lastPage$.next(this.currentPage$.value); + } +} diff --git a/src/app/shared/pagination-drag-and-drop/pagination-drag-and-drop.component.html b/src/app/shared/pagination-drag-and-drop/pagination-drag-and-drop.component.html deleted file mode 100644 index 033ef90834..0000000000 --- a/src/app/shared/pagination-drag-and-drop/pagination-drag-and-drop.component.html +++ /dev/null @@ -1,11 +0,0 @@ - - - diff --git a/src/app/shared/pagination-drag-and-drop/pagination-drag-and-drop.component.ts b/src/app/shared/pagination-drag-and-drop/pagination-drag-and-drop.component.ts deleted file mode 100644 index 2d87aa89d8..0000000000 --- a/src/app/shared/pagination-drag-and-drop/pagination-drag-and-drop.component.ts +++ /dev/null @@ -1,55 +0,0 @@ -import { Component, EventEmitter, Input, Output } from '@angular/core'; -import { PaginationComponentOptions } from '../pagination/pagination-component-options.model'; -import { PaginatedList } from '../../core/data/paginated-list'; - -@Component({ - selector: 'ds-pagination-drag-and-drop', - templateUrl: './pagination-drag-and-drop.component.html', -}) -export class PaginationDragAndDropComponent { - /** - * Configuration for the NgbPagination component. - */ - @Input() paginationOptions: PaginationComponentOptions; - - /** - * The paginated list being displayed - */ - @Input() paginatedList: PaginatedList; - - /** - * Option for hiding the pagination detail - */ - @Input() public hidePaginationDetail = false; - - /** - * Option for hiding the gear - */ - @Input() public hideGear = false; - - /** - * Option for hiding the pager when there is less than 2 pages - */ - @Input() public hidePagerWhenSinglePage = true; - - /** - * Option for disabling updating and reading route parameters on pagination changes - * In other words, changing pagination won't add or update the url parameters on the current page, and the url - * parameters won't affect the pagination of this component - */ - @Input() public disableRouteParameterUpdate = false; - - /** - * An event fired when the page is changed. - * Event's payload equals to the newly selected page. - */ - @Output() pageChange: EventEmitter = new EventEmitter(); - - /** - * Switch to a different page - * @param page Page to switch to - */ - switchPage(page: number) { - this.pageChange.emit(page); - } -} diff --git a/src/app/shared/shared.module.ts b/src/app/shared/shared.module.ts index a02b77c0b8..cd6417d964 100644 --- a/src/app/shared/shared.module.ts +++ b/src/app/shared/shared.module.ts @@ -178,7 +178,6 @@ import { ImportableListItemControlComponent } from './object-collection/shared/i import { DragDropModule } from '@angular/cdk/drag-drop'; import { ExistingMetadataListElementComponent } from './form/builder/ds-dynamic-form-ui/existing-metadata-list-element/existing-metadata-list-element.component'; import { CustomSwitchComponent } from './form/builder/ds-dynamic-form-ui/models/custom-switch/custom-switch.component'; -import { PaginationDragAndDropComponent } from './pagination-drag-and-drop/pagination-drag-and-drop.component'; const MODULES = [ // Do NOT include UniversalModule, HttpModule, or JsonpModule here @@ -264,7 +263,6 @@ const COMPONENTS = [ AbstractListableElementComponent, ObjectCollectionComponent, PaginationComponent, - PaginationDragAndDropComponent, SearchFormComponent, PageWithSidebarComponent, SidebarDropdownComponent,