Merge remote-tracking branch 'origin/develop' into luke/feature-flair

This commit is contained in:
David Baker 2017-09-13 16:52:12 +01:00
commit 5087da9247
73 changed files with 3335 additions and 3724 deletions

View file

@ -53,14 +53,14 @@ module.exports = React.createClass({
this.scalarClient = null;
if (SdkConfig.get().integrations_ui_url && SdkConfig.get().integrations_rest_url) {
this.scalarClient = new ScalarAuthClient();
this.scalarClient.connect().done(() => {
this.scalarClient.connect().then(() => {
this.forceUpdate();
// TODO -- Handle Scalar errors
// },
// (err) => {
// this.setState({
// scalar_error: err,
// });
}).catch((e) => {
console.log("Failed to connect to integrations server");
// TODO -- Handle Scalar errors
// this.setState({
// scalar_error: err,
// });
});
}

View file

@ -143,7 +143,6 @@ export default class Autocomplete extends React.Component {
return null;
}
this.setSelection(selectionOffset);
return selectionOffset === COMPOSER_SELECTED ? null : this.state.completionList[selectionOffset - 1];
}
// called from MessageComposerInput
@ -155,7 +154,6 @@ export default class Autocomplete extends React.Component {
return null;
}
this.setSelection(selectionOffset);
return selectionOffset === COMPOSER_SELECTED ? null : this.state.completionList[selectionOffset - 1];
}
onEscape(e): boolean {
@ -201,6 +199,9 @@ export default class Autocomplete extends React.Component {
setSelection(selectionOffset: number) {
this.setState({selectionOffset, hide: false});
if (this.props.onSelectionChange) {
this.props.onSelectionChange(this.state.completionList[selectionOffset - 1]);
}
}
componentDidUpdate() {

View file

@ -139,7 +139,7 @@ module.exports = React.createClass({
}
return (
<div className={ appsDrawer ? "mx_RoomView_auxPanel mx_RoomView_auxPanel_apps" : "mx_RoomView_auxPanel" } style={{maxHeight: this.props.maxHeight}} >
<div className="mx_RoomView_auxPanel" style={{maxHeight: this.props.maxHeight}} >
{ appsDrawer }
{ fileDropTarget }
{ callView }

View file

@ -949,8 +949,7 @@ export default class MessageComposerInput extends React.Component {
};
moveAutocompleteSelection = (up) => {
const completion = up ? this.autocomplete.onUpArrow() : this.autocomplete.onDownArrow();
return this.setDisplayedCompletion(completion);
up ? this.autocomplete.onUpArrow() : this.autocomplete.onDownArrow();
};
onEscape = async (e) => {
@ -1133,6 +1132,7 @@ export default class MessageComposerInput extends React.Component {
<Autocomplete
ref={(e) => this.autocomplete = e}
onConfirm={this.setDisplayedCompletion}
onSelectionChange={this.setDisplayedCompletion}
query={this.getAutocompleteQuery(content)}
selection={selection}/>
</div>

View file

@ -123,7 +123,19 @@ module.exports = React.createClass({
}
var newElement = ReactDOM.findDOMNode(this);
var startTopOffset = oldTop - newElement.offsetParent.getBoundingClientRect().top;
let startTopOffset;
if (!newElement.offsetParent) {
// this seems to happen sometimes for reasons I don't understand
// the docs for `offsetParent` say it may be null if `display` is
// `none`, but I can't see why that would happen.
console.warn(
`ReadReceiptMarker for ${this.props.member.userId} in ` +
`${this.props.member.roomId} has no offsetParent`,
);
startTopOffset = 0;
} else {
startTopOffset = oldTop - newElement.offsetParent.getBoundingClientRect().top;
}
var startStyles = [];
var enterTransitionOpts = [];
@ -131,13 +143,12 @@ module.exports = React.createClass({
if (oldInfo && oldInfo.left) {
// start at the old height and in the old h pos
var leftOffset = oldInfo.left;
startStyles.push({ top: startTopOffset+"px",
left: oldInfo.left+"px" });
var reorderTransitionOpts = {
duration: 100,
easing: 'easeOut'
easing: 'easeOut',
};
enterTransitionOpts.push(reorderTransitionOpts);
@ -175,7 +186,7 @@ module.exports = React.createClass({
if (this.props.timestamp) {
title = _t(
"Seen by %(userName)s at %(dateTime)s",
{userName: this.props.member.userId, dateTime: DateUtils.formatDate(new Date(this.props.timestamp), this.props.showTwelveHour)}
{userName: this.props.member.userId, dateTime: DateUtils.formatDate(new Date(this.props.timestamp), this.props.showTwelveHour)},
);
}

View file

@ -63,7 +63,6 @@ module.exports = React.createClass({
propTypes: {
ConferenceHandler: React.PropTypes.any,
collapsed: React.PropTypes.bool.isRequired,
currentRoom: React.PropTypes.string,
searchFilter: React.PropTypes.string,
},
@ -88,6 +87,7 @@ module.exports = React.createClass({
cli.on("Room.receipt", this.onRoomReceipt);
cli.on("RoomState.events", this.onRoomStateEvents);
cli.on("RoomMember.name", this.onRoomMemberName);
cli.on("Event.decrypted", this.onEventDecrypted);
cli.on("accountData", this.onAccountData);
this.refreshRoomList();
@ -155,6 +155,7 @@ module.exports = React.createClass({
MatrixClientPeg.get().removeListener("Room.receipt", this.onRoomReceipt);
MatrixClientPeg.get().removeListener("RoomState.events", this.onRoomStateEvents);
MatrixClientPeg.get().removeListener("RoomMember.name", this.onRoomMemberName);
MatrixClientPeg.get().removeListener("Event.decrypted", this.onEventDecrypted);
MatrixClientPeg.get().removeListener("accountData", this.onAccountData);
}
// cancel any pending calls to the rate_limited_funcs
@ -224,6 +225,11 @@ module.exports = React.createClass({
this._delayedRefreshRoomList();
},
onEventDecrypted: function(ev) {
// An event being decrypted may mean we need to re-order the room list
this._delayedRefreshRoomList();
},
onAccountData: function(ev) {
if (ev.getType() == 'm.direct') {
this._delayedRefreshRoomList();
@ -571,6 +577,7 @@ module.exports = React.createClass({
label={ _t('Invites') }
editable={ false }
order="recent"
isInvite={true}
selectedRoom={ self.props.selectedRoom }
incomingCall={ self.state.incomingCall }
collapsed={ self.props.collapsed }

View file

@ -1,5 +1,6 @@
/*
Copyright 2015, 2016 OpenMarket Ltd
Copyright 2017 New Vector Ltd
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@ -27,6 +28,8 @@ var RoomNotifs = require('../../../RoomNotifs');
var FormattingUtils = require('../../../utils/FormattingUtils');
import AccessibleButton from '../elements/AccessibleButton';
var UserSettingsStore = require('../../../UserSettingsStore');
import ActiveRoomObserver from '../../../ActiveRoomObserver';
import RoomViewStore from '../../../stores/RoomViewStore';
module.exports = React.createClass({
displayName: 'RoomTile',
@ -39,7 +42,6 @@ module.exports = React.createClass({
room: React.PropTypes.object.isRequired,
collapsed: React.PropTypes.bool.isRequired,
selected: React.PropTypes.bool.isRequired,
unread: React.PropTypes.bool.isRequired,
highlight: React.PropTypes.bool.isRequired,
isInvite: React.PropTypes.bool.isRequired,
@ -58,6 +60,7 @@ module.exports = React.createClass({
badgeHover : false,
menuDisplayed: false,
notifState: RoomNotifs.getRoomNotifsState(this.props.room.roomId),
selected: this.props.room.roomId === RoomViewStore.getRoomId(),
});
},
@ -87,8 +90,15 @@ module.exports = React.createClass({
}
},
_onActiveRoomChange: function() {
this.setState({
selected: this.props.room.roomId === RoomViewStore.getRoomId(),
});
},
componentWillMount: function() {
MatrixClientPeg.get().on("accountData", this.onAccountData);
ActiveRoomObserver.addListener(this.props.room.roomId, this._onActiveRoomChange);
},
componentWillUnmount: function() {
@ -96,6 +106,7 @@ module.exports = React.createClass({
if (cli) {
MatrixClientPeg.get().removeListener("accountData", this.onAccountData);
}
ActiveRoomObserver.removeListener(this.props.room.roomId, this._onActiveRoomChange);
},
onClick: function(ev) {
@ -174,7 +185,7 @@ module.exports = React.createClass({
var classes = classNames({
'mx_RoomTile': true,
'mx_RoomTile_selected': this.props.selected,
'mx_RoomTile_selected': this.state.selected,
'mx_RoomTile_unread': this.props.unread,
'mx_RoomTile_unreadNotify': notifBadges,
'mx_RoomTile_highlight': mentionBadges,
@ -221,7 +232,7 @@ module.exports = React.createClass({
'mx_RoomTile_badgeShown': badges || this.state.badgeHover || this.state.menuDisplayed,
});
if (this.props.selected) {
if (this.state.selected) {
let nameSelected = <EmojiText>{name}</EmojiText>;
label = <div title={ name } className={ nameClasses } dir="auto">{ nameSelected }</div>;