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>
<conversation :collapsable="false" :statusoid="statusoid"></conversation>
<conversation
:collapsable="false"
isPage="true"
:statusoid="statusoid"
></conversation>
</template>
<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 Status from '../status/status.vue'
const sortById = (a, b) => {
const seqA = Number(a.id)
const seqB = Number(b.id)
const idA = a.type === 'retweet' ? a.retweeted_status.id : a.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 isSeqB = !Number.isNaN(seqB)
if (isSeqA && isSeqB) {
@ -14,12 +16,19 @@ const sortById = (a, b) => {
} else if (!isSeqA && isSeqB) {
return 1
} else {
return a.id < b.id ? -1 : 1
return idA < idB ? -1 : 1
}
}
const sortAndFilterConversation = (conversation) => {
conversation = filter(conversation, (status) => status.type !== 'retweet')
const sortAndFilterConversation = (conversation, statusoid) => {
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)
}
@ -27,13 +36,20 @@ const conversation = {
data () {
return {
highlight: null,
expanded: false,
converationStatusIds: []
}
},
props: [
'statusoid',
'collapsable'
'collapsable',
'isPage'
],
created () {
if (this.isPage) {
this.fetchConversation()
}
},
computed: {
status () {
return this.statusoid
@ -59,12 +75,22 @@ const conversation = {
return []
}
if (!this.isExpanded) {
return [this.status]
}
const statusesObject = this.$store.state.statuses.allStatusesObject
const conversation = this.idsToShow.reduce((acc, id) => {
acc.push(statusesObject[id])
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 () {
let i = 1
@ -82,16 +108,21 @@ const conversation = {
i++
return result
}, {})
},
isExpanded () {
return this.expanded || this.isPage
}
},
components: {
Status
},
created () {
this.fetchConversation()
},
watch: {
'$route': 'fetchConversation'
'$route': 'fetchConversation',
expanded (value) {
if (value) {
this.fetchConversation()
}
}
},
methods: {
fetchConversation () {
@ -117,10 +148,19 @@ const conversation = {
return this.replies[id] || []
},
focused (id) {
return id === this.statusId
return (this.isExpanded) && id === this.status.id
},
setHighlight (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>
<div class="timeline panel panel-default">
<div class="panel-heading conversation-heading">
<div class="timeline panel-default" :class="[isExpanded ? 'panel' : 'panel-disabled']">
<div v-if="isExpanded" class="panel-heading conversation-heading">
<span class="title"> {{ $t('timeline.conversation') }} </span>
<span v-if="collapsable">
<a href="#" @click.prevent="$emit('toggleExpanded')">{{ $t('timeline.collapse') }}</a>
<a href="#" @click.prevent="toggleExpanded">{{ $t('timeline.collapse') }}</a>
</span>
</div>
<div class="panel-body">
<div class="timeline">
<status
v-for="status in conversation"
@goto="setHighlight" :key="status.id"
:inlineExpanded="collapsable" :statusoid="status"
:expandable='false' :focused="focused(status.id)"
:inConversation='true'
:highlight="highlight"
:replies="getReplies(status.id)"
class="status-fadein">
</status>
</div>
</div>
<status
v-for="status in conversation"
@goto="setHighlight"
@toggleExpanded="toggleExpanded"
:key="status.id"
:inlineExpanded="collapsable"
:statusoid="status"
:expandable='!expanded'
:focused="focused(status.id)"
:inConversation="isExpanded"
:highlight="getHighlight()"
:replies="getReplies(status.id)"
class="status-fadein panel-body"
/>
</div>
</template>
<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
},
gotoOriginal (id) {
// only handled by conversation, not status_or_conversation
if (this.inConversation) {
this.$emit('goto', id)
}

View File

@ -12,7 +12,7 @@
</div>
</template>
<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"/>
<div class="media-body faint">
<span class="user-name">
@ -24,7 +24,7 @@
</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">
<router-link :to="userProfileLink" @click.stop.prevent.capture.native="toggleUserExpanded">
<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 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'
const Timeline = {
@ -43,7 +43,7 @@ const Timeline = {
},
components: {
Status,
StatusOrConversation
Conversation
},
created () {
const store = this.$store

View File

@ -16,7 +16,13 @@
</div>
<div :class="classes.body">
<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 :class="classes.footer">