Infinite scrolling

pull/1/head
David Baker 2015-06-24 13:28:44 +01:00
parent aaa38d95ba
commit 8f1258b6cc
2 changed files with 63 additions and 3 deletions

View File

@ -21,6 +21,7 @@ var React = require('react');
var MatrixClientPeg = require("../../../../src/MatrixClientPeg"); var MatrixClientPeg = require("../../../../src/MatrixClientPeg");
var ComponentBroker = require('../../../../src/ComponentBroker'); var ComponentBroker = require('../../../../src/ComponentBroker');
var classNames = require("classnames");
var MessageTile = ComponentBroker.get('molecules/MessageTile'); var MessageTile = ComponentBroker.get('molecules/MessageTile');
var RoomHeader = ComponentBroker.get('molecules/RoomHeader'); var RoomHeader = ComponentBroker.get('molecules/RoomHeader');
@ -68,11 +69,17 @@ module.exports = React.createClass({
); );
} }
} else { } else {
var scrollheader_classes = classNames({
mx_RoomView_scrollheader: true,
loading: this.state.paginating
});
return ( return (
<div className="mx_RoomView"> <div className="mx_RoomView">
<RoomHeader room={this.state.room} /> <RoomHeader room={this.state.room} />
<div className="mx_RoomView_HSplit"> <div className="mx_RoomView_HSplit">
<ul className="mx_RoomView_MessageList" ref="messageList"> <ul className="mx_RoomView_MessageList" ref="messageList" onScroll={this.onMessageListScroll}>
<li className={scrollheader_classes}>
</li>
{this.getMessageTiles()} {this.getMessageTiles()}
</ul> </ul>
<MemberList roomId={this.props.roomId} key={this.props.roomId} /> <MemberList roomId={this.props.roomId} key={this.props.roomId} />

View File

@ -18,6 +18,8 @@ limitations under the License.
var MatrixClientPeg = require("../../MatrixClientPeg"); var MatrixClientPeg = require("../../MatrixClientPeg");
var PAGINATE_SIZE = 20;
module.exports = { module.exports = {
getInitialState: function() { getInitialState: function() {
return { return {
@ -43,6 +45,12 @@ module.exports = {
},*/ },*/
onRoomTimeline: function(ev, room, toStartOfTimeline) { onRoomTimeline: function(ev, room, toStartOfTimeline) {
// ignore anything that comes in whilst pagingating: we get one
// event for each new matrix event so this would cause a huge
// number of UI updates. Just update the UI when the paginate
// call returns.
if (this.state.paginating) return;
// no point handling anything while we're waiting for the join to finish: // no point handling anything while we're waiting for the join to finish:
// we'll only be showing a spinner. // we'll only be showing a spinner.
if (this.state.joining) return; if (this.state.joining) return;
@ -55,22 +63,59 @@ module.exports = {
this.setState({ this.setState({
room: MatrixClientPeg.get().getRoom(this.props.roomId) room: MatrixClientPeg.get().getRoom(this.props.roomId)
}); });
if (toStartOfTimeline && !this.state.paginating) {
this.fillSpace();
}
}, },
componentDidMount: function() { componentDidMount: function() {
if (this.refs.messageList) { if (this.refs.messageList) {
var messageUl = this.refs.messageList.getDOMNode(); var messageUl = this.refs.messageList.getDOMNode();
messageUl.scrollTop = messageUl.scrollHeight; messageUl.scrollTop = messageUl.scrollHeight;
this.fillSpace();
} }
}, },
componentDidUpdate: function() { componentDidUpdate: function() {
if (this.refs.messageList && this.atBottom) { if (!this.refs.messageList) return;
var messageUl = this.refs.messageList.getDOMNode(); var messageUl = this.refs.messageList.getDOMNode();
if (this.state.paginating && !this.waiting_for_paginate) {
var heightGained = messageUl.scrollHeight - this.oldScrollHeight;
messageUl.scrollTop += heightGained;
this.oldScrollHeight = undefined;
if (!this.fillSpace()) {
this.setState({paginating: false});
}
} else if (this.atBottom) {
messageUl.scrollTop = messageUl.scrollHeight; messageUl.scrollTop = messageUl.scrollHeight;
} }
}, },
fillSpace: function() {
var messageUl = this.refs.messageList.getDOMNode();
if (messageUl.scrollTop < messageUl.clientHeight) {
this.setState({paginating: true});
this.waiting_for_paginate = true;
this.oldScrollHeight = messageUl.scrollHeight;
var that = this;
MatrixClientPeg.get().scrollback(this.state.room, PAGINATE_SIZE).finally(function() {
that.waiting_for_paginate = false;
that.setState({
room: MatrixClientPeg.get().getRoom(that.props.roomId)
});
// wait and set paginating to false when the component updates
});
return true;
}
return false;
},
onJoinButtonClicked: function(ev) { onJoinButtonClicked: function(ev) {
var that = this; var that = this;
MatrixClientPeg.get().joinRoom(this.props.roomId).then(function() { MatrixClientPeg.get().joinRoom(this.props.roomId).then(function() {
@ -87,6 +132,14 @@ module.exports = {
this.setState({ this.setState({
joining: true joining: true
}); });
},
onMessageListScroll: function(ev) {
if (this.refs.messageList) {
var messageUl = this.refs.messageList.getDOMNode();
this.atBottom = messageUl.scrollHeight - messageUl.scrollTop <= messageUl.clientHeight;
}
if (!this.state.paginating) this.fillSpace();
} }
}; };