2020-06-13 00:38:05 +01:00
|
|
|
import { Map as ImmutableMap, List as ImmutableList, toJS } from 'immutable';
|
2019-07-02 08:10:25 +01:00
|
|
|
import { importFetchedStatus, importFetchedStatuses } from './importer';
|
|
|
|
import api, { getLinks } from '../api';
|
2020-06-13 00:38:05 +01:00
|
|
|
import { fetchRelationships } from './accounts'
|
2019-07-02 08:10:25 +01:00
|
|
|
|
2020-03-04 22:26:01 +00:00
|
|
|
export const TIMELINE_UPDATE = 'TIMELINE_UPDATE';
|
|
|
|
export const TIMELINE_DELETE = 'TIMELINE_DELETE';
|
|
|
|
export const TIMELINE_CLEAR = 'TIMELINE_CLEAR';
|
Added redux functionality for queueing/dequeueing timelines
using streaming.js, when a status comes in to the current page, it queues up using updateTimelineQueue action, it then goes to the reducer to add "queuedItems" to state (up to max:40) and to tally up all count in that timeilne state "totalQueuedItemsCount".
the dequeueTimeline action takes in a "timelineId", "expandFunc", and "optionalExpandArgs". when clicking on the "click to load more" it passes in the timelineId (e.g. "home", "community", etc.) and the "handleLoadMore" function from the timeline component. if within the range of the max: 40, it pushes them to the dom, if over the max: 40 it clears the timeline and refreshes the page/timeline to show the most recent 20 statuses. Then, it resets the "queuedItems" and "totalQueuedItemsCount" in timeline state.
if no expandFunc is added, and timeline is "home" or "community" it expands those timelines with "optionalExpandArgs". Otherwise, it queues up to any other timeline (e.g. "hashtags", etc.)
2019-07-11 17:09:41 +01:00
|
|
|
export const TIMELINE_UPDATE_QUEUE = 'TIMELINE_UPDATE_QUEUE';
|
|
|
|
export const TIMELINE_DEQUEUE = 'TIMELINE_DEQUEUE';
|
2019-07-17 23:59:50 +01:00
|
|
|
export const TIMELINE_SCROLL_TOP = 'TIMELINE_SCROLL_TOP';
|
2019-07-02 08:10:25 +01:00
|
|
|
|
|
|
|
export const TIMELINE_EXPAND_REQUEST = 'TIMELINE_EXPAND_REQUEST';
|
|
|
|
export const TIMELINE_EXPAND_SUCCESS = 'TIMELINE_EXPAND_SUCCESS';
|
2020-03-04 22:26:01 +00:00
|
|
|
export const TIMELINE_EXPAND_FAIL = 'TIMELINE_EXPAND_FAIL';
|
2019-07-02 08:10:25 +01:00
|
|
|
|
2020-03-04 22:26:01 +00:00
|
|
|
export const TIMELINE_CONNECT = 'TIMELINE_CONNECT';
|
2019-07-02 08:10:25 +01:00
|
|
|
export const TIMELINE_DISCONNECT = 'TIMELINE_DISCONNECT';
|
|
|
|
|
Added redux functionality for queueing/dequeueing timelines
using streaming.js, when a status comes in to the current page, it queues up using updateTimelineQueue action, it then goes to the reducer to add "queuedItems" to state (up to max:40) and to tally up all count in that timeilne state "totalQueuedItemsCount".
the dequeueTimeline action takes in a "timelineId", "expandFunc", and "optionalExpandArgs". when clicking on the "click to load more" it passes in the timelineId (e.g. "home", "community", etc.) and the "handleLoadMore" function from the timeline component. if within the range of the max: 40, it pushes them to the dom, if over the max: 40 it clears the timeline and refreshes the page/timeline to show the most recent 20 statuses. Then, it resets the "queuedItems" and "totalQueuedItemsCount" in timeline state.
if no expandFunc is added, and timeline is "home" or "community" it expands those timelines with "optionalExpandArgs". Otherwise, it queues up to any other timeline (e.g. "hashtags", etc.)
2019-07-11 17:09:41 +01:00
|
|
|
export const MAX_QUEUED_ITEMS = 40;
|
|
|
|
|
2020-06-13 00:38:05 +01:00
|
|
|
const fetchStatusesAccountsRelationships = (dispatch, statuses) => {
|
|
|
|
const accountIds = statuses.map(item => item.account.id)
|
|
|
|
if (accountIds.length > 0) {
|
|
|
|
dispatch(fetchRelationships(accountIds));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-07-02 08:10:25 +01:00
|
|
|
export function updateTimeline(timeline, status, accept) {
|
|
|
|
return dispatch => {
|
|
|
|
if (typeof accept === 'function' && !accept(status)) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
dispatch(importFetchedStatus(status));
|
|
|
|
|
|
|
|
dispatch({
|
|
|
|
type: TIMELINE_UPDATE,
|
|
|
|
timeline,
|
|
|
|
status,
|
|
|
|
});
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
Added redux functionality for queueing/dequeueing timelines
using streaming.js, when a status comes in to the current page, it queues up using updateTimelineQueue action, it then goes to the reducer to add "queuedItems" to state (up to max:40) and to tally up all count in that timeilne state "totalQueuedItemsCount".
the dequeueTimeline action takes in a "timelineId", "expandFunc", and "optionalExpandArgs". when clicking on the "click to load more" it passes in the timelineId (e.g. "home", "community", etc.) and the "handleLoadMore" function from the timeline component. if within the range of the max: 40, it pushes them to the dom, if over the max: 40 it clears the timeline and refreshes the page/timeline to show the most recent 20 statuses. Then, it resets the "queuedItems" and "totalQueuedItemsCount" in timeline state.
if no expandFunc is added, and timeline is "home" or "community" it expands those timelines with "optionalExpandArgs". Otherwise, it queues up to any other timeline (e.g. "hashtags", etc.)
2019-07-11 17:09:41 +01:00
|
|
|
export function updateTimelineQueue(timeline, status, accept) {
|
|
|
|
return dispatch => {
|
|
|
|
if (typeof accept === 'function' && !accept(status)) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
dispatch({
|
|
|
|
type: TIMELINE_UPDATE_QUEUE,
|
|
|
|
timeline,
|
|
|
|
status,
|
|
|
|
});
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2020-06-10 22:44:38 +01:00
|
|
|
export function forceDequeueTimeline(timeline) {
|
|
|
|
return (dispatch) => {
|
|
|
|
dispatch({
|
|
|
|
type: TIMELINE_DEQUEUE,
|
|
|
|
timeline,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
Added redux functionality for queueing/dequeueing timelines
using streaming.js, when a status comes in to the current page, it queues up using updateTimelineQueue action, it then goes to the reducer to add "queuedItems" to state (up to max:40) and to tally up all count in that timeilne state "totalQueuedItemsCount".
the dequeueTimeline action takes in a "timelineId", "expandFunc", and "optionalExpandArgs". when clicking on the "click to load more" it passes in the timelineId (e.g. "home", "community", etc.) and the "handleLoadMore" function from the timeline component. if within the range of the max: 40, it pushes them to the dom, if over the max: 40 it clears the timeline and refreshes the page/timeline to show the most recent 20 statuses. Then, it resets the "queuedItems" and "totalQueuedItemsCount" in timeline state.
if no expandFunc is added, and timeline is "home" or "community" it expands those timelines with "optionalExpandArgs". Otherwise, it queues up to any other timeline (e.g. "hashtags", etc.)
2019-07-11 17:09:41 +01:00
|
|
|
export function dequeueTimeline(timeline, expandFunc, optionalExpandArgs) {
|
|
|
|
return (dispatch, getState) => {
|
|
|
|
const queuedItems = getState().getIn(['timelines', timeline, 'queuedItems'], ImmutableList());
|
|
|
|
const totalQueuedItemsCount = getState().getIn(['timelines', timeline, 'totalQueuedItemsCount'], 0);
|
|
|
|
|
|
|
|
let shouldDispatchDequeue = true;
|
|
|
|
|
2020-04-08 02:06:59 +01:00
|
|
|
if (totalQueuedItemsCount === 0) {
|
Added redux functionality for queueing/dequeueing timelines
using streaming.js, when a status comes in to the current page, it queues up using updateTimelineQueue action, it then goes to the reducer to add "queuedItems" to state (up to max:40) and to tally up all count in that timeilne state "totalQueuedItemsCount".
the dequeueTimeline action takes in a "timelineId", "expandFunc", and "optionalExpandArgs". when clicking on the "click to load more" it passes in the timelineId (e.g. "home", "community", etc.) and the "handleLoadMore" function from the timeline component. if within the range of the max: 40, it pushes them to the dom, if over the max: 40 it clears the timeline and refreshes the page/timeline to show the most recent 20 statuses. Then, it resets the "queuedItems" and "totalQueuedItemsCount" in timeline state.
if no expandFunc is added, and timeline is "home" or "community" it expands those timelines with "optionalExpandArgs". Otherwise, it queues up to any other timeline (e.g. "hashtags", etc.)
2019-07-11 17:09:41 +01:00
|
|
|
return;
|
2020-04-08 02:06:59 +01:00
|
|
|
} else if (totalQueuedItemsCount > 0 && totalQueuedItemsCount <= MAX_QUEUED_ITEMS) {
|
Added redux functionality for queueing/dequeueing timelines
using streaming.js, when a status comes in to the current page, it queues up using updateTimelineQueue action, it then goes to the reducer to add "queuedItems" to state (up to max:40) and to tally up all count in that timeilne state "totalQueuedItemsCount".
the dequeueTimeline action takes in a "timelineId", "expandFunc", and "optionalExpandArgs". when clicking on the "click to load more" it passes in the timelineId (e.g. "home", "community", etc.) and the "handleLoadMore" function from the timeline component. if within the range of the max: 40, it pushes them to the dom, if over the max: 40 it clears the timeline and refreshes the page/timeline to show the most recent 20 statuses. Then, it resets the "queuedItems" and "totalQueuedItemsCount" in timeline state.
if no expandFunc is added, and timeline is "home" or "community" it expands those timelines with "optionalExpandArgs". Otherwise, it queues up to any other timeline (e.g. "hashtags", etc.)
2019-07-11 17:09:41 +01:00
|
|
|
queuedItems.forEach(status => {
|
|
|
|
dispatch(updateTimeline(timeline, status.toJS(), null));
|
|
|
|
});
|
2020-04-08 02:06:59 +01:00
|
|
|
} else {
|
Added redux functionality for queueing/dequeueing timelines
using streaming.js, when a status comes in to the current page, it queues up using updateTimelineQueue action, it then goes to the reducer to add "queuedItems" to state (up to max:40) and to tally up all count in that timeilne state "totalQueuedItemsCount".
the dequeueTimeline action takes in a "timelineId", "expandFunc", and "optionalExpandArgs". when clicking on the "click to load more" it passes in the timelineId (e.g. "home", "community", etc.) and the "handleLoadMore" function from the timeline component. if within the range of the max: 40, it pushes them to the dom, if over the max: 40 it clears the timeline and refreshes the page/timeline to show the most recent 20 statuses. Then, it resets the "queuedItems" and "totalQueuedItemsCount" in timeline state.
if no expandFunc is added, and timeline is "home" or "community" it expands those timelines with "optionalExpandArgs". Otherwise, it queues up to any other timeline (e.g. "hashtags", etc.)
2019-07-11 17:09:41 +01:00
|
|
|
if (typeof expandFunc === 'function') {
|
|
|
|
dispatch(clearTimeline(timeline));
|
|
|
|
expandFunc();
|
2020-04-08 02:06:59 +01:00
|
|
|
} else {
|
Added redux functionality for queueing/dequeueing timelines
using streaming.js, when a status comes in to the current page, it queues up using updateTimelineQueue action, it then goes to the reducer to add "queuedItems" to state (up to max:40) and to tally up all count in that timeilne state "totalQueuedItemsCount".
the dequeueTimeline action takes in a "timelineId", "expandFunc", and "optionalExpandArgs". when clicking on the "click to load more" it passes in the timelineId (e.g. "home", "community", etc.) and the "handleLoadMore" function from the timeline component. if within the range of the max: 40, it pushes them to the dom, if over the max: 40 it clears the timeline and refreshes the page/timeline to show the most recent 20 statuses. Then, it resets the "queuedItems" and "totalQueuedItemsCount" in timeline state.
if no expandFunc is added, and timeline is "home" or "community" it expands those timelines with "optionalExpandArgs". Otherwise, it queues up to any other timeline (e.g. "hashtags", etc.)
2019-07-11 17:09:41 +01:00
|
|
|
if (timeline === 'home') {
|
|
|
|
dispatch(clearTimeline(timeline));
|
|
|
|
dispatch(expandHomeTimeline(optionalExpandArgs));
|
2020-04-08 02:06:59 +01:00
|
|
|
} else if (timeline === 'community') {
|
Added redux functionality for queueing/dequeueing timelines
using streaming.js, when a status comes in to the current page, it queues up using updateTimelineQueue action, it then goes to the reducer to add "queuedItems" to state (up to max:40) and to tally up all count in that timeilne state "totalQueuedItemsCount".
the dequeueTimeline action takes in a "timelineId", "expandFunc", and "optionalExpandArgs". when clicking on the "click to load more" it passes in the timelineId (e.g. "home", "community", etc.) and the "handleLoadMore" function from the timeline component. if within the range of the max: 40, it pushes them to the dom, if over the max: 40 it clears the timeline and refreshes the page/timeline to show the most recent 20 statuses. Then, it resets the "queuedItems" and "totalQueuedItemsCount" in timeline state.
if no expandFunc is added, and timeline is "home" or "community" it expands those timelines with "optionalExpandArgs". Otherwise, it queues up to any other timeline (e.g. "hashtags", etc.)
2019-07-11 17:09:41 +01:00
|
|
|
dispatch(clearTimeline(timeline));
|
|
|
|
dispatch(expandCommunityTimeline(optionalExpandArgs));
|
2020-04-08 02:06:59 +01:00
|
|
|
} else {
|
Added redux functionality for queueing/dequeueing timelines
using streaming.js, when a status comes in to the current page, it queues up using updateTimelineQueue action, it then goes to the reducer to add "queuedItems" to state (up to max:40) and to tally up all count in that timeilne state "totalQueuedItemsCount".
the dequeueTimeline action takes in a "timelineId", "expandFunc", and "optionalExpandArgs". when clicking on the "click to load more" it passes in the timelineId (e.g. "home", "community", etc.) and the "handleLoadMore" function from the timeline component. if within the range of the max: 40, it pushes them to the dom, if over the max: 40 it clears the timeline and refreshes the page/timeline to show the most recent 20 statuses. Then, it resets the "queuedItems" and "totalQueuedItemsCount" in timeline state.
if no expandFunc is added, and timeline is "home" or "community" it expands those timelines with "optionalExpandArgs". Otherwise, it queues up to any other timeline (e.g. "hashtags", etc.)
2019-07-11 17:09:41 +01:00
|
|
|
shouldDispatchDequeue = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!shouldDispatchDequeue) return;
|
|
|
|
|
|
|
|
dispatch({
|
|
|
|
type: TIMELINE_DEQUEUE,
|
|
|
|
timeline,
|
|
|
|
});
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2019-07-02 08:10:25 +01:00
|
|
|
export function deleteFromTimelines(id) {
|
|
|
|
return (dispatch, getState) => {
|
2020-03-04 22:26:01 +00:00
|
|
|
const accountId = getState().getIn(['statuses', id, 'account']);
|
2019-07-02 08:10:25 +01:00
|
|
|
const references = getState().get('statuses').filter(status => status.get('reblog') === id).map(status => [status.get('id'), status.get('account')]);
|
2020-03-04 22:26:01 +00:00
|
|
|
const reblogOf = getState().getIn(['statuses', id, 'reblog'], null);
|
2019-07-02 08:10:25 +01:00
|
|
|
|
|
|
|
dispatch({
|
|
|
|
type: TIMELINE_DELETE,
|
|
|
|
id,
|
|
|
|
accountId,
|
|
|
|
references,
|
|
|
|
reblogOf,
|
|
|
|
});
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
export function clearTimeline(timeline) {
|
|
|
|
return (dispatch) => {
|
|
|
|
dispatch({ type: TIMELINE_CLEAR, timeline });
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
2020-03-04 22:26:01 +00:00
|
|
|
const noOp = () => { };
|
2019-07-02 08:10:25 +01:00
|
|
|
|
|
|
|
const parseTags = (tags = {}, mode) => {
|
|
|
|
return (tags[mode] || []).map((tag) => {
|
|
|
|
return tag.value;
|
|
|
|
});
|
|
|
|
};
|
|
|
|
|
|
|
|
export function expandTimeline(timelineId, path, params = {}, done = noOp) {
|
|
|
|
return (dispatch, getState) => {
|
|
|
|
const timeline = getState().getIn(['timelines', timelineId], ImmutableMap());
|
|
|
|
const isLoadingMore = !!params.max_id;
|
|
|
|
|
|
|
|
if (timeline.get('isLoading')) {
|
|
|
|
done();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!params.max_id && !params.pinned && timeline.get('items', ImmutableList()).size > 0) {
|
|
|
|
params.since_id = timeline.getIn(['items', 0]);
|
|
|
|
}
|
|
|
|
|
|
|
|
const isLoadingRecent = !!params.since_id;
|
|
|
|
|
|
|
|
dispatch(expandTimelineRequest(timelineId, isLoadingMore));
|
|
|
|
|
|
|
|
api(getState).get(path, { params }).then(response => {
|
|
|
|
const next = getLinks(response).refs.find(link => link.rel === 'next');
|
|
|
|
dispatch(importFetchedStatuses(response.data));
|
|
|
|
dispatch(expandTimelineSuccess(timelineId, response.data, next ? next.uri : null, response.code === 206, isLoadingRecent, isLoadingMore));
|
2020-06-13 00:38:05 +01:00
|
|
|
fetchStatusesAccountsRelationships(dispatch, response.data)
|
2019-07-02 08:10:25 +01:00
|
|
|
done();
|
|
|
|
}).catch(error => {
|
|
|
|
dispatch(expandTimelineFail(timelineId, error, isLoadingMore));
|
|
|
|
done();
|
|
|
|
});
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
2020-03-04 22:26:01 +00:00
|
|
|
export const expandHomeTimeline = ({ maxId } = {}, done = noOp) => expandTimeline('home', '/api/v1/timelines/home', { max_id: maxId }, done);
|
2020-09-15 02:20:27 +01:00
|
|
|
export const expandExploreTimeline = ({ maxId, sortBy } = {}, done = noOp) => expandTimeline('explore', '/api/v1/timelines/explore', { max_id: maxId, sort_by: sortBy }, done);
|
2020-07-02 02:40:00 +01:00
|
|
|
export const expandProTimeline = ({ maxId } = {}, done = noOp) => expandTimeline('pro', '/api/v1/timelines/pro', { max_id: maxId }, done);
|
2020-06-06 21:25:07 +01:00
|
|
|
export const expandCommunityTimeline = ({ maxId, onlyMedia } = {}, done = noOp) => expandTimeline(`community${onlyMedia ? ':media' : ''}`, '/api/v1/timelines/public', { max_id: maxId, only_media: !!onlyMedia }, done);
|
2020-04-17 06:35:46 +01:00
|
|
|
export const expandAccountTimeline = (accountId, { maxId, withReplies, commentsOnly } = {}) => expandTimeline(`account:${accountId}${withReplies ? ':with_replies' : ''}${commentsOnly ? ':comments_only' : ''}`, `/api/v1/accounts/${accountId}/statuses`, { only_comments: commentsOnly, exclude_replies: (!withReplies && !commentsOnly), max_id: maxId });
|
2019-07-02 08:10:25 +01:00
|
|
|
export const expandAccountFeaturedTimeline = accountId => expandTimeline(`account:${accountId}:pinned`, `/api/v1/accounts/${accountId}/statuses`, { pinned: true });
|
2020-06-09 00:38:36 +01:00
|
|
|
export const expandAccountMediaTimeline = (accountId, { maxId, limit, mediaType } = {}) => expandTimeline(`account:${accountId}:media`, `/api/v1/accounts/${accountId}/statuses`, { max_id: maxId, only_media: true, limit: limit || 20, media_type: mediaType });
|
2020-03-04 22:26:01 +00:00
|
|
|
export const expandListTimeline = (id, { maxId } = {}, done = noOp) => expandTimeline(`list:${id}`, `/api/v1/timelines/list/${id}`, { max_id: maxId }, done);
|
2020-08-07 23:59:39 +01:00
|
|
|
export const expandGroupTimeline = (id, { sortBy, maxId, onlyMedia } = {}, done = noOp) => expandTimeline(`group:${id}`, `/api/v1/timelines/group/${id}`, { sort_by: sortBy, max_id: maxId, only_media: onlyMedia }, done);
|
2020-09-10 21:07:01 +01:00
|
|
|
export const expandGroupFeaturedTimeline = (groupId, done = noOp) => expandTimeline(`group:${groupId}:pinned`, `/api/v1/timelines/group_pins/${groupId}`, {}, done);
|
2020-08-07 23:59:39 +01:00
|
|
|
export const expandGroupCollectionTimeline = (collectionType, { sortBy, maxId } = {}, done = noOp) => expandTimeline(`group_collection:${collectionType}`, `/api/v1/timelines/group_collection/${collectionType}`, { sort_by: sortBy, max_id: maxId }, done);
|
2020-03-04 22:26:01 +00:00
|
|
|
export const expandHashtagTimeline = (hashtag, { maxId, tags } = {}, done = noOp) => {
|
2019-07-02 08:10:25 +01:00
|
|
|
return expandTimeline(`hashtag:${hashtag}`, `/api/v1/timelines/tag/${hashtag}`, {
|
|
|
|
max_id: maxId,
|
2020-03-04 22:26:01 +00:00
|
|
|
any: parseTags(tags, 'any'),
|
|
|
|
all: parseTags(tags, 'all'),
|
|
|
|
none: parseTags(tags, 'none'),
|
2019-07-02 08:10:25 +01:00
|
|
|
}, done);
|
|
|
|
};
|
|
|
|
|
|
|
|
export function expandTimelineRequest(timeline, isLoadingMore) {
|
|
|
|
return {
|
|
|
|
type: TIMELINE_EXPAND_REQUEST,
|
|
|
|
timeline,
|
|
|
|
skipLoading: !isLoadingMore,
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
export function expandTimelineSuccess(timeline, statuses, next, partial, isLoadingRecent, isLoadingMore) {
|
|
|
|
return {
|
|
|
|
type: TIMELINE_EXPAND_SUCCESS,
|
|
|
|
timeline,
|
|
|
|
statuses,
|
|
|
|
next,
|
|
|
|
partial,
|
|
|
|
isLoadingRecent,
|
|
|
|
skipLoading: !isLoadingMore,
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
export function expandTimelineFail(timeline, error, isLoadingMore) {
|
|
|
|
return {
|
|
|
|
type: TIMELINE_EXPAND_FAIL,
|
|
|
|
timeline,
|
|
|
|
error,
|
|
|
|
skipLoading: !isLoadingMore,
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
export function connectTimeline(timeline) {
|
|
|
|
return {
|
|
|
|
type: TIMELINE_CONNECT,
|
|
|
|
timeline,
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
export function disconnectTimeline(timeline) {
|
|
|
|
return {
|
|
|
|
type: TIMELINE_DISCONNECT,
|
|
|
|
timeline,
|
|
|
|
};
|
|
|
|
};
|
2019-07-17 23:59:50 +01:00
|
|
|
|
|
|
|
export function scrollTopTimeline(timeline, top) {
|
|
|
|
return {
|
|
|
|
type: TIMELINE_SCROLL_TOP,
|
|
|
|
timeline,
|
|
|
|
top,
|
|
|
|
};
|
|
|
|
};
|