akkoma-fe/src/components/post_status_form/post_status_form.js

271 lines
8.1 KiB
JavaScript
Raw Normal View History

2016-10-30 15:53:58 +00:00
import statusPoster from '../../services/status_poster/status_poster.service.js'
2016-11-06 18:30:35 +00:00
import MediaUpload from '../media_upload/media_upload.vue'
import ScopeSelector from '../scope_selector/scope_selector.vue'
2019-03-26 02:38:15 +00:00
import EmojiInput from '../emoji-input/emoji-input.vue'
2016-11-25 17:21:25 +00:00
import fileTypeService from '../../services/file_type/file_type.service.js'
2019-06-09 18:35:49 +00:00
import { reject, map, uniqBy } from 'lodash'
import suggestor from '../emoji-input/suggestor.js'
2016-11-03 16:17:32 +00:00
2019-06-09 18:35:49 +00:00
const buildMentionsString = ({ user, attentions }, currentUser) => {
2016-11-03 16:17:32 +00:00
let allAttentions = [...attentions]
allAttentions.unshift(user)
allAttentions = uniqBy(allAttentions, 'id')
2019-06-09 18:35:49 +00:00
allAttentions = reject(allAttentions, { id: currentUser.id })
2016-11-03 16:17:32 +00:00
let mentions = map(allAttentions, (attention) => {
return `@${attention.screen_name}`
})
return mentions.length > 0 ? mentions.join(' ') + ' ' : ''
2016-11-03 16:17:32 +00:00
}
2016-10-30 15:53:58 +00:00
const PostStatusForm = {
2016-11-03 15:59:27 +00:00
props: [
2016-11-03 16:17:32 +00:00
'replyTo',
'repliedUser',
2018-06-12 17:28:48 +00:00
'attentions',
2018-09-25 12:16:26 +00:00
'copyMessageScope',
2018-08-26 00:50:11 +00:00
'subject'
2016-11-03 15:59:27 +00:00
],
2016-11-06 18:30:35 +00:00
components: {
MediaUpload,
ScopeSelector,
2019-03-26 02:38:15 +00:00
EmojiInput
2016-11-06 18:30:35 +00:00
},
2018-04-15 16:05:16 +00:00
mounted () {
this.resize(this.$refs.textarea)
const textLength = this.$refs.textarea.value.length
this.$refs.textarea.setSelectionRange(textLength, textLength)
2018-08-05 19:17:11 +00:00
if (this.replyTo) {
this.$refs.textarea.focus()
}
2018-04-15 16:05:16 +00:00
},
2016-11-03 15:59:27 +00:00
data () {
2018-04-29 14:44:08 +00:00
const preset = this.$route.query.message
let statusText = preset || ''
2016-11-03 16:17:32 +00:00
const scopeCopy = typeof this.$store.state.config.scopeCopy === 'undefined'
2019-06-09 18:35:49 +00:00
? this.$store.state.instance.scopeCopy
: this.$store.state.config.scopeCopy
2016-11-03 16:17:32 +00:00
if (this.replyTo) {
const currentUser = this.$store.state.users.currentUser
statusText = buildMentionsString({ user: this.repliedUser, attentions: this.attentions }, currentUser)
}
2019-06-09 18:35:49 +00:00
const scope = ((this.copyMessageScope && scopeCopy) || this.copyMessageScope === 'direct')
? this.copyMessageScope
: this.$store.state.users.currentUser.default_scope
2018-09-25 12:16:26 +00:00
2019-02-21 16:16:11 +00:00
const contentType = typeof this.$store.state.config.postContentType === 'undefined'
? this.$store.state.instance.postContentType
: this.$store.state.config.postContentType
2016-10-30 15:53:58 +00:00
return {
dropFiles: [],
submitDisabled: false,
error: null,
posting: false,
highlighted: 0,
2016-11-03 16:17:32 +00:00
newStatus: {
spoilerText: this.subject || '',
2016-11-06 18:30:35 +00:00
status: statusText,
nsfw: false,
files: [],
2019-02-21 16:16:11 +00:00
visibility: scope,
contentType
},
caret: 0
2016-10-30 15:53:58 +00:00
}
},
computed: {
users () {
return this.$store.state.users.users
},
userDefaultScope () {
return this.$store.state.users.currentUser.default_scope
},
showAllScopes () {
const minimalScopesMode = typeof this.$store.state.config.minimalScopesMode === 'undefined'
2019-06-09 18:35:49 +00:00
? this.$store.state.instance.minimalScopesMode
: this.$store.state.config.minimalScopesMode
return !minimalScopesMode
},
emojiUserSuggestor () {
return suggestor({
emoji: [
...this.$store.state.instance.emoji,
...this.$store.state.instance.customEmoji
],
users: this.$store.state.users.users
})
},
emojiSuggestor () {
2019-06-09 18:35:49 +00:00
return suggestor({
emoji: [
...this.$store.state.instance.emoji,
...this.$store.state.instance.customEmoji
]
})
},
emoji () {
return this.$store.state.instance.emoji || []
},
customEmoji () {
return this.$store.state.instance.customEmoji || []
},
2018-02-09 14:51:04 +00:00
statusLength () {
return this.newStatus.status.length
},
spoilerTextLength () {
return this.newStatus.spoilerText.length
},
2018-02-09 14:51:04 +00:00
statusLengthLimit () {
2018-09-09 19:31:34 +00:00
return this.$store.state.instance.textlimit
2018-02-09 14:51:04 +00:00
},
hasStatusLengthLimit () {
return this.statusLengthLimit > 0
},
charactersLeft () {
return this.statusLengthLimit - (this.statusLength + this.spoilerTextLength)
},
isOverLengthLimit () {
return this.hasStatusLengthLimit && (this.charactersLeft < 0)
},
2019-03-30 10:41:42 +00:00
minimalScopesMode () {
return this.$store.state.instance.minimalScopesMode
},
alwaysShowSubject () {
if (typeof this.$store.state.config.alwaysShowSubjectInput !== 'undefined') {
return this.$store.state.config.alwaysShowSubjectInput
} else if (typeof this.$store.state.instance.alwaysShowSubjectInput !== 'undefined') {
return this.$store.state.instance.alwaysShowSubjectInput
} else {
return true
}
},
2019-03-07 04:13:04 +00:00
postFormats () {
return this.$store.state.instance.postFormats || []
},
2019-04-02 15:19:45 +00:00
safeDMEnabled () {
return this.$store.state.instance.safeDM
},
hideScopeNotice () {
return this.$store.state.config.hideScopeNotice
}
},
2016-10-30 15:53:58 +00:00
methods: {
2016-11-03 15:59:27 +00:00
postStatus (newStatus) {
if (this.posting) { return }
2018-01-31 17:48:09 +00:00
if (this.submitDisabled) { return }
if (this.newStatus.status === '') {
if (this.newStatus.files.length > 0) {
this.newStatus.status = '\u200b' // hack
} else {
this.error = 'Cannot post an empty status with no files'
2017-08-24 13:25:26 +00:00
return
}
}
this.posting = true
2016-10-30 15:53:58 +00:00
statusPoster.postStatus({
status: newStatus.status,
2018-06-07 21:31:43 +00:00
spoilerText: newStatus.spoilerText || null,
2018-06-07 09:03:50 +00:00
visibility: newStatus.visibility,
sensitive: newStatus.nsfw,
2016-11-06 18:30:35 +00:00
media: newStatus.files,
2016-11-03 15:59:27 +00:00
store: this.$store,
inReplyToStatusId: this.replyTo,
contentType: newStatus.contentType
}).then((data) => {
if (!data.error) {
this.newStatus = {
status: '',
2018-11-08 18:34:59 +00:00
spoilerText: '',
files: [],
visibility: newStatus.visibility,
contentType: newStatus.contentType
}
this.$refs.mediaUpload.clearFile()
this.$emit('posted')
let el = this.$el.querySelector('textarea')
2018-12-25 01:24:49 +00:00
el.style.height = 'auto'
el.style.height = undefined
this.error = null
} else {
this.error = data.error
}
this.posting = false
2016-10-30 15:53:58 +00:00
})
2016-11-06 18:30:35 +00:00
},
addMediaFile (fileInfo) {
this.newStatus.files.push(fileInfo)
this.enableSubmit()
},
2016-11-26 02:00:06 +00:00
removeMediaFile (fileInfo) {
let index = this.newStatus.files.indexOf(fileInfo)
this.newStatus.files.splice(index, 1)
},
2018-12-08 21:36:54 +00:00
uploadFailed (errString, templateArgs) {
2018-12-08 21:39:58 +00:00
templateArgs = templateArgs || {}
this.error = this.$t('upload.error.base') + ' ' + this.$t('upload.error.' + errString, templateArgs)
2018-12-08 15:23:21 +00:00
this.enableSubmit()
},
disableSubmit () {
this.submitDisabled = true
},
enableSubmit () {
this.submitDisabled = false
2016-11-25 17:21:25 +00:00
},
type (fileInfo) {
return fileTypeService.fileType(fileInfo.mimetype)
},
2017-11-28 20:31:40 +00:00
paste (e) {
if (e.clipboardData.files.length > 0) {
// prevent pasting of file as text
e.preventDefault()
2017-11-28 20:31:40 +00:00
// Strangely, files property gets emptied after event propagation
// Trying to wrap it in array doesn't work. Plus I doubt it's possible
// to hold more than one file in clipboard.
this.dropFiles = [e.clipboardData.files[0]]
}
},
fileDrop (e) {
if (e.dataTransfer.files.length > 0) {
2019-06-09 18:35:49 +00:00
e.preventDefault() // allow dropping text like before
this.dropFiles = e.dataTransfer.files
}
},
fileDrag (e) {
2017-02-22 21:33:28 +00:00
e.dataTransfer.dropEffect = 'copy'
},
resize (e) {
const target = e.target || e
if (!(target instanceof window.Element)) { return }
const vertPadding = Number(window.getComputedStyle(target)['padding-top'].substr(0, 1)) +
Number(window.getComputedStyle(target)['padding-bottom'].substr(0, 1))
// Auto is needed to make textbox shrink when removing lines
target.style.height = 'auto'
target.style.height = `${target.scrollHeight - vertPadding}px`
if (target.value === '') {
target.style.height = null
}
},
clearError () {
this.error = null
2018-06-07 09:03:50 +00:00
},
changeVis (visibility) {
this.newStatus.visibility = visibility
},
dismissScopeNotice () {
this.$store.dispatch('setOption', { name: 'hideScopeNotice', value: true })
2016-10-30 15:53:58 +00:00
}
}
}
export default PostStatusForm