Make publicrooms use the new paginating API

Also do filtering on the server

WIP: This breaks the network dropdown
pull/2241/head
David Baker 2016-09-16 17:33:28 +01:00
parent 135c22c99d
commit a11516a984
2 changed files with 72 additions and 43 deletions

View File

@ -29,6 +29,7 @@ var linkify = require('linkifyjs');
var linkifyString = require('linkifyjs/string'); var linkifyString = require('linkifyjs/string');
var linkifyMatrix = require('matrix-react-sdk/lib/linkify-matrix'); var linkifyMatrix = require('matrix-react-sdk/lib/linkify-matrix');
var sanitizeHtml = require('sanitize-html'); var sanitizeHtml = require('sanitize-html');
var q = require('q');
linkifyMatrix(linkify); linkifyMatrix(linkify);
@ -50,7 +51,6 @@ module.exports = React.createClass({
getInitialState: function() { getInitialState: function() {
return { return {
publicRooms: [], publicRooms: [],
roomAlias: '',
loading: true, loading: true,
filterByNetwork: null, filterByNetwork: null,
} }
@ -64,6 +64,8 @@ module.exports = React.createClass({
this.networkPatterns[network] = new RegExp(this.props.config.networkPatterns[network]); this.networkPatterns[network] = new RegExp(this.props.config.networkPatterns[network]);
} }
} }
this.nextBatch = null;
this.filterString = null;
// dis.dispatch({ // dis.dispatch({
// action: 'ui_opacity', // action: 'ui_opacity',
@ -73,7 +75,7 @@ module.exports = React.createClass({
}, },
componentDidMount: function() { componentDidMount: function() {
this.getPublicRooms(); this.refreshRoomList();
}, },
componentWillUnmount: function() { componentWillUnmount: function() {
@ -84,24 +86,34 @@ module.exports = React.createClass({
// }); // });
}, },
getPublicRooms: function() { refreshRoomList: function() {
var self = this; this.nextBatch = null;
MatrixClientPeg.get().publicRooms(function (err, data) { this.setState({
if (err) { publicRooms: [],
self.setState({ loading: false }); });
this.getMoreRooms().done();
},
getMoreRooms: function() {
const opts = {limit: 20};
if (this.nextBatch) opts.since = this.nextBatch;
if (this.filterString) opts.filter = { generic_search_term: this.filterString } ;
return MatrixClientPeg.get().publicRooms(opts).then((data) => {
this.nextBatch = data.next_batch;
this.setState((s) => {
s.publicRooms.push(...data.chunk);
s.loading = false;
return s;
});
return Boolean(data.next_batch);
}, (err) => {
this.setState({ loading: false });
console.error("Failed to get publicRooms: %s", JSON.stringify(err)); console.error("Failed to get publicRooms: %s", JSON.stringify(err));
var ErrorDialog = sdk.getComponent("dialogs.ErrorDialog"); var ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
Modal.createDialog(ErrorDialog, { Modal.createDialog(ErrorDialog, {
title: "Failed to get public room list", title: "Failed to get public room list",
description: err.message description: err.message
}); });
}
else {
self.setState({
publicRooms: data.chunk,
loading: false,
});
}
}); });
}, },
@ -142,10 +154,10 @@ module.exports = React.createClass({
return MatrixClientPeg.get().deleteAlias(alias); return MatrixClientPeg.get().deleteAlias(alias);
}).done(() => { }).done(() => {
modal.close(); modal.close();
this.getPublicRooms(); this.refreshRoomList();
}, function(err) { }, function(err) {
modal.close(); modal.close();
this.getPublicRooms(); this.refreshRoomList();
Modal.createDialog(ErrorDialog, { Modal.createDialog(ErrorDialog, {
title: "Failed to "+step, title: "Failed to "+step,
description: err.toString() description: err.toString()
@ -170,6 +182,23 @@ module.exports = React.createClass({
}); });
}, },
onFillRequest: function(backwards) {
if (backwards || !this.nextBatch) return q(false);
return this.getMoreRooms();
},
onFilterChange: function(ev) {
const alias = ev.target.value;
if (ev.key == "Enter") {
this.showRoomAlias(alias);
} else {
this.filterString = alias || null;
this.refreshRoomList();
}
},
showRoomAlias: function(alias) { showRoomAlias: function(alias) {
this.showRoom(null, alias); this.showRoom(null, alias);
}, },
@ -214,23 +243,17 @@ module.exports = React.createClass({
dis.dispatch(payload); dis.dispatch(payload);
}, },
getRows: function(filter) { getRows: function() {
var BaseAvatar = sdk.getComponent('avatars.BaseAvatar'); var BaseAvatar = sdk.getComponent('avatars.BaseAvatar');
if (!this.state.publicRooms) return []; if (!this.state.publicRooms) return [];
var rooms = this.state.publicRooms.filter((a) => { var rooms = this.state.publicRooms.filter((a) => {
// FIXME: if incrementally typing, keep narrowing down the search set
// incrementally rather than starting over each time.
if (this.state.filterByNetwork) { if (this.state.filterByNetwork) {
if (!this._isRoomInNetwork(a, this.state.filterByNetwork)) return false; if (!this._isRoomInNetwork(a, this.state.filterByNetwork)) return false;
} }
return (((a.name && a.name.toLowerCase().search(filter.toLowerCase()) >= 0) || return true;
(a.aliases && a.aliases[0].toLowerCase().search(filter.toLowerCase()) >= 0)) &&
a.num_joined_members > 0);
}).sort(function(a,b) {
return a.num_joined_members - b.num_joined_members;
}); });
var rows = []; var rows = [];
var self = this; var self = this;
@ -259,7 +282,7 @@ module.exports = React.createClass({
var topic = rooms[i].topic || ''; var topic = rooms[i].topic || '';
topic = linkifyString(sanitizeHtml(topic)); topic = linkifyString(sanitizeHtml(topic));
rows.unshift( rows.push(
<tr key={ rooms[i].room_id } <tr key={ rooms[i].room_id }
onClick={self.onRoomClicked.bind(self, rooms[i])} onClick={self.onRoomClicked.bind(self, rooms[i])}
// cancel onMouseDown otherwise shift-clicking highlights text // cancel onMouseDown otherwise shift-clicking highlights text
@ -289,14 +312,6 @@ module.exports = React.createClass({
return rows; return rows;
}, },
onKeyUp: function(ev) {
this.forceUpdate();
this.setState({ roomAlias : this.refs.roomAlias.value })
if (ev.key == "Enter") {
this.showRoomAlias(this.refs.roomAlias.value);
}
},
/** /**
* Terrible temporary function that guess what network a public room * Terrible temporary function that guess what network a public room
* entry is in, until synapse is able to tell us * entry is in, until synapse is able to tell us
@ -323,21 +338,30 @@ module.exports = React.createClass({
const SimpleRoomHeader = sdk.getComponent('rooms.SimpleRoomHeader'); const SimpleRoomHeader = sdk.getComponent('rooms.SimpleRoomHeader');
const NetworkDropdown = sdk.getComponent('directory.NetworkDropdown'); const NetworkDropdown = sdk.getComponent('directory.NetworkDropdown');
const ScrollPanel = sdk.getComponent("structures.ScrollPanel");
return ( return (
<div className="mx_RoomDirectory"> <div className="mx_RoomDirectory">
<SimpleRoomHeader title="Directory" /> <SimpleRoomHeader title="Directory" />
<div className="mx_RoomDirectory_list"> <div className="mx_RoomDirectory_list">
<div className="mx_RoomDirectory_listheader"> <div className="mx_RoomDirectory_listheader">
<input ref="roomAlias" placeholder="Join a room (e.g. #foo:domain.com)" className="mx_RoomDirectory_input" size="64" onKeyUp={ this.onKeyUp }/> <input type="text" placeholder="Find a room by keyword or room ID (#foo:matrix.org)"
className="mx_RoomDirectory_input" size="64" onChange={this.onFilterChange}
/>
<NetworkDropdown config={this.props.config} onNetworkChange={this.onNetworkChange} /> <NetworkDropdown config={this.props.config} onNetworkChange={this.onNetworkChange} />
</div> </div>
<GeminiScrollbar className="mx_RoomDirectory_tableWrapper"> <ScrollPanel
className="mx_RoomDirectory_tableWrapper"
onFillRequest={ this.onFillRequest }
stickyBottom={false}
startAtBottom={false}
onResize={function(){}}
>
<table ref="directory_table" className="mx_RoomDirectory_table"> <table ref="directory_table" className="mx_RoomDirectory_table">
<tbody> <tbody>
{ this.getRows(this.state.roomAlias) } { this.getRows() }
</tbody> </tbody>
</table> </table>
</GeminiScrollbar> </ScrollPanel>
</div> </div>
</div> </div>
); );

View File

@ -46,6 +46,11 @@ limitations under the License.
-webkit-flex-direction: column; -webkit-flex-direction: column;
} }
.mx_RoomDirectory_list .mx_RoomView_messageListWrapper {
justify-content: flex-start;
-webkit-justify-content: flex-start;
}
.mx_RoomDirectory_listheader { .mx_RoomDirectory_listheader {
display: table; display: table;
width: 100%; width: 100%;