1- import { Component , Inject , Input , OnInit , ViewChild } from '@angular/core' ;
1+ import { Component , Input , OnInit , ViewChild } from '@angular/core' ;
22import { NgbCarousel , NgbSlideEvent , NgbSlideEventSource } from '@ng-bootstrap/ng-bootstrap' ;
3- import { BehaviorSubject , concatMap , from , Observable } 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' ;
77import { Bitstream } from '../../core/shared/bitstream.model' ;
88import { BitstreamDataService } from '../../core/data/bitstream-data.service' ;
9- import { NativeWindowRef , NativeWindowService } from '../../core/services/window.service' ;
109import { getFirstCompletedRemoteData } from '../../core/shared/operators' ;
1110import { hasValue , isNotEmpty } from '../empty.util' ;
1211import { ItemSearchResult } from '../object-collection/shared/item-search-result.model' ;
@@ -19,8 +18,8 @@ import { SearchObjects } from '../search/models/search-objects.model';
1918import { SortOptions } from '../../core/cache/models/sort-options.model' ;
2019import { PaginationComponentOptions } from '../pagination/pagination-component-options.model' ;
2120import { PaginatedSearchOptions } from '../search/models/paginated-search-options.model' ;
22- import { DSpaceObjectType } from '../../core/shared/dspace-object-type.model' ;
2321import { InternalLinkService } from '../../core/services/internal-link.service' ;
22+ import difference from 'lodash/difference' ;
2423
2524/**
2625 * Component representing the Carousel component section.
@@ -84,56 +83,49 @@ export class CarouselComponent implements OnInit {
8483 isLoading$ = new BehaviorSubject ( true ) ;
8584
8685 /**
87- * The total search item pages
86+ * The map of the loaded bitstreams
8887 */
89- totalPages = 0 ;
90- /**
91- * the total number of item available
92- */
93- totalItems = 0 ;
88+ pageToBitstreamsMap : Map < number , ItemSearchResult [ ] > = new Map ( ) ;
9489
9590 /**
96- * The list of the item to show
91+ * The page number that drives the bitstreams preload
9792 */
98- itemList : ItemSearchResult [ ] = [ ] ;
93+ currentSliderPage = 1 ;
9994
10095 /**
101- * A boolean representing if there are more items to be loaded
102- */
103- hasMoreToLoad : boolean ;
104- /**
105- * The page number currently visualized
96+ * Items contained in currently active page
10697 */
107- currentPage = 1 ;
98+ carouselItems$ : BehaviorSubject < ItemSearchResult [ ] > = new BehaviorSubject < ItemSearchResult [ ] > ( [ ] ) ;
10899
109- itemPlaceholderList : number [ ] ;
100+ private paginationOptionId : string ;
101+
102+ private pageSize = 5 ;
103+
104+ private slideLoadingBuffer = 2 ;
110105
111106
112107
113108 constructor (
114109 protected bitstreamDataService : BitstreamDataService ,
115110 private searchManager : SearchManager ,
116111 public internalLinkService : InternalLinkService ,
117- @Inject ( NativeWindowService ) private _window : NativeWindowRef ,
118- ) {
119- }
112+ ) { }
120113
121114 ngOnInit ( ) {
122115 this . title = this . carouselOptions . title ;
123116 this . link = this . carouselOptions . link ;
124117 this . description = this . carouselOptions . description ;
125118 this . bundle = this . carouselOptions . bundle ?? 'ORIGINAL' ;
119+ this . paginationOptionId = 'carousel-search-' + this . carouselOptions . discoveryConfiguration ;
120+
126121 this . retrieveItems ( ) . pipe (
127122 mergeMap ( ( searchResult : SearchObjects < Item > ) => {
128123 if ( isNotEmpty ( searchResult ) ) {
129- this . totalPages = searchResult . totalPages ;
130- this . totalItems = searchResult . totalElements ;
131- this . itemPlaceholderList = Array ( searchResult . totalElements ) . fill ( 1 ) . map ( ( x , i ) => i + 1 ) ;
132124 const items = searchResult . page ;
133- this . itemList = [ ...this . itemList , ...items ] ;
134- this . hasMoreToLoad = this . itemList . length < searchResult . totalElements ;
125+ this . carouselItems$ . next ( items ) ;
135126 this . isLoading$ . next ( true ) ;
136- return this . findAllBitstreamImages ( items ) ;
127+
128+ return this . findAllBitstreamImages ( items . filter ( ( _ , i ) => i <= this . pageSize - 1 ) ) ;
137129 } else {
138130 return null ;
139131 }
@@ -161,36 +153,37 @@ export class CarouselComponent implements OnInit {
161153 * function to call on slide
162154 */
163155 onSlide ( slideEvent : NgbSlideEvent ) {
164- const previousSlideIndex = parseInt ( slideEvent . prev . split ( ( '_' ) ) [ 1 ] , 10 ) ;
165- const direction = slideEvent . direction ;
166-
167156 if ( this . unpauseOnArrow && slideEvent . paused &&
168157 ( slideEvent . source === NgbSlideEventSource . ARROW_LEFT || slideEvent . source === NgbSlideEventSource . ARROW_RIGHT ) ) {
169158 this . togglePaused ( ) ;
170159 }
160+
171161 if ( this . pauseOnIndicator && ! slideEvent . paused && slideEvent . source === NgbSlideEventSource . INDICATOR ) {
172162 this . togglePaused ( ) ;
173163 }
174164
175- if ( previousSlideIndex === ( this . carouselOptions . numberOfItems - 1 ) && direction === 'left' && ( this . hasMoreToLoad || this . currentPage < this . totalPages ) ) {
176- this . changePage ( this . currentPage + 1 ) ;
177- } else if ( previousSlideIndex === 0 && direction === 'right' && this . currentPage !== 1 ) {
178- this . changePage ( this . currentPage - 1 ) ;
179- } else if ( previousSlideIndex === 0 && direction === 'right' && this . currentPage === 1 ) {
180- this . changePage ( this . totalPages ) ;
181- } else if ( previousSlideIndex === ( this . currentPageItems ( ) . length - 1 ) && direction === 'left' && ( ! this . hasMoreToLoad || this . currentPage === this . totalPages ) ) {
182- this . changePage ( 1 ) ;
165+ const currentSlideIndex = parseInt ( slideEvent . current . split ( '-' ) [ 2 ] , 10 ) ;
166+ const currentPage = Math . ceil ( currentSlideIndex / this . pageSize ) ;
167+
168+ if ( ! this . pageToBitstreamsMap . get ( currentPage + 1 ) && currentSlideIndex + this . slideLoadingBuffer === currentPage * this . pageSize ) {
169+ this . loadNextPageBitstreams ( ) ;
170+ } else if ( slideEvent . source === 'indicator' && currentSlideIndex > this . pageSize * this . currentSliderPage ) {
171+ this . isLoading$ . next ( true ) ;
172+ this . currentSliderPage = currentPage ;
173+ this . loadNextPageBitstreams ( ) ;
183174 }
184175 }
185176
186177 /**
187178 * Find the first image of each item
188179 */
189180 findAllBitstreamImages ( items : ItemSearchResult [ ] ) : Observable < Map < string , string > > {
181+ this . pageToBitstreamsMap . set ( this . currentSliderPage , items ) ;
182+
190183 return from ( items ) . pipe (
191184 map ( ( itemSR ) => itemSR . indexableObject ) ,
192- mergeMap ( ( item ) => this . bitstreamDataService . findAllByItemAndBundleName (
193- item , this . bundle , { } , true , true , followLink ( 'format' ) ,
185+ mergeMap ( ( item ) => this . bitstreamDataService . showableByItem (
186+ item . uuid , this . bundle , [ ] , { } , true , true , followLink ( 'format' ) ,
194187 ) . pipe (
195188 getFirstCompletedRemoteData ( ) ,
196189 switchMap ( ( rd : RemoteData < PaginatedList < Bitstream > > ) => rd . hasSucceeded ? rd . payload . page : [ ] ) ,
@@ -217,34 +210,22 @@ export class CarouselComponent implements OnInit {
217210 return item . firstMetadataValue ( this . link ) ;
218211 }
219212
220-
221- /**
222- * to open a link of an item
223- */
224- openLinkUrl ( url ) {
225- if ( url && url [ 0 ] . value ) {
226- this . _window . nativeWindow . open ( url [ 0 ] . value , '_blank' ) ;
227- }
228- }
229-
230213 /**
231214 * Retrieve items by the given page number
232215 *
233- * @param currentPage
234216 */
235- retrieveItems ( currentPage : number = 1 ) : Observable < SearchObjects < Item > > {
217+ retrieveItems ( ) : Observable < SearchObjects < Item > > {
236218 const pagination : PaginationComponentOptions = Object . assign ( new PaginationComponentOptions ( ) , {
237- id : 'sop' ,
219+ id : this . paginationOptionId ,
238220 pageSize : this . carouselOptions . numberOfItems ,
239- currentPage : currentPage
221+ currentPage : 1
240222 } ) ;
241223
242224 const paginatedSearchOptions = new PaginatedSearchOptions ( {
243225 configuration : this . carouselOptions . discoveryConfiguration ,
244226 pagination : pagination ,
245227 sort : new SortOptions ( this . carouselOptions . sortField , this . carouselOptions . sortDirection ) ,
246- dsoTypes : [ DSpaceObjectType . ITEM ] ,
247- forcedEmbeddedKeys : [ 'bundles' ]
228+ projection : 'preventMetadataSecurity'
248229 } ) ;
249230 return this . searchManager . search ( paginatedSearchOptions ) . pipe (
250231 getFirstCompletedRemoteData ( ) ,
@@ -258,69 +239,30 @@ export class CarouselComponent implements OnInit {
258239 ) ;
259240 }
260241
261- currentPageItems ( ) : ItemSearchResult [ ] {
262- return this . itemList . slice ( ( this . currentPage - 1 ) * this . carouselOptions . numberOfItems , this . currentPage * this . carouselOptions . numberOfItems ) ;
263- }
264242
265243 pages = ( ) => {
266- return Array . from ( { length : Math . ceil ( this . itemPlaceholderList . length / this . carouselOptions . numberOfItems ) } , ( _ , i ) => i + 1 ) ;
267- } ;
268- previousPage = ( ) => {
269- if ( this . currentPage > 1 ) {
270- this . currentPage -- ;
271- }
244+ return Array . from ( { length : this . carouselOptions . numberOfItems / this . pageSize } , ( _ , i ) => i + 1 ) ;
272245 } ;
273246
274- nextPage = ( ) => {
275- if ( this . currentPage < this . pages ( ) . length ) {
276- if ( this . hasMoreToLoad ) {
277- this . isLoading$ . next ( true ) ;
278- this . currentPage ++ ;
279- this . retrieveMoreItems ( this . currentPage ) ;
280- } else {
281- this . currentPage ++ ;
282- }
283- }
284- } ;
285247
286- changePage = ( page ) => {
287- if ( page > this . currentPage && this . hasMoreToLoad ) {
288- this . isLoading$ . next ( true ) ;
289- const startIndex = this . pages ( ) . indexOf ( this . currentPage ) + 1 ;
290- const endIndex = this . pages ( ) . indexOf ( page ) + 1 ;
291- const pagesToFetch : number [ ] = this . pages ( ) . slice ( startIndex , endIndex ) ;
292- this . currentPage = page ;
293- this . retrieveMoreItems ( ...pagesToFetch ) ;
294- } else {
295- this . currentPage = page ;
296- }
297- } ;
248+ private loadNextPageBitstreams ( ) : void {
249+ const items = this . carouselItems$ . value ;
250+ const itemsWithLoadedImages = [ ] . concat ( ( Array . from ( { length : this . currentSliderPage } , ( _ , i ) => i + 1 ) . map ( page => this . pageToBitstreamsMap . get ( page ) ) ) ) ;
251+ const itemsWithoutBistreamsInNextPage = difference ( items , itemsWithLoadedImages ) . filter ( item => ( items . indexOf ( item ) > itemsWithLoadedImages . length - 1 ) && items . indexOf ( item ) < ( this . currentSliderPage + 1 ) * this . pageSize ) ;
298252
299- retrieveMoreItems ( ...page : number [ ] ) {
300- from ( page ) . pipe (
301- concatMap ( ( currentPage : number ) => this . retrieveItems ( currentPage ) . pipe (
302- mergeMap ( ( searchResult : SearchObjects < Item > ) => {
303- if ( isNotEmpty ( searchResult ) ) {
304- const items = searchResult . page ;
305- this . itemList = [ ...this . itemList , ...items ] ;
306- this . hasMoreToLoad = this . itemList . length < searchResult . totalElements ;
307- return this . findAllBitstreamImages ( items ) ;
308- } else {
309- return null ;
310- }
311- } ) ,
312- take ( 1 ) ,
313- // tap((itemToImageHrefMap) => this.itemToImageHrefMap$.next(new Map([...Array.from(this.itemToImageHrefMap$.value.entries()), ...Array.from(itemToImageHrefMap.entries())]))),
314- ) ) ,
253+ this . findAllBitstreamImages ( itemsWithoutBistreamsInNextPage ) . pipe (
254+ take ( 1 ) ,
315255 reduce ( ( itemToImageHrefMap , value ) => {
316256 return new Map ( [ ...Array . from ( itemToImageHrefMap . entries ( ) ) , ...Array . from ( value . entries ( ) ) ] ) ;
317257 } , new Map ( ) ) ,
318- ) . subscribe ( ( itemToImageHrefMap : Map < string , string > ) => {
258+ ) . subscribe ( ( ( itemToImageHrefMap : Map < string , string > ) => {
259+ this . currentSliderPage += 1 ;
319260 if ( isNotEmpty ( itemToImageHrefMap ) ) {
320261 this . itemToImageHrefMap$ . next ( new Map ( [ ...Array . from ( this . itemToImageHrefMap$ . value . entries ( ) ) , ...Array . from ( itemToImageHrefMap . entries ( ) ) ] ) ) ;
321262 }
322263 this . isLoading$ . next ( false ) ;
323- } ) ;
264+ } ) ) ;
265+
324266 }
325267
326268}
0 commit comments