aboutsummaryrefslogtreecommitdiffhomepage
path: root/client/src
diff options
context:
space:
mode:
Diffstat (limited to 'client/src')
-rw-r--r--client/src/app/videos/+video-watch/comment/video-comment.component.html47
-rw-r--r--client/src/app/videos/+video-watch/comment/video-comment.component.scss11
-rw-r--r--client/src/app/videos/+video-watch/comment/video-comment.component.ts2
-rw-r--r--client/src/app/videos/+video-watch/comment/video-comment.model.ts16
-rw-r--r--client/src/app/videos/+video-watch/comment/video-comments.component.ts35
5 files changed, 62 insertions, 49 deletions
diff --git a/client/src/app/videos/+video-watch/comment/video-comment.component.html b/client/src/app/videos/+video-watch/comment/video-comment.component.html
index 60b803206..6ec35d63b 100644
--- a/client/src/app/videos/+video-watch/comment/video-comment.component.html
+++ b/client/src/app/videos/+video-watch/comment/video-comment.component.html
@@ -1,22 +1,45 @@
1<div class="root-comment"> 1<div class="root-comment">
2 <img [src]="comment.accountAvatarUrl" alt="Avatar" /> 2 <img
3 *ngIf="!comment.isDeleted"
4 class="comment-avatar"
5 [src]="comment.accountAvatarUrl"
6 alt="Avatar"
7 />
8
9 <span
10 *ngIf="comment.isDeleted"
11 class="comment-avatar"
12 ></span>
3 13
4 <div class="comment"> 14 <div class="comment">
5 <div *ngIf="highlightedComment === true" class="highlighted-comment" i18n>Highlighted comment</div> 15 <ng-container *ngIf="!comment.isDeleted">
16 <div *ngIf="highlightedComment === true" class="highlighted-comment" i18n>Highlighted comment</div>
6 17
7 <div class="comment-account-date"> 18 <div class="comment-account-date">
8 <a [href]="comment.account.url" target="_blank" rel="noopener noreferrer" class="comment-account">{{ comment.by }}</a> 19 <a [href]="comment.account.url" target="_blank" rel="noopener noreferrer" class="comment-account">{{ comment.by }}</a>
9 <a [routerLink]="['/videos/watch', video.uuid, { 'threadId': comment.threadId }]" class="comment-date">{{ comment.createdAt | myFromNow }}</a> 20 <a [routerLink]="['/videos/watch', video.uuid, { 'threadId': comment.threadId }]" class="comment-date">{{ comment.createdAt | myFromNow }}</a>
10 </div> 21 </div>
11 <div class="comment-html" [innerHTML]="sanitizedCommentHTML"></div> 22 <div class="comment-html" [innerHTML]="sanitizedCommentHTML"></div>
12 23
13 <div class="comment-actions"> 24 <div class="comment-actions">
14 <div *ngIf="isUserLoggedIn()" (click)="onWantToReply()" class="comment-action-reply" i18n>Reply</div> 25 <div *ngIf="isUserLoggedIn()" (click)="onWantToReply()" class="comment-action-reply" i18n>Reply</div>
15 <div *ngIf="isRemovableByUser()" (click)="onWantToDelete()" class="comment-action-delete" i18n>Delete</div> 26 <div *ngIf="isRemovableByUser()" (click)="onWantToDelete()" class="comment-action-delete" i18n>Delete</div>
16 </div> 27 </div>
28 </ng-container>
29
30 <ng-container *ngIf="comment.isDeleted">
31 <div class="comment-account-date">
32 <span class="comment-account" i18n>Deleted</span>
33 <a [routerLink]="['/videos/watch', video.uuid, { 'threadId': comment.threadId }]" class="comment-date">{{ comment.createdAt | myFromNow }}</a>
34 </div>
35
36 <div *ngIf="comment.isDeleted" class="comment-html comment-html-deleted">
37 <i i18n>This comment has been deleted</i>
38 </div>
39 </ng-container>
17 40
18 <my-video-comment-add 41 <my-video-comment-add
19 *ngIf="isUserLoggedIn() && inReplyToCommentId === comment.id" 42 *ngIf="!comment.isDeleted && isUserLoggedIn() && inReplyToCommentId === comment.id"
20 [user]="user" 43 [user]="user"
21 [video]="video" 44 [video]="video"
22 [parentComment]="comment" 45 [parentComment]="comment"
diff --git a/client/src/app/videos/+video-watch/comment/video-comment.component.scss b/client/src/app/videos/+video-watch/comment/video-comment.component.scss
index c3ab1ab01..ac633fd64 100644
--- a/client/src/app/videos/+video-watch/comment/video-comment.component.scss
+++ b/client/src/app/videos/+video-watch/comment/video-comment.component.scss
@@ -5,7 +5,7 @@
5 font-size: 15px; 5 font-size: 15px;
6 display: flex; 6 display: flex;
7 7
8 img { 8 .comment-avatar {
9 @include avatar(36px); 9 @include avatar(36px);
10 10
11 margin-top: 5px; 11 margin-top: 5px;
@@ -48,6 +48,7 @@
48 48
49 .comment-html { 49 .comment-html {
50 @include peertube-word-wrap; 50 @include peertube-word-wrap;
51 margin-bottom: 10px;
51 52
52 // Mentions 53 // Mentions
53 ::ng-deep a { 54 ::ng-deep a {
@@ -61,10 +62,14 @@
61 } 62 }
62 63
63 } 64 }
65
66 &.comment-html-deleted {
67 color: $grey-foreground-color;
68 }
64 } 69 }
65 70
66 .comment-actions { 71 .comment-actions {
67 margin: 10px 0; 72 margin-bottom: 10px;
68 display: flex; 73 display: flex;
69 74
70 .comment-action-reply, 75 .comment-action-reply,
@@ -100,7 +105,7 @@
100 } 105 }
101 106
102 .root-comment { 107 .root-comment {
103 img { margin-right: 10px; } 108 .comment-avatar { margin-right: 10px; }
104 } 109 }
105} 110}
106 111
diff --git a/client/src/app/videos/+video-watch/comment/video-comment.component.ts b/client/src/app/videos/+video-watch/comment/video-comment.component.ts
index 172eb0a39..4d3c049a1 100644
--- a/client/src/app/videos/+video-watch/comment/video-comment.component.ts
+++ b/client/src/app/videos/+video-watch/comment/video-comment.component.ts
@@ -78,7 +78,7 @@ export class VideoCommentComponent implements OnInit, OnChanges {
78 } 78 }
79 79
80 isRemovableByUser () { 80 isRemovableByUser () {
81 return this.isUserLoggedIn() && 81 return this.comment.account && this.isUserLoggedIn() &&
82 ( 82 (
83 this.user.account.id === this.comment.account.id || 83 this.user.account.id === this.comment.account.id ||
84 this.user.hasRight(UserRight.REMOVE_ANY_VIDEO_COMMENT) 84 this.user.hasRight(UserRight.REMOVE_ANY_VIDEO_COMMENT)
diff --git a/client/src/app/videos/+video-watch/comment/video-comment.model.ts b/client/src/app/videos/+video-watch/comment/video-comment.model.ts
index 3ed3ddcc7..719d1f04e 100644
--- a/client/src/app/videos/+video-watch/comment/video-comment.model.ts
+++ b/client/src/app/videos/+video-watch/comment/video-comment.model.ts
@@ -12,6 +12,8 @@ export class VideoComment implements VideoCommentServerModel {
12 videoId: number 12 videoId: number
13 createdAt: Date | string 13 createdAt: Date | string
14 updatedAt: Date | string 14 updatedAt: Date | string
15 deletedAt: Date | string
16 isDeleted: boolean
15 account: AccountInterface 17 account: AccountInterface
16 totalReplies: number 18 totalReplies: number
17 by: string 19 by: string
@@ -28,14 +30,18 @@ export class VideoComment implements VideoCommentServerModel {
28 this.videoId = hash.videoId 30 this.videoId = hash.videoId
29 this.createdAt = new Date(hash.createdAt.toString()) 31 this.createdAt = new Date(hash.createdAt.toString())
30 this.updatedAt = new Date(hash.updatedAt.toString()) 32 this.updatedAt = new Date(hash.updatedAt.toString())
33 this.deletedAt = hash.deletedAt ? new Date(hash.deletedAt.toString()) : null
34 this.isDeleted = hash.isDeleted
31 this.account = hash.account 35 this.account = hash.account
32 this.totalReplies = hash.totalReplies 36 this.totalReplies = hash.totalReplies
33 37
34 this.by = Actor.CREATE_BY_STRING(this.account.name, this.account.host) 38 if (this.account) {
35 this.accountAvatarUrl = Actor.GET_ACTOR_AVATAR_URL(this.account) 39 this.by = Actor.CREATE_BY_STRING(this.account.name, this.account.host)
40 this.accountAvatarUrl = Actor.GET_ACTOR_AVATAR_URL(this.account)
36 41
37 const absoluteAPIUrl = getAbsoluteAPIUrl() 42 const absoluteAPIUrl = getAbsoluteAPIUrl()
38 const thisHost = new URL(absoluteAPIUrl).host 43 const thisHost = new URL(absoluteAPIUrl).host
39 this.isLocal = this.account.host.trim() === thisHost 44 this.isLocal = this.account.host.trim() === thisHost
45 }
40 } 46 }
41} 47}
diff --git a/client/src/app/videos/+video-watch/comment/video-comments.component.ts b/client/src/app/videos/+video-watch/comment/video-comments.component.ts
index 57b98afce..cc8b98b4e 100644
--- a/client/src/app/videos/+video-watch/comment/video-comments.component.ts
+++ b/client/src/app/videos/+video-watch/comment/video-comments.component.ts
@@ -153,10 +153,6 @@ export class VideoCommentsComponent implements OnInit, OnChanges, OnDestroy {
153 async onWantedToDelete (commentToDelete: VideoComment) { 153 async onWantedToDelete (commentToDelete: VideoComment) {
154 let message = 'Do you really want to delete this comment?' 154 let message = 'Do you really want to delete this comment?'
155 155
156 if (commentToDelete.totalReplies !== 0) {
157 message += this.i18n(' {{totalReplies}} replies will be deleted too.', { totalReplies: commentToDelete.totalReplies })
158 }
159
160 if (commentToDelete.isLocal) { 156 if (commentToDelete.isLocal) {
161 message += this.i18n(' The deletion will be sent to remote instances, so they remove the comment too.') 157 message += this.i18n(' The deletion will be sent to remote instances, so they remove the comment too.')
162 } else { 158 } else {
@@ -169,21 +165,8 @@ export class VideoCommentsComponent implements OnInit, OnChanges, OnDestroy {
169 this.videoCommentService.deleteVideoComment(commentToDelete.videoId, commentToDelete.id) 165 this.videoCommentService.deleteVideoComment(commentToDelete.videoId, commentToDelete.id)
170 .subscribe( 166 .subscribe(
171 () => { 167 () => {
172 // Delete the comment in the tree 168 // Mark the comment as deleted
173 if (commentToDelete.inReplyToCommentId) { 169 this.softDeleteComment(commentToDelete)
174 const thread = this.threadComments[commentToDelete.threadId]
175 if (!thread) {
176 console.error(`Cannot find thread ${commentToDelete.threadId} of the comment to delete ${commentToDelete.id}`)
177 return
178 }
179
180 this.deleteLocalCommentThread(thread, commentToDelete)
181 return
182 }
183
184 // Delete the thread
185 this.comments = this.comments.filter(c => c.id !== commentToDelete.id)
186 this.componentPagination.totalItems--
187 170
188 if (this.highlightedThread.id === commentToDelete.id) this.highlightedThread = undefined 171 if (this.highlightedThread.id === commentToDelete.id) this.highlightedThread = undefined
189 }, 172 },
@@ -204,15 +187,11 @@ export class VideoCommentsComponent implements OnInit, OnChanges, OnDestroy {
204 } 187 }
205 } 188 }
206 189
207 private deleteLocalCommentThread (parentComment: VideoCommentThreadTree, commentToDelete: VideoComment) { 190 private softDeleteComment (comment: VideoComment) {
208 for (const commentChild of parentComment.children) { 191 comment.isDeleted = true
209 if (commentChild.comment.id === commentToDelete.id) { 192 comment.deletedAt = new Date()
210 parentComment.children = parentComment.children.filter(c => c.comment.id !== commentToDelete.id) 193 comment.text = ''
211 return 194 comment.account = null
212 }
213
214 this.deleteLocalCommentThread(commentChild, commentToDelete)
215 }
216 } 195 }
217 196
218 private resetVideo () { 197 private resetVideo () {