pinafore/routes/_components/VirtualListContainer.html
2018-01-24 18:58:10 -08:00

138 lines
4.1 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<div class="container"
on:scroll="onScroll(event)"
on:fullscreen="onFullscreenChange()"
ref:node>
<slot></slot>
</div>
<script>
import { virtualListStore } from '../_utils/virtualListStore'
import throttle from 'lodash/throttle'
import { isFullscreen, attachFullscreenListener, detachFullscreenListener } from '../_utils/fullscreen'
import { mark, stop } from '../_utils/marks'
const SCROLL_EVENT_DELAY = 300
const cachedVirtualStores = {}
if (process.browser && process.env.NODE_ENV !== 'production') {
window.cachedVirtualStores = cachedVirtualStores
}
export default {
oncreate() {
mark('onCreate VirtualListContainer')
let node = this.refs.node
let storeKey = this.get('storeKey')
let cachedStore
if (storeKey && (cachedStore = cachedVirtualStores[storeKey])) {
this.store.set({
scrollTop: cachedStore.state.scrollTop,
scrollHeight: cachedStore.state.scrollHeight,
offsetHeight: cachedStore.state.offsetHeight
})
this.store.set(cachedStore.state)
// rehydrate scroll top
let cachedScrollTop = cachedStore.state.scrollTop || 0
if (cachedScrollTop === 0) {
if (process.env.NODE_ENV !== 'production') {
console.log('no need to force scroll top')
}
return
}
let initializedScrollTop = false
let node = this.refs.node
this.observe('allVisibleItemsHaveHeight', allVisibleItemsHaveHeight => {
if (process.env.NODE_ENV !== 'production') {
console.log('allVisibleItemsHaveHeight', allVisibleItemsHaveHeight)
}
if (!initializedScrollTop && allVisibleItemsHaveHeight && node) {
initializedScrollTop = true
requestAnimationFrame(() => {
mark('set scrollTop')
if (process.env.NODE_ENV !== 'production') {
console.log('forcing scroll top to ', cachedScrollTop)
}
node.scrollTop = cachedScrollTop
stop('set scrollTop')
})
}
})
} else {
this.store.set({
scrollTop: 0,
scrollHeight: node.scrollHeight,
offsetHeight: node.offsetHeight
})
}
stop('onCreate VirtualListContainer')
},
ondestroy() {
let storeKey = this.get('storeKey')
if (storeKey) {
let clonedState = this.store.cloneState()
if (process.env.NODE_ENV !== 'production') {
console.log('caching scroll top', clonedState.scrollTop)
}
cachedVirtualStores[storeKey] = {
state: clonedState
}
}
},
store: () => virtualListStore,
events: {
scroll(node, callback) {
const onScroll = throttle(event => {
mark('onScroll')
if (this.get('fullscreen')) {
return
}
callback(event)
stop('onScroll')
}, SCROLL_EVENT_DELAY, {
leading: true,
trailing: true
})
node.addEventListener('scroll', onScroll)
return {
teardown() {
node.removeEventListener('scroll', onScroll)
}
}
},
fullscreen(node, callback) {
const onFullscreen = (() => {
callback()
})
attachFullscreenListener(onFullscreen)
return {
teardown() {
detachFullscreenListener(onFullscreen)
}
}
}
},
methods: {
onScroll(event) {
this.store.set({
scrollTop: event.target.scrollTop,
scrollHeight: event.target.scrollHeight
})
},
onFullscreenChange() {
mark('onFullscreenChange')
if (process.env.NODE_ENV !== 'production') {
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>