Add delete & re-draft for comments without replies

pull/3085/head
kimsible 2020-08-07 14:03:28 +02:00 committed by Chocobozzz
parent 09f8f73fbc
commit f63c03fb6e
7 changed files with 73 additions and 10 deletions

View File

@ -22,6 +22,7 @@ form {
textarea {
@include peertube-textarea(100%, 60px);
@include button-focus(pvar(--mainColorLightest));
&:focus::placeholder {
opacity: 0;

View File

@ -1,5 +1,5 @@
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 { Notifier, User } from '@app/core'
import { FormReactive, FormValidatorService, VideoCommentValidatorsService } from '@app/shared/shared-forms'
@ -13,12 +13,13 @@ import { VideoCommentCreate } from '@shared/models'
templateUrl: './video-comment-add.component.html',
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() video: Video
@Input() parentComment: VideoComment
@Input() parentComments: VideoComment[]
@Input() focusOnInit = false
@Input() textValue?: string
@Output() commentCreated = new EventEmitter<VideoComment>()
@Output() cancel = new EventEmitter()
@ -45,8 +46,9 @@ export class VideoCommentAddComponent extends FormReactive implements OnInit {
})
if (this.user) {
if (this.focusOnInit === true) {
this.textareaElement.nativeElement.focus()
if (this.textValue) {
this.patchTextValue(this.textValue, this.focusOnInit)
return
}
if (this.parentComment) {
@ -57,11 +59,17 @@ export class VideoCommentAddComponent extends FormReactive implements OnInit {
const mentionsSet = new Set(mentions)
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 () {
this.check()
if (!this.form.valid) return
@ -145,4 +153,16 @@ export class VideoCommentAddComponent extends FormReactive implements OnInit {
return this.videoCommentService
.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 })
}
}

View File

@ -43,6 +43,7 @@
<div class="comment-actions">
<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="isRedraftableByUser()" (click)="onWantToRedraft()" class="comment-action-redraft" i18n>Delete & re-draft</div>
<my-user-moderation-dropdown
[prependActions]="prependModerationActions"
@ -72,6 +73,7 @@
[focusOnInit]="true"
(commentCreated)="onCommentReplyCreated($event)"
(cancel)="onResetReply()"
[textValue]="redraftValue"
></my-video-comment-add>
<div *ngIf="commentTree" class="children">
@ -84,8 +86,10 @@
[parentComments]="newParentComments"
(wantedToReply)="onWantToReply($event)"
(wantedToDelete)="onWantToDelete($event)"
(wantedToRedraft)="onWantToRedraft($event)"
(resetReply)="onResetReply()"
(timestampClicked)="handleTimestampClicked($event)"
[redraftValue]="redraftValue"
></my-video-comment>
</div>
</div>

View File

@ -119,7 +119,8 @@
::ng-deep .dropdown-toggle,
.comment-action-reply,
.comment-action-delete {
.comment-action-delete,
.comment-action-redraft {
color: pvar(--greyForegroundColor);
cursor: pointer;
margin-right: 10px;

View File

@ -22,9 +22,11 @@ export class VideoCommentComponent implements OnInit, OnChanges {
@Input() inReplyToCommentId: number
@Input() highlightedComment = false
@Input() firstInThread = false
@Input() redraftValue?: string
@Output() wantedToDelete = new EventEmitter<VideoComment>()
@Output() wantedToReply = new EventEmitter<VideoComment>()
@Output() wantedToDelete = new EventEmitter<VideoComment>()
@Output() wantedToRedraft = new EventEmitter<VideoComment>()
@Output() threadCreated = new EventEmitter<VideoCommentThreadTree>()
@Output() resetReply = new EventEmitter()
@Output() timestampClicked = new EventEmitter<number>()
@ -70,7 +72,10 @@ export class VideoCommentComponent implements OnInit, OnChanges {
comment: createdComment,
children: []
})
this.resetReply.emit()
delete this.redraftValue
}
onWantToReply (comment?: VideoComment) {
@ -81,6 +86,10 @@ export class VideoCommentComponent implements OnInit, OnChanges {
this.wantedToDelete.emit(comment || this.comment)
}
onWantToRedraft (comment?: VideoComment) {
this.wantedToRedraft.emit(comment || this.comment)
}
isUserLoggedIn () {
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) {
($event.target as HTMLImageElement).src = Actor.GET_DEFAULT_AVATAR_URL()
}

View File

@ -27,6 +27,7 @@
[video]="video"
[user]="user"
(commentCreated)="onCommentThreadCreated($event)"
[textValue]="commentThreadRedraftValue"
></my-video-comment-add>
<div *ngIf="componentPagination.totalItems === 0 && comments.length === 0" i18n>No comments.</div>
@ -50,9 +51,11 @@
[firstInThread]="true"
(wantedToReply)="onWantedToReply($event)"
(wantedToDelete)="onWantedToDelete($event)"
(wantedToRedraft)="onWantedToRedraft($event)"
(threadCreated)="onThreadCreated($event)"
(resetReply)="onResetReply()"
(timestampClicked)="handleTimestampClicked($event)"
[redraftValue]="commentReplyRedraftValue"
></my-video-comment>
</div>
@ -66,9 +69,11 @@
[firstInThread]="i + 1 !== comments.length"
(wantedToReply)="onWantedToReply($event)"
(wantedToDelete)="onWantedToDelete($event)"
(wantedToRedraft)="onWantedToRedraft($event)"
(threadCreated)="onThreadCreated($event)"
(resetReply)="onResetReply()"
(timestampClicked)="handleTimestampClicked($event)"
[redraftValue]="commentReplyRedraftValue"
>
<div *ngIf="comment.totalReplies !== 0 && !threadComments[comment.id]" (click)="viewReplies(comment.id)" class="view-replies mb-2">
<span class="glyphicon glyphicon-menu-down"></span>

View File

@ -27,6 +27,8 @@ export class VideoCommentsComponent implements OnInit, OnChanges, OnDestroy {
totalItems: null
}
inReplyToCommentId: number
commentReplyRedraftValue: string
commentThreadRedraftValue: string
threadComments: { [ id: number ]: VideoCommentThreadTree } = {}
threadLoading: { [ id: number ]: boolean } = {}
@ -131,6 +133,7 @@ export class VideoCommentsComponent implements OnInit, OnChanges, OnDestroy {
onCommentThreadCreated (comment: VideoComment) {
this.comments.unshift(comment)
delete this.commentThreadRedraftValue
}
onWantedToReply (comment: VideoComment) {
@ -139,6 +142,7 @@ export class VideoCommentsComponent implements OnInit, OnChanges, OnDestroy {
onResetReply () {
this.inReplyToCommentId = undefined
delete this.commentReplyRedraftValue
}
onThreadCreated (commentTree: VideoCommentThreadTree) {
@ -156,9 +160,7 @@ export class VideoCommentsComponent implements OnInit, OnChanges, OnDestroy {
this.timestampClicked.emit(timestamp)
}
async onWantedToDelete (commentToDelete: VideoComment) {
let message = 'Do you really want to delete this comment?'
async onWantedToDelete (commentToDelete: VideoComment, message = 'Do you really want to delete this comment?'): Promise<boolean> {
if (commentToDelete.isLocal || this.video.isLocal) {
message += $localize` The deletion will be sent to remote instances so they can reflect the change.`
} else {
@ -183,6 +185,23 @@ export class VideoCommentsComponent implements OnInit, OnChanges, OnDestroy {
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 () {