forked from cybrespace/pinafore
		
	
		
			
				
	
	
		
			112 lines
		
	
	
		
			No EOL
		
	
	
		
			3.9 KiB
		
	
	
	
		
			HTML
		
	
	
	
	
	
			
		
		
	
	
			112 lines
		
	
	
		
			No EOL
		
	
	
		
			3.9 KiB
		
	
	
	
		
			HTML
		
	
	
	
	
	
<slot></slot>
 | 
						||
<script>
 | 
						||
  import { virtualListStore } from './virtualListStore'
 | 
						||
  import throttle from 'lodash-es/throttle'
 | 
						||
  import { isFullscreen, attachFullscreenListener, detachFullscreenListener } from '../../_utils/fullscreen'
 | 
						||
  import { mark, stop } from '../../_utils/marks'
 | 
						||
  import { scheduleIdleTask } from '../../_utils/scheduleIdleTask'
 | 
						||
  import { isMobile } from '../../_utils/isMobile'
 | 
						||
  import { doubleRAF } from '../../_utils/doubleRAF'
 | 
						||
 | 
						||
  const SCROLL_EVENT_DELAY = 300
 | 
						||
 | 
						||
  export default {
 | 
						||
    oncreate() {
 | 
						||
      mark('onCreate VirtualListContainer')
 | 
						||
      this.store.setCurrentRealm(this.get('realm'))
 | 
						||
      let node = document.querySelector(this.get('containerQuery'))
 | 
						||
      this.setupScroll(node)
 | 
						||
      this.setupFullscreen()
 | 
						||
      let scrollTop = this.store.get('scrollTop')
 | 
						||
      if (scrollTop > 0) {
 | 
						||
        this.observe('allVisibleItemsHaveHeight', allVisibleItemsHaveHeight => {
 | 
						||
          console.log('allVisibleItemsHaveHeight', allVisibleItemsHaveHeight)
 | 
						||
          if (!this.get('initializedScrollTop') && allVisibleItemsHaveHeight && node) {
 | 
						||
            this.set({'initializedScrollTop': true})
 | 
						||
            mark('set scrollTop')
 | 
						||
            console.log('forcing scroll top to ', scrollTop)
 | 
						||
            node.scrollTop = scrollTop
 | 
						||
            stop('set scrollTop')
 | 
						||
            doubleRAF(() => {
 | 
						||
              console.log('initialized VirtualList')
 | 
						||
              this.fire('initialized')
 | 
						||
            })
 | 
						||
          }
 | 
						||
        })
 | 
						||
      } else {
 | 
						||
        this.fire('noNeedToScroll')
 | 
						||
        this.observe('allVisibleItemsHaveHeight', allVisibleItemsHaveHeight => {
 | 
						||
          if (allVisibleItemsHaveHeight) {
 | 
						||
            console.log('initialized VirtualList')
 | 
						||
            this.fire('initialized')
 | 
						||
          }
 | 
						||
        })
 | 
						||
        this.store.setForRealm({
 | 
						||
          scrollHeight: node.scrollHeight,
 | 
						||
          offsetHeight: node.offsetHeight
 | 
						||
        })
 | 
						||
      }
 | 
						||
      stop('onCreate VirtualListContainer')
 | 
						||
    },
 | 
						||
    ondestroy() {
 | 
						||
      this.teardownScroll()
 | 
						||
      this.teardownFullscreen()
 | 
						||
      this.store.setCurrentRealm(null)
 | 
						||
    },
 | 
						||
    store: () => virtualListStore,
 | 
						||
    methods: {
 | 
						||
      setupScroll(node) {
 | 
						||
        if (!node) {
 | 
						||
          return
 | 
						||
        }
 | 
						||
        this.scrollListener = throttle(event => {
 | 
						||
          if (this.get('fullscreen')) {
 | 
						||
            return
 | 
						||
          }
 | 
						||
          this.onScroll(event)
 | 
						||
        }, SCROLL_EVENT_DELAY, {
 | 
						||
          leading: true,
 | 
						||
          trailing: true
 | 
						||
        })
 | 
						||
        node.addEventListener('scroll', this.scrollListener)
 | 
						||
      },
 | 
						||
      teardownScroll() {
 | 
						||
        let node = document.querySelector(this.get('containerQuery'))
 | 
						||
        if (node) {
 | 
						||
          node.removeEventListener('scroll', this.scrollListener)
 | 
						||
        }
 | 
						||
      },
 | 
						||
      setupFullscreen() {
 | 
						||
        this.onFullscreenChange = this.onFullscreenChange.bind(this)
 | 
						||
        attachFullscreenListener(this.onFullscreenChange)
 | 
						||
      },
 | 
						||
      teardownFullscreen() {
 | 
						||
        detachFullscreenListener(this.onFullscreenChange)
 | 
						||
      },
 | 
						||
      onScroll(event) {
 | 
						||
        let { scrollTop, scrollHeight } = event.target
 | 
						||
 | 
						||
        // On mobile devices, this can make scrolling more responsive. On
 | 
						||
        // desktop browsers... it's probably overkill, and can lead to a
 | 
						||
        // checkerboarding issue ("I just scrolled, why is it blank for 5 seconds?").
 | 
						||
        let runTask = isMobile() ? scheduleIdleTask : requestAnimationFrame
 | 
						||
 | 
						||
        runTask(() => {
 | 
						||
          mark('onScroll -> setForRealm()')
 | 
						||
          this.store.setForRealm({scrollTop, scrollHeight})
 | 
						||
          stop('onScroll -> setForRealm()')
 | 
						||
        })
 | 
						||
      },
 | 
						||
      onFullscreenChange() {
 | 
						||
        mark('onFullscreenChange')
 | 
						||
        console.log('is fullscreen? ', isFullscreen())
 | 
						||
        this.set({ fullscreen: isFullscreen() })
 | 
						||
        stop('onFullscreenChange')
 | 
						||
      }
 | 
						||
    },
 | 
						||
    computed: {
 | 
						||
      // TODO: bug in svelte/store – the observer in oncreate() never get removed without this hack
 | 
						||
      allVisibleItemsHaveHeight: ($allVisibleItemsHaveHeight) => $allVisibleItemsHaveHeight
 | 
						||
    }
 | 
						||
  };
 | 
						||
</script> |