From db961af3c8ee11823a4b33c3127635c280996183 Mon Sep 17 00:00:00 2001 From: Henry Jameson Date: Sun, 15 Sep 2019 16:01:57 +0300 Subject: [PATCH 1/7] unit test for emoji input, for now covering only insertion mechanism --- .../unit/specs/components/emoji_input.spec.js | 122 ++++++++++++++++++ 1 file changed, 122 insertions(+) create mode 100644 test/unit/specs/components/emoji_input.spec.js diff --git a/test/unit/specs/components/emoji_input.spec.js b/test/unit/specs/components/emoji_input.spec.js new file mode 100644 index 000000000..5f24331a6 --- /dev/null +++ b/test/unit/specs/components/emoji_input.spec.js @@ -0,0 +1,122 @@ +import { shallowMount, createLocalVue } from '@vue/test-utils' +import EmojiInput from 'src/components/emoji_input/emoji_input.vue' + +const generateInput = (value) => { + const localVue = createLocalVue() + localVue.directive('click-outside', () => {}) + const wrapper = shallowMount(EmojiInput, { + propsData: { + suggest: () => [], + enableEmojiPicker: true, + value + }, + slots: { + default: '' + }, + localVue + }) + return [wrapper, localVue] +} + +describe('EmojiInput', () => { + describe('insertion mechanism', () => { + it('inserts string at the end with trailing space', () => { + const initialString = 'Testing' + const [wrapper] = generateInput(initialString) + const input = wrapper.find('input') + input.setValue(initialString) + wrapper.setData({ caret: initialString.length }) + wrapper.vm.insert({ insertion: '(test)', spamMode: false }) + expect(wrapper.emitted().input[0][0]).to.eql('Testing (test) ') + }) + + it('inserts string at the end with trailing space (source has a trailing space)', () => { + const initialString = 'Testing ' + const [wrapper] = generateInput(initialString) + const input = wrapper.find('input') + input.setValue(initialString) + wrapper.setData({ caret: initialString.length }) + wrapper.vm.insert({ insertion: '(test)', spamMode: false }) + expect(wrapper.emitted().input[0][0]).to.eql('Testing (test) ') + }) + + it('inserts string at the begginning without leading space', () => { + const initialString = 'Testing' + const [wrapper] = generateInput(initialString) + const input = wrapper.find('input') + input.setValue(initialString) + wrapper.setData({ caret: 0 }) + wrapper.vm.insert({ insertion: '(test)', spamMode: false }) + expect(wrapper.emitted().input[0][0]).to.eql('(test) Testing') + }) + + it('inserts string between words without creating extra spaces', () => { + const initialString = 'Spurdo Sparde' + const [wrapper] = generateInput(initialString) + const input = wrapper.find('input') + input.setValue(initialString) + wrapper.setData({ caret: 6 }) + wrapper.vm.insert({ insertion: ':ebin:', spamMode: false }) + expect(wrapper.emitted().input[0][0]).to.eql('Spurdo :ebin: Sparde') + }) + + it('inserts string between words without creating extra spaces (other caret)', () => { + const initialString = 'Spurdo Sparde' + const [wrapper] = generateInput(initialString) + const input = wrapper.find('input') + input.setValue(initialString) + wrapper.setData({ caret: 7 }) + wrapper.vm.insert({ insertion: ':ebin:', spamMode: false }) + expect(wrapper.emitted().input[0][0]).to.eql('Spurdo :ebin: Sparde') + }) + + it('inserts string without any padding in spam mode', () => { + const initialString = 'Eat some spam!' + const [wrapper] = generateInput(initialString) + const input = wrapper.find('input') + input.setValue(initialString) + wrapper.setData({ caret: initialString.length }) + wrapper.vm.insert({ insertion: ':spam:', spamMode: true }) + expect(wrapper.emitted().input[0][0]).to.eql('Eat some spam!:spam:') + }) + + it('correctly sets caret after insertion at beginning', (done) => { + const initialString = '1234' + const [wrapper, vue] = generateInput(initialString) + const input = wrapper.find('input') + input.setValue(initialString) + wrapper.setData({ caret: 0 }) + wrapper.vm.insert({ insertion: '1234', spamMode: false }) + vue.nextTick(() => { + expect(wrapper.vm.caret).to.eql(5) + done() + }) + }) + + it('correctly sets caret after insertion at end', (done) => { + const initialString = '1234' + const [wrapper, vue] = generateInput(initialString) + const input = wrapper.find('input') + input.setValue(initialString) + wrapper.setData({ caret: initialString.length }) + wrapper.vm.insert({ insertion: '1234', spamMode: false }) + vue.nextTick(() => { + expect(wrapper.vm.caret).to.eql(10) + done() + }) + }) + + it('correctly sets caret after insertion in spam mode', (done) => { + const initialString = '1234' + const [wrapper, vue] = generateInput(initialString) + const input = wrapper.find('input') + input.setValue(initialString) + wrapper.setData({ caret: initialString.length }) + wrapper.vm.insert({ insertion: '1234', spamMode: true }) + vue.nextTick(() => { + expect(wrapper.vm.caret).to.eql(8) + done() + }) + }) + }) +}) From f961ce0f98c655364c6b780bc4dbf8f635e32cbc Mon Sep 17 00:00:00 2001 From: Henry Jameson Date: Sun, 15 Sep 2019 16:40:31 +0300 Subject: [PATCH 2/7] docs update --- docs/USER_GUIDE.md | 7 +++++++ docs/example_emoji.png | Bin 0 -> 491 bytes 2 files changed, 7 insertions(+) create mode 100644 docs/example_emoji.png diff --git a/docs/USER_GUIDE.md b/docs/USER_GUIDE.md index cb95a2440..81490f221 100644 --- a/docs/USER_GUIDE.md +++ b/docs/USER_GUIDE.md @@ -23,6 +23,13 @@ Posts will contain the text you are posting, but some content will be modified: **Depending on your instance some of the options might not be available or have different defaults** Let's clear up some basic stuff. When you post something it's called a **post** or it could be called a **status** or even a **toot** or a **prööt** depending on whom you ask. Post has body/content but it also has some other stuff in it - from attachments, visibility scope, subject line. +* **Emoji** are small images embedded in text, there are two major types of emoji: [unicode emoji](https://en.wikipedia.org/wiki/Emoji) and custom emoji. While unicode emoji are universal and standardized, they can appear differently depending on where you are using them or may not appear at all on older systems. Custom emoji are more *fun* kind - instance administrator can define many images as *custom emoji* for their users. This works very simple - custom emoji is defined by its *shortcode* and an image, so that any shortcode enclosed in colons get replaced with image if such shortcode exist. +Let's say there's `:pleroma:` emoji defined on instance. That means +> First time using :pleroma: pleroma! +will become +> First time using ![pleroma](./example_emoji.png) pleroma! +Note that you can only use emoji defined on your instance, you cannot "copy" someone else's emoji, and will have to ask your administrator to copy emoji from other instance to yours. +Lastly, there's two convenience options for emoji: an emoji picker (smiley face to the right of "submit" button) and autocomplete suggestions - when you start typing :shortcode: it will automatically try to suggest you emoj and complete the shortcode for you if you select one. **Note** that if emoji doesn't show up in suggestions nor in emoji picker it means there's no such emoji on your instance, if shortcode doesn't match any defined emoji it will appear as text. * **Attachments** are fairly simple - you can attach any file to a post as long as the file is within maximum size limits. If you're uploading explicit material you can mark all of your attachments as sensitive (or add `#nsfw` tag) - it will hide the images and videos behind a warning so that it won't be displayed instantly. * **Subject line** also known as **CW** (Content Warning) could be used as a header to the post and/or to warn others about contents of the post having something that might upset somebody or something among those lines. Several applications allow to hide post content leaving only subject line visible. As a side-effect using subject line will also mark your images as sensitive (see above). * **Visiblity scope** controls who will be able to see your posts. There are four scopes available: diff --git a/docs/example_emoji.png b/docs/example_emoji.png new file mode 100644 index 0000000000000000000000000000000000000000..0a22a256b00f1fbe962cd1988ec4df5cb6024bec GIT binary patch literal 491 zcmV<{Zw<2*9B?w#`Yw4B)3cGKFN_ ze2T3Iy{UCUO0kRr3CXsMBy0iLO2K4*>B__w z!1YU3Ex>19ss$*eDgY$|2zsj30ys5=Ct#%WEbcuNw-x`T>FwJ}5mo?7{~q{Dv%^6K zn(Hic;fo|&$FJo9=xVHCu)W@TgFa`~rodGt)B Date: Sun, 15 Sep 2019 13:43:42 +0000 Subject: [PATCH 3/7] Update docs/USER_GUIDE.md --- docs/USER_GUIDE.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/USER_GUIDE.md b/docs/USER_GUIDE.md index 81490f221..18b6c5601 100644 --- a/docs/USER_GUIDE.md +++ b/docs/USER_GUIDE.md @@ -26,8 +26,10 @@ Let's clear up some basic stuff. When you post something it's called a **post** * **Emoji** are small images embedded in text, there are two major types of emoji: [unicode emoji](https://en.wikipedia.org/wiki/Emoji) and custom emoji. While unicode emoji are universal and standardized, they can appear differently depending on where you are using them or may not appear at all on older systems. Custom emoji are more *fun* kind - instance administrator can define many images as *custom emoji* for their users. This works very simple - custom emoji is defined by its *shortcode* and an image, so that any shortcode enclosed in colons get replaced with image if such shortcode exist. Let's say there's `:pleroma:` emoji defined on instance. That means > First time using :pleroma: pleroma! + will become > First time using ![pleroma](./example_emoji.png) pleroma! + Note that you can only use emoji defined on your instance, you cannot "copy" someone else's emoji, and will have to ask your administrator to copy emoji from other instance to yours. Lastly, there's two convenience options for emoji: an emoji picker (smiley face to the right of "submit" button) and autocomplete suggestions - when you start typing :shortcode: it will automatically try to suggest you emoj and complete the shortcode for you if you select one. **Note** that if emoji doesn't show up in suggestions nor in emoji picker it means there's no such emoji on your instance, if shortcode doesn't match any defined emoji it will appear as text. * **Attachments** are fairly simple - you can attach any file to a post as long as the file is within maximum size limits. If you're uploading explicit material you can mark all of your attachments as sensitive (or add `#nsfw` tag) - it will hide the images and videos behind a warning so that it won't be displayed instantly. From c933f5edfcf50b8e8ed17ae52a8fb4df04e8c7cf Mon Sep 17 00:00:00 2001 From: Henry Jameson Date: Sun, 15 Sep 2019 17:19:17 +0300 Subject: [PATCH 4/7] changelog --- CHANGELOG.md | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 CHANGELOG.md diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 000000000..ff4c2fd1b --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,13 @@ +# Changelog +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), + +## [Unreleased] +### Added +- Emoji picker +- Started changelog anew +### Changed +- changed the way fading effects for user profile/long statuses works, now uses css-mask instead of gradient background hacks which weren't exactly compatible with semi-transparent themes +### Fixed +- improved hotkey behavior on autocomplete popup From 3cd23ae2d4d28c79890442bf343a55e44544bcdf Mon Sep 17 00:00:00 2001 From: HJ <30-hj@users.noreply.git.pleroma.social> Date: Mon, 16 Sep 2019 07:23:56 +0000 Subject: [PATCH 5/7] Apply suggestion to src/components/emoji_input/emoji_input.js --- src/components/emoji_input/emoji_input.js | 1 - 1 file changed, 1 deletion(-) diff --git a/src/components/emoji_input/emoji_input.js b/src/components/emoji_input/emoji_input.js index 41ee239c5..86ff97073 100644 --- a/src/components/emoji_input/emoji_input.js +++ b/src/components/emoji_input/emoji_input.js @@ -64,7 +64,6 @@ const EmojiInput = { }, hideEmojiButton: { /** - enableStickerPicker: { * intended to use with external picker trigger, i.e. you have a button outside * input that will open up the picker, see triggerShowPicker() */ From 7b4cb387345c0e278a6cfe5bbff5265c09281567 Mon Sep 17 00:00:00 2001 From: Henry Jameson Date: Mon, 23 Sep 2019 20:29:01 +0300 Subject: [PATCH 6/7] split spam mode into two separate options (one in settings page) --- src/components/emoji_input/emoji_input.js | 15 +++++++++------ src/components/emoji_picker/emoji_picker.js | 4 ++-- src/components/emoji_picker/emoji_picker.scss | 4 ++-- src/components/emoji_picker/emoji_picker.vue | 12 ++++++------ src/components/settings/settings.js | 4 ++++ src/components/settings/settings.vue | 8 ++++++++ src/i18n/en.json | 3 ++- src/modules/config.js | 1 + test/unit/specs/components/emoji_input.spec.js | 18 +++++++++--------- 9 files changed, 43 insertions(+), 26 deletions(-) diff --git a/src/components/emoji_input/emoji_input.js b/src/components/emoji_input/emoji_input.js index 86ff97073..5f90d7f46 100644 --- a/src/components/emoji_input/emoji_input.js +++ b/src/components/emoji_input/emoji_input.js @@ -89,7 +89,7 @@ const EmojiInput = { blurTimeout: null, showPicker: false, temporarilyHideSuggestions: false, - spamMode: false, + keepOpen: false, disableClickOutside: false } }, @@ -97,6 +97,9 @@ const EmojiInput = { EmojiPicker }, computed: { + padEmoji () { + return this.$store.state.config.padEmoji + }, suggestions () { const firstchar = this.textAtCaret.charAt(0) if (this.textAtCaret === firstchar) { return [] } @@ -176,7 +179,7 @@ const EmojiInput = { this.$emit('input', newValue) this.caret = 0 }, - insert ({ insertion, spamMode }) { + insert ({ insertion, keepOpen }) { const before = this.value.substring(0, this.caret) || '' const after = this.value.substring(this.caret) || '' @@ -195,8 +198,8 @@ const EmojiInput = { * them, masto seem to be rendering :emoji::emoji: correctly now so why not */ const isSpaceRegex = /\s/ - const spaceBefore = !isSpaceRegex.exec(before.slice(-1)) && before.length && !spamMode > 0 ? ' ' : '' - const spaceAfter = !isSpaceRegex.exec(after[0]) && !spamMode ? ' ' : '' + const spaceBefore = !isSpaceRegex.exec(before.slice(-1)) && before.length && this.padEmoji > 0 ? ' ' : '' + const spaceAfter = !isSpaceRegex.exec(after[0]) && this.padEmoji ? ' ' : '' const newValue = [ before, @@ -205,7 +208,7 @@ const EmojiInput = { spaceAfter, after ].join('') - this.spamMode = spamMode + this.keepOpen = keepOpen this.$emit('input', newValue) const position = this.caret + (insertion + spaceAfter + spaceBefore).length @@ -283,7 +286,7 @@ const EmojiInput = { this.blurTimeout = null } - if (!this.spamMode) { + if (!this.keepOpen) { this.showPicker = false } this.focused = true diff --git a/src/components/emoji_picker/emoji_picker.js b/src/components/emoji_picker/emoji_picker.js index cb93f0c18..824412ddc 100644 --- a/src/components/emoji_picker/emoji_picker.js +++ b/src/components/emoji_picker/emoji_picker.js @@ -18,7 +18,7 @@ const EmojiPicker = { activeGroup: 'custom', showingStickers: false, groupsScrolledClass: 'scrolled-top', - spamMode: false + keepOpen: false } }, components: { @@ -27,7 +27,7 @@ const EmojiPicker = { methods: { onEmoji (emoji) { const value = emoji.imageUrl ? `:${emoji.displayText}:` : emoji.replacement - this.$emit('emoji', { insertion: value, spamMode: this.spamMode }) + this.$emit('emoji', { insertion: value, keepOpen: this.keepOpen }) }, highlight (key) { const ref = this.$refs['group-' + key] diff --git a/src/components/emoji_picker/emoji_picker.scss b/src/components/emoji_picker/emoji_picker.scss index 094388987..b0ed00e99 100644 --- a/src/components/emoji_picker/emoji_picker.scss +++ b/src/components/emoji_picker/emoji_picker.scss @@ -10,11 +10,11 @@ margin: 0 !important; z-index: 1; - .spam-mode { + .keep-open { padding: 7px; line-height: normal; } - .spam-mode-label { + .keep-open-label { padding: 0 7px; display: flex; } diff --git a/src/components/emoji_picker/emoji_picker.vue b/src/components/emoji_picker/emoji_picker.vue index b32d08622..6c43dd970 100644 --- a/src/components/emoji_picker/emoji_picker.vue +++ b/src/components/emoji_picker/emoji_picker.vue @@ -76,16 +76,16 @@
-
diff --git a/src/i18n/en.json b/src/i18n/en.json index 7676e7a83..20d4ed221 100644 --- a/src/i18n/en.json +++ b/src/i18n/en.json @@ -109,7 +109,7 @@ "emoji": { "stickers": "Stickers", "emoji": "Emoji", - "spam": "Keep picker open, don't separate emoji with spaces", + "keep_open": "Keep picker open", "search_emoji": "Search for an emoji", "add_emoji": "Insert emoji", "custom": "Custom emoji", @@ -232,6 +232,7 @@ "delete_account_error": "There was an issue deleting your account. If this persists please contact your instance administrator.", "delete_account_instructions": "Type your password in the input below to confirm account deletion.", "avatar_size_instruction": "The recommended minimum size for avatar images is 150x150 pixels.", + "pad_emoji": "Pad emoji with spaces when adding from picker", "export_theme": "Save preset", "filtering": "Filtering", "filtering_explanation": "All statuses containing these words will be muted, one per line", diff --git a/src/modules/config.js b/src/modules/config.js index 2bfad8f6f..cf04d14fe 100644 --- a/src/modules/config.js +++ b/src/modules/config.js @@ -7,6 +7,7 @@ const defaultState = { colors: {}, hideMutedPosts: undefined, // instance default collapseMessageWithSubject: undefined, // instance default + padEmoji: true, hideAttachments: false, hideAttachmentsInConv: false, maxThumbnails: 16, diff --git a/test/unit/specs/components/emoji_input.spec.js b/test/unit/specs/components/emoji_input.spec.js index 5f24331a6..13a599615 100644 --- a/test/unit/specs/components/emoji_input.spec.js +++ b/test/unit/specs/components/emoji_input.spec.js @@ -26,7 +26,7 @@ describe('EmojiInput', () => { const input = wrapper.find('input') input.setValue(initialString) wrapper.setData({ caret: initialString.length }) - wrapper.vm.insert({ insertion: '(test)', spamMode: false }) + wrapper.vm.insert({ insertion: '(test)', keepOpen: false }) expect(wrapper.emitted().input[0][0]).to.eql('Testing (test) ') }) @@ -36,7 +36,7 @@ describe('EmojiInput', () => { const input = wrapper.find('input') input.setValue(initialString) wrapper.setData({ caret: initialString.length }) - wrapper.vm.insert({ insertion: '(test)', spamMode: false }) + wrapper.vm.insert({ insertion: '(test)', keepOpen: false }) expect(wrapper.emitted().input[0][0]).to.eql('Testing (test) ') }) @@ -46,7 +46,7 @@ describe('EmojiInput', () => { const input = wrapper.find('input') input.setValue(initialString) wrapper.setData({ caret: 0 }) - wrapper.vm.insert({ insertion: '(test)', spamMode: false }) + wrapper.vm.insert({ insertion: '(test)', keepOpen: false }) expect(wrapper.emitted().input[0][0]).to.eql('(test) Testing') }) @@ -56,7 +56,7 @@ describe('EmojiInput', () => { const input = wrapper.find('input') input.setValue(initialString) wrapper.setData({ caret: 6 }) - wrapper.vm.insert({ insertion: ':ebin:', spamMode: false }) + wrapper.vm.insert({ insertion: ':ebin:', keepOpen: false }) expect(wrapper.emitted().input[0][0]).to.eql('Spurdo :ebin: Sparde') }) @@ -66,7 +66,7 @@ describe('EmojiInput', () => { const input = wrapper.find('input') input.setValue(initialString) wrapper.setData({ caret: 7 }) - wrapper.vm.insert({ insertion: ':ebin:', spamMode: false }) + wrapper.vm.insert({ insertion: ':ebin:', keepOpen: false }) expect(wrapper.emitted().input[0][0]).to.eql('Spurdo :ebin: Sparde') }) @@ -76,7 +76,7 @@ describe('EmojiInput', () => { const input = wrapper.find('input') input.setValue(initialString) wrapper.setData({ caret: initialString.length }) - wrapper.vm.insert({ insertion: ':spam:', spamMode: true }) + wrapper.vm.insert({ insertion: ':spam:', keepOpen: true }) expect(wrapper.emitted().input[0][0]).to.eql('Eat some spam!:spam:') }) @@ -86,7 +86,7 @@ describe('EmojiInput', () => { const input = wrapper.find('input') input.setValue(initialString) wrapper.setData({ caret: 0 }) - wrapper.vm.insert({ insertion: '1234', spamMode: false }) + wrapper.vm.insert({ insertion: '1234', keepOpen: false }) vue.nextTick(() => { expect(wrapper.vm.caret).to.eql(5) done() @@ -99,7 +99,7 @@ describe('EmojiInput', () => { const input = wrapper.find('input') input.setValue(initialString) wrapper.setData({ caret: initialString.length }) - wrapper.vm.insert({ insertion: '1234', spamMode: false }) + wrapper.vm.insert({ insertion: '1234', keepOpen: false }) vue.nextTick(() => { expect(wrapper.vm.caret).to.eql(10) done() @@ -112,7 +112,7 @@ describe('EmojiInput', () => { const input = wrapper.find('input') input.setValue(initialString) wrapper.setData({ caret: initialString.length }) - wrapper.vm.insert({ insertion: '1234', spamMode: true }) + wrapper.vm.insert({ insertion: '1234', keepOpen: true }) vue.nextTick(() => { expect(wrapper.vm.caret).to.eql(8) done() From 6f0257cd7df8eca257774a0c456af7218896946f Mon Sep 17 00:00:00 2001 From: Henry Jameson Date: Mon, 23 Sep 2019 22:12:25 +0300 Subject: [PATCH 7/7] autoscroll post form on typing + some minor improvements --- src/components/emoji_input/emoji_input.js | 4 +++- .../post_status_form/post_status_form.js | 21 ++++++++++++++++++- .../post_status_form/post_status_form.vue | 8 +++---- 3 files changed, 26 insertions(+), 7 deletions(-) diff --git a/src/components/emoji_input/emoji_input.js b/src/components/emoji_input/emoji_input.js index 5f90d7f46..25c21403c 100644 --- a/src/components/emoji_input/emoji_input.js +++ b/src/components/emoji_input/emoji_input.js @@ -211,10 +211,12 @@ const EmojiInput = { this.keepOpen = keepOpen this.$emit('input', newValue) const position = this.caret + (insertion + spaceAfter + spaceBefore).length + if (!keepOpen) { + this.input.elm.focus() + } this.$nextTick(function () { // Re-focus inputbox after clicking suggestion - this.input.elm.focus() // Set selection right after the replacement instead of the very end this.input.elm.setSelectionRange(position, position) this.caret = position diff --git a/src/components/post_status_form/post_status_form.js b/src/components/post_status_form/post_status_form.js index d468be76f..60cb5a9a3 100644 --- a/src/components/post_status_form/post_status_form.js +++ b/src/components/post_status_form/post_status_form.js @@ -249,6 +249,7 @@ const PostStatusForm = { return fileTypeService.fileType(fileInfo.mimetype) }, paste (e) { + this.resize() if (e.clipboardData.files.length > 0) { // prevent pasting of file as text e.preventDefault() @@ -267,6 +268,11 @@ const PostStatusForm = { fileDrag (e) { e.dataTransfer.dropEffect = 'copy' }, + onEmojiInputInput (e) { + this.$nextTick(() => { + this.resize(this.$refs['textarea']) + }) + }, resize (e) { const target = e.target || e if (!(target instanceof window.Element)) { return } @@ -275,12 +281,25 @@ const PostStatusForm = { // Remove "px" at the end of the values const vertPadding = Number(topPaddingStr.substr(0, topPaddingStr.length - 2)) + Number(bottomPaddingStr.substr(0, bottomPaddingStr.length - 2)) + const oldValue = Number((/([0-9.]+)px/.exec(target.style.height || '') || [])[1]) // Auto is needed to make textbox shrink when removing lines target.style.height = 'auto' - target.style.height = `${target.scrollHeight - vertPadding}px` + const newValue = target.scrollHeight - vertPadding + target.style.height = `${newValue}px` + const scroller = this.$el.closest('.sidebar-scroller') || + this.$el.closest('.post-form-modal-view') || + window + const delta = newValue - oldValue || 0 if (target.value === '') { target.style.height = null + } else { + /* For some reason this doens't _exactly_ work on mobile post form when typing + * but it works when adding emojis. Supposedly, removing the "height = auto" + * line helps with that but it obviously breaks the autoheight. + */ + scroller.scrollBy(0, delta) } + this.$refs['emoji-input'].resize() }, showEmojiPicker () { this.$refs['textarea'].focus() diff --git a/src/components/post_status_form/post_status_form.vue b/src/components/post_status_form/post_status_form.vue index b50607e6a..99ffeef8e 100644 --- a/src/components/post_status_form/post_status_form.vue +++ b/src/components/post_status_form/post_status_form.vue @@ -81,6 +81,7 @@ enable-emoji-picker hide-emoji-button enable-sticker-picker + @input="onEmojiInputInput" @sticker-uploaded="addMediaFile" @sticker-upload-failed="uploadFailed" > @@ -95,7 +96,8 @@ @keyup.ctrl.enter="postStatus(newStatus)" @drop="fileDrop" @dragover.prevent="fileDrag" - @input="resize" + @keydown.exact="resize" + @compositionupdate="resize" @paste="paste" />