diff options
| author | Henry Jameson <me@hjkos.com> | 2021-02-01 19:39:57 +0200 |
|---|---|---|
| committer | Henry Jameson <me@hjkos.com> | 2021-02-01 19:39:57 +0200 |
| commit | 8958f386bef9317ff5782fa0f16164d7fbc2af21 (patch) | |
| tree | 8c33fed5331c18023d608fbb366c464783559220 /src/components/emoji_input/suggestor.js | |
| parent | e695506c514e49964dfd81c7db5c5b4d4918f47d (diff) | |
| parent | de66267a07eb018cc0309ff6f9dd896d53ba3ff4 (diff) | |
Merge remote-tracking branch 'origin/develop' into settings-changed
* origin/develop: (306 commits)
fallback if shadows aren't defined
Translated using Weblate (Chinese (Traditional))
Translated using Weblate (Ukrainian)
Translated using Weblate (Italian)
Translated using Weblate (Ukrainian)
Translated using Weblate (Portuguese)
Translated using Weblate (Italian)
Translated using Weblate (Russian)
Translated using Weblate (Portuguese)
Translated using Weblate (Russian)
Translated using Weblate (Portuguese)
Translated using Weblate (Portuguese)
Translated using Weblate (Portuguese)
Translated using Weblate (Portuguese)
Translated using Weblate (Portuguese)
Translated using Weblate (Portuguese)
Translated using Weblate (Portuguese)
Translated using Weblate (Portuguese)
Translated using Weblate (Portuguese)
Translated using Weblate (Portuguese)
...
Diffstat (limited to 'src/components/emoji_input/suggestor.js')
| -rw-r--r-- | src/components/emoji_input/suggestor.js | 124 |
1 files changed, 74 insertions, 50 deletions
diff --git a/src/components/emoji_input/suggestor.js b/src/components/emoji_input/suggestor.js index 8330345b..14a2b41e 100644 --- a/src/components/emoji_input/suggestor.js +++ b/src/components/emoji_input/suggestor.js @@ -1,4 +1,3 @@ -import { debounce } from 'lodash' /** * suggest - generates a suggestor function to be used by emoji-input * data: object providing source information for specific types of suggestions: @@ -11,19 +10,19 @@ import { debounce } from 'lodash' * doesn't support user linking you can just provide only emoji. */ -const debounceUserSearch = debounce((data, input) => { - data.updateUsersList(input) -}, 500) - -export default data => input => { - const firstChar = input[0] - if (firstChar === ':' && data.emoji) { - return suggestEmoji(data.emoji)(input) - } - if (firstChar === '@' && data.users) { - return suggestUsers(data)(input) +export default data => { + const emojiCurry = suggestEmoji(data.emoji) + const usersCurry = data.store && suggestUsers(data.store) + return input => { + const firstChar = input[0] + if (firstChar === ':' && data.emoji) { + return emojiCurry(input) + } + if (firstChar === '@' && usersCurry) { + return usersCurry(input) + } + return [] } - return [] } export const suggestEmoji = emojis => input => { @@ -57,50 +56,75 @@ export const suggestEmoji = emojis => input => { }) } -export const suggestUsers = data => input => { - const noPrefix = input.toLowerCase().substr(1) - const users = data.users +export const suggestUsers = ({ dispatch, state }) => { + // Keep some persistent values in closure, most importantly for the + // custom debounce to work. Lodash debounce does not return a promise. + let suggestions = [] + let previousQuery = '' + let timeout = null + let cancelUserSearch = null - const newUsers = users.filter( - user => - user.screen_name.toLowerCase().startsWith(noPrefix) || - user.name.toLowerCase().startsWith(noPrefix) + const userSearch = (query) => dispatch('searchUsers', { query }) + const debounceUserSearch = (query) => { + cancelUserSearch && cancelUserSearch() + return new Promise((resolve, reject) => { + timeout = setTimeout(() => { + userSearch(query).then(resolve).catch(reject) + }, 300) + cancelUserSearch = () => { + clearTimeout(timeout) + resolve([]) + } + }) + } - /* taking only 20 results so that sorting is a bit cheaper, we display - * only 5 anyway. could be inaccurate, but we ideally we should query - * backend anyway - */ - ).slice(0, 20).sort((a, b) => { - let aScore = 0 - let bScore = 0 + return async input => { + const noPrefix = input.toLowerCase().substr(1) + if (previousQuery === noPrefix) return suggestions + + suggestions = [] + previousQuery = noPrefix + // Fetch more and wait, don't fetch if there's the 2nd @ because + // the backend user search can't deal with it. + // Reference semantics make it so that we get the updated data after + // the await. + if (!noPrefix.includes('@')) { + await debounceUserSearch(noPrefix) + } + + const newSuggestions = state.users.users.filter( + user => + user.screen_name.toLowerCase().startsWith(noPrefix) || + user.name.toLowerCase().startsWith(noPrefix) + ).slice(0, 20).sort((a, b) => { + let aScore = 0 + let bScore = 0 - // Matches on screen name (i.e. user@instance) makes a priority - aScore += a.screen_name.toLowerCase().startsWith(noPrefix) ? 2 : 0 - bScore += b.screen_name.toLowerCase().startsWith(noPrefix) ? 2 : 0 + // Matches on screen name (i.e. user@instance) makes a priority + aScore += a.screen_name.toLowerCase().startsWith(noPrefix) ? 2 : 0 + bScore += b.screen_name.toLowerCase().startsWith(noPrefix) ? 2 : 0 - // Matches on name takes second priority - aScore += a.name.toLowerCase().startsWith(noPrefix) ? 1 : 0 - bScore += b.name.toLowerCase().startsWith(noPrefix) ? 1 : 0 + // Matches on name takes second priority + aScore += a.name.toLowerCase().startsWith(noPrefix) ? 1 : 0 + bScore += b.name.toLowerCase().startsWith(noPrefix) ? 1 : 0 - const diff = (bScore - aScore) * 10 + const diff = (bScore - aScore) * 10 - // Then sort alphabetically - const nameAlphabetically = a.name > b.name ? 1 : -1 - const screenNameAlphabetically = a.screen_name > b.screen_name ? 1 : -1 + // Then sort alphabetically + const nameAlphabetically = a.name > b.name ? 1 : -1 + const screenNameAlphabetically = a.screen_name > b.screen_name ? 1 : -1 - return diff + nameAlphabetically + screenNameAlphabetically - /* eslint-disable camelcase */ - }).map(({ screen_name, name, profile_image_url_original }) => ({ - displayText: screen_name, - detailText: name, - imageUrl: profile_image_url_original, - replacement: '@' + screen_name + ' ' - })) + return diff + nameAlphabetically + screenNameAlphabetically + /* eslint-disable camelcase */ + }).map(({ screen_name, name, profile_image_url_original }) => ({ + displayText: screen_name, + detailText: name, + imageUrl: profile_image_url_original, + replacement: '@' + screen_name + ' ' + })) + /* eslint-enable camelcase */ - // BE search users to get more comprehensive results - if (data.updateUsersList) { - debounceUserSearch(data, noPrefix) + suggestions = newSuggestions || [] + return suggestions } - return newUsers - /* eslint-enable camelcase */ } |
