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/emoji_input.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'src/components/emoji_input/emoji_input.js') diff --git a/src/components/emoji_input/emoji_input.js b/src/components/emoji_input/emoji_input.js index 5ba3907f..b664d6b3 100644 --- a/src/components/emoji_input/emoji_input.js +++ b/src/components/emoji_input/emoji_input.js @@ -1,5 +1,6 @@ import Completion from '../../services/completion/completion.js' 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' @@ -120,7 +121,8 @@ const EmojiInput = { } }, components: { - EmojiPicker + EmojiPicker, + UnicodeDomainIndicator }, computed: { padEmoji () { -- cgit v1.2.3-70-g09d2 From 8777b6eadd7deadf010dc36bb90514f75fc0da16 Mon Sep 17 00:00:00 2001 From: Tusooa Zhu Date: Fri, 8 Oct 2021 01:02:16 -0400 Subject: Clean up legacy code in emoji picker Ref: grouped-emoji-picker --- src/components/emoji_input/emoji_input.js | 1 - src/components/emoji_picker/emoji_picker.js | 130 ++++++--------------------- src/components/emoji_picker/emoji_picker.vue | 3 +- src/directives/lazy_image_container.js | 13 --- 4 files changed, 28 insertions(+), 119 deletions(-) delete mode 100644 src/directives/lazy_image_container.js (limited to 'src/components/emoji_input/emoji_input.js') diff --git a/src/components/emoji_input/emoji_input.js b/src/components/emoji_input/emoji_input.js index b664d6b3..fb2096c9 100644 --- a/src/components/emoji_input/emoji_input.js +++ b/src/components/emoji_input/emoji_input.js @@ -207,7 +207,6 @@ const EmojiInput = { }, triggerShowPicker () { this.showPicker = true - this.$refs.picker.startEmojiLoad() this.$nextTick(() => { this.scrollIntoView() this.focusPickerInput() diff --git a/src/components/emoji_picker/emoji_picker.js b/src/components/emoji_picker/emoji_picker.js index 82e5ad0b..b0162479 100644 --- a/src/components/emoji_picker/emoji_picker.js +++ b/src/components/emoji_picker/emoji_picker.js @@ -1,6 +1,6 @@ import { defineAsyncComponent } from 'vue' import Checkbox from '../checkbox/checkbox.vue' -import LazyImageContainer from '../../directives/lazy_image_container' +import lozad from 'lozad' import { library } from '@fortawesome/fontawesome-svg-core' import { faBoxOpen, @@ -54,7 +54,6 @@ const EmojiPicker = { showingStickers: false, groupsScrolledClass: 'scrolled-top', keepOpen: false, - customEmojiBufferSlice: LOAD_EMOJI_BY, customEmojiTimeout: null, customEmojiLoadAllConfirmed: false, groupLoadedCount: {}, @@ -65,9 +64,6 @@ const EmojiPicker = { StickerPicker: defineAsyncComponent(() => import('../sticker_picker/sticker_picker.vue')), Checkbox }, - directives: { - LazyImageContainer - }, methods: { onStickerUploaded (e) { this.$emit('sticker-uploaded', e) @@ -82,10 +78,6 @@ const EmojiPicker = { onScroll (e) { const target = (e && e.target) || this.$refs['emoji-groups'] this.updateScrolledClass(target) - this.scrolledGroup(target) - this.$nextTick(() => { - this.triggerLoadMore(target) - }) }, highlight (key) { const ref = this.$refs['group-' + key] @@ -94,7 +86,6 @@ const EmojiPicker = { this.activeGroup = key this.$nextTick(() => { this.$refs['emoji-groups'].scrollTop = top + 1 - this.loadEmoji(key) }) }, updateScrolledClass (target) { @@ -106,101 +97,48 @@ const EmojiPicker = { this.groupsScrolledClass = 'scrolled-middle' } }, - triggerLoadMore (target) { - Object.keys(this.allCustomGroups) - .filter(id => this.filteredEmojiGroups.filter(group => group.id === id).length > 0) - .map(groupId => { - const ref = this.$refs[`group-end-${groupId}`][0] - if (!ref) return undefined - - const bottom = ref.offsetTop + ref.offsetHeight - - const group = this.$refs[`group-${groupId}`][0] - const top = group.offsetTop - - const scrollerBottom = target.scrollTop + target.clientHeight - const scrollerTop = target.scrollTop - const scrollerMax = target.scrollHeight - - // Loads more emoji when they come into view - const approachingBottom = bottom - scrollerBottom < LOAD_EMOJI_MARGIN - // Always load when at the very top in case there's no scroll space yet - const atTop = scrollerTop < top + target.clientHeight / 2 && top < scrollerBottom - const unscrollable = top - bottom < target.clientHeight - // Don't load when looking at unicode category or at the very bottom - const bottomAboveViewport = bottom < scrollerTop || scrollerBottom === scrollerMax - if (!bottomAboveViewport && (approachingBottom || atTop || unscrollable)) { - return groupId - } - return undefined - }) - .filter(k => k) - .map(k => { - this.loadEmoji(k) - }) - }, - scrolledGroup (target) { - const top = target.scrollTop + 5 - this.$nextTick(() => { - this.allEmojiGroups.forEach(group => { - const ref = this.$refs['group-' + group.id] - if (ref.offsetTop <= top) { - this.activeGroup = group.id - } - }) - }) - }, - loadEmoji (loadGroup) { - if (!this.allCustomGroups[loadGroup]) { - return - } - - const allLoaded = this.loadedCount[loadGroup] >= this.allCustomGroups[loadGroup].emojis.length - - if (allLoaded) { - return - } - - this.groupLoadedCount = { - ...this.groupLoadedCount, - [loadGroup]: this.loadedCount[loadGroup] + LOAD_EMOJI_BY - } - }, - startEmojiLoad (forceUpdate = false) { - if (!forceUpdate) { - this.keyword = '' - } - this.$nextTick(() => { - this.$refs['emoji-groups'].scrollTop = 0 - this.$nextTick(() => { - if (this.firstLoaded) { - return - } - this.triggerLoadMore(this.$refs['emoji-groups']) - this.firstLoaded = true - }) - }) - }, toggleStickers () { this.showingStickers = !this.showingStickers }, setShowStickers (value) { this.showingStickers = value }, - limitedEmojis (list, groupId) { - return list // list.slice(0, this.loadedCount[groupId]) - }, filterByKeyword (list, keyword) { return filterByKeyword(list, keyword) + }, + initializeLazyLoad () { + this.destroyLazyLoad() + this.$lozad = lozad('img', {}) + this.$lozad.observe() + }, + destroyLazyLoad () { + if (this.$lozad) { + if (this.$lozad.observer) { + this.$lozad.observer.disconnect() + } + if (this.$lozad.mutationObserver) { + this.$lozad.mutationObserver.disconnect() + } + } } }, watch: { keyword () { this.customEmojiLoadAllConfirmed = false this.onScroll() - this.startEmojiLoad(true) + // Wait for the dom to change + this.$nextTick(() => this.initializeLazyLoad()) + }, + allCustomGroups () { + this.$nextTick(() => this.initializeLazyLoad()) } }, + mounted () { + this.initializeLazyLoad() + }, + destroyed () { + this.destroyLazyLoad() + }, computed: { activeGroupView () { return this.showingStickers ? '' : this.activeGroup @@ -214,10 +152,6 @@ const EmojiPicker = { allCustomGroups () { return this.$store.getters.groupedCustomEmojis }, - sensibleInitialAmountForAGroup () { - const groupCount = Object.keys(this.allCustomGroups).length - return Math.max(Math.floor(LOAD_EMOJI_BY / Math.max(groupCount, 1)), 1) - }, allEmojiGroups () { const standardEmojis = this.$store.state.instance.emoji || [] return Object.entries(this.allCustomGroups) @@ -237,16 +171,6 @@ const EmojiPicker = { })) .filter(group => group.emojis.length > 0) }, - loadedCount () { - return Object.keys(this.allCustomGroups) - .reduce((res, groupId) => { - res[groupId] = this.groupLoadedCount[groupId] || this.sensibleInitialAmountForAGroup - return res - }, {}) - }, - lastNonUnicodeGroupId () { - return this.emojis[this.emojis.length - 2].id - }, stickerPickerEnabled () { return (this.$store.state.instance.stickers || []).length !== 0 } diff --git a/src/components/emoji_picker/emoji_picker.vue b/src/components/emoji_picker/emoji_picker.vue index 0e6c7e41..0df33c24 100644 --- a/src/components/emoji_picker/emoji_picker.vue +++ b/src/components/emoji_picker/emoji_picker.vue @@ -62,7 +62,6 @@
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/emoji_input.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