From 91ca1db7788a0603fd19ae603970f081c63e04c0 Mon Sep 17 00:00:00 2001 From: Henry Jameson Date: Tue, 1 Oct 2019 20:14:14 +0300 Subject: [PATCH 01/19] moved emoji stuff away from after-store and into users module since we only need emoji after login --- src/boot/after_store.js | 55 +---------------------------------------- src/modules/users.js | 53 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 54 insertions(+), 54 deletions(-) diff --git a/src/boot/after_store.js b/src/boot/after_store.js index 490ac4d0..80a55849 100644 --- a/src/boot/after_store.js +++ b/src/boot/after_store.js @@ -173,58 +173,6 @@ const getStickers = async ({ store }) => { } } -const getStaticEmoji = async ({ store }) => { - try { - 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, - imageUrl: false, - replacement: values[key] - } - }).sort((a, b) => a.displayText - b.displayText) - store.dispatch('setInstanceOption', { name: 'emoji', value: emoji }) - } else { - throw (res) - } - } catch (e) { - console.warn("Can't load static emoji") - console.warn(e) - } -} - -// This is also used to indicate if we have a 'pleroma backend' or not. -// Somewhat weird, should probably be somewhere else. -const getCustomEmoji = async ({ store }) => { - try { - const res = await window.fetch('/api/pleroma/emoji.json') - if (res.ok) { - const result = await res.json() - const values = Array.isArray(result) ? Object.assign({}, ...result) : result - const emoji = Object.entries(values).map(([key, value]) => { - const imageUrl = value.image_url - return { - displayText: key, - imageUrl: imageUrl ? store.state.instance.server + imageUrl : value, - tags: imageUrl ? value.tags.sort((a, b) => a > b ? 1 : 0) : ['utf'], - replacement: `:${key}: ` - } - // Technically could use tags but those are kinda useless right now, should have been "pack" field, that would be more useful - }).sort((a, b) => a.displayText.toLowerCase() > b.displayText.toLowerCase() ? 1 : 0) - store.dispatch('setInstanceOption', { name: 'customEmoji', value: emoji }) - store.dispatch('setInstanceOption', { name: 'pleromaBackend', value: true }) - } else { - throw (res) - } - } catch (e) { - store.dispatch('setInstanceOption', { name: 'pleromaBackend', value: false }) - console.warn("Can't load custom emojis, maybe not a Pleroma instance?") - console.warn(e) - } -} - const getAppSecret = async ({ store }) => { const { state, commit } = store const { oauth, instance } = state @@ -259,6 +207,7 @@ const getNodeInfo = async ({ store }) => { const software = data.software store.dispatch('setInstanceOption', { name: 'backendVersion', value: software.version }) + store.dispatch('setInstanceOption', { name: 'pleromaBackend', value: software.name === 'pleroma' }) const frontendVersion = window.___pleromafe_commit_hash store.dispatch('setInstanceOption', { name: 'frontendVersion', value: frontendVersion }) @@ -315,8 +264,6 @@ const afterStoreSetup = async ({ store, i18n }) => { getTOS({ store }), getInstancePanel({ store }), getStickers({ store }), - getStaticEmoji({ store }), - getCustomEmoji({ store }), getNodeInfo({ store }) ]) diff --git a/src/modules/users.js b/src/modules/users.js index 4d02f8d7..fed948e4 100644 --- a/src/modules/users.js +++ b/src/modules/users.js @@ -60,6 +60,56 @@ const unmuteUser = (store, id) => { .then((relationship) => store.commit('updateUserRelationship', [relationship])) } +const getStaticEmoji = async (store) => { + try { + 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, + imageUrl: false, + replacement: values[key] + } + }).sort((a, b) => a.displayText - b.displayText) + store.dispatch('setInstanceOption', { name: 'emoji', value: emoji }) + } else { + throw (res) + } + } catch (e) { + console.warn("Can't load static emoji") + console.warn(e) + } +} + +// This is also used to indicate if we have a 'pleroma backend' or not. +// Somewhat weird, should probably be somewhere else. +const getCustomEmoji = async (store) => { + try { + const res = await window.fetch('/api/pleroma/emoji.json') + if (res.ok) { + const result = await res.json() + const values = Array.isArray(result) ? Object.assign({}, ...result) : result + const emoji = Object.entries(values).map(([key, value]) => { + const imageUrl = value.image_url + return { + displayText: key, + imageUrl: imageUrl ? store.rootState.instance.server + imageUrl : value, + tags: imageUrl ? value.tags.sort((a, b) => a > b ? 1 : 0) : ['utf'], + replacement: `:${key}: ` + } + // Technically could use tags but those are kinda useless right now, should have been "pack" field, that would be more useful + }).sort((a, b) => a.displayText.toLowerCase() > b.displayText.toLowerCase() ? 1 : 0) + store.dispatch('setInstanceOption', { name: 'customEmoji', value: emoji }) + } else { + throw (res) + } + } catch (e) { + console.warn("Can't load custom emojis") + console.warn(e) + } +} + export const mutations = { setMuted (state, { user: { id }, muted }) { const user = state.usersObject[id] @@ -434,6 +484,9 @@ const users = { commit('setCurrentUser', user) commit('addNewUsers', [user]) + getCustomEmoji(store) + getStaticEmoji(store) + getNotificationPermission() .then(permission => commit('setNotificationPermission', permission)) From 29e6e62e7cbddf8e936bdfbdb2ecb935bb297cec Mon Sep 17 00:00:00 2001 From: Henry Jameson Date: Thu, 3 Oct 2019 20:16:01 +0300 Subject: [PATCH 02/19] emoji picker gradual render --- src/components/emoji_picker/emoji_picker.js | 42 +++++++++++++++++++-- 1 file changed, 39 insertions(+), 3 deletions(-) diff --git a/src/components/emoji_picker/emoji_picker.js b/src/components/emoji_picker/emoji_picker.js index 824412dd..81f7437f 100644 --- a/src/components/emoji_picker/emoji_picker.js +++ b/src/components/emoji_picker/emoji_picker.js @@ -1,3 +1,4 @@ +import { set } from 'vue' const filterByKeyword = (list, keyword = '') => { return list.filter(x => x.displayText.includes(keyword)) @@ -18,7 +19,10 @@ const EmojiPicker = { activeGroup: 'custom', showingStickers: false, groupsScrolledClass: 'scrolled-top', - keepOpen: false + keepOpen: false, + customEmojiBuffer: [], + customEmojiInterval: null, + customEmojiCounter: 0 } }, components: { @@ -57,6 +61,36 @@ const EmojiPicker = { }) }) }, + restartInterval () { + const customEmojis = filterByKeyword( + this.$store.state.instance.customEmoji || [], + this.keyword + ) + const amount = 50 + const interval = 100 + + if (this.customEmojiInterval) { + window.clearInterval(this.customEmojiInterval) + } + window.setTimeout( + window.clearInterval(this.customEmojiInterval), + 1000 + ) + set(this, 'customEmojiBuffer', []) + this.customEmojiCounter = 0 + this.customEmojiInterval = window.setInterval(() => { + console.log(this.customEmojiBuffer.length) + console.log(customEmojis.length) + if (this.customEmojiBuffer.length < customEmojis.length) { + this.customEmojiBuffer.push( + ...customEmojis.slice(this.customEmojiCounter, this.customEmojiCounter + amount) + ) + } else { + window.clearInterval(this.customEmojiInterval) + } + this.customEmojiCounter += amount + }, interval) + }, toggleStickers () { this.showingStickers = !this.showingStickers }, @@ -73,6 +107,7 @@ const EmojiPicker = { watch: { keyword () { this.scrolledGroup() + this.restartInterval() } }, computed: { @@ -87,13 +122,14 @@ const EmojiPicker = { }, 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', From 6511a744a29c760aa2613b0902db55be3b59dfa5 Mon Sep 17 00:00:00 2001 From: Henry Jameson Date: Mon, 7 Oct 2019 23:46:40 +0300 Subject: [PATCH 03/19] arbitrary limit with option to overcome it --- src/App.scss | 12 +++ src/_variables.scss | 1 + src/components/emoji_picker/emoji_picker.js | 80 ++++++++++++------- src/components/emoji_picker/emoji_picker.scss | 24 ++++-- src/components/emoji_picker/emoji_picker.vue | 11 +++ .../style_switcher/style_switcher.js | 3 + .../style_switcher/style_switcher.vue | 7 ++ src/i18n/en.json | 5 +- src/services/style_setter/style_setter.js | 5 ++ 9 files changed, 113 insertions(+), 35 deletions(-) diff --git a/src/App.scss b/src/App.scss index 2190f91a..fe271ce1 100644 --- a/src/App.scss +++ b/src/App.scss @@ -658,6 +658,18 @@ nav { color: var(--alertErrorPanelText, $fallback--text); } } + + &.warning { + background-color: $fallback--alertWarning; + background-color: var(--alertWarning, $fallback--alertWarning); + color: $fallback--text; + color: var(--alertWarningText, $fallback--text); + + .panel-heading & { + color: $fallback--text; + color: var(--alertWarningPanelText, $fallback--text); + } + } } .faint { diff --git a/src/_variables.scss b/src/_variables.scss index 150e4fb5..e18101f0 100644 --- a/src/_variables.scss +++ b/src/_variables.scss @@ -17,6 +17,7 @@ $fallback--cGreen: #0fa00f; $fallback--cOrange: orange; $fallback--alertError: rgba(211,16,20,.5); +$fallback--alertWarning: rgba(111,111,20,.5); $fallback--panelRadius: 10px; $fallback--checkboxRadius: 2px; diff --git a/src/components/emoji_picker/emoji_picker.js b/src/components/emoji_picker/emoji_picker.js index 81f7437f..11dbdf44 100644 --- a/src/components/emoji_picker/emoji_picker.js +++ b/src/components/emoji_picker/emoji_picker.js @@ -1,5 +1,9 @@ import { set } from 'vue' +const LOAD_EMOJI_BY = 50 +const LOAD_EMOJI_INTERVAL = 100 +const LOAD_EMOJI_SANE_AMOUNT = 500 + const filterByKeyword = (list, keyword = '') => { return list.filter(x => x.displayText.includes(keyword)) } @@ -21,13 +25,17 @@ const EmojiPicker = { groupsScrolledClass: 'scrolled-top', keepOpen: false, customEmojiBuffer: [], - customEmojiInterval: null, - customEmojiCounter: 0 + customEmojiTimeout: null, + customEmojiCounter: 0, + customEmojiLoadAllConfirmed: false } }, components: { StickerPicker: () => import('../sticker_picker/sticker_picker.vue') }, + mounted () { + this.startEmojiLoad() + }, methods: { onEmoji (emoji) { const value = emoji.imageUrl ? `:${emoji.displayText}:` : emoji.replacement @@ -61,35 +69,39 @@ const EmojiPicker = { }) }) }, - restartInterval () { - const customEmojis = filterByKeyword( - this.$store.state.instance.customEmoji || [], - this.keyword - ) - const amount = 50 - const interval = 100 + loadEmojiInsane () { + this.customEmojiLoadAllConfirmed = true + this.continueEmojiLoad() + }, + loadEmoji () { + const allLoaded = this.customEmojiBuffer.length === this.filteredEmoji.length + const saneLoaded = this.customEmojiBuffer.length >= LOAD_EMOJI_SANE_AMOUNT && + !this.customEmojiLoadAllConfirmed - if (this.customEmojiInterval) { - window.clearInterval(this.customEmojiInterval) + if (allLoaded || saneLoaded) { + return } - window.setTimeout( - window.clearInterval(this.customEmojiInterval), - 1000 + + this.customEmojiBuffer.push( + ...this.filteredEmoji.slice( + this.customEmojiCounter, + this.customEmojiCounter + LOAD_EMOJI_BY + ) ) + this.customEmojiTimeout = window.setTimeout(this.loadEmoji, LOAD_EMOJI_INTERVAL) + this.customEmojiCounter += LOAD_EMOJI_BY + }, + startEmojiLoad () { + if (this.customEmojiTimeout) { + window.clearTimeout(this.customEmojiTimeout) + } + set(this, 'customEmojiBuffer', []) this.customEmojiCounter = 0 - this.customEmojiInterval = window.setInterval(() => { - console.log(this.customEmojiBuffer.length) - console.log(customEmojis.length) - if (this.customEmojiBuffer.length < customEmojis.length) { - this.customEmojiBuffer.push( - ...customEmojis.slice(this.customEmojiCounter, this.customEmojiCounter + amount) - ) - } else { - window.clearInterval(this.customEmojiInterval) - } - this.customEmojiCounter += amount - }, interval) + this.customEmojiTimeout = window.setTimeout(this.loadEmoji, LOAD_EMOJI_INTERVAL) + }, + continueEmojiLoad () { + this.customEmojiTimeout = window.setTimeout(this.loadEmoji, LOAD_EMOJI_INTERVAL) }, toggleStickers () { this.showingStickers = !this.showingStickers @@ -107,7 +119,7 @@ const EmojiPicker = { watch: { keyword () { this.scrolledGroup() - this.restartInterval() + this.startEmojiLoad() } }, computed: { @@ -120,6 +132,20 @@ const EmojiPicker = { } return 0 }, + saneAmount () { + // for UI + return LOAD_EMOJI_SANE_AMOUNT + }, + filteredEmoji () { + return filterByKeyword( + this.$store.state.instance.customEmoji || [], + this.keyword + ) + }, + askForSanity () { + return this.customEmojiBuffer.length >= LOAD_EMOJI_SANE_AMOUNT && + !this.customEmojiLoadAllConfirmed + }, emojis () { const standardEmojis = this.$store.state.instance.emoji || [] const customEmojis = this.customEmojiBuffer diff --git a/src/components/emoji_picker/emoji_picker.scss b/src/components/emoji_picker/emoji_picker.scss index b0ed00e9..6608f393 100644 --- a/src/components/emoji_picker/emoji_picker.scss +++ b/src/components/emoji_picker/emoji_picker.scss @@ -6,14 +6,20 @@ position: absolute; right: 0; left: 0; - height: 320px; margin: 0 !important; z-index: 1; - .keep-open { + .keep-open, + .too-many-emoji { padding: 7px; line-height: normal; } + + .too-many-emoji { + display: flex; + flex-direction: column; + } + .keep-open-label { padding: 0 7px; display: flex; @@ -28,7 +34,7 @@ .content { display: flex; flex-direction: column; - flex: 1 1 0; + flex: 1 1 auto; min-height: 0px; } @@ -36,12 +42,16 @@ flex-grow: 1; } + .emoji-groups { + min-height: 200px; + } + .additional-tabs { border-left: 1px solid; border-left-color: $fallback--icon; border-left-color: var(--icon, $fallback--icon); padding-left: 7px; - flex: 0 0 0; + flex: 0 0 auto; } .additional-tabs, @@ -72,7 +82,7 @@ } .sticker-picker { - flex: 1 1 0 + flex: 1 1 auto } .stickers, @@ -80,7 +90,7 @@ &-content { display: flex; flex-direction: column; - flex: 1 1 0; + flex: 1 1 auto; min-height: 0; &.hidden { @@ -94,7 +104,7 @@ .emoji { &-search { padding: 5px; - flex: 0 0 0; + flex: 0 0 auto; input { width: 100%; diff --git a/src/components/emoji_picker/emoji_picker.vue b/src/components/emoji_picker/emoji_picker.vue index 42f20130..d9daac3e 100644 --- a/src/components/emoji_picker/emoji_picker.vue +++ b/src/components/emoji_picker/emoji_picker.vue @@ -92,6 +92,17 @@ +
+
+ {{ $t('emoji.load_all_hint', { saneAmount } ) }} +
+ +
+ +

