more work on pseudo-virtual list

This commit is contained in:
Nolan Lawson 2018-01-30 18:26:13 -08:00
parent 98b22e0243
commit d2fe8b29f4
6 changed files with 71 additions and 28 deletions

View file

@ -7,9 +7,8 @@
makeProps="{{makeProps}}"
key="{{wrappedItem.item}}"
intersectionObserver="{{intersectionObserver}}"
hide="{{shouldHide(wrappedItem.item, intersectionStates)}}"
height="{{getHeight(wrappedItem.item, intersectionStates)}}"
on:renderedListItem="onRenderedListItem()"
hide="{{shouldHide(wrappedItem.item, $intersectionStates)}}"
height="{{getHeight(wrappedItem.item, $intersectionStates)}}"
/>
{{/each}}
</div>
@ -24,16 +23,26 @@
import PseudoVirtualListLazyItem from './PseudoVirtualListLazyItem.html'
import { getRectFromEntry } from '../../_utils/getRectFromEntry'
import { mark, stop } from '../../_utils/marks'
import { pseudoVirtualListStore } from './pseudoVirtualListStore'
export default {
oncreate() {
this.set({
intersectionObserver: new IntersectionObserver(this.onIntersection.bind(this), {
root: document.getElementsByClassName('container')[0], // TODO: fix this
rootMargin: '300% 0px'
}),
intersectionStates: {}
})
mark('PseudoVirtualList oncreate()')
this.store.set({currentRealm: this.get('realm')})
// When re-rendering, assume all items are non-intersecting until told otherwise.
// We already have the heights cached.
let intersectionStates = this.store.get('intersectionStates')
let keys = Object.keys(intersectionStates)
for (let key of keys) {
intersectionStates[key].isIntersecting = false
}
this.store.setForRealm({intersectionStates: intersectionStates})
this.set({intersectionObserver: new IntersectionObserver(this.onIntersection.bind(this), {
root: document.getElementsByClassName('container')[0], // TODO: fix this
rootMargin: '300% 0px'
})})
this.observe('allItemsHaveHeight', allItemsHaveHeight => {
console.log('allItemsHaveHeight', allItemsHaveHeight)
if (allItemsHaveHeight && !this.get('initialized')) {
@ -42,6 +51,7 @@
this.fire('initializedVisibleItems')
}
})
stop('PseudoVirtualList oncreate()')
},
ondestroy() {
let intersectionObserver = this.get('intersectionObserver')
@ -49,15 +59,12 @@
intersectionObserver.disconnect()
}
},
data: () => ({
intersectionStates: {}
}),
helpers: {
shouldHide(key, intersectionStates) {
return !!(intersectionStates[key] && !intersectionStates[key].isIntersecting)
shouldHide(key, $intersectionStates) {
return !!($intersectionStates[key] && !$intersectionStates[key].isIntersecting)
},
getHeight(key, intersectionStates) {
return intersectionStates[key] && intersectionStates[key].rect.height
getHeight(key, $intersectionStates) {
return $intersectionStates[key] && $intersectionStates[key].rect.height
}
},
methods: {
@ -85,7 +92,7 @@
mark('onIntersection')
let newIntersectionStates = {}
let scrollToItem = this.get('scrollToItem')
let intersectionStates = this.get('intersectionStates')
let intersectionStates = this.store.get('intersectionStates')
for (let entry of entries) {
let key = entry.target.getAttribute('pseudo-virtual-list-key')
let rect = getRectFromEntry(entry)
@ -98,18 +105,18 @@
}
}
intersectionStates = Object.assign(intersectionStates, newIntersectionStates)
this.set({intersectionStates: intersectionStates})
this.store.setForRealm({intersectionStates: intersectionStates})
stop('onIntersection')
}
},
computed: {
wrappedItems: (items) => items.map(item => ({item: item})),
allItemsHaveHeight: (items, intersectionStates) => {
allItemsHaveHeight: (items, $intersectionStates) => {
if (!items.length) {
return false
}
for (let item of items) {
if (!intersectionStates[item]) {
if (!$intersectionStates[item]) {
return false
}
}
@ -118,6 +125,7 @@
},
components: {
PseudoVirtualListLazyItem
}
},
store: () => pseudoVirtualListStore
}
</script>

View file

@ -0,0 +1,24 @@
import { Store } from 'svelte/store.js'
class PseudoVirtualListStore extends Store {
setForRealm(obj) {
let realmName = this.get('currentRealm')
let realms = this.get('realms') || {}
realms[realmName] = Object.assign(realms[realmName] || {}, obj)
this.set({realms: realms})
}
}
const pseudoVirtualListStore = new PseudoVirtualListStore()
pseudoVirtualListStore.compute('intersectionStates',
['realms', 'currentRealm'],
(realms, currentRealm) => {
return (realms && realms[currentRealm] && realms[currentRealm].intersectionStates) || {}
})
if (process.browser && process.env.NODE_NODE !== 'production') {
window.pseudoVirtualListStore = pseudoVirtualListStore
}
export { pseudoVirtualListStore }

View file

@ -19,7 +19,7 @@
<span class="status-author-handle">
{{'@' + originalAccount.acct}}
</span>
{{#if timelineType === 'status'}}
{{#if isStatusInContext}}
<ExternalLink class="status-author-date" href="{{originalStatus.url}}" showIcon="true">
<time datetime={{createdAtDate}} title="{{relativeDate}}">{{relativeDate}}</time>
</ExternalLink>
@ -39,7 +39,7 @@
</div>
{{/if}}
{{#if !originalStatus.spoiler_text || spoilerShown}}
<div class="status-content" ref:contentNode>
<div class="status-content {{isStatusInContext ? 'status-in-context' : ''}}" ref:contentNode>
{{{emojifiedContent}}}
</div>
{{/if}}
@ -176,6 +176,11 @@
font-size: 0.9em;
}
.status-content.status-in-context {
font-size: 1.1em;
margin: 20px 10px 20px 5px;
}
:global(.status-content .status-emoji) {
width: 20px;
height: 20px;
@ -323,6 +328,9 @@
},
store: () => store,
computed: {
isStatusInContext: (timelineType, timelineValue, statusId) => {
return timelineType === 'status' && timelineValue === statusId
},
createdAtDate: (status) => status.created_at,
relativeDate: (createdAtDate) => {
mark('compute relativeDate')

View file

@ -19,15 +19,15 @@
min-height: 60vh;
}
.loading-page {
position: absolute;
top: 0;
position: fixed;
top: 72px;
left: 0;
bottom: 0;
right: 0;
display: flex;
align-items: center;
justify-content: center;
z-index: 50
z-index: 50;
}
</style>
<script>

View file

@ -1,5 +1,6 @@
<Status status="{{virtualProps.status}}"
timelineType="{{virtualProps.timelineType}}"
timelineValue="{{virtualProps.timelineValue}}"
index="{{virtualIndex}}"
length="{{virtualLength}}"
on:recalculateHeight />

View file

@ -19,6 +19,7 @@
shown="{{$initialized}}"
on:initializedVisibleItems="initialize()"
scrollToItem="{{timelineValue}}"
realm="{{$currentInstance + '/' + timeline}}"
/>
{{/if}}
</div>
@ -49,8 +50,9 @@
Status
}),
computed: {
makeProps: ($currentInstance, timelineType) => async (statusId) => ({
makeProps: ($currentInstance, timelineType, timelineValue) => async (statusId) => ({
timelineType: timelineType,
timelineValue: timelineValue,
status: await database.getStatus($currentInstance, statusId)
}),
label: (timeline, $currentInstance, timelineType, timelineValue) => {