From 0a79a747730bb4a10eb2544412dab68a10602240 Mon Sep 17 00:00:00 2001 From: Tusooa Zhu Date: Mon, 29 Aug 2022 18:46:41 -0400 Subject: Use dedicated indicator for non-ascii domain names --- src/components/emoji_input/suggestor.js | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) (limited to 'src/components/emoji_input/suggestor.js') diff --git a/src/components/emoji_input/suggestor.js b/src/components/emoji_input/suggestor.js index e8efbd1e..0ddb4d68 100644 --- a/src/components/emoji_input/suggestor.js +++ b/src/components/emoji_input/suggestor.js @@ -116,11 +116,12 @@ export const suggestUsers = ({ dispatch, state }) => { return diff + nameAlphabetically + screenNameAlphabetically /* eslint-disable camelcase */ - }).map(({ screen_name, screen_name_ui, name, profile_image_url_original }) => ({ - displayText: screen_name_ui, - detailText: name, - imageUrl: profile_image_url_original, - replacement: '@' + screen_name + ' ' + }).map((user) => ({ + user, + displayText: user.screen_name_ui, + detailText: user.name, + imageUrl: user.profile_image_url_original, + replacement: '@' + user.screen_name + ' ' })) /* eslint-enable camelcase */ -- cgit v1.2.3-70-g09d2 From 8f4f02683f89129cf6f28f2059122cff7db02242 Mon Sep 17 00:00:00 2001 From: Tusooa Zhu Date: Sat, 8 Jan 2022 16:55:00 -0500 Subject: Make emoji picker use grouped unicode emojis --- src/components/emoji_input/suggestor.js | 2 +- src/components/emoji_picker/emoji_picker.js | 16 +++++---- .../post_status_form/post_status_form.js | 6 ++-- src/components/react_button/react_button.js | 4 +-- src/components/settings_modal/tabs/profile_tab.js | 4 +-- src/modules/instance.js | 38 ++++++++++++++++++---- 6 files changed, 48 insertions(+), 22 deletions(-) (limited to 'src/components/emoji_input/suggestor.js') diff --git a/src/components/emoji_input/suggestor.js b/src/components/emoji_input/suggestor.js index 0ddb4d68..1765f843 100644 --- a/src/components/emoji_input/suggestor.js +++ b/src/components/emoji_input/suggestor.js @@ -2,7 +2,7 @@ * 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) + * (getters.standardEmojiList + state.instance.customEmoji) * data.users - optional, an array of all known users * updateUsersList - optional, a function to search and append to users * diff --git a/src/components/emoji_picker/emoji_picker.js b/src/components/emoji_picker/emoji_picker.js index 26c767ac..4990afb3 100644 --- a/src/components/emoji_picker/emoji_picker.js +++ b/src/components/emoji_picker/emoji_picker.js @@ -214,16 +214,18 @@ const EmojiPicker = { defaultGroup () { return Object.keys(this.allCustomGroups)[0] }, + unicodeEmojiGroups () { + return this.$store.getters.standardEmojiGroupList.map(group => ({ + id: `standard-${group.id}`, + text: this.$t(`emoji.unicode_groups.${group.id}`), + icon: 'box-open', + emojis: group.emojis + })) + }, allEmojiGroups () { - const standardEmojis = this.$store.state.instance.emoji || [] return Object.entries(this.allCustomGroups) .map(([_, v]) => v) - .concat({ - id: 'standard', - text: this.$t('emoji.unicode'), - icon: 'box-open', - emojis: filterByKeyword(standardEmojis, this.keyword) - }) + .concat(this.unicodeEmojiGroups) }, filteredEmojiGroups () { return this.allEmojiGroups diff --git a/src/components/post_status_form/post_status_form.js b/src/components/post_status_form/post_status_form.js index 77f73d04..5c536b74 100644 --- a/src/components/post_status_form/post_status_form.js +++ b/src/components/post_status_form/post_status_form.js @@ -189,7 +189,7 @@ const PostStatusForm = { emojiUserSuggestor () { return suggestor({ emoji: [ - ...this.$store.state.instance.emoji, + ...this.$store.getters.standardEmojiList, ...this.$store.state.instance.customEmoji ], store: this.$store @@ -198,13 +198,13 @@ const PostStatusForm = { emojiSuggestor () { return suggestor({ emoji: [ - ...this.$store.state.instance.emoji, + ...this.$store.getters.standardEmojiList, ...this.$store.state.instance.customEmoji ] }) }, emoji () { - return this.$store.state.instance.emoji || [] + return this.$store.getters.standardEmojiList || [] }, customEmoji () { return this.$store.state.instance.customEmoji || [] diff --git a/src/components/react_button/react_button.js b/src/components/react_button/react_button.js index 5e052e1e..e65bfd93 100644 --- a/src/components/react_button/react_button.js +++ b/src/components/react_button/react_button.js @@ -59,7 +59,7 @@ const ReactButton = { if (this.filterWord !== '') { const filterWordLowercase = trim(this.filterWord.toLowerCase()) const orderedEmojiList = [] - for (const emoji of this.$store.state.instance.emoji) { + for (const emoji of this.$store.getters.standardEmojiList) { if (emoji.replacement === this.filterWord) return [emoji] const indexOfFilterWord = emoji.displayText.toLowerCase().indexOf(filterWordLowercase) @@ -72,7 +72,7 @@ const ReactButton = { } return orderedEmojiList.flat() } - return this.$store.state.instance.emoji || [] + return this.$store.getters.standardEmojiList || [] }, mergedConfig () { return this.$store.getters.mergedConfig diff --git a/src/components/settings_modal/tabs/profile_tab.js b/src/components/settings_modal/tabs/profile_tab.js index 376248ef..b86faef0 100644 --- a/src/components/settings_modal/tabs/profile_tab.js +++ b/src/components/settings_modal/tabs/profile_tab.js @@ -64,7 +64,7 @@ const ProfileTab = { emojiUserSuggestor () { return suggestor({ emoji: [ - ...this.$store.state.instance.emoji, + ...this.$store.getters.standardEmojiList, ...this.$store.state.instance.customEmoji ], store: this.$store @@ -73,7 +73,7 @@ const ProfileTab = { emojiSuggestor () { return suggestor({ emoji: [ - ...this.$store.state.instance.emoji, + ...this.$store.getters.standardEmojiList, ...this.$store.state.instance.customEmoji ] }) diff --git a/src/modules/instance.js b/src/modules/instance.js index a7a91d99..2fcb059c 100644 --- a/src/modules/instance.js +++ b/src/modules/instance.js @@ -3,6 +3,18 @@ import { CURRENT_VERSION } from '../services/theme_data/theme_data.service.js' import apiService from '../services/api/api.service.js' import { instanceDefaultProperties } from './config.js' +const SORTED_EMOJI_GROUP_IDS = [ + 'smileys-and-emotion', + 'people-and-body', + 'animals-and-nature', + 'food-and-drink', + 'travel-and-places', + 'activities', + 'objects', + 'symbols', + 'flags' +] + const defaultState = { // Stuff from apiConfig name: 'Pleroma FE', @@ -64,7 +76,7 @@ const defaultState = { // Nasty stuff customEmoji: [], customEmojiFetched: false, - emoji: [], + emoji: {}, emojiFetched: false, pleromaBackend: true, postFormats: [], @@ -139,6 +151,17 @@ const instance = { return res }, {}) }, + standardEmojiList (state) { + return SORTED_EMOJI_GROUP_IDS + .map(groupId => state.emoji[groupId] || []) + .reduce((a, b) => a.concat(b), []) + }, + standardEmojiGroupList (state) { + return SORTED_EMOJI_GROUP_IDS.map(groupId => ({ + id: groupId, + emojis: state.emoji[groupId] || [] + })) + }, instanceDomain (state) { return new URL(state.server).hostname } @@ -165,13 +188,14 @@ const instance = { const res = await window.fetch('/static/emoji.json') if (res.ok) { const values = await res.json() - const emoji = Object.keys(values).map((key) => { - return { - displayText: key, + const emoji = Object.keys(values).reduce((res, groupId) => { + res[groupId] = values[groupId].map(e => ({ + displayText: e.name, imageUrl: false, - replacement: values[key] - } - }).sort((a, b) => a.name > b.name ? 1 : -1) + replacement: e.emoji + })) + return res + }, {}) commit('setInstanceOption', { name: 'emoji', value: emoji }) } else { throw (res) -- cgit v1.2.3-70-g09d2 From a7f836a64e334d6c46ed1e12c7bf9b2ff4a09c7e Mon Sep 17 00:00:00 2001 From: Tusooa Zhu Date: Wed, 21 Sep 2022 23:16:33 -0400 Subject: Make suggestor suggest according to cldr annotations --- src/components/emoji_input/emoji_input.js | 49 ++++++++++++++++++++++++++++-- src/components/emoji_input/emoji_input.vue | 2 +- src/components/emoji_input/suggestor.js | 32 +++++++++---------- 3 files changed, 64 insertions(+), 19 deletions(-) (limited to 'src/components/emoji_input/suggestor.js') diff --git a/src/components/emoji_input/emoji_input.js b/src/components/emoji_input/emoji_input.js index fb2096c9..ffc0ffac 100644 --- a/src/components/emoji_input/emoji_input.js +++ b/src/components/emoji_input/emoji_input.js @@ -3,7 +3,7 @@ import EmojiPicker from '../emoji_picker/emoji_picker.vue' import UnicodeDomainIndicator from '../unicode_domain_indicator/unicode_domain_indicator.vue' import { take } from 'lodash' import { findOffset } from '../../services/offset_finder/offset_finder.service.js' - +import { ensureFinalFallback } from '../../i18n/languages.js' import { library } from '@fortawesome/fontawesome-svg-core' import { faSmileBeam @@ -143,6 +143,51 @@ const EmojiInput = { const word = Completion.wordAtPosition(this.modelValue, this.caret - 1) || {} return word } + }, + languages () { + return ensureFinalFallback(this.$store.getters.mergedConfig.interfaceLanguage) + }, + maybeLocalizedEmojiNamesAndKeywords () { + return emoji => { + const names = [emoji.displayText] + const keywords = [] + + if (emoji.displayTextI18n) { + names.push(this.$t(emoji.displayTextI18n.key, emoji.displayTextI18n.args)) + } + + if (emoji.annotations) { + this.languages.forEach(lang => { + names.push(emoji.annotations[lang]?.name) + + keywords.push(...(emoji.annotations[lang]?.keywords || [])) + }) + } + + return { + names: names.filter(k => k), + keywords: keywords.filter(k => k) + } + } + }, + maybeLocalizedEmojiName () { + return emoji => { + if (!emoji.annotations) { + return emoji.displayText + } + + if (emoji.displayTextI18n) { + return this.$t(emoji.displayTextI18n.key, emoji.displayTextI18n.args) + } + + for (const lang of this.languages) { + if (emoji.annotations[lang]?.name) { + return emoji.annotations[lang].name + } + } + + return emoji.displayText + } } }, mounted () { @@ -181,7 +226,7 @@ const EmojiInput = { const firstchar = newWord.charAt(0) this.suggestions = [] if (newWord === firstchar) return - const matchedSuggestions = await this.suggest(newWord) + const matchedSuggestions = await this.suggest(newWord, this.maybeLocalizedEmojiNamesAndKeywords) // Async: cancel if textAtCaret has changed during wait if (this.textAtCaret !== newWord) return if (matchedSuggestions.length <= 0) return diff --git a/src/components/emoji_input/emoji_input.vue b/src/components/emoji_input/emoji_input.vue index eedde9aa..43581dbf 100644 --- a/src/components/emoji_input/emoji_input.vue +++ b/src/components/emoji_input/emoji_input.vue @@ -64,7 +64,7 @@ v-if="!suggestion.user" class="displayText" > - {{ suggestion.displayText }} + {{ maybeLocalizedEmojiName(suggestion) }} {{ suggestion.detailText }} diff --git a/src/components/emoji_input/suggestor.js b/src/components/emoji_input/suggestor.js index 1765f843..adaa879e 100644 --- a/src/components/emoji_input/suggestor.js +++ b/src/components/emoji_input/suggestor.js @@ -13,10 +13,10 @@ export default data => { const emojiCurry = suggestEmoji(data.emoji) const usersCurry = data.store && suggestUsers(data.store) - return input => { + return (input, nameKeywordLocalizer) => { const firstChar = input[0] if (firstChar === ':' && data.emoji) { - return emojiCurry(input) + return emojiCurry(input, nameKeywordLocalizer) } if (firstChar === '@' && usersCurry) { return usersCurry(input) @@ -25,34 +25,34 @@ export default data => { } } -export const suggestEmoji = emojis => input => { +export const suggestEmoji = emojis => (input, nameKeywordLocalizer) => { const noPrefix = input.toLowerCase().substr(1) return emojis - .filter(({ displayText }) => displayText.toLowerCase().match(noPrefix)) - .sort((a, b) => { - let aScore = 0 - let bScore = 0 + .map(emoji => ({ ...emoji, ...nameKeywordLocalizer(emoji) })) + .filter((emoji) => (emoji.names.concat(emoji.keywords)).filter(kw => kw.toLowerCase().match(noPrefix)).length) + .map(k => { + let score = 0 // An exact match always wins - aScore += a.displayText.toLowerCase() === noPrefix ? 200 : 0 - bScore += b.displayText.toLowerCase() === noPrefix ? 200 : 0 + score += Math.max(...k.names.map(name => name.toLowerCase() === noPrefix ? 200 : 0), 0) // Prioritize custom emoji a lot - aScore += a.imageUrl ? 100 : 0 - bScore += b.imageUrl ? 100 : 0 + score += k.imageUrl ? 100 : 0 // Prioritize prefix matches somewhat - aScore += a.displayText.toLowerCase().startsWith(noPrefix) ? 10 : 0 - bScore += b.displayText.toLowerCase().startsWith(noPrefix) ? 10 : 0 + score += Math.max(...k.names.map(kw => kw.toLowerCase().startsWith(noPrefix) ? 10 : 0), 0) // Sort by length - aScore -= a.displayText.length - bScore -= b.displayText.length + score -= k.displayText.length + k.score = score + return k + }) + .sort((a, b) => { // Break ties alphabetically const alphabetically = a.displayText > b.displayText ? 0.5 : -0.5 - return bScore - aScore + alphabetically + return b.score - a.score + alphabetically }) } -- cgit v1.2.3-70-g09d2