11import { Component , Input , OnInit , ViewChild } from '@angular/core' ;
22import { NgbCarousel , NgbSlideEvent , NgbSlideEventSource } from '@ng-bootstrap/ng-bootstrap' ;
3- import { BehaviorSubject , concatMap , from , Observable , of } from 'rxjs' ;
3+ import { BehaviorSubject , from , Observable } from 'rxjs' ;
44import { filter , map , mergeMap , reduce , switchMap , take } from 'rxjs/operators' ;
55import { PaginatedList } from '../../core/data/paginated-list.model' ;
66import { BitstreamFormat } from '../../core/shared/bitstream-format.model' ;
@@ -18,8 +18,8 @@ import { SearchObjects } from '../search/models/search-objects.model';
1818import { SortOptions } from '../../core/cache/models/sort-options.model' ;
1919import { PaginationComponentOptions } from '../pagination/pagination-component-options.model' ;
2020import { PaginatedSearchOptions } from '../search/models/paginated-search-options.model' ;
21- import { DSpaceObjectType } from '../../core/shared/dspace-object-type.model' ;
2221import { InternalLinkService } from '../../core/services/internal-link.service' ;
22+ import difference from 'lodash/difference' ;
2323
2424/**
2525 * Component representing the Carousel component section.
@@ -38,12 +38,6 @@ export class CarouselComponent implements OnInit {
3838 @Input ( )
3939 carouselOptions : CarouselOptions ;
4040
41- /**
42- * Option to activate dependency between slide event and pagination
43- */
44- @Input ( )
45- changePageOnSlide = false ;
46-
4741 /**
4842 * Carousel section title field.
4943 */
@@ -89,43 +83,27 @@ export class CarouselComponent implements OnInit {
8983 isLoading$ = new BehaviorSubject ( true ) ;
9084
9185 /**
92- * The total search item pages
93- */
94- totalPages = 0 ;
95- /**
96- * the total number of item available
97- */
98- totalItems = 0 ;
99-
100- /**
101- * The map of the item to show
102- */
103- itemMap : Map < number , ItemSearchResult [ ] > = new Map ( ) ;
104-
105- /**
106- * The page number currently visualized
86+ * The map of the loaded bitstreams
10787 */
108- currentPage = 1 ;
88+ pageToBitstreamsMap : Map < number , ItemSearchResult [ ] > = new Map ( ) ;
10989
11090 /**
111- * Pages displayed in pagination controls
91+ * The page number that drives the bitstreams preload
11292 */
113- currentlyVisiblePages$ : BehaviorSubject < ( string | number ) [ ] > = new BehaviorSubject < ( string | number ) [ ] > ( null ) ;
93+ currentSliderPage = 1 ;
11494
11595 /**
11696 * Items contained in currently active page
11797 */
118- currentPageItems$ : BehaviorSubject < ItemSearchResult [ ] > = new BehaviorSubject < ItemSearchResult [ ] > ( [ ] ) ;
119-
120- /**
121- * Number of pages to be shown in the pagination bar (boundaries excluded)
122- * @private
123- */
98+ carouselItems$ : BehaviorSubject < ItemSearchResult [ ] > = new BehaviorSubject < ItemSearchResult [ ] > ( [ ] ) ;
12499
125- private pagesToVisualize = 10 ;
126100
127101 private paginationOptionId : string ;
128102
103+ private pageSize = 5 ;
104+
105+ private slideLoadingBuffer = 2 ;
106+
129107
130108
131109 constructor (
@@ -144,21 +122,18 @@ export class CarouselComponent implements OnInit {
144122 this . retrieveItems ( ) . pipe (
145123 mergeMap ( ( searchResult : SearchObjects < Item > ) => {
146124 if ( isNotEmpty ( searchResult ) ) {
147- this . totalPages = searchResult . totalPages ;
148- this . totalItems = searchResult . totalElements ;
149125 const items = searchResult . page ;
150- this . itemMap . set ( searchResult . currentPage , items ) ;
126+ this . carouselItems$ . next ( items ) ;
151127 this . isLoading$ . next ( true ) ;
152- return this . findAllBitstreamImages ( items ) ;
128+
129+ return this . findAllBitstreamImages ( items . filter ( ( _ , i ) => i <= this . pageSize - 1 ) ) ;
153130 } else {
154131 return null ;
155132 }
156133 } ) ,
157134 take ( 1 )
158135 ) . subscribe ( ( res ) => {
159136 this . itemToImageHrefMap$ . next ( res ) ;
160- this . currentlyVisiblePages$ . next ( this . getPagesToVisualize ( ) ) ;
161- this . currentPageItems$ . next ( this . getCurrentPageItems ( ) ) ;
162137 this . isLoading$ . next ( false ) ;
163138 } ) ;
164139 }
@@ -188,29 +163,20 @@ export class CarouselComponent implements OnInit {
188163 this . togglePaused ( ) ;
189164 }
190165
191- if ( this . changePageOnSlide ) {
192- const previousSlideIndex = parseInt ( slideEvent . prev . split ( '-' ) [ 2 ] , 10 ) ;
193- const currentSlideIndex = parseInt ( slideEvent . current . split ( '-' ) [ 2 ] , 10 ) ;
194- const direction = slideEvent . direction ;
195- const pageSlidesBounds = {
196- min : ( this . carouselOptions . numberOfItems * this . currentPage ) - this . carouselOptions . numberOfItems ,
197- max : ( this . carouselOptions . numberOfItems * this . currentPage )
198- } ;
199- const isPreviousIndexInCurrentPage = ( previousSlideIndex + 1 >= pageSlidesBounds . min ) && previousSlideIndex + 1 <= pageSlidesBounds . max ;
200-
201- if ( currentSlideIndex < previousSlideIndex && ! ( this . currentPage === this . totalPages ) && direction === 'left' && isPreviousIndexInCurrentPage ) {
202- this . changePage ( this . currentPage + 1 ) ;
203- } else if ( previousSlideIndex < currentSlideIndex && direction === 'right' && this . currentPage !== 1 && isPreviousIndexInCurrentPage ) {
204- this . changePage ( this . currentPage - 1 ) ;
205- }
206- }
166+ const currentSlideIndex = parseInt ( slideEvent . current . split ( '-' ) [ 2 ] , 10 ) ;
167+ const currentPage = Math . ceil ( currentSlideIndex / this . pageSize ) ;
207168
169+ if ( ! this . pageToBitstreamsMap . get ( currentPage + 1 ) && currentSlideIndex + this . slideLoadingBuffer === currentPage * this . pageSize ) {
170+ this . loadNextPageBitstreams ( ) ;
171+ }
208172 }
209173
210174 /**
211175 * Find the first image of each item
212176 */
213177 findAllBitstreamImages ( items : ItemSearchResult [ ] ) : Observable < Map < string , string > > {
178+ this . pageToBitstreamsMap . set ( this . currentSliderPage , items ) ;
179+
214180 return from ( items ) . pipe (
215181 map ( ( itemSR ) => itemSR . indexableObject ) ,
216182 mergeMap ( ( item ) => this . bitstreamDataService . showableByItem (
@@ -244,20 +210,18 @@ export class CarouselComponent implements OnInit {
244210 /**
245211 * Retrieve items by the given page number
246212 *
247- * @param currentPage
248213 */
249- retrieveItems ( currentPage : number = 1 ) : Observable < SearchObjects < Item > > {
214+ retrieveItems ( ) : Observable < SearchObjects < Item > > {
250215 const pagination : PaginationComponentOptions = Object . assign ( new PaginationComponentOptions ( ) , {
251216 id : this . paginationOptionId ,
252217 pageSize : this . carouselOptions . numberOfItems ,
253- currentPage : currentPage
218+ currentPage : 1
254219 } ) ;
255220
256221 const paginatedSearchOptions = new PaginatedSearchOptions ( {
257222 configuration : this . carouselOptions . discoveryConfiguration ,
258223 pagination : pagination ,
259224 sort : new SortOptions ( this . carouselOptions . sortField , this . carouselOptions . sortDirection ) ,
260- dsoTypes : [ DSpaceObjectType . ITEM ] ,
261225 projection : 'preventMetadataSecurity'
262226 } ) ;
263227 return this . searchManager . search ( paginatedSearchOptions ) . pipe (
@@ -272,93 +236,29 @@ export class CarouselComponent implements OnInit {
272236 ) ;
273237 }
274238
275- getCurrentPageItems ( ) : ItemSearchResult [ ] {
276- return this . itemMap . get ( this . currentPage ) ;
277- }
278239
279240 pages = ( ) => {
280- return Array . from ( { length : this . totalPages } , ( _ , i ) => i + 1 ) ;
281- } ;
282-
283- /**
284- * return pages in scope for loading
285- */
286- getPagesToVisualize ( ) : ( string | number ) [ ] {
287- const pagesArray = this . pages ( ) ;
288- let currentPagesInScope : ( string | number ) [ ] = this . currentPage > this . pagesToVisualize ?
289- (
290- this . currentPage - 1 + this . pagesToVisualize > this . totalPages ?
291- [ ...pagesArray . slice ( this . currentPage - this . pagesToVisualize , this . currentPage + this . pagesToVisualize ) ] :
292- [ ...pagesArray . slice ( this . currentPage - 1 , this . currentPage + this . pagesToVisualize ) ]
293- ) :
294- [ ...pagesArray . slice ( 0 , this . pagesToVisualize ) ] ;
295-
296- if ( currentPagesInScope . some ( page => page > this . pagesToVisualize ) ) {
297- currentPagesInScope = [ 1 , '...' , ...currentPagesInScope ] ;
298- currentPagesInScope = currentPagesInScope . includes ( this . totalPages ) ? currentPagesInScope : [ ...currentPagesInScope , '...' , this . totalPages ] ;
299- } else {
300- currentPagesInScope = [ 1 , ...currentPagesInScope . filter ( page => page !== 1 ) , '...' , this . totalPages ] ;
301- }
302-
303- return currentPagesInScope ;
304- }
305- previousPage = ( ) => {
306- if ( this . currentPage > 1 ) {
307- this . currentPage -- ;
308-
309- if ( ! this . itemMap . get ( this . currentPage ) ) {
310- this . isLoading$ . next ( true ) ;
311- this . retrieveMoreItems ( this . currentPage ) ;
312- }
313- }
241+ return Array . from ( { length : this . carouselOptions . numberOfItems / this . pageSize } , ( _ , i ) => i + 1 ) ;
314242 } ;
315243
316- nextPage = ( ) => {
317- if ( this . currentPage < this . totalPages ) {
318- this . currentPage ++ ;
319-
320- if ( ! this . itemMap . get ( this . currentPage ) ) {
321- this . isLoading$ . next ( true ) ;
322- this . retrieveMoreItems ( this . currentPage ) ;
323- }
324- }
325- } ;
326244
327- changePage = ( page : number ) => {
328- this . currentPage = page ;
245+ private loadNextPageBitstreams ( ) : void {
246+ const items = this . carouselItems$ . value ;
247+ const itemsWithLoadedImages = [ ] . concat ( ( Array . from ( { length : this . currentSliderPage } , ( _ , i ) => i + 1 ) . map ( page => this . pageToBitstreamsMap . get ( page ) ) ) ) ;
248+ const itemsWithoutBistreamsInNextPage = difference ( items , itemsWithLoadedImages ) . filter ( item => ( items . indexOf ( item ) > itemsWithLoadedImages . length - 1 ) && items . indexOf ( item ) < ( this . currentSliderPage + 1 ) * this . pageSize ) ;
329249
330- if ( ! this . itemMap . get ( this . currentPage ) ) {
331- this . isLoading$ . next ( true ) ;
332- this . retrieveMoreItems ( this . currentPage ) ;
333- }
334- } ;
335-
336- retrieveMoreItems ( page : number ) {
337- of ( page ) . pipe (
338- concatMap ( ( currentPage : number ) => this . retrieveItems ( currentPage ) . pipe (
339- mergeMap ( ( searchResult : SearchObjects < Item > ) => {
340- if ( isNotEmpty ( searchResult ) ) {
341- const items = searchResult . page ;
342- this . itemMap . set ( searchResult . currentPage , items ) ;
343-
344- return this . findAllBitstreamImages ( items ) ;
345- } else {
346- return of ( null ) ;
347- }
348- } ) ,
349- take ( 1 ) ,
350- ) ) ,
250+ this . findAllBitstreamImages ( itemsWithoutBistreamsInNextPage ) . pipe (
251+ take ( 1 ) ,
351252 reduce ( ( itemToImageHrefMap , value ) => {
352253 return new Map ( [ ...Array . from ( itemToImageHrefMap . entries ( ) ) , ...Array . from ( value . entries ( ) ) ] ) ;
353254 } , new Map ( ) ) ,
354- ) . subscribe ( ( itemToImageHrefMap : Map < string , string > ) => {
255+ ) . subscribe ( ( ( itemToImageHrefMap : Map < string , string > ) => {
256+ this . currentSliderPage += 1 ;
355257 if ( isNotEmpty ( itemToImageHrefMap ) ) {
356258 this . itemToImageHrefMap$ . next ( new Map ( [ ...Array . from ( this . itemToImageHrefMap$ . value . entries ( ) ) , ...Array . from ( itemToImageHrefMap . entries ( ) ) ] ) ) ;
357259 }
358- this . currentlyVisiblePages$ . next ( this . getPagesToVisualize ( ) ) ;
359- this . currentPageItems$ . next ( this . getCurrentPageItems ( ) ) ;
360- this . isLoading$ . next ( false ) ;
361- } ) ;
260+ } ) ) ;
261+
362262 }
363263
364264}
0 commit comments