]> git.immae.eu Git - github/Chocobozzz/PeerTube.git/blob - client/src/app/videos/+video-watch/comment/video-comments.component.ts
7970a5dcfd7f39a2c8bbd3094e5ba056e8ddc2ce
[github/Chocobozzz/PeerTube.git] / client / src / app / videos / +video-watch / comment / video-comments.component.ts
1 import { Component, Input, OnChanges, SimpleChanges } from '@angular/core'
2 import { ConfirmService } from '@app/core'
3 import { NotificationsService } from 'angular2-notifications'
4 import { VideoComment as VideoCommentInterface, VideoCommentThreadTree } from '../../../../../../shared/models/videos/video-comment.model'
5 import { AuthService } from '../../../core/auth'
6 import { ComponentPagination } from '../../../shared/rest/component-pagination.model'
7 import { User } from '../../../shared/users'
8 import { SortField } from '../../../shared/video/sort-field.type'
9 import { VideoDetails } from '../../../shared/video/video-details.model'
10 import { VideoComment } from './video-comment.model'
11 import { VideoCommentService } from './video-comment.service'
12 import { ActivatedRoute } from '@angular/router'
13
14 @Component({
15 selector: 'my-video-comments',
16 templateUrl: './video-comments.component.html',
17 styleUrls: ['./video-comments.component.scss']
18 })
19 export class VideoCommentsComponent implements OnChanges {
20 @Input() video: VideoDetails
21 @Input() user: User
22
23 comments: VideoComment[] = []
24 sort: SortField = '-createdAt'
25 componentPagination: ComponentPagination = {
26 currentPage: 1,
27 itemsPerPage: 10,
28 totalItems: null
29 }
30 inReplyToCommentId: number
31 threadComments: { [ id: number ]: VideoCommentThreadTree } = {}
32 threadLoading: { [ id: number ]: boolean } = {}
33 markedCommentID: number
34
35 constructor (
36 private authService: AuthService,
37 private notificationsService: NotificationsService,
38 private confirmService: ConfirmService,
39 private videoCommentService: VideoCommentService,
40 private activatedRoute: ActivatedRoute
41 ) {}
42
43 ngOnChanges (changes: SimpleChanges) {
44 if (changes['video']) {
45 this.loadVideoComments()
46 }
47 }
48
49 viewReplies (comment: VideoCommentInterface) {
50 this.threadLoading[comment.id] = true
51
52 this.videoCommentService.getVideoThreadComments(this.video.id, comment.id)
53 .subscribe(
54 res => {
55 this.threadComments[comment.id] = res
56 this.threadLoading[comment.id] = false
57 },
58
59 err => this.notificationsService.error('Error', err.message)
60 )
61 }
62
63 loadMoreComments () {
64 this.videoCommentService.getVideoCommentThreads(this.video.id, this.componentPagination, this.sort)
65 .subscribe(
66 res => {
67 this.comments = this.comments.concat(res.comments)
68 this.componentPagination.totalItems = res.totalComments
69
70 if (this.markedCommentID) {
71 // If there is a marked comment, retrieve it separately as it may not be on this page, filter to prevent duplicate
72 this.comments = this.comments.filter(value => value.id !== this.markedCommentID)
73 this.videoCommentService.getVideoThreadComments(this.video.id, this.markedCommentID).subscribe(
74 res => {
75 let comment = new VideoComment(res.comment)
76 comment.marked = true
77 this.comments.unshift(comment) // Insert marked comment at the beginning
78 }
79 )
80 }
81 },
82
83 err => this.notificationsService.error('Error', err.message)
84 )
85 }
86
87 onCommentThreadCreated (comment: VideoComment) {
88 this.comments.unshift(comment)
89 }
90
91 onWantedToReply (comment: VideoComment) {
92 this.inReplyToCommentId = comment.id
93 }
94
95 onResetReply () {
96 this.inReplyToCommentId = undefined
97 }
98
99 onThreadCreated (commentTree: VideoCommentThreadTree) {
100 this.viewReplies(commentTree.comment)
101 }
102
103 onWantedToDelete (commentToDelete: VideoComment) {
104 let message = 'Do you really want to delete this comment?'
105 if (commentToDelete.totalReplies !== 0) message += `${commentToDelete.totalReplies} would be deleted too.`
106
107 this.confirmService.confirm(message, 'Delete').subscribe(
108 res => {
109 if (res === false) return
110
111 this.videoCommentService.deleteVideoComment(commentToDelete.videoId, commentToDelete.id)
112 .subscribe(
113 () => {
114 // Delete the comment in the tree
115 if (commentToDelete.inReplyToCommentId) {
116 const thread = this.threadComments[commentToDelete.threadId]
117 if (!thread) {
118 console.error(`Cannot find thread ${commentToDelete.threadId} of the comment to delete ${commentToDelete.id}`)
119 return
120 }
121
122 this.deleteLocalCommentThread(thread, commentToDelete)
123 return
124 }
125
126 // Delete the thread
127 this.comments = this.comments.filter(c => c.id !== commentToDelete.id)
128 this.componentPagination.totalItems--
129 },
130
131 err => this.notificationsService.error('Error', err.message)
132 )
133 }
134 )
135 }
136
137 isUserLoggedIn () {
138 return this.authService.isLoggedIn()
139 }
140
141 onNearOfBottom () {
142 this.componentPagination.currentPage++
143
144 if (this.hasMoreComments()) {
145 this.loadMoreComments()
146 }
147 }
148
149 private hasMoreComments () {
150 // No results
151 if (this.componentPagination.totalItems === 0) return false
152
153 // Not loaded yet
154 if (!this.componentPagination.totalItems) return true
155
156 const maxPage = this.componentPagination.totalItems / this.componentPagination.itemsPerPage
157 return maxPage > this.componentPagination.currentPage
158 }
159
160 private deleteLocalCommentThread (parentComment: VideoCommentThreadTree, commentToDelete: VideoComment) {
161 for (const commentChild of parentComment.children) {
162 if (commentChild.comment.id === commentToDelete.id) {
163 parentComment.children = parentComment.children.filter(c => c.comment.id !== commentToDelete.id)
164 return
165 }
166
167 this.deleteLocalCommentThread(commentChild, commentToDelete)
168 }
169 }
170
171 private loadVideoComments () {
172 if (this.video.commentsEnabled === true) {
173 // Reset all our fields
174 this.comments = []
175 this.threadComments = {}
176 this.threadLoading = {}
177 this.inReplyToCommentId = undefined
178 this.componentPagination.currentPage = 1
179 this.componentPagination.totalItems = null
180
181 // Find marked comment in params
182 this.activatedRoute.params.subscribe(
183 params => {
184 if (params['commentId']) {
185 this.markedCommentID = +params['commentId']
186 }
187 }
188 )
189
190 this.loadMoreComments()
191 }
192 }
193 }