fix: poll for updates to timeago displays (#1232)
* fix: poll for updates to timeago displays * code cleanup * avoid some recomputes * avoid costly recomputes
This commit is contained in:
parent
bf640b9b0f
commit
dac4b493c8
|
@ -13,11 +13,11 @@
|
|||
<StatusAuthorName {...params} />
|
||||
<StatusAuthorHandle {...params} />
|
||||
{#if !isStatusInOwnThread}
|
||||
<StatusRelativeDate {...params} />
|
||||
<StatusRelativeDate {...params} {...timestampParams} />
|
||||
{/if}
|
||||
<StatusSidebar {...params} />
|
||||
{#if spoilerText}
|
||||
<StatusSpoiler {...params} on:recalculateHeight />
|
||||
<StatusSpoiler {...params} {spoilerShown} on:recalculateHeight />
|
||||
{/if}
|
||||
{#if !showContent}
|
||||
<StatusMentions {...params} />
|
||||
|
@ -35,9 +35,9 @@
|
|||
<StatusPoll {...params} />
|
||||
{/if}
|
||||
{#if isStatusInOwnThread}
|
||||
<StatusDetails {...params} />
|
||||
<StatusDetails {...params} {...timestampParams} />
|
||||
{/if}
|
||||
<StatusToolbar {...params} on:recalculateHeight />
|
||||
<StatusToolbar {...params} {replyShown} on:recalculateHeight />
|
||||
{#if replyShown}
|
||||
<StatusComposeBox {...params} on:recalculateHeight />
|
||||
{/if}
|
||||
|
@ -277,13 +277,15 @@
|
|||
originalStatus.media_attachments.length
|
||||
),
|
||||
originalAccountEmojis: ({ originalAccount }) => (originalAccount.emojis || []),
|
||||
originalStatusEmojis: ({ originalStatus }) => (originalStatus.emojis || []),
|
||||
originalAccountDisplayName: ({ originalAccount }) => (originalAccount.display_name || originalAccount.username),
|
||||
originalAccountAccessibleName: ({ originalAccount, $omitEmojiInDisplayNames }) => {
|
||||
return getAccountAccessibleName(originalAccount, $omitEmojiInDisplayNames)
|
||||
},
|
||||
createdAtDate: ({ originalStatus }) => originalStatus.created_at,
|
||||
absoluteFormattedDate: ({ createdAtDate }) => absoluteDateFormatter.format(new Date(createdAtDate)),
|
||||
timeagoFormattedDate: ({ createdAtDate }) => formatTimeagoDate(createdAtDate),
|
||||
createdAtDateTS: ({ createdAtDate }) => new Date(createdAtDate).getTime(),
|
||||
absoluteFormattedDate: ({ createdAtDateTS }) => absoluteDateFormatter.format(createdAtDateTS),
|
||||
timeagoFormattedDate: ({ createdAtDateTS, $now }) => formatTimeagoDate(createdAtDateTS, $now),
|
||||
reblog: ({ status }) => status.reblog,
|
||||
ariaLabel: ({ originalAccount, account, plainTextContent, timeagoFormattedDate, spoilerText,
|
||||
showContent, reblog, notification, visibility, $omitEmojiInDisplayNames, $disableLongAriaLabels }) => (
|
||||
|
@ -307,11 +309,22 @@
|
|||
)),
|
||||
content: ({ originalStatus }) => originalStatus.content || '',
|
||||
showContent: ({ spoilerText, spoilerShown }) => !spoilerText || spoilerShown,
|
||||
// These timestamp params may change every 10 seconds due to now() polling, so keep them
|
||||
// separate from the generic `params` list to avoid costly recomputes.
|
||||
timestampParams: ({ createdAtDate, createdAtDateTS, timeagoFormattedDate, absoluteFormattedDate }) => ({
|
||||
createdAtDate,
|
||||
createdAtDateTS,
|
||||
timeagoFormattedDate,
|
||||
absoluteFormattedDate
|
||||
}),
|
||||
// This params list deliberately does *not* include `spoilersShown` or `replyShown`, because these
|
||||
// change frequently and would therefore cause costly recomputes if included here.
|
||||
// The main goal here is to avoid typing by passing as many params as possible to child components.
|
||||
params: ({ notification, notificationId, status, statusId, timelineType,
|
||||
account, accountId, uuid, isStatusInNotification, isStatusInOwnThread,
|
||||
originalAccount, originalAccountId, spoilerShown, visibility, replyShown,
|
||||
originalAccount, originalAccountId, visibility,
|
||||
replyVisibility, spoilerText, originalStatus, originalStatusId, inReplyToId,
|
||||
createdAtDate, timeagoFormattedDate, enableShortcuts, absoluteFormattedDate, shortcutScope }) => ({
|
||||
enableShortcuts, shortcutScope, originalStatusEmojis }) => ({
|
||||
notification,
|
||||
notificationId,
|
||||
status,
|
||||
|
@ -324,19 +337,15 @@
|
|||
isStatusInOwnThread,
|
||||
originalAccount,
|
||||
originalAccountId,
|
||||
spoilerShown,
|
||||
visibility,
|
||||
replyShown,
|
||||
replyVisibility,
|
||||
spoilerText,
|
||||
originalStatus,
|
||||
originalStatusId,
|
||||
inReplyToId,
|
||||
createdAtDate,
|
||||
timeagoFormattedDate,
|
||||
enableShortcuts,
|
||||
absoluteFormattedDate,
|
||||
shortcutScope
|
||||
shortcutScope,
|
||||
originalStatusEmojis
|
||||
})
|
||||
},
|
||||
events: {
|
||||
|
|
|
@ -76,8 +76,9 @@
|
|||
)
|
||||
},
|
||||
content: ({ originalStatus }) => (originalStatus.content || ''),
|
||||
emojis: ({ originalStatus }) => originalStatus.emojis,
|
||||
massagedContent: ({ content, emojis, $autoplayGifs }) => massageUserText(content, emojis, $autoplayGifs)
|
||||
massagedContent: ({ content, originalStatusEmojis, $autoplayGifs }) => (
|
||||
massageUserText(content, originalStatusEmojis, $autoplayGifs)
|
||||
)
|
||||
},
|
||||
methods: {
|
||||
hydrateContent () {
|
||||
|
|
|
@ -158,7 +158,6 @@
|
|||
application: ({ originalStatus }) => originalStatus.application,
|
||||
applicationName: ({ application }) => (application && application.name),
|
||||
applicationWebsite: ({ application }) => (application && application.website),
|
||||
createdAtDate: ({ originalStatus }) => originalStatus.created_at,
|
||||
numReblogs: ({ overrideNumReblogs, originalStatus }) => {
|
||||
if (typeof overrideNumReblogs === 'number') {
|
||||
return overrideNumReblogs
|
||||
|
@ -171,8 +170,8 @@
|
|||
}
|
||||
return originalStatus.favourites_count || 0
|
||||
},
|
||||
displayAbsoluteFormattedDate: ({ createdAtDate, $isMobileSize }) => (
|
||||
$isMobileSize ? shortAbsoluteDateFormatter : absoluteDateFormatter).format(new Date(createdAtDate)
|
||||
displayAbsoluteFormattedDate: ({ createdAtDateTS, $isMobileSize }) => (
|
||||
($isMobileSize ? shortAbsoluteDateFormatter : absoluteDateFormatter).format(createdAtDateTS)
|
||||
),
|
||||
reblogsLabel: ({ numReblogs }) => {
|
||||
// TODO: intl
|
||||
|
|
|
@ -64,10 +64,9 @@
|
|||
Shortcut
|
||||
},
|
||||
computed: {
|
||||
emojis: ({ originalStatus }) => originalStatus.emojis,
|
||||
massagedSpoilerText: ({ spoilerText, emojis, $autoplayGifs }) => {
|
||||
massagedSpoilerText: ({ spoilerText, originalStatusEmojis, $autoplayGifs }) => {
|
||||
spoilerText = escapeHtml(spoilerText)
|
||||
return emojifyText(spoilerText, emojis, $autoplayGifs)
|
||||
return emojifyText(spoilerText, originalStatusEmojis, $autoplayGifs)
|
||||
},
|
||||
elementId: ({ uuid }) => `spoiler-${uuid}`
|
||||
},
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
import { format } from '../_thirdparty/timeago/timeago'
|
||||
import { mark, stop } from '../_utils/marks'
|
||||
|
||||
export function formatTimeagoDate (date) {
|
||||
export function formatTimeagoDate (date, now) {
|
||||
mark('formatTimeagoDate')
|
||||
let res = format(date)
|
||||
// use Math.max() to avoid things like "in 10 seconds" when the timestamps are slightly off
|
||||
let res = format(date, Math.max(now, date))
|
||||
stop('formatTimeagoDate')
|
||||
return res
|
||||
}
|
||||
|
|
|
@ -0,0 +1,47 @@
|
|||
// For convenience, periodically re-compute the current time. This ensures freshness of
|
||||
// displays like "x minutes ago" without having to jump through a lot of hoops.
|
||||
import { scheduleIdleTask } from '../../_utils/scheduleIdleTask'
|
||||
import lifecycle from 'page-lifecycle/dist/lifecycle.mjs'
|
||||
|
||||
const POLL_INTERVAL = 10000
|
||||
|
||||
export function nowObservers (store) {
|
||||
let interval
|
||||
|
||||
function updateNow () {
|
||||
store.set({ now: Date.now() })
|
||||
}
|
||||
|
||||
function startPolling () {
|
||||
interval = setInterval(() => scheduleIdleTask(updateNow), POLL_INTERVAL)
|
||||
}
|
||||
|
||||
function stopPolling () {
|
||||
if (interval) {
|
||||
clearInterval(interval)
|
||||
interval = null
|
||||
}
|
||||
}
|
||||
|
||||
function restartPolling () {
|
||||
stopPolling()
|
||||
scheduleIdleTask(updateNow)
|
||||
startPolling()
|
||||
}
|
||||
|
||||
updateNow()
|
||||
|
||||
if (process.browser) {
|
||||
startPolling()
|
||||
|
||||
lifecycle.addEventListener('statechange', e => {
|
||||
if (e.newState === 'passive') {
|
||||
console.log('stopping Date.now() observer...')
|
||||
stopPolling()
|
||||
} else if (e.newState === 'active') {
|
||||
console.log('restarting Date.now() observer...')
|
||||
restartPolling()
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
|
@ -1,4 +1,5 @@
|
|||
import { onlineObservers } from './onlineObservers'
|
||||
import { nowObservers } from './nowObservers'
|
||||
import { navObservers } from './navObservers'
|
||||
import { pageVisibilityObservers } from './pageVisibilityObservers'
|
||||
import { resizeObservers } from './resizeObservers'
|
||||
|
@ -8,6 +9,7 @@ import { touchObservers } from './touchObservers'
|
|||
|
||||
export function observers (store) {
|
||||
onlineObservers(store)
|
||||
nowObservers(store)
|
||||
navObservers(store)
|
||||
pageVisibilityObservers(store)
|
||||
resizeObservers(store)
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
* Contract: i@hust.cc
|
||||
*/
|
||||
|
||||
var IndexMapEn = 'second_minute_hour_day_week_month_year'.split('_')
|
||||
var IndexMapEn = ['second', 'minute', 'hour', 'day', 'week', 'month', 'year']
|
||||
var SEC_ARRAY = [60, 60, 24, 7, 365 / 7 / 12, 12]
|
||||
|
||||
/**
|
||||
|
@ -63,16 +63,14 @@ function formatDiff (diff) {
|
|||
* @param nowDate
|
||||
* @returns {number}
|
||||
*/
|
||||
function diffSec (date) {
|
||||
var nowDate = new Date()
|
||||
var otherDate = new Date(date)
|
||||
return (nowDate - otherDate) / 1000
|
||||
function diffSec (date, now) {
|
||||
return (now - date) / 1000
|
||||
}
|
||||
|
||||
/**
|
||||
* Created by hustcc on 18/5/20.
|
||||
* Contract: i@hust.cc
|
||||
*/
|
||||
export function format (date) {
|
||||
return formatDiff(diffSec(date))
|
||||
export function format (date, now) {
|
||||
return formatDiff(diffSec(date, now))
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue