diff options
| author | eugenijm <eugenijm@protonmail.com> | 2020-05-07 16:10:53 +0300 |
|---|---|---|
| committer | eugenijm <eugenijm@protonmail.com> | 2020-07-08 15:21:31 +0300 |
| commit | aa2cf51c05ebdf411d74af5debbbc8fa4d3cf457 (patch) | |
| tree | 6032c3ee359b20cefca000df93b59787fc0d54d9 /src/components/post_status_form | |
| parent | a0ddcbdf5b19f658bc07086beaa4034a6309fe3b (diff) | |
Add Chats
Diffstat (limited to 'src/components/post_status_form')
| -rw-r--r-- | src/components/post_status_form/post_status_form.js | 138 | ||||
| -rw-r--r-- | src/components/post_status_form/post_status_form.vue | 50 |
2 files changed, 134 insertions, 54 deletions
diff --git a/src/components/post_status_form/post_status_form.js b/src/components/post_status_form/post_status_form.js index 18f02eba..90d0fa81 100644 --- a/src/components/post_status_form/post_status_form.js +++ b/src/components/post_status_form/post_status_form.js @@ -9,7 +9,7 @@ import fileTypeService from '../../services/file_type/file_type.service.js' import { findOffset } from '../../services/offset_finder/offset_finder.service.js' import { reject, map, uniqBy, debounce } from 'lodash' import suggestor from '../emoji_input/suggestor.js' -import { mapGetters } from 'vuex' +import { mapGetters, mapState } from 'vuex' import Checkbox from '../checkbox/checkbox.vue' const buildMentionsString = ({ user, attentions = [] }, currentUser) => { @@ -33,7 +33,22 @@ const PostStatusForm = { 'repliedUser', 'attentions', 'copyMessageScope', - 'subject' + 'subject', + 'disableSubject', + 'disableScopeSelector', + 'disableNotice', + 'disableLockWarning', + 'disablePolls', + 'disableSensitivityCheckbox', + 'disableSubmit', + 'placeholder', + 'maxHeight', + 'request', + 'preserveFocus', + 'autoFocus', + 'fileLimit', + 'submitOnEnter', + 'emojiPickerPlacement' ], components: { MediaUpload, @@ -46,10 +61,13 @@ const PostStatusForm = { }, mounted () { this.resize(this.$refs.textarea) - const textLength = this.$refs.textarea.value.length - this.$refs.textarea.setSelectionRange(textLength, textLength) if (this.replyTo) { + const textLength = this.$refs.textarea.value.length + this.$refs.textarea.setSelectionRange(textLength, textLength) + } + + if (this.replyTo || this.autoFocus) { this.$refs.textarea.focus() } }, @@ -72,7 +90,7 @@ const PostStatusForm = { return { dropFiles: [], - submitDisabled: false, + uploadingFiles: false, error: null, posting: false, highlighted: 0, @@ -91,7 +109,8 @@ const PostStatusForm = { showDropIcon: 'hide', dropStopTimeout: null, preview: null, - previewLoading: false + previewLoading: false, + emojiInputShown: false } }, computed: { @@ -160,10 +179,11 @@ const PostStatusForm = { }, pollsAvailable () { return this.$store.state.instance.pollsAvailable && - this.$store.state.instance.pollLimits.max_options >= 2 + this.$store.state.instance.pollLimits.max_options >= 2 && + this.disablePolls !== true }, hideScopeNotice () { - return this.$store.getters.mergedConfig.hideScopeNotice + return this.disableNotice || this.$store.getters.mergedConfig.hideScopeNotice }, pollContentError () { return this.pollFormVisible && @@ -176,7 +196,13 @@ const PostStatusForm = { emptyStatus () { return this.newStatus.status.trim() === '' && this.newStatus.files.length === 0 }, - ...mapGetters(['mergedConfig']) + uploadFileLimitReached () { + return this.newStatus.files.length >= this.fileLimit + }, + ...mapGetters(['mergedConfig']), + ...mapState({ + mobileLayout: state => state.interface.mobileLayout + }) }, watch: { 'newStatus.contentType': function () { @@ -187,9 +213,19 @@ const PostStatusForm = { } }, methods: { - async postStatus (newStatus) { + async postStatus (event, newStatus, opts = {}) { if (this.posting) { return } if (this.submitDisabled) { return } + if (this.emojiInputShown) { return } + if (this.submitOnEnter) { + event.stopPropagation() + event.preventDefault() + } + if (opts.control && this.submitOnEnter) { + newStatus.status = `${newStatus.status}\n` + return + } + if (this.emptyStatus) { this.error = this.$t('post_status.empty_status_error') return @@ -211,7 +247,7 @@ const PostStatusForm = { return } - const data = await statusPoster.postStatus({ + const postingOptions = { status: newStatus.status, spoilerText: newStatus.spoilerText || null, visibility: newStatus.visibility, @@ -221,32 +257,40 @@ const PostStatusForm = { inReplyToStatusId: this.replyTo, contentType: newStatus.contentType, poll - }) - - if (!data.error) { - this.newStatus = { - status: '', - spoilerText: '', - files: [], - visibility: newStatus.visibility, - contentType: newStatus.contentType, - poll: {}, - mediaDescriptions: {} - } - this.pollFormVisible = false - this.$refs.mediaUpload.clearFile() - this.clearPollForm() - this.$emit('posted') - let el = this.$el.querySelector('textarea') - el.style.height = 'auto' - el.style.height = undefined - this.error = null - if (this.preview) this.previewStatus() - } else { - this.error = data.error } - this.posting = false + const request = this.request ? this.request : statusPoster.postStatus + + request(postingOptions).then((data) => { + if (!data.error) { + this.newStatus = { + status: '', + spoilerText: '', + files: [], + visibility: newStatus.visibility, + contentType: newStatus.contentType, + poll: {}, + mediaDescriptions: {} + } + this.pollFormVisible = false + this.$refs.mediaUpload && this.$refs.mediaUpload.clearFile() + this.clearPollForm() + this.$emit('posted', data) + if (this.preserveFocus) { + this.$nextTick(() => { + this.$refs.textarea.focus() + }) + } + let el = this.$el.querySelector('textarea') + el.style.height = 'auto' + el.style.height = undefined + this.error = null + if (this.preview) this.previewStatus() + } else { + this.error = data.error + } + this.posting = false + }) }, previewStatus () { if (this.emptyStatus && this.newStatus.spoilerText.trim() === '') { @@ -301,20 +345,26 @@ const PostStatusForm = { }, addMediaFile (fileInfo) { this.newStatus.files.push(fileInfo) + + // TODO: use fixed dimensions instead so relying on timeout + setTimeout(() => { + this.$emit('resize') + }, 150) }, removeMediaFile (fileInfo) { let index = this.newStatus.files.indexOf(fileInfo) this.newStatus.files.splice(index, 1) + this.$emit('resize') }, uploadFailed (errString, templateArgs) { templateArgs = templateArgs || {} this.error = this.$t('upload.error.base') + ' ' + this.$t('upload.error.' + errString, templateArgs) }, - disableSubmit () { - this.submitDisabled = true + startedUploadingFiles () { + this.uploadingFiles = true }, - enableSubmit () { - this.submitDisabled = false + finishedUploadingFiles () { + this.uploadingFiles = false }, type (fileInfo) { return fileTypeService.fileType(fileInfo.mimetype) @@ -348,7 +398,7 @@ const PostStatusForm = { this.dropStopTimeout = setTimeout(() => (this.showDropIcon = 'hide'), 500) }, fileDrag (e) { - e.dataTransfer.dropEffect = 'copy' + e.dataTransfer.dropEffect = this.uploadFileLimitReached ? 'none' : 'copy' if (e.dataTransfer && e.dataTransfer.types.includes('Files')) { clearTimeout(this.dropStopTimeout) this.showDropIcon = 'show' @@ -367,6 +417,7 @@ const PostStatusForm = { // Reset to default height for empty form, nothing else to do here. if (target.value === '') { target.style.height = null + this.$emit('resize', null) this.$refs['emoji-input'].resize() return } @@ -419,8 +470,10 @@ const PostStatusForm = { // BEGIN content size update target.style.height = 'auto' - const newHeight = target.scrollHeight - vertPadding + const heightWithoutPadding = target.scrollHeight - vertPadding + const newHeight = this.maxHeight ? Math.min(heightWithoutPadding, this.maxHeight) : heightWithoutPadding target.style.height = `${newHeight}px` + this.$emit('resize', newHeight) // END content size update // We check where the bottom border of form-bottom element is, this uses findOffset @@ -480,6 +533,9 @@ const PostStatusForm = { setAllMediaDescriptions () { const ids = this.newStatus.files.map(file => file.id) return Promise.all(ids.map(id => this.setMediaDescription(id))) + }, + handleEmojiInputShow (value) { + this.emojiInputShown = value } } } diff --git a/src/components/post_status_form/post_status_form.vue b/src/components/post_status_form/post_status_form.vue index 626584ed..d8df68d6 100644 --- a/src/components/post_status_form/post_status_form.vue +++ b/src/components/post_status_form/post_status_form.vue @@ -5,19 +5,20 @@ > <form autocomplete="off" - @submit.prevent="postStatus(newStatus)" + @submit.prevent @dragover.prevent="fileDrag" > <div v-show="showDropIcon !== 'hide'" :style="{ animation: showDropIcon === 'show' ? 'fade-in 0.25s' : 'fade-out 0.5s' }" - class="drop-indicator icon-upload" + class="drop-indicator" + :class="[uploadFileLimitReached ? 'icon-block' : 'icon-upload']" @dragleave="fileDragStop" @drop.stop="fileDrop" /> <div class="form-group"> <i18n - v-if="!$store.state.users.currentUser.locked && newStatus.visibility == 'private'" + v-if="!$store.state.users.currentUser.locked && newStatus.visibility == 'private' && !disableLockWarning" path="post_status.account_not_locked_warning" tag="p" class="visibility-notice" @@ -108,7 +109,7 @@ /> </div> <EmojiInput - v-if="newStatus.spoilerText || alwaysShowSubject" + v-if="!disableSubject && (newStatus.spoilerText || alwaysShowSubject)" v-model="newStatus.spoilerText" enable-emoji-picker :suggest="emojiSuggestor" @@ -126,6 +127,7 @@ ref="emoji-input" v-model="newStatus.status" :suggest="emojiUserSuggestor" + :placement="emojiPickerPlacement" class="form-control main-input" enable-emoji-picker hide-emoji-button @@ -133,16 +135,19 @@ @input="onEmojiInputInput" @sticker-uploaded="addMediaFile" @sticker-upload-failed="uploadFailed" + @shown="handleEmojiInputShow" > <textarea ref="textarea" v-model="newStatus.status" - :placeholder="$t('post_status.default')" + :placeholder="placeholder || $t('post_status.default')" rows="1" :disabled="posting" class="form-post-body" - @keydown.meta.enter="postStatus(newStatus)" - @keydown.ctrl.enter="postStatus(newStatus)" + :class="{ 'scrollable-form': !!maxHeight }" + @keydown.exact.enter="submitOnEnter && postStatus($event, newStatus)" + @keydown.meta.enter="postStatus($event, newStatus, { control: true })" + @keydown.ctrl.enter="postStatus($event, newStatus)" @input="resize" @compositionupdate="resize" @paste="paste" @@ -155,7 +160,10 @@ {{ charactersLeft }} </p> </EmojiInput> - <div class="visibility-tray"> + <div + v-if="!disableScopeSelector" + class="visibility-tray" + > <scope-selector :show-all="showAllScopes" :user-default="userDefaultScope" @@ -213,10 +221,11 @@ ref="mediaUpload" class="media-upload-icon" :drop-files="dropFiles" - @uploading="disableSubmit" + :disabled="uploadFileLimitReached" + @uploading="startedUploadingFiles" @uploaded="addMediaFile" @upload-failed="uploadFailed" - @all-uploaded="enableSubmit" + @all-uploaded="finishedUploadingFiles" /> <div class="emoji-icon" @@ -253,11 +262,13 @@ > {{ $t('general.submit') }} </button> + <!-- touchstart is used to keep the OSK at the same position after a message send --> <button v-else - :disabled="submitDisabled" - type="submit" + :disabled="uploadingFiles || disableSubmit" class="btn btn-default" + @touchstart.stop.prevent="postStatus($event, newStatus)" + @click.stop.prevent="postStatus($event, newStatus)" > {{ $t('general.submit') }} </button> @@ -297,7 +308,7 @@ </div> </div> <div - v-if="newStatus.files.length > 0" + v-if="newStatus.files.length > 0 && !disableSensitivityCheckbox" class="upload_settings" > <Checkbox v-model="newStatus.nsfw"> @@ -331,6 +342,8 @@ } .post-status-form { + position: relative; + .form-bottom { display: flex; justify-content: space-between; @@ -547,6 +560,10 @@ padding-bottom: 1.75em; min-height: 1px; box-sizing: content-box; + + &.scrollable-form { + overflow-y: auto; + } } .main-input { @@ -609,4 +626,11 @@ border: 2px dashed var(--text, $fallback--text); } } + +// todo: unify with attachment.vue (otherwise the uploaded images are not minified unless a status with an attachment was displayed before) +img.media-upload { + line-height: 0; + max-height: 200px; + max-width: 100%; +} </style> |
