Page Menu
Home
Phorge
Search
Configure Global Search
Log In
Files
F85711150
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Award Token
Flag For Later
Size
14 KB
Referenced Files
None
Subscribers
None
View Options
diff --git a/src/components/emoji-input/emoji-input.js b/src/components/emoji-input/emoji-input.js
index aae11a9ba7..e6c26106bf 100644
--- a/src/components/emoji-input/emoji-input.js
+++ b/src/components/emoji-input/emoji-input.js
@@ -1,184 +1,186 @@
import Completion from '../../services/completion/completion.js'
import { take } from 'lodash'
const EmojiInput = {
props: [
'placeholder',
'suggest',
'value',
'type',
'classname'
],
data () {
return {
input: undefined,
highlighted: 0,
caret: 0,
focused: false,
popupOptions: {
placement: 'bottom-start',
trigger: 'hover',
// See: https://github.com/RobinCK/vue-popper/issues/63
'delay-on-mouse-over': 9999999,
'delay-on-mouse-out': 9999999,
modifiers: {
arrow: { enabled: true },
offset: { offset: '0, 5px' }
}
}
}
},
computed: {
suggestions () {
const firstchar = this.textAtCaret.charAt(0)
if (this.textAtCaret === firstchar) { return }
const matchedSuggestions = this.suggest(this.textAtCaret)
if (matchedSuggestions.length <= 0) {
return false
}
return take(matchedSuggestions, 5)
.map(({ imageUrl, ...rest }, index) => ({
...rest,
// eslint-disable-next-line camelcase
img: imageUrl || '',
highlighted: index === this.highlighted
}))
},
showPopup () {
return this.focused && this.suggestions && this.suggestions.length > 0
},
textAtCaret () {
return (this.wordAtCaret || {}).word || ''
},
wordAtCaret () {
if (this.value && this.caret) {
const word = Completion.wordAtPosition(this.value, this.caret - 1) || {}
return word
}
}
},
mounted () {
const slots = this.$slots.default
if (!slots || slots.length === 0) return
const input = slots.find(slot => ['input', 'textarea'].includes(slot.tag))
if (!input) return
this.input = input
this.resize()
+ input.elm.addEventListener('transitionend', this.onTransition)
input.elm.addEventListener('blur', this.onBlur)
input.elm.addEventListener('focus', this.onFocus)
input.elm.addEventListener('paste', this.onPaste)
input.elm.addEventListener('keyup', this.onKeyUp)
input.elm.addEventListener('keydown', this.onKeyDown)
},
unmounted () {
const { input } = this
if (input) {
+ input.elm.removeEventListener('transitionend', this.onTransition)
input.elm.removeEventListener('blur', this.onBlur)
input.elm.removeEventListener('focus', this.onFocus)
input.elm.removeEventListener('paste', this.onPaste)
input.elm.removeEventListener('keyup', this.onKeyUp)
input.elm.removeEventListener('keydown', this.onKeyDown)
}
},
methods: {
replace (replacement) {
const newValue = Completion.replaceWord(this.value, this.wordAtCaret, replacement)
this.$emit('input', newValue)
this.caret = 0
},
- replaceText () {
- const len = this.suggestions.length || 0
+ replaceText (e) {
+ const len = (this.suggestions && this.suggestions.length) || 0
if (this.textAtCaret.length === 1) { return }
if (len > 0) {
const suggestion = this.suggestions[this.highlighted]
const replacement = suggestion.replacement
const newValue = Completion.replaceWord(this.value, this.wordAtCaret, replacement)
this.$emit('input', newValue)
this.caret = 0
this.highlighted = 0
+ e.preventDefault()
}
},
- cycleBackward () {
+ cycleBackward (e) {
const len = this.suggestions.length || 0
if (len > 0) {
this.highlighted -= 1
if (this.highlighted < 0) {
this.highlighted = this.suggestions.length - 1
}
} else {
this.highlighted = 0
}
},
- cycleForward () {
+ cycleForward (e) {
const len = this.suggestions.length || 0
if (len > 0) {
this.highlighted += 1
if (this.highlighted >= len) {
this.highlighted = 0
}
} else {
this.highlighted = 0
}
},
+ onTransition (e) {
+ this.resize(e)
+ },
onBlur (e) {
this.focused = false
this.setCaret(e)
this.resize(e)
},
onFocus (e) {
this.focused = true
this.setCaret(e)
this.resize(e)
},
onKeyUp (e) {
this.setCaret(e)
this.resize(e)
},
onPaste (e) {
this.setCaret(e)
this.resize(e)
},
onKeyDown (e) {
this.setCaret(e)
this.resize(e)
const { ctrlKey, shiftKey, key } = e
if (key === 'Tab') {
if (shiftKey) {
- this.cycleBackward()
- e.preventDefault()
+ this.cycleBackward(e)
} else {
- this.cycleForward()
- e.preventDefault()
+ this.cycleForward(e)
}
}
if (key === 'ArrowUp') {
- this.cycleBackward()
+ this.cycleBackward(e)
e.preventDefault()
} else if (key === 'ArrowDown') {
- this.cycleForward()
- e.preventDefault()
+ this.cycleForward(e)
}
if (key === 'Enter') {
if (!ctrlKey) {
- this.replaceText()
- e.preventDefault()
+ this.replaceText(e)
}
}
},
onInput (e) {
this.$emit('input', e.target.value)
},
setCaret ({ target: { selectionStart, value } }) {
this.caret = selectionStart
},
resize () {
const { panel } = this.$refs
if (!panel) return
const { offsetHeight, offsetTop } = this.input.elm
this.$refs.panel.style.top = (offsetTop + offsetHeight) + 'px'
}
}
}
export default EmojiInput
diff --git a/src/components/post_status_form/post_status_form.js b/src/components/post_status_form/post_status_form.js
index 008b821a57..1db7af30af 100644
--- a/src/components/post_status_form/post_status_form.js
+++ b/src/components/post_status_form/post_status_form.js
@@ -1,272 +1,272 @@
import statusPoster from '../../services/status_poster/status_poster.service.js'
import MediaUpload from '../media_upload/media_upload.vue'
import ScopeSelector from '../scope_selector/scope_selector.vue'
import EmojiInput from '../emoji-input/emoji-input.vue'
import fileTypeService from '../../services/file_type/file_type.service.js'
import Completion from '../../services/completion/completion.js'
import { take, filter, reject, map, uniqBy } from 'lodash'
import suggestor from '../emoji-input/suggestor.js'
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.length > 0 ? mentions.join(' ') + ' ' : ''
}
const PostStatusForm = {
props: [
'replyTo',
'repliedUser',
'attentions',
'copyMessageScope',
'subject'
],
components: {
MediaUpload,
ScopeSelector,
EmojiInput
},
mounted () {
this.resize(this.$refs.textarea)
const textLength = this.$refs.textarea.value.length
this.$refs.textarea.setSelectionRange(textLength, textLength)
if (this.replyTo) {
this.$refs.textarea.focus()
}
},
data () {
const preset = this.$route.query.message
let statusText = preset || ''
const scopeCopy = typeof this.$store.state.config.scopeCopy === 'undefined'
? this.$store.state.instance.scopeCopy
: this.$store.state.config.scopeCopy
if (this.replyTo) {
const currentUser = this.$store.state.users.currentUser
statusText = buildMentionsString({ user: this.repliedUser, attentions: this.attentions }, currentUser)
}
const scope = (this.copyMessageScope && scopeCopy || this.copyMessageScope === 'direct')
? this.copyMessageScope
: this.$store.state.users.currentUser.default_scope
const contentType = typeof this.$store.state.config.postContentType === 'undefined'
? this.$store.state.instance.postContentType
: this.$store.state.config.postContentType
return {
dropFiles: [],
submitDisabled: false,
error: null,
posting: false,
highlighted: 0,
newStatus: {
spoilerText: this.subject || '',
status: statusText,
nsfw: false,
files: [],
visibility: scope,
contentType
},
caret: 0
}
},
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'
? 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 () {
- suggestor({ emoji: [
+ 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 || []
},
statusLength () {
return this.newStatus.status.length
},
spoilerTextLength () {
return this.newStatus.spoilerText.length
},
statusLengthLimit () {
return this.$store.state.instance.textlimit
},
hasStatusLengthLimit () {
return this.statusLengthLimit > 0
},
charactersLeft () {
return this.statusLengthLimit - (this.statusLength + this.spoilerTextLength)
},
isOverLengthLimit () {
return this.hasStatusLengthLimit && (this.charactersLeft < 0)
},
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
}
},
formattingOptionsEnabled () {
return this.$store.state.instance.formattingOptionsEnabled
},
postFormats () {
return this.$store.state.instance.postFormats || []
},
safeDMEnabled () {
return this.$store.state.instance.safeDM
},
hideScopeNotice () {
return this.$store.state.config.hideScopeNotice
}
},
methods: {
postStatus (newStatus) {
if (this.posting) { return }
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'
return
}
}
this.posting = true
statusPoster.postStatus({
status: newStatus.status,
spoilerText: newStatus.spoilerText || null,
visibility: newStatus.visibility,
sensitive: newStatus.nsfw,
media: newStatus.files,
store: this.$store,
inReplyToStatusId: this.replyTo,
contentType: newStatus.contentType
}).then((data) => {
if (!data.error) {
this.newStatus = {
status: '',
spoilerText: '',
files: [],
visibility: newStatus.visibility,
contentType: newStatus.contentType
}
this.$refs.mediaUpload.clearFile()
this.$emit('posted')
let el = this.$el.querySelector('textarea')
el.style.height = 'auto'
el.style.height = undefined
this.error = null
} else {
this.error = data.error
}
this.posting = false
})
},
addMediaFile (fileInfo) {
this.newStatus.files.push(fileInfo)
this.enableSubmit()
},
removeMediaFile (fileInfo) {
let index = this.newStatus.files.indexOf(fileInfo)
this.newStatus.files.splice(index, 1)
},
uploadFailed (errString, templateArgs) {
templateArgs = templateArgs || {}
this.error = this.$t('upload.error.base') + ' ' + this.$t('upload.error.' + errString, templateArgs)
this.enableSubmit()
},
disableSubmit () {
this.submitDisabled = true
},
enableSubmit () {
this.submitDisabled = false
},
type (fileInfo) {
return fileTypeService.fileType(fileInfo.mimetype)
},
paste (e) {
if (e.clipboardData.files.length > 0) {
// prevent pasting of file as text
e.preventDefault()
// 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) {
e.preventDefault() // allow dropping text like before
this.dropFiles = e.dataTransfer.files
}
},
fileDrag (e) {
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
},
changeVis (visibility) {
this.newStatus.visibility = visibility
},
dismissScopeNotice () {
this.$store.dispatch('setOption', { name: 'hideScopeNotice', value: true })
}
}
}
export default PostStatusForm
File Metadata
Details
Attached
Mime Type
text/x-diff
Expires
Sat, Sep 19, 4:12 AM (1 d, 3 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
1768830
Default Alt Text
(14 KB)
Attached To
Mode
rPUFE pleroma-fe-upstream
Attached
Detach File
Event Timeline
Log In to Comment