refactor out the sections of the RoomList into RoomSubLists. Start wiring up tags
This commit is contained in:
parent
8b9b268ec0
commit
7fe7af6026
9 changed files with 295 additions and 102 deletions
|
@ -34,7 +34,8 @@
|
||||||
"q": "^1.4.1",
|
"q": "^1.4.1",
|
||||||
"react": "^0.13.3",
|
"react": "^0.13.3",
|
||||||
"react-loader": "^1.4.0",
|
"react-loader": "^1.4.0",
|
||||||
"sanitize-html": "^1.11.1"
|
"react-dnd": "^1.1.8",
|
||||||
|
"sanitize-html": "^1.0.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"babel": "^5.8.23",
|
"babel": "^5.8.23",
|
||||||
|
|
|
@ -23,7 +23,6 @@ var dis = require("matrix-react-sdk/lib/dispatcher");
|
||||||
|
|
||||||
var sdk = require('matrix-react-sdk');
|
var sdk = require('matrix-react-sdk');
|
||||||
var VectorConferenceHandler = require("../../modules/VectorConferenceHandler");
|
var VectorConferenceHandler = require("../../modules/VectorConferenceHandler");
|
||||||
var CallHandler = require("matrix-react-sdk/lib/CallHandler");
|
|
||||||
|
|
||||||
var HIDE_CONFERENCE_CHANS = true;
|
var HIDE_CONFERENCE_CHANS = true;
|
||||||
|
|
||||||
|
@ -31,8 +30,7 @@ module.exports = {
|
||||||
getInitialState: function() {
|
getInitialState: function() {
|
||||||
return {
|
return {
|
||||||
activityMap: null,
|
activityMap: null,
|
||||||
inviteList: [],
|
lists: {},
|
||||||
roomList: [],
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -41,6 +39,7 @@ module.exports = {
|
||||||
cli.on("Room", this.onRoom);
|
cli.on("Room", this.onRoom);
|
||||||
cli.on("Room.timeline", this.onRoomTimeline);
|
cli.on("Room.timeline", this.onRoomTimeline);
|
||||||
cli.on("Room.name", this.onRoomName);
|
cli.on("Room.name", this.onRoomName);
|
||||||
|
cli.on("Room.tags", this.onRoomTags);
|
||||||
cli.on("RoomState.events", this.onRoomStateEvents);
|
cli.on("RoomState.events", this.onRoomStateEvents);
|
||||||
cli.on("RoomMember.name", this.onRoomMemberName);
|
cli.on("RoomMember.name", this.onRoomMemberName);
|
||||||
|
|
||||||
|
@ -55,11 +54,6 @@ module.exports = {
|
||||||
|
|
||||||
onAction: function(payload) {
|
onAction: function(payload) {
|
||||||
switch (payload.action) {
|
switch (payload.action) {
|
||||||
// listen for call state changes to prod the render method, which
|
|
||||||
// may hide the global CallView if the call it is tracking is dead
|
|
||||||
case 'call_state':
|
|
||||||
this._recheckCallElement(this.props.selectedRoom);
|
|
||||||
break;
|
|
||||||
case 'view_tooltip':
|
case 'view_tooltip':
|
||||||
this.tooltip = payload.tooltip;
|
this.tooltip = payload.tooltip;
|
||||||
this._repositionTooltip();
|
this._repositionTooltip();
|
||||||
|
@ -80,7 +74,6 @@ module.exports = {
|
||||||
|
|
||||||
componentWillReceiveProps: function(newProps) {
|
componentWillReceiveProps: function(newProps) {
|
||||||
this.state.activityMap[newProps.selectedRoom] = undefined;
|
this.state.activityMap[newProps.selectedRoom] = undefined;
|
||||||
this._recheckCallElement(newProps.selectedRoom);
|
|
||||||
this.setState({
|
this.setState({
|
||||||
activityMap: this.state.activityMap
|
activityMap: this.state.activityMap
|
||||||
});
|
});
|
||||||
|
@ -117,6 +110,10 @@ module.exports = {
|
||||||
this.refreshRoomList();
|
this.refreshRoomList();
|
||||||
},
|
},
|
||||||
|
|
||||||
|
onRoomTags: function(room) {
|
||||||
|
this.refreshRoomList();
|
||||||
|
},
|
||||||
|
|
||||||
onRoomStateEvents: function(ev, state) {
|
onRoomStateEvents: function(ev, state) {
|
||||||
setTimeout(this.refreshRoomList, 0);
|
setTimeout(this.refreshRoomList, 0);
|
||||||
},
|
},
|
||||||
|
@ -125,26 +122,31 @@ module.exports = {
|
||||||
setTimeout(this.refreshRoomList, 0);
|
setTimeout(this.refreshRoomList, 0);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
||||||
refreshRoomList: function() {
|
refreshRoomList: function() {
|
||||||
|
// TODO: rather than bluntly regenerating and re-sorting everything
|
||||||
|
// every time we see any kind of room change from the JS SDK
|
||||||
|
// we could do incremental updates on our copy of the state
|
||||||
|
// based on the room which has actually changed. This would stop
|
||||||
|
// us re-rendering all the sublists every time anything changes anywhere
|
||||||
|
// in the state of the client.
|
||||||
this.setState(this.getRoomLists());
|
this.setState(this.getRoomLists());
|
||||||
},
|
},
|
||||||
|
|
||||||
getRoomLists: function() {
|
getRoomLists: function() {
|
||||||
var s = {};
|
var s = { lists: {} };
|
||||||
var inviteList = [];
|
|
||||||
s.roomList = RoomListSorter.mostRecentActivityFirst(
|
MatrixClientPeg.get().getRooms().forEach(function(room) {
|
||||||
MatrixClientPeg.get().getRooms().filter(function(room) {
|
|
||||||
var me = room.getMember(MatrixClientPeg.get().credentials.userId);
|
var me = room.getMember(MatrixClientPeg.get().credentials.userId);
|
||||||
|
|
||||||
if (me && me.membership == "invite") {
|
if (me && me.membership == "invite") {
|
||||||
inviteList.push(room);
|
s.lists["invites"] = s.lists["invites"] || [];
|
||||||
return false;
|
s.lists["invites"].push(room);
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
var shouldShowRoom = (
|
var shouldShowRoom = (
|
||||||
me && (me.membership == "join")
|
me && (me.membership == "join")
|
||||||
);
|
);
|
||||||
|
|
||||||
// hiding conf rooms only ever toggles shouldShowRoom to false
|
// hiding conf rooms only ever toggles shouldShowRoom to false
|
||||||
if (shouldShowRoom && HIDE_CONFERENCE_CHANS) {
|
if (shouldShowRoom && HIDE_CONFERENCE_CHANS) {
|
||||||
// we want to hide the 1:1 conf<->user room and not the group chat
|
// we want to hide the 1:1 conf<->user room and not the group chat
|
||||||
|
@ -159,23 +161,27 @@ module.exports = {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return shouldShowRoom;
|
|
||||||
})
|
|
||||||
);
|
|
||||||
s.inviteList = RoomListSorter.mostRecentActivityFirst(inviteList);
|
|
||||||
return s;
|
|
||||||
},
|
|
||||||
|
|
||||||
_recheckCallElement: function(selectedRoomId) {
|
if (shouldShowRoom) {
|
||||||
// if we aren't viewing a room with an ongoing call, but there is an
|
var tagNames = Object.keys(room.tags);
|
||||||
// active call, show the call element - we need to do this to make
|
if (tagNames.length) {
|
||||||
// audio/video not crap out
|
for (var i = 0; i < tagNames.length; i++) {
|
||||||
var activeCall = CallHandler.getAnyActiveCall();
|
var tagName = tagNames[i];
|
||||||
var callForRoom = CallHandler.getCallForRoom(selectedRoomId);
|
s.lists[tagName] = s.lists[tagName] || [];
|
||||||
var showCall = (activeCall && !callForRoom);
|
s.lists[tagNames[i]].push(room);
|
||||||
this.setState({
|
}
|
||||||
show_call_element: showCall
|
}
|
||||||
|
else {
|
||||||
|
s.lists["recents"] = s.lists["recents"] || [];
|
||||||
|
s.lists["recents"].push(room);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// we actually apply the sorting to this when receiving the prop in RoomSubLists.
|
||||||
|
|
||||||
|
return s;
|
||||||
},
|
},
|
||||||
|
|
||||||
_repositionTooltip: function(e) {
|
_repositionTooltip: function(e) {
|
||||||
|
@ -184,23 +190,4 @@ module.exports = {
|
||||||
this.tooltip.style.top = (scroll.parentElement.offsetTop + this.tooltip.parentElement.offsetTop - scroll.scrollTop) + "px";
|
this.tooltip.style.top = (scroll.parentElement.offsetTop + this.tooltip.parentElement.offsetTop - scroll.scrollTop) + "px";
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
makeRoomTiles: function(list, isInvite) {
|
|
||||||
var self = this;
|
|
||||||
var RoomTile = sdk.getComponent("molecules.RoomTile");
|
|
||||||
return list.map(function(room) {
|
|
||||||
var selected = room.roomId == self.props.selectedRoom;
|
|
||||||
return (
|
|
||||||
<RoomTile
|
|
||||||
room={room}
|
|
||||||
key={room.roomId}
|
|
||||||
collapsed={self.props.collapsed}
|
|
||||||
selected={selected}
|
|
||||||
unread={self.state.activityMap[room.roomId] === 1}
|
|
||||||
highlight={self.state.activityMap[room.roomId] === 2}
|
|
||||||
isInvite={isInvite}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
|
@ -34,6 +34,10 @@ limitations under the License.
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.mx_LeftPanel_callView {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
.mx_LeftPanel .mx_RoomList {
|
.mx_LeftPanel .mx_RoomList {
|
||||||
-webkit-box-ordinal-group: 1;
|
-webkit-box-ordinal-group: 1;
|
||||||
-moz-box-ordinal-group: 1;
|
-moz-box-ordinal-group: 1;
|
||||||
|
|
|
@ -18,27 +18,9 @@ limitations under the License.
|
||||||
padding-top: 24px;
|
padding-top: 24px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.mx_RoomList_invites,
|
|
||||||
.mx_RoomList_recents {
|
|
||||||
display: table;
|
|
||||||
table-layout: fixed;
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.mx_RoomList_expandButton {
|
.mx_RoomList_expandButton {
|
||||||
margin-left: 8px;
|
margin-left: 8px;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
padding-left: 12px;
|
padding-left: 12px;
|
||||||
padding-right: 12px;
|
padding-right: 12px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.mx_RoomList h2 {
|
|
||||||
text-transform: uppercase;
|
|
||||||
color: #3d3b39;
|
|
||||||
font-weight: 600;
|
|
||||||
font-size: 14px;
|
|
||||||
padding-left: 12px;
|
|
||||||
padding-right: 12px;
|
|
||||||
margin-top: 8px;
|
|
||||||
margin-bottom: 4px;
|
|
||||||
}
|
|
||||||
|
|
32
src/skins/vector/css/organisms/RoomSubList.css
Normal file
32
src/skins/vector/css/organisms/RoomSubList.css
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
/*
|
||||||
|
Copyright 2015 OpenMarket Ltd
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
.mx_RoomSubList {
|
||||||
|
display: table;
|
||||||
|
table-layout: fixed;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mx_RoomSubList_label {
|
||||||
|
text-transform: uppercase;
|
||||||
|
color: #3d3b39;
|
||||||
|
font-weight: 600;
|
||||||
|
font-size: 14px;
|
||||||
|
padding-left: 12px;
|
||||||
|
padding-right: 12px;
|
||||||
|
margin-top: 8px;
|
||||||
|
margin-bottom: 4px;
|
||||||
|
}
|
|
@ -30,6 +30,7 @@ skin['atoms.LogoutButton'] = require('./views/atoms/LogoutButton');
|
||||||
skin['atoms.MemberAvatar'] = require('./views/atoms/MemberAvatar');
|
skin['atoms.MemberAvatar'] = require('./views/atoms/MemberAvatar');
|
||||||
skin['atoms.MessageTimestamp'] = require('./views/atoms/MessageTimestamp');
|
skin['atoms.MessageTimestamp'] = require('./views/atoms/MessageTimestamp');
|
||||||
skin['atoms.RoomAvatar'] = require('./views/atoms/RoomAvatar');
|
skin['atoms.RoomAvatar'] = require('./views/atoms/RoomAvatar');
|
||||||
|
skin['atoms.Spinner'] = require('./views/atoms/Spinner');
|
||||||
skin['atoms.create_room.CreateRoomButton'] = require('./views/atoms/create_room/CreateRoomButton');
|
skin['atoms.create_room.CreateRoomButton'] = require('./views/atoms/create_room/CreateRoomButton');
|
||||||
skin['atoms.create_room.Presets'] = require('./views/atoms/create_room/Presets');
|
skin['atoms.create_room.Presets'] = require('./views/atoms/create_room/Presets');
|
||||||
skin['atoms.create_room.RoomAlias'] = require('./views/atoms/create_room/RoomAlias');
|
skin['atoms.create_room.RoomAlias'] = require('./views/atoms/create_room/RoomAlias');
|
||||||
|
@ -80,9 +81,11 @@ skin['organisms.QuestionDialog'] = require('./views/organisms/QuestionDialog');
|
||||||
skin['organisms.RightPanel'] = require('./views/organisms/RightPanel');
|
skin['organisms.RightPanel'] = require('./views/organisms/RightPanel');
|
||||||
skin['organisms.RoomDirectory'] = require('./views/organisms/RoomDirectory');
|
skin['organisms.RoomDirectory'] = require('./views/organisms/RoomDirectory');
|
||||||
skin['organisms.RoomList'] = require('./views/organisms/RoomList');
|
skin['organisms.RoomList'] = require('./views/organisms/RoomList');
|
||||||
|
skin['organisms.RoomSubList'] = require('./views/organisms/RoomSubList');
|
||||||
skin['organisms.RoomView'] = require('./views/organisms/RoomView');
|
skin['organisms.RoomView'] = require('./views/organisms/RoomView');
|
||||||
skin['organisms.UserSettings'] = require('./views/organisms/UserSettings');
|
skin['organisms.UserSettings'] = require('./views/organisms/UserSettings');
|
||||||
skin['organisms.ViewSource'] = require('./views/organisms/ViewSource');
|
skin['organisms.ViewSource'] = require('./views/organisms/ViewSource');
|
||||||
|
skin['pages.CompatibilityPage'] = require('./views/pages/CompatibilityPage');
|
||||||
skin['pages.MatrixChat'] = require('./views/pages/MatrixChat');
|
skin['pages.MatrixChat'] = require('./views/pages/MatrixChat');
|
||||||
skin['templates.Login'] = require('./views/templates/Login');
|
skin['templates.Login'] = require('./views/templates/Login');
|
||||||
skin['templates.Register'] = require('./views/templates/Register');
|
skin['templates.Register'] = require('./views/templates/Register');
|
||||||
|
|
|
@ -20,9 +20,51 @@ var React = require('react');
|
||||||
var sdk = require('matrix-react-sdk')
|
var sdk = require('matrix-react-sdk')
|
||||||
var dis = require('matrix-react-sdk/lib/dispatcher');
|
var dis = require('matrix-react-sdk/lib/dispatcher');
|
||||||
|
|
||||||
|
var CallHandler = require("matrix-react-sdk/lib/CallHandler");
|
||||||
|
|
||||||
module.exports = React.createClass({
|
module.exports = React.createClass({
|
||||||
displayName: 'LeftPanel',
|
displayName: 'LeftPanel',
|
||||||
|
|
||||||
|
getInitialState: function() {
|
||||||
|
return {
|
||||||
|
showCallElement: null,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
|
componentDidMount: function() {
|
||||||
|
this.dispatcherRef = dis.register(this.onAction);
|
||||||
|
},
|
||||||
|
|
||||||
|
componentWillReceiveProps: function(newProps) {
|
||||||
|
this._recheckCallElement(newProps.selectedRoom);
|
||||||
|
},
|
||||||
|
|
||||||
|
componentWillUnmount: function() {
|
||||||
|
dis.unregister(this.dispatcherRef);
|
||||||
|
},
|
||||||
|
|
||||||
|
onAction: function(payload) {
|
||||||
|
switch (payload.action) {
|
||||||
|
// listen for call state changes to prod the render method, which
|
||||||
|
// may hide the global CallView if the call it is tracking is dead
|
||||||
|
case 'call_state':
|
||||||
|
this._recheckCallElement(this.props.selectedRoom);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
_recheckCallElement: function(selectedRoomId) {
|
||||||
|
// if we aren't viewing a room with an ongoing call, but there is an
|
||||||
|
// active call, show the call element - we need to do this to make
|
||||||
|
// audio/video not crap out
|
||||||
|
var activeCall = CallHandler.getAnyActiveCall();
|
||||||
|
var callForRoom = CallHandler.getCallForRoom(selectedRoomId);
|
||||||
|
var showCall = (activeCall && !callForRoom);
|
||||||
|
this.setState({
|
||||||
|
showCallElement: showCall
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
onHideClick: function() {
|
onHideClick: function() {
|
||||||
dis.dispatch({
|
dis.dispatch({
|
||||||
action: 'hide_left_panel',
|
action: 'hide_left_panel',
|
||||||
|
@ -44,10 +86,17 @@ module.exports = React.createClass({
|
||||||
// collapseButton = <img className="mx_LeftPanel_hideButton" onClick={ this.onHideClick } src="img/hide.png" width="12" height="20" alt="<"/>
|
// collapseButton = <img className="mx_LeftPanel_hideButton" onClick={ this.onHideClick } src="img/hide.png" width="12" height="20" alt="<"/>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var callPreview;
|
||||||
|
if (this.state.showCallElement) {
|
||||||
|
var CallView = sdk.getComponent('molecules.voip.CallView');
|
||||||
|
callPreview = <CallView className="mx_LeftPanel_callView"/>
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<aside className={classes}>
|
<aside className={classes}>
|
||||||
{ collapseButton }
|
{ collapseButton }
|
||||||
<IncomingCallBox />
|
<IncomingCallBox />
|
||||||
|
{ callPreview }
|
||||||
<RoomList selectedRoom={this.props.selectedRoom} collapsed={this.props.collapsed}/>
|
<RoomList selectedRoom={this.props.selectedRoom} collapsed={this.props.collapsed}/>
|
||||||
<BottomLeftMenu collapsed={this.props.collapsed}/>
|
<BottomLeftMenu collapsed={this.props.collapsed}/>
|
||||||
</aside>
|
</aside>
|
||||||
|
|
|
@ -33,46 +33,57 @@ module.exports = React.createClass({
|
||||||
},
|
},
|
||||||
|
|
||||||
render: function() {
|
render: function() {
|
||||||
var CallView = sdk.getComponent('molecules.voip.CallView');
|
|
||||||
var RoomDropTarget = sdk.getComponent('molecules.RoomDropTarget');
|
|
||||||
|
|
||||||
var callElement;
|
|
||||||
if (this.state.show_call_element) {
|
|
||||||
callElement = <CallView className="mx_MatrixChat_callView"/>
|
|
||||||
}
|
|
||||||
|
|
||||||
var expandButton = this.props.collapsed ?
|
var expandButton = this.props.collapsed ?
|
||||||
<img className="mx_RoomList_expandButton" onClick={ this.onShowClick } src="img/menu.png" width="20" alt=">"/> :
|
<img className="mx_RoomList_expandButton" onClick={ this.onShowClick } src="img/menu.png" width="20" alt=">"/> :
|
||||||
null;
|
null;
|
||||||
|
|
||||||
var invitesLabel = this.props.collapsed ? null : "Invites";
|
var RoomSubList = sdk.getComponent('organisms.RoomSubList');
|
||||||
var recentsLabel = this.props.collapsed ? null : "Recent";
|
|
||||||
|
|
||||||
var invites;
|
|
||||||
if (this.state.inviteList.length) {
|
|
||||||
invites = <div>
|
|
||||||
<h2 className="mx_RoomList_invitesLabel">{ invitesLabel }</h2>
|
|
||||||
<div className="mx_RoomList_invites">
|
|
||||||
{this.makeRoomTiles(this.state.inviteList, true)}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="mx_RoomList" onScroll={this._repositionTooltip}>
|
<div className="mx_RoomList" onScroll={this._repositionTooltip}>
|
||||||
{ expandButton }
|
{ expandButton }
|
||||||
{ callElement }
|
|
||||||
{ invites }
|
|
||||||
<h2 className="mx_RoomList_favouritesLabel">Favourites</h2>
|
|
||||||
<RoomDropTarget text="Drop here to favourite"/>
|
|
||||||
|
|
||||||
<h2 className="mx_RoomList_recentsLabel">{ recentsLabel }</h2>
|
<RoomSubList list={ this.state.lists['invites'] }
|
||||||
<div className="mx_RoomList_recents">
|
label="Invites"
|
||||||
{this.makeRoomTiles(this.state.roomList, false)}
|
editable={ false }
|
||||||
</div>
|
order="recent"
|
||||||
|
activityMap={ this.state.activityMap }
|
||||||
|
selectedRoom={ this.props.selectedRoom }
|
||||||
|
collapsed={ this.props.collapsed } />
|
||||||
|
|
||||||
<h2 className="mx_RoomList_archiveLabel">Archive</h2>
|
<RoomSubList list={ this.state.lists['favourites'] }
|
||||||
<RoomDropTarget text="Drop here to archive"/>
|
label="Favourites"
|
||||||
|
tagname="favourites"
|
||||||
|
editable={ true }
|
||||||
|
order="manual"
|
||||||
|
activityMap={ this.state.activityMap }
|
||||||
|
selectedRoom={ this.props.selectedRoom }
|
||||||
|
collapsed={ this.props.collapsed } />
|
||||||
|
|
||||||
|
<RoomSubList list={ this.state.lists['recents'] }
|
||||||
|
label="Recents"
|
||||||
|
editable={ true }
|
||||||
|
order="recent"
|
||||||
|
activityMap={ this.state.activityMap }
|
||||||
|
selectedRoom={ this.props.selectedRoom }
|
||||||
|
collapsed={ this.props.collapsed } />
|
||||||
|
|
||||||
|
<RoomSubList list={ this.state.lists['lurking'] }
|
||||||
|
label="Others"
|
||||||
|
tagname="secondary"
|
||||||
|
editable={ true }
|
||||||
|
order="recent"
|
||||||
|
activityMap={ this.state.activityMap }
|
||||||
|
selectedRoom={ this.props.selectedRoom }
|
||||||
|
collapsed={ this.props.collapsed } />
|
||||||
|
|
||||||
|
<RoomSubList list={ this.state.lists['archived'] }
|
||||||
|
label="Historical"
|
||||||
|
editable={ false }
|
||||||
|
order="recent"
|
||||||
|
activityMap={ this.state.activityMap }
|
||||||
|
selectedRoom={ this.props.selectedRoom }
|
||||||
|
collapsed={ this.props.collapsed } />
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
124
src/skins/vector/views/organisms/RoomSubList.js
Normal file
124
src/skins/vector/views/organisms/RoomSubList.js
Normal file
|
@ -0,0 +1,124 @@
|
||||||
|
/*
|
||||||
|
Copyright 2015 OpenMarket Ltd
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
var React = require('react');
|
||||||
|
var sdk = require('matrix-react-sdk')
|
||||||
|
var dis = require('matrix-react-sdk/lib/dispatcher');
|
||||||
|
|
||||||
|
module.exports = React.createClass({
|
||||||
|
displayName: 'RoomSubList',
|
||||||
|
|
||||||
|
propTypes: {
|
||||||
|
list: React.PropTypes.arrayOf(React.PropTypes.object).isRequired,
|
||||||
|
label: React.PropTypes.string.isRequired,
|
||||||
|
tagname: React.PropTypes.string,
|
||||||
|
editable: React.PropTypes.bool,
|
||||||
|
order: React.PropTypes.string.isRequired,
|
||||||
|
selectedRoom: React.PropTypes.string.isRequired,
|
||||||
|
activityMap: React.PropTypes.object.isRequired,
|
||||||
|
collapsed: React.PropTypes.bool.isRequired
|
||||||
|
},
|
||||||
|
|
||||||
|
getInitialState: function() {
|
||||||
|
return {
|
||||||
|
sortedList: [],
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
|
componentWillMount: function() {
|
||||||
|
this.sortList(this.props.list, this.props.order);
|
||||||
|
},
|
||||||
|
|
||||||
|
componentWillReceiveProps: function(newProps) {
|
||||||
|
// order the room list appropriately before we re-render
|
||||||
|
this.sortList(newProps.list, newProps.order);
|
||||||
|
},
|
||||||
|
|
||||||
|
tsOfNewestEvent: function(room) {
|
||||||
|
if (room.timeline.length) {
|
||||||
|
return room.timeline[room.timeline.length - 1].getTs();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return Number.MAX_SAFE_INTEGER;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
// TODO: factor the comparators back out into a generic comparator
|
||||||
|
// so that view_prev_room and view_next_room can do the right thing
|
||||||
|
|
||||||
|
recentsComparator: function(roomA, roomB) {
|
||||||
|
return this.tsOfNewestEvent(roomB) - this.tsOfNewestEvent(roomA);
|
||||||
|
},
|
||||||
|
|
||||||
|
manualComparator: function(roomA, roomB) {
|
||||||
|
var a = roomA.tags[this.props.tagname].order;
|
||||||
|
var b = roomB.tags[this.props.tagname].order;
|
||||||
|
return a == b ? this.recentsComparator(roomA, roomB) : ( a > b ? 1 : -1);
|
||||||
|
},
|
||||||
|
|
||||||
|
sortList: function(list, order) {
|
||||||
|
var comparator;
|
||||||
|
list = list || [];
|
||||||
|
if (order === "manual") comparator = this.manualComparator;
|
||||||
|
if (order === "recent") comparator = this.recentsComparator;
|
||||||
|
|
||||||
|
this.setState({ sortedList: list.sort(comparator) });
|
||||||
|
},
|
||||||
|
|
||||||
|
makeRoomTiles: function() {
|
||||||
|
var self = this;
|
||||||
|
var RoomTile = sdk.getComponent("molecules.RoomTile");
|
||||||
|
return this.state.sortedList.map(function(room) {
|
||||||
|
var selected = room.roomId == self.props.selectedRoom;
|
||||||
|
return (
|
||||||
|
<RoomTile
|
||||||
|
room={room}
|
||||||
|
key={room.roomId}
|
||||||
|
collapsed={self.props.collapsed}
|
||||||
|
selected={selected}
|
||||||
|
unread={self.props.activityMap[room.roomId] === 1}
|
||||||
|
highlight={self.props.activityMap[room.roomId] === 2}
|
||||||
|
isInvite={self.props.label === 'Invites'} />
|
||||||
|
);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
render: function() {
|
||||||
|
var RoomDropTarget = sdk.getComponent('molecules.RoomDropTarget');
|
||||||
|
|
||||||
|
var label = this.props.collapsed ? null : this.props.label;
|
||||||
|
|
||||||
|
if (this.state.sortedList.length > 0 || this.props.editable) {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<h2 className="mx_RoomSubList_label">{ this.props.label }</h2>
|
||||||
|
<div className="mx_RoomSubList">
|
||||||
|
{ this.makeRoomTiles() }
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return (
|
||||||
|
<div className="mx_RoomSubList">
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
Loading…
Reference in a new issue