From 78081836dfa40abdb587dcbca59d339a27e23fb2 Mon Sep 17 00:00:00 2001 From: tusooa Date: Sat, 24 Dec 2022 12:43:30 -0500 Subject: [PATCH 1/7] Remove lozad code --- src/components/emoji_picker/emoji_picker.js | 40 -------------------- src/components/emoji_picker/emoji_picker.vue | 4 +- src/components/still-image/still-image.js | 3 +- src/components/still-image/still-image.vue | 1 + 4 files changed, 5 insertions(+), 43 deletions(-) diff --git a/src/components/emoji_picker/emoji_picker.js b/src/components/emoji_picker/emoji_picker.js index 2838e102..68240fd8 100644 --- a/src/components/emoji_picker/emoji_picker.js +++ b/src/components/emoji_picker/emoji_picker.js @@ -3,7 +3,6 @@ import Checkbox from '../checkbox/checkbox.vue' import Popover from 'src/components/popover/popover.vue' import StillImage from '../still-image/still-image.vue' import { ensureFinalFallback } from '../../i18n/languages.js' -import lozad from 'lozad' import { library } from '@fortawesome/fontawesome-svg-core' import { faBoxOpen, @@ -125,9 +124,6 @@ const EmojiPicker = { setGroupRef (name) { return el => { this.groupRefs[name] = el } }, - setEmojiRef (name) { - return el => { this.emojiRefs[name] = el } - }, onPopoverShown () { this.$emit('show') }, @@ -208,43 +204,12 @@ const EmojiPicker = { filterByKeyword (list, keyword) { return filterByKeyword(list, keyword, this.languages, this.maybeLocalizedEmojiName) }, - initializeLazyLoad () { - this.destroyLazyLoad() - this.$nextTick(() => { - this.$lozad = lozad('.still-image.emoji-picker-emoji', { - load: el => { - const name = el.getAttribute('data-emoji-name') - const vn = this.emojiRefs[name] - if (!vn) { - return - } - - vn.loadLazy() - } - }) - this.$lozad.observe() - }) - }, - waitForDomAndInitializeLazyLoad () { - this.$nextTick(() => this.initializeLazyLoad()) - }, - destroyLazyLoad () { - if (this.$lozad) { - if (this.$lozad.observer) { - this.$lozad.observer.disconnect() - } - if (this.$lozad.mutationObserver) { - this.$lozad.mutationObserver.disconnect() - } - } - }, onShowing () { const oldContentLoaded = this.contentLoaded this.$nextTick(() => { this.$refs.search.focus() }) this.contentLoaded = true - this.waitForDomAndInitializeLazyLoad() this.filteredEmojiGroups = this.getFilteredEmojiGroups() if (!oldContentLoaded) { this.$nextTick(() => { @@ -269,13 +234,9 @@ const EmojiPicker = { this.debouncedHandleKeywordChange() }, allCustomGroups () { - this.waitForDomAndInitializeLazyLoad() this.filteredEmojiGroups = this.getFilteredEmojiGroups() } }, - destroyed () { - this.destroyLazyLoad() - }, computed: { activeGroupView () { return this.showingStickers ? '' : this.activeGroup @@ -314,7 +275,6 @@ const EmojiPicker = { }, debouncedHandleKeywordChange () { return debounce(() => { - this.waitForDomAndInitializeLazyLoad() this.filteredEmojiGroups = this.getFilteredEmojiGroups() }, 500) }, diff --git a/src/components/emoji_picker/emoji_picker.vue b/src/components/emoji_picker/emoji_picker.vue index ff56d637..d0b7fe8f 100644 --- a/src/components/emoji_picker/emoji_picker.vue +++ b/src/components/emoji_picker/emoji_picker.vue @@ -104,9 +104,9 @@ >{{ emoji.replacement }} diff --git a/src/components/still-image/still-image.js b/src/components/still-image/still-image.js index 200ef147..56fd2fd9 100644 --- a/src/components/still-image/still-image.js +++ b/src/components/still-image/still-image.js @@ -8,7 +8,8 @@ const StillImage = { 'alt', 'height', 'width', - 'dataSrc' + 'dataSrc', + 'loading' ], data () { return { diff --git a/src/components/still-image/still-image.vue b/src/components/still-image/still-image.vue index 633fb229..d015e138 100644 --- a/src/components/still-image/still-image.vue +++ b/src/components/still-image/still-image.vue @@ -17,6 +17,7 @@ :data-src="dataSrc" :src="realSrc" :referrerpolicy="referrerpolicy" + :loading="loading" @load="onLoad" @error="onError" > From d0c7ceb58420c40ff82736cdf65750ad8f8a8e19 Mon Sep 17 00:00:00 2001 From: tusooa Date: Sat, 24 Dec 2022 12:44:23 -0500 Subject: [PATCH 2/7] Remove lozad --- package.json | 1 - yarn.lock | 5 ----- 2 files changed, 6 deletions(-) diff --git a/package.json b/package.json index 6ce0b116..231a93ad 100644 --- a/package.json +++ b/package.json @@ -34,7 +34,6 @@ "escape-html": "1.0.3", "js-cookie": "3.0.1", "localforage": "1.10.0", - "lozad": "1.16.0", "parse-link-header": "2.0.0", "phoenix": "1.6.2", "punycode.js": "2.1.0", diff --git a/yarn.lock b/yarn.lock index 5058407a..dc2050ca 100644 --- a/yarn.lock +++ b/yarn.lock @@ -6103,11 +6103,6 @@ lower-case@^2.0.2: dependencies: tslib "^2.0.3" -lozad@1.16.0: - version "1.16.0" - resolved "https://registry.yarnpkg.com/lozad/-/lozad-1.16.0.tgz#86ce732c64c69926ccdebb81c8c90bb3735948b4" - integrity sha512-JBr9WjvEFeKoyim3svo/gsQPTkgG/mOHJmDctZ/+U9H3ymUuvEkqpn8bdQMFsvTMcyRJrdJkLv0bXqGm0sP72w== - lru-cache@^5.1.1: version "5.1.1" resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-5.1.1.tgz#1da27e6710271947695daf6848e847f01d84b920" From afd7f5fabe58dc08a5a6e35e923e2e8fd71926dc Mon Sep 17 00:00:00 2001 From: tusooa Date: Sat, 24 Dec 2022 13:48:36 -0500 Subject: [PATCH 3/7] Use virtual scrolling for emoji picker --- package.json | 1 + src/boot/after_store.js | 3 + src/components/emoji_picker/emoji_picker.js | 33 +++----- src/components/emoji_picker/emoji_picker.scss | 1 + src/components/emoji_picker/emoji_picker.vue | 79 ++++++++++--------- yarn.lock | 24 ++++++ 6 files changed, 83 insertions(+), 58 deletions(-) diff --git a/package.json b/package.json index 231a93ad..a32f93a4 100644 --- a/package.json +++ b/package.json @@ -45,6 +45,7 @@ "vue-i18n": "9.2.2", "vue-router": "4.1.6", "vue-template-compiler": "2.7.14", + "vue-virtual-scroller": "^2.0.0-beta.7", "vuex": "4.1.0" }, "devDependencies": { diff --git a/src/boot/after_store.js b/src/boot/after_store.js index 7a4672b6..1fa9dd2a 100644 --- a/src/boot/after_store.js +++ b/src/boot/after_store.js @@ -1,6 +1,8 @@ import { createApp } from 'vue' import { createRouter, createWebHistory } from 'vue-router' import vClickOutside from 'click-outside-vue3' +import VueVirtualScroller from 'vue-virtual-scroller' +import 'vue-virtual-scroller/dist/vue-virtual-scroller.css' import { FontAwesomeIcon, FontAwesomeLayers } from '@fortawesome/vue-fontawesome' @@ -397,6 +399,7 @@ const afterStoreSetup = async ({ store, i18n }) => { app.use(vClickOutside) app.use(VBodyScrollLock) + app.use(VueVirtualScroller) app.component('FAIcon', FontAwesomeIcon) app.component('FALayers', FontAwesomeLayers) diff --git a/src/components/emoji_picker/emoji_picker.js b/src/components/emoji_picker/emoji_picker.js index 68240fd8..c87dea7e 100644 --- a/src/components/emoji_picker/emoji_picker.js +++ b/src/components/emoji_picker/emoji_picker.js @@ -143,22 +143,13 @@ const EmojiPicker = { } 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) + onScroll (startIndex, endIndex, visibleStartIndex, visibleEndIndex) { + const current = this.filteredEmojiGroups[visibleStartIndex].id + this.scrolledGroup(current) }, - scrolledGroup (target) { - const top = target.scrollTop + 5 - this.$nextTick(() => { - this.allEmojiGroups.forEach(group => { - const ref = this.groupRefs['group-' + group.id] - if (ref && ref.offsetTop <= top) { - this.activeGroup = group.id - } - }) - this.scrollHeader() - }) + scrolledGroup (groupId) { + this.activeGroup = groupId + this.scrollHeader() }, scrollHeader () { // Scroll the active tab's header into view @@ -177,14 +168,9 @@ const EmojiPicker = { setScroll(right + margin - headerCont.clientWidth) } }, - highlight (key) { - const ref = this.groupRefs['group-' + key] - const top = ref.offsetTop + highlight (index) { this.setShowStickers(false) - this.activeGroup = key - this.$nextTick(() => { - this.$refs['emoji-groups'].scrollTop = top + 1 - }) + this.$refs['emoji-groups'].scrollToItem(index) }, updateScrolledClass (target) { if (target.scrollTop <= 5) { @@ -238,6 +224,9 @@ const EmojiPicker = { } }, computed: { + minItemSize () { + return 32 + }, activeGroupView () { return this.showingStickers ? '' : this.activeGroup }, diff --git a/src/components/emoji_picker/emoji_picker.scss b/src/components/emoji_picker/emoji_picker.scss index 53363ec1..dda12197 100644 --- a/src/components/emoji_picker/emoji_picker.scss +++ b/src/components/emoji_picker/emoji_picker.scss @@ -74,6 +74,7 @@ $emoji-picker-emoji-size: 32px; } .emoji-groups { + height: 100%; min-height: 200px; } diff --git a/src/components/emoji_picker/emoji_picker.vue b/src/components/emoji_picker/emoji_picker.vue index d0b7fe8f..15cdb704 100644 --- a/src/components/emoji_picker/emoji_picker.vue +++ b/src/components/emoji_picker/emoji_picker.vue @@ -13,7 +13,7 @@ class="emoji-tabs" > -
-
-
+ - {{ group.text }} -
- - {{ emoji.replacement }} - - - -
-
+
+
+ {{ group.text }} +
+ + {{ emoji.replacement }} + + +
+ + +
{{ $t('emoji.keep_open') }} diff --git a/yarn.lock b/yarn.lock index dc2050ca..7b45ee14 100644 --- a/yarn.lock +++ b/yarn.lock @@ -6370,6 +6370,11 @@ minimist@^1.2.5: resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602" integrity sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw== +mitt@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/mitt/-/mitt-2.1.0.tgz#f740577c23176c6205b121b2973514eade1b2230" + integrity sha512-ILj2TpLiysu2wkBbWjAmww7TkZb65aiQO+DkVdUTBpBXq+MHYiETENkKFMtsJZX1Lf4pe4QOrTSjIfUwN5lRdg== + mkdirp@^0.5.1: version "0.5.1" resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903" @@ -8805,6 +8810,16 @@ vue-loader@17.0.1: hash-sum "^2.0.0" loader-utils "^2.0.0" +vue-observe-visibility@^2.0.0-alpha.1: + version "2.0.0-alpha.1" + resolved "https://registry.yarnpkg.com/vue-observe-visibility/-/vue-observe-visibility-2.0.0-alpha.1.tgz#1e4eda7b12562161d58984b7e0dea676d83bdb13" + integrity sha512-flFbp/gs9pZniXR6fans8smv1kDScJ8RS7rEpMjhVabiKeq7Qz3D9+eGsypncjfIyyU84saU88XZ0zjbD6Gq/g== + +vue-resize@^2.0.0-alpha.1: + version "2.0.0-alpha.1" + resolved "https://registry.yarnpkg.com/vue-resize/-/vue-resize-2.0.0-alpha.1.tgz#43eeb79e74febe932b9b20c5c57e0ebc14e2df3a" + integrity sha512-7+iqOueLU7uc9NrMfrzbG8hwMqchfVfSzpVlCMeJQe4pyibqyoifDNbKTZvwxZKDvGkB+PdFeKvnGZMoEb8esg== + vue-router@4.1.6: version "4.1.6" resolved "https://registry.yarnpkg.com/vue-router/-/vue-router-4.1.6.tgz#b70303737e12b4814578d21d68d21618469375a1" @@ -8828,6 +8843,15 @@ vue-template-compiler@2.7.14: de-indent "^1.0.2" he "^1.2.0" +vue-virtual-scroller@^2.0.0-beta.7: + version "2.0.0-beta.7" + resolved "https://registry.yarnpkg.com/vue-virtual-scroller/-/vue-virtual-scroller-2.0.0-beta.7.tgz#4ea8158638c84b2033b001a8b26c5fcb6896b271" + integrity sha512-OrouVj1i2939jaLjVfu8f5fsDlbzhAb4bOsYZYrAkpcVLylAmMoGtIL7eT3hJrdTiaKbwQpRdnv7DKf9Fn+tHg== + dependencies: + mitt "^2.1.0" + vue-observe-visibility "^2.0.0-alpha.1" + vue-resize "^2.0.0-alpha.1" + vue@3.2.45: version "3.2.45" resolved "https://registry.yarnpkg.com/vue/-/vue-3.2.45.tgz#94a116784447eb7dbd892167784619fef379b3c8" From 314a4474f6475435cfac7e5e02862015a9455660 Mon Sep 17 00:00:00 2001 From: tusooa Date: Mon, 2 Jan 2023 12:40:03 -0500 Subject: [PATCH 4/7] Fix header indicator --- src/components/emoji_picker/emoji_picker.js | 28 +++++++++++++++++--- src/components/emoji_picker/emoji_picker.vue | 2 ++ 2 files changed, 26 insertions(+), 4 deletions(-) diff --git a/src/components/emoji_picker/emoji_picker.js b/src/components/emoji_picker/emoji_picker.js index c87dea7e..9c97e16c 100644 --- a/src/components/emoji_picker/emoji_picker.js +++ b/src/components/emoji_picker/emoji_picker.js @@ -81,6 +81,13 @@ const filterByKeyword = (list, keyword = '', languages, nameLocalizer) => { return orderedEmojiList.flat() } +const getOffset = (elem) => { + const style = elem.style.transform + const res = /translateY\((\d+)px\)/.exec(style) + if (!res) { return 0 } + return res[1] +} + const EmojiPicker = { props: { enableStickerPicker: { @@ -144,12 +151,25 @@ const EmojiPicker = { this.$emit('emoji', { insertion: value, keepOpen: this.keepOpen }) }, onScroll (startIndex, endIndex, visibleStartIndex, visibleEndIndex) { + console.log('onScroll', startIndex, endIndex, visibleStartIndex, visibleEndIndex) const current = this.filteredEmojiGroups[visibleStartIndex].id - this.scrolledGroup(current) + const target = this.$refs['emoji-groups'].$el + this.scrolledGroup(target, current, visibleStartIndex, visibleEndIndex) }, - scrolledGroup (groupId) { - this.activeGroup = groupId - this.scrollHeader() + scrolledGroup (target, groupId, start, end) { + const top = target.scrollTop + 5 + this.$nextTick(() => { + this.filteredEmojiGroups.slice(start, end + 1).forEach(group => { + const ref = this.groupRefs['group-' + group.id] + if (!ref) { return } + const elem = ref.$el.parentElement + if (!elem) { return } + if (elem && getOffset(elem) <= top) { + this.activeGroup = group.id + } + }) + this.scrollHeader() + }) }, scrollHeader () { // Scroll the active tab's header into view diff --git a/src/components/emoji_picker/emoji_picker.vue b/src/components/emoji_picker/emoji_picker.vue index 15cdb704..78da4808 100644 --- a/src/components/emoji_picker/emoji_picker.vue +++ b/src/components/emoji_picker/emoji_picker.vue @@ -80,10 +80,12 @@ :class="groupsScrolledClass" :min-item-size="minItemSize" :items="filteredEmojiGroups" + :emit-update="true" @update="onScroll" >