Merge branch 'issue-433-status-reply-form' into 'develop'

Issue 433 status reply form

Closes #433

See merge request pleroma/pleroma-fe!674
This commit is contained in:
Shpuld Shpludson 2019-03-28 20:08:40 +00:00
commit 7e8c2acc98
9 changed files with 102 additions and 73 deletions

View file

@ -1,5 +1,9 @@
<template> <template>
<conversation :collapsable="false" :statusoid="statusoid"></conversation> <conversation
:collapsable="false"
isPage="true"
:statusoid="statusoid"
></conversation>
</template> </template>
<script src="./conversation-page.js"></script> <script src="./conversation-page.js"></script>

View file

@ -1,10 +1,12 @@
import { reduce, filter } from 'lodash' import { reduce, filter, findIndex } from 'lodash'
import { set } from 'vue' import { set } from 'vue'
import Status from '../status/status.vue' import Status from '../status/status.vue'
const sortById = (a, b) => { const sortById = (a, b) => {
const seqA = Number(a.id) const idA = a.type === 'retweet' ? a.retweeted_status.id : a.id
const seqB = Number(b.id) const idB = b.type === 'retweet' ? b.retweeted_status.id : b.id
const seqA = Number(idA)
const seqB = Number(idB)
const isSeqA = !Number.isNaN(seqA) const isSeqA = !Number.isNaN(seqA)
const isSeqB = !Number.isNaN(seqB) const isSeqB = !Number.isNaN(seqB)
if (isSeqA && isSeqB) { if (isSeqA && isSeqB) {
@ -14,12 +16,19 @@ const sortById = (a, b) => {
} else if (!isSeqA && isSeqB) { } else if (!isSeqA && isSeqB) {
return 1 return 1
} else { } else {
return a.id < b.id ? -1 : 1 return idA < idB ? -1 : 1
} }
} }
const sortAndFilterConversation = (conversation) => { const sortAndFilterConversation = (conversation, statusoid) => {
conversation = filter(conversation, (status) => status.type !== 'retweet') if (statusoid.type === 'retweet') {
conversation = filter(
conversation,
(status) => (status.type === 'retweet' || status.id !== statusoid.retweeted_status.id)
)
} else {
conversation = filter(conversation, (status) => status.type !== 'retweet')
}
return conversation.filter(_ => _).sort(sortById) return conversation.filter(_ => _).sort(sortById)
} }
@ -27,13 +36,20 @@ const conversation = {
data () { data () {
return { return {
highlight: null, highlight: null,
expanded: false,
converationStatusIds: [] converationStatusIds: []
} }
}, },
props: [ props: [
'statusoid', 'statusoid',
'collapsable' 'collapsable',
'isPage'
], ],
created () {
if (this.isPage) {
this.fetchConversation()
}
},
computed: { computed: {
status () { status () {
return this.statusoid return this.statusoid
@ -59,12 +75,22 @@ const conversation = {
return [] return []
} }
if (!this.isExpanded) {
return [this.status]
}
const statusesObject = this.$store.state.statuses.allStatusesObject const statusesObject = this.$store.state.statuses.allStatusesObject
const conversation = this.idsToShow.reduce((acc, id) => { const conversation = this.idsToShow.reduce((acc, id) => {
acc.push(statusesObject[id]) acc.push(statusesObject[id])
return acc return acc
}, []) }, [])
return sortAndFilterConversation(conversation)
const statusIndex = findIndex(conversation, { id: this.statusId })
if (statusIndex !== -1) {
conversation[statusIndex] = this.status
}
return sortAndFilterConversation(conversation, this.status)
}, },
replies () { replies () {
let i = 1 let i = 1
@ -82,16 +108,21 @@ const conversation = {
i++ i++
return result return result
}, {}) }, {})
},
isExpanded () {
return this.expanded || this.isPage
} }
}, },
components: { components: {
Status Status
}, },
created () {
this.fetchConversation()
},
watch: { watch: {
'$route': 'fetchConversation' '$route': 'fetchConversation',
expanded (value) {
if (value) {
this.fetchConversation()
}
}
}, },
methods: { methods: {
fetchConversation () { fetchConversation () {
@ -117,10 +148,19 @@ const conversation = {
return this.replies[id] || [] return this.replies[id] || []
}, },
focused (id) { focused (id) {
return id === this.statusId return (this.isExpanded) && id === this.status.id
}, },
setHighlight (id) { setHighlight (id) {
this.highlight = id this.highlight = id
},
getHighlight () {
return this.isExpanded ? this.highlight : null
},
toggleExpanded () {
this.expanded = !this.expanded
if (!this.expanded) {
this.setHighlight(null)
}
} }
} }
} }

View file

