Page Menu
Home
Phorge
Search
Configure Global Search
Log In
Files
F85629462
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Award Token
Flag For Later
Size
11 KB
Referenced Files
None
Subscribers
None
View Options
diff --git a/src/components/post_status_form/post_status_form.js b/src/components/post_status_form/post_status_form.js
index 6b78b7dda2..3313ec3f96 100644
--- a/src/components/post_status_form/post_status_form.js
+++ b/src/components/post_status_form/post_status_form.js
@@ -1,145 +1,148 @@
import statusPoster from '../../services/status_poster/status_poster.service.js'
import MediaUpload from '../media_upload/media_upload.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'
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(' ') + ' '
}
const PostStatusForm = {
props: [
'replyTo',
'repliedUser',
'attentions'
],
components: {
MediaUpload
},
data () {
let statusText = ''
if (this.replyTo) {
const currentUser = this.$store.state.users.currentUser
statusText = buildMentionsString({ user: this.repliedUser, attentions: this.attentions }, currentUser)
}
return {
dropFiles: [],
submitDisabled: false,
error: null,
+ posting: false,
newStatus: {
status: statusText,
files: []
},
caret: 0
}
},
computed: {
candidates () {
if (this.textAtCaret.charAt(0) === '@') {
const matchedUsers = filter(this.users, (user) => (String(user.name + user.screen_name)).match(this.textAtCaret.slice(1)))
if (matchedUsers.length <= 0) {
return false
}
// eslint-disable-next-line camelcase
return map(take(matchedUsers, 5), ({screen_name, name, profile_image_url_original}) => ({
screen_name: screen_name,
name: name,
img: profile_image_url_original
}))
} else {
return false
}
},
textAtCaret () {
return (this.wordAtCaret || {}).word || ''
},
wordAtCaret () {
const word = Completion.wordAtPosition(this.newStatus.status, this.caret - 1) || {}
return word
},
users () {
return this.$store.state.users.users
}
},
methods: {
replace (replacement) {
this.newStatus.status = Completion.replaceWord(this.newStatus.status, this.wordAtCaret, replacement)
const el = this.$el.querySelector('textarea')
el.focus()
this.caret = 0
},
setCaret ({target: {selectionStart}}) {
this.caret = selectionStart
},
postStatus (newStatus) {
+ this.posting = true
statusPoster.postStatus({
status: newStatus.status,
media: newStatus.files,
store: this.$store,
inReplyToStatusId: this.replyTo
}).then((data) => {
if (!data.error) {
this.newStatus = {
status: '',
files: []
}
this.$emit('posted')
let el = this.$el.querySelector('textarea')
el.style.height = '16px'
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)
},
disableSubmit () {
this.submitDisabled = true
},
enableSubmit () {
this.submitDisabled = false
},
type (fileInfo) {
return fileTypeService.fileType(fileInfo.mimetype)
},
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) {
e.target.style.height = 'auto'
e.target.style.height = `${e.target.scrollHeight - 10}px`
if (e.target.value === '') {
e.target.style.height = '16px'
}
}
}
}
export default PostStatusForm
diff --git a/src/components/post_status_form/post_status_form.vue b/src/components/post_status_form/post_status_form.vue
index e1e3e4be3f..e775c45e3f 100644
--- a/src/components/post_status_form/post_status_form.vue
+++ b/src/components/post_status_form/post_status_form.vue
@@ -1,174 +1,175 @@
<template>
<div class="post-status-form">
<form @submit.prevent="postStatus(newStatus)">
<div class="form-group base03-border" >
<textarea @click="setCaret" @keyup="setCaret" v-model="newStatus.status" placeholder="Just landed in L.A." rows="1" class="form-control" @keydown.meta.enter="postStatus(newStatus)" @keyup.ctrl.enter="postStatus(newStatus)" @drop="fileDrop" @dragover.prevent="fileDrag" @input="resize"></textarea>
</div>
<div style="position:relative;" v-if="candidates">
<div class="autocomplete-panel base05-background">
<div v-for="candidate in candidates" @click="replace('@' + candidate.screen_name + ' ')" class="autocomplete base01">
<img :src="candidate.img"></img>
<span>
@{{candidate.screen_name}}
<small class="base02">{{candidate.name}}</small>
</span>
</div>
</div>
</div>
<div class='form-bottom'>
<media-upload @uploading="disableSubmit" @uploaded="addMediaFile" @upload-failed="enableSubmit" :drop-files="dropFiles"></media-upload>
- <button :disabled="submitDisabled" type="submit" class="btn btn-default base05 base01-background">Submit</button>
+ <button v-if="posting" disabled class="btn btn-default base05 base01-background">Posting</button>
+ <button v-else :disabled="submitDisabled" type="submit" class="btn btn-default base05 base01-background">Submit</button>
</div>
<div class='error' v-if="error">
Error: {{ error }}
</div>
<div class="attachments">
<div class="attachment" v-for="file in newStatus.files">
<i class="fa icon-cancel" @click="removeMediaFile(file)"></i>
<img class="thumbnail media-upload" :src="file.image" v-if="type(file) === 'image'"></img>
<video v-if="type(file) === 'video'" :src="file.image" controls></video>
<audio v-if="type(file) === 'audio'" :src="file.image" controls></audio>
<a v-if="type(file) === 'unknown'" :href="file.image">{{file.url}}</a>
</div>
</div>
</form>
</div>
</template>
<script src="./post_status_form.js"></script>
<style lang="scss">
.tribute-container {
ul {
padding: 0px;
li {
display: flex;
align-items: center;
}
}
img {
padding: 3px;
width: 16px;
height: 16px;
border-radius: 50%;
}
}
.post-status-form, .login {
.form-bottom {
display: flex;
padding: 0.5em;
height: 32px;
button {
width: 10em;
}
}
.error {
border-radius: 5px;
text-align: center;
background-color: rgba(255, 48, 16, 0.65);
padding: 0.25em;
margin: 0.35em;
}
.attachments {
padding: 0 0.5em;
.attachment {
position: relative;
margin: 0.5em 0.8em 0.2em 0;
}
i {
position: absolute;
margin: 10px;
padding: 5px;
background: rgba(230,230,230,0.6);
border-radius: 5px;
font-weight: bold;
}
}
.btn {
cursor: pointer;
}
.btn[disabled] {
cursor: not-allowed;
}
.icon-cancel {
cursor: pointer;
}
form {
display: flex;
flex-direction: column;
padding: 0.6em;
}
.form-group {
display: flex;
flex-direction: column;
padding: 0.3em 0.5em 0.6em;
line-height:24px;
}
form textarea {
border: solid;
border-width: 1px;
border-color: inherit;
border-radius: 5px;
line-height:16px;
padding: 5px;
resize: none;
overflow: hidden;
}
form textarea:focus {
min-height: 48px;
}
.btn {
cursor: pointer;
}
.btn[disabled] {
cursor: not-allowed;
}
.icon-cancel {
cursor: pointer;
}
.autocomplete-panel {
margin: 0 0.5em 0 0.5em;
border-radius: 5px;
position: absolute;
z-index: 1;
box-shadow: 1px 2px 4px rgba(0, 0, 0, 0.5);
min-width: 75%;
}
.autocomplete {
cursor: pointer;
padding: 0.2em 0.4em 0.2em 0.4em;
border-bottom: 1px solid rgba(0, 0, 0, 0.4);
display: flex;
img {
width: 24px;
height: 24px;
border-radius: 2px;
}
span {
line-height: 24px;
margin: 0 0.1em 0 0.2em;
}
small {
font-style: italic;
}
}
}
</style>
diff --git a/src/services/status_poster/status_poster.service.js b/src/services/status_poster/status_poster.service.js
index ee8d160a48..001ff8a50e 100644
--- a/src/services/status_poster/status_poster.service.js
+++ b/src/services/status_poster/status_poster.service.js
@@ -1,51 +1,56 @@
import { map } from 'lodash'
import apiService from '../api/api.service.js'
const postStatus = ({ store, status, media = [], inReplyToStatusId = undefined }) => {
const mediaIds = map(media, 'id')
return apiService.postStatus({credentials: store.state.users.currentUser.credentials, status, mediaIds, inReplyToStatusId})
.then((data) => data.json())
.then((data) => {
if (!data.error) {
store.dispatch('addNewStatuses', {
statuses: [data],
timeline: 'friends',
showImmediately: true,
noIdUpdate: true // To prevent missing notices on next pull.
})
}
return data
})
+ .catch((err) => {
+ return {
+ error: err.message
+ }
+ })
}
const uploadMedia = ({ store, formData }) => {
const credentials = store.state.users.currentUser.credentials
return apiService.uploadMedia({ credentials, formData }).then((xml) => {
// Firefox and Chrome treat method differently...
let link = xml.getElementsByTagName('link')
if (link.length === 0) {
link = xml.getElementsByTagName('atom:link')
}
link = link[0]
const mediaData = {
id: xml.getElementsByTagName('media_id')[0].textContent,
url: xml.getElementsByTagName('media_url')[0].textContent,
image: link.getAttribute('href'),
mimetype: link.getAttribute('type')
}
return mediaData
})
}
const statusPosterService = {
postStatus,
uploadMedia
}
export default statusPosterService
File Metadata
Details
Attached
Mime Type
text/x-diff
Expires
Sat, Aug 8, 9:43 PM (1 d, 18 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
1723996
Default Alt Text
(11 KB)
Attached To
Mode
rPUFE pleroma-fe-upstream
Attached
Detach File
Event Timeline
Log In to Comment