@ -1,6 +1,7 @@
< template >
< div class = "container" style = "" >
< div v-if ="layout === 'feed'" class="row" >
< div >
< div v-if ="currentLayout === 'feed'" class="container" >
< div class = "row" >
< div v-if ="morePostsAvailable == true" class="col-12 mt-5 pt-3 mb-3 fixed-top" >
< p class = "text-center" >
< button class = "btn btn-dark px-4 rounded-pill font-weight-bold shadow" @click ="syncNewPosts" > Load New Posts < / button >
@ -207,10 +208,10 @@
< div class = "card-body" >
< div class = "reactions my-1 pb-2" >
< h3 v-if ="status.favourited" class="fas fa-heart text-danger pr-3 m-0 cursor-pointer" title="Like" v-on:click="likeStatus(status, $event);" > < / h3 >
< h3 v -else class = "far fa-heart pr-3 m-0 like-btn text- lighter cursor-pointer" title = "Like" v -on : click = "likeStatus(status, $event);" > < / h3 >
< h3 v-if ="!status.comments_disabled" class="far fa-comment text- lighter pr-3 m-0 cursor-pointer" title="Comment" v-on:click="commentFocus(status, $event)"> < / h3 >
< h3 v-if ="status.visibility == 'public'" v-bind:class="[status.reblogged ? 'fas fa-retweet pr-3 m-0 text-primary cursor-pointer' : 'fas fa-retweet pr-3 m-0 text- lighter share-btn cursor-pointer']" title="Share" v-on:click="shareStatus(status, $event)"> < / h3 >
< h3 class = "fas fa-expand pr-3 m-0 cursor-pointer text- lighter " v -on :click ="lightbox(status)" > < / h3 >
< h3 v -else class = "far fa-heart pr-3 m-0 like-btn text- dark cursor-pointer" title = "Like" v -on : click = "likeStatus(status, $event);" > < / h3 >
< h3 v-if ="!status.comments_disabled" class="far fa-comment text- dark pr-3 m-0 cursor-pointer" title="Comment" v-on:click="commentFocus(status, $event)"> < / h3 >
<!-- < h3 v-if ="status.visibility == 'public'" v-bind:class="[status.reblogged ? 'fas fa-retweet pr-3 m-0 text-primary cursor-pointer' : 'fas fa-retweet pr-3 m-0 text- dark share-btn cursor-pointer']" title="Share" v-on:click="shareStatus(status, $event)"> < / h3 > - - >
<!-- < h3 class = "fas fa-expand pr-3 m-0 cursor-pointer text- dark " v -on :click ="lightbox(status)" > < / h3 > -- >
< span v-if ="status.taggedPeople.length" class="float-right" >
< span class = "font-weight-light small" style = "color:#718096" >
< i class = "far fa-user" data -toggle = " tooltip " title = "Tagged People" > < / i >
@ -234,7 +235,7 @@
< span class = "status-content" v-html ="status.content" > < / span >
< / p >
< / div >
< div class = "comments" v-if ="status.id == replyId && !status.comments_disabled" >
<!-- < div class = "comments" v-if ="status.id == replyId && !status.comments_disabled" >
< p class = "mb-0 d-flex justify-content-between align-items-top read-more mt-2" style = "overflow-y: hidden;" v-for ="(reply, index) in replies" >
< span >
< a class = "text-dark font-weight-bold mr-1" :href ="profileUrl(reply)" > { { reply . account . username } } < / a >
@ -244,13 +245,13 @@
< span v -on : click = "likeStatus(reply, $event);" >
< i v -bind : class = "[reply.favourited ? 'fas fa-heart fa-sm text-danger cursor-pointer':'far fa-heart fa-sm text-lighter cursor-pointer']" > < / i >
< / span >
<!-- < post -menu :status ="reply" :profile ="profile" size = "sm" :modal ="'true'" :feed ="feed" class = "d-inline-flex pl-2" > < / p o s t - m e n u > - - >
<!-- < post -menu :status ="reply" :profile ="profile" size = "sm" :modal ="'true'" :feed ="feed" class = "d-inline-flex pl-2" > < / p o s t - m e n u > - - >
< span class = "text-lighter pl-2 cursor-pointer" @click ="ctxMenu(reply)" >
< span class = "fas fa-ellipsis-v text-lighter" > < / span >
< / span >
< / span >
< / p >
< / div >
< / div > -- >
< div class = "timestamp mt-2" >
< p class = "small text-uppercase mb-0" >
< a :href ="statusUrl(status)" class = "text-muted" >
@ -296,7 +297,6 @@
< / div >
< / div >
< / div >
< div class = "col-md-4 col-lg-4 my-4 order-1 order-md-2 d-none d-md-block" >
< div >
@ -401,75 +401,145 @@
< / div >
< / div >
< / div >
< div v -else class = "row" >
< div class = "col-12" >
<!-- < div v-if ="loading" class="text-center" >
< div class = "spinner-border" role = "status" >
< span class = "sr-only" > Loading ... < / span >
< / div >
< / div > -- >
< div v-if ="currentLayout === 'comments'" class="container p-0 overflow-hidden" >
< div class = "row" >
< div class = "col-12 pl-3 pl-md-0 pt-3 pl-0" >
< div class = "d-flex justify-content-between align-items-center" >
< p class = "lead text-muted mb-0" > < i : class = "[scope == 'home' ? 'fas fa-home':'fas fa-stream']" > < / i > & nbsp ; { { scope == 'local' ? 'Public' : 'Home' } } Timeline < / p >
< p class = "mb-0" >
< span class = "btn-group" >
< a href = "#" : class = "[layout=='feed'?'btn btn-sm btn-outline-primary font-weight-bold text-decoration-none':'btn btn-sm btn-outline-lighter font-weight-light text-decoration-none']" @click.prevent ="switchFeedLayout('feed')" > < i class = "fas fa-list" > < / i > < / a >
< a href = "#" : class = "[layout!=='feed'?'btn btn-sm btn-outline-primary font-weight-bold text-decoration-none':'btn btn-sm btn-outline-lighter font-weight-light text-decoration-none']" @click.prevent ="switchFeedLayout('grid')" > < i class = "fas fa-th" > < / i > < / a >
< div class = "col-12 col-md-6 offset-md-3" >
< div class = "card shadow-none border" style = "height:100vh;" >
< div class = "card-header d-flex justify-content-between align-items-center" >
< div
@ click = "commentNavigateBack(status.id)"
class = "cursor-pointer"
>
< i class = "fas fa-chevron-left fa-lg px-2" > < / i >
< / div >
< div >
< p class = "font-weight-bold mb-0 h5" > Comments < / p >
< / div >
< div >
< i class = "fas fa-cog fa-lg text-white" > < / i >
< / div >
< / div >
< div class = "card-body" style = "overflow-y: auto !important" >
< div class = "media" >
< img :src ="status.account.avatar" class = "rounded-circle border mr-3" width = "32px" height = "32px" >
< div class = "media-body" >
< p class = "d-flex justify-content-between align-items-top mb-0" style = "overflow-y: hidden;" >
< span class = "mr-2" style = "font-size: 13px;" >
< a class = "text-dark font-weight-bold mr-1 text-break" :href ="status.account.url" v -bind :title ="status.account.username" > { { trimCaption ( status . account . username , 15 ) } } < / a >
< span class = "text-break comment-body" style = "word-break: break-all;" v-html ="status.content" > < / span >
< / span >
< / p >
< p class = "mb-0 d-none d-md-block" >
< a class = "btn btn-block btn-primary btn-sm font-weight-bold" href = "/i/compose" data -toggle = " modal " data -target = " # composeModal " >
New Post
< / a >
< / p >
< / div >
< hr >
< / div >
< div class = "col-12 col-md-4 p-1 p-md-3 mb-3" v-for ="(s, index) in feed" :key="`${index}-${s.id}`" >
< a class = "card info-overlay card-md-border-0 shadow-sm border border-light" :href ="statusUrl(s)" >
< div : class = "[s.sensitive ? 'square' : 'square ' + s.media_attachments[0].filter_class]" >
< span v-if ="s.pf_type == 'photo:album'" class="float-right mr-3 post-icon"><i class="fas fa-images fa-2x" > < / i > < / span >
< span v-if ="s.pf_type == 'video'" class="float-right mr-3 post-icon"><i class="fas fa-video fa-2x" > < / i > < / span >
< span v-if ="s.pf_type == 'video:album'" class="float-right mr-3 post-icon"><i class="fas fa-film fa-2x" > < / i > < / span >
< div class = "square-content" v -bind :style ="previewBackground(s)" >
< / div >
< div class = "info-overlay-text px-4" >
< p class = "text-white m-auto text-center" >
{ { trimCaption ( s . content _text ) } }
< / p >
< hr >
< div class = "postCommentsLoader text-center py-2" >
< div class = "spinner-border" role = "status" >
< span class = "sr-only" > Loading ... < / span >
< / div >
< / div >
< div class = "postCommentsContainer d-none" >
< p v-if ="replies.length" class="mb-1 text-center load-more-link my-4" >
< a
href = "#"
class = "text-dark"
title = "Load more comments"
@ click . prevent = "loadMoreComments"
>
< svg class = "bi bi-plus-circle" width = "1em" height = "1em" viewBox = "0 0 16 16" fill = "currentColor" xmlns = "http://www.w3.org/2000/svg" style = "font-size:2em;" > < path fill -rule = " evenodd " d = "M8 3.5a.5.5 0 01.5.5v4a.5.5 0 01-.5.5H4a.5.5 0 010-1h3.5V4a.5.5 0 01.5-.5z" clip -rule = " evenodd " / > < path fill -rule = " evenodd " d = "M7.5 8a.5.5 0 01.5-.5h4a.5.5 0 010 1H8.5V12a.5.5 0 01-1 0V8z" clip -rule = " evenodd " / > < path fill -rule = " evenodd " d = "M8 15A7 7 0 108 1a7 7 0 000 14zm0 1A8 8 0 108 0a8 8 0 000 16z" clip -rule = " evenodd " / > < / svg >
< / a >
< div class = "py-3 media align-items-center" >
< a class = "text-decoration-none" :href ="s.account.url" > < img :src ="s.account.avatar" class = "mr-3 rounded-circle shadow-sm" : alt = "s.account.username + ' \'s avatar'" width = "30px" height = "30px" onerror = "this.onerror=null;this.src='/storage/avatars/default.png?v=2'" > < / a >
< / p >
< div v-for ="(reply, index) in replies" class="pb-3 media" :key="'tl' + reply.id + '_' + index" >
< img :src ="reply.account.avatar" class = "rounded-circle border mr-3" width = "32px" height = "32px" >
< div class = "media-body" >
< p class = "mb-0 font-weight-bold small" > < a class = "text-dark" :href ="s.account.url" > { { s . account . username } } < / a > < / p >
< p class = "mb-0" style = "line-height: 0.7;" >
< a :href ="statusUrl(s)" class = "small text-lighter" >
< timeago :datetime ="s.created_at" :auto-update ="60" :converter-options ="{includeSeconds:true}" :title ="timestampFormat(s.created_at)" v-b-tooltip.hover.bottom></timeago>
< / a >
< div v-if ="reply.sensitive == true" >
< span class = "py-3" >
< a class = "text-dark font-weight-bold mr-3" style = "font-size: 13px;" :href ="reply.account.url" v -bind :title ="reply.account.username" > { { trimCaption ( reply . account . username , 15 ) } } < / a >
< span class = "text-break" style = "font-size: 13px;" >
< span class = "font-italic text-muted" > This comment may contain sensitive material < / span >
< span class = "text-primary cursor-pointer pl-1" @ click = "reply.sensitive = false;" > Show < / span >
< / span >
< / span >
< / div >
< div v-else >
< p class = "d-flex justify-content-between align-items-top read-more mb-0" style = "overflow-y: hidden;" >
< span class = "mr-3" style = "font-size: 13px;" >
< a class = "text-dark font-weight-bold mr-1 text-break" :href ="reply.account.url" v -bind :title ="reply.account.username" > { { trimCaption ( reply . account . username , 15 ) } } < / a >
< span class = "text-break comment-body" style = "word-break: break-all;" v-html ="reply.content" > < / span >
< / span >
< span class = "text-right" style = "min-width: 30px;" >
< span v -on : click = "likeReply(reply, $event)" > < i v -bind : class = "[reply.favourited ? 'fas fa-heart fa-sm text-danger':'far fa-heart fa-sm text-lighter']" > < / i > < / span >
< span class = "pl-2 text-lighter cursor-pointer" @click ="ctxMenu(reply)" >
< span class = "fas fa-ellipsis-v text-lighter" > < / span >
< / span >
<!-- < post -menu :status ="reply" :profile ="user" :size ="'sm'" :modal ="'true'" class = "d-inline-block px-2" v -on : deletePost = "" > < / p o s t - m e n u > - - >
< / span >
< / p >
< p class = "mb-0" >
< a v -once class = "text-muted mr-3 text-decoration-none small" style = "width: 20px;" v-text ="timeAgo(reply.created_at)" :href="reply.url" > < / a >
< span v-if ="reply.favourites_count" class="text-muted comment-reaction font-weight-bold mr-3 small" > {{ reply.favourites_count = = 1 ? ' 1 like ' : reply.favourites_count + ' likes ' }} < / span >
< span class = "small text-muted comment-reaction font-weight-bold cursor-pointer" v -on : click = "replyFocus(reply, index, true)" > Reply < / span >
< / p >
< div v-if ="reply.reply_count > 0" class="cursor-pointer pb-2" v-on:click="toggleReplies(reply)" >
< span class = "show-reply-bar" > < / span >
< span class = "comment-reaction small font-weight-bold" > { { reply . thread ? 'Hide' : 'View' } } Replies ( { { reply . reply _count } } ) < / span >
< / div >
< div class = "ml-3" >
< div v-if ="reply.thread == true" class="comment-thread" >
< div v-for ="(s, sindex) in reply.replies" class="py-1 media" :key="'cr' + s.id + '_' + index" >
< img :src ="s.account.avatar" class = "rounded-circle border mr-3" width = "25px" height = "25px" >
< div class = "media-body" >
< p class = "d-flex justify-content-between align-items-top read-more mb-0" style = "overflow-y: hidden;" >
< span class = "mr-2" style = "font-size: 13px;" >
< a class = "text-dark font-weight-bold mr-1" :href ="s.account.url" :title ="s.account.username" > { { s . account . username } } < / a >
< span class = "text-break comment-body" style = "word-break: break-all;" v-html ="s.content" > < / span >
< / span >
< span >
< span v -on : click = "likeReply(s, $event)" > < i v -bind : class = "[s.favourited ? 'fas fa-heart fa-sm text-danger':'far fa-heart fa-sm text-lighter']" > < / i > < / span >
<!-- < post -menu :status ="s" :profile ="user" :size ="'sm'" :modal ="'true'" class = "d-inline-block pl-2" v -on : deletePost = "deleteCommentReply(s.id, sindex, index) " > < / p o s t - m e n u > - - >
< / span >
< / p >
< p class = "mb-0" >
< span v-if ="statusOwner(s)" class="font-weight-bold small" > {{ s.favourites_count = = 1 ? ' 1 like ' : s.favourites_count + ' likes ' }} < / span >
< span class = "px-2" > < i v -bind : class = "[s.favourited ? 'fas fa-heart text-danger cursor-pointer' : 'far fa-heart like-btn text-lighter cursor-pointer']" v -on : click = "likeStatus(s, $event);" > < / i > < / span >
< span class = "mr-2 cursor-pointer" > < i class = "fas fa-ellipsis-v" @click ="ctxMenu(s)" > < / i > < / span >
< a v -once class = "text-muted mr-3 text-decoration-none small" style = "width: 20px;" v-text ="timeAgo(s.created_at)" :href="s.url" > < / a >
< span v-if ="s.favourites_count" class="text-muted comment-reaction font-weight-bold mr-3" > {{ s.favourites_count = = 1 ? ' 1 like ' : s.favourites_count + ' likes ' }} < / span >
< / p >
< / div >
< / div >
< / div >
< / div >
< div v-if ="!loading && feed.length" >
< infinite -loading @infinite ="infiniteTimeline" :distance ="800" >
< div slot = "no-more" class = "font-weight-bold" > No more posts to load < / div >
< div slot = "no-results" class = "font-weight-bold" > No more posts to load < / div >
< / i n f i n i t e - l o a d i n g >
< / div >
< / div >
< div v-if ="!replies.length" >
< p class = "text-center text-muted font-weight-bold small" > No comments yet < / p >
< / div >
< / div >
< / div >
< div class = "card-footer mb-3" >
< div class = "align-middle d-flex" >
< img
: src = "profile.avatar"
width = "36"
height = "36"
class = "rounded-circle border mr-3" >
< textarea
class = "form-control rounded-pill"
name = "comment"
placeholder = "Add a comment…"
autocomplete = "off"
autocorrect = "off"
rows = "1"
maxlength = "0"
style = "resize: none;overflow-y: hidden"
@ click = "replyFocus(status)" >
< / textarea >
< / div >
< / div >
< / div >
< / div >
< / div >
< / div >
< div class = "modal-stack" >
< b -modal ref = "ctxModal"
id = "ctx-modal"
hide - header
@ -538,6 +608,7 @@
rounded
size = "sm"
body - class = "list-group-flush p-0 rounded text-center" >
< div class = "list-group-item rounded cursor-pointer" @ click = "shareStatus(ctxMenuStatus, $event)" > { { ctxMenuStatus . reblogged ? 'Unshare' : 'Share' } } to Followers < / div >
< div class = "list-group-item rounded cursor-pointer" @click ="ctxMenuCopyLink()" > Copy Link < / div >
< div v-if ="ctxMenuStatus && ctxMenuStatus.local == true && !ctxMenuStatus.in_reply_to_id" class="list-group-item rounded cursor-pointer" @click="ctxMenuEmbed()" > Embed < / div >
<!-- < div class = "list-group-item rounded cursor-pointer border-top-0" > Email < / div >
@ -669,8 +740,13 @@
size = "md"
body - class = "p-2 rounded" >
< div >
< textarea class = "form-control" rows = "4" style = "border: none; font-size: 18px; resize: none; white-space: pre-wrap;outline: none;" placeholder = "Reply here ..." v-model ="replyText" >
< vue -tribute :options ="tributeSettings" >
< textarea
class = "form-control replyModalTextarea"
rows = "4"
v - model = "replyText" >
< / textarea >
< / v u e - t r i b u t e >
< div class = "border-top border-bottom my-2" >
< ul class = "nav align-items-center emoji-reactions" style = "overflow-x: scroll;flex-wrap: unset;" >
@ -716,81 +792,20 @@
profile - layout = "metro" >
< / p o s t - c o m p o n e n t > - - >
< / b - m o d a l >
< / div >
< / div >
< / div >
< / template >
< style type = "text/css" scoped >
. postPresenterContainer {
display : flex ;
align - items : center ;
background : # fff ;
}
. word - break {
word - break : break - all ;
}
. small . custom - control - label {
padding - top : 3 px ;
}
. reply - btn {
position : absolute ;
bottom : 12 px ;
right : 20 px ;
width : 60 px ;
text - align : center ;
border - radius : 0 3 px 3 px 0 ;
}
. emoji - reactions . nav - item {
font - size : 1.2 rem ;
padding : 9 px ;
cursor : pointer ;
}
. emoji - reactions : : - webkit - scrollbar {
width : 0 px ;
height : 0 px ;
background : transparent ;
}
. reply - btn [ disabled ] {
opacity : .3 ;
color : # 3897 f0 ;
}
. has - story {
width : 64 px ;
height : 64 px ;
border - radius : 50 % ;
padding : 2 px ;
background : radial - gradient ( ellipse at 70 % 70 % , # ee583f 8 % , # d92d77 42 % , # bd3381 58 % ) ;
}
. has - story img {
width : 60 px ;
height : 60 px ;
border - radius : 50 % ;
padding : 3 px ;
background : # fff ;
}
. has - story . has - story - sm {
width : 32 px ;
height : 32 px ;
border - radius : 50 % ;
padding : 2 px ;
background : radial - gradient ( ellipse at 70 % 70 % , # ee583f 8 % , # d92d77 42 % , # bd3381 58 % ) ;
}
. has - story . has - story - sm img {
width : 28 px ;
height : 28 px ;
border - radius : 50 % ;
padding : 3 px ;
background : # fff ;
}
# ctx - reply - modal . form - control : focus {
border : none ;
outline : 0 ;
box - shadow : none ;
}
< / style >
< script type = "text/javascript" >
import VueTribute from 'vue-tribute'
export default {
props : [ 'scope' , 'layout' ] ,
components : {
VueTribute
} ,
data ( ) {
return {
ids : [ ] ,
@ -844,7 +859,41 @@
mpPoller : null ,
confirmModalTitle : 'Are you sure?' ,
confirmModalIdentifer : null ,
confirmModalType : false
confirmModalType : false ,
currentLayout : 'feed' ,
pagination : { } ,
tributeSettings : {
collection : [
{
trigger : '@' ,
menuShowMinLength : 2 ,
values : ( function ( text , cb ) {
let url = '/api/compose/v0/search/mention' ;
axios . get ( url , { params : { q : text } } )
. then ( res => {
cb ( res . data ) ;
} )
. catch ( err => {
console . log ( err ) ;
} )
} )
} ,
{
trigger : '#' ,
menuShowMinLength : 2 ,
values : ( function ( text , cb ) {
let url = '/api/compose/v0/search/hashtag' ;
axios . get ( url , { params : { q : text } } )
. then ( res => {
cb ( res . data ) ;
} )
. catch ( err => {
console . log ( err ) ;
} )
} )
}
]
}
}
} ,
@ -1057,10 +1106,10 @@
return ;
}
if ( this . status && this . status . id == status . id ) {
this . $refs . replyModal . show ( ) ;
return ;
}
/ / i f ( t h i s . s t a t u s & & t h i s . s t a t u s . i d = = s t a t u s . i d ) {
/ / t h i s . $ r e f s . r e p l y M o d a l . s h o w ( ) ;
/ / r e t u r n ;
/ / }
this . status = status ;
this . replies = { } ;
@ -1068,10 +1117,32 @@
this . replyText = '' ;
this . replyId = status . id ;
this . replyStatus = status ;
this . $refs . replyModal . show ( ) ;
/ / t h i s . $ r e f s . r e p l y M o d a l . s h o w ( ) ;
this . fetchStatusComments ( status , '' ) ;
$ ( 'nav' ) . hide ( ) ;
$ ( 'footer' ) . hide ( ) ;
$ ( '.mobile-footer-spacer' ) . attr ( 'style' , 'display:none !important' ) ;
$ ( '.mobile-footer' ) . attr ( 'style' , 'display:none !important' ) ;
this . currentLayout = 'comments' ;
window . history . pushState ( { } , '' , status . url ) ;
return ;
} ,
commentNavigateBack ( id ) {
$ ( 'nav' ) . show ( ) ;
$ ( 'footer' ) . show ( ) ;
$ ( '.mobile-footer-spacer' ) . attr ( 'style' , 'display:block' ) ;
$ ( '.mobile-footer' ) . attr ( 'style' , 'display:block' ) ;
this . currentLayout = 'feed' ;
setTimeout ( function ( ) {
$ ( [ document . documentElement , document . body ] ) . animate ( {
scrollTop : $ ( ` div[data-status-id=" ${ id } "] ` ) . offset ( ) . top
} , 1000 ) ;
} , 500 ) ;
let path = this . scope == 'home' ? '/' : '/timeline/public' ;
window . history . pushState ( { } , '' , path ) ;
} ,
likeStatus ( status , event ) {
@ -1102,11 +1173,18 @@
return ;
}
this . closeModals ( ) ;
axios . post ( '/i/share' , {
item : status . id
} ) . then ( res => {
status . reblogs _count = res . data . count ;
status . reblogged = ! status . reblogged ;
if ( status . reblogged ) {
swal ( 'Success' , 'You shared this post' , 'success' ) ;
} else {
swal ( 'Success' , 'You unshared this post' , 'success' ) ;
}
} ) . catch ( err => {
swal ( 'Error' , 'Something went wrong, please try again later.' , 'error' ) ;
} ) ;
@ -1133,19 +1211,67 @@
} ,
fetchStatusComments ( status , card ) {
axios . get ( '/api/v2/status/' + status . id + '/replies' )
. then ( res => {
let data = res . data . filter ( res => {
return res . sensitive == false ;
} ) ;
this . replies = _ . reverse ( data ) ;
setTimeout ( function ( ) {
document . querySelectorAll ( '.timeline .card-body .comments .comment-body a' ) . forEach ( function ( i , e ) {
i . href = App . util . format . rewriteLinks ( i ) ;
/ / a x i o s . g e t ( ' / a p i / v 2 / s t a t u s / ' + s t a t u s . i d + ' / r e p l i e s ' ,
/ / {
/ / p a r a m s : {
/ / l i m i t : 6
/ / }
/ / } )
/ / . t h e n ( r e s = > {
/ / l e t d a t a = r e s . d a t a . f i l t e r ( r e s = > {
/ / r e t u r n r e s . s e n s i t i v e = = f a l s e ;
/ / } ) ;
/ / t h i s . r e p l i e s = _ . r e v e r s e ( d a t a ) ;
/ / s e t T i m e o u t ( f u n c t i o n ( ) {
/ / d o c u m e n t . q u e r y S e l e c t o r A l l ( ' . t i m e l i n e . c a r d - b o d y . c o m m e n t s . c o m m e n t - b o d y a ' ) . f o r E a c h ( f u n c t i o n ( i , e ) {
/ / i . h r e f = A p p . u t i l . f o r m a t . r e w r i t e L i n k s ( i ) ;
/ / } ) ;
/ / } , 5 0 0 ) ;
/ / } ) . c a t c h ( e r r = > {
/ / } )
let url = '/api/v2/comments/' + status . account . id + '/status/' + status . id ;
axios . get ( url )
. then ( response => {
let self = this ;
/ / t h i s . r e s u l t s = t h i s . l a y o u t = = ' m e t r o ' ?
/ / _ . r e v e r s e ( r e s p o n s e . d a t a . d a t a ) :
/ / r e s p o n s e . d a t a . d a t a ;
this . replies = _ . reverse ( response . data . data ) ;
this . pagination = response . data . meta . pagination ;
if ( this . replies . length > 0 ) {
$ ( '.load-more-link' ) . removeClass ( 'd-none' ) ;
}
$ ( '.postCommentsLoader' ) . addClass ( 'd-none' ) ;
$ ( '.postCommentsContainer' ) . removeClass ( 'd-none' ) ;
/ / s e t T i m e o u t ( f u n c t i o n ( ) {
/ / d o c u m e n t . q u e r y S e l e c t o r A l l ( ' . s t a t u s - c o m m e n t . p o s t C o m m e n t s C o n t a i n e r . c o m m e n t - b o d y a ' ) . f o r E a c h ( f u n c t i o n ( i , e ) {
/ / i . h r e f = A p p . u t i l . f o r m a t . r e w r i t e L i n k s ( i ) ;
/ / } ) ;
/ / } , 5 0 0 ) ;
} ) . catch ( error => {
if ( ! error . response ) {
$ ( '.postCommentsLoader .lds-ring' )
. attr ( 'style' , 'width:100%' )
. addClass ( 'pt-4 font-weight-bold text-muted' )
. text ( 'An error occurred, cannot fetch comments. Please try again later.' ) ;
} else {
switch ( error . response . status ) {
case 401 :
$ ( '.postCommentsLoader .lds-ring' )
. attr ( 'style' , 'width:100%' )
. addClass ( 'pt-4 font-weight-bold text-muted' )
. text ( 'Please login to view.' ) ;
break ;
default :
$ ( '.postCommentsLoader .lds-ring' )
. attr ( 'style' , 'width:100%' )
. addClass ( 'pt-4 font-weight-bold text-muted' )
. text ( 'An error occurred, cannot fetch comments. Please try again later.' ) ;
break ;
}
}
} ) ;
} , 500 ) ;
} ) . catch ( err => {
} )
} ,
muteProfile ( status ) {
@ -1217,7 +1343,7 @@
sensitive : this . replyNsfw
} ) . then ( res => {
this . replyText = '' ;
this . replies . un shift ( res . data . entity ) ;
this . replies . p ush( res . data . entity ) ;
this . $refs . replyModal . hide ( ) ;
} ) ;
this . replySending = false ;
@ -1927,6 +2053,92 @@
confirmModalCancel ( ) {
this . closeConfirmModal ( ) ;
} ,
timeAgo ( ts ) {
return App . util . format . timeAgo ( ts ) ;
} ,
toggleReplies ( reply ) {
if ( reply . thread ) {
reply . thread = false ;
} else {
if ( reply . replies . length > 0 ) {
reply . thread = true ;
return ;
}
let url = '/api/v2/comments/' + reply . account . id + '/status/' + reply . id ;
axios . get ( url )
. then ( response => {
reply . replies = _ . reverse ( response . data . data ) ;
reply . thread = true ;
} ) ;
}
} ,
likeReply ( status , $event ) {
if ( $ ( 'body' ) . hasClass ( 'loggedIn' ) == false ) {
swal ( 'Login' , 'Please login to perform this action.' , 'info' ) ;
return ;
}
axios . post ( '/i/like' , {
item : status . id
} ) . then ( res => {
status . favourites _count = res . data . count ;
if ( status . favourited == true ) {
status . favourited = false ;
} else {
status . favourited = true ;
}
} ) . catch ( err => {
swal ( 'Error' , 'Something went wrong, please try again later.' , 'error' ) ;
} ) ;
} ,
replyFocus ( e , index , prependUsername = false ) {
if ( $ ( 'body' ) . hasClass ( 'loggedIn' ) == false ) {
this . redirect ( '/login?next=' + encodeURIComponent ( window . location . pathname ) ) ;
return ;
}
if ( this . status . comments _disabled ) {
return ;
}
this . replyToIndex = index ;
this . replyingToId = e . id ;
this . replyingToUsername = e . account . username ;
this . reply _to _profile _id = e . account . id ;
let username = e . account . local ? '@' + e . account . username + ' '
: '@' + e . account . acct + ' ' ;
if ( prependUsername == true ) {
this . replyText = username ;
}
this . $refs . replyModal . show ( ) ;
setTimeout ( function ( ) {
$ ( '.replyModalTextarea' ) . focus ( ) ;
} , 500 ) ;
} ,
loadMoreComments ( ) {
if ( this . pagination . total _pages == 1 || this . pagination . current _page == this . pagination . total _pages ) {
$ ( '.load-more-link' ) . addClass ( 'd-none' ) ;
return ;
}
$ ( '.load-more-link' ) . addClass ( 'd-none' ) ;
$ ( '.postCommentsLoader' ) . removeClass ( 'd-none' ) ;
let next = this . pagination . links . next ;
axios . get ( next )
. then ( response => {
let self = this ;
let res = response . data . data ;
$ ( '.postCommentsLoader' ) . addClass ( 'd-none' ) ;
for ( let i = 0 ; i < res . length ; i ++ ) {
this . replies . unshift ( res [ i ] ) ;
}
this . pagination = response . data . meta . pagination ;
$ ( '.load-more-link' ) . removeClass ( 'd-none' ) ;
} ) ;
}
} ,
@ -1935,3 +2147,129 @@
}
}
< / script >
< style type = "text/css" scoped >
. postPresenterContainer {
display : flex ;
align - items : center ;
background : # fff ;
}
. word - break {
word - break : break - all ;
}
. small . custom - control - label {
padding - top : 3 px ;
}
/ * . r e p l y - b t n {
position : absolute ;
bottom : 30 px ;
right : 20 px ;
width : 60 px ;
text - align : center ;
font - size : 13 px ;
border - radius : 0 3 px 3 px 0 ;
} * /
. emoji - reactions . nav - item {
font - size : 1.2 rem ;
padding : 9 px ;
cursor : pointer ;
}
. emoji - reactions : : - webkit - scrollbar {
width : 0 px ;
height : 0 px ;
background : transparent ;
}
. reply - btn [ disabled ] {
opacity : .3 ;
color : # 3897 f0 ;
}
. replyModalTextarea {
border : none ;
font - size : 18 px ;
resize : none ;
white - space : pre - wrap ;
outline : none ;
}
. has - story {
width : 64 px ;
height : 64 px ;
border - radius : 50 % ;
padding : 2 px ;
background : radial - gradient ( ellipse at 70 % 70 % , # ee583f 8 % , # d92d77 42 % , # bd3381 58 % ) ;
}
. has - story img {
width : 60 px ;
height : 60 px ;
border - radius : 50 % ;
padding : 3 px ;
background : # fff ;
}
. has - story . has - story - sm {
width : 32 px ;
height : 32 px ;
border - radius : 50 % ;
padding : 2 px ;
background : radial - gradient ( ellipse at 70 % 70 % , # ee583f 8 % , # d92d77 42 % , # bd3381 58 % ) ;
}
. has - story . has - story - sm img {
width : 28 px ;
height : 28 px ;
border - radius : 50 % ;
padding : 3 px ;
background : # fff ;
}
# ctx - reply - modal . form - control : focus {
border : none ;
outline : 0 ;
box - shadow : none ;
}
< / style >
< style type = "text/css" >
. tribute - container {
position : absolute ;
top : 0 ;
left : 0 ;
height : auto ;
max - height : 300 px ;
min - width : 120 px ;
max - width : 100 vw ;
overflow : auto ;
display : block ;
z - index : 999999 ;
border : 1 px solid # ccc ;
border - radius : 4 px ;
box - shadow : 0 1 px 4 px rgba ( # 000 , 0.13 ) ;
}
. tribute - container ul {
margin : 0 ;
margin - top : 2 px ;
padding : 0 ;
list - style : none ;
background : # fff ;
border - radius : 4 px ;
border : 1 px solid rgba ( # 000 , 0.13 ) ;
background - clip : padding - box ;
overflow : hidden ;
}
. tribute - container li {
color : # 000 ;
padding : 5 px 15 px ;
cursor : pointer ;
font - size : 14 px ;
overflow - x : hidden ! important ;
}
. tribute - container li . highlight ,
. tribute - container li : hover {
background : # 2 c78bf ;
color : # fff ;
}
. tribute - container li span {
font - weight : bold ;
}
. tribute - container li . no - match {
cursor : default ;
}
. tribute - container . menu - highlighted {
font - weight : bold ;
}
< / style >