track RoomTile focus in RoomList, and stop the RoomList from updating during mouseOver
This commit is contained in:
parent
0a91511f05
commit
691639d1e0
2 changed files with 69 additions and 4 deletions
|
@ -63,12 +63,15 @@ module.exports = React.createClass({
|
||||||
|
|
||||||
var s = this.getRoomLists();
|
var s = this.getRoomLists();
|
||||||
this.setState(s);
|
this.setState(s);
|
||||||
|
|
||||||
|
this.focusedRoomTileRoomId = null;
|
||||||
},
|
},
|
||||||
|
|
||||||
componentDidMount: function() {
|
componentDidMount: function() {
|
||||||
this.dispatcherRef = dis.register(this.onAction);
|
this.dispatcherRef = dis.register(this.onAction);
|
||||||
// Initialise the stickyHeaders when the component is created
|
// Initialise the stickyHeaders when the component is created
|
||||||
this._updateStickyHeaders(true);
|
this._updateStickyHeaders(true);
|
||||||
|
document.addEventListener('keydown', this._onKeyDown);
|
||||||
},
|
},
|
||||||
|
|
||||||
componentDidUpdate: function() {
|
componentDidUpdate: function() {
|
||||||
|
@ -100,6 +103,8 @@ module.exports = React.createClass({
|
||||||
// Force an update because the notif count state is too deep to cause
|
// Force an update because the notif count state is too deep to cause
|
||||||
// an update. This forces the local echo of reading notifs to be
|
// an update. This forces the local echo of reading notifs to be
|
||||||
// reflected by the RoomTiles.
|
// reflected by the RoomTiles.
|
||||||
|
//
|
||||||
|
// FIXME: we should surely just be refreshing the right tile...
|
||||||
this.forceUpdate();
|
this.forceUpdate();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -120,6 +125,8 @@ module.exports = React.createClass({
|
||||||
}
|
}
|
||||||
// cancel any pending calls to the rate_limited_funcs
|
// cancel any pending calls to the rate_limited_funcs
|
||||||
this._delayedRefreshRoomList.cancelPendingCall();
|
this._delayedRefreshRoomList.cancelPendingCall();
|
||||||
|
document.removeEventListener('keydown', this._onKeyDown);
|
||||||
|
|
||||||
},
|
},
|
||||||
|
|
||||||
onRoom: function(room) {
|
onRoom: function(room) {
|
||||||
|
@ -149,6 +156,35 @@ module.exports = React.createClass({
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
_onMouseOver: function(ev) {
|
||||||
|
this._lastMouseOverTs = Date.now();
|
||||||
|
},
|
||||||
|
|
||||||
|
_onKeyDown: function(ev) {
|
||||||
|
if (!this.focusedRoomTileRoomId) return;
|
||||||
|
let handled = false;
|
||||||
|
|
||||||
|
switch (ev.keyCode) {
|
||||||
|
case KeyCode.UP:
|
||||||
|
this._onMoveFocus(true);
|
||||||
|
handled = true;
|
||||||
|
break;
|
||||||
|
case KeyCode.DOWN:
|
||||||
|
this._onMoveFocus(false);
|
||||||
|
handled = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (handled) {
|
||||||
|
ev.stopPropagation();
|
||||||
|
ev.preventDefault();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
_onMoveFocus: function(up) {
|
||||||
|
|
||||||
|
},
|
||||||
|
|
||||||
onSubListHeaderClick: function(isHidden, scrollToPosition) {
|
onSubListHeaderClick: function(isHidden, scrollToPosition) {
|
||||||
// The scroll area has expanded or contracted, so re-calculate sticky headers positions
|
// The scroll area has expanded or contracted, so re-calculate sticky headers positions
|
||||||
this._updateStickyHeaders(true, scrollToPosition);
|
this._updateStickyHeaders(true, scrollToPosition);
|
||||||
|
@ -192,7 +228,15 @@ module.exports = React.createClass({
|
||||||
},
|
},
|
||||||
|
|
||||||
_delayedRefreshRoomList: new rate_limited_func(function() {
|
_delayedRefreshRoomList: new rate_limited_func(function() {
|
||||||
this.refreshRoomList();
|
// if the mouse has been moving over the RoomList in the last 500ms
|
||||||
|
// then delay the refresh further to avoid bouncing around under the
|
||||||
|
// cursor
|
||||||
|
if (Date.now() - this._lastMouseOverTs > 500) {
|
||||||
|
this.refreshRoomList();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
this._delayedRefreshRoomList();
|
||||||
|
}
|
||||||
}, 500),
|
}, 500),
|
||||||
|
|
||||||
refreshRoomList: function() {
|
refreshRoomList: function() {
|
||||||
|
@ -207,7 +251,8 @@ module.exports = React.createClass({
|
||||||
// us re-rendering all the sublists every time anything changes anywhere
|
// us re-rendering all the sublists every time anything changes anywhere
|
||||||
// in the state of the client.
|
// in the state of the client.
|
||||||
this.setState(this.getRoomLists());
|
this.setState(this.getRoomLists());
|
||||||
this._lastRefreshRoomListTs = Date.now();
|
|
||||||
|
// this._lastRefreshRoomListTs = Date.now();
|
||||||
},
|
},
|
||||||
|
|
||||||
getRoomLists: function() {
|
getRoomLists: function() {
|
||||||
|
@ -457,6 +502,10 @@ module.exports = React.createClass({
|
||||||
this.refs.gemscroll.forceUpdate();
|
this.refs.gemscroll.forceUpdate();
|
||||||
},
|
},
|
||||||
|
|
||||||
|
onRoomTileFocus: function(roomId) {
|
||||||
|
this.focusedRoomTileRoomId = roomId;
|
||||||
|
},
|
||||||
|
|
||||||
render: function() {
|
render: function() {
|
||||||
var RoomSubList = sdk.getComponent('structures.RoomSubList');
|
var RoomSubList = sdk.getComponent('structures.RoomSubList');
|
||||||
var self = this;
|
var self = this;
|
||||||
|
@ -464,7 +513,7 @@ module.exports = React.createClass({
|
||||||
return (
|
return (
|
||||||
<GeminiScrollbar className="mx_RoomList_scrollbar"
|
<GeminiScrollbar className="mx_RoomList_scrollbar"
|
||||||
autoshow={true} onScroll={ self._whenScrolling } ref="gemscroll">
|
autoshow={true} onScroll={ self._whenScrolling } ref="gemscroll">
|
||||||
<div className="mx_RoomList">
|
<div className="mx_RoomList" onMouseOver={ this._onMouseOver }>
|
||||||
<RoomSubList list={ self.state.lists['im.vector.fake.invite'] }
|
<RoomSubList list={ self.state.lists['im.vector.fake.invite'] }
|
||||||
label="Invites"
|
label="Invites"
|
||||||
editable={ false }
|
editable={ false }
|
||||||
|
@ -474,6 +523,7 @@ module.exports = React.createClass({
|
||||||
collapsed={ self.props.collapsed }
|
collapsed={ self.props.collapsed }
|
||||||
searchFilter={ self.props.searchFilter }
|
searchFilter={ self.props.searchFilter }
|
||||||
onHeaderClick={ self.onSubListHeaderClick }
|
onHeaderClick={ self.onSubListHeaderClick }
|
||||||
|
onRoomTileFocus={ self.onRoomTileFocus }
|
||||||
onShowMoreRooms={ self.onShowMoreRooms } />
|
onShowMoreRooms={ self.onShowMoreRooms } />
|
||||||
|
|
||||||
<RoomSubList list={ self.state.lists['m.favourite'] }
|
<RoomSubList list={ self.state.lists['m.favourite'] }
|
||||||
|
@ -487,6 +537,7 @@ module.exports = React.createClass({
|
||||||
collapsed={ self.props.collapsed }
|
collapsed={ self.props.collapsed }
|
||||||
searchFilter={ self.props.searchFilter }
|
searchFilter={ self.props.searchFilter }
|
||||||
onHeaderClick={ self.onSubListHeaderClick }
|
onHeaderClick={ self.onSubListHeaderClick }
|
||||||
|
onRoomTileFocus={ self.onRoomTileFocus }
|
||||||
onShowMoreRooms={ self.onShowMoreRooms } />
|
onShowMoreRooms={ self.onShowMoreRooms } />
|
||||||
|
|
||||||
<RoomSubList list={ self.state.lists['im.vector.fake.direct'] }
|
<RoomSubList list={ self.state.lists['im.vector.fake.direct'] }
|
||||||
|
@ -501,6 +552,7 @@ module.exports = React.createClass({
|
||||||
alwaysShowHeader={ true }
|
alwaysShowHeader={ true }
|
||||||
searchFilter={ self.props.searchFilter }
|
searchFilter={ self.props.searchFilter }
|
||||||
onHeaderClick={ self.onSubListHeaderClick }
|
onHeaderClick={ self.onSubListHeaderClick }
|
||||||
|
onRoomTileFocus={ self.onRoomTileFocus }
|
||||||
onShowMoreRooms={ self.onShowMoreRooms } />
|
onShowMoreRooms={ self.onShowMoreRooms } />
|
||||||
|
|
||||||
<RoomSubList list={ self.state.lists['im.vector.fake.recent'] }
|
<RoomSubList list={ self.state.lists['im.vector.fake.recent'] }
|
||||||
|
@ -513,6 +565,7 @@ module.exports = React.createClass({
|
||||||
collapsed={ self.props.collapsed }
|
collapsed={ self.props.collapsed }
|
||||||
searchFilter={ self.props.searchFilter }
|
searchFilter={ self.props.searchFilter }
|
||||||
onHeaderClick={ self.onSubListHeaderClick }
|
onHeaderClick={ self.onSubListHeaderClick }
|
||||||
|
onRoomTileFocus={ self.onRoomTileFocus }
|
||||||
onShowMoreRooms={ self.onShowMoreRooms } />
|
onShowMoreRooms={ self.onShowMoreRooms } />
|
||||||
|
|
||||||
{ Object.keys(self.state.lists).map(function(tagName) {
|
{ Object.keys(self.state.lists).map(function(tagName) {
|
||||||
|
@ -529,6 +582,7 @@ module.exports = React.createClass({
|
||||||
collapsed={ self.props.collapsed }
|
collapsed={ self.props.collapsed }
|
||||||
searchFilter={ self.props.searchFilter }
|
searchFilter={ self.props.searchFilter }
|
||||||
onHeaderClick={ self.onSubListHeaderClick }
|
onHeaderClick={ self.onSubListHeaderClick }
|
||||||
|
onRoomTileFocus={ self.onRoomTileFocus }
|
||||||
onShowMoreRooms={ self.onShowMoreRooms } />;
|
onShowMoreRooms={ self.onShowMoreRooms } />;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -545,6 +599,7 @@ module.exports = React.createClass({
|
||||||
collapsed={ self.props.collapsed }
|
collapsed={ self.props.collapsed }
|
||||||
searchFilter={ self.props.searchFilter }
|
searchFilter={ self.props.searchFilter }
|
||||||
onHeaderClick={ self.onSubListHeaderClick }
|
onHeaderClick={ self.onSubListHeaderClick }
|
||||||
|
onRoomTileFocus={ self.onRoomTileFocus }
|
||||||
onShowMoreRooms={ self.onShowMoreRooms } />
|
onShowMoreRooms={ self.onShowMoreRooms } />
|
||||||
|
|
||||||
<RoomSubList list={ self.state.lists['im.vector.fake.archived'] }
|
<RoomSubList list={ self.state.lists['im.vector.fake.archived'] }
|
||||||
|
@ -559,6 +614,7 @@ module.exports = React.createClass({
|
||||||
onHeaderClick= { self.onArchivedHeaderClick }
|
onHeaderClick= { self.onArchivedHeaderClick }
|
||||||
incomingCall={ self.state.incomingCall }
|
incomingCall={ self.state.incomingCall }
|
||||||
searchFilter={ self.props.searchFilter }
|
searchFilter={ self.props.searchFilter }
|
||||||
|
onRoomTileFocus={ self.onRoomTileFocus }
|
||||||
onShowMoreRooms={ self.onShowMoreRooms } />
|
onShowMoreRooms={ self.onShowMoreRooms } />
|
||||||
</div>
|
</div>
|
||||||
</GeminiScrollbar>
|
</GeminiScrollbar>
|
||||||
|
|
|
@ -35,6 +35,7 @@ module.exports = React.createClass({
|
||||||
connectDragSource: React.PropTypes.func,
|
connectDragSource: React.PropTypes.func,
|
||||||
connectDropTarget: React.PropTypes.func,
|
connectDropTarget: React.PropTypes.func,
|
||||||
onClick: React.PropTypes.func,
|
onClick: React.PropTypes.func,
|
||||||
|
onFocus: React.PropTypes.func,
|
||||||
isDragging: React.PropTypes.bool,
|
isDragging: React.PropTypes.bool,
|
||||||
|
|
||||||
room: React.PropTypes.object.isRequired,
|
room: React.PropTypes.object.isRequired,
|
||||||
|
@ -104,6 +105,12 @@ module.exports = React.createClass({
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
onFocus: function() {
|
||||||
|
if (this.props.onFocus) {
|
||||||
|
this.props.onFocus(this.props.room.roomId);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
onMouseEnter: function() {
|
onMouseEnter: function() {
|
||||||
this.setState( { hover : true });
|
this.setState( { hover : true });
|
||||||
this.badgeOnMouseEnter();
|
this.badgeOnMouseEnter();
|
||||||
|
@ -255,7 +262,9 @@ module.exports = React.createClass({
|
||||||
|
|
||||||
let ret = (
|
let ret = (
|
||||||
<div> { /* Only native elements can be wrapped in a DnD object. */}
|
<div> { /* Only native elements can be wrapped in a DnD object. */}
|
||||||
<AccessibleButton className={classes} tabIndex="0" onClick={this.onClick} onMouseEnter={this.onMouseEnter} onMouseLeave={this.onMouseLeave}>
|
<AccessibleButton className={classes} tabIndex="0" onClick={this.onClick}
|
||||||
|
onMouseEnter={this.onMouseEnter} onMouseLeave={this.onMouseLeave}
|
||||||
|
onFocus={this.onFocus} onBlur={this.onFocus.bind(this, null)}>
|
||||||
<div className={avatarClasses}>
|
<div className={avatarClasses}>
|
||||||
<div className="mx_RoomTile_avatar_container">
|
<div className="mx_RoomTile_avatar_container">
|
||||||
<RoomAvatar room={this.props.room} width={24} height={24} />
|
<RoomAvatar room={this.props.room} width={24} height={24} />
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue