Add delete & re-draft for comments without replies
This commit is contained in:
parent
09f8f73fbc
commit
f63c03fb6e
|
@ -22,6 +22,7 @@ form {
|
||||||
|
|
||||||
textarea {
|
textarea {
|
||||||
@include peertube-textarea(100%, 60px);
|
@include peertube-textarea(100%, 60px);
|
||||||
|
@include button-focus(pvar(--mainColorLightest));
|
||||||
|
|
||||||
&:focus::placeholder {
|
&:focus::placeholder {
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { Observable } from 'rxjs'
|
import { Observable } from 'rxjs'
|
||||||
import { Component, ElementRef, EventEmitter, Input, OnInit, Output, ViewChild } from '@angular/core'
|
import { Component, ElementRef, EventEmitter, Input, OnChanges, OnInit, Output, SimpleChanges, ViewChild } from '@angular/core'
|
||||||
import { Router } from '@angular/router'
|
import { Router } from '@angular/router'
|
||||||
import { Notifier, User } from '@app/core'
|
import { Notifier, User } from '@app/core'
|
||||||
import { FormReactive, FormValidatorService, VideoCommentValidatorsService } from '@app/shared/shared-forms'
|
import { FormReactive, FormValidatorService, VideoCommentValidatorsService } from '@app/shared/shared-forms'
|
||||||
|
@ -13,12 +13,13 @@ import { VideoCommentCreate } from '@shared/models'
|
||||||
templateUrl: './video-comment-add.component.html',
|
templateUrl: './video-comment-add.component.html',
|
||||||
styleUrls: ['./video-comment-add.component.scss']
|
styleUrls: ['./video-comment-add.component.scss']
|
||||||
})
|
})
|
||||||
export class VideoCommentAddComponent extends FormReactive implements OnInit {
|
export class VideoCommentAddComponent extends FormReactive implements OnChanges, OnInit {
|
||||||
@Input() user: User
|
@Input() user: User
|
||||||
@Input() video: Video
|
@Input() video: Video
|
||||||
@Input() parentComment: VideoComment
|
@Input() parentComment: VideoComment
|
||||||
@Input() parentComments: VideoComment[]
|
@Input() parentComments: VideoComment[]
|
||||||
@Input() focusOnInit = false
|
@Input() focusOnInit = false
|
||||||
|
@Input() textValue?: string
|
||||||
|
|
||||||
@Output() commentCreated = new EventEmitter<VideoComment>()
|
@Output() commentCreated = new EventEmitter<VideoComment>()
|
||||||
@Output() cancel = new EventEmitter()
|
@Output() cancel = new EventEmitter()
|
||||||
|
@ -45,8 +46,9 @@ export class VideoCommentAddComponent extends FormReactive implements OnInit {
|
||||||
})
|
})
|
||||||
|
|
||||||
if (this.user) {
|
if (this.user) {
|
||||||
if (this.focusOnInit === true) {
|
if (this.textValue) {
|
||||||
this.textareaElement.nativeElement.focus()
|
this.patchTextValue(this.textValue, this.focusOnInit)
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.parentComment) {
|
if (this.parentComment) {
|
||||||
|
@ -57,11 +59,17 @@ export class VideoCommentAddComponent extends FormReactive implements OnInit {
|
||||||
const mentionsSet = new Set(mentions)
|
const mentionsSet = new Set(mentions)
|
||||||
const mentionsText = Array.from(mentionsSet).join(' ') + ' '
|
const mentionsText = Array.from(mentionsSet).join(' ') + ' '
|
||||||
|
|
||||||
this.form.patchValue({ text: mentionsText })
|
this.patchTextValue(mentionsText, this.focusOnInit)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ngOnChanges (changes: SimpleChanges) {
|
||||||
|
if (changes.textValue && changes.textValue.currentValue && changes.textValue.currentValue !== changes.textValue.previousValue) {
|
||||||
|
this.patchTextValue(changes.textValue.currentValue, true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
onValidKey () {
|
onValidKey () {
|
||||||
this.check()
|
this.check()
|
||||||
if (!this.form.valid) return
|
if (!this.form.valid) return
|
||||||
|
@ -145,4 +153,16 @@ export class VideoCommentAddComponent extends FormReactive implements OnInit {
|
||||||
return this.videoCommentService
|
return this.videoCommentService
|
||||||
.addCommentThread(this.video.id, commentCreate)
|
.addCommentThread(this.video.id, commentCreate)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private patchTextValue (text: string, focus: boolean) {
|
||||||
|
setTimeout(() => {
|
||||||
|
if (focus) {
|
||||||
|
this.textareaElement.nativeElement.focus()
|
||||||
|
}
|
||||||
|
|
||||||
|
this.textareaElement.nativeElement.scrollIntoView({ behavior: 'smooth', block: 'center', inline: 'nearest' })
|
||||||
|
})
|
||||||
|
|
||||||
|
this.form.patchValue({ text })
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -43,6 +43,7 @@
|
||||||
<div class="comment-actions">
|
<div class="comment-actions">
|
||||||
<div *ngIf="isUserLoggedIn()" (click)="onWantToReply()" class="comment-action-reply" i18n>Reply</div>
|
<div *ngIf="isUserLoggedIn()" (click)="onWantToReply()" class="comment-action-reply" i18n>Reply</div>
|
||||||
<div *ngIf="isRemovableByUser()" (click)="onWantToDelete()" class="comment-action-delete" i18n>Delete</div>
|
<div *ngIf="isRemovableByUser()" (click)="onWantToDelete()" class="comment-action-delete" i18n>Delete</div>
|
||||||
|
<div *ngIf="isRedraftableByUser()" (click)="onWantToRedraft()" class="comment-action-redraft" i18n>Delete & re-draft</div>
|
||||||
|
|
||||||
<my-user-moderation-dropdown
|
<my-user-moderation-dropdown
|
||||||
[prependActions]="prependModerationActions"
|
[prependActions]="prependModerationActions"
|
||||||
|
@ -72,6 +73,7 @@
|
||||||
[focusOnInit]="true"
|
[focusOnInit]="true"
|
||||||
(commentCreated)="onCommentReplyCreated($event)"
|
(commentCreated)="onCommentReplyCreated($event)"
|
||||||
(cancel)="onResetReply()"
|
(cancel)="onResetReply()"
|
||||||
|
[textValue]="redraftValue"
|
||||||
></my-video-comment-add>
|
></my-video-comment-add>
|
||||||
|
|
||||||
<div *ngIf="commentTree" class="children">
|
<div *ngIf="commentTree" class="children">
|
||||||
|
@ -84,8 +86,10 @@
|
||||||
[parentComments]="newParentComments"
|
[parentComments]="newParentComments"
|
||||||
(wantedToReply)="onWantToReply($event)"
|
(wantedToReply)="onWantToReply($event)"
|
||||||
(wantedToDelete)="onWantToDelete($event)"
|
(wantedToDelete)="onWantToDelete($event)"
|
||||||
|
(wantedToRedraft)="onWantToRedraft($event)"
|
||||||
(resetReply)="onResetReply()"
|
(resetReply)="onResetReply()"
|
||||||
(timestampClicked)="handleTimestampClicked($event)"
|
(timestampClicked)="handleTimestampClicked($event)"
|
||||||
|
[redraftValue]="redraftValue"
|
||||||
></my-video-comment>
|
></my-video-comment>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -119,7 +119,8 @@
|
||||||
|
|
||||||
::ng-deep .dropdown-toggle,
|
::ng-deep .dropdown-toggle,
|
||||||
.comment-action-reply,
|
.comment-action-reply,
|
||||||
.comment-action-delete {
|
.comment-action-delete,
|
||||||
|
.comment-action-redraft {
|
||||||
color: pvar(--greyForegroundColor);
|
color: pvar(--greyForegroundColor);
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
margin-right: 10px;
|
margin-right: 10px;
|
||||||
|
|
|
@ -22,9 +22,11 @@ export class VideoCommentComponent implements OnInit, OnChanges {
|
||||||
@Input() inReplyToCommentId: number
|
@Input() inReplyToCommentId: number
|
||||||
@Input() highlightedComment = false
|
@Input() highlightedComment = false
|
||||||
@Input() firstInThread = false
|
@Input() firstInThread = false
|
||||||
|
@Input() redraftValue?: string
|
||||||
|
|
||||||
@Output() wantedToDelete = new EventEmitter<VideoComment>()
|
|
||||||
@Output() wantedToReply = new EventEmitter<VideoComment>()
|
@Output() wantedToReply = new EventEmitter<VideoComment>()
|
||||||
|
@Output() wantedToDelete = new EventEmitter<VideoComment>()
|
||||||
|
@Output() wantedToRedraft = new EventEmitter<VideoComment>()
|
||||||
@Output() threadCreated = new EventEmitter<VideoCommentThreadTree>()
|
@Output() threadCreated = new EventEmitter<VideoCommentThreadTree>()
|
||||||
@Output() resetReply = new EventEmitter()
|
@Output() resetReply = new EventEmitter()
|
||||||
@Output() timestampClicked = new EventEmitter<number>()
|
@Output() timestampClicked = new EventEmitter<number>()
|
||||||
|
@ -70,7 +72,10 @@ export class VideoCommentComponent implements OnInit, OnChanges {
|
||||||
comment: createdComment,
|
comment: createdComment,
|
||||||
children: []
|
children: []
|
||||||
})
|
})
|
||||||
|
|
||||||
this.resetReply.emit()
|
this.resetReply.emit()
|
||||||
|
|
||||||
|
delete this.redraftValue
|
||||||
}
|
}
|
||||||
|
|
||||||
onWantToReply (comment?: VideoComment) {
|
onWantToReply (comment?: VideoComment) {
|
||||||
|
@ -81,6 +86,10 @@ export class VideoCommentComponent implements OnInit, OnChanges {
|
||||||
this.wantedToDelete.emit(comment || this.comment)
|
this.wantedToDelete.emit(comment || this.comment)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
onWantToRedraft (comment?: VideoComment) {
|
||||||
|
this.wantedToRedraft.emit(comment || this.comment)
|
||||||
|
}
|
||||||
|
|
||||||
isUserLoggedIn () {
|
isUserLoggedIn () {
|
||||||
return this.authService.isLoggedIn()
|
return this.authService.isLoggedIn()
|
||||||
}
|
}
|
||||||
|
@ -102,6 +111,10 @@ export class VideoCommentComponent implements OnInit, OnChanges {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
isRedraftableByUser () {
|
||||||
|
return this.comment.account && this.isUserLoggedIn() && this.user.account.id === this.comment.account.id && this.comment.totalReplies === 0
|
||||||
|
}
|
||||||
|
|
||||||
switchToDefaultAvatar ($event: Event) {
|
switchToDefaultAvatar ($event: Event) {
|
||||||
($event.target as HTMLImageElement).src = Actor.GET_DEFAULT_AVATAR_URL()
|
($event.target as HTMLImageElement).src = Actor.GET_DEFAULT_AVATAR_URL()
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,6 +27,7 @@
|
||||||
[video]="video"
|
[video]="video"
|
||||||
[user]="user"
|
[user]="user"
|
||||||
(commentCreated)="onCommentThreadCreated($event)"
|
(commentCreated)="onCommentThreadCreated($event)"
|
||||||
|
[textValue]="commentThreadRedraftValue"
|
||||||
></my-video-comment-add>
|
></my-video-comment-add>
|
||||||
|
|
||||||
<div *ngIf="componentPagination.totalItems === 0 && comments.length === 0" i18n>No comments.</div>
|
<div *ngIf="componentPagination.totalItems === 0 && comments.length === 0" i18n>No comments.</div>
|
||||||
|
@ -50,9 +51,11 @@
|
||||||
[firstInThread]="true"
|
[firstInThread]="true"
|
||||||
(wantedToReply)="onWantedToReply($event)"
|
(wantedToReply)="onWantedToReply($event)"
|
||||||
(wantedToDelete)="onWantedToDelete($event)"
|
(wantedToDelete)="onWantedToDelete($event)"
|
||||||
|
(wantedToRedraft)="onWantedToRedraft($event)"
|
||||||
(threadCreated)="onThreadCreated($event)"
|
(threadCreated)="onThreadCreated($event)"
|
||||||
(resetReply)="onResetReply()"
|
(resetReply)="onResetReply()"
|
||||||
(timestampClicked)="handleTimestampClicked($event)"
|
(timestampClicked)="handleTimestampClicked($event)"
|
||||||
|
[redraftValue]="commentReplyRedraftValue"
|
||||||
></my-video-comment>
|
></my-video-comment>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -66,9 +69,11 @@
|
||||||
[firstInThread]="i + 1 !== comments.length"
|
[firstInThread]="i + 1 !== comments.length"
|
||||||
(wantedToReply)="onWantedToReply($event)"
|
(wantedToReply)="onWantedToReply($event)"
|
||||||
(wantedToDelete)="onWantedToDelete($event)"
|
(wantedToDelete)="onWantedToDelete($event)"
|
||||||
|
(wantedToRedraft)="onWantedToRedraft($event)"
|
||||||
(threadCreated)="onThreadCreated($event)"
|
(threadCreated)="onThreadCreated($event)"
|
||||||
(resetReply)="onResetReply()"
|
(resetReply)="onResetReply()"
|
||||||
(timestampClicked)="handleTimestampClicked($event)"
|
(timestampClicked)="handleTimestampClicked($event)"
|
||||||
|
[redraftValue]="commentReplyRedraftValue"
|
||||||
>
|
>
|
||||||
<div *ngIf="comment.totalReplies !== 0 && !threadComments[comment.id]" (click)="viewReplies(comment.id)" class="view-replies mb-2">
|
<div *ngIf="comment.totalReplies !== 0 && !threadComments[comment.id]" (click)="viewReplies(comment.id)" class="view-replies mb-2">
|
||||||
<span class="glyphicon glyphicon-menu-down"></span>
|
<span class="glyphicon glyphicon-menu-down"></span>
|
||||||
|
|
|
@ -27,6 +27,8 @@ export class VideoCommentsComponent implements OnInit, OnChanges, OnDestroy {
|
||||||
totalItems: null
|
totalItems: null
|
||||||
}
|
}
|
||||||
inReplyToCommentId: number
|
inReplyToCommentId: number
|
||||||
|
commentReplyRedraftValue: string
|
||||||
|
commentThreadRedraftValue: string
|
||||||
threadComments: { [ id: number ]: VideoCommentThreadTree } = {}
|
threadComments: { [ id: number ]: VideoCommentThreadTree } = {}
|
||||||
threadLoading: { [ id: number ]: boolean } = {}
|
threadLoading: { [ id: number ]: boolean } = {}
|
||||||
|
|
||||||
|
@ -131,6 +133,7 @@ export class VideoCommentsComponent implements OnInit, OnChanges, OnDestroy {
|
||||||
|
|
||||||
onCommentThreadCreated (comment: VideoComment) {
|
onCommentThreadCreated (comment: VideoComment) {
|
||||||
this.comments.unshift(comment)
|
this.comments.unshift(comment)
|
||||||
|
delete this.commentThreadRedraftValue
|
||||||
}
|
}
|
||||||
|
|
||||||
onWantedToReply (comment: VideoComment) {
|
onWantedToReply (comment: VideoComment) {
|
||||||
|
@ -139,6 +142,7 @@ export class VideoCommentsComponent implements OnInit, OnChanges, OnDestroy {
|
||||||
|
|
||||||
onResetReply () {
|
onResetReply () {
|
||||||
this.inReplyToCommentId = undefined
|
this.inReplyToCommentId = undefined
|
||||||
|
delete this.commentReplyRedraftValue
|
||||||
}
|
}
|
||||||
|
|
||||||
onThreadCreated (commentTree: VideoCommentThreadTree) {
|
onThreadCreated (commentTree: VideoCommentThreadTree) {
|
||||||
|
@ -156,9 +160,7 @@ export class VideoCommentsComponent implements OnInit, OnChanges, OnDestroy {
|
||||||
this.timestampClicked.emit(timestamp)
|
this.timestampClicked.emit(timestamp)
|
||||||
}
|
}
|
||||||
|
|
||||||
async onWantedToDelete (commentToDelete: VideoComment) {
|
async onWantedToDelete (commentToDelete: VideoComment, message = 'Do you really want to delete this comment?'): Promise<boolean> {
|
||||||
let message = 'Do you really want to delete this comment?'
|
|
||||||
|
|
||||||
if (commentToDelete.isLocal || this.video.isLocal) {
|
if (commentToDelete.isLocal || this.video.isLocal) {
|
||||||
message += $localize` The deletion will be sent to remote instances so they can reflect the change.`
|
message += $localize` The deletion will be sent to remote instances so they can reflect the change.`
|
||||||
} else {
|
} else {
|
||||||
|
@ -183,6 +185,23 @@ export class VideoCommentsComponent implements OnInit, OnChanges, OnDestroy {
|
||||||
|
|
||||||
err => this.notifier.error(err.message)
|
err => this.notifier.error(err.message)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
async onWantedToRedraft(commentToRedraft: VideoComment) {
|
||||||
|
const confirm = await this.onWantedToDelete(commentToRedraft, 'Do you really want to delete and re-draft this comment?')
|
||||||
|
|
||||||
|
if (confirm) {
|
||||||
|
this.inReplyToCommentId = commentToRedraft.inReplyToCommentId
|
||||||
|
|
||||||
|
if (commentToRedraft.threadId === commentToRedraft.id) {
|
||||||
|
this.commentThreadRedraftValue = commentToRedraft.text
|
||||||
|
} else {
|
||||||
|
this.commentReplyRedraftValue = commentToRedraft.text
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
isUserLoggedIn () {
|
isUserLoggedIn () {
|
||||||
|
|
Loading…
Reference in New Issue