aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorChocobozzz <me@florianbigard.com>2019-02-15 15:52:18 +0100
committerChocobozzz <me@florianbigard.com>2019-02-15 15:52:18 +0100
commit41d713446c2152d47943ddb0c841a9e36ca5a9db (patch)
tree7b22f6f7ea5652107ef503470d2455c4bb087799
parent17036be5bc2f14dc4e66053087e39887599df4de (diff)
downloadPeerTube-41d713446c2152d47943ddb0c841a9e36ca5a9db.tar.gz
PeerTube-41d713446c2152d47943ddb0c841a9e36ca5a9db.tar.zst
PeerTube-41d713446c2152d47943ddb0c841a9e36ca5a9db.zip
Lazy import some modules
-rw-r--r--client/package.json3
-rw-r--r--client/src/app/+about/about-instance/about-instance.component.ts7
-rw-r--r--client/src/app/+accounts/account-about/account-about.component.ts4
-rw-r--r--client/src/app/+admin/moderation/video-abuse-list/video-abuse-list.component.html4
-rw-r--r--client/src/app/+admin/moderation/video-abuse-list/video-abuse-list.component.ts23
-rw-r--r--client/src/app/+admin/moderation/video-blacklist-list/video-blacklist-list.component.html2
-rw-r--r--client/src/app/+admin/moderation/video-blacklist-list/video-blacklist-list.component.ts11
-rw-r--r--client/src/app/+video-channels/video-channel-about/video-channel-about.component.ts6
-rw-r--r--client/src/app/core/notification/user-notification-socket.service.ts15
-rw-r--r--client/src/app/menu/avatar-notification.component.ts32
-rw-r--r--client/src/app/shared/forms/markdown-textarea.component.ts6
-rw-r--r--client/src/app/shared/renderer/html-renderer.service.ts6
-rw-r--r--client/src/app/shared/renderer/linkifier.service.ts5
-rw-r--r--client/src/app/shared/renderer/markdown.service.ts32
-rw-r--r--client/src/app/shared/users/user-notification.service.ts2
-rw-r--r--client/src/app/videos/+video-watch/comment/video-comment.component.ts4
-rw-r--r--client/src/app/videos/+video-watch/modal/video-support.component.ts4
-rw-r--r--client/src/app/videos/+video-watch/video-watch.component.ts4
-rw-r--r--client/src/assets/player/peertube-plugin.ts1
-rw-r--r--client/src/sass/include/_mixins.scss2
-rw-r--r--client/yarn.lock32
-rw-r--r--server/lib/notifier.ts9
22 files changed, 132 insertions, 82 deletions
diff --git a/client/package.json b/client/package.json
index 92659b091..08d309b07 100644
--- a/client/package.json
+++ b/client/package.json
@@ -93,6 +93,7 @@
93 "@types/jasminewd2": "^2.0.3", 93 "@types/jasminewd2": "^2.0.3",
94 "@types/jest": "^23.3.1", 94 "@types/jest": "^23.3.1",
95 "@types/jschannel": "^1.0.0", 95 "@types/jschannel": "^1.0.0",
96 "@types/linkifyjs": "^2.1.1",
96 "@types/lodash-es": "^4.17.0", 97 "@types/lodash-es": "^4.17.0",
97 "@types/markdown-it": "^0.0.5", 98 "@types/markdown-it": "^0.0.5",
98 "@types/node": "^10.9.2", 99 "@types/node": "^10.9.2",
@@ -154,7 +155,7 @@
154 "ts-jest": "^23.1.4", 155 "ts-jest": "^23.1.4",
155 "tslint": "^5.7.0", 156 "tslint": "^5.7.0",
156 "tslint-config-standard": "^8.0.1", 157 "tslint-config-standard": "^8.0.1",
157 "typescript": "3.1.6", 158 "typescript": "3.2",
158 "video.js": "^7", 159 "video.js": "^7",
159 "videojs-contextmenu-ui": "^5.0.0", 160 "videojs-contextmenu-ui": "^5.0.0",
160 "videojs-contrib-quality-levels": "^2.0.9", 161 "videojs-contrib-quality-levels": "^2.0.9",
diff --git a/client/src/app/+about/about-instance/about-instance.component.ts b/client/src/app/+about/about-instance/about-instance.component.ts
index a1b30fa8c..ec572ff80 100644
--- a/client/src/app/+about/about-instance/about-instance.component.ts
+++ b/client/src/app/+about/about-instance/about-instance.component.ts
@@ -44,10 +44,11 @@ export class AboutInstanceComponent implements OnInit {
44 ngOnInit () { 44 ngOnInit () {
45 this.instanceService.getAbout() 45 this.instanceService.getAbout()
46 .subscribe( 46 .subscribe(
47 res => { 47 async res => {
48 this.shortDescription = res.instance.shortDescription 48 this.shortDescription = res.instance.shortDescription
49 this.descriptionHTML = this.markdownService.textMarkdownToHTML(res.instance.description) 49
50 this.termsHTML = this.markdownService.textMarkdownToHTML(res.instance.terms) 50 this.descriptionHTML = await this.markdownService.textMarkdownToHTML(res.instance.description)
51 this.termsHTML = await this.markdownService.textMarkdownToHTML(res.instance.terms)
51 }, 52 },
52 53
53 () => this.notifier.error(this.i18n('Cannot get about information from server')) 54 () => this.notifier.error(this.i18n('Cannot get about information from server'))
diff --git a/client/src/app/+accounts/account-about/account-about.component.ts b/client/src/app/+accounts/account-about/account-about.component.ts
index 13890a0ee..ce22d3c2e 100644
--- a/client/src/app/+accounts/account-about/account-about.component.ts
+++ b/client/src/app/+accounts/account-about/account-about.component.ts
@@ -25,9 +25,9 @@ export class AccountAboutComponent implements OnInit, OnDestroy {
25 ngOnInit () { 25 ngOnInit () {
26 // Parent get the account for us 26 // Parent get the account for us
27 this.accountSub = this.accountService.accountLoaded 27 this.accountSub = this.accountService.accountLoaded
28 .subscribe(account => { 28 .subscribe(async account => {
29 this.account = account 29 this.account = account
30 this.descriptionHTML = this.markdownService.textMarkdownToHTML(this.account.description) 30 this.descriptionHTML = await this.markdownService.textMarkdownToHTML(this.account.description)
31 }) 31 })
32 } 32 }
33 33
diff --git a/client/src/app/+admin/moderation/video-abuse-list/video-abuse-list.component.html b/client/src/app/+admin/moderation/video-abuse-list/video-abuse-list.component.html
index 05b549de6..627437053 100644
--- a/client/src/app/+admin/moderation/video-abuse-list/video-abuse-list.component.html
+++ b/client/src/app/+admin/moderation/video-abuse-list/video-abuse-list.component.html
@@ -51,11 +51,11 @@
51 <td class="moderation-expanded" colspan="6"> 51 <td class="moderation-expanded" colspan="6">
52 <div> 52 <div>
53 <span i18n class="moderation-expanded-label">Reason:</span> 53 <span i18n class="moderation-expanded-label">Reason:</span>
54 <span class="moderation-expanded-text" [innerHTML]="toHtml(videoAbuse.reason)"></span> 54 <span class="moderation-expanded-text" [innerHTML]="videoAbuse.reasonHtml"></span>
55 </div> 55 </div>
56 <div *ngIf="videoAbuse.moderationComment"> 56 <div *ngIf="videoAbuse.moderationComment">
57 <span i18n class="moderation-expanded-label">Moderation comment:</span> 57 <span i18n class="moderation-expanded-label">Moderation comment:</span>
58 <span class="moderation-expanded-text" [innerHTML]="toHtml(videoAbuse.moderationComment)"></span> 58 <span class="moderation-expanded-text" [innerHTML]="videoAbuse.moderationCommentHtml"></span>
59 </div> 59 </div>
60 </td> 60 </td>
61 </tr> 61 </tr>
diff --git a/client/src/app/+admin/moderation/video-abuse-list/video-abuse-list.component.ts b/client/src/app/+admin/moderation/video-abuse-list/video-abuse-list.component.ts
index 00c871659..3aa875668 100644
--- a/client/src/app/+admin/moderation/video-abuse-list/video-abuse-list.component.ts
+++ b/client/src/app/+admin/moderation/video-abuse-list/video-abuse-list.component.ts
@@ -19,7 +19,7 @@ import { MarkdownService } from '@app/shared/renderer'
19export class VideoAbuseListComponent extends RestTable implements OnInit { 19export class VideoAbuseListComponent extends RestTable implements OnInit {
20 @ViewChild('moderationCommentModal') moderationCommentModal: ModerationCommentModalComponent 20 @ViewChild('moderationCommentModal') moderationCommentModal: ModerationCommentModalComponent
21 21
22 videoAbuses: VideoAbuse[] = [] 22 videoAbuses: (VideoAbuse & { moderationCommentHtml?: string, reasonHtml?: string })[] = []
23 totalRecords = 0 23 totalRecords = 0
24 rowsPerPage = 10 24 rowsPerPage = 10
25 sort: SortMeta = { field: 'createdAt', order: 1 } 25 sort: SortMeta = { field: 'createdAt', order: 1 }
@@ -110,19 +110,28 @@ export class VideoAbuseListComponent extends RestTable implements OnInit {
110 110
111 } 111 }
112 112
113 toHtml (text: string) {
114 return this.markdownRenderer.textMarkdownToHTML(text)
115 }
116
117 protected loadData () { 113 protected loadData () {
118 return this.videoAbuseService.getVideoAbuses(this.pagination, this.sort) 114 return this.videoAbuseService.getVideoAbuses(this.pagination, this.sort)
119 .subscribe( 115 .subscribe(
120 resultList => { 116 async resultList => {
121 this.videoAbuses = resultList.data
122 this.totalRecords = resultList.total 117 this.totalRecords = resultList.total
118
119 this.videoAbuses = resultList.data
120
121 for (const abuse of this.videoAbuses) {
122 Object.assign(abuse, {
123 reasonHtml: await this.toHtml(abuse.reason),
124 moderationCommentHtml: await this.toHtml(abuse.moderationComment)
125 })
126 }
127
123 }, 128 },
124 129
125 err => this.notifier.error(err.message) 130 err => this.notifier.error(err.message)
126 ) 131 )
127 } 132 }
133
134 private toHtml (text: string) {
135 return this.markdownRenderer.textMarkdownToHTML(text)
136 }
128} 137}
diff --git a/client/src/app/+admin/moderation/video-blacklist-list/video-blacklist-list.component.html b/client/src/app/+admin/moderation/video-blacklist-list/video-blacklist-list.component.html
index 247f441c1..608dff2d8 100644
--- a/client/src/app/+admin/moderation/video-blacklist-list/video-blacklist-list.component.html
+++ b/client/src/app/+admin/moderation/video-blacklist-list/video-blacklist-list.component.html
@@ -41,7 +41,7 @@
41 <tr> 41 <tr>
42 <td class="moderation-expanded" colspan="6"> 42 <td class="moderation-expanded" colspan="6">
43 <span i18n class="moderation-expanded-label">Blacklist reason:</span> 43 <span i18n class="moderation-expanded-label">Blacklist reason:</span>
44 <span class="moderation-expanded-text" [innerHTML]="toHtml(videoBlacklist.reason)"></span> 44 <span class="moderation-expanded-text" [innerHTML]="videoBlacklist.reasonHtml"></span>
45 </td> 45 </td>
46 </tr> 46 </tr>
47 </ng-template> 47 </ng-template>
diff --git a/client/src/app/+admin/moderation/video-blacklist-list/video-blacklist-list.component.ts b/client/src/app/+admin/moderation/video-blacklist-list/video-blacklist-list.component.ts
index b27bbbfef..5443d816d 100644
--- a/client/src/app/+admin/moderation/video-blacklist-list/video-blacklist-list.component.ts
+++ b/client/src/app/+admin/moderation/video-blacklist-list/video-blacklist-list.component.ts
@@ -15,7 +15,7 @@ import { MarkdownService } from '@app/shared/renderer'
15 styleUrls: [ '../moderation.component.scss' ] 15 styleUrls: [ '../moderation.component.scss' ]
16}) 16})
17export class VideoBlacklistListComponent extends RestTable implements OnInit { 17export class VideoBlacklistListComponent extends RestTable implements OnInit {
18 blacklist: VideoBlacklist[] = [] 18 blacklist: (VideoBlacklist & { reasonHtml?: string })[] = []
19 totalRecords = 0 19 totalRecords = 0
20 rowsPerPage = 10 20 rowsPerPage = 10
21 sort: SortMeta = { field: 'createdAt', order: 1 } 21 sort: SortMeta = { field: 'createdAt', order: 1 }
@@ -79,9 +79,14 @@ export class VideoBlacklistListComponent extends RestTable implements OnInit {
79 protected loadData () { 79 protected loadData () {
80 this.videoBlacklistService.listBlacklist(this.pagination, this.sort) 80 this.videoBlacklistService.listBlacklist(this.pagination, this.sort)
81 .subscribe( 81 .subscribe(
82 resultList => { 82 async resultList => {
83 this.blacklist = resultList.data
84 this.totalRecords = resultList.total 83 this.totalRecords = resultList.total
84
85 this.blacklist = resultList.data
86
87 for (const element of this.blacklist) {
88 Object.assign(element, { reasonHtml: await this.toHtml(element.reason) })
89 }
85 }, 90 },
86 91
87 err => this.notifier.error(err.message) 92 err => this.notifier.error(err.message)
diff --git a/client/src/app/+video-channels/video-channel-about/video-channel-about.component.ts b/client/src/app/+video-channels/video-channel-about/video-channel-about.component.ts
index 895b19064..11f9391e1 100644
--- a/client/src/app/+video-channels/video-channel-about/video-channel-about.component.ts
+++ b/client/src/app/+video-channels/video-channel-about/video-channel-about.component.ts
@@ -26,11 +26,11 @@ export class VideoChannelAboutComponent implements OnInit, OnDestroy {
26 ngOnInit () { 26 ngOnInit () {
27 // Parent get the video channel for us 27 // Parent get the video channel for us
28 this.videoChannelSub = this.videoChannelService.videoChannelLoaded 28 this.videoChannelSub = this.videoChannelService.videoChannelLoaded
29 .subscribe(videoChannel => { 29 .subscribe(async videoChannel => {
30 this.videoChannel = videoChannel 30 this.videoChannel = videoChannel
31 31
32 this.descriptionHTML = this.markdownService.textMarkdownToHTML(this.videoChannel.description) 32 this.descriptionHTML = await this.markdownService.textMarkdownToHTML(this.videoChannel.description)
33 this.supportHTML = this.markdownService.enhancedMarkdownToHTML(this.videoChannel.support) 33 this.supportHTML = await this.markdownService.enhancedMarkdownToHTML(this.videoChannel.support)
34 }) 34 })
35 } 35 }
36 36
diff --git a/client/src/app/core/notification/user-notification-socket.service.ts b/client/src/app/core/notification/user-notification-socket.service.ts
index f367d9ae4..29337d3a7 100644
--- a/client/src/app/core/notification/user-notification-socket.service.ts
+++ b/client/src/app/core/notification/user-notification-socket.service.ts
@@ -21,21 +21,22 @@ export class UserNotificationSocket {
21 this.notificationSubject.next({ type, notification }) 21 this.notificationSubject.next({ type, notification })
22 } 22 }
23 23
24 getMyNotificationsSocket () { 24 async getMyNotificationsSocket () {
25 const socket = this.getSocket() 25 await this.initSocket()
26
27 socket.on('new-notification', (n: UserNotificationServer) => this.dispatch('new', n))
28 26
29 return this.notificationSubject.asObservable() 27 return this.notificationSubject.asObservable()
30 } 28 }
31 29
32 private getSocket () { 30 private async initSocket () {
33 if (this.socket) return this.socket 31 if (this.socket) return
32
33 // FIXME: import('..') returns a struct module, containing a "default" field corresponding to our sanitizeHtml function
34 const io: typeof import ('socket.io-client') = (await import('socket.io-client') as any).default
34 35
35 this.socket = io(environment.apiUrl + '/user-notifications', { 36 this.socket = io(environment.apiUrl + '/user-notifications', {
36 query: { accessToken: this.auth.getAccessToken() } 37 query: { accessToken: this.auth.getAccessToken() }
37 }) 38 })
38 39
39 return this.socket 40 this.socket.on('new-notification', (n: UserNotificationServer) => this.dispatch('new', n))
40 } 41 }
41} 42}
diff --git a/client/src/app/menu/avatar-notification.component.ts b/client/src/app/menu/avatar-notification.component.ts
index f1af08096..878c5c88c 100644
--- a/client/src/app/menu/avatar-notification.component.ts
+++ b/client/src/app/menu/avatar-notification.component.ts
@@ -26,18 +26,19 @@ export class AvatarNotificationComponent implements OnInit, OnDestroy {
26 private userNotificationSocket: UserNotificationSocket, 26 private userNotificationSocket: UserNotificationSocket,
27 private notifier: Notifier, 27 private notifier: Notifier,
28 private router: Router 28 private router: Router
29 ) {} 29 ) {
30 }
30 31
31 ngOnInit () { 32 ngOnInit () {
32 this.userNotificationService.countUnreadNotifications() 33 this.userNotificationService.countUnreadNotifications()
33 .subscribe( 34 .subscribe(
34 result => { 35 result => {
35 this.unreadNotifications = Math.min(result, 99) // Limit number to 99 36 this.unreadNotifications = Math.min(result, 99) // Limit number to 99
36 this.subscribeToNotifications() 37 this.subscribeToNotifications()
37 }, 38 },
38 39
39 err => this.notifier.error(err.message) 40 err => this.notifier.error(err.message)
40 ) 41 )
41 42
42 this.routeSub = this.router.events 43 this.routeSub = this.router.events
43 .pipe(filter(event => event instanceof NavigationEnd)) 44 .pipe(filter(event => event instanceof NavigationEnd))
@@ -53,13 +54,14 @@ export class AvatarNotificationComponent implements OnInit, OnDestroy {
53 this.popover.close() 54 this.popover.close()
54 } 55 }
55 56
56 private subscribeToNotifications () { 57 private async subscribeToNotifications () {
57 this.notificationSub = this.userNotificationSocket.getMyNotificationsSocket() 58 const obs = await this.userNotificationSocket.getMyNotificationsSocket()
58 .subscribe(data => { 59
59 if (data.type === 'new') return this.unreadNotifications++ 60 this.notificationSub = obs.subscribe(data => {
60 if (data.type === 'read') return this.unreadNotifications-- 61 if (data.type === 'new') return this.unreadNotifications++
61 if (data.type === 'read-all') return this.unreadNotifications = 0 62 if (data.type === 'read') return this.unreadNotifications--
62 }) 63 if (data.type === 'read-all') return this.unreadNotifications = 0
64 })
63 } 65 }
64 66
65} 67}
diff --git a/client/src/app/shared/forms/markdown-textarea.component.ts b/client/src/app/shared/forms/markdown-textarea.component.ts
index e87aca0d4..49a57f29d 100644
--- a/client/src/app/shared/forms/markdown-textarea.component.ts
+++ b/client/src/app/shared/forms/markdown-textarea.component.ts
@@ -82,11 +82,11 @@ export class MarkdownTextareaComponent implements ControlValueAccessor, OnInit {
82 return this.screenService.isInSmallView() === false 82 return this.screenService.isInSmallView() === false
83 } 83 }
84 84
85 private updatePreviews () { 85 private async updatePreviews () {
86 if (this.content === null || this.content === undefined) return 86 if (this.content === null || this.content === undefined) return
87 87
88 this.truncatedPreviewHTML = this.markdownRender(truncate(this.content, { length: this.truncate })) 88 this.truncatedPreviewHTML = await this.markdownRender(truncate(this.content, { length: this.truncate }))
89 this.previewHTML = this.markdownRender(this.content) 89 this.previewHTML = await this.markdownRender(this.content)
90 } 90 }
91 91
92 private markdownRender (text: string) { 92 private markdownRender (text: string) {
diff --git a/client/src/app/shared/renderer/html-renderer.service.ts b/client/src/app/shared/renderer/html-renderer.service.ts
index d49df9b6d..28ef51e72 100644
--- a/client/src/app/shared/renderer/html-renderer.service.ts
+++ b/client/src/app/shared/renderer/html-renderer.service.ts
@@ -1,6 +1,5 @@
1import { Injectable } from '@angular/core' 1import { Injectable } from '@angular/core'
2import { LinkifierService } from '@app/shared/renderer/linkifier.service' 2import { LinkifierService } from '@app/shared/renderer/linkifier.service'
3import * as sanitizeHtml from 'sanitize-html'
4 3
5@Injectable() 4@Injectable()
6export class HtmlRendererService { 5export class HtmlRendererService {
@@ -9,7 +8,10 @@ export class HtmlRendererService {
9 8
10 } 9 }
11 10
12 toSafeHtml (text: string) { 11 async toSafeHtml (text: string) {
12 // FIXME: import('..') returns a struct module, containing a "default" field corresponding to our sanitizeHtml function
13 const sanitizeHtml: typeof import ('sanitize-html') = (await import('sanitize-html') as any).default
14
13 // Convert possible markdown to html 15 // Convert possible markdown to html
14 const html = this.linkifier.linkify(text) 16 const html = this.linkifier.linkify(text)
15 17
diff --git a/client/src/app/shared/renderer/linkifier.service.ts b/client/src/app/shared/renderer/linkifier.service.ts
index 2529c9eaf..95d5f17cc 100644
--- a/client/src/app/shared/renderer/linkifier.service.ts
+++ b/client/src/app/shared/renderer/linkifier.service.ts
@@ -1,8 +1,7 @@
1import { Injectable } from '@angular/core' 1import { Injectable } from '@angular/core'
2import { getAbsoluteAPIUrl } from '@app/shared/misc/utils' 2import { getAbsoluteAPIUrl } from '@app/shared/misc/utils'
3// FIXME: use @types/linkify when https://github.com/DefinitelyTyped/DefinitelyTyped/pull/29682/files is merged? 3import * as linkify from 'linkifyjs'
4const linkify = require('linkifyjs') 4import linkifyHtml from 'linkifyjs/html'
5const linkifyHtml = require('linkifyjs/html')
6 5
7@Injectable() 6@Injectable()
8export class LinkifierService { 7export class LinkifierService {
diff --git a/client/src/app/shared/renderer/markdown.service.ts b/client/src/app/shared/renderer/markdown.service.ts
index 07017eca5..69dc60aaf 100644
--- a/client/src/app/shared/renderer/markdown.service.ts
+++ b/client/src/app/shared/renderer/markdown.service.ts
@@ -1,6 +1,6 @@
1import { Injectable } from '@angular/core' 1import { Injectable } from '@angular/core'
2 2
3import * as MarkdownIt from 'markdown-it' 3import { MarkdownIt } from 'markdown-it'
4 4
5@Injectable() 5@Injectable()
6export class MarkdownService { 6export class MarkdownService {
@@ -14,30 +14,36 @@ export class MarkdownService {
14 ] 14 ]
15 static ENHANCED_RULES = MarkdownService.TEXT_RULES.concat([ 'image' ]) 15 static ENHANCED_RULES = MarkdownService.TEXT_RULES.concat([ 'image' ])
16 16
17 private textMarkdownIt: MarkdownIt.MarkdownIt 17 private textMarkdownIt: MarkdownIt
18 private enhancedMarkdownIt: MarkdownIt.MarkdownIt 18 private enhancedMarkdownIt: MarkdownIt
19 19
20 constructor () { 20 async textMarkdownToHTML (markdown: string) {
21 this.textMarkdownIt = this.createMarkdownIt(MarkdownService.TEXT_RULES)
22 this.enhancedMarkdownIt = this.createMarkdownIt(MarkdownService.ENHANCED_RULES)
23 }
24
25 textMarkdownToHTML (markdown: string) {
26 if (!markdown) return '' 21 if (!markdown) return ''
27 22
23 if (!this.textMarkdownIt) {
24 this.textMarkdownIt = await this.createMarkdownIt(MarkdownService.TEXT_RULES)
25 }
26
28 const html = this.textMarkdownIt.render(markdown) 27 const html = this.textMarkdownIt.render(markdown)
29 return this.avoidTruncatedTags(html) 28 return this.avoidTruncatedTags(html)
30 } 29 }
31 30
32 enhancedMarkdownToHTML (markdown: string) { 31 async enhancedMarkdownToHTML (markdown: string) {
33 if (!markdown) return '' 32 if (!markdown) return ''
34 33
34 if (!this.enhancedMarkdownIt) {
35 this.enhancedMarkdownIt = await this.createMarkdownIt(MarkdownService.ENHANCED_RULES)
36 }
37
35 const html = this.enhancedMarkdownIt.render(markdown) 38 const html = this.enhancedMarkdownIt.render(markdown)
36 return this.avoidTruncatedTags(html) 39 return this.avoidTruncatedTags(html)
37 } 40 }
38 41
39 private createMarkdownIt (rules: string[]) { 42 private async createMarkdownIt (rules: string[]) {
40 const markdownIt = new MarkdownIt('zero', { linkify: true, breaks: true }) 43 // FIXME: import('..') returns a struct module, containing a "default" field corresponding to our sanitizeHtml function
44 const MarkdownItClass: typeof import ('markdown-it') = (await import('markdown-it') as any).default
45
46 const markdownIt = new MarkdownItClass('zero', { linkify: true, breaks: true })
41 47
42 for (let rule of rules) { 48 for (let rule of rules) {
43 markdownIt.enable(rule) 49 markdownIt.enable(rule)
@@ -48,7 +54,7 @@ export class MarkdownService {
48 return markdownIt 54 return markdownIt
49 } 55 }
50 56
51 private setTargetToLinks (markdownIt: MarkdownIt.MarkdownIt) { 57 private setTargetToLinks (markdownIt: MarkdownIt) {
52 // Snippet from markdown-it documentation: https://github.com/markdown-it/markdown-it/blob/master/docs/architecture.md#renderer 58 // Snippet from markdown-it documentation: https://github.com/markdown-it/markdown-it/blob/master/docs/architecture.md#renderer
53 const defaultRender = markdownIt.renderer.rules.link_open || function (tokens, idx, options, env, self) { 59 const defaultRender = markdownIt.renderer.rules.link_open || function (tokens, idx, options, env, self) {
54 return self.renderToken(tokens, idx, options) 60 return self.renderToken(tokens, idx, options)
diff --git a/client/src/app/shared/users/user-notification.service.ts b/client/src/app/shared/users/user-notification.service.ts
index f8a30955d..ae0bc9cb1 100644
--- a/client/src/app/shared/users/user-notification.service.ts
+++ b/client/src/app/shared/users/user-notification.service.ts
@@ -7,7 +7,7 @@ import { ResultList, UserNotification as UserNotificationServer, UserNotificatio
7import { UserNotification } from './user-notification.model' 7import { UserNotification } from './user-notification.model'
8import { AuthService } from '../../core' 8import { AuthService } from '../../core'
9import { ComponentPagination } from '../rest/component-pagination.model' 9import { ComponentPagination } from '../rest/component-pagination.model'
10import { User } from '..' 10import { User } from '../users/user.model'
11import { UserNotificationSocket } from '@app/core/notification/user-notification-socket.service' 11import { UserNotificationSocket } from '@app/core/notification/user-notification-socket.service'
12 12
13@Injectable() 13@Injectable()
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 aba7f9d1c..172eb0a39 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
@@ -85,8 +85,8 @@ export class VideoCommentComponent implements OnInit, OnChanges {
85 ) 85 )
86 } 86 }
87 87
88 private init () { 88 private async init () {
89 this.sanitizedCommentHTML = this.htmlRenderer.toSafeHtml(this.comment.text) 89 this.sanitizedCommentHTML = await this.htmlRenderer.toSafeHtml(this.comment.text)
90 90
91 this.newParentComments = this.parentComments.concat([ this.comment ]) 91 this.newParentComments = this.parentComments.concat([ this.comment ])
92 } 92 }
diff --git a/client/src/app/videos/+video-watch/modal/video-support.component.ts b/client/src/app/videos/+video-watch/modal/video-support.component.ts
index deb8fbc67..5e7afa012 100644
--- a/client/src/app/videos/+video-watch/modal/video-support.component.ts
+++ b/client/src/app/videos/+video-watch/modal/video-support.component.ts
@@ -21,7 +21,9 @@ export class VideoSupportComponent {
21 ) { } 21 ) { }
22 22
23 show () { 23 show () {
24 this.videoHTMLSupport = this.markdownService.enhancedMarkdownToHTML(this.video.support)
25 this.modalService.open(this.modal) 24 this.modalService.open(this.modal)
25
26 this.markdownService.enhancedMarkdownToHTML(this.video.support)
27 .then(r => this.videoHTMLSupport = r)
26 } 28 }
27} 29}
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 4dbfa41e5..0f04441ba 100644
--- a/client/src/app/videos/+video-watch/video-watch.component.ts
+++ b/client/src/app/videos/+video-watch/video-watch.component.ts
@@ -325,8 +325,8 @@ export class VideoWatchComponent implements OnInit, OnDestroy {
325 this.setVideoDescriptionHTML() 325 this.setVideoDescriptionHTML()
326 } 326 }
327 327
328 private setVideoDescriptionHTML () { 328 private async setVideoDescriptionHTML () {
329 this.videoHTMLDescription = this.markdownService.textMarkdownToHTML(this.video.description) 329 this.videoHTMLDescription = await this.markdownService.textMarkdownToHTML(this.video.description)
330 } 330 }
331 331
332 private setVideoLikesBarTooltipText () { 332 private setVideoLikesBarTooltipText () {
diff --git a/client/src/assets/player/peertube-plugin.ts b/client/src/assets/player/peertube-plugin.ts
index 7ea4a06d4..92ac57cf5 100644
--- a/client/src/assets/player/peertube-plugin.ts
+++ b/client/src/assets/player/peertube-plugin.ts
@@ -22,7 +22,6 @@ import {
22 22
23const Plugin: VideoJSComponentInterface = videojs.getPlugin('plugin') 23const Plugin: VideoJSComponentInterface = videojs.getPlugin('plugin')
24class PeerTubePlugin extends Plugin { 24class PeerTubePlugin extends Plugin {
25 private readonly autoplay: boolean = false
26 private readonly startTime: number = 0 25 private readonly startTime: number = 0
27 private readonly videoViewUrl: string 26 private readonly videoViewUrl: string
28 private readonly videoDuration: number 27 private readonly videoDuration: number
diff --git a/client/src/sass/include/_mixins.scss b/client/src/sass/include/_mixins.scss
index e18e9ae9d..6fb9bf200 100644
--- a/client/src/sass/include/_mixins.scss
+++ b/client/src/sass/include/_mixins.scss
@@ -432,7 +432,7 @@
432 height: 160px; 432 height: 160px;
433 display: flex; 433 display: flex;
434 flex-direction: column; 434 flex-direction: column;
435 align-items: start; 435 align-items: flex-start;
436 436
437 .actor { 437 .actor {
438 display: flex; 438 display: flex;
diff --git a/client/yarn.lock b/client/yarn.lock
index 63394e0f7..2d3ade3dd 100644
--- a/client/yarn.lock
+++ b/client/yarn.lock
@@ -445,6 +445,13 @@
445 resolved "https://registry.yarnpkg.com/@types/jschannel/-/jschannel-1.0.1.tgz#79d582ccf42554c8457230526a3054d018d559f0" 445 resolved "https://registry.yarnpkg.com/@types/jschannel/-/jschannel-1.0.1.tgz#79d582ccf42554c8457230526a3054d018d559f0"
446 integrity sha512-S34NuOoOOKXbft3f9GDeLKp777ABCGArZaqUWOuu1Xn+1S75Osmk8kCeqmw5x2TuASyjE082DwDAuoaXNIRCTw== 446 integrity sha512-S34NuOoOOKXbft3f9GDeLKp777ABCGArZaqUWOuu1Xn+1S75Osmk8kCeqmw5x2TuASyjE082DwDAuoaXNIRCTw==
447 447
448"@types/linkifyjs@^2.1.1":
449 version "2.1.1"
450 resolved "https://registry.yarnpkg.com/@types/linkifyjs/-/linkifyjs-2.1.1.tgz#d6902c165f7108ff9293f7145dfb703fee6814c7"
451 integrity sha512-rTXD/qsdI0aAf1tOtacWaE47K2QLz5C/g7rmB6kYyNuRKWMtStcQjVAM5R/T6kaiR8EVLMwPZ1RqX3aA/CS95g==
452 dependencies:
453 "@types/react" "*"
454
448"@types/lodash-es@^4.17.0": 455"@types/lodash-es@^4.17.0":
449 version "4.17.1" 456 version "4.17.1"
450 resolved "https://registry.yarnpkg.com/@types/lodash-es/-/lodash-es-4.17.1.tgz#56745e5411558362aeca31def918f88f725dd29d" 457 resolved "https://registry.yarnpkg.com/@types/lodash-es/-/lodash-es-4.17.1.tgz#56745e5411558362aeca31def918f88f725dd29d"
@@ -500,11 +507,24 @@
500 "@types/node" "*" 507 "@types/node" "*"
501 "@types/parse-torrent-file" "*" 508 "@types/parse-torrent-file" "*"
502 509
510"@types/prop-types@*":
511 version "15.5.9"
512 resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.5.9.tgz#f2d14df87b0739041bc53a7d75e3d77d726a3ec0"
513 integrity sha512-Nha5b+jmBI271jdTMwrHiNXM+DvThjHOfyZtMX9kj/c/LUj2xiLHsG/1L3tJ8DjAoQN48cHwUwtqBotjyXaSdQ==
514
503"@types/q@^0.0.32": 515"@types/q@^0.0.32":
504 version "0.0.32" 516 version "0.0.32"
505 resolved "https://registry.yarnpkg.com/@types/q/-/q-0.0.32.tgz#bd284e57c84f1325da702babfc82a5328190c0c5" 517 resolved "https://registry.yarnpkg.com/@types/q/-/q-0.0.32.tgz#bd284e57c84f1325da702babfc82a5328190c0c5"
506 integrity sha1-vShOV8hPEyXacCur/IKlMoGQwMU= 518 integrity sha1-vShOV8hPEyXacCur/IKlMoGQwMU=
507 519
520"@types/react@*":
521 version "16.8.3"
522 resolved "https://registry.yarnpkg.com/@types/react/-/react-16.8.3.tgz#7b67956f682bea30a5a09b3242c0784ff196c848"
523 integrity sha512-PjPocAxL9SNLjYMP4dfOShW/rj9FDBJGu3JFRt0zEYf77xfihB6fq8zfDpMrV6s82KnAi7F1OEe5OsQX25Ybdw==
524 dependencies:
525 "@types/prop-types" "*"
526 csstype "^2.2.0"
527
508"@types/sanitize-html@1.18.0": 528"@types/sanitize-html@1.18.0":
509 version "1.18.0" 529 version "1.18.0"
510 resolved "https://registry.yarnpkg.com/@types/sanitize-html/-/sanitize-html-1.18.0.tgz#de5cb560a41308ea8474e93b9d10bbb4050692f5" 530 resolved "https://registry.yarnpkg.com/@types/sanitize-html/-/sanitize-html-1.18.0.tgz#de5cb560a41308ea8474e93b9d10bbb4050692f5"
@@ -2611,6 +2631,11 @@ cssstyle@^1.0.0:
2611 dependencies: 2631 dependencies:
2612 cssom "0.3.x" 2632 cssom "0.3.x"
2613 2633
2634csstype@^2.2.0:
2635 version "2.6.2"
2636 resolved "https://registry.yarnpkg.com/csstype/-/csstype-2.6.2.tgz#3043d5e065454579afc7478a18de41909c8a2f01"
2637 integrity sha512-Rl7PvTae0pflc1YtxtKbiSqq20Ts6vpIYOD5WBafl4y123DyHUeLrRdQP66sQW8/6gmX8jrYJLXwNeMqYVJcow==
2638
2614currently-unhandled@^0.4.1: 2639currently-unhandled@^0.4.1:
2615 version "0.4.1" 2640 version "0.4.1"
2616 resolved "https://registry.yarnpkg.com/currently-unhandled/-/currently-unhandled-0.4.1.tgz#988df33feab191ef799a61369dd76c17adf957ea" 2641 resolved "https://registry.yarnpkg.com/currently-unhandled/-/currently-unhandled-0.4.1.tgz#988df33feab191ef799a61369dd76c17adf957ea"
@@ -9927,12 +9952,7 @@ typedarray@^0.0.6:
9927 resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" 9952 resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777"
9928 integrity sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c= 9953 integrity sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=
9929 9954
9930typescript@3.1.6: 9955typescript@3.2, typescript@3.2.4:
9931 version "3.1.6"
9932 resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.1.6.tgz#b6543a83cfc8c2befb3f4c8fba6896f5b0c9be68"
9933 integrity sha512-tDMYfVtvpb96msS1lDX9MEdHrW4yOuZ4Kdc4Him9oU796XldPYF/t2+uKoX0BBa0hXXwDlqYQbXY5Rzjzc5hBA==
9934
9935typescript@3.2.4:
9936 version "3.2.4" 9956 version "3.2.4"
9937 resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.2.4.tgz#c585cb952912263d915b462726ce244ba510ef3d" 9957 resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.2.4.tgz#c585cb952912263d915b462726ce244ba510ef3d"
9938 integrity sha512-0RNDbSdEokBeEAkgNbxJ+BLwSManFy9TeXz8uW+48j/xhEXv1ePME60olyzw2XzUqUBNAYFeJadIqAgNqIACwg== 9958 integrity sha512-0RNDbSdEokBeEAkgNbxJ+BLwSManFy9TeXz8uW+48j/xhEXv1ePME60olyzw2XzUqUBNAYFeJadIqAgNqIACwg==
diff --git a/server/lib/notifier.ts b/server/lib/notifier.ts
index 2fa320cd7..9cdd603a3 100644
--- a/server/lib/notifier.ts
+++ b/server/lib/notifier.ts
@@ -147,10 +147,13 @@ class Notifier {
147 } 147 }
148 148
149 private async notifyOfCommentMention (comment: VideoCommentModel) { 149 private async notifyOfCommentMention (comment: VideoCommentModel) {
150 const usernames = comment.extractMentions() 150 const extractedUsernames = comment.extractMentions()
151 logger.debug('Extracted %d username from comment %s.', usernames.length, comment.url, { usernames, text: comment.text }) 151 logger.debug(
152 'Extracted %d username from comment %s.', extractedUsernames.length, comment.url,
153 { usernames: extractedUsernames, text: comment.text }
154 )
152 155
153 let users = await UserModel.listByUsernames(usernames) 156 let users = await UserModel.listByUsernames(extractedUsernames)
154 157
155 if (comment.Video.isOwned()) { 158 if (comment.Video.isOwned()) {
156 const userException = await UserModel.loadByVideoId(comment.videoId) 159 const userException = await UserModel.loadByVideoId(comment.videoId)