104 lines
		
	
	
		
			No EOL
		
	
	
		
			3.4 KiB
		
	
	
	
		
			HTML
		
	
	
	
	
	
			
		
		
	
	
			104 lines
		
	
	
		
			No EOL
		
	
	
		
			3.4 KiB
		
	
	
	
		
			HTML
		
	
	
	
	
	
| <div class="virtual-list {{shown ? '' : 'hidden'}}" style="height: {{$height}}px;">
 | |
|   <VirtualListHeader component="{{headerComponent}}" virtualProps="{{headerProps}}" shown="{{$showHeader}}"/>
 | |
|   {{#if $visibleItems}}
 | |
|     {{#each $visibleItems as visibleItem @key}}
 | |
|       <VirtualListLazyItem :component
 | |
|                            offset="{{visibleItem.offset}}"
 | |
|                            makeProps="{{makeProps}}"
 | |
|                            key="{{visibleItem.key}}"
 | |
|                            index="{{visibleItem.index}}"
 | |
|       />
 | |
|     {{/each}}
 | |
|   {{/if}}
 | |
|   {{#if $showFooter}}
 | |
|     <VirtualListFooter component="{{footerComponent}}"/>
 | |
|   {{/if}}
 | |
| </div>
 | |
| <style>
 | |
|   .virtual-list {
 | |
|     position: relative;
 | |
|     transition: opacity 0.25s linear;
 | |
|   }
 | |
| </style>
 | |
| <script>
 | |
|   import VirtualListLazyItem from './VirtualListLazyItem'
 | |
|   import VirtualListFooter from './VirtualListFooter.html'
 | |
|   import VirtualListHeader from './VirtualListHeader.html'
 | |
|   import { virtualListStore } from './virtualListStore'
 | |
|   import throttle from 'lodash/throttle'
 | |
|   import { mark, stop } from '../../_utils/marks'
 | |
| 
 | |
|   const DISTANCE_FROM_BOTTOM_TO_FIRE = 400
 | |
|   const SCROLL_EVENT_THROTTLE = 1000
 | |
| 
 | |
|   export default {
 | |
|     oncreate () {
 | |
|       this.fireScrollToBottom = throttle(() => {
 | |
|         this.fire('scrollToBottom')
 | |
|       }, SCROLL_EVENT_THROTTLE)
 | |
|       this.fireScrollToTop = throttle(() => {
 | |
|         this.fire('scrollToTop')
 | |
|       }, SCROLL_EVENT_THROTTLE)
 | |
|       this.observe('showFooter', showFooter => {
 | |
|         mark('set showFooter')
 | |
|         this.store.setForRealm({showFooter: showFooter})
 | |
|         mark('set showFooter')
 | |
|       })
 | |
|       this.observe('showHeader', showHeader => {
 | |
|         mark('set showHeader')
 | |
|         this.store.setForRealm({showHeader: showHeader})
 | |
|         stop('set showHeader')
 | |
|       })
 | |
|       this.observe('itemsStringified', (itemsStringified) => {
 | |
|         let items = typeof itemsStringified === 'undefined' ? undefined :
 | |
|           JSON.parse(itemsStringified)
 | |
|         mark('set items')
 | |
|         this.store.setForRealm({items: items})
 | |
|         stop('set items')
 | |
|       })
 | |
|       this.observe('allVisibleItemsHaveHeight', allVisibleItemsHaveHeight => {
 | |
|         if (allVisibleItemsHaveHeight) {
 | |
|           this.fire('initializedVisibleItems')
 | |
|         }
 | |
|       })
 | |
| 
 | |
|       let observedOnce = false
 | |
| 
 | |
|       this.observe('distanceFromBottom', (distanceFromBottom) => {
 | |
|         if (!observedOnce) {
 | |
|           observedOnce = true // TODO: the first time is always 0... need better way to handle this
 | |
|           return
 | |
|         }
 | |
|         if (distanceFromBottom >= 0 &&
 | |
|             distanceFromBottom <= DISTANCE_FROM_BOTTOM_TO_FIRE) {
 | |
|           this.fireScrollToBottom()
 | |
|         }
 | |
|       })
 | |
| 
 | |
|       this.observe('distanceFromTop', (distanceFromTop) => {
 | |
|         if (distanceFromTop === 0) {
 | |
|           this.fireScrollToTop()
 | |
|         }
 | |
|       })
 | |
|     },
 | |
|     data: () => ({
 | |
|       component: null
 | |
|     }),
 | |
|     store: () => virtualListStore,
 | |
|     components: {
 | |
|       VirtualListLazyItem,
 | |
|       VirtualListFooter,
 | |
|       VirtualListHeader
 | |
|     },
 | |
|     computed: {
 | |
|       distanceFromBottom: ($scrollHeight, $scrollTop, $offsetHeight) => {
 | |
|         return $scrollHeight - $scrollTop - $offsetHeight
 | |
|       },
 | |
|       distanceFromTop: ($scrollTop) => $scrollTop,
 | |
|       // TODO: bug in svelte store, shouldn't need to do this
 | |
|       allVisibleItemsHaveHeight: ($allVisibleItemsHaveHeight) => $allVisibleItemsHaveHeight,
 | |
|       // hack to avoid getting called too often
 | |
|       itemsStringified: (items) => JSON.stringify(items)
 | |
|     }
 | |
|   }
 | |
| </script> |