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'
|
2016-11-25 17:21:25 +00:00
|
|
|
import fileTypeService from '../../services/file_type/file_type.service.js'
|
2017-03-15 16:06:48 +00:00
|
|
|
import Completion from '../../services/completion/completion.js'
|
|
|
|
import { take, filter, reject, map, uniqBy } from 'lodash'
|
2016-11-03 16:17:32 +00:00
|
|
|
|
|
|
|
const buildMentionsString = ({user, attentions}, currentUser) => {
|
|
|
|
let allAttentions = [...attentions]
|
|
|
|
|
|
|
|
allAttentions.unshift(user)
|
|
|
|
|
|
|
|
allAttentions = uniqBy(allAttentions, 'id')
|
|
|
|
allAttentions = reject(allAttentions, {id: currentUser.id})
|
|
|
|
|
|
|
|
let mentions = map(allAttentions, (attention) => {
|
|
|
|
return `@${attention.screen_name}`
|
|
|
|
})
|
|
|
|
|
|
|
|
return mentions.join(' ') + ' '
|
|
|
|
}
|
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
|
|
|
|
},
|
2018-04-15 16:05:16 +00:00
|
|
|
mounted () {
|
|
|
|
this.resize(this.$refs.textarea)
|
2018-08-05 19:41:34 +00:00
|
|
|
|
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
|
|
|
|
|
|
|
if (this.replyTo) {
|
|
|
|
const currentUser = this.$store.state.users.currentUser
|
|
|
|
statusText = buildMentionsString({ user: this.repliedUser, attentions: this.attentions }, currentUser)
|
|
|
|
}
|
|
|
|
|
2018-09-25 12:16:26 +00:00
|
|
|
const scope = (this.copyMessageScope && this.$store.state.config.copyScope || this.copyMessageScope === 'direct')
|
|
|
|
? this.copyMessageScope
|
|
|
|
: this.$store.state.users.currentUser.default_scope
|
|
|
|
|
2016-10-30 15:53:58 +00:00
|
|
|
return {
|
2017-02-21 13:13:19 +00:00
|
|
|
dropFiles: [],
|
2016-11-26 11:38:33 +00:00
|
|
|
submitDisabled: false,
|
2017-08-20 10:16:41 +00:00
|
|
|
error: null,
|
2017-08-21 12:35:14 +00:00
|
|
|
posting: false,
|
2018-02-03 14:05:47 +00:00
|
|
|
highlighted: 0,
|
2016-11-03 16:17:32 +00:00
|
|
|
newStatus: {
|
2018-11-07 16:20:33 +00:00
|
|
|
spoilerText: this.subject || '',
|
2016-11-06 18:30:35 +00:00
|
|
|
status: statusText,
|
2018-08-31 00:42:42 +00:00
|
|
|
contentType: 'text/plain',
|
2018-08-25 21:18:43 +00:00
|
|
|
nsfw: false,
|
2018-06-08 13:25:48 +00:00
|
|
|
files: [],
|
2018-09-25 12:16:26 +00:00
|
|
|
visibility: scope
|
2017-03-15 16:06:48 +00:00
|
|
|
},
|
|
|
|
caret: 0
|
2016-10-30 15:53:58 +00:00
|
|
|
}
|
|
|
|
},
|
2016-11-30 12:39:17 +00:00
|
|
|
computed: {
|
2018-06-08 13:25:48 +00:00
|
|
|
vis () {
|
|
|
|
return {
|
|
|
|
public: { selected: this.newStatus.visibility === 'public' },
|
|
|
|
unlisted: { selected: this.newStatus.visibility === 'unlisted' },
|
|
|
|
private: { selected: this.newStatus.visibility === 'private' },
|
|
|
|
direct: { selected: this.newStatus.visibility === 'direct' }
|
|
|
|
}
|
|
|
|
},
|
2017-03-15 16:06:48 +00:00
|
|
|
candidates () {
|
2017-09-19 19:43:20 +00:00
|
|
|
const firstchar = this.textAtCaret.charAt(0)
|
|
|
|
if (firstchar === '@') {
|
2018-09-12 08:46:02 +00:00
|
|
|
const query = this.textAtCaret.slice(1).toUpperCase()
|
|
|
|
const matchedUsers = filter(this.users, (user) => {
|
|
|
|
return user.screen_name.toUpperCase().startsWith(query) ||
|
|
|
|
user.name && user.name.toUpperCase().startsWith(query)
|
|
|
|
})
|
2017-06-15 22:13:54 +00:00
|
|
|
if (matchedUsers.length <= 0) {
|
|
|
|
return false
|
|
|
|
}
|
2017-03-15 16:14:51 +00:00
|
|
|
// eslint-disable-next-line camelcase
|
2018-02-03 14:05:47 +00:00
|
|
|
return map(take(matchedUsers, 5), ({screen_name, name, profile_image_url_original}, index) => ({
|
2017-09-19 19:43:20 +00:00
|
|
|
// eslint-disable-next-line camelcase
|
|
|
|
screen_name: `@${screen_name}`,
|
2017-06-15 22:13:54 +00:00
|
|
|
name: name,
|
2018-02-03 14:05:47 +00:00
|
|
|
img: profile_image_url_original,
|
|
|
|
highlighted: index === this.highlighted
|
2017-06-15 22:13:54 +00:00
|
|
|
}))
|
2017-09-19 19:43:20 +00:00
|
|
|
} else if (firstchar === ':') {
|
2018-02-03 14:05:47 +00:00
|
|
|
if (this.textAtCaret === ':') { return }
|
2018-08-26 12:50:36 +00:00
|
|
|
const matchedEmoji = filter(this.emoji.concat(this.customEmoji), (emoji) => emoji.shortcode.startsWith(this.textAtCaret.slice(1)))
|
2017-09-19 19:43:20 +00:00
|
|
|
if (matchedEmoji.length <= 0) {
|
|
|
|
return false
|
|
|
|
}
|
2018-02-03 14:05:47 +00:00
|
|
|
return map(take(matchedEmoji, 5), ({shortcode, image_url, utf}, index) => ({
|
2017-09-19 19:43:20 +00:00
|
|
|
screen_name: `:${shortcode}:`,
|
|
|
|
name: '',
|
2017-11-20 18:32:51 +00:00
|
|
|
utf: utf || '',
|
2018-08-06 06:52:07 +00:00
|
|
|
// eslint-disable-next-line camelcase
|
2018-09-09 19:31:34 +00:00
|
|
|
img: utf ? '' : this.$store.state.instance.server + image_url,
|
2018-02-03 14:05:47 +00:00
|
|
|
highlighted: index === this.highlighted
|
2017-09-19 19:43:20 +00:00
|
|
|
}))
|
2017-03-15 16:06:48 +00:00
|
|
|
} else {
|
2017-06-15 22:13:54 +00:00
|
|
|
return false
|
2017-03-15 16:06:48 +00:00
|
|
|
}
|
|
|
|
},
|
|
|
|
textAtCaret () {
|
|
|
|
return (this.wordAtCaret || {}).word || ''
|
|
|
|
},
|
|
|
|
wordAtCaret () {
|
|
|
|
const word = Completion.wordAtPosition(this.newStatus.status, this.caret - 1) || {}
|
|
|
|
return word
|
|
|
|
},
|
2016-11-30 17:30:43 +00:00
|
|
|
users () {
|
|
|
|
return this.$store.state.users.users
|
2017-09-19 19:43:20 +00:00
|
|
|
},
|
|
|
|
emoji () {
|
2018-09-09 18:21:23 +00:00
|
|
|
return this.$store.state.instance.emoji || []
|
2017-11-20 18:32:51 +00:00
|
|
|
},
|
|
|
|
customEmoji () {
|
2018-09-09 18:21:23 +00:00
|
|
|
return this.$store.state.instance.customEmoji || []
|
2018-02-09 14:51:04 +00:00
|
|
|
},
|
|
|
|
statusLength () {
|
|
|
|
return this.newStatus.status.length
|
|
|
|
},
|
2018-11-07 16:20:33 +00:00
|
|
|
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 () {
|
2018-11-07 16:20:33 +00:00
|
|
|
return this.statusLengthLimit - (this.statusLength + this.spoilerTextLength)
|
2018-02-11 14:07:29 +00:00
|
|
|
},
|
|
|
|
isOverLengthLimit () {
|
2018-11-07 16:20:33 +00:00
|
|
|
return this.hasStatusLengthLimit && (this.charactersLeft < 0)
|
2018-06-08 13:25:48 +00:00
|
|
|
},
|
|
|
|
scopeOptionsEnabled () {
|
2018-09-09 18:21:23 +00:00
|
|
|
return this.$store.state.instance.scopeOptionsEnabled
|
2018-08-31 14:00:41 +00:00
|
|
|
},
|
2018-12-03 03:47:35 +00:00
|
|
|
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 this.$store.state.instance.scopeOptionsEnabled
|
|
|
|
}
|
|
|
|
},
|
2018-08-31 14:00:41 +00:00
|
|
|
formattingOptionsEnabled () {
|
2018-09-09 18:21:23 +00:00
|
|
|
return this.$store.state.instance.formattingOptionsEnabled
|
2016-11-30 12:39:17 +00:00
|
|
|
}
|
|
|
|
},
|
2016-10-30 15:53:58 +00:00
|
|
|
methods: {
|
2017-03-15 16:06:48 +00:00
|
|
|
replace (replacement) {
|
|
|
|
this.newStatus.status = Completion.replaceWord(this.newStatus.status, this.wordAtCaret, replacement)
|
2017-06-16 07:26:54 +00:00
|
|
|
const el = this.$el.querySelector('textarea')
|
|
|
|
el.focus()
|
|
|
|
this.caret = 0
|
2017-03-15 16:06:48 +00:00
|
|
|
},
|
2018-02-03 14:05:47 +00:00
|
|
|
replaceCandidate (e) {
|
|
|
|
const len = this.candidates.length || 0
|
|
|
|
if (this.textAtCaret === ':' || e.ctrlKey) { return }
|
|
|
|
if (len > 0) {
|
|
|
|
e.preventDefault()
|
|
|
|
const candidate = this.candidates[this.highlighted]
|
|
|
|
const replacement = candidate.utf || (candidate.screen_name + ' ')
|
|
|
|
this.newStatus.status = Completion.replaceWord(this.newStatus.status, this.wordAtCaret, replacement)
|
|
|
|
const el = this.$el.querySelector('textarea')
|
|
|
|
el.focus()
|
|
|
|
this.caret = 0
|
|
|
|
this.highlighted = 0
|
|
|
|
}
|
|
|
|
},
|
|
|
|
cycleBackward (e) {
|
|
|
|
const len = this.candidates.length || 0
|
|
|
|
if (len > 0) {
|
|
|
|
e.preventDefault()
|
|
|
|
this.highlighted -= 1
|
|
|
|
if (this.highlighted < 0) {
|
|
|
|
this.highlighted = this.candidates.length - 1
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
this.highlighted = 0
|
|
|
|
}
|
|
|
|
},
|
|
|
|
cycleForward (e) {
|
|
|
|
const len = this.candidates.length || 0
|
|
|
|
if (len > 0) {
|
|
|
|
if (e.shiftKey) { return }
|
|
|
|
e.preventDefault()
|
|
|
|
this.highlighted += 1
|
|
|
|
if (this.highlighted >= len) {
|
|
|
|
this.highlighted = 0
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
this.highlighted = 0
|
|
|
|
}
|
|
|
|
},
|
2017-03-15 16:06:48 +00:00
|
|
|
setCaret ({target: {selectionStart}}) {
|
|
|
|
this.caret = selectionStart
|
|
|
|
},
|
2016-11-03 15:59:27 +00:00
|
|
|
postStatus (newStatus) {
|
2017-08-22 08:43:03 +00:00
|
|
|
if (this.posting) { return }
|
2018-01-31 17:48:09 +00:00
|
|
|
if (this.submitDisabled) { return }
|
2017-08-24 13:16:06 +00:00
|
|
|
|
|
|
|
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
|
2017-08-24 13:16:06 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-08-21 12:35:14 +00:00
|
|
|
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,
|
2018-08-25 21:18:43 +00:00
|
|
|
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,
|
2018-08-31 00:42:42 +00:00
|
|
|
inReplyToStatusId: this.replyTo,
|
|
|
|
contentType: newStatus.contentType
|
2017-08-20 10:16:41 +00:00
|
|
|
}).then((data) => {
|
|
|
|
if (!data.error) {
|
|
|
|
this.newStatus = {
|
|
|
|
status: '',
|
2018-11-08 18:34:59 +00:00
|
|
|
spoilerText: '',
|
2018-06-08 13:25:48 +00:00
|
|
|
files: [],
|
2018-08-31 00:42:42 +00:00
|
|
|
visibility: newStatus.visibility,
|
|
|
|
contentType: newStatus.contentType
|
2017-08-20 10:16:41 +00:00
|
|
|
}
|
|
|
|
this.$emit('posted')
|
|
|
|
let el = this.$el.querySelector('textarea')
|
|
|
|
el.style.height = '16px'
|
|
|
|
this.error = null
|
|
|
|
} else {
|
|
|
|
this.error = data.error
|
|
|
|
}
|
2017-08-21 12:35:14 +00:00
|
|
|
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)
|
2016-11-24 22:07:21 +00:00
|
|
|
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)
|
|
|
|
},
|
2016-11-24 22:07:21 +00:00
|
|
|
disableSubmit () {
|
|
|
|
this.submitDisabled = true
|
|
|
|
},
|
|
|
|
enableSubmit () {
|
|
|
|
this.submitDisabled = false
|
2016-11-25 17:21:25 +00:00
|
|
|
},
|
|
|
|
type (fileInfo) {
|
|
|
|
return fileTypeService.fileType(fileInfo.mimetype)
|
2017-02-21 13:13:19 +00:00
|
|
|
},
|
2017-11-28 20:31:40 +00:00
|
|
|
paste (e) {
|
|
|
|
if (e.clipboardData.files.length > 0) {
|
|
|
|
// 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]]
|
|
|
|
}
|
|
|
|
},
|
2017-02-21 13:13:19 +00:00
|
|
|
fileDrop (e) {
|
2017-02-21 20:48:48 +00:00
|
|
|
if (e.dataTransfer.files.length > 0) {
|
2017-02-21 13:13:19 +00:00
|
|
|
e.preventDefault() // allow dropping text like before
|
|
|
|
this.dropFiles = e.dataTransfer.files
|
|
|
|
}
|
2017-02-22 12:53:05 +00:00
|
|
|
},
|
|
|
|
fileDrag (e) {
|
2017-02-22 21:33:28 +00:00
|
|
|
e.dataTransfer.dropEffect = 'copy'
|
2017-05-31 11:02:54 +00:00
|
|
|
},
|
|
|
|
resize (e) {
|
2018-06-08 13:25:48 +00:00
|
|
|
if (!e.target) { return }
|
2018-04-15 15:22:56 +00:00
|
|
|
const vertPadding = Number(window.getComputedStyle(e.target)['padding-top'].substr(0, 1)) +
|
|
|
|
Number(window.getComputedStyle(e.target)['padding-bottom'].substr(0, 1))
|
2018-04-15 12:55:47 +00:00
|
|
|
e.target.style.height = 'auto'
|
|
|
|
e.target.style.height = `${e.target.scrollHeight - vertPadding}px`
|
|
|
|
if (e.target.value === '') {
|
|
|
|
e.target.style.height = '16px'
|
2017-05-31 14:36:22 +00:00
|
|
|
}
|
2017-08-24 13:16:06 +00:00
|
|
|
},
|
|
|
|
clearError () {
|
|
|
|
this.error = null
|
2018-06-07 09:03:50 +00:00
|
|
|
},
|
|
|
|
changeVis (visibility) {
|
|
|
|
this.newStatus.visibility = visibility
|
2016-10-30 15:53:58 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
export default PostStatusForm
|