forked from cybrespace/pinafore
save scroll positions
This commit is contained in:
parent
208316b914
commit
fb234adb79
|
@ -1,10 +1,18 @@
|
|||
<Nav :page :dynamicPage :dynamicHref :dynamicIcon :dynamicLabel/>
|
||||
|
||||
<VirtualListContainer>
|
||||
{{#if virtual}}
|
||||
<VirtualListContainer storeKey="{{virtualStoreKey}}">
|
||||
<main>
|
||||
<slot></slot>
|
||||
</main>
|
||||
</VirtualListContainer>
|
||||
{{else}}
|
||||
<div class="container">
|
||||
<main>
|
||||
<slot></slot>
|
||||
</main>
|
||||
</div>
|
||||
{{/if}}
|
||||
<script>
|
||||
import Nav from './Nav.html';
|
||||
import VirtualListContainer from './VirtualListContainer.html'
|
||||
|
|
|
@ -7,6 +7,8 @@
|
|||
shown="{{initialized}}"
|
||||
footerComponent="{{LoadingFooter}}"
|
||||
showFooter="{{initialized && runningUpdate}}"
|
||||
storeKey="{{timeline}}"
|
||||
initialized="{{initialized}}"
|
||||
/>
|
||||
</div>
|
||||
<style>
|
||||
|
@ -27,18 +29,32 @@
|
|||
import { toast } from '../_utils/toast'
|
||||
import { database } from '../_utils/database/database'
|
||||
|
||||
const cachedTimelines = {}
|
||||
|
||||
if (process.browser && process.env.NODE_ENV !== 'production') {
|
||||
window.cachedTimelines = cachedTimelines
|
||||
}
|
||||
|
||||
const FETCH_LIMIT = 20
|
||||
|
||||
export default {
|
||||
async oncreate() {
|
||||
let statuses = await this.fetchStatusesAndPossiblyFallBack()
|
||||
this.addStatuses(statuses)
|
||||
let timeline = this.get('timeline')
|
||||
let cachedStatusIds = cachedTimelines[timeline]
|
||||
if (cachedStatusIds) {
|
||||
this.set({statusIds: cachedStatusIds})
|
||||
} else {
|
||||
this.addStatuses(await this.fetchStatusesAndPossiblyFallBack())
|
||||
}
|
||||
requestAnimationFrame(() => {
|
||||
requestAnimationFrame(() => {
|
||||
requestAnimationFrame((() => {
|
||||
this.set({initialized: true})
|
||||
this.fire('initialized')
|
||||
}))
|
||||
})
|
||||
})
|
||||
},
|
||||
ondestroy() {
|
||||
cachedTimelines[this.get('timeline')] = this.get('statusIds')
|
||||
},
|
||||
data: () => ({
|
||||
StatusListItem: StatusListItem,
|
||||
|
|
|
@ -13,17 +13,44 @@
|
|||
|
||||
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: node.scrollTop,
|
||||
scrollTop: cachedStore.state.scrollTop,
|
||||
scrollHeight: cachedStore.state.scrollHeight,
|
||||
offsetHeight: cachedStore.state.offsetHeight
|
||||
})
|
||||
this.rehydrateScrollTop(cachedStore)
|
||||
this.store.set(cachedStore.state)
|
||||
} else {
|
||||
this.store.set({
|
||||
scrollTop: 0,
|
||||
scrollHeight: node.scrollHeight,
|
||||
offsetHeight: node.offsetHeight
|
||||
})
|
||||
}
|
||||
stop('onCreate VirtualListContainer')
|
||||
},
|
||||
ondestroy() {
|
||||
let storeKey = this.get('storeKey')
|
||||
if (storeKey) {
|
||||
cachedVirtualStores[storeKey] = {
|
||||
state: this.store.cloneState(),
|
||||
height: this.store.get('height')
|
||||
}
|
||||
}
|
||||
},
|
||||
store: () => virtualListStore,
|
||||
events: {
|
||||
scroll(node, callback) {
|
||||
|
@ -70,6 +97,25 @@
|
|||
console.log('is fullscreen? ', isFullscreen())
|
||||
this.set({ fullscreen: isFullscreen() })
|
||||
stop('onFullscreenChange')
|
||||
},
|
||||
rehydrateScrollTop(cachedStore) {
|
||||
let cachedScrollTop = cachedStore.state.scrollTop || 0
|
||||
let cachedHeight = cachedStore.height
|
||||
if (cachedScrollTop === 0) {
|
||||
return
|
||||
}
|
||||
let initializedScrollTop = false
|
||||
let node = this.refs.node
|
||||
this.store.observe('height', height => {
|
||||
if (!initializedScrollTop && height === cachedHeight && node) {
|
||||
initializedScrollTop = true
|
||||
requestAnimationFrame(() => {
|
||||
mark('set scrollTop')
|
||||
node.scrollTop = cachedScrollTop
|
||||
stop('set scrollTop')
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
@ -3,12 +3,28 @@ import { mark, stop } from '../_utils/marks'
|
|||
|
||||
const VIEWPORT_RENDER_FACTOR = 4
|
||||
|
||||
const cloneKeys = [
|
||||
'items',
|
||||
'itemHeights',
|
||||
'scrollTop',
|
||||
'scrollHeight',
|
||||
'offsetHeight'
|
||||
]
|
||||
|
||||
class VirtualListStore extends Store {
|
||||
constructor(state) {
|
||||
super(state)
|
||||
this._batches = {}
|
||||
}
|
||||
|
||||
cloneState() {
|
||||
let res = {}
|
||||
for (let key of cloneKeys) {
|
||||
res[key] = this.get(key)
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
batchUpdate(key, subKey, value) {
|
||||
let batch = this._batches[key]
|
||||
if (!batch) {
|
||||
|
|
|
@ -3,6 +3,8 @@
|
|||
</:Head>
|
||||
|
||||
<Layout page='tags'
|
||||
virtual="true"
|
||||
virtualStoreKey='account/{{params.accountId}}'
|
||||
dynamicPage="{{profileName}}"
|
||||
dynamicHref="/accounts/{{params.accountId}}"
|
||||
dynamicLabel="{{shortProfileName}}"
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
<title>Pinafore – Federated</title>
|
||||
</:Head>
|
||||
|
||||
<Layout page='federated'>
|
||||
<Layout page='federated' virtual="true" virtualStoreKey="federated">
|
||||
{{#if $isUserLoggedIn}}
|
||||
<LazyTimeline timeline='federated' />
|
||||
{{else}}
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
<title>Pinafore – Home</title>
|
||||
</:Head>
|
||||
|
||||
<Layout page='home'>
|
||||
<Layout page='home' virtual="true" virtualStoreKey="home">
|
||||
{{#if $isUserLoggedIn}}
|
||||
<LazyTimeline timeline='home' />
|
||||
{{else}}
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
<title>Pinafore – Local</title>
|
||||
</:Head>
|
||||
|
||||
<Layout page='local'>
|
||||
<Layout page='local' virtual="true" virtualStoreKey="local">
|
||||
{{#if $isUserLoggedIn}}
|
||||
<LazyTimeline timeline='local' />
|
||||
{{else}}
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
<title>Pinafore – Notifications</title>
|
||||
</:Head>
|
||||
|
||||
<Layout page='notifications'>
|
||||
<Layout page='notifications' virtual="true" virtualStoreKey="federated">
|
||||
<HiddenFromSSR>
|
||||
<FreeTextLayout>
|
||||
<h1>Notifications</h1>
|
||||
|
|
|
@ -3,6 +3,8 @@
|
|||
</:Head>
|
||||
|
||||
<Layout page='tags'
|
||||
virtual="true"
|
||||
virtualStoreKey='tag/{{params.tagName}}'
|
||||
dynamicPage="{{params.tagName}}"
|
||||
dynamicHref="/tags/{{params.tagName}}"
|
||||
dynamicLabel="{{'#' + params.tagName}}"
|
||||
|
|
Loading…
Reference in New Issue