forked from cybrespace/pinafore
streaming is kinda working
This commit is contained in:
parent
075066ba9a
commit
2a86425c90
|
@ -16,17 +16,13 @@ async function removeDuplicates (instanceName, timelineName, updates) {
|
||||||
}
|
}
|
||||||
|
|
||||||
async function handleFreshChanges (instanceName, timelineName) {
|
async function handleFreshChanges (instanceName, timelineName) {
|
||||||
console.log('handleFreshChanges')
|
|
||||||
let freshChanges = store.getForTimeline(instanceName, timelineName, 'freshChanges')
|
let freshChanges = store.getForTimeline(instanceName, timelineName, 'freshChanges')
|
||||||
console.log('freshChanges', freshChanges)
|
|
||||||
if (freshChanges.updates && freshChanges.updates.length) {
|
if (freshChanges.updates && freshChanges.updates.length) {
|
||||||
let updates = freshChanges.updates.slice()
|
let updates = freshChanges.updates.slice()
|
||||||
freshChanges.updates = []
|
freshChanges.updates = []
|
||||||
store.setForTimeline(instanceName, timelineName, {freshChanges: freshChanges})
|
store.setForTimeline(instanceName, timelineName, {freshChanges: freshChanges})
|
||||||
|
|
||||||
console.log('before removing duplicates, updates are ', updates.length)
|
|
||||||
updates = await removeDuplicates(instanceName, timelineName, updates)
|
updates = await removeDuplicates(instanceName, timelineName, updates)
|
||||||
console.log('after removing duplicates, updates are ', updates.length)
|
|
||||||
|
|
||||||
await database.insertTimelineItems(instanceName, timelineName, updates)
|
await database.insertTimelineItems(instanceName, timelineName, updates)
|
||||||
|
|
||||||
|
@ -39,7 +35,6 @@ async function handleFreshChanges (instanceName, timelineName) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleStreamMessage (instanceName, timelineName, message) {
|
function handleStreamMessage (instanceName, timelineName, message) {
|
||||||
console.log('handleStreamMessage')
|
|
||||||
let { event, payload } = message
|
let { event, payload } = message
|
||||||
let key = event === 'update' ? 'updates' : 'deletes'
|
let key = event === 'update' ? 'updates' : 'deletes'
|
||||||
let freshChanges = store.getForTimeline(instanceName, timelineName, 'freshChanges') || {}
|
let freshChanges = store.getForTimeline(instanceName, timelineName, 'freshChanges') || {}
|
||||||
|
@ -54,7 +49,6 @@ function handleStreamMessage (instanceName, timelineName, message) {
|
||||||
export function createStream (streamingApi, instanceName, accessToken, timelineName) {
|
export function createStream (streamingApi, instanceName, accessToken, timelineName) {
|
||||||
return new TimelineStream(streamingApi, accessToken, timelineName, {
|
return new TimelineStream(streamingApi, accessToken, timelineName, {
|
||||||
onMessage (msg) {
|
onMessage (msg) {
|
||||||
console.log('message', msg)
|
|
||||||
if (msg.event !== 'update' && msg.event !== 'delete') {
|
if (msg.event !== 'update' && msg.event !== 'delete') {
|
||||||
console.error("don't know how to handle event", msg)
|
console.error("don't know how to handle event", msg)
|
||||||
return
|
return
|
||||||
|
@ -73,4 +67,4 @@ export function createStream (streamingApi, instanceName, accessToken, timelineN
|
||||||
console.log('reconnected stream for timeline', timelineName)
|
console.log('reconnected stream for timeline', timelineName)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
|
@ -81,3 +81,15 @@ export async function fetchTimelineItemsOnScrollToBottom () {
|
||||||
await fetchTimelineItemsAndPossiblyFallBack()
|
await fetchTimelineItemsAndPossiblyFallBack()
|
||||||
store.setForTimeline(instanceName, timelineName, { runningUpdate: false })
|
store.setForTimeline(instanceName, timelineName, { runningUpdate: false })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function showMoreItemsForCurrentTimeline() {
|
||||||
|
let instanceName = store.get('currentInstance')
|
||||||
|
let timelineName = store.get('currentTimeline')
|
||||||
|
let itemIdsToAdd = store.get('itemIdsToAdd')
|
||||||
|
addTimelineItemIds(instanceName, timelineName, itemIdsToAdd)
|
||||||
|
store.setForTimeline(instanceName, timelineName, {
|
||||||
|
itemIdsToAdd: [],
|
||||||
|
shouldShowHeader: false,
|
||||||
|
showHeader: false
|
||||||
|
})
|
||||||
|
}
|
|
@ -0,0 +1,25 @@
|
||||||
|
<div class="more-items-header" role="dialog">
|
||||||
|
<button class="primary" type="button" on:click="onClick(event)">
|
||||||
|
Click to show {{count}} more
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<style>
|
||||||
|
.more-items-header {
|
||||||
|
display: flex;
|
||||||
|
padding: 5px;
|
||||||
|
align-items: center;
|
||||||
|
justify-content:center;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
methods: {
|
||||||
|
onClick(event) {
|
||||||
|
let onClick = this.get('onClick')
|
||||||
|
if (onClick) {
|
||||||
|
onClick(event)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
|
@ -0,0 +1,11 @@
|
||||||
|
<MoreHeader count="{{virtualProps.count}}"
|
||||||
|
onClick="{{virtualProps.onClick}}"
|
||||||
|
/>
|
||||||
|
<script>
|
||||||
|
import MoreHeader from './MoreHeader.html'
|
||||||
|
export default {
|
||||||
|
components: {
|
||||||
|
MoreHeader
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
|
@ -12,9 +12,13 @@
|
||||||
:makeProps
|
:makeProps
|
||||||
items="{{$timelineItemIds}}"
|
items="{{$timelineItemIds}}"
|
||||||
on:scrollToBottom="onScrollToBottom()"
|
on:scrollToBottom="onScrollToBottom()"
|
||||||
|
on:scrollToTop="onScrollToTop()"
|
||||||
shown="{{$initialized}}"
|
shown="{{$initialized}}"
|
||||||
footerComponent="{{LoadingFooter}}"
|
footerComponent="{{LoadingFooter}}"
|
||||||
showFooter="{{$initialized && $runningUpdate}}"
|
showFooter="{{$initialized && $runningUpdate}}"
|
||||||
|
showHeader="{{$showHeader}}"
|
||||||
|
headerComponent="{{MoreHeaderVirtualWrapper}}"
|
||||||
|
:headerProps
|
||||||
realm="{{$currentInstance + '/' + timeline}}"
|
realm="{{$currentInstance + '/' + timeline}}"
|
||||||
on:initializedVisibleItems="initialize()"
|
on:initializedVisibleItems="initialize()"
|
||||||
/>
|
/>
|
||||||
|
@ -23,8 +27,12 @@
|
||||||
:makeProps
|
:makeProps
|
||||||
items="{{$timelineItemIds}}"
|
items="{{$timelineItemIds}}"
|
||||||
on:scrollToBottom="onScrollToBottom()"
|
on:scrollToBottom="onScrollToBottom()"
|
||||||
|
on:scrollToTop="onScrollToTop()"
|
||||||
shown="{{$initialized}}"
|
shown="{{$initialized}}"
|
||||||
footerComponent="{{LoadingFooter}}"
|
footerComponent="{{LoadingFooter}}"
|
||||||
|
showHeader="{{$showHeader}}"
|
||||||
|
headerComponent="{{MoreHeaderVirtualWrapper}}"
|
||||||
|
:headerProps
|
||||||
showFooter="{{$initialized && $runningUpdate}}"
|
showFooter="{{$initialized && $runningUpdate}}"
|
||||||
realm="{{$currentInstance + '/' + timeline}}"
|
realm="{{$currentInstance + '/' + timeline}}"
|
||||||
on:initializedVisibleItems="initialize()"
|
on:initializedVisibleItems="initialize()"
|
||||||
|
@ -55,13 +63,16 @@
|
||||||
import Status from '../status/Status.html'
|
import Status from '../status/Status.html'
|
||||||
import PseudoVirtualList from '../pseudoVirtualList/PseudoVirtualList.html'
|
import PseudoVirtualList from '../pseudoVirtualList/PseudoVirtualList.html'
|
||||||
import LoadingFooter from './LoadingFooter.html'
|
import LoadingFooter from './LoadingFooter.html'
|
||||||
|
import MoreHeaderVirtualWrapper from './MoreHeaderVirtualWrapper.html'
|
||||||
import VirtualList from '../virtualList/VirtualList.html'
|
import VirtualList from '../virtualList/VirtualList.html'
|
||||||
import { timelines } from '../../_static/timelines'
|
import { timelines } from '../../_static/timelines'
|
||||||
import { database } from '../../_database/database'
|
import { database } from '../../_database/database'
|
||||||
import { initializeTimeline, fetchTimelineItemsOnScrollToBottom, setupTimeline } from '../../_actions/timeline'
|
import { initializeTimeline, fetchTimelineItemsOnScrollToBottom, setupTimeline } from '../../_actions/timeline'
|
||||||
import LoadingPage from '../LoadingPage.html'
|
import LoadingPage from '../LoadingPage.html'
|
||||||
import { focusWithCapture, blurWithCapture } from '../../_utils/events'
|
import { focusWithCapture, blurWithCapture } from '../../_utils/events'
|
||||||
import { addTimelineItemIds } from '../../_actions/timeline'
|
import { showMoreItemsForCurrentTimeline } from '../../_actions/timeline'
|
||||||
|
import { virtualListStore } from '../virtualList/virtualListStore' // TODO: hacky, need better way to expose scrollTop
|
||||||
|
import { scheduleIdleTask } from '../../_utils/scheduleIdleTask'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
oncreate() {
|
oncreate() {
|
||||||
|
@ -71,15 +82,7 @@
|
||||||
if (this.store.get('initialized')) {
|
if (this.store.get('initialized')) {
|
||||||
this.restoreFocus()
|
this.restoreFocus()
|
||||||
}
|
}
|
||||||
let instanceName = this.store.get('currentInstance')
|
this.setupStreaming()
|
||||||
let timelineName = this.get('timeline')
|
|
||||||
this.observe('itemIdsToAdd', itemIdsToAdd => {
|
|
||||||
console.log('itemIdsToAdd', itemIdsToAdd)
|
|
||||||
if (itemIdsToAdd && itemIdsToAdd.length) {
|
|
||||||
addTimelineItemIds(instanceName, timelineName, itemIdsToAdd)
|
|
||||||
this.store.setForTimeline(instanceName, timelineName, {itemIdsToAdd: []})
|
|
||||||
}
|
|
||||||
})
|
|
||||||
},
|
},
|
||||||
ondestroy() {
|
ondestroy() {
|
||||||
console.log('ondestroy')
|
console.log('ondestroy')
|
||||||
|
@ -89,6 +92,7 @@
|
||||||
StatusVirtualListItem,
|
StatusVirtualListItem,
|
||||||
NotificationVirtualListItem,
|
NotificationVirtualListItem,
|
||||||
LoadingFooter,
|
LoadingFooter,
|
||||||
|
MoreHeaderVirtualWrapper,
|
||||||
Status
|
Status
|
||||||
}),
|
}),
|
||||||
computed: {
|
computed: {
|
||||||
|
@ -139,6 +143,12 @@
|
||||||
$timelines[$currentInstance] &&
|
$timelines[$currentInstance] &&
|
||||||
$timelines[$currentInstance][timeline] &&
|
$timelines[$currentInstance][timeline] &&
|
||||||
$timelines[$currentInstance][timeline].itemIdsToAdd) || []
|
$timelines[$currentInstance][timeline].itemIdsToAdd) || []
|
||||||
|
},
|
||||||
|
headerProps: (itemIdsToAdd) => {
|
||||||
|
return {
|
||||||
|
count: (itemIdsToAdd && itemIdsToAdd.length) || 0,
|
||||||
|
onClick: showMoreItemsForCurrentTimeline
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
store: () => store,
|
store: () => store,
|
||||||
|
@ -168,6 +178,41 @@
|
||||||
}
|
}
|
||||||
fetchTimelineItemsOnScrollToBottom()
|
fetchTimelineItemsOnScrollToBottom()
|
||||||
},
|
},
|
||||||
|
onScrollToTop() {
|
||||||
|
if (this.store.get('shouldShowHeader')) {
|
||||||
|
this.store.setForCurrentTimeline({
|
||||||
|
showHeader: true,
|
||||||
|
shouldShowHeader: false
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
setupStreaming() {
|
||||||
|
let instanceName = this.store.get('currentInstance')
|
||||||
|
let timelineName = this.get('timeline')
|
||||||
|
let handleItemIdsToAdd = () => {
|
||||||
|
let itemIdsToAdd = this.get('itemIdsToAdd')
|
||||||
|
if (!itemIdsToAdd || !itemIdsToAdd.length) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
let scrollTop = virtualListStore.get('scrollTop')
|
||||||
|
let shouldShowHeader = this.store.get('shouldShowHeader')
|
||||||
|
let showHeader = this.store.get('showHeader')
|
||||||
|
//console.log('handleItemIdsToAdd', (itemIdsToAdd && itemIdsToAdd.length) || 0)
|
||||||
|
if (scrollTop === 0 && !shouldShowHeader && !showHeader) {
|
||||||
|
// if the user is scrolled to the top and we're not showing the header, then
|
||||||
|
// just insert the statuses. this is "chat room mode"
|
||||||
|
showMoreItemsForCurrentTimeline()
|
||||||
|
} else {
|
||||||
|
// user hasn't scrolled to the top, show a header instead
|
||||||
|
this.store.setForTimeline(instanceName, timelineName, {shouldShowHeader: true})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.observe('itemIdsToAdd', itemIdsToAdd => {
|
||||||
|
if (itemIdsToAdd && itemIdsToAdd.length) {
|
||||||
|
scheduleIdleTask(handleItemIdsToAdd)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
setupFocus() {
|
setupFocus() {
|
||||||
this.onPushState = this.onPushState.bind(this)
|
this.onPushState = this.onPushState.bind(this)
|
||||||
this.store.setForCurrentTimeline({ignoreBlurEvents: false})
|
this.store.setForCurrentTimeline({ignoreBlurEvents: false})
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
<!-- TODO: setting height is hacky, just make this element the scroller -->
|
|
||||||
<div class="virtual-list {{shown ? '' : 'hidden'}}" style="height: {{$height}}px;">
|
<div class="virtual-list {{shown ? '' : 'hidden'}}" style="height: {{$height}}px;">
|
||||||
|
<VirtualListHeader component="{{headerComponent}}" virtualProps="{{headerProps}}" shown="{{$showHeader}}"/>
|
||||||
{{#if $visibleItems}}
|
{{#if $visibleItems}}
|
||||||
{{#each $visibleItems as visibleItem @key}}
|
{{#each $visibleItems as visibleItem @key}}
|
||||||
<VirtualListLazyItem :component
|
<VirtualListLazyItem :component
|
||||||
|
@ -23,25 +23,32 @@
|
||||||
<script>
|
<script>
|
||||||
import VirtualListLazyItem from './VirtualListLazyItem'
|
import VirtualListLazyItem from './VirtualListLazyItem'
|
||||||
import VirtualListFooter from './VirtualListFooter.html'
|
import VirtualListFooter from './VirtualListFooter.html'
|
||||||
|
import VirtualListHeader from './VirtualListHeader.html'
|
||||||
import { virtualListStore } from './virtualListStore'
|
import { virtualListStore } from './virtualListStore'
|
||||||
import throttle from 'lodash/throttle'
|
import throttle from 'lodash/throttle'
|
||||||
import { mark, stop } from '../../_utils/marks'
|
import { mark, stop } from '../../_utils/marks'
|
||||||
|
|
||||||
const DISTANCE_FROM_BOTTOM_TO_FIRE = 400
|
const DISTANCE_FROM_BOTTOM_TO_FIRE = 400
|
||||||
const SCROLL_TO_BOTTOM_DELAY = 1000
|
const SCROLL_EVENT_THROTTLE = 1000
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
oncreate () {
|
oncreate () {
|
||||||
this.observe('showFooter', showFooter => {
|
this.observe('showFooter', showFooter => {
|
||||||
this.store.setForRealm({showFooter: showFooter})
|
this.store.setForRealm({showFooter: showFooter})
|
||||||
})
|
})
|
||||||
|
this.observe('showHeader', showHeader => {
|
||||||
|
this.store.setForRealm({showHeader: showHeader})
|
||||||
|
})
|
||||||
this.observe('items', (items) => {
|
this.observe('items', (items) => {
|
||||||
mark('set items')
|
mark('set items')
|
||||||
this.store.setForRealm({items: items})
|
this.store.setForRealm({items: items})
|
||||||
stop('set items')
|
stop('set items')
|
||||||
this.fireScrollToBottom = throttle(() => {
|
this.fireScrollToBottom = throttle(() => {
|
||||||
this.fire('scrollToBottom')
|
this.fire('scrollToBottom')
|
||||||
}, SCROLL_TO_BOTTOM_DELAY)
|
}, SCROLL_EVENT_THROTTLE)
|
||||||
|
this.fireScrollToTop = throttle(() => {
|
||||||
|
this.fire('scrollToTop')
|
||||||
|
}, SCROLL_EVENT_THROTTLE)
|
||||||
})
|
})
|
||||||
|
|
||||||
this.observe('allVisibleItemsHaveHeight', allVisibleItemsHaveHeight => {
|
this.observe('allVisibleItemsHaveHeight', allVisibleItemsHaveHeight => {
|
||||||
|
@ -62,6 +69,12 @@
|
||||||
this.fireScrollToBottom()
|
this.fireScrollToBottom()
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
this.observe('distanceFromTop', (distanceFromTop) => {
|
||||||
|
if (distanceFromTop === 0) {
|
||||||
|
this.fireScrollToTop()
|
||||||
|
}
|
||||||
|
})
|
||||||
},
|
},
|
||||||
data: () => ({
|
data: () => ({
|
||||||
component: null
|
component: null
|
||||||
|
@ -69,12 +82,14 @@
|
||||||
store: () => virtualListStore,
|
store: () => virtualListStore,
|
||||||
components: {
|
components: {
|
||||||
VirtualListLazyItem,
|
VirtualListLazyItem,
|
||||||
VirtualListFooter
|
VirtualListFooter,
|
||||||
|
VirtualListHeader
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
distanceFromBottom: ($scrollHeight, $scrollTop, $offsetHeight) => {
|
distanceFromBottom: ($scrollHeight, $scrollTop, $offsetHeight) => {
|
||||||
return $scrollHeight - $scrollTop - $offsetHeight
|
return $scrollHeight - $scrollTop - $offsetHeight
|
||||||
},
|
},
|
||||||
|
distanceFromTop: ($scrollTop) => $scrollTop,
|
||||||
// TODO: bug in svelte store, shouldn't need to do this
|
// TODO: bug in svelte store, shouldn't need to do this
|
||||||
allVisibleItemsHaveHeight: ($allVisibleItemsHaveHeight) => $allVisibleItemsHaveHeight
|
allVisibleItemsHaveHeight: ($allVisibleItemsHaveHeight) => $allVisibleItemsHaveHeight
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,34 @@
|
||||||
|
<div class="virtual-list-header {{shown ? 'shown' : ''}}"
|
||||||
|
aria-hidden="{{!shown}}"
|
||||||
|
ref:node >
|
||||||
|
<:Component {component} :virtualProps />
|
||||||
|
</div>
|
||||||
|
<style>
|
||||||
|
.virtual-list-header {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
width: 100%;
|
||||||
|
opacity: 0;
|
||||||
|
pointer-events: none;
|
||||||
|
z-index: 10;
|
||||||
|
}
|
||||||
|
.virtual-list-header.shown {
|
||||||
|
opacity: 1;
|
||||||
|
pointer-events: auto;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<script>
|
||||||
|
import { virtualListStore } from './virtualListStore'
|
||||||
|
import { AsyncLayout } from '../../_utils/AsyncLayout'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
oncreate() {
|
||||||
|
const asyncLayout = new AsyncLayout(() => '__header__')
|
||||||
|
asyncLayout.observe('__header__', this.refs.node, (rect) => {
|
||||||
|
asyncLayout.disconnect()
|
||||||
|
this.store.setForRealm({headerHeight: rect.height})
|
||||||
|
})
|
||||||
|
},
|
||||||
|
store: () => virtualListStore,
|
||||||
|
}
|
||||||
|
</script>
|
|
@ -14,21 +14,23 @@ const virtualListStore = new VirtualListStore()
|
||||||
virtualListStore.computeForRealm('items', null)
|
virtualListStore.computeForRealm('items', null)
|
||||||
virtualListStore.computeForRealm('showFooter', false)
|
virtualListStore.computeForRealm('showFooter', false)
|
||||||
virtualListStore.computeForRealm('footerHeight', 0)
|
virtualListStore.computeForRealm('footerHeight', 0)
|
||||||
|
virtualListStore.computeForRealm('showHeader', false)
|
||||||
|
virtualListStore.computeForRealm('headerHeight', 0)
|
||||||
virtualListStore.computeForRealm('scrollTop', 0)
|
virtualListStore.computeForRealm('scrollTop', 0)
|
||||||
virtualListStore.computeForRealm('scrollHeight', 0)
|
virtualListStore.computeForRealm('scrollHeight', 0)
|
||||||
virtualListStore.computeForRealm('offsetHeight', 0)
|
virtualListStore.computeForRealm('offsetHeight', 0)
|
||||||
virtualListStore.computeForRealm('itemHeights', {})
|
virtualListStore.computeForRealm('itemHeights', {})
|
||||||
|
|
||||||
virtualListStore.compute('visibleItems',
|
virtualListStore.compute('visibleItems',
|
||||||
['items', 'scrollTop', 'itemHeights', 'offsetHeight'],
|
['items', 'scrollTop', 'itemHeights', 'offsetHeight', 'showHeader', 'headerHeight'],
|
||||||
(items, scrollTop, itemHeights, offsetHeight) => {
|
(items, scrollTop, itemHeights, offsetHeight, showHeader, headerHeight) => {
|
||||||
mark('compute visibleItems')
|
mark('compute visibleItems')
|
||||||
if (!items) {
|
if (!items) {
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
let renderBuffer = VIEWPORT_RENDER_FACTOR * offsetHeight
|
let renderBuffer = VIEWPORT_RENDER_FACTOR * offsetHeight
|
||||||
let visibleItems = []
|
let visibleItems = []
|
||||||
let totalOffset = 0
|
let totalOffset = showHeader ? headerHeight : 0
|
||||||
let len = items.length
|
let len = items.length
|
||||||
let i = -1
|
let i = -1
|
||||||
while (++i < len) {
|
while (++i < len) {
|
||||||
|
@ -57,12 +59,12 @@ virtualListStore.compute('visibleItems',
|
||||||
})
|
})
|
||||||
|
|
||||||
virtualListStore.compute('heightWithoutFooter',
|
virtualListStore.compute('heightWithoutFooter',
|
||||||
['items', 'itemHeights'],
|
['items', 'itemHeights', 'showHeader', 'headerHeight'],
|
||||||
(items, itemHeights) => {
|
(items, itemHeights, showHeader, headerHeight) => {
|
||||||
if (!items) {
|
if (!items) {
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
let sum = 0
|
let sum = showHeader ? headerHeight : 0
|
||||||
let i = -1
|
let i = -1
|
||||||
let len = items.length
|
let len = items.length
|
||||||
while (++i < len) {
|
while (++i < len) {
|
||||||
|
|
|
@ -15,6 +15,8 @@ export function timelineComputations (store) {
|
||||||
computeForTimeline(store, 'lastFocusedElementSelector')
|
computeForTimeline(store, 'lastFocusedElementSelector')
|
||||||
computeForTimeline(store, 'ignoreBlurEvents')
|
computeForTimeline(store, 'ignoreBlurEvents')
|
||||||
computeForTimeline(store, 'itemIdsToAdd')
|
computeForTimeline(store, 'itemIdsToAdd')
|
||||||
|
computeForTimeline(store, 'showHeader')
|
||||||
|
computeForTimeline(store, 'shouldShowHeader')
|
||||||
|
|
||||||
store.compute('firstTimelineItemId', ['timelineItemIds'], (timelineItemIds) => timelineItemIds && timelineItemIds.length && timelineItemIds[0])
|
store.compute('firstTimelineItemId', ['timelineItemIds'], (timelineItemIds) => timelineItemIds && timelineItemIds.length && timelineItemIds[0])
|
||||||
store.compute('lastTimelineItemId', ['timelineItemIds'], (timelineItemIds) => timelineItemIds && timelineItemIds.length && timelineItemIds[timelineItemIds.length - 1])
|
store.compute('lastTimelineItemId', ['timelineItemIds'], (timelineItemIds) => timelineItemIds && timelineItemIds.length && timelineItemIds[timelineItemIds.length - 1])
|
||||||
|
|
Loading…
Reference in New Issue