refactor virtual store to use realms
This commit is contained in:
parent
610e54469e
commit
687cc5c961
|
@ -1,7 +1,7 @@
|
||||||
<Nav :page :dynamicPage :dynamicHref :dynamicIcon :dynamicLabel/>
|
<Nav :page :dynamicPage :dynamicHref :dynamicIcon :dynamicLabel/>
|
||||||
|
|
||||||
{{#if virtual}}
|
{{#if virtual}}
|
||||||
<VirtualListContainer storeKey="{{virtualStoreKey}}">
|
<VirtualListContainer realm="{{virtualRealm}}">
|
||||||
<main>
|
<main>
|
||||||
<slot></slot>
|
<slot></slot>
|
||||||
</main>
|
</main>
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
shown="{{initialized}}"
|
shown="{{initialized}}"
|
||||||
footerComponent="{{LoadingFooter}}"
|
footerComponent="{{LoadingFooter}}"
|
||||||
showFooter="{{initialized && runningUpdate}}"
|
showFooter="{{initialized && runningUpdate}}"
|
||||||
storeKey="{{timeline}}"
|
realm="{{timeline}}"
|
||||||
on:initializedVisibleItems="initialize()"
|
on:initializedVisibleItems="initialize()"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -31,13 +31,11 @@
|
||||||
export default {
|
export default {
|
||||||
oncreate () {
|
oncreate () {
|
||||||
this.observe('showFooter', showFooter => {
|
this.observe('showFooter', showFooter => {
|
||||||
this.store.set({showFooter: showFooter})
|
this.store.setForRealm({showFooter: showFooter})
|
||||||
})
|
})
|
||||||
this.observe('items', (items) => {
|
this.observe('items', (items) => {
|
||||||
mark('set items')
|
mark('set items')
|
||||||
this.store.set({
|
this.store.setForRealm({items: items})
|
||||||
items: items
|
|
||||||
})
|
|
||||||
stop('set items')
|
stop('set items')
|
||||||
this.fireScrollToBottom = throttle(() => {
|
this.fireScrollToBottom = throttle(() => {
|
||||||
this.fire('scrollToBottom')
|
this.fire('scrollToBottom')
|
||||||
|
|
|
@ -13,73 +13,38 @@
|
||||||
|
|
||||||
const SCROLL_EVENT_DELAY = 300
|
const SCROLL_EVENT_DELAY = 300
|
||||||
|
|
||||||
const cachedVirtualStores = {}
|
|
||||||
|
|
||||||
if (process.browser && process.env.NODE_ENV !== 'production') {
|
|
||||||
window.cachedVirtualStores = cachedVirtualStores
|
|
||||||
}
|
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
oncreate() {
|
oncreate() {
|
||||||
mark('onCreate VirtualListContainer')
|
mark('onCreate VirtualListContainer')
|
||||||
let node = this.refs.node
|
let node = this.refs.node
|
||||||
let storeKey = this.get('storeKey')
|
let realm = this.get('realm')
|
||||||
let cachedStore
|
this.store.set({currentRealm: realm})
|
||||||
if (storeKey && (cachedStore = cachedVirtualStores[storeKey])) {
|
let scrollTop = this.store.get('scrollTop')
|
||||||
this.store.set({
|
if (scrollTop > 0) {
|
||||||
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 => {
|
this.observe('allVisibleItemsHaveHeight', allVisibleItemsHaveHeight => {
|
||||||
if (process.env.NODE_ENV !== 'production') {
|
if (process.env.NODE_ENV !== 'production') {
|
||||||
console.log('allVisibleItemsHaveHeight', allVisibleItemsHaveHeight)
|
console.log('allVisibleItemsHaveHeight', allVisibleItemsHaveHeight)
|
||||||
}
|
}
|
||||||
if (!initializedScrollTop && allVisibleItemsHaveHeight && node) {
|
if (!this.get('initializedScrollTop') && allVisibleItemsHaveHeight && node) {
|
||||||
initializedScrollTop = true
|
this.set({'initializedScrollTop': true})
|
||||||
requestAnimationFrame(() => {
|
requestAnimationFrame(() => {
|
||||||
mark('set scrollTop')
|
mark('set scrollTop')
|
||||||
if (process.env.NODE_ENV !== 'production') {
|
if (process.env.NODE_ENV !== 'production') {
|
||||||
console.log('forcing scroll top to ', cachedScrollTop)
|
console.log('forcing scroll top to ', scrollTop)
|
||||||
}
|
}
|
||||||
node.scrollTop = cachedScrollTop
|
node.scrollTop = scrollTop
|
||||||
stop('set scrollTop')
|
stop('set scrollTop')
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
this.store.set({
|
this.store.setForRealm({
|
||||||
scrollTop: 0,
|
|
||||||
scrollHeight: node.scrollHeight,
|
scrollHeight: node.scrollHeight,
|
||||||
offsetHeight: node.offsetHeight
|
offsetHeight: node.offsetHeight
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
stop('onCreate VirtualListContainer')
|
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,
|
store: () => virtualListStore,
|
||||||
events: {
|
events: {
|
||||||
scroll(node, callback) {
|
scroll(node, callback) {
|
||||||
|
@ -116,7 +81,7 @@
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
onScroll(event) {
|
onScroll(event) {
|
||||||
this.store.set({
|
this.store.setForRealm({
|
||||||
scrollTop: event.target.scrollTop,
|
scrollTop: event.target.scrollTop,
|
||||||
scrollHeight: event.target.scrollHeight
|
scrollHeight: event.target.scrollHeight
|
||||||
})
|
})
|
||||||
|
|
|
@ -3,28 +3,12 @@ import { mark, stop } from '../../_utils/marks'
|
||||||
|
|
||||||
const VIEWPORT_RENDER_FACTOR = 4
|
const VIEWPORT_RENDER_FACTOR = 4
|
||||||
|
|
||||||
const cloneKeys = [
|
|
||||||
'items',
|
|
||||||
'itemHeights',
|
|
||||||
'scrollTop',
|
|
||||||
'scrollHeight',
|
|
||||||
'offsetHeight'
|
|
||||||
]
|
|
||||||
|
|
||||||
class VirtualListStore extends Store {
|
class VirtualListStore extends Store {
|
||||||
constructor(state) {
|
constructor(state) {
|
||||||
super(state)
|
super(state)
|
||||||
this._batches = {}
|
this._batches = {}
|
||||||
}
|
}
|
||||||
|
|
||||||
cloneState() {
|
|
||||||
let res = {}
|
|
||||||
for (let key of cloneKeys) {
|
|
||||||
res[key] = this.get(key)
|
|
||||||
}
|
|
||||||
return res
|
|
||||||
}
|
|
||||||
|
|
||||||
batchUpdate(key, subKey, value) {
|
batchUpdate(key, subKey, value) {
|
||||||
let batch = this._batches[key]
|
let batch = this._batches[key]
|
||||||
if (!batch) {
|
if (!batch) {
|
||||||
|
@ -53,15 +37,42 @@ class VirtualListStore extends Store {
|
||||||
stop('batchUpdate()')
|
stop('batchUpdate()')
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setForRealm(obj) {
|
||||||
|
let realmName = this.get('currentRealm')
|
||||||
|
let realms = this.get('realms') || {}
|
||||||
|
realms[realmName] = Object.assign(realms[realmName] || {}, obj)
|
||||||
|
this.set({realms: realms})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const virtualListStore = new VirtualListStore({
|
const virtualListStore = new VirtualListStore({
|
||||||
items: [],
|
realms: {},
|
||||||
|
currentRealm: null,
|
||||||
itemHeights: {},
|
itemHeights: {},
|
||||||
showFooter: false,
|
|
||||||
footerHeight: 0
|
footerHeight: 0
|
||||||
})
|
})
|
||||||
|
|
||||||
|
virtualListStore.compute('items', ['currentRealm', 'realms'], (currentRealm, realms) => {
|
||||||
|
return realms[currentRealm] && realms[currentRealm].items || []
|
||||||
|
})
|
||||||
|
|
||||||
|
virtualListStore.compute('showFooter', ['currentRealm', 'realms'], (currentRealm, realms) => {
|
||||||
|
return realms[currentRealm] && realms[currentRealm].showFooter
|
||||||
|
})
|
||||||
|
|
||||||
|
virtualListStore.compute('scrollTop', ['currentRealm', 'realms'], (currentRealm, realms) => {
|
||||||
|
return realms[currentRealm] && realms[currentRealm].scrollTop || 0
|
||||||
|
})
|
||||||
|
|
||||||
|
virtualListStore.compute('scrollHeight', ['currentRealm', 'realms'], (currentRealm, realms) => {
|
||||||
|
return realms[currentRealm] && realms[currentRealm].scrollHeight || 0
|
||||||
|
})
|
||||||
|
|
||||||
|
virtualListStore.compute('offsetHeight', ['currentRealm', 'realms'], (currentRealm, realms) => {
|
||||||
|
return realms[currentRealm] && realms[currentRealm].offsetHeight || 0
|
||||||
|
})
|
||||||
|
|
||||||
virtualListStore.compute('visibleItems',
|
virtualListStore.compute('visibleItems',
|
||||||
['items', 'scrollTop', 'itemHeights', 'offsetHeight'],
|
['items', 'scrollTop', 'itemHeights', 'offsetHeight'],
|
||||||
(items, scrollTop, itemHeights, offsetHeight) => {
|
(items, scrollTop, itemHeights, offsetHeight) => {
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
|
|
||||||
<Layout page='tags'
|
<Layout page='tags'
|
||||||
virtual="true"
|
virtual="true"
|
||||||
virtualStoreKey='account/{{params.accountId}}'
|
virtualRealm='account/{{params.accountId}}'
|
||||||
dynamicPage="{{profileName}}"
|
dynamicPage="{{profileName}}"
|
||||||
dynamicHref="/accounts/{{params.accountId}}"
|
dynamicHref="/accounts/{{params.accountId}}"
|
||||||
dynamicLabel="{{shortProfileName}}"
|
dynamicLabel="{{shortProfileName}}"
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
<title>Pinafore – Federated</title>
|
<title>Pinafore – Federated</title>
|
||||||
</:Head>
|
</:Head>
|
||||||
|
|
||||||
<Layout page='federated' virtual="true" virtualStoreKey="federated">
|
<Layout page='federated' virtual="true" virtualRealm="federated">
|
||||||
{{#if $isUserLoggedIn}}
|
{{#if $isUserLoggedIn}}
|
||||||
<LazyTimeline timeline='federated' />
|
<LazyTimeline timeline='federated' />
|
||||||
{{else}}
|
{{else}}
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
<title>Pinafore – Home</title>
|
<title>Pinafore – Home</title>
|
||||||
</:Head>
|
</:Head>
|
||||||
|
|
||||||
<Layout page='home' virtual="true" virtualStoreKey="home">
|
<Layout page='home' virtual="true" virtualRealm="home">
|
||||||
{{#if $isUserLoggedIn}}
|
{{#if $isUserLoggedIn}}
|
||||||
<LazyTimeline timeline='home' />
|
<LazyTimeline timeline='home' />
|
||||||
{{else}}
|
{{else}}
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
<title>Pinafore – Local</title>
|
<title>Pinafore – Local</title>
|
||||||
</:Head>
|
</:Head>
|
||||||
|
|
||||||
<Layout page='local' virtual="true" virtualStoreKey="local">
|
<Layout page='local' virtual="true" virtualRealm="local">
|
||||||
{{#if $isUserLoggedIn}}
|
{{#if $isUserLoggedIn}}
|
||||||
<LazyTimeline timeline='local' />
|
<LazyTimeline timeline='local' />
|
||||||
{{else}}
|
{{else}}
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
<title>Pinafore – Notifications</title>
|
<title>Pinafore – Notifications</title>
|
||||||
</:Head>
|
</:Head>
|
||||||
|
|
||||||
<Layout page='notifications' virtual="true" virtualStoreKey="federated">
|
<Layout page='notifications' virtual="true" virtualRealm="federated">
|
||||||
<HiddenFromSSR>
|
<HiddenFromSSR>
|
||||||
<FreeTextLayout>
|
<FreeTextLayout>
|
||||||
<h1>Notifications</h1>
|
<h1>Notifications</h1>
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
|
|
||||||
<Layout page='tags'
|
<Layout page='tags'
|
||||||
virtual="true"
|
virtual="true"
|
||||||
virtualStoreKey='tag/{{params.tagName}}'
|
virtualRealm='tag/{{params.tagName}}'
|
||||||
dynamicPage="{{params.tagName}}"
|
dynamicPage="{{params.tagName}}"
|
||||||
dynamicHref="/tags/{{params.tagName}}"
|
dynamicHref="/tags/{{params.tagName}}"
|
||||||
dynamicLabel="{{'#' + params.tagName}}"
|
dynamicLabel="{{'#' + params.tagName}}"
|
||||||
|
|
Loading…
Reference in a new issue