From c4fd04efb642b42b5829e25b4fc5d8b389fff8de Mon Sep 17 00:00:00 2001 From: Harrison Healey Date: Tue, 4 Apr 2017 00:22:09 -0400 Subject: Fixed channel autocomplete flickering (#5961) --- .../components/suggestion/at_mention_provider.jsx | 101 +++++++++++---------- .../suggestion/channel_mention_provider.jsx | 6 +- webapp/components/suggestion/emoticon_provider.jsx | 6 +- .../suggestion/search_channel_provider.jsx | 2 + .../components/suggestion/search_user_provider.jsx | 2 + webapp/components/suggestion/suggestion_box.jsx | 7 +- webapp/stores/suggestion_store.jsx | 4 +- 7 files changed, 72 insertions(+), 56 deletions(-) (limited to 'webapp') diff --git a/webapp/components/suggestion/at_mention_provider.jsx b/webapp/components/suggestion/at_mention_provider.jsx index 5f79e08ae..68a5c64bc 100644 --- a/webapp/components/suggestion/at_mention_provider.jsx +++ b/webapp/components/suggestion/at_mention_provider.jsx @@ -6,7 +6,6 @@ import Provider from './provider.jsx'; import ChannelStore from 'stores/channel_store.jsx'; import UserStore from 'stores/user_store.jsx'; -import SuggestionStore from 'stores/suggestion_store.jsx'; import {autocompleteUsersInChannel} from 'actions/user_actions.jsx'; @@ -112,58 +111,60 @@ export default class AtMentionProvider extends Provider { handlePretextChanged(suggestionId, pretext) { const captured = XRegExp.cache('(?:^|\\W)@([\\pL\\d\\-_.]*)$', 'i').exec(pretext.toLowerCase()); - if (captured) { - const prefix = captured[1]; - - this.startNewRequest(prefix); - - autocompleteUsersInChannel( - prefix, - this.channelId, - (data) => { - if (this.shouldCancelDispatch(prefix)) { - return; - } - - const members = data.in_channel; - for (const id of Object.keys(members)) { - members[id].type = Constants.MENTION_MEMBERS; - } - - const nonmembers = data.out_of_channel; - for (const id of Object.keys(nonmembers)) { - nonmembers[id].type = Constants.MENTION_NONMEMBERS; - } - - let specialMentions = []; - if (!pretext.startsWith('/msg')) { - specialMentions = ['here', 'channel', 'all'].filter((item) => { - return item.startsWith(prefix); - }).map((name) => { - return {username: name, type: Constants.MENTION_SPECIAL}; - }); - } - - let users = members.concat(specialMentions).concat(nonmembers); - const me = UserStore.getCurrentUser(); - users = users.filter((user) => { - return user.id !== me.id; - }); + if (!captured) { + return false; + } + + const prefix = captured[1]; + + this.startNewRequest(prefix); + + autocompleteUsersInChannel( + prefix, + this.channelId, + (data) => { + if (this.shouldCancelDispatch(prefix)) { + return; + } + + const members = data.in_channel; + for (const id of Object.keys(members)) { + members[id].type = Constants.MENTION_MEMBERS; + } - const mentions = users.map((user) => '@' + user.username); + const nonmembers = data.out_of_channel; + for (const id of Object.keys(nonmembers)) { + nonmembers[id].type = Constants.MENTION_NONMEMBERS; + } - AppDispatcher.handleServerAction({ - type: ActionTypes.SUGGESTION_RECEIVED_SUGGESTIONS, - id: suggestionId, - matchedPretext: `@${captured[1]}`, - terms: mentions, - items: users, - component: AtMentionSuggestion + let specialMentions = []; + if (!pretext.startsWith('/msg')) { + specialMentions = ['here', 'channel', 'all'].filter((item) => { + return item.startsWith(prefix); + }).map((name) => { + return {username: name, type: Constants.MENTION_SPECIAL}; }); } - ); - } else { - SuggestionStore.clearSuggestions(suggestionId); - } + + let users = members.concat(specialMentions).concat(nonmembers); + const me = UserStore.getCurrentUser(); + users = users.filter((user) => { + return user.id !== me.id; + }); + + const mentions = users.map((user) => '@' + user.username); + + AppDispatcher.handleServerAction({ + type: ActionTypes.SUGGESTION_RECEIVED_SUGGESTIONS, + id: suggestionId, + matchedPretext: `@${captured[1]}`, + terms: mentions, + items: users, + component: AtMentionSuggestion + }); + } + ); + + return true; } } diff --git a/webapp/components/suggestion/channel_mention_provider.jsx b/webapp/components/suggestion/channel_mention_provider.jsx index f1d6d9e76..7ea5f7374 100644 --- a/webapp/components/suggestion/channel_mention_provider.jsx +++ b/webapp/components/suggestion/channel_mention_provider.jsx @@ -62,12 +62,12 @@ export default class ChannelMentionProvider extends Provider { if (!captured) { // Not a channel mention - return; + return false; } if (this.lastCompletedWord && captured[0].startsWith(this.lastCompletedWord)) { // It appears we're still matching a channel handle that we already completed - return; + return false; } // Clear the last completed word since we've started to match new text @@ -125,6 +125,8 @@ export default class ChannelMentionProvider extends Provider { }); } ); + + return true; } handleCompleteWord(term) { diff --git a/webapp/components/suggestion/emoticon_provider.jsx b/webapp/components/suggestion/emoticon_provider.jsx index 6a4332e2f..6cead0abb 100644 --- a/webapp/components/suggestion/emoticon_provider.jsx +++ b/webapp/components/suggestion/emoticon_provider.jsx @@ -55,7 +55,7 @@ export default class EmoticonProvider { if (partialName.length < MIN_EMOTICON_LENGTH) { SuggestionStore.clearSuggestions(suggestionId); - return; + return false; } const matched = []; @@ -117,6 +117,10 @@ export default class EmoticonProvider { if (hasSuggestions) { // force the selection to be cleared since the order of elements may have changed SuggestionStore.clearSelection(suggestionId); + + return true; } + + return false; } } diff --git a/webapp/components/suggestion/search_channel_provider.jsx b/webapp/components/suggestion/search_channel_provider.jsx index c0ec06181..06b332127 100644 --- a/webapp/components/suggestion/search_channel_provider.jsx +++ b/webapp/components/suggestion/search_channel_provider.jsx @@ -85,5 +85,7 @@ export default class SearchChannelProvider extends Provider { } ); } + + return Boolean(captured); } } diff --git a/webapp/components/suggestion/search_user_provider.jsx b/webapp/components/suggestion/search_user_provider.jsx index 70808ca26..f1b45c0d6 100644 --- a/webapp/components/suggestion/search_user_provider.jsx +++ b/webapp/components/suggestion/search_user_provider.jsx @@ -86,5 +86,7 @@ export default class SearchUserProvider extends Provider { } ); } + + return Boolean(captured); } } diff --git a/webapp/components/suggestion/suggestion_box.jsx b/webapp/components/suggestion/suggestion_box.jsx index 2ac842846..e6179d5e5 100644 --- a/webapp/components/suggestion/suggestion_box.jsx +++ b/webapp/components/suggestion/suggestion_box.jsx @@ -185,8 +185,13 @@ export default class SuggestionBox extends React.Component { } handlePretextChanged(pretext) { + let handled = false; for (const provider of this.props.providers) { - provider.handlePretextChanged(this.suggestionId, pretext); + handled = provider.handlePretextChanged(this.suggestionId, pretext) || handled; + } + + if (!handled) { + SuggestionStore.clearSuggestions(this.suggestionId); } } diff --git a/webapp/stores/suggestion_store.jsx b/webapp/stores/suggestion_store.jsx index a0cd88370..5a8ea3006 100644 --- a/webapp/stores/suggestion_store.jsx +++ b/webapp/stores/suggestion_store.jsx @@ -227,8 +227,8 @@ class SuggestionStore extends EventEmitter { switch (type) { case ActionTypes.SUGGESTION_PRETEXT_CHANGED: - // Clear the suggestions if the pretext is empty or has whitespace - if (other.pretext === '' || (/\s/g.test(other.pretext))) { + // Clear the suggestions if the pretext is empty or ends with whitespace + if (other.pretext === '') { this.clearSuggestions(id); } -- cgit v1.2.3-1-g7c22