From c3f786cc5ef2f60cab13f07ea0fdffa39544dd08 Mon Sep 17 00:00:00 2001 From: Kegan Dougal Date: Fri, 22 Jan 2016 17:20:52 +0000 Subject: [PATCH] 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); }); },