diff options
| author | Henry Jameson <me@hjkos.com> | 2019-07-28 13:30:29 +0300 |
|---|---|---|
| committer | Henry Jameson <me@hjkos.com> | 2019-07-28 13:30:29 +0300 |
| commit | b3aff9bbae77b2fd34b2267ce9196c0ebd3e4691 (patch) | |
| tree | 1219e00b6bfe6784add1578a3bc986c1dbb5f34d /src/components/emoji-input/suggestor.js | |
| parent | 7f6f025792dcb3a10c94c8952d0312abd0b46989 (diff) | |
| parent | 4827e4d972f8ee11e606693e24ae4ca21711c6b1 (diff) | |
Merge remote-tracking branch 'upstream/develop' into emoji-selector-update
* upstream/develop: (469 commits)
Feature/add sticker picker
guard more secure routes
guard secure routes by redirecting to root
closest can returns itself as well
find inside status-content div only
try to use the closest a tag as target
Update es.json
Also apply keyword filter to subjects
Remove files I accidentally pushed in
fix issues caused by merges in usersearch on @
Add user search at
fix eslint warnings
remove vue-popperjs
fix moderation menu partially hidden by usercard boundary
migrate popper css
rewrite ModerationTools using v-tooltip
make popover position for status action dropdow relative to parent node
rewrite ExtraButtons using v-tooltip
install v-tooltip
i18n/Update pedantic Japanese translation
...
Diffstat (limited to 'src/components/emoji-input/suggestor.js')
| -rw-r--r-- | src/components/emoji-input/suggestor.js | 94 |
1 files changed, 94 insertions, 0 deletions
diff --git a/src/components/emoji-input/suggestor.js b/src/components/emoji-input/suggestor.js new file mode 100644 index 00000000..aec5c39d --- /dev/null +++ b/src/components/emoji-input/suggestor.js @@ -0,0 +1,94 @@ +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: + * data.emoji - optional, an array of all emoji available i.e. + * (state.instance.emoji + state.instance.customEmoji) + * data.users - optional, an array of all known users + * updateUsersList - optional, a function to search and append to users + * + * Depending on data present one or both (or none) can be present, so if field + * doesn't support user linking you can just provide only emoji. + */ + +const debounceUserSearch = debounce((data, input) => { + data.updateUsersList(input) +}, 500, { leading: true, trailing: false }) + +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) + } + return [] +} + +export const suggestEmoji = emojis => input => { + const noPrefix = input.toLowerCase().substr(1) + return emojis + .filter(({ displayText }) => displayText.toLowerCase().startsWith(noPrefix)) + .sort((a, b) => { + let aScore = 0 + let bScore = 0 + + // Make custom emojis a priority + aScore += a.imageUrl ? 10 : 0 + bScore += b.imageUrl ? 10 : 0 + + // Sort alphabetically + const alphabetically = a.displayText > b.displayText ? 1 : -1 + + return bScore - aScore + alphabetically + }) +} + +export const suggestUsers = data => input => { + const noPrefix = input.toLowerCase().substr(1) + const users = data.users + + const newUsers = users.filter( + user => + user.screen_name.toLowerCase().startsWith(noPrefix) || + user.name.toLowerCase().startsWith(noPrefix) + + /* 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 + + // 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 + + 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 + + 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 + ' ' + })) + + // BE search users if there are no matches + if (newUsers.length === 0 && data.updateUsersList) { + debounceUserSearch(data, noPrefix) + } + return newUsers + /* eslint-enable camelcase */ +} |
