@@ -122,8 +122,10 @@ angular.module('ui.scroll', [])
122
122
buffer . bof = false ;
123
123
buffer . first = origin ;
124
124
buffer . next = origin ;
125
- buffer . minIndex = Number . MAX_VALUE ;
126
- buffer . maxIndex = Number . MIN_VALUE ;
125
+ buffer . minIndex = origin ;
126
+ buffer . maxIndex = origin ;
127
+ buffer . minIndexUser = null ;
128
+ buffer . maxIndexUser = null ;
127
129
}
128
130
129
131
angular . extend ( buffer , {
@@ -200,15 +202,6 @@ angular.module('ui.scroll', [])
200
202
buffer . minIndex = buffer . bof ? buffer . minIndex = buffer . first : Math . min ( buffer . first , buffer . minIndex ) ;
201
203
} ,
202
204
203
- syncDatasource ( datasource ) {
204
- const offset = buffer . minIndex - ( Math . min ( buffer . minIndex , datasource . minIndex || Number . MAX_VALUE ) ) ;
205
-
206
- datasource . minIndex = ( buffer . minIndex -= offset ) ;
207
- datasource . maxIndex = buffer . maxIndex = Math . max ( buffer . maxIndex , datasource . maxIndex || Number . MIN_VALUE ) ;
208
-
209
- return offset ;
210
- } ,
211
-
212
205
// clears the buffer
213
206
clear ( ) {
214
207
buffer . remove ( 0 , buffer . length ) ;
@@ -226,7 +219,6 @@ angular.module('ui.scroll', [])
226
219
const PADDING_DEFAULT = 0.5 ;
227
220
let topPadding = null ;
228
221
let bottomPadding = null ;
229
- let averageItemHeight = 0 ;
230
222
const viewport = controllers [ 0 ] && controllers [ 0 ] . viewport ? controllers [ 0 ] . viewport : angular . element ( window ) ;
231
223
232
224
viewport . css ( {
@@ -246,7 +238,7 @@ angular.module('ui.scroll', [])
246
238
bottomPadding = new Padding ( template ) ;
247
239
element . before ( topPadding ) ;
248
240
element . after ( bottomPadding ) ;
249
-
241
+
250
242
function Padding ( template ) {
251
243
let result ;
252
244
let tagName = template . localName ;
@@ -347,45 +339,55 @@ angular.module('ui.scroll', [])
347
339
}
348
340
} ,
349
341
350
- adjustPadding ( ) {
351
- if ( ! buffer . length || ! cache . length ) {
342
+ adjustPadding ( adjustScrollTop ) {
343
+ if ( ! buffer . length ) {
352
344
return ;
353
345
}
354
346
347
+ // percise heights calculation, items that were in buffer once
355
348
let topPaddingHeight = 0 ;
356
349
let bottomPaddingHeight = 0 ;
357
- for ( let i = cache . length - 1 ; i >= 0 ; i -- ) {
358
- if ( cache [ i ] . index < buffer . first ) {
359
- topPaddingHeight += cache [ i ] . height ;
360
- }
361
- if ( cache [ i ] . index >= buffer . next ) {
362
- bottomPaddingHeight += cache [ i ] . height ;
350
+
351
+ if ( cache . length ) {
352
+ for ( let i = cache . length - 1 ; i >= 0 ; i -- ) {
353
+ if ( cache [ i ] . index < buffer . first ) {
354
+ topPaddingHeight += cache [ i ] . height ;
355
+ }
356
+ if ( cache [ i ] . index >= buffer . next ) {
357
+ bottomPaddingHeight += cache [ i ] . height ;
358
+ }
363
359
}
364
360
}
365
361
366
- topPadding . height ( topPaddingHeight ) ;
367
- bottomPadding . height ( bottomPaddingHeight ) ;
368
- } ,
362
+ // average heights calculation, items that have never been reached
363
+ let topPaddingHeightAdd = 0 ;
364
+ let bottomPaddingHeightAdd = 0 ;
365
+ let adjustTopPadding = buffer . minIndexUser && buffer . minIndex > buffer . minIndexUser ;
366
+ let adjustBottomPadding = buffer . maxIndexUser && buffer . maxIndex < buffer . maxIndexUser ;
369
367
370
- syncDatasource ( datasource ) {
371
- if ( ! buffer . length ) {
372
- return ;
368
+ if ( adjustTopPadding || adjustBottomPadding ) {
369
+ let visibleItemsHeight = 0 ;
370
+ for ( let i = buffer . length - 1 ; i >= 0 ; i -- ) {
371
+ visibleItemsHeight += buffer [ i ] . element . outerHeight ( true ) ;
372
+ }
373
+ let averageItemHeight = ( visibleItemsHeight + topPaddingHeight + bottomPaddingHeight ) / ( buffer . maxIndex - buffer . minIndex + 1 ) ;
374
+ topPaddingHeightAdd = adjustTopPadding ? ( buffer . minIndex - buffer . minIndexUser ) * averageItemHeight : 0 ;
375
+ bottomPaddingHeightAdd = adjustBottomPadding ? ( buffer . maxIndexUser - buffer . maxIndex ) * averageItemHeight : 0 ;
373
376
}
374
377
375
- const bufferFirstEl = buffer [ 0 ] . element ;
376
- const bufferLastEl = buffer [ buffer . length - 1 ] . element ;
377
- averageItemHeight = ( bufferLastEl . offset ( ) . top + bufferLastEl . outerHeight ( true ) - bufferFirstEl . offset ( ) . top ) / buffer . length ;
378
+ // paddings combine adjustement
379
+ let topPaddingHeightOld = topPadding . height ( ) ;
380
+ topPadding . height ( topPaddingHeight + topPaddingHeightAdd ) ;
381
+ bottomPadding . height ( bottomPaddingHeight + bottomPaddingHeightAdd ) ;
378
382
379
- const delta = buffer . syncDatasource ( datasource ) * averageItemHeight ;
380
-
381
- topPadding . height ( topPadding . height ( ) + delta ) ;
382
-
383
- viewport . scrollTop ( viewport . scrollTop ( ) + delta ) ;
384
-
385
- viewport . adjustPadding ( ) ;
383
+ // additional scrollTop adjustement in case of datasource.minIndex external set
384
+ if ( adjustScrollTop && adjustTopPadding && topPaddingHeightAdd ) {
385
+ let diff = topPadding . height ( ) - topPaddingHeightOld ;
386
+ viewport . scrollTop ( viewport . scrollTop ( ) + diff ) ;
387
+ }
386
388
} ,
387
389
388
- adjustScrollTop ( height ) {
390
+ adjustScrollTopAfterPrepend ( height ) {
389
391
const paddingHeight = topPadding . height ( ) - height ;
390
392
391
393
if ( paddingHeight >= 0 ) {
@@ -520,21 +522,39 @@ angular.module('ui.scroll', [])
520
522
linker = linker || compileLinker ;
521
523
522
524
const datasource = ( ( ) => {
523
- let _datasource = $parse ( datasourceName ) ( $scope ) ;
525
+ let isDatasourceValid = function ( ) {
526
+ return angular . isObject ( _datasource ) && angular . isFunction ( _datasource . get ) ;
527
+ } ;
524
528
529
+ let _datasource = $parse ( datasourceName ) ( $scope ) ; // try to get datasource on scope
525
530
if ( ! isDatasourceValid ( ) ) {
526
- _datasource = $injector . get ( datasourceName ) ;
531
+ _datasource = $injector . get ( datasourceName ) ; // try to inject datasource as service
527
532
if ( ! isDatasourceValid ( ) ) {
528
533
throw new Error ( datasourceName + ' is not a valid datasource' ) ;
529
534
}
530
535
}
531
536
532
- return _datasource ;
537
+ Object . defineProperty ( _datasource , 'minIndex' , {
538
+ set : function ( value ) {
539
+ this . _minIndex = value ;
540
+ onDatasourceMinIndexChanged ( value ) ;
541
+ } ,
542
+ get : function get ( ) {
543
+ return this . _minIndex ;
544
+ }
545
+ } ) ;
533
546
534
- function isDatasourceValid ( ) {
535
- // then try to inject datasource as service
536
- return angular . isObject ( _datasource ) && angular . isFunction ( _datasource . get ) ;
537
- }
547
+ Object . defineProperty ( _datasource , 'maxIndex' , {
548
+ set : function ( value ) {
549
+ this . _maxIndex = value ;
550
+ onDatasourceMaxIndexChanged ( value ) ;
551
+ } ,
552
+ get : function get ( ) {
553
+ return this . _maxIndex ;
554
+ }
555
+ } ) ;
556
+
557
+ return _datasource ;
538
558
} ) ( ) ;
539
559
540
560
let ridActual = 0 ; // current data revision id
@@ -547,6 +567,23 @@ angular.module('ui.scroll', [])
547
567
return adjustBuffer ( ridActual ) ;
548
568
} ) ;
549
569
570
+ var onDatasourceMinIndexChanged = function ( value ) {
571
+ $timeout ( function ( ) {
572
+ buffer . minIndexUser = value ;
573
+ if ( ! pending . length ) {
574
+ viewport . adjustPadding ( true ) ;
575
+ }
576
+ } ) ;
577
+ } ;
578
+ var onDatasourceMaxIndexChanged = function ( value ) {
579
+ $timeout ( function ( ) {
580
+ buffer . maxIndexUser = value ;
581
+ if ( ! pending . length ) {
582
+ viewport . adjustPadding ( ) ;
583
+ }
584
+ } ) ;
585
+ } ;
586
+
550
587
const fetchNext = ( ( ) => {
551
588
if ( datasource . get . length !== 2 ) {
552
589
return ( success ) => datasource . get ( buffer . next , bufferSize , success ) ;
@@ -747,7 +784,7 @@ angular.module('ui.scroll', [])
747
784
adjustedPaddingHeight += wrapper . element . outerHeight ( true ) ;
748
785
} ) ;
749
786
750
- viewport . adjustScrollTop ( adjustedPaddingHeight ) ;
787
+ viewport . adjustScrollTopAfterPrepend ( adjustedPaddingHeight ) ;
751
788
}
752
789
753
790
// re-index the buffer
@@ -762,9 +799,6 @@ angular.module('ui.scroll', [])
762
799
} ) ;
763
800
} else {
764
801
viewport . adjustPadding ( ) ;
765
- if ( ! pending . length ) {
766
- viewport . syncDatasource ( datasource ) ;
767
- }
768
802
}
769
803
770
804
return keepFetching ;
@@ -899,4 +933,4 @@ angular.module('ui.scroll', [])
899
933
} ;
900
934
}
901
935
}
902
- ] ) ;
936
+ ] ) ;
0 commit comments