{{ $t('settings.style.advanced_colors.badge') }}

diff --git a/src/i18n/en.json b/src/i18n/en.json index 32c25e3e..c6c98c48 100644 --- a/src/i18n/en.json +++ b/src/i18n/en.json @@ -114,7 +114,9 @@ "search_emoji": "Search for an emoji", "add_emoji": "Insert emoji", "custom": "Custom emoji", - "unicode": "Unicode emoji" + "unicode": "Unicode emoji", + "load_all_hint": "Loaded first {saneAmount} emoji, loading all emoji may cause performance issues.", + "load_all": "Loading all {emojiAmount} emoji" }, "interactions": { "favs_repeats": "Repeats and Favorites", @@ -387,6 +389,7 @@ "_tab_label": "Advanced", "alert": "Alert background", "alert_error": "Error", + "alert_warning": "Warning", "badge": "Badge background", "badge_notification": "Notification", "panel_header": "Panel header", diff --git a/src/services/style_setter/style_setter.js b/src/services/style_setter/style_setter.js index 1cf7edc3..eaa495c4 100644 --- a/src/services/style_setter/style_setter.js +++ b/src/services/style_setter/style_setter.js @@ -215,6 +215,10 @@ const generateColors = (input) => { colors.alertErrorText = getTextColor(alphaBlend(colors.alertError, opacity.alert, colors.bg), colors.text) colors.alertErrorPanelText = getTextColor(alphaBlend(colors.alertError, opacity.alert, colors.panel), colors.panelText) + colors.alertWarning = col.alertWarning || Object.assign({}, colors.cOrange) + colors.alertWarningText = getTextColor(alphaBlend(colors.alertWarning, opacity.alert, colors.bg), colors.text) + colors.alertWarningPanelText = getTextColor(alphaBlend(colors.alertWarning, opacity.alert, colors.panel), colors.panelText) + colors.badgeNotification = col.badgeNotification || Object.assign({}, colors.cRed) colors.badgeNotificationText = contrastRatio(colors.badgeNotification).rgb @@ -222,6 +226,7 @@ const generateColors = (input) => { if (typeof v === 'undefined') return if (k === 'alert') { colors.alertError.a = v + colors.alertWarning.a = v return } if (k === 'faint') { From 37b8490c01ab4ccb9670922b58d3a6e6bb052a20 Mon Sep 17 00:00:00 2001 From: Henry Jameson Date: Tue, 8 Oct 2019 20:53:55 +0300 Subject: [PATCH 04/19] remove the "textbox grows the 'wrong' way" behavior, replace it with more conditions to scroll to bottom --- .../post_status_form/post_status_form.js | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/src/components/post_status_form/post_status_form.js b/src/components/post_status_form/post_status_form.js index 9b2a9c90..dba03b4e 100644 --- a/src/components/post_status_form/post_status_form.js +++ b/src/components/post_status_form/post_status_form.js @@ -301,9 +301,6 @@ const PostStatusForm = { const bottomPadding = Number(bottomPaddingStr.substring(0, bottomPaddingStr.length - 2)) const vertPadding = topPadding + bottomPadding - const oldHeightStr = target.style.height || '' - const oldHeight = Number(oldHeightStr.substring(0, oldHeightStr.length - 2)) - /* Explanation: * * https://developer.mozilla.org/en-US/docs/Web/API/Element/scrollHeight @@ -340,12 +337,17 @@ const PostStatusForm = { // to find offset relative to scrollable container (scroller) const rootBottomBorder = rootRef.offsetHeight + findOffset(rootRef, scrollerRef).top - const textareaSizeChangeDelta = newHeight - oldHeight || 0 const isBottomObstructed = scrollerBottomBorder < rootBottomBorder + const isRootBiggerThanScroller = scrollerHeight < rootRef.offsetHeight const rootChangeDelta = rootBottomBorder - scrollerBottomBorder - const totalDelta = textareaSizeChangeDelta + - (isBottomObstructed ? rootChangeDelta : 0) - + // The intention is basically this; + // Keep bottom side always visible so that submit button is in view EXCEPT + // if root element bigger than scroller and caret isn't at the end, so that + // if you scroll up and edit middle of text you won't get scrolled back to bottom + const shouldScrollToBottom = isBottomObstructed && + !(isRootBiggerThanScroller && + this.$refs.textarea.selectionStart !== this.$refs.textarea.value.length) + const totalDelta = shouldScrollToBottom ? rootChangeDelta : 0 const targetScroll = currentScroll + totalDelta if (scrollerRef === window) { From bed109ae46a7ae6db7264b9cfb1d3ed88372e270 Mon Sep 17 00:00:00 2001 From: Henry Jameson Date: Tue, 8 Oct 2019 20:54:30 +0300 Subject: [PATCH 05/19] start loading emoji when picker is open --- src/components/emoji_input/emoji_input.js | 2 ++ src/components/emoji_picker/emoji_picker.js | 3 --- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/components/emoji_input/emoji_input.js b/src/components/emoji_input/emoji_input.js index a586b819..920fd4bd 100644 --- a/src/components/emoji_input/emoji_input.js +++ b/src/components/emoji_input/emoji_input.js @@ -165,6 +165,7 @@ const EmojiInput = { methods: { triggerShowPicker () { this.showPicker = true + this.$refs.picker.startEmojiLoad() this.$nextTick(() => { this.scrollIntoView() }) @@ -181,6 +182,7 @@ const EmojiInput = { this.showPicker = !this.showPicker if (this.showPicker) { this.scrollIntoView() + this.$refs.picker.startEmojiLoad() } }, replace (replacement) { diff --git a/src/components/emoji_picker/emoji_picker.js b/src/components/emoji_picker/emoji_picker.js index 11dbdf44..29e07299 100644 --- a/src/components/emoji_picker/emoji_picker.js +++ b/src/components/emoji_picker/emoji_picker.js @@ -33,9 +33,6 @@ const EmojiPicker = { components: { StickerPicker: () => import('../sticker_picker/sticker_picker.vue') }, - mounted () { - this.startEmojiLoad() - }, methods: { onEmoji (emoji) { const value = emoji.imageUrl ? `:${emoji.displayText}:` : emoji.replacement From 81d86a39fe84794005772a382cbb0f7b3b0c97c7 Mon Sep 17 00:00:00 2001 From: Henry Jameson Date: Tue, 8 Oct 2019 21:30:27 +0300 Subject: [PATCH 06/19] fixed emoji picker showing up beyond viewport --- src/components/emoji_input/emoji_input.js | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/src/components/emoji_input/emoji_input.js b/src/components/emoji_input/emoji_input.js index 920fd4bd..c02a9327 100644 --- a/src/components/emoji_input/emoji_input.js +++ b/src/components/emoji_input/emoji_input.js @@ -308,6 +308,17 @@ const EmojiInput = { } else { scrollerRef.scrollTop = targetScroll } + + this.$nextTick(() => { + const { offsetHeight } = this.input.elm + const { picker } = this.$refs + console.log(picker) + const pickerBottom = picker.$el.getBoundingClientRect().bottom + if (pickerBottom > window.innerHeight) { + picker.$el.style.top = 'auto' + picker.$el.style.bottom = offsetHeight + 'px' + } + }) }, onTransition (e) { this.resize() @@ -421,11 +432,14 @@ const EmojiInput = { this.caret = selectionStart }, resize () { - const { panel } = this.$refs + const { panel, picker } = this.$refs if (!panel) return const { offsetHeight, offsetTop } = this.input.elm - this.$refs.panel.style.top = (offsetTop + offsetHeight) + 'px' - this.$refs.picker.$el.style.top = (offsetTop + offsetHeight) + 'px' + const offsetBottom = offsetTop + offsetHeight + + panel.style.top = offsetBottom + 'px' + picker.$el.style.top = offsetBottom + 'px' + picker.$el.style.bottom = 'auto' } } } From fa4e69ec8ca430c0b0fae6418d955580a1a727d0 Mon Sep 17 00:00:00 2001 From: Henry Jameson Date: Tue, 8 Oct 2019 21:34:36 +0300 Subject: [PATCH 07/19] eslint --- src/components/emoji_picker/emoji_picker.vue | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/components/emoji_picker/emoji_picker.vue b/src/components/emoji_picker/emoji_picker.vue index d9daac3e..56501467 100644 --- a/src/components/emoji_picker/emoji_picker.vue +++ b/src/components/emoji_picker/emoji_picker.vue @@ -92,14 +92,17 @@
-
+
{{ $t('emoji.load_all_hint', { saneAmount } ) }}
From b02de56fcbe8433597a738a797cfe5fb9f57eb3d Mon Sep 17 00:00:00 2001 From: Henry Jameson Date: Wed, 9 Oct 2019 22:33:15 +0300 Subject: [PATCH 08/19] always preload first batch of emoji to avoid unnecessary UI jumps --- src/components/emoji_picker/emoji_picker.js | 24 +++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/src/components/emoji_picker/emoji_picker.js b/src/components/emoji_picker/emoji_picker.js index 29e07299..67b08ef8 100644 --- a/src/components/emoji_picker/emoji_picker.js +++ b/src/components/emoji_picker/emoji_picker.js @@ -24,9 +24,10 @@ const EmojiPicker = { showingStickers: false, groupsScrolledClass: 'scrolled-top', keepOpen: false, - customEmojiBuffer: [], + customEmojiBuffer: (this.$store.state.instance.customEmoji || []) + .slice(0, LOAD_EMOJI_BY), customEmojiTimeout: null, - customEmojiCounter: 0, + customEmojiCounter: LOAD_EMOJI_BY, customEmojiLoadAllConfirmed: false } }, @@ -88,13 +89,23 @@ const EmojiPicker = { this.customEmojiTimeout = window.setTimeout(this.loadEmoji, LOAD_EMOJI_INTERVAL) this.customEmojiCounter += LOAD_EMOJI_BY }, - startEmojiLoad () { + startEmojiLoad (forceUpdate = false) { + const bufferSize = this.customEmojiBuffer.length + const bufferPrefilledSane = bufferSize === LOAD_EMOJI_SANE_AMOUNT && !this.customEmojiLoadAllConfirmed + const bufferPrefilledAll = bufferSize === this.filteredEmoji.length + if (!forceUpdate || bufferPrefilledSane || bufferPrefilledAll) { + return + } if (this.customEmojiTimeout) { window.clearTimeout(this.customEmojiTimeout) } - set(this, 'customEmojiBuffer', []) - this.customEmojiCounter = 0 + set( + this, + 'customEmojiBuffer', + this.filteredEmoji.slice(0, LOAD_EMOJI_BY) + ) + this.customEmojiCounter = LOAD_EMOJI_BY this.customEmojiTimeout = window.setTimeout(this.loadEmoji, LOAD_EMOJI_INTERVAL) }, continueEmojiLoad () { @@ -115,8 +126,9 @@ const EmojiPicker = { }, watch: { keyword () { + this.customEmojiLoadAllConfirmed = false this.scrolledGroup() - this.startEmojiLoad() + this.startEmojiLoad(true) } }, computed: { From c000879f2fb20b273731d78dda5499e4b3cb77c2 Mon Sep 17 00:00:00 2001 From: Henry Jameson Date: Wed, 9 Oct 2019 22:50:00 +0300 Subject: [PATCH 09/19] moved emoji fetching from user to instance since it's its state anyway --- src/modules/instance.js | 61 +++++++++++++++++++++++++++++++++++++++++ src/modules/users.js | 53 +---------------------------------- 2 files changed, 62 insertions(+), 52 deletions(-) diff --git a/src/modules/instance.js b/src/modules/instance.js index 7d602aa1..15280e82 100644 --- a/src/modules/instance.js +++ b/src/modules/instance.js @@ -35,7 +35,9 @@ const defaultState = { // Nasty stuff pleromaBackend: true, emoji: [], + emojiFetched: false, customEmoji: [], + customEmojiFetched: false, restrictedNicknames: [], postFormats: [], @@ -86,9 +88,68 @@ const instance = { break } }, + async getStaticEmoji ({ commit }) { + try { + 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, + imageUrl: false, + replacement: values[key] + } + }).sort((a, b) => a.displayText - b.displayText) + commit('setInstanceOption', { name: 'emoji', value: emoji }) + } else { + throw (res) + } + } catch (e) { + console.warn("Can't load static emoji") + console.warn(e) + } + }, + + async getCustomEmoji ({ commit, state }) { + try { + const res = await window.fetch('/api/pleroma/emoji.json') + if (res.ok) { + const result = await res.json() + const values = Array.isArray(result) ? Object.assign({}, ...result) : result + const emoji = Object.entries(values).map(([key, value]) => { + const imageUrl = value.image_url + return { + displayText: key, + imageUrl: imageUrl ? state.server + imageUrl : value, + tags: imageUrl ? value.tags.sort((a, b) => a > b ? 1 : 0) : ['utf'], + replacement: `:${key}: ` + } + // Technically could use tags but those are kinda useless right now, + // should have been "pack" field, that would be more useful + }).sort((a, b) => a.displayText.toLowerCase() > b.displayText.toLowerCase() ? 1 : 0) + commit('setInstanceOption', { name: 'customEmoji', value: emoji }) + } else { + throw (res) + } + } catch (e) { + console.warn("Can't load custom emojis") + console.warn(e) + } + }, + setTheme ({ commit }, themeName) { commit('setInstanceOption', { name: 'theme', value: themeName }) return setPreset(themeName, commit) + }, + fetchEmoji ({ dispatch, state }) { + if (!state.customEmojiFetched) { + state.customEmojiFetched = true + dispatch('getCustomEmoji') + } + if (!state.emojiFetched) { + state.emojiFetched = true + dispatch('getStaticEmoji') + } } } } diff --git a/src/modules/users.js b/src/modules/users.js index fed948e4..0b2f8a9e 100644 --- a/src/modules/users.js +++ b/src/modules/users.js @@ -60,56 +60,6 @@ const unmuteUser = (store, id) => { .then((relationship) => store.commit('updateUserRelationship', [relationship])) } -const getStaticEmoji = async (store) => { - try { - 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, - imageUrl: false, - replacement: values[key] - } - }).sort((a, b) => a.displayText - b.displayText) - store.dispatch('setInstanceOption', { name: 'emoji', value: emoji }) - } else { - throw (res) - } - } catch (e) { - console.warn("Can't load static emoji") - console.warn(e) - } -} - -// This is also used to indicate if we have a 'pleroma backend' or not. -// Somewhat weird, should probably be somewhere else. -const getCustomEmoji = async (store) => { - try { - const res = await window.fetch('/api/pleroma/emoji.json') - if (res.ok) { - const result = await res.json() - const values = Array.isArray(result) ? Object.assign({}, ...result) : result - const emoji = Object.entries(values).map(([key, value]) => { - const imageUrl = value.image_url - return { - displayText: key, - imageUrl: imageUrl ? store.rootState.instance.server + imageUrl : value, - tags: imageUrl ? value.tags.sort((a, b) => a > b ? 1 : 0) : ['utf'], - replacement: `:${key}: ` - } - // Technically could use tags but those are kinda useless right now, should have been "pack" field, that would be more useful - }).sort((a, b) => a.displayText.toLowerCase() > b.displayText.toLowerCase() ? 1 : 0) - store.dispatch('setInstanceOption', { name: 'customEmoji', value: emoji }) - } else { - throw (res) - } - } catch (e) { - console.warn("Can't load custom emojis") - console.warn(e) - } -} - export const mutations = { setMuted (state, { user: { id }, muted }) { const user = state.usersObject[id] @@ -484,8 +434,7 @@ const users = { commit('setCurrentUser', user) commit('addNewUsers', [user]) - getCustomEmoji(store) - getStaticEmoji(store) + store.dispatch('fetchEmoji') getNotificationPermission() .then(permission => commit('setNotificationPermission', permission)) From 1400d723f25ded6614a6f27cb35b3b25edc2b1ec Mon Sep 17 00:00:00 2001 From: Henry Jameson Date: Thu, 10 Oct 2019 19:58:00 +0300 Subject: [PATCH 10/19] fix picker not filling on opening, removed console log --- src/components/emoji_input/emoji_input.js | 1 - src/components/emoji_picker/emoji_picker.js | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/components/emoji_input/emoji_input.js b/src/components/emoji_input/emoji_input.js index c02a9327..2c73faa7 100644 --- a/src/components/emoji_input/emoji_input.js +++ b/src/components/emoji_input/emoji_input.js @@ -312,7 +312,6 @@ const EmojiInput = { this.$nextTick(() => { const { offsetHeight } = this.input.elm const { picker } = this.$refs - console.log(picker) const pickerBottom = picker.$el.getBoundingClientRect().bottom if (pickerBottom > window.innerHeight) { picker.$el.style.top = 'auto' diff --git a/src/components/emoji_picker/emoji_picker.js b/src/components/emoji_picker/emoji_picker.js index 67b08ef8..0d5ffc9b 100644 --- a/src/components/emoji_picker/emoji_picker.js +++ b/src/components/emoji_picker/emoji_picker.js @@ -93,7 +93,7 @@ const EmojiPicker = { const bufferSize = this.customEmojiBuffer.length const bufferPrefilledSane = bufferSize === LOAD_EMOJI_SANE_AMOUNT && !this.customEmojiLoadAllConfirmed const bufferPrefilledAll = bufferSize === this.filteredEmoji.length - if (!forceUpdate || bufferPrefilledSane || bufferPrefilledAll) { + if (forceUpdate || bufferPrefilledSane || bufferPrefilledAll) { return } if (this.customEmojiTimeout) { From 62661487452847f33c6cd5473fa972892a14908d Mon Sep 17 00:00:00 2001 From: Henry Jameson Date: Mon, 14 Oct 2019 19:56:46 +0300 Subject: [PATCH 11/19] Reserve space for emoji picker button in emoji input --- src/components/emoji_input/emoji_input.vue | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/components/emoji_input/emoji_input.vue b/src/components/emoji_input/emoji_input.vue index 13530e8b..a7215670 100644 --- a/src/components/emoji_input/emoji_input.vue +++ b/src/components/emoji_input/emoji_input.vue @@ -2,6 +2,7 @@