Merge pull request #473 from matrix-org/wmwragg/multi-invite-bugfix
Wmwragg/multi invite bugfix
This commit is contained in:
commit
1a126fee54
4 changed files with 82 additions and 49 deletions
|
@ -71,10 +71,21 @@ module.exports = React.createClass({
|
||||||
},
|
},
|
||||||
|
|
||||||
onButtonClick: function() {
|
onButtonClick: function() {
|
||||||
if (this.state.inviteList.length > 0) {
|
var inviteList = this.state.inviteList.slice();
|
||||||
if (this._isDmChat()) {
|
// Check the text input field to see if user has an unconverted address
|
||||||
|
// If there is and it's valid add it to the local inviteList
|
||||||
|
var check = Invite.isValidAddress(this.refs.textinput.value);
|
||||||
|
if (check === true || check === null) {
|
||||||
|
inviteList.push(this.refs.textinput.value);
|
||||||
|
} else if (this.refs.textinput.value.length > 0) {
|
||||||
|
this.setState({ error: true });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (inviteList.length > 0) {
|
||||||
|
if (this._isDmChat(inviteList)) {
|
||||||
// Direct Message chat
|
// Direct Message chat
|
||||||
var room = this._getDirectMessageRoom(this.state.inviteList[0]);
|
var room = this._getDirectMessageRoom(inviteList[0]);
|
||||||
if (room) {
|
if (room) {
|
||||||
// A Direct Message room already exists for this user and you
|
// A Direct Message room already exists for this user and you
|
||||||
// so go straight to that room
|
// so go straight to that room
|
||||||
|
@ -82,13 +93,13 @@ module.exports = React.createClass({
|
||||||
action: 'view_room',
|
action: 'view_room',
|
||||||
room_id: room.roomId,
|
room_id: room.roomId,
|
||||||
});
|
});
|
||||||
this.props.onFinished(true, this.state.inviteList[0]);
|
this.props.onFinished(true, inviteList[0]);
|
||||||
} else {
|
} else {
|
||||||
this._startChat(this.state.inviteList);
|
this._startChat(inviteList);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Multi invite chat
|
// Multi invite chat
|
||||||
this._startChat(this.state.inviteList);
|
this._startChat(inviteList);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// No addresses supplied
|
// No addresses supplied
|
||||||
|
@ -108,16 +119,16 @@ module.exports = React.createClass({
|
||||||
} else if (e.keyCode === 38) { // up arrow
|
} else if (e.keyCode === 38) { // up arrow
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
this.addressSelector.onKeyUpArrow();
|
this.addressSelector.onKeyU();
|
||||||
} else if (e.keyCode === 40) { // down arrow
|
} else if (e.keyCode === 40) { // down arrow
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
this.addressSelector.onKeyDownArrow();
|
this.addressSelector.onKeyDown();
|
||||||
} else if (e.keyCode === 13) { // enter
|
} else if (e.keyCode === 13 || (e.keyCode === 9 && this.state.queryList.length > 0)) { // enter or tab
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
this.addressSelector.onKeyReturn();
|
this.addressSelector.onKeySelect();
|
||||||
} else if (e.keyCode === 32 || e.keyCode === 188) { // space or comma
|
} else if (e.keyCode === 32 || e.keyCode === 188 || e.keyCode === 9) { // space, comma or tab
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
var check = Invite.isValidAddress(this.refs.textinput.value);
|
var check = Invite.isValidAddress(this.refs.textinput.value);
|
||||||
|
@ -200,17 +211,22 @@ module.exports = React.createClass({
|
||||||
_startChat: function(addrs) {
|
_startChat: function(addrs) {
|
||||||
if (this.props.roomId) {
|
if (this.props.roomId) {
|
||||||
// Invite new user to a room
|
// Invite new user to a room
|
||||||
|
var self = this;
|
||||||
Invite.inviteMultipleToRoom(this.props.roomId, addrs)
|
Invite.inviteMultipleToRoom(this.props.roomId, addrs)
|
||||||
|
.then(function(addrs) {
|
||||||
|
var room = MatrixClientPeg.get().getRoom(this.props.roomId);
|
||||||
|
return self._showAnyInviteErrors(addrs, room);
|
||||||
|
})
|
||||||
.catch(function(err) {
|
.catch(function(err) {
|
||||||
var ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
|
var ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
|
||||||
Modal.createDialog(ErrorDialog, {
|
Modal.createDialog(ErrorDialog, {
|
||||||
title: "Failure to invite user",
|
title: "Failure to invite",
|
||||||
description: err.toString()
|
description: err.toString()
|
||||||
});
|
});
|
||||||
return null;
|
return null;
|
||||||
})
|
})
|
||||||
.done();
|
.done();
|
||||||
} else if (this._isDmChat()) {
|
} else if (this._isDmChat(addrs)) {
|
||||||
// Start the DM chat
|
// Start the DM chat
|
||||||
createRoom({dmUserId: addrs[0]})
|
createRoom({dmUserId: addrs[0]})
|
||||||
.catch(function(err) {
|
.catch(function(err) {
|
||||||
|
@ -225,13 +241,18 @@ module.exports = React.createClass({
|
||||||
} else {
|
} else {
|
||||||
// Start multi user chat
|
// Start multi user chat
|
||||||
var self = this;
|
var self = this;
|
||||||
|
var room;
|
||||||
createRoom().then(function(roomId) {
|
createRoom().then(function(roomId) {
|
||||||
|
room = MatrixClientPeg.get().getRoom(roomId);
|
||||||
return Invite.inviteMultipleToRoom(roomId, addrs);
|
return Invite.inviteMultipleToRoom(roomId, addrs);
|
||||||
})
|
})
|
||||||
|
.then(function(addrs) {
|
||||||
|
return self._showAnyInviteErrors(addrs, room);
|
||||||
|
})
|
||||||
.catch(function(err) {
|
.catch(function(err) {
|
||||||
var ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
|
var ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
|
||||||
Modal.createDialog(ErrorDialog, {
|
Modal.createDialog(ErrorDialog, {
|
||||||
title: "Failure to invite user",
|
title: "Failure to invite",
|
||||||
description: err.toString()
|
description: err.toString()
|
||||||
});
|
});
|
||||||
return null;
|
return null;
|
||||||
|
@ -254,11 +275,16 @@ module.exports = React.createClass({
|
||||||
var uid = user.userId.toLowerCase();
|
var uid = user.userId.toLowerCase();
|
||||||
query = query.toLowerCase();
|
query = query.toLowerCase();
|
||||||
|
|
||||||
// dount match any that are already on the invite list
|
// don't match any that are already on the invite list
|
||||||
if (this._isOnInviteList(uid)) {
|
if (this._isOnInviteList(uid)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ignore current user
|
||||||
|
if (uid === MatrixClientPeg.get().credentials.userId) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
// direct prefix matches
|
// direct prefix matches
|
||||||
if (name.indexOf(query) === 0 || uid.indexOf(query) === 0) {
|
if (name.indexOf(query) === 0 || uid.indexOf(query) === 0) {
|
||||||
return true;
|
return true;
|
||||||
|
@ -288,14 +314,33 @@ module.exports = React.createClass({
|
||||||
return false;
|
return false;
|
||||||
},
|
},
|
||||||
|
|
||||||
_isDmChat: function() {
|
_isDmChat: function(addrs) {
|
||||||
if (this.state.inviteList.length === 1 && Invite.getAddressType(this.state.inviteList[0]) === "mx" && !this.props.roomId) {
|
if (addrs.length === 1 && Invite.getAddressType(addrs[0]) === "mx" && !this.props.roomId) {
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
_showAnyInviteErrors: function(addrs, room) {
|
||||||
|
// Show user any errors
|
||||||
|
var errorList = [];
|
||||||
|
for (var addr in addrs) {
|
||||||
|
if (addrs.hasOwnProperty(addr) && addrs[addr] === "error") {
|
||||||
|
errorList.push(addr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (errorList.length > 0) {
|
||||||
|
var ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
|
||||||
|
Modal.createDialog(ErrorDialog, {
|
||||||
|
title: "Failed to invite the following users to the " + room.name + " room:",
|
||||||
|
description: errorList.join(", "),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return addrs;
|
||||||
|
},
|
||||||
|
|
||||||
render: function() {
|
render: function() {
|
||||||
var TintableSvg = sdk.getComponent("elements.TintableSvg");
|
var TintableSvg = sdk.getComponent("elements.TintableSvg");
|
||||||
var AddressSelector = sdk.getComponent("elements.AddressSelector");
|
var AddressSelector = sdk.getComponent("elements.AddressSelector");
|
||||||
|
|
|
@ -55,7 +55,7 @@ module.exports = React.createClass({
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
onKeyUpArrow: function() {
|
onKeyUp: function() {
|
||||||
if (this.state.selected > 0) {
|
if (this.state.selected > 0) {
|
||||||
this.setState({
|
this.setState({
|
||||||
selected: this.state.selected - 1,
|
selected: this.state.selected - 1,
|
||||||
|
@ -64,7 +64,7 @@ module.exports = React.createClass({
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
onKeyDownArrow: function() {
|
onKeyDown: function() {
|
||||||
if (this.state.selected < this._maxSelected(this.props.addressList)) {
|
if (this.state.selected < this._maxSelected(this.props.addressList)) {
|
||||||
this.setState({
|
this.setState({
|
||||||
selected: this.state.selected + 1,
|
selected: this.state.selected + 1,
|
||||||
|
@ -73,7 +73,7 @@ module.exports = React.createClass({
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
onKeyReturn: function() {
|
onKeySelect: function() {
|
||||||
this.selectAddress(this.state.selected);
|
this.selectAddress(this.state.selected);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
|
@ -90,7 +90,7 @@ module.exports = React.createClass({
|
||||||
var EntityTile = sdk.getComponent("rooms.EntityTile");
|
var EntityTile = sdk.getComponent("rooms.EntityTile");
|
||||||
var BaseAvatar = sdk.getComponent("avatars.BaseAvatar");
|
var BaseAvatar = sdk.getComponent("avatars.BaseAvatar");
|
||||||
|
|
||||||
var label = input;
|
// var label = input;
|
||||||
// if (input[0] === "@") {
|
// if (input[0] === "@") {
|
||||||
// label = input;
|
// label = input;
|
||||||
// }
|
// }
|
||||||
|
@ -98,16 +98,16 @@ module.exports = React.createClass({
|
||||||
// label = "Email: " + input;
|
// label = "Email: " + input;
|
||||||
// }
|
// }
|
||||||
|
|
||||||
this._emailEntity = new Entities.newEntity(
|
// this._emailEntity = new Entities.newEntity(
|
||||||
<EntityTile key="dynamic_invite_tile" suppressOnHover={true} showInviteButton={true}
|
// <EntityTile key="dynamic_invite_tile" suppressOnHover={true} showInviteButton={true}
|
||||||
avatarJsx={ <BaseAvatar name="@" width={36} height={36} /> }
|
// avatarJsx={ <BaseAvatar name="@" width={36} height={36} /> }
|
||||||
className="mx_EntityTile_invitePlaceholder"
|
// className="mx_EntityTile_invitePlaceholder"
|
||||||
presenceState="online" onClick={this.onThirdPartyInvite} name={"Invite by email"}
|
// presenceState="online" onClick={this.onThirdPartyInvite} name={"Invite by email"}
|
||||||
/>,
|
// />,
|
||||||
function(query) {
|
// function(query) {
|
||||||
return true; // always show this
|
// return true; // always show this
|
||||||
}
|
// }
|
||||||
);
|
// );
|
||||||
|
|
||||||
this.props.onSearchQueryChanged(input);
|
this.props.onSearchQueryChanged(input);
|
||||||
},
|
},
|
||||||
|
@ -117,9 +117,9 @@ module.exports = React.createClass({
|
||||||
var entities = Entities.fromUsers(this._userList || [], true, this.props.onInvite);
|
var entities = Entities.fromUsers(this._userList || [], true, this.props.onInvite);
|
||||||
|
|
||||||
// Add an "Email: foo@bar.com" tile as the first tile
|
// Add an "Email: foo@bar.com" tile as the first tile
|
||||||
if (this._emailEntity) {
|
// if (this._emailEntity) {
|
||||||
entities.unshift(this._emailEntity);
|
// entities.unshift(this._emailEntity);
|
||||||
}
|
// }
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<SearchableEntityList searchPlaceholderText={"Search/invite by name, email, id"}
|
<SearchableEntityList searchPlaceholderText={"Search/invite by name, email, id"}
|
||||||
|
|
|
@ -102,7 +102,7 @@ var SearchableEntityList = React.createClass({
|
||||||
|
|
||||||
getSearchResults: function(query, entities) {
|
getSearchResults: function(query, entities) {
|
||||||
if (!query || query.length === 0) {
|
if (!query || query.length === 0) {
|
||||||
return this.props.emptyQueryShowsAll ? entities : [ entities[0] ]
|
return this.props.emptyQueryShowsAll ? entities : [];
|
||||||
}
|
}
|
||||||
return entities.filter(function(e) {
|
return entities.filter(function(e) {
|
||||||
return e.matches(query);
|
return e.matches(query);
|
||||||
|
@ -135,20 +135,8 @@ var SearchableEntityList = React.createClass({
|
||||||
<form onSubmit={this.onQuerySubmit} autoComplete="off">
|
<form onSubmit={this.onQuerySubmit} autoComplete="off">
|
||||||
<input className="mx_SearchableEntityList_query" id="mx_SearchableEntityList_query" type="text"
|
<input className="mx_SearchableEntityList_query" id="mx_SearchableEntityList_query" type="text"
|
||||||
onChange={this.onQueryChanged} value={this.state.query}
|
onChange={this.onQueryChanged} value={this.state.query}
|
||||||
onFocus={ ()=>{
|
onFocus= {() => { this.setState({ focused: true }) }}
|
||||||
if (this._blurTimeout) {
|
onBlur= {() => { this.setState({ focused: false }) }}
|
||||||
clearTimeout(this.blurTimeout);
|
|
||||||
}
|
|
||||||
this.setState({ focused: true });
|
|
||||||
} }
|
|
||||||
onBlur={ ()=>{
|
|
||||||
// nasty setTimeout heuristic to avoid the 'invite by email' prompt disappearing
|
|
||||||
// due to the onBlur before we can click on it
|
|
||||||
this._blurTimeout = setTimeout(
|
|
||||||
()=>{ this.setState({ focused: false }) },
|
|
||||||
300
|
|
||||||
);
|
|
||||||
} }
|
|
||||||
placeholder={this.props.searchPlaceholderText} />
|
placeholder={this.props.searchPlaceholderText} />
|
||||||
</form>
|
</form>
|
||||||
);
|
);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue