@@ -154,17 +154,47 @@ export class VirtualRepeat extends AbstractRepeater {
154154 if ( ! this . scope ) {
155155 return ;
156156 }
157+ let reducingItems = false ;
158+ let previousLastViewIndex = this . _getIndexOfLastView ( ) ;
159+
157160 let items = this . items ;
158161 this . strategy = this . strategyLocator . getStrategy ( items ) ;
159162 if ( items . length > 0 && this . viewCount ( ) === 0 ) {
160163 this . strategy . createFirstItem ( this ) ;
161164 }
165+ // Skip scroll handling if we are decreasing item list
166+ // Otherwise if expanding list, call the handle scroll below
167+ if ( this . _itemsLength >= items . length ) {
168+ //Scroll handle is redundant in this case since the instanceChanged will re-evaluate orderings
169+ // Also, when items are reduced, we're not having to move any bindings, just a straight rebind of the items in the list
170+ this . _skipNextScrollHandle = true ;
171+ reducingItems = true ;
172+ }
173+ this . _checkFixedHeightContainer ( ) ;
162174 this . _calcInitialHeights ( items . length ) ;
163175 if ( ! this . isOneTime && ! this . _observeInnerCollection ( ) ) {
164176 this . _observeCollection ( ) ;
165177 }
178+ this . strategy . instanceChanged ( this , items , this . _first ) ;
179+ this . _lastRebind = this . _first ; //Reset rebinding
180+
181+ if ( reducingItems && previousLastViewIndex > this . items . length - 1 ) {
182+ //Do we need to set scrolltop so that we appear at the bottom of the list to match scrolling as far as we could?
183+ //We only want to execute this line if we're reducing such that it brings us to the bottom of the new list
184+ this . scrollContainer . scrollTop = this . scrollContainer . scrollTop + ( this . viewCount ( ) * this . itemHeight ) ;
185+ }
186+ if ( ! reducingItems ) {
187+ // If we're expanding our items, then we need to reset our previous first for the next go around of scroll handling
188+ this . _previousFirst = this . _first ;
189+ this . _scrollingDown = true ; //Simulating the down scroll event to load up data appropriately
190+ this . _scrollingUp = false ;
191+
192+ //Make sure we fix any state (we could have been at the last index before, but this doesn't get set until too late for scrolling)
193+ this . isLastIndex = this . _getIndexOfLastView ( ) >= this . items . length - 1 ;
194+ }
166195
167- this . strategy . instanceChanged ( this , items , this . _viewsLength ) ;
196+ //Need to readjust the scroll position to "move" us back to the appropriate position, since moving the views will shift our view port's percieved location
197+ this . _handleScroll ( ) ;
168198 }
169199
170200 unbind ( ) : void {
@@ -215,6 +245,10 @@ export class VirtualRepeat extends AbstractRepeater {
215245 if ( ! this . _isAttached ) {
216246 return ;
217247 }
248+ if ( this . _skipNextScrollHandle ) {
249+ this . _skipNextScrollHandle = false ;
250+ return ;
251+ }
218252 let itemHeight = this . itemHeight ;
219253 let scrollTop = this . _fixedHeightContainer ? this . scrollContainer . scrollTop : pageYOffset - this . distanceToTop ;
220254 this . _first = Math . floor ( scrollTop / itemHeight ) ;
@@ -346,6 +380,12 @@ export class VirtualRepeat extends AbstractRepeater {
346380 }
347381 }
348382
383+ _checkFixedHeightContainer ( ) : void {
384+ if ( this . domHelper . hasOverflowScroll ( this . scrollContainer ) ) {
385+ this . _fixedHeightContainer = true ;
386+ }
387+ }
388+
349389 _adjustBufferHeights ( ) : void {
350390 this . topBuffer . style . height = `${ this . _topBufferHeight } px` ;
351391 this . bottomBuffer . style . height = `${ this . _bottomBufferHeight } px` ;
@@ -422,20 +462,38 @@ export class VirtualRepeat extends AbstractRepeater {
422462 } , 500 ) ;
423463 return ;
424464 }
465+
425466 this . _itemsLength = itemsLength ;
426467 this . scrollContainerHeight = this . _fixedHeightContainer ? this . _calcScrollHeight ( this . scrollContainer ) : document . documentElement . clientHeight ;
427468 this . elementsInView = Math . ceil ( this . scrollContainerHeight / this . itemHeight ) + 1 ;
428469 this . _viewsLength = ( this . elementsInView * 2 ) + this . _bufferSize ;
429- this . _bottomBufferHeight = this . itemHeight * itemsLength - this . itemHeight * this . _viewsLength ;
430- if ( this . _bottomBufferHeight < 0 ) {
470+
471+ //Look at top buffer height (how far we've scrolled down)
472+ //If top buffer height is greater than the new bottom buffer height (how far we *can* scroll down)
473+ // Then set top buffer height to max it can be (bottom buffer height - views in length?) and bottom buffer height to 0
474+ let newBottomBufferHeight = this . itemHeight * itemsLength - this . itemHeight * this . _viewsLength ; //How much buffer room to the bottom if you were at the top
475+ if ( newBottomBufferHeight < 0 ) { // In case of small lists, ensure that we never set the buffer heights to impossible values
476+ newBottomBufferHeight = 0 ;
477+ }
478+ if ( this . _topBufferHeight >= newBottomBufferHeight ) { //Use case when items are removed (we've scrolled past where we can)
479+ this . _topBufferHeight = newBottomBufferHeight ;
431480 this . _bottomBufferHeight = 0 ;
481+ this . _first = this . _itemsLength - this . _viewsLength ;
482+ if ( this . _first < 0 ) { // In case of small lists, ensure that we never set first to less than possible
483+ this . _first = 0 ;
484+ }
485+ } else { //Use case when items are added (we are adding scrollable space to the bottom)
486+ // We need to re-evaluate which is the true "first". If we've added items, then the previous "first" is actually too far down the list
487+ this . _first = this . _getIndexOfFirstView ( ) ;
488+ let adjustedTopBufferHeight = this . _first * this . itemHeight ; //appropriate buffer height for top, might be 1 too long...
489+ this . _topBufferHeight = adjustedTopBufferHeight ;
490+ //But what about when we've only scrolled slightly down the list? We need to readjust the top buffer height then
491+ this . _bottomBufferHeight = newBottomBufferHeight - adjustedTopBufferHeight ;
492+ if ( this . _bottomBufferHeight < 0 ) {
493+ this . _bottomBufferHeight = 0 ;
494+ }
432495 }
433- this . bottomBuffer . style . height = `${ this . _bottomBufferHeight } px` ;
434- this . _topBufferHeight = 0 ;
435- this . topBuffer . style . height = `${ this . _topBufferHeight } px` ;
436- // TODO This will cause scrolling back to top when swapping collection instances that have different lengths - instead should keep the scroll position
437- this . scrollContainer . scrollTop = 0 ;
438- this . _first = 0 ;
496+ this . _adjustBufferHeights ( ) ;
439497 return ;
440498 }
441499
@@ -480,6 +538,7 @@ export class VirtualRepeat extends AbstractRepeater {
480538 }
481539
482540 // @override AbstractRepeater
541+ // How will these behaviors need to change since we are in a virtual list instead?
483542 viewCount ( ) { return this . viewSlot . children . length ; }
484543 views ( ) { return this . viewSlot . children ; }
485544 view ( index ) { return this . viewSlot . children [ index ] ; }
0 commit comments