@ -1,26 +1,42 @@
<template> <template>
<div class="timeline panel panel-default"> <div class="timeline panel-default" :class="[isExpanded ? 'panel' : 'panel-disabled']">
<div class="panel-heading conversation-heading"> <div v-if="isExpanded" class="panel-heading conversation-heading">
<span class="title"> {{ $t('timeline.conversation') }} </span> <span class="title"> {{ $t('timeline.conversation') }} </span>
<span v-if="collapsable"> <span v-if="collapsable">
<a href="#" @click.prevent="$emit('toggleExpanded')">{{ $t('timeline.collapse') }}</a> <a href="#" @click.prevent="toggleExpanded">{{ $t('timeline.collapse') }}</a>
</span> </span>
</div> </div>
<div class="panel-body"> <status
<div class="timeline"> v-for="status in conversation"
<status @goto="setHighlight"
v-for="status in conversation" @toggleExpanded="toggleExpanded"
@goto="setHighlight" :key="status.id" :key="status.id"
:inlineExpanded="collapsable" :statusoid="status" :inlineExpanded="collapsable"
:expandable='false' :focused="focused(status.id)" :statusoid="status"
:inConversation='true' :expandable='!expanded'
:highlight="highlight" :focused="focused(status.id)"
:replies="getReplies(status.id)" :inConversation="isExpanded"
class="status-fadein"> :highlight="getHighlight()"
</status> :replies="getReplies(status.id)"
</div> class="status-fadein panel-body"
</div> />
</div> </div>
</template> </template>
<script src="./conversation.js"></script> <script src="./conversation.js"></script>
<style lang="scss">
@import '../../_variables.scss';
.timeline {
.panel-disabled {
.status-el {
border-left: none;
border-bottom-width: 1px;
border-bottom-style: solid;
border-color: var(--border, $fallback--border);
border-radius: 0;
}
}
}
</style>

View file

@ -310,7 +310,6 @@ const Status = {
this.replying = !this.replying this.replying = !this.replying
}, },
gotoOriginal (id) { gotoOriginal (id) {
// only handled by conversation, not status_or_conversation
if (this.inConversation) { if (this.inConversation) {
this.$emit('goto', id) this.$emit('goto', id)
} }

View file

@ -12,7 +12,7 @@
</div> </div>
</template> </template>
<template v-else> <template v-else>
<div v-if="retweet && !noHeading" :class="[repeaterClass, { highlighted: repeaterStyle }]" :style="[repeaterStyle]" class="media container retweet-info"> <div v-if="retweet && !noHeading && !inConversation" :class="[repeaterClass, { highlighted: repeaterStyle }]" :style="[repeaterStyle]" class="media container retweet-info">
<UserAvatar class="media-left" v-if="retweet" :betterShadow="betterShadow" :src="statusoid.user.profile_image_url_original"/> <UserAvatar class="media-left" v-if="retweet" :betterShadow="betterShadow" :src="statusoid.user.profile_image_url_original"/>
<div class="media-body faint"> <div class="media-body faint">
<span class="user-name"> <span class="user-name">
@ -24,7 +24,7 @@
</div> </div>
</div> </div>
<div :class="[userClass, { highlighted: userStyle, 'is-retweet': retweet }]" :style="[ userStyle ]" class="media status"> <div :class="[userClass, { highlighted: userStyle, 'is-retweet': retweet && !inConversation }]" :style="[ userStyle ]" class="media status">
<div v-if="!noHeading" class="media-left"> <div v-if="!noHeading" class="media-left">
<router-link :to="userProfileLink" @click.stop.prevent.capture.native="toggleUserExpanded"> <router-link :to="userProfileLink" @click.stop.prevent.capture.native="toggleUserExpanded">
<UserAvatar :compact="compact" :betterShadow="betterShadow" :src="status.user.profile_image_url_original"/> <UserAvatar :compact="compact" :betterShadow="betterShadow" :src="status.user.profile_image_url_original"/>

View file

@ -1,22 +0,0 @@
import Status from '../status/status.vue'
import Conversation from '../conversation/conversation.vue'
const statusOrConversation = {
props: ['statusoid'],
data () {
return {
expanded: false
}
},
components: {
Status,
Conversation
},
methods: {
toggleExpanded () {
this.expanded = !this.expanded
}
}
}
export default statusOrConversation

View file

@ -1,14 +0,0 @@
<template>
<div>
<conversation v-if="expanded" @toggleExpanded="toggleExpanded" :collapsable="true" :statusoid="statusoid"></conversation>
<status v-if="!expanded" @toggleExpanded="toggleExpanded" :expandable="true" :inConversation="false" :focused="false" :statusoid="statusoid"></status>
</div>
</template>
<script src="./status_or_conversation.js"></script>
<style lang="scss">
.spacer {
height: 1em
}
</style>

View file

@ -1,6 +1,6 @@
import Status from '../status/status.vue' import Status from '../status/status.vue'
import timelineFetcher from '../../services/timeline_fetcher/timeline_fetcher.service.js' import timelineFetcher from '../../services/timeline_fetcher/timeline_fetcher.service.js'
import StatusOrConversation from '../status_or_conversation/status_or_conversation.vue' import Conversation from '../conversation/conversation.vue'
import { throttle } from 'lodash' import { throttle } from 'lodash'
const Timeline = { const Timeline = {
@ -43,7 +43,7 @@ const Timeline = {
}, },
components: { components: {
Status, Status,
StatusOrConversation Conversation
}, },
created () { created () {
const store = this.$store const store = this.$store

View file

@ -16,7 +16,13 @@
</div> </div>
<div :class="classes.body"> <div :class="classes.body">
<div class="timeline"> <div class="timeline">
<status-or-conversation v-for="status in timeline.visibleStatuses" :key="status.id" v-bind:statusoid="status" class="status-fadein"></status-or-conversation> <conversation
v-for="status in timeline.visibleStatuses"
class="status-fadein"
:key="status.id"
:statusoid="status"
:collapsable="true"
/>
</div> </div>
</div> </div>
<div :class="classes.footer"> <div :class="classes.footer">