1 import React
from 'react';
2 import ImmutablePropTypes
from 'react-immutable-proptypes';
3 import { ScrollContainer
} from 'react-router-scroll';
4 import PropTypes
from 'prop-types';
5 import StatusContainer
from '../containers/status_container';
6 import LoadMore
from './load_more';
7 import ImmutablePureComponent
from 'react-immutable-pure-component';
8 import IntersectionObserverWrapper
from '../features/ui/util/intersection_observer_wrapper';
10 class StatusList
extends ImmutablePureComponent
{
13 scrollKey: PropTypes
.string
.isRequired
,
14 statusIds: ImmutablePropTypes
.list
.isRequired
,
15 onScrollToBottom: PropTypes
.func
,
16 onScrollToTop: PropTypes
.func
,
17 onScroll: PropTypes
.func
,
18 trackScroll: PropTypes
.bool
,
19 shouldUpdateScroll: PropTypes
.func
,
20 isLoading: PropTypes
.bool
,
21 isUnread: PropTypes
.bool
,
22 hasMore: PropTypes
.bool
,
23 prepend: PropTypes
.node
,
24 emptyMessage: PropTypes
.node
,
27 static defaultProps
= {
31 intersectionObserverWrapper
= new IntersectionObserverWrapper();
33 handleScroll
= (e
) => {
34 const { scrollTop
, scrollHeight
, clientHeight
} = e
.target
;
35 const offset
= scrollHeight
- scrollTop
- clientHeight
;
36 this._oldScrollPosition
= scrollHeight
- scrollTop
;
38 if (250 > offset
&& this.props
.onScrollToBottom
&& !this.props
.isLoading
) {
39 this.props
.onScrollToBottom();
40 } else if (scrollTop
< 100 && this.props
.onScrollToTop
) {
41 this.props
.onScrollToTop();
42 } else if (this.props
.onScroll
) {
43 this.props
.onScroll();
47 componentDidMount () {
48 this.attachScrollListener();
49 this.attachIntersectionObserver();
52 componentDidUpdate (prevProps
) {
53 if ((prevProps
.statusIds
.size
< this.props
.statusIds
.size
&& prevProps
.statusIds
.first() !== this.props
.statusIds
.first() && !!this._oldScrollPosition
) && this.node
.scrollTop
> 0) {
54 this.node
.scrollTop
= this.node
.scrollHeight
- this._oldScrollPosition
;
58 componentWillUnmount () {
59 this.detachScrollListener();
60 this.detachIntersectionObserver();
63 attachIntersectionObserver () {
64 this.intersectionObserverWrapper
.connect({
66 rootMargin: '300% 0px',
70 detachIntersectionObserver () {
71 this.intersectionObserverWrapper
.disconnect();
74 attachScrollListener () {
75 this.node
.addEventListener('scroll', this.handleScroll
);
78 detachScrollListener () {
79 this.node
.removeEventListener('scroll', this.handleScroll
);
86 handleLoadMore
= (e
) => {
88 this.props
.onScrollToBottom();
92 const { statusIds
, onScrollToBottom
, scrollKey
, trackScroll
, shouldUpdateScroll
, isLoading
, isUnread
, hasMore
, prepend
, emptyMessage
} = this.props
;
95 let scrollableArea
= null;
98 if (!isLoading
&& statusIds
.size
> 0 && hasMore
) {
99 loadMore
= <LoadMore onClick
={this.handleLoadMore
} />;
103 unread
= <div className
='status-list__unread-indicator' />;
106 if (isLoading
|| statusIds
.size
> 0 || !emptyMessage
) {
108 <div className
='scrollable' ref
={this.setRef
}>
111 <div className
='status-list'>
114 {statusIds
.map((statusId
) => {
115 return <StatusContainer key
={statusId
} id
={statusId
} intersectionObserverWrapper
={this.intersectionObserverWrapper
} />;
124 <div className
='empty-column-indicator' ref
={this.setRef
}>
132 <ScrollContainer scrollKey
={scrollKey
} shouldUpdateScroll
={shouldUpdateScroll
}>
137 return scrollableArea
;
143 export default StatusList
;