aboutsummaryrefslogtreecommitdiffhomepage
path: root/client
diff options
context:
space:
mode:
Diffstat (limited to 'client')
-rw-r--r--client/src/app/app.component.ts6
-rw-r--r--client/src/app/shared/account/account.model.ts2
-rw-r--r--client/src/app/videos/+video-edit/shared/video-edit.component.scss2
-rw-r--r--client/src/app/videos/+video-watch/comment/video-comment.component.html6
-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.ts26
-rw-r--r--client/src/app/videos/+video-watch/comment/video-comment.service.ts9
-rw-r--r--client/src/app/videos/+video-watch/comment/video-comments.component.html2
-rw-r--r--client/src/app/videos/+video-watch/comment/video-comments.component.ts57
-rw-r--r--client/src/app/videos/+video-watch/video-watch.component.ts2
-rw-r--r--client/tsconfig.json6
11 files changed, 106 insertions, 23 deletions
diff --git a/client/src/app/app.component.ts b/client/src/app/app.component.ts
index b1818c298..ef8597203 100644
--- a/client/src/app/app.component.ts
+++ b/client/src/app/app.component.ts
@@ -1,6 +1,6 @@
1import { Component, OnInit } from '@angular/core' 1import { Component, OnInit } from '@angular/core'
2import { Router } from '@angular/router' 2import { Router } from '@angular/router'
3import { AuthService, ServerService } from './core' 3import { AuthService, ServerService } from '@app/core'
4 4
5@Component({ 5@Component({
6 selector: 'my-app', 6 selector: 'my-app',
@@ -50,10 +50,6 @@ export class AppComponent implements OnInit {
50 } 50 }
51 } 51 }
52 52
53 isInAdmin () {
54 return this.router.url.indexOf('/admin/') !== -1
55 }
56
57 toggleMenu () { 53 toggleMenu () {
58 window.scrollTo(0, 0) 54 window.scrollTo(0, 0)
59 this.isMenuDisplayed = !this.isMenuDisplayed 55 this.isMenuDisplayed = !this.isMenuDisplayed
diff --git a/client/src/app/shared/account/account.model.ts b/client/src/app/shared/account/account.model.ts
index cc46dad77..1dce0003c 100644
--- a/client/src/app/shared/account/account.model.ts
+++ b/client/src/app/shared/account/account.model.ts
@@ -1,11 +1,11 @@
1import { Account as ServerAccount } from '../../../../../shared/models/actors/account.model' 1import { Account as ServerAccount } from '../../../../../shared/models/actors/account.model'
2import { Avatar } from '../../../../../shared/models/avatars/avatar.model' 2import { Avatar } from '../../../../../shared/models/avatars/avatar.model'
3import { environment } from '../../../environments/environment'
4import { getAbsoluteAPIUrl } from '../misc/utils' 3import { getAbsoluteAPIUrl } from '../misc/utils'
5 4
6export class Account implements ServerAccount { 5export class Account implements ServerAccount {
7 id: number 6 id: number
8 uuid: string 7 uuid: string
8 url: string
9 name: string 9 name: string
10 displayName: string 10 displayName: string
11 host: string 11 host: string
diff --git a/client/src/app/videos/+video-edit/shared/video-edit.component.scss b/client/src/app/videos/+video-edit/shared/video-edit.component.scss
index 0fefcee28..1df9d4006 100644
--- a/client/src/app/videos/+video-edit/shared/video-edit.component.scss
+++ b/client/src/app/videos/+video-edit/shared/video-edit.component.scss
@@ -51,8 +51,6 @@
51 51
52.submit-container { 52.submit-container {
53 text-align: right; 53 text-align: right;
54 position: relative;
55 bottom: $button-height;
56 54
57 .message-submit { 55 .message-submit {
58 display: inline-block; 56 display: inline-block;
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 e9c23929c..4f9597607 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
@@ -3,13 +3,14 @@
3 3
4 <div class="comment"> 4 <div class="comment">
5 <div class="comment-account-date"> 5 <div class="comment-account-date">
6 <div class="comment-account">{{ comment.by }}</div> 6 <a target="_blank" [href]="comment.account.url" class="comment-account">{{ comment.by }}</a>
7 <div class="comment-date">{{ comment.createdAt | myFromNow }}</div> 7 <div class="comment-date">{{ comment.createdAt | myFromNow }}</div>
8 </div> 8 </div>
9 <div>{{ comment.text }}</div> 9 <div>{{ comment.text }}</div>
10 10
11 <div class="comment-actions"> 11 <div class="comment-actions">
12 <div *ngIf="isUserLoggedIn()" (click)="onWantToReply()" class="comment-action-reply">Reply</div> 12 <div *ngIf="isUserLoggedIn()" (click)="onWantToReply()" class="comment-action-reply">Reply</div>
13 <div *ngIf="isRemovableByUser()" (click)="onWantToDelete()" class="comment-action-delete">Delete</div>
13 </div> 14 </div>
14 15
15 <my-video-comment-add 16 <my-video-comment-add
@@ -28,7 +29,8 @@
28 [video]="video" 29 [video]="video"
29 [inReplyToCommentId]="inReplyToCommentId" 30 [inReplyToCommentId]="inReplyToCommentId"
30 [commentTree]="commentChild" 31 [commentTree]="commentChild"
31 (wantedToReply)="onWantedToReply($event)" 32 (wantedToReply)="onWantToReply($event)"
33 (wantedToDelete)="onWantToDelete($event)"
32 (resetReply)="onResetReply()" 34 (resetReply)="onResetReply()"
33 ></my-video-comment> 35 ></my-video-comment>
34 </div> 36 </div>
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 aae03ab6d..a22c5a9fd 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
@@ -20,6 +20,9 @@
20 margin-bottom: 4px; 20 margin-bottom: 4px;
21 21
22 .comment-account { 22 .comment-account {
23 @include disable-default-a-behaviour;
24
25 color: #000;
23 font-weight: $font-bold; 26 font-weight: $font-bold;
24 } 27 }
25 28
@@ -31,10 +34,16 @@
31 34
32 .comment-actions { 35 .comment-actions {
33 margin: 10px 0; 36 margin: 10px 0;
37 display: flex;
34 38
35 .comment-action-reply { 39 .comment-action-reply, .comment-action-delete {
36 color: #585858; 40 color: #585858;
37 cursor: pointer; 41 cursor: pointer;
42 margin-right: 10px;
43
44 &:hover {
45 color: #000;
46 }
38 } 47 }
39 } 48 }
40 } 49 }
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 b305c639a..9bc9c8844 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
@@ -1,5 +1,6 @@
1import { Component, EventEmitter, Input, Output } from '@angular/core' 1import { Component, EventEmitter, Input, Output } from '@angular/core'
2import { Account as AccountInterface } from '../../../../../../shared/models/actors' 2import { Account as AccountInterface } from '../../../../../../shared/models/actors'
3import { UserRight } from '../../../../../../shared/models/users'
3import { VideoCommentThreadTree } from '../../../../../../shared/models/videos/video-comment.model' 4import { VideoCommentThreadTree } from '../../../../../../shared/models/videos/video-comment.model'
4import { AuthService } from '../../../core/auth' 5import { AuthService } from '../../../core/auth'
5import { Account } from '../../../shared/account/account.model' 6import { Account } from '../../../shared/account/account.model'
@@ -17,7 +18,9 @@ export class VideoCommentComponent {
17 @Input() commentTree: VideoCommentThreadTree 18 @Input() commentTree: VideoCommentThreadTree
18 @Input() inReplyToCommentId: number 19 @Input() inReplyToCommentId: number
19 20
21 @Output() wantedToDelete = new EventEmitter<VideoComment>()
20 @Output() wantedToReply = new EventEmitter<VideoComment>() 22 @Output() wantedToReply = new EventEmitter<VideoComment>()
23 @Output() threadCreated = new EventEmitter<VideoCommentThreadTree>()
21 @Output() resetReply = new EventEmitter() 24 @Output() resetReply = new EventEmitter()
22 25
23 constructor (private authService: AuthService) {} 26 constructor (private authService: AuthService) {}
@@ -32,6 +35,8 @@ export class VideoCommentComponent {
32 comment: this.comment, 35 comment: this.comment,
33 children: [] 36 children: []
34 } 37 }
38
39 this.threadCreated.emit(this.commentTree)
35 } 40 }
36 41
37 this.commentTree.children.push({ 42 this.commentTree.children.push({
@@ -41,17 +46,16 @@ export class VideoCommentComponent {
41 this.resetReply.emit() 46 this.resetReply.emit()
42 } 47 }
43 48
44 onWantToReply () { 49 onWantToReply (comment?: VideoComment) {
45 this.wantedToReply.emit(this.comment) 50 this.wantedToReply.emit(comment || this.comment)
46 } 51 }
47 52
48 isUserLoggedIn () { 53 onWantToDelete (comment?: VideoComment) {
49 return this.authService.isLoggedIn() 54 this.wantedToDelete.emit(comment || this.comment)
50 } 55 }
51 56
52 // Event from child comment 57 isUserLoggedIn () {
53 onWantedToReply (comment: VideoComment) { 58 return this.authService.isLoggedIn()
54 this.wantedToReply.emit(comment)
55 } 59 }
56 60
57 onResetReply () { 61 onResetReply () {
@@ -61,4 +65,12 @@ export class VideoCommentComponent {
61 getAvatarUrl (account: AccountInterface) { 65 getAvatarUrl (account: AccountInterface) {
62 return Account.GET_ACCOUNT_AVATAR_URL(account) 66 return Account.GET_ACCOUNT_AVATAR_URL(account)
63 } 67 }
68
69 isRemovableByUser () {
70 return this.isUserLoggedIn() &&
71 (
72 this.user.account.id === this.comment.account.id ||
73 this.user.hasRight(UserRight.REMOVE_ANY_VIDEO_COMMENT)
74 )
75 }
64} 76}
diff --git a/client/src/app/videos/+video-watch/comment/video-comment.service.ts b/client/src/app/videos/+video-watch/comment/video-comment.service.ts
index 2fe6cc3e9..c42f55496 100644
--- a/client/src/app/videos/+video-watch/comment/video-comment.service.ts
+++ b/client/src/app/videos/+video-watch/comment/video-comment.service.ts
@@ -66,6 +66,15 @@ export class VideoCommentService {
66 .catch((res) => this.restExtractor.handleError(res)) 66 .catch((res) => this.restExtractor.handleError(res))
67 } 67 }
68 68
69 deleteVideoComment (videoId: number | string, commentId: number) {
70 const url = `${VideoCommentService.BASE_VIDEO_URL + videoId}/comments/${commentId}`
71
72 return this.authHttp
73 .delete(url)
74 .map(this.restExtractor.extractDataBool)
75 .catch((res) => this.restExtractor.handleError(res))
76 }
77
69 private extractVideoComment (videoComment: VideoCommentServerModel) { 78 private extractVideoComment (videoComment: VideoCommentServerModel) {
70 return new VideoComment(videoComment) 79 return new VideoComment(videoComment)
71 } 80 }
diff --git a/client/src/app/videos/+video-watch/comment/video-comments.component.html b/client/src/app/videos/+video-watch/comment/video-comments.component.html
index 4a4248073..80b200931 100644
--- a/client/src/app/videos/+video-watch/comment/video-comments.component.html
+++ b/client/src/app/videos/+video-watch/comment/video-comments.component.html
@@ -27,6 +27,8 @@
27 [inReplyToCommentId]="inReplyToCommentId" 27 [inReplyToCommentId]="inReplyToCommentId"
28 [commentTree]="threadComments[comment.id]" 28 [commentTree]="threadComments[comment.id]"
29 (wantedToReply)="onWantedToReply($event)" 29 (wantedToReply)="onWantedToReply($event)"
30 (wantedToDelete)="onWantedToDelete($event)"
31 (threadCreated)="onThreadCreated($event)"
30 (resetReply)="onResetReply()" 32 (resetReply)="onResetReply()"
31 ></my-video-comment> 33 ></my-video-comment>
32 34
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 1230725c1..030dee9af 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
@@ -1,6 +1,7 @@
1import { Component, Input, OnInit } from '@angular/core' 1import { Component, Input, OnInit } from '@angular/core'
2import { ConfirmService } from '@app/core'
2import { NotificationsService } from 'angular2-notifications' 3import { NotificationsService } from 'angular2-notifications'
3import { VideoCommentThreadTree } from '../../../../../../shared/models/videos/video-comment.model' 4import { VideoComment as VideoCommentInterface, VideoCommentThreadTree } from '../../../../../../shared/models/videos/video-comment.model'
4import { AuthService } from '../../../core/auth' 5import { AuthService } from '../../../core/auth'
5import { ComponentPagination } from '../../../shared/rest/component-pagination.model' 6import { ComponentPagination } from '../../../shared/rest/component-pagination.model'
6import { User } from '../../../shared/users' 7import { User } from '../../../shared/users'
@@ -32,6 +33,7 @@ export class VideoCommentsComponent implements OnInit {
32 constructor ( 33 constructor (
33 private authService: AuthService, 34 private authService: AuthService,
34 private notificationsService: NotificationsService, 35 private notificationsService: NotificationsService,
36 private confirmService: ConfirmService,
35 private videoCommentService: VideoCommentService 37 private videoCommentService: VideoCommentService
36 ) {} 38 ) {}
37 39
@@ -41,7 +43,7 @@ export class VideoCommentsComponent implements OnInit {
41 } 43 }
42 } 44 }
43 45
44 viewReplies (comment: VideoComment) { 46 viewReplies (comment: VideoCommentInterface) {
45 this.threadLoading[comment.id] = true 47 this.threadLoading[comment.id] = true
46 48
47 this.videoCommentService.getVideoThreadComments(this.video.id, comment.id) 49 this.videoCommentService.getVideoThreadComments(this.video.id, comment.id)
@@ -79,6 +81,44 @@ export class VideoCommentsComponent implements OnInit {
79 this.inReplyToCommentId = undefined 81 this.inReplyToCommentId = undefined
80 } 82 }
81 83
84 onThreadCreated (commentTree: VideoCommentThreadTree) {
85 this.viewReplies(commentTree.comment)
86 }
87
88 onWantedToDelete (commentToDelete: VideoComment) {
89 let message = 'Do you really want to delete this comment?'
90 if (commentToDelete.totalReplies !== 0) message += `${commentToDelete.totalReplies} would be deleted too.`
91
92 this.confirmService.confirm(message, 'Delete').subscribe(
93 res => {
94 if (res === false) return
95
96 this.videoCommentService.deleteVideoComment(commentToDelete.videoId, commentToDelete.id)
97 .subscribe(
98 () => {
99 // Delete the comment in the tree
100 if (commentToDelete.inReplyToCommentId) {
101 const thread = this.threadComments[commentToDelete.threadId]
102 if (!thread) {
103 console.error(`Cannot find thread ${commentToDelete.threadId} of the comment to delete ${commentToDelete.id}`)
104 return
105 }
106
107 this.deleteLocalCommentThread(thread, commentToDelete)
108 return
109 }
110
111 // Delete the thread
112 this.comments = this.comments.filter(c => c.id !== commentToDelete.id)
113 this.componentPagination.totalItems--
114 },
115
116 err => this.notificationsService.error('Error', err.message)
117 )
118 }
119 )
120 }
121
82 isUserLoggedIn () { 122 isUserLoggedIn () {
83 return this.authService.isLoggedIn() 123 return this.authService.isLoggedIn()
84 } 124 }
@@ -91,7 +131,7 @@ export class VideoCommentsComponent implements OnInit {
91 } 131 }
92 } 132 }
93 133
94 protected hasMoreComments () { 134 private hasMoreComments () {
95 // No results 135 // No results
96 if (this.componentPagination.totalItems === 0) return false 136 if (this.componentPagination.totalItems === 0) return false
97 137
@@ -101,4 +141,15 @@ export class VideoCommentsComponent implements OnInit {
101 const maxPage = this.componentPagination.totalItems / this.componentPagination.itemsPerPage 141 const maxPage = this.componentPagination.totalItems / this.componentPagination.itemsPerPage
102 return maxPage > this.componentPagination.currentPage 142 return maxPage > this.componentPagination.currentPage
103 } 143 }
144
145 private deleteLocalCommentThread (parentComment: VideoCommentThreadTree, commentToDelete: VideoComment) {
146 for (const commentChild of parentComment.children) {
147 if (commentChild.comment.id === commentToDelete.id) {
148 parentComment.children = parentComment.children.filter(c => c.comment.id !== commentToDelete.id)
149 return
150 }
151
152 this.deleteLocalCommentThread(commentChild, commentToDelete)
153 }
154 }
104} 155}
diff --git a/client/src/app/videos/+video-watch/video-watch.component.ts b/client/src/app/videos/+video-watch/video-watch.component.ts
index 0f44d3dd7..f1f194764 100644
--- a/client/src/app/videos/+video-watch/video-watch.component.ts
+++ b/client/src/app/videos/+video-watch/video-watch.component.ts
@@ -137,7 +137,7 @@ export class VideoWatchComponent implements OnInit, OnDestroy {
137 blacklistVideo (event: Event) { 137 blacklistVideo (event: Event) {
138 event.preventDefault() 138 event.preventDefault()
139 139
140 this.confirmService.confirm('Do you really want to blacklist this video ?', 'Blacklist').subscribe( 140 this.confirmService.confirm('Do you really want to blacklist this video?', 'Blacklist').subscribe(
141 res => { 141 res => {
142 if (res === false) return 142 if (res === false) return
143 143
diff --git a/client/tsconfig.json b/client/tsconfig.json
index a6c016bf3..43b27ce8e 100644
--- a/client/tsconfig.json
+++ b/client/tsconfig.json
@@ -14,6 +14,10 @@
14 "lib": [ 14 "lib": [
15 "es2017", 15 "es2017",
16 "dom" 16 "dom"
17 ] 17 ],
18 "baseUrl": "src",
19 "paths": {
20 "@app/*": [ "app/*" ]
21 }
18 } 22 }
19} 23}