From c3f786cc5ef2f60cab13f07ea0fdffa39544dd08 Mon Sep 17 00:00:00 2001 From: Kegan Dougal Date: Fri, 22 Jan 2016 17:20:52 +0000 Subject: [PATCH 1/3] Add a tile to the invitee list which represents an email tile --- src/Entities.js | 9 +++++++ src/components/views/rooms/MemberList.js | 22 +++++++++++++-- .../views/rooms/SearchableEntityList.js | 27 ++++++++++++++----- 3 files changed, 49 insertions(+), 9 deletions(-) diff --git a/src/Entities.js b/src/Entities.js index 5a666b1493..ac3c976797 100644 --- a/src/Entities.js +++ b/src/Entities.js @@ -108,6 +108,15 @@ class UserEntity extends Entity { module.exports = { + newEntity: function(jsx, matchFn) { + var entity = new Entity(); + entity.getJsx = function() { + return jsx; + }; + entity.matches = matchFn; + return entity; + }, + /** * @param {RoomMember[]} members * @return {Entity[]} diff --git a/src/components/views/rooms/MemberList.js b/src/components/views/rooms/MemberList.js index 9172d43a24..d58a5df25c 100644 --- a/src/components/views/rooms/MemberList.js +++ b/src/components/views/rooms/MemberList.js @@ -311,6 +311,17 @@ module.exports = React.createClass({ }, onSearchQueryChanged: function(input) { + var EntityTile = sdk.getComponent("rooms.EntityTile"); + this._emailEntity = new Entities.newEntity( + , + function(query) { + return true; // always show this + } + ); + this.setState({ searchQuery: input }); @@ -369,12 +380,19 @@ module.exports = React.createClass({ ); } else { var SearchableEntityList = sdk.getComponent("rooms.SearchableEntityList"); - + var entities = Entities.fromUsers(this.userList || [], true, this.onInvite); + + // Add an "Email: foo@bar.com" tile as the first tile + if (this._emailEntity) { + entities.unshift(this._emailEntity); + } + + return ( + entities={entities} /> ); } }, diff --git a/src/components/views/rooms/SearchableEntityList.js b/src/components/views/rooms/SearchableEntityList.js index efaebfd655..b6f8938967 100644 --- a/src/components/views/rooms/SearchableEntityList.js +++ b/src/components/views/rooms/SearchableEntityList.js @@ -46,10 +46,17 @@ var SearchableEntityList = React.createClass({ getInitialState: function() { return { query: "", - results: this.getSearchResults("") + results: this.getSearchResults("", this.props.entities) }; }, + componentWillReceiveProps: function(newProps) { + // recalculate the search results in case we got new entities + this.setState({ + results: this.getSearchResults(this.state.query, newProps.entities) + }); + }, + componentWillUnmount: function() { // pretend the query box was blanked out else filters could still be // applied to other components which rely on onQueryChanged. @@ -63,7 +70,7 @@ var SearchableEntityList = React.createClass({ setQuery: function(input) { this.setState({ query: input, - results: this.getSearchResults(input) + results: this.getSearchResults(input, this.props.entities) }); }, @@ -71,9 +78,15 @@ var SearchableEntityList = React.createClass({ var q = ev.target.value; this.setState({ query: q, - results: this.getSearchResults(q) + results: this.getSearchResults(q, this.props.entities) + }, () => { + // invoke the callback AFTER we've flushed the new state. We need to + // do this because onQueryChanged can result in new props being passed + // to this component, which will then try to recalculate the search + // list. If we do this without flushing, we'll recalc with the last + // search term and not the current one! + this.props.onQueryChanged(q); }); - this.props.onQueryChanged(q); }, onQuerySubmit: function(ev) { @@ -81,11 +94,11 @@ var SearchableEntityList = React.createClass({ this.props.onSubmit(this.state.query); }, - getSearchResults: function(query) { + getSearchResults: function(query, entities) { if (!query || query.length === 0) { - return this.props.emptyQueryShowsAll ? this.props.entities : [] + return this.props.emptyQueryShowsAll ? entities : [] } - return this.props.entities.filter(function(e) { + return entities.filter(function(e) { return e.matches(query); }); }, From e78c1fba87d8d2761f3601e9d59e03f51bdc1557 Mon Sep 17 00:00:00 2001 From: Kegan Dougal Date: Fri, 22 Jan 2016 17:28:23 +0000 Subject: [PATCH 2/3] Hide 'Email: ' is the first char is @ --- src/components/views/rooms/MemberList.js | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/src/components/views/rooms/MemberList.js b/src/components/views/rooms/MemberList.js index d58a5df25c..7990b71bd7 100644 --- a/src/components/views/rooms/MemberList.js +++ b/src/components/views/rooms/MemberList.js @@ -312,11 +312,18 @@ module.exports = React.createClass({ onSearchQueryChanged: function(input) { var EntityTile = sdk.getComponent("rooms.EntityTile"); + + var label; + if (input[0] === "@") { + label = input; + } + else { + label = "Email: " + input; + } + this._emailEntity = new Entities.newEntity( - , + , function(query) { return true; // always show this } From 437280020c6566bd4e877bd3ee61ab4c74b7f91c Mon Sep 17 00:00:00 2001 From: Kegan Dougal Date: Fri, 22 Jan 2016 17:32:43 +0000 Subject: [PATCH 3/3] Turn off autocomplete for search list --- src/components/views/rooms/SearchableEntityList.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/views/rooms/SearchableEntityList.js b/src/components/views/rooms/SearchableEntityList.js index b6f8938967..b2e20f23db 100644 --- a/src/components/views/rooms/SearchableEntityList.js +++ b/src/components/views/rooms/SearchableEntityList.js @@ -108,7 +108,7 @@ var SearchableEntityList = React.createClass({ if (this.props.showInputBox) { inputBox = ( -
+