diff options
Diffstat (limited to 'src/components/emoji_picker/emoji_picker.js')
| -rw-r--r-- | src/components/emoji_picker/emoji_picker.js | 97 |
1 files changed, 84 insertions, 13 deletions
diff --git a/src/components/emoji_picker/emoji_picker.js b/src/components/emoji_picker/emoji_picker.js index b1d70176..0f397b59 100644 --- a/src/components/emoji_picker/emoji_picker.js +++ b/src/components/emoji_picker/emoji_picker.js @@ -1,5 +1,12 @@ import Checkbox from '../checkbox/checkbox.vue' +// At widest, approximately 20 emoji are visible in a row, +// loading 3 rows, could be overkill for narrow picker +const LOAD_EMOJI_BY = 60 + +// When to start loading new batch emoji, in pixels +const LOAD_EMOJI_MARGIN = 64 + const filterByKeyword = (list, keyword = '') => { return list.filter(x => x.displayText.includes(keyword)) } @@ -18,7 +25,10 @@ const EmojiPicker = { activeGroup: 'custom', showingStickers: false, groupsScrolledClass: 'scrolled-top', - keepOpen: false + keepOpen: false, + customEmojiBufferSlice: LOAD_EMOJI_BY, + customEmojiTimeout: null, + customEmojiLoadAllConfirmed: false } }, components: { @@ -26,10 +36,22 @@ const EmojiPicker = { Checkbox }, methods: { + onStickerUploaded (e) { + this.$emit('sticker-uploaded', e) + }, + onStickerUploadFailed (e) { + this.$emit('sticker-upload-failed', e) + }, onEmoji (emoji) { const value = emoji.imageUrl ? `:${emoji.displayText}:` : emoji.replacement this.$emit('emoji', { insertion: value, keepOpen: this.keepOpen }) }, + onScroll (e) { + const target = (e && e.target) || this.$refs['emoji-groups'] + this.updateScrolledClass(target) + this.scrolledGroup(target) + this.triggerLoadMore(target) + }, highlight (key) { const ref = this.$refs['group-' + key] const top = ref[0].offsetTop @@ -39,9 +61,7 @@ const EmojiPicker = { this.$refs['emoji-groups'].scrollTop = top + 1 }) }, - scrolledGroup (e) { - const target = (e && e.target) || this.$refs['emoji-groups'] - const top = target.scrollTop + 5 + updateScrolledClass (target) { if (target.scrollTop <= 5) { this.groupsScrolledClass = 'scrolled-top' } else if (target.scrollTop >= target.scrollTopMax - 5) { @@ -49,6 +69,28 @@ const EmojiPicker = { } else { this.groupsScrolledClass = 'scrolled-middle' } + }, + triggerLoadMore (target) { + const ref = this.$refs['group-end-custom'][0] + if (!ref) return + const bottom = ref.offsetTop + ref.offsetHeight + + 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 < 5 + // Don't load when looking at unicode category or at the very bottom + const bottomAboveViewport = bottom < scrollerTop || scrollerBottom === scrollerMax + if (!bottomAboveViewport && (approachingBottom || atTop)) { + this.loadEmoji() + } + }, + scrolledGroup (target) { + const top = target.scrollTop + 5 this.$nextTick(() => { this.emojisView.forEach(group => { const ref = this.$refs['group-' + group.id] @@ -58,22 +100,41 @@ const EmojiPicker = { }) }) }, + loadEmoji () { + const allLoaded = this.customEmojiBuffer.length === this.filteredEmoji.length + + if (allLoaded) { + return + } + + this.customEmojiBufferSlice += LOAD_EMOJI_BY + }, + startEmojiLoad (forceUpdate = false) { + if (!forceUpdate) { + this.keyword = '' + } + this.$nextTick(() => { + this.$refs['emoji-groups'].scrollTop = 0 + }) + const bufferSize = this.customEmojiBuffer.length + const bufferPrefilledAll = bufferSize === this.filteredEmoji.length + if (bufferPrefilledAll && !forceUpdate) { + return + } + this.customEmojiBufferSlice = LOAD_EMOJI_BY + }, toggleStickers () { this.showingStickers = !this.showingStickers }, setShowStickers (value) { this.showingStickers = value - }, - onStickerUploaded (e) { - this.$emit('sticker-uploaded', e) - }, - onStickerUploadFailed (e) { - this.$emit('sticker-upload-failed', e) } }, watch: { keyword () { - this.scrolledGroup() + this.customEmojiLoadAllConfirmed = false + this.onScroll() + this.startEmojiLoad(true) } }, computed: { @@ -86,15 +147,25 @@ const EmojiPicker = { } return 0 }, + filteredEmoji () { + return filterByKeyword( + this.$store.state.instance.customEmoji || [], + this.keyword + ) + }, + customEmojiBuffer () { + return this.filteredEmoji.slice(0, this.customEmojiBufferSlice) + }, emojis () { const standardEmojis = this.$store.state.instance.emoji || [] - const customEmojis = this.$store.state.instance.customEmoji || [] + const customEmojis = this.customEmojiBuffer + return [ { id: 'custom', text: this.$t('emoji.custom'), icon: 'icon-smile', - emojis: filterByKeyword(customEmojis, this.keyword) + emojis: customEmojis }, { id: 'standard', |
