From 2a8518b72bc409773e1a57a6d064eb08b5af3e27 Mon Sep 17 00:00:00 2001 From: wmwragg Date: Wed, 14 Sep 2016 14:53:13 +0100 Subject: [PATCH 1/8] Tab can now be used for selection of address from list, as well as adding a manual mxid or email address --- src/components/views/dialogs/ChatInviteDialog.js | 10 +++++----- src/components/views/elements/AddressSelector.js | 6 +++--- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/components/views/dialogs/ChatInviteDialog.js b/src/components/views/dialogs/ChatInviteDialog.js index 7f04986b6b..884b6dc79e 100644 --- a/src/components/views/dialogs/ChatInviteDialog.js +++ b/src/components/views/dialogs/ChatInviteDialog.js @@ -108,16 +108,16 @@ module.exports = React.createClass({ } else if (e.keyCode === 38) { // up arrow e.stopPropagation(); e.preventDefault(); - this.addressSelector.onKeyUpArrow(); + this.addressSelector.onKeyU(); } else if (e.keyCode === 40) { // down arrow e.stopPropagation(); e.preventDefault(); - this.addressSelector.onKeyDownArrow(); - } else if (e.keyCode === 13) { // enter + this.addressSelector.onKeyDown(); + } else if (e.keyCode === 13 || (e.keyCode === 9 && this.state.queryList.length > 0)) { // enter or tab e.stopPropagation(); e.preventDefault(); - this.addressSelector.onKeyReturn(); - } else if (e.keyCode === 32 || e.keyCode === 188) { // space or comma + this.addressSelector.onKeySelect(); + } else if (e.keyCode === 32 || e.keyCode === 188 || e.keyCode === 9) { // space, comma or tab e.stopPropagation(); e.preventDefault(); var check = Invite.isValidAddress(this.refs.textinput.value); diff --git a/src/components/views/elements/AddressSelector.js b/src/components/views/elements/AddressSelector.js index 204e08404e..2c2d7e2d61 100644 --- a/src/components/views/elements/AddressSelector.js +++ b/src/components/views/elements/AddressSelector.js @@ -55,7 +55,7 @@ module.exports = React.createClass({ } }, - onKeyUpArrow: function() { + onKeyUp: function() { if (this.state.selected > 0) { this.setState({ 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)) { this.setState({ selected: this.state.selected + 1, @@ -73,7 +73,7 @@ module.exports = React.createClass({ } }, - onKeyReturn: function() { + onKeySelect: function() { this.selectAddress(this.state.selected); }, From a7a81c8a3249a6f64aa84ba77f60c8a938410533 Mon Sep 17 00:00:00 2001 From: wmwragg Date: Wed, 14 Sep 2016 15:09:23 +0100 Subject: [PATCH 2/8] A manual address doesn't have to be converted to an address tile before it can be used if it is the still in the input field when the start/invite button is pressed --- .../views/dialogs/ChatInviteDialog.js | 21 ++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/src/components/views/dialogs/ChatInviteDialog.js b/src/components/views/dialogs/ChatInviteDialog.js index 884b6dc79e..d03341502c 100644 --- a/src/components/views/dialogs/ChatInviteDialog.js +++ b/src/components/views/dialogs/ChatInviteDialog.js @@ -71,10 +71,21 @@ module.exports = React.createClass({ }, onButtonClick: function() { - if (this.state.inviteList.length > 0) { + var inviteList = this.state.inviteList.slice(); + // 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()) { // Direct Message chat - var room = this._getDirectMessageRoom(this.state.inviteList[0]); + var room = this._getDirectMessageRoom(inviteList[0]); if (room) { // A Direct Message room already exists for this user and you // so go straight to that room @@ -82,13 +93,13 @@ module.exports = React.createClass({ action: 'view_room', room_id: room.roomId, }); - this.props.onFinished(true, this.state.inviteList[0]); + this.props.onFinished(true, inviteList[0]); } else { - this._startChat(this.state.inviteList); + this._startChat(inviteList); } } else { // Multi invite chat - this._startChat(this.state.inviteList); + this._startChat(inviteList); } } else { // No addresses supplied From c3566e0b49305e13e93043ad434bd7d1c5a9cee6 Mon Sep 17 00:00:00 2001 From: wmwragg Date: Wed, 14 Sep 2016 15:17:29 +0100 Subject: [PATCH 3/8] _isDmChat needs to check the passed in addrs rather than the state.inviteList as they may now differ --- src/components/views/dialogs/ChatInviteDialog.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/components/views/dialogs/ChatInviteDialog.js b/src/components/views/dialogs/ChatInviteDialog.js index d03341502c..f797131814 100644 --- a/src/components/views/dialogs/ChatInviteDialog.js +++ b/src/components/views/dialogs/ChatInviteDialog.js @@ -221,7 +221,7 @@ module.exports = React.createClass({ return null; }) .done(); - } else if (this._isDmChat()) { + } else if (this._isDmChat(addrs)) { // Start the DM chat createRoom({dmUserId: addrs[0]}) .catch(function(err) { @@ -299,8 +299,8 @@ module.exports = React.createClass({ return false; }, - _isDmChat: function() { - if (this.state.inviteList.length === 1 && Invite.getAddressType(this.state.inviteList[0]) === "mx" && !this.props.roomId) { + _isDmChat: function(addrs) { + if (addrs.length === 1 && Invite.getAddressType(addrs[0]) === "mx" && !this.props.roomId) { return true; } else { return false; From d3a709f98e733de83f712b2aba5db46c2a53f33a Mon Sep 17 00:00:00 2001 From: wmwragg Date: Wed, 14 Sep 2016 15:19:57 +0100 Subject: [PATCH 4/8] Missed a _isDmChat call when refactoring --- src/components/views/dialogs/ChatInviteDialog.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/views/dialogs/ChatInviteDialog.js b/src/components/views/dialogs/ChatInviteDialog.js index f797131814..1c8f95f6d8 100644 --- a/src/components/views/dialogs/ChatInviteDialog.js +++ b/src/components/views/dialogs/ChatInviteDialog.js @@ -83,7 +83,7 @@ module.exports = React.createClass({ } if (inviteList.length > 0) { - if (this._isDmChat()) { + if (this._isDmChat(inviteList)) { // Direct Message chat var room = this._getDirectMessageRoom(inviteList[0]); if (room) { From 75c9f707e01154a2942dd5f082cd560fa12d81d5 Mon Sep 17 00:00:00 2001 From: wmwragg Date: Wed, 14 Sep 2016 15:35:04 +0100 Subject: [PATCH 5/8] Don't show current user in queryList --- src/components/views/dialogs/ChatInviteDialog.js | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/components/views/dialogs/ChatInviteDialog.js b/src/components/views/dialogs/ChatInviteDialog.js index 1c8f95f6d8..93beb4da79 100644 --- a/src/components/views/dialogs/ChatInviteDialog.js +++ b/src/components/views/dialogs/ChatInviteDialog.js @@ -265,11 +265,16 @@ module.exports = React.createClass({ var uid = user.userId.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)) { return false; } + // ignore current user + if (uid === MatrixClientPeg.get().credentials.userId) { + return false; + } + // direct prefix matches if (name.indexOf(query) === 0 || uid.indexOf(query) === 0) { return true; From 435570a022d862ebf747f3de991ff172eb03cd36 Mon Sep 17 00:00:00 2001 From: wmwragg Date: Wed, 14 Sep 2016 16:19:09 +0100 Subject: [PATCH 6/8] Better error reporting for failed multi invites --- .../views/dialogs/ChatInviteDialog.js | 29 +++++++++++++++++-- 1 file changed, 27 insertions(+), 2 deletions(-) diff --git a/src/components/views/dialogs/ChatInviteDialog.js b/src/components/views/dialogs/ChatInviteDialog.js index 93beb4da79..0592e0635d 100644 --- a/src/components/views/dialogs/ChatInviteDialog.js +++ b/src/components/views/dialogs/ChatInviteDialog.js @@ -211,11 +211,15 @@ module.exports = React.createClass({ _startChat: function(addrs) { if (this.props.roomId) { // Invite new user to a room + var self = this; Invite.inviteMultipleToRoom(this.props.roomId, addrs) + .then(function(addrs) { + return self._showAnyInviteErrors(addrs); + }) .catch(function(err) { var ErrorDialog = sdk.getComponent("dialogs.ErrorDialog"); Modal.createDialog(ErrorDialog, { - title: "Failure to invite user", + title: "Failure to invite", description: err.toString() }); return null; @@ -239,10 +243,13 @@ module.exports = React.createClass({ createRoom().then(function(roomId) { return Invite.inviteMultipleToRoom(roomId, addrs); }) + .then(function(addrs) { + return self._showAnyInviteErrors(addrs); + }) .catch(function(err) { var ErrorDialog = sdk.getComponent("dialogs.ErrorDialog"); Modal.createDialog(ErrorDialog, { - title: "Failure to invite user", + title: "Failure to invite", description: err.toString() }); return null; @@ -312,6 +319,24 @@ module.exports = React.createClass({ } }, + _showAnyInviteErrors: function(addrs) { + // 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:", + description: errorList.join(", "), + }); + } + return addrs; + }, + render: function() { var TintableSvg = sdk.getComponent("elements.TintableSvg"); var AddressSelector = sdk.getComponent("elements.AddressSelector"); From a06896f96c7618d9e252ffee6cf95937cb1ac2d2 Mon Sep 17 00:00:00 2001 From: wmwragg Date: Wed, 14 Sep 2016 16:28:44 +0100 Subject: [PATCH 7/8] Added the room name to the error message --- src/components/views/dialogs/ChatInviteDialog.js | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/components/views/dialogs/ChatInviteDialog.js b/src/components/views/dialogs/ChatInviteDialog.js index 0592e0635d..06a46a6d29 100644 --- a/src/components/views/dialogs/ChatInviteDialog.js +++ b/src/components/views/dialogs/ChatInviteDialog.js @@ -214,7 +214,8 @@ module.exports = React.createClass({ var self = this; Invite.inviteMultipleToRoom(this.props.roomId, addrs) .then(function(addrs) { - return self._showAnyInviteErrors(addrs); + var room = MatrixClientPeg.get().getRoom(this.props.roomId); + return self._showAnyInviteErrors(addrs, room); }) .catch(function(err) { var ErrorDialog = sdk.getComponent("dialogs.ErrorDialog"); @@ -240,11 +241,13 @@ module.exports = React.createClass({ } else { // Start multi user chat var self = this; + var room; createRoom().then(function(roomId) { + room = MatrixClientPeg.get().getRoom(roomId); return Invite.inviteMultipleToRoom(roomId, addrs); }) .then(function(addrs) { - return self._showAnyInviteErrors(addrs); + return self._showAnyInviteErrors(addrs, room); }) .catch(function(err) { var ErrorDialog = sdk.getComponent("dialogs.ErrorDialog"); @@ -319,7 +322,7 @@ module.exports = React.createClass({ } }, - _showAnyInviteErrors: function(addrs) { + _showAnyInviteErrors: function(addrs, room) { // Show user any errors var errorList = []; for (var addr in addrs) { @@ -327,10 +330,11 @@ module.exports = React.createClass({ errorList.push(addr); } } + if (errorList.length > 0) { var ErrorDialog = sdk.getComponent("dialogs.ErrorDialog"); Modal.createDialog(ErrorDialog, { - title: "Failed to invite the following users:", + title: "Failed to invite the following users to the " + room.name + " room:", description: errorList.join(", "), }); } From 6a9194846945303a88025fc1cdad5c6fff45f761 Mon Sep 17 00:00:00 2001 From: wmwragg Date: Wed, 14 Sep 2016 18:01:07 +0100 Subject: [PATCH 8/8] Removed the Email (Invite by email) section --- .../views/rooms/InviteMemberList.js | 28 +++++++++---------- .../views/rooms/SearchableEntityList.js | 18 ++---------- 2 files changed, 17 insertions(+), 29 deletions(-) diff --git a/src/components/views/rooms/InviteMemberList.js b/src/components/views/rooms/InviteMemberList.js index 1e5b19fdf1..ee5eabbeab 100644 --- a/src/components/views/rooms/InviteMemberList.js +++ b/src/components/views/rooms/InviteMemberList.js @@ -90,7 +90,7 @@ module.exports = React.createClass({ var EntityTile = sdk.getComponent("rooms.EntityTile"); var BaseAvatar = sdk.getComponent("avatars.BaseAvatar"); - var label = input; + // var label = input; // if (input[0] === "@") { // label = input; // } @@ -98,16 +98,16 @@ module.exports = React.createClass({ // label = "Email: " + input; // } - this._emailEntity = new Entities.newEntity( - } - className="mx_EntityTile_invitePlaceholder" - presenceState="online" onClick={this.onThirdPartyInvite} name={"Invite by email"} - />, - function(query) { - return true; // always show this - } - ); + // this._emailEntity = new Entities.newEntity( + // } + // className="mx_EntityTile_invitePlaceholder" + // presenceState="online" onClick={this.onThirdPartyInvite} name={"Invite by email"} + // />, + // function(query) { + // return true; // always show this + // } + // ); this.props.onSearchQueryChanged(input); }, @@ -117,9 +117,9 @@ module.exports = React.createClass({ var entities = Entities.fromUsers(this._userList || [], true, this.props.onInvite); // Add an "Email: foo@bar.com" tile as the first tile - if (this._emailEntity) { - entities.unshift(this._emailEntity); - } + // if (this._emailEntity) { + // entities.unshift(this._emailEntity); + // } return ( { - if (this._blurTimeout) { - 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 - ); - } } + onFocus= {() => { this.setState({ focused: true }) }} + onBlur= {() => { this.setState({ focused: false }) }} placeholder={this.props.searchPlaceholderText} /> );