Skip to content

Commit

Permalink
Fixed channel autocomplete flickering (#5961)
Browse files Browse the repository at this point in the history
  • Loading branch information
hmhealey authored and coreyhulen committed Apr 4, 2017
1 parent 5cd0d5b commit c4fd04e
Show file tree
Hide file tree
Showing 7 changed files with 72 additions and 56 deletions.
101 changes: 51 additions & 50 deletions webapp/components/suggestion/at_mention_provider.jsx
Expand Up @@ -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';

Expand Down Expand Up @@ -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;
}
}
6 changes: 4 additions & 2 deletions webapp/components/suggestion/channel_mention_provider.jsx
Expand Up @@ -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
Expand Down Expand Up @@ -125,6 +125,8 @@ export default class ChannelMentionProvider extends Provider {
});
}
);

return true;
}

handleCompleteWord(term) {
Expand Down
6 changes: 5 additions & 1 deletion webapp/components/suggestion/emoticon_provider.jsx
Expand Up @@ -55,7 +55,7 @@ export default class EmoticonProvider {

if (partialName.length < MIN_EMOTICON_LENGTH) {
SuggestionStore.clearSuggestions(suggestionId);
return;
return false;
}

const matched = [];
Expand Down Expand Up @@ -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;
}
}
2 changes: 2 additions & 0 deletions webapp/components/suggestion/search_channel_provider.jsx
Expand Up @@ -85,5 +85,7 @@ export default class SearchChannelProvider extends Provider {
}
);
}

return Boolean(captured);
}
}
2 changes: 2 additions & 0 deletions webapp/components/suggestion/search_user_provider.jsx
Expand Up @@ -86,5 +86,7 @@ export default class SearchUserProvider extends Provider {
}
);
}

return Boolean(captured);
}
}
7 changes: 6 additions & 1 deletion webapp/components/suggestion/suggestion_box.jsx
Expand Up @@ -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);
}
}

Expand Down
4 changes: 2 additions & 2 deletions webapp/stores/suggestion_store.jsx
Expand Up @@ -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);
}

Expand Down

0 comments on commit c4fd04e

Please sign in to comment.