]> git.immae.eu Git - github/Chocobozzz/PeerTube.git/blob - client/src/app/+videos/+video-watch/shared/comment/video-comment.component.ts
Migrate client to eslint
[github/Chocobozzz/PeerTube.git] / client / src / app / +videos / +video-watch / shared / comment / video-comment.component.ts
1
2 import { Component, EventEmitter, Input, OnChanges, OnInit, Output, ViewChild } from '@angular/core'
3 import { MarkdownService, Notifier, UserService } from '@app/core'
4 import { AuthService } from '@app/core/auth'
5 import { Account, DropdownAction, Video } from '@app/shared/shared-main'
6 import { CommentReportComponent } from '@app/shared/shared-moderation/report-modals/comment-report.component'
7 import { VideoComment, VideoCommentThreadTree } from '@app/shared/shared-video-comment'
8 import { User, UserRight } from '@shared/models'
9
10 @Component({
11 selector: 'my-video-comment',
12 templateUrl: './video-comment.component.html',
13 styleUrls: [ './video-comment.component.scss' ]
14 })
15 export class VideoCommentComponent implements OnInit, OnChanges {
16 @ViewChild('commentReportModal') commentReportModal: CommentReportComponent
17
18 @Input() video: Video
19 @Input() comment: VideoComment
20 @Input() parentComments: VideoComment[] = []
21 @Input() commentTree: VideoCommentThreadTree
22 @Input() inReplyToCommentId: number
23 @Input() highlightedComment = false
24 @Input() firstInThread = false
25 @Input() redraftValue?: string
26
27 @Output() wantedToReply = new EventEmitter<VideoComment>()
28 @Output() wantedToDelete = new EventEmitter<VideoComment>()
29 @Output() wantedToRedraft = new EventEmitter<VideoComment>()
30 @Output() threadCreated = new EventEmitter<VideoCommentThreadTree>()
31 @Output() resetReply = new EventEmitter()
32 @Output() timestampClicked = new EventEmitter<number>()
33
34 prependModerationActions: DropdownAction<any>[]
35
36 sanitizedCommentHTML = ''
37 newParentComments: VideoComment[] = []
38
39 commentAccount: Account
40 commentUser: User
41
42 constructor (
43 private markdownService: MarkdownService,
44 private authService: AuthService,
45 private userService: UserService,
46 private notifier: Notifier
47 ) {}
48
49 get user () {
50 return this.authService.getUser()
51 }
52
53 ngOnInit () {
54 this.init()
55 }
56
57 ngOnChanges () {
58 this.init()
59 }
60
61 onCommentReplyCreated (createdComment: VideoComment) {
62 if (!this.commentTree) {
63 this.commentTree = {
64 comment: this.comment,
65 hasDisplayedChildren: false,
66 children: []
67 }
68
69 this.threadCreated.emit(this.commentTree)
70 }
71
72 this.commentTree.children.unshift({
73 comment: createdComment,
74 hasDisplayedChildren: false,
75 children: []
76 })
77
78 this.resetReply.emit()
79
80 this.redraftValue = undefined
81 }
82
83 onWantToReply (comment?: VideoComment) {
84 this.wantedToReply.emit(comment || this.comment)
85 }
86
87 onWantToDelete (comment?: VideoComment) {
88 this.wantedToDelete.emit(comment || this.comment)
89 }
90
91 onWantToRedraft (comment?: VideoComment) {
92 this.wantedToRedraft.emit(comment || this.comment)
93 }
94
95 isUserLoggedIn () {
96 return this.authService.isLoggedIn()
97 }
98
99 onResetReply () {
100 this.resetReply.emit()
101 }
102
103 handleTimestampClicked (timestamp: number) {
104 this.timestampClicked.emit(timestamp)
105 }
106
107 isRemovableByUser () {
108 return this.comment.account && this.isUserLoggedIn() &&
109 (
110 this.user.account.id === this.comment.account.id ||
111 this.user.account.id === this.video.account.id ||
112 this.user.hasRight(UserRight.REMOVE_ANY_VIDEO_COMMENT)
113 )
114 }
115
116 isRedraftableByUser () {
117 return (
118 this.comment.account &&
119 this.isUserLoggedIn() &&
120 this.user.account.id === this.comment.account.id &&
121 this.comment.totalReplies === 0
122 )
123 }
124
125 isReportableByUser () {
126 return (
127 this.comment.account &&
128 this.isUserLoggedIn() &&
129 this.comment.isDeleted === false &&
130 this.user.account.id !== this.comment.account.id
131 )
132 }
133
134 isCommentDisplayed () {
135 // Not deleted
136 return !this.comment.isDeleted ||
137 this.comment.totalReplies !== 0 || // Or root comment thread has replies
138 (this.commentTree?.hasDisplayedChildren) // Or this is a reply that have other replies
139 }
140
141 isChild () {
142 return this.parentComments.length !== 0
143 }
144
145 private getUserIfNeeded (account: Account) {
146 if (!account.userId) return
147 if (!this.authService.isLoggedIn()) return
148
149 const user = this.authService.getUser()
150 if (user.hasRight(UserRight.MANAGE_USERS)) {
151 this.userService.getUserWithCache(account.userId)
152 .subscribe({
153 next: user => this.commentUser = user,
154
155 error: err => this.notifier.error(err.message)
156 })
157 }
158 }
159
160 private async init () {
161 // Before HTML rendering restore line feed for markdown list compatibility
162 const commentText = this.comment.text.replace(/<br.?\/?>/g, '\r\n')
163 const html = await this.markdownService.textMarkdownToHTML(commentText, true, true)
164 this.sanitizedCommentHTML = this.markdownService.processVideoTimestamps(this.video.shortUUID, html)
165 this.newParentComments = this.parentComments.concat([ this.comment ])
166
167 if (this.comment.account) {
168 this.commentAccount = new Account(this.comment.account)
169 this.getUserIfNeeded(this.commentAccount)
170 } else {
171 this.comment.account = null
172 }
173
174 this.prependModerationActions = []
175
176 if (this.isReportableByUser()) {
177 this.prependModerationActions.push({
178 label: $localize`Report this comment`,
179 iconName: 'flag',
180 handler: () => this.showReportModal()
181 })
182 }
183
184 if (this.isRemovableByUser()) {
185 this.prependModerationActions.push({
186 label: $localize`Remove`,
187 iconName: 'delete',
188 handler: () => this.onWantToDelete()
189 })
190 }
191
192 if (this.isRedraftableByUser()) {
193 this.prependModerationActions.push({
194 label: $localize`Remove & re-draft`,
195 iconName: 'edit',
196 handler: () => this.onWantToRedraft()
197 })
198 }
199
200 if (this.prependModerationActions.length === 0) {
201 this.prependModerationActions = undefined
202 }
203 }
204
205 private showReportModal () {
206 this.commentReportModal.show()
207 }
208 }