refactor VirtualList to be more self-contained
This commit is contained in:
		
							parent
							
								
									24e8bdbd86
								
							
						
					
					
						commit
						acc1ce396d
					
				
					 12 changed files with 65 additions and 77 deletions
				
			
		| 
						 | 
				
			
			@ -1,19 +1,11 @@
 | 
			
		|||
<:Window bind:online />
 | 
			
		||||
<Nav :page />
 | 
			
		||||
 | 
			
		||||
{{#if virtual}}
 | 
			
		||||
  <VirtualListContainer realm="{{$currentInstance + '/' + virtualRealm}}">
 | 
			
		||||
    <main>
 | 
			
		||||
      <slot></slot>
 | 
			
		||||
    </main>
 | 
			
		||||
  </VirtualListContainer>
 | 
			
		||||
{{else}}
 | 
			
		||||
  <div class="container">
 | 
			
		||||
    <main>
 | 
			
		||||
      <slot></slot>
 | 
			
		||||
    </main>
 | 
			
		||||
  </div>
 | 
			
		||||
{{/if}}
 | 
			
		||||
<div class="container">
 | 
			
		||||
  <main>
 | 
			
		||||
    <slot></slot>
 | 
			
		||||
  </main>
 | 
			
		||||
</div>
 | 
			
		||||
<script>
 | 
			
		||||
	import Nav from './Nav.html';
 | 
			
		||||
	import VirtualListContainer from './virtualList/VirtualListContainer.html'
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -43,7 +43,7 @@
 | 
			
		|||
      this.store.setForRealm({intersectionStates: intersectionStates})
 | 
			
		||||
 | 
			
		||||
      this.set({intersectionObserver: new IntersectionObserver(this.onIntersection.bind(this), {
 | 
			
		||||
        root: document.getElementsByClassName('container')[0], // TODO: fix this
 | 
			
		||||
        root: document.querySelector('.container'),
 | 
			
		||||
        rootMargin: '300% 0px'
 | 
			
		||||
      })})
 | 
			
		||||
      this.observe('allItemsHaveHeight', allItemsHaveHeight => {
 | 
			
		||||
| 
						 | 
				
			
			@ -80,8 +80,7 @@
 | 
			
		|||
        }
 | 
			
		||||
        this.set({scrolledToPosition: true})
 | 
			
		||||
        console.log('scrollToPosition', rect.top)
 | 
			
		||||
        // TODO: there should be some cleaner way to grab the container element
 | 
			
		||||
        let container = document.getElementsByClassName('container')[0]
 | 
			
		||||
        let container = document.querySelector('.container')
 | 
			
		||||
        if (!container) {
 | 
			
		||||
          return
 | 
			
		||||
        }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,19 +1,21 @@
 | 
			
		|||
<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>
 | 
			
		||||
<VirtualListContainer :realm >
 | 
			
		||||
  <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>
 | 
			
		||||
</VirtualListContainer>
 | 
			
		||||
<style>
 | 
			
		||||
  .virtual-list {
 | 
			
		||||
    position: relative;
 | 
			
		||||
| 
						 | 
				
			
			@ -21,6 +23,7 @@
 | 
			
		|||
  }
 | 
			
		||||
</style>
 | 
			
		||||
<script>
 | 
			
		||||
  import VirtualListContainer from './VirtualListContainer.html'
 | 
			
		||||
  import VirtualListLazyItem from './VirtualListLazyItem'
 | 
			
		||||
  import VirtualListFooter from './VirtualListFooter.html'
 | 
			
		||||
  import VirtualListHeader from './VirtualListHeader.html'
 | 
			
		||||
| 
						 | 
				
			
			@ -86,6 +89,7 @@
 | 
			
		|||
    }),
 | 
			
		||||
    store: () => virtualListStore,
 | 
			
		||||
    components: {
 | 
			
		||||
      VirtualListContainer,
 | 
			
		||||
      VirtualListLazyItem,
 | 
			
		||||
      VirtualListFooter,
 | 
			
		||||
      VirtualListHeader
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,12 +1,6 @@
 | 
			
		|||
<div class="container"
 | 
			
		||||
     on:scroll="onScroll(event)"
 | 
			
		||||
     on:fullscreen="onFullscreenChange()"
 | 
			
		||||
     ref:node>
 | 
			
		||||
  <slot></slot>
 | 
			
		||||
</div>
 | 
			
		||||
<slot></slot>
 | 
			
		||||
<script>
 | 
			
		||||
  import { virtualListStore } from './virtualListStore'
 | 
			
		||||
 | 
			
		||||
  import throttle from 'lodash/throttle'
 | 
			
		||||
  import { isFullscreen, attachFullscreenListener, detachFullscreenListener } from '../../_utils/fullscreen'
 | 
			
		||||
  import { mark, stop } from '../../_utils/marks'
 | 
			
		||||
| 
						 | 
				
			
			@ -16,7 +10,9 @@
 | 
			
		|||
  export default {
 | 
			
		||||
    oncreate() {
 | 
			
		||||
      mark('onCreate VirtualListContainer')
 | 
			
		||||
      let node = this.refs.node
 | 
			
		||||
      let node = document.querySelector('.container')
 | 
			
		||||
      this.setupScroll(node)
 | 
			
		||||
      this.setupFullscreen()
 | 
			
		||||
      this.store.setCurrentRealm(this.get('realm'))
 | 
			
		||||
      let scrollTop = this.store.get('scrollTop')
 | 
			
		||||
      if (scrollTop > 0) {
 | 
			
		||||
| 
						 | 
				
			
			@ -40,46 +36,47 @@
 | 
			
		|||
      }
 | 
			
		||||
      stop('onCreate VirtualListContainer')
 | 
			
		||||
    },
 | 
			
		||||
    ondestroy() {
 | 
			
		||||
      this.teardownScroll()
 | 
			
		||||
      this.teardownFullscreen()
 | 
			
		||||
    },
 | 
			
		||||
    store: () => virtualListStore,
 | 
			
		||||
    events: {
 | 
			
		||||
      scroll(node, callback) {
 | 
			
		||||
        const onScroll = throttle(event => {
 | 
			
		||||
          mark('onScroll')
 | 
			
		||||
    methods: {
 | 
			
		||||
      setupScroll(node) {
 | 
			
		||||
        if (!node) {
 | 
			
		||||
          return
 | 
			
		||||
        }
 | 
			
		||||
        this.scrollListener = throttle(event => {
 | 
			
		||||
          if (this.get('fullscreen')) {
 | 
			
		||||
            return
 | 
			
		||||
          }
 | 
			
		||||
          callback(event)
 | 
			
		||||
          stop('onScroll')
 | 
			
		||||
          this.onScroll(event)
 | 
			
		||||
        }, SCROLL_EVENT_DELAY, {
 | 
			
		||||
          leading: true,
 | 
			
		||||
          trailing: true
 | 
			
		||||
        })
 | 
			
		||||
        node.addEventListener('scroll', onScroll)
 | 
			
		||||
 | 
			
		||||
        return {
 | 
			
		||||
          teardown() {
 | 
			
		||||
            node.removeEventListener('scroll', onScroll)
 | 
			
		||||
          }
 | 
			
		||||
        node.addEventListener('scroll', this.scrollListener)
 | 
			
		||||
      },
 | 
			
		||||
      teardownScroll() {
 | 
			
		||||
        let node = document.querySelector('.container')
 | 
			
		||||
        if (node) {
 | 
			
		||||
          node.removeEventListener('scroll', this.scrollListener)
 | 
			
		||||
        }
 | 
			
		||||
      },
 | 
			
		||||
      fullscreen(node, callback) {
 | 
			
		||||
        const onFullscreen = (() => {
 | 
			
		||||
          callback()
 | 
			
		||||
        })
 | 
			
		||||
        attachFullscreenListener(onFullscreen)
 | 
			
		||||
        return {
 | 
			
		||||
          teardown() {
 | 
			
		||||
            detachFullscreenListener(onFullscreen)
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    methods: {
 | 
			
		||||
      setupFullscreen() {
 | 
			
		||||
        this.onFullscreenChange = this.onFullscreenChange.bind(this)
 | 
			
		||||
        attachFullscreenListener(this.onFullscreenChange)
 | 
			
		||||
      },
 | 
			
		||||
      teardownFullscreen() {
 | 
			
		||||
        detachFullscreenListener(this.onFullscreenChange)
 | 
			
		||||
      },
 | 
			
		||||
      onScroll(event) {
 | 
			
		||||
        mark('onScroll')
 | 
			
		||||
        this.store.setForRealm({
 | 
			
		||||
          scrollTop: event.target.scrollTop,
 | 
			
		||||
          scrollHeight: event.target.scrollHeight
 | 
			
		||||
        })
 | 
			
		||||
        stop('onScroll')
 | 
			
		||||
      },
 | 
			
		||||
      onFullscreenChange() {
 | 
			
		||||
        mark('onFullscreenChange')
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2,9 +2,7 @@
 | 
			
		|||
  <title>Pinafore – {{profileName}}</title>
 | 
			
		||||
</:Head>
 | 
			
		||||
 | 
			
		||||
<Layout page='tags'
 | 
			
		||||
        virtual="true"
 | 
			
		||||
        virtualRealm='account/{{params.accountId}}' >
 | 
			
		||||
<Layout page='tags'>
 | 
			
		||||
  {{#if $isUserLoggedIn}}
 | 
			
		||||
  <DynamicPageBanner title="{{profileName}}" />
 | 
			
		||||
    {{#if $currentAccountProfile}}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2,7 +2,7 @@
 | 
			
		|||
  <title>Pinafore – Favorites</title>
 | 
			
		||||
</:Head>
 | 
			
		||||
 | 
			
		||||
<Layout page='favorites' virtual="true" virtualRealm="favorites">
 | 
			
		||||
<Layout page='favorites'>
 | 
			
		||||
  {{#if $isUserLoggedIn}}
 | 
			
		||||
  {{#if $pinnedPage !== '/favorites'}}
 | 
			
		||||
    <DynamicPageBanner title="Favorites" icon="#fa-star"/>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2,7 +2,7 @@
 | 
			
		|||
  <title>Pinafore – Federated</title>
 | 
			
		||||
</:Head>
 | 
			
		||||
 | 
			
		||||
<Layout page='federated' virtual="true" virtualRealm="federated">
 | 
			
		||||
<Layout page='federated'>
 | 
			
		||||
  {{#if $isUserLoggedIn}}
 | 
			
		||||
  {{#if $pinnedPage !== '/federated'}}
 | 
			
		||||
    <DynamicPageBanner title="Federated Timeline" icon="#fa-globe"/>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2,7 +2,7 @@
 | 
			
		|||
	<title>Pinafore – Home</title>
 | 
			
		||||
</:Head>
 | 
			
		||||
 | 
			
		||||
<Layout page='home' virtual="true" virtualRealm="home">
 | 
			
		||||
<Layout page='home'>
 | 
			
		||||
  {{#if $isUserLoggedIn}}
 | 
			
		||||
  <LazyTimeline timeline='home' />
 | 
			
		||||
  {{else}}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2,7 +2,7 @@
 | 
			
		|||
  <title>Pinafore – {{listTitle}}</title>
 | 
			
		||||
</:Head>
 | 
			
		||||
 | 
			
		||||
<Layout page='lists' virtual="true" virtualRealm="list/{{params.listId}}">
 | 
			
		||||
<Layout page='lists'>
 | 
			
		||||
  {{#if $isUserLoggedIn}}
 | 
			
		||||
  {{#if $pinnedPage !== `/lists/${params.listId}`}}
 | 
			
		||||
    <DynamicPageBanner title="{{listTitle}}" icon="#fa-bars"/>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2,7 +2,7 @@
 | 
			
		|||
  <title>Pinafore – Local</title>
 | 
			
		||||
</:Head>
 | 
			
		||||
 | 
			
		||||
<Layout page='local' virtual="true" virtualRealm="local">
 | 
			
		||||
<Layout page='local'>
 | 
			
		||||
  {{#if $isUserLoggedIn}}
 | 
			
		||||
  {{#if $pinnedPage !== '/local'}}
 | 
			
		||||
    <DynamicPageBanner title="Local Timeline" icon="#fa-users"/>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2,7 +2,7 @@
 | 
			
		|||
	<title>Pinafore – Notifications</title>
 | 
			
		||||
</:Head>
 | 
			
		||||
 | 
			
		||||
<Layout page='notifications' virtual="true" virtualRealm="notifications">
 | 
			
		||||
<Layout page='notifications'>
 | 
			
		||||
  {{#if $isUserLoggedIn}}
 | 
			
		||||
  <LazyTimeline timeline='notifications' />
 | 
			
		||||
  {{else}}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2,9 +2,7 @@
 | 
			
		|||
  <title>Pinafore – #{{params.tagName}}</title>
 | 
			
		||||
</:Head>
 | 
			
		||||
 | 
			
		||||
<Layout page='tags'
 | 
			
		||||
        virtual="true"
 | 
			
		||||
        virtualRealm='tag/{{params.tagName}}' >
 | 
			
		||||
<Layout page='tags'>
 | 
			
		||||
  {{#if $isUserLoggedIn}}
 | 
			
		||||
  <DynamicPageBanner title="{{'#' + params.tagName}}"/>
 | 
			
		||||
  <LazyTimeline timeline='tag/{{params.tagName}}' />
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		
		Reference in a new issue