dispatch/client/src/js/components/MessageBox.js

223 lines
5.2 KiB
JavaScript
Raw Normal View History

import React, { PureComponent } from 'react';
2017-03-23 19:38:27 +00:00
import { List } from 'react-virtualized/dist/commonjs/List';
import { AutoSizer } from 'react-virtualized/dist/commonjs/AutoSizer';
2017-05-02 21:21:25 +00:00
import debounce from 'lodash/debounce';
2016-02-16 21:43:25 +00:00
import Message from './Message';
2017-03-30 02:18:25 +00:00
import { measureScrollBarWidth } from '../util';
import { getScrollPos, saveScrollPos } from '../util/scrollPosition';
2015-12-28 23:34:32 +00:00
2017-03-30 02:18:25 +00:00
const scrollBarWidth = measureScrollBarWidth();
2017-03-23 19:38:27 +00:00
const listStyle = { padding: '7px 0', boxSizing: 'content-box' };
2017-05-02 21:21:25 +00:00
const threshold = 100;
2015-12-28 23:34:32 +00:00
2017-03-23 19:38:27 +00:00
export default class MessageBox extends PureComponent {
componentDidMount() {
this.loadScrollPos();
}
componentWillUpdate(nextProps) {
2017-05-02 21:21:25 +00:00
if (nextProps.messages !== this.props.messages) {
this.list.recomputeRowHeights();
}
2017-03-23 19:38:27 +00:00
if (nextProps.tab !== this.props.tab) {
this.saveScrollPos();
2017-03-23 19:38:27 +00:00
}
2015-12-28 23:34:32 +00:00
2017-05-02 21:21:25 +00:00
if (nextProps.messages.get(0) !== this.props.messages.get(0)) {
if (nextProps.tab === this.props.tab) {
const addedMessages = nextProps.messages.size - this.props.messages.size;
let addedHeight = 0;
for (let i = 0; i < addedMessages; i++) {
addedHeight += nextProps.messages.get(i).height;
}
this.nextScrollTop = addedHeight + this.container.scrollTop;
}
this.loading = false;
2016-02-16 21:43:25 +00:00
}
}
componentDidUpdate(prevProps) {
if (prevProps.tab !== this.props.tab) {
this.loadScrollPos();
}
2017-05-02 21:21:25 +00:00
if (this.nextScrollTop > 0) {
this.container.scrollTop = this.nextScrollTop;
this.nextScrollTop = 0;
} else if (this.bottom) {
this.list.scrollToRow(this.props.messages.size);
2015-12-28 23:34:32 +00:00
}
2017-03-23 19:38:27 +00:00
this.updateWidth();
2015-12-28 23:34:32 +00:00
}
componentWillUnmount() {
this.saveScrollPos();
}
2017-05-02 21:21:25 +00:00
getRowHeight = ({ index }) => {
if (index === 0) {
if (this.props.hasMoreMessages) {
return 100;
}
return 0;
}
return this.props.messages.get(index - 1).height;
}
2016-02-16 21:43:25 +00:00
2017-05-02 21:21:25 +00:00
listRef = el => {
this.list = el;
if (el) {
// eslint-disable-next-line no-underscore-dangle
this.container = el.Grid._scrollingContainer;
}
};
updateScrollKey = () => {
const { tab } = this.props;
this.scrollKey = `msg:${tab.server}:${tab.name}`;
return this.scrollKey;
}
loadScrollPos = () => {
const pos = getScrollPos(this.updateScrollKey());
if (pos >= 0) {
this.bottom = false;
this.container.scrollTop = pos;
} else {
this.bottom = true;
}
};
saveScrollPos = () => {
if (this.bottom) {
saveScrollPos(this.scrollKey, -1);
} else {
saveScrollPos(this.scrollKey, this.container.scrollTop);
}
}
scrollDown = () => {
this.container.scrollTop = this.container.scrollHeight - this.container.clientHeight;
2017-05-02 21:21:25 +00:00
};
2016-02-16 21:43:25 +00:00
2017-03-28 21:55:50 +00:00
updateWidth = (width) => {
const { tab, setWrapWidth, updateMessageHeight } = this.props;
2017-03-28 21:55:50 +00:00
let wrapWidth = width || this.width;
2016-02-16 21:43:25 +00:00
2017-03-28 21:55:50 +00:00
if (width) {
if (tab.isChannel() && window.innerWidth > 600) {
2017-03-28 21:55:50 +00:00
wrapWidth += 200;
}
this.width = wrapWidth;
2017-03-23 19:38:27 +00:00
}
2016-02-16 21:43:25 +00:00
2017-05-02 21:21:25 +00:00
if (this.container.scrollHeight > this.container.clientHeight) {
2017-03-30 02:18:25 +00:00
wrapWidth -= scrollBarWidth;
2017-03-23 19:38:27 +00:00
}
2016-02-16 21:43:25 +00:00
2017-03-23 19:38:27 +00:00
if (this.wrapWidth !== wrapWidth) {
this.wrapWidth = wrapWidth;
setWrapWidth(wrapWidth);
updateMessageHeight();
2015-12-28 23:34:32 +00:00
}
};
2015-12-28 23:34:32 +00:00
2017-03-23 19:38:27 +00:00
handleResize = size => {
2017-03-28 21:55:50 +00:00
this.updateWidth(size.width - 30);
};
2015-12-28 23:34:32 +00:00
2017-05-02 21:21:25 +00:00
fetchMore = debounce(() => {
this.loading = true;
this.props.onFetchMore();
}, 100);
2017-03-23 19:38:27 +00:00
handleScroll = ({ scrollTop, clientHeight, scrollHeight }) => {
2017-05-02 21:21:25 +00:00
if (this.props.hasMoreMessages &&
scrollTop <= threshold &&
scrollTop < this.prevScrollTop &&
!this.loading) {
if (this.mouseDown) {
this.shouldFetch = true;
} else {
this.fetchMore();
}
}
this.bottom = scrollTop + clientHeight >= scrollHeight - 10;
2017-05-02 21:21:25 +00:00
this.prevScrollTop = scrollTop;
};
handleMouseDown = () => {
this.mouseDown = true;
};
handleMouseUp = () => {
this.mouseDown = false;
if (this.shouldFetch) {
this.shouldFetch = false;
this.loading = true;
this.props.onFetchMore();
}
2017-03-23 19:38:27 +00:00
};
2016-02-16 21:43:25 +00:00
2017-04-20 03:32:22 +00:00
renderMessage = ({ index, style }) => {
2017-05-02 21:21:25 +00:00
if (index === 0) {
if (this.props.hasMoreMessages) {
return (
<div
key="top"
className="messagebox-top-indicator"
style={style}
>
Loading messages...
</div>
);
}
return null;
}
const { messages, onNickClick } = this.props;
2017-05-02 21:21:25 +00:00
const message = messages.get(index - 1);
2015-12-28 23:34:32 +00:00
2016-02-16 21:43:25 +00:00
return (
<Message
2017-04-20 03:32:22 +00:00
key={message.id}
message={message}
2017-03-23 19:38:27 +00:00
style={style}
onNickClick={onNickClick}
2016-02-16 21:43:25 +00:00
/>
);
};
render() {
2015-12-28 23:34:32 +00:00
return (
2017-05-02 21:21:25 +00:00
<div
className="messagebox"
onMouseDown={this.handleMouseDown}
onMouseUp={this.handleMouseUp}
>
2017-03-23 19:38:27 +00:00
<AutoSizer onResize={this.handleResize}>
{({ width, height }) => (
<List
ref={this.listRef}
width={width}
height={height - 14}
2017-05-02 21:21:25 +00:00
rowCount={this.props.messages.size + 1}
2017-03-23 19:38:27 +00:00
rowHeight={this.getRowHeight}
rowRenderer={this.renderMessage}
onScroll={this.handleScroll}
style={listStyle}
/>
)}
</AutoSizer>
2015-12-28 23:34:32 +00:00
</div>
);
}
}