From 156c50af3085468a47b8ae73fe8cfcae46b42398 Mon Sep 17 00:00:00 2001 From: Lucas Declercq Date: Sat, 6 Oct 2018 19:17:21 +0200 Subject: Add downloadingEnabled property to video model --- client/src/app/shared/video-import/video-import.service.ts | 1 + client/src/app/shared/video/video-details.model.ts | 2 ++ client/src/app/shared/video/video-edit.model.ts | 5 ++++- client/src/app/shared/video/video.service.ts | 1 + .../video-add-components/video-import-torrent.component.ts | 2 ++ .../+video-edit/video-add-components/video-import-url.component.ts | 2 ++ .../+video-edit/video-add-components/video-upload.component.ts | 2 ++ client/src/app/videos/+video-watch/video-watch.component.html | 2 +- client/src/app/videos/+video-watch/video-watch.component.ts | 4 ++++ 9 files changed, 19 insertions(+), 2 deletions(-) (limited to 'client/src/app') diff --git a/client/src/app/shared/video-import/video-import.service.ts b/client/src/app/shared/video-import/video-import.service.ts index 7ae66ddfc..74c458645 100644 --- a/client/src/app/shared/video-import/video-import.service.ts +++ b/client/src/app/shared/video-import/video-import.service.ts @@ -81,6 +81,7 @@ export class VideoImportService { nsfw: video.nsfw, waitTranscoding: video.waitTranscoding, commentsEnabled: video.commentsEnabled, + downloadingEnabled: video.downloadingEnabled, thumbnailfile: video.thumbnailfile, previewfile: video.previewfile, scheduleUpdate diff --git a/client/src/app/shared/video/video-details.model.ts b/client/src/app/shared/video/video-details.model.ts index fa4ca7f93..ad85641dc 100644 --- a/client/src/app/shared/video/video-details.model.ts +++ b/client/src/app/shared/video/video-details.model.ts @@ -12,6 +12,7 @@ export class VideoDetails extends Video implements VideoDetailsServerModel { files: VideoFile[] account: Account commentsEnabled: boolean + downloadingEnabled: boolean waitTranscoding: boolean state: VideoConstant @@ -29,6 +30,7 @@ export class VideoDetails extends Video implements VideoDetailsServerModel { this.tags = hash.tags this.support = hash.support this.commentsEnabled = hash.commentsEnabled + this.downloadingEnabled = hash.downloadingEnabled this.buildLikeAndDislikePercents() } diff --git a/client/src/app/shared/video/video-edit.model.ts b/client/src/app/shared/video/video-edit.model.ts index 0046be964..47703ff79 100644 --- a/client/src/app/shared/video/video-edit.model.ts +++ b/client/src/app/shared/video/video-edit.model.ts @@ -14,6 +14,7 @@ export class VideoEdit implements VideoUpdate { tags: string[] nsfw: boolean commentsEnabled: boolean + downloadingEnabled: boolean waitTranscoding: boolean channelId: number privacy: VideoPrivacy @@ -26,7 +27,7 @@ export class VideoEdit implements VideoUpdate { id?: number scheduleUpdate?: VideoScheduleUpdate - constructor (video?: Video & { tags: string[], commentsEnabled: boolean, support: string, thumbnailUrl: string, previewUrl: string }) { + constructor (video?: Video & { tags: string[], commentsEnabled: boolean, downloadingEnabled: boolean, support: string, thumbnailUrl: string, previewUrl: string }) { if (video) { this.id = video.id this.uuid = video.uuid @@ -38,6 +39,7 @@ export class VideoEdit implements VideoUpdate { this.tags = video.tags this.nsfw = video.nsfw this.commentsEnabled = video.commentsEnabled + this.downloadingEnabled = video.downloadingEnabled this.waitTranscoding = video.waitTranscoding this.channelId = video.channel.id this.privacy = video.privacy.id @@ -80,6 +82,7 @@ export class VideoEdit implements VideoUpdate { tags: this.tags, nsfw: this.nsfw, commentsEnabled: this.commentsEnabled, + downloadingEnabled: this.downloadingEnabled, waitTranscoding: this.waitTranscoding, channelId: this.channelId, privacy: this.privacy diff --git a/client/src/app/shared/video/video.service.ts b/client/src/app/shared/video/video.service.ts index 724a0bde9..c0339dd39 100644 --- a/client/src/app/shared/video/video.service.ts +++ b/client/src/app/shared/video/video.service.ts @@ -95,6 +95,7 @@ export class VideoService implements VideosProvider { nsfw: video.nsfw, waitTranscoding: video.waitTranscoding, commentsEnabled: video.commentsEnabled, + downloadingEnabled: video.downloadingEnabled, thumbnailfile: video.thumbnailfile, previewfile: video.previewfile, scheduleUpdate diff --git a/client/src/app/videos/+video-edit/video-add-components/video-import-torrent.component.ts b/client/src/app/videos/+video-edit/video-add-components/video-import-torrent.component.ts index 0f7184ff8..57cf0e395 100644 --- a/client/src/app/videos/+video-edit/video-add-components/video-import-torrent.component.ts +++ b/client/src/app/videos/+video-edit/video-add-components/video-import-torrent.component.ts @@ -77,6 +77,7 @@ export class VideoImportTorrentComponent extends VideoSend implements OnInit, Ca privacy: this.firstStepPrivacyId, waitTranscoding: false, commentsEnabled: true, + downloadingEnabled: true, channelId: this.firstStepChannelId } @@ -91,6 +92,7 @@ export class VideoImportTorrentComponent extends VideoSend implements OnInit, Ca this.video = new VideoEdit(Object.assign(res.video, { commentsEnabled: videoUpdate.commentsEnabled, + downloadingEnabled: videoUpdate.downloadingEnabled, support: null, thumbnailUrl: null, previewUrl: null diff --git a/client/src/app/videos/+video-edit/video-add-components/video-import-url.component.ts b/client/src/app/videos/+video-edit/video-add-components/video-import-url.component.ts index 031e557ed..11db4a7ef 100644 --- a/client/src/app/videos/+video-edit/video-add-components/video-import-url.component.ts +++ b/client/src/app/videos/+video-edit/video-add-components/video-import-url.component.ts @@ -69,6 +69,7 @@ export class VideoImportUrlComponent extends VideoSend implements OnInit, CanCom privacy: this.firstStepPrivacyId, waitTranscoding: false, commentsEnabled: true, + downloadingEnabled: true, channelId: this.firstStepChannelId } @@ -83,6 +84,7 @@ export class VideoImportUrlComponent extends VideoSend implements OnInit, CanCom this.video = new VideoEdit(Object.assign(res.video, { commentsEnabled: videoUpdate.commentsEnabled, + downloadingEnabled: videoUpdate.downloadingEnabled, support: null, thumbnailUrl: null, previewUrl: null diff --git a/client/src/app/videos/+video-edit/video-add-components/video-upload.component.ts b/client/src/app/videos/+video-edit/video-add-components/video-upload.component.ts index 941dc5441..53f72f4e6 100644 --- a/client/src/app/videos/+video-edit/video-add-components/video-upload.component.ts +++ b/client/src/app/videos/+video-edit/video-add-components/video-upload.component.ts @@ -159,6 +159,7 @@ export class VideoUploadComponent extends VideoSend implements OnInit, OnDestroy const nsfw = false const waitTranscoding = true const commentsEnabled = true + const downloadingEnabled = true const channelId = this.firstStepChannelId.toString() const formData = new FormData() @@ -167,6 +168,7 @@ export class VideoUploadComponent extends VideoSend implements OnInit, OnDestroy formData.append('privacy', VideoPrivacy.PRIVATE.toString()) formData.append('nsfw', '' + nsfw) formData.append('commentsEnabled', '' + commentsEnabled) + formData.append('downloadingEnabled', '' + downloadingEnabled) formData.append('waitTranscoding', '' + waitTranscoding) formData.append('channelId', '' + channelId) formData.append('videofile', videofile) diff --git a/client/src/app/videos/+video-watch/video-watch.component.html b/client/src/app/videos/+video-watch/video-watch.component.html index 770785d02..ba04d638f 100644 --- a/client/src/app/videos/+video-watch/video-watch.component.html +++ b/client/src/app/videos/+video-watch/video-watch.component.html @@ -80,7 +80,7 @@
- + Download 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 c5deddf05..7cc831ab1 100644 --- a/client/src/app/videos/+video-watch/video-watch.component.ts +++ b/client/src/app/videos/+video-watch/video-watch.component.ts @@ -313,6 +313,10 @@ export class VideoWatchComponent implements OnInit, OnDestroy { return this.video && this.video.state.id === VideoState.TO_TRANSCODE } + isVideoDownloadable () { + return this.video && this.video.downloadingEnabled + } + isVideoToImport () { return this.video && this.video.state.id === VideoState.TO_IMPORT } -- cgit v1.2.3 From e0d827e29afc1b29eaf550deb0627c13088c0c65 Mon Sep 17 00:00:00 2001 From: Lucas Declercq Date: Sat, 6 Oct 2018 19:18:00 +0200 Subject: Only show download button if downloadingEnabled is set to true --- client/src/app/videos/+video-edit/shared/video-edit.component.html | 5 +++++ client/src/app/videos/+video-edit/shared/video-edit.component.ts | 2 ++ 2 files changed, 7 insertions(+) (limited to 'client/src/app') diff --git a/client/src/app/videos/+video-edit/shared/video-edit.component.html b/client/src/app/videos/+video-edit/shared/video-edit.component.html index 33c766d87..46eb019b1 100644 --- a/client/src/app/videos/+video-edit/shared/video-edit.component.html +++ b/client/src/app/videos/+video-edit/shared/video-edit.component.html @@ -125,6 +125,11 @@ i18n-labelText labelText="Enable video comments" > + + Date: Mon, 8 Oct 2018 14:42:55 +0200 Subject: Fix some defaults values + indentation --- client/src/app/videos/+video-edit/shared/video-edit.component.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'client/src/app') diff --git a/client/src/app/videos/+video-edit/shared/video-edit.component.html b/client/src/app/videos/+video-edit/shared/video-edit.component.html index 46eb019b1..70d535055 100644 --- a/client/src/app/videos/+video-edit/shared/video-edit.component.html +++ b/client/src/app/videos/+video-edit/shared/video-edit.component.html @@ -126,8 +126,8 @@ > Date: Mon, 8 Oct 2018 14:45:22 +0200 Subject: Rename downloadingEnabled property to downloadEnabled --- client/src/app/shared/video-import/video-import.service.ts | 2 +- client/src/app/shared/video/video-details.model.ts | 4 ++-- client/src/app/shared/video/video-edit.model.ts | 8 ++++---- client/src/app/shared/video/video.service.ts | 2 +- .../src/app/videos/+video-edit/shared/video-edit.component.html | 2 +- client/src/app/videos/+video-edit/shared/video-edit.component.ts | 4 ++-- .../video-add-components/video-import-torrent.component.ts | 4 ++-- .../video-add-components/video-import-url.component.ts | 4 ++-- .../+video-edit/video-add-components/video-upload.component.ts | 4 ++-- client/src/app/videos/+video-watch/video-watch.component.ts | 2 +- 10 files changed, 18 insertions(+), 18 deletions(-) (limited to 'client/src/app') diff --git a/client/src/app/shared/video-import/video-import.service.ts b/client/src/app/shared/video-import/video-import.service.ts index 74c458645..2163eb905 100644 --- a/client/src/app/shared/video-import/video-import.service.ts +++ b/client/src/app/shared/video-import/video-import.service.ts @@ -81,7 +81,7 @@ export class VideoImportService { nsfw: video.nsfw, waitTranscoding: video.waitTranscoding, commentsEnabled: video.commentsEnabled, - downloadingEnabled: video.downloadingEnabled, + downloadEnabled: video.downloadEnabled, thumbnailfile: video.thumbnailfile, previewfile: video.previewfile, scheduleUpdate diff --git a/client/src/app/shared/video/video-details.model.ts b/client/src/app/shared/video/video-details.model.ts index ad85641dc..5ff3926c4 100644 --- a/client/src/app/shared/video/video-details.model.ts +++ b/client/src/app/shared/video/video-details.model.ts @@ -12,7 +12,7 @@ export class VideoDetails extends Video implements VideoDetailsServerModel { files: VideoFile[] account: Account commentsEnabled: boolean - downloadingEnabled: boolean + downloadEnabled: boolean waitTranscoding: boolean state: VideoConstant @@ -30,7 +30,7 @@ export class VideoDetails extends Video implements VideoDetailsServerModel { this.tags = hash.tags this.support = hash.support this.commentsEnabled = hash.commentsEnabled - this.downloadingEnabled = hash.downloadingEnabled + this.downloadEnabled = hash.downloadEnabled this.buildLikeAndDislikePercents() } diff --git a/client/src/app/shared/video/video-edit.model.ts b/client/src/app/shared/video/video-edit.model.ts index 47703ff79..e385004e5 100644 --- a/client/src/app/shared/video/video-edit.model.ts +++ b/client/src/app/shared/video/video-edit.model.ts @@ -14,7 +14,7 @@ export class VideoEdit implements VideoUpdate { tags: string[] nsfw: boolean commentsEnabled: boolean - downloadingEnabled: boolean + downloadEnabled: boolean waitTranscoding: boolean channelId: number privacy: VideoPrivacy @@ -27,7 +27,7 @@ export class VideoEdit implements VideoUpdate { id?: number scheduleUpdate?: VideoScheduleUpdate - constructor (video?: Video & { tags: string[], commentsEnabled: boolean, downloadingEnabled: boolean, support: string, thumbnailUrl: string, previewUrl: string }) { + constructor (video?: Video & { tags: string[], commentsEnabled: boolean, downloadEnabled: boolean, support: string, thumbnailUrl: string, previewUrl: string }) { if (video) { this.id = video.id this.uuid = video.uuid @@ -39,7 +39,7 @@ export class VideoEdit implements VideoUpdate { this.tags = video.tags this.nsfw = video.nsfw this.commentsEnabled = video.commentsEnabled - this.downloadingEnabled = video.downloadingEnabled + this.downloadEnabled = video.downloadEnabled this.waitTranscoding = video.waitTranscoding this.channelId = video.channel.id this.privacy = video.privacy.id @@ -82,7 +82,7 @@ export class VideoEdit implements VideoUpdate { tags: this.tags, nsfw: this.nsfw, commentsEnabled: this.commentsEnabled, - downloadingEnabled: this.downloadingEnabled, + downloadEnabled: this.downloadEnabled, waitTranscoding: this.waitTranscoding, channelId: this.channelId, privacy: this.privacy diff --git a/client/src/app/shared/video/video.service.ts b/client/src/app/shared/video/video.service.ts index c0339dd39..c9d6da7a4 100644 --- a/client/src/app/shared/video/video.service.ts +++ b/client/src/app/shared/video/video.service.ts @@ -95,7 +95,7 @@ export class VideoService implements VideosProvider { nsfw: video.nsfw, waitTranscoding: video.waitTranscoding, commentsEnabled: video.commentsEnabled, - downloadingEnabled: video.downloadingEnabled, + downloadEnabled: video.downloadEnabled, thumbnailfile: video.thumbnailfile, previewfile: video.previewfile, scheduleUpdate diff --git a/client/src/app/videos/+video-edit/shared/video-edit.component.html b/client/src/app/videos/+video-edit/shared/video-edit.component.html index 70d535055..8c74a1ca6 100644 --- a/client/src/app/videos/+video-edit/shared/video-edit.component.html +++ b/client/src/app/videos/+video-edit/shared/video-edit.component.html @@ -126,7 +126,7 @@ > diff --git a/client/src/app/videos/+video-edit/shared/video-edit.component.ts b/client/src/app/videos/+video-edit/shared/video-edit.component.ts index b09664376..1dae931e2 100644 --- a/client/src/app/videos/+video-edit/shared/video-edit.component.ts +++ b/client/src/app/videos/+video-edit/shared/video-edit.component.ts @@ -80,7 +80,7 @@ export class VideoEditComponent implements OnInit, OnDestroy { const defaultValues = { nsfw: 'false', commentsEnabled: 'true', - downloadingEnabled: 'true', + downloadEnabled: 'true', waitTranscoding: 'true', tags: [] } @@ -90,7 +90,7 @@ export class VideoEditComponent implements OnInit, OnDestroy { channelId: this.videoValidatorsService.VIDEO_CHANNEL, nsfw: null, commentsEnabled: null, - downloadingEnabled: null, + downloadEnabled: null, waitTranscoding: null, category: this.videoValidatorsService.VIDEO_CATEGORY, licence: this.videoValidatorsService.VIDEO_LICENCE, diff --git a/client/src/app/videos/+video-edit/video-add-components/video-import-torrent.component.ts b/client/src/app/videos/+video-edit/video-add-components/video-import-torrent.component.ts index 57cf0e395..0f6fd17a9 100644 --- a/client/src/app/videos/+video-edit/video-add-components/video-import-torrent.component.ts +++ b/client/src/app/videos/+video-edit/video-add-components/video-import-torrent.component.ts @@ -77,7 +77,7 @@ export class VideoImportTorrentComponent extends VideoSend implements OnInit, Ca privacy: this.firstStepPrivacyId, waitTranscoding: false, commentsEnabled: true, - downloadingEnabled: true, + downloadEnabled: true, channelId: this.firstStepChannelId } @@ -92,7 +92,7 @@ export class VideoImportTorrentComponent extends VideoSend implements OnInit, Ca this.video = new VideoEdit(Object.assign(res.video, { commentsEnabled: videoUpdate.commentsEnabled, - downloadingEnabled: videoUpdate.downloadingEnabled, + downloadEnabled: videoUpdate.downloadEnabled, support: null, thumbnailUrl: null, previewUrl: null diff --git a/client/src/app/videos/+video-edit/video-add-components/video-import-url.component.ts b/client/src/app/videos/+video-edit/video-add-components/video-import-url.component.ts index 11db4a7ef..fbc85c74f 100644 --- a/client/src/app/videos/+video-edit/video-add-components/video-import-url.component.ts +++ b/client/src/app/videos/+video-edit/video-add-components/video-import-url.component.ts @@ -69,7 +69,7 @@ export class VideoImportUrlComponent extends VideoSend implements OnInit, CanCom privacy: this.firstStepPrivacyId, waitTranscoding: false, commentsEnabled: true, - downloadingEnabled: true, + downloadEnabled: true, channelId: this.firstStepChannelId } @@ -84,7 +84,7 @@ export class VideoImportUrlComponent extends VideoSend implements OnInit, CanCom this.video = new VideoEdit(Object.assign(res.video, { commentsEnabled: videoUpdate.commentsEnabled, - downloadingEnabled: videoUpdate.downloadingEnabled, + downloadEnabled: videoUpdate.downloadEnabled, support: null, thumbnailUrl: null, previewUrl: null diff --git a/client/src/app/videos/+video-edit/video-add-components/video-upload.component.ts b/client/src/app/videos/+video-edit/video-add-components/video-upload.component.ts index 53f72f4e6..ac6c1786f 100644 --- a/client/src/app/videos/+video-edit/video-add-components/video-upload.component.ts +++ b/client/src/app/videos/+video-edit/video-add-components/video-upload.component.ts @@ -159,7 +159,7 @@ export class VideoUploadComponent extends VideoSend implements OnInit, OnDestroy const nsfw = false const waitTranscoding = true const commentsEnabled = true - const downloadingEnabled = true + const downloadEnabled = true const channelId = this.firstStepChannelId.toString() const formData = new FormData() @@ -168,7 +168,7 @@ export class VideoUploadComponent extends VideoSend implements OnInit, OnDestroy formData.append('privacy', VideoPrivacy.PRIVATE.toString()) formData.append('nsfw', '' + nsfw) formData.append('commentsEnabled', '' + commentsEnabled) - formData.append('downloadingEnabled', '' + downloadingEnabled) + formData.append('downloadEnabled', '' + downloadEnabled) formData.append('waitTranscoding', '' + waitTranscoding) formData.append('channelId', '' + channelId) formData.append('videofile', videofile) 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 7cc831ab1..a7fd45695 100644 --- a/client/src/app/videos/+video-watch/video-watch.component.ts +++ b/client/src/app/videos/+video-watch/video-watch.component.ts @@ -314,7 +314,7 @@ export class VideoWatchComponent implements OnInit, OnDestroy { } isVideoDownloadable () { - return this.video && this.video.downloadingEnabled + return this.video && this.video.downloadEnabled } isVideoToImport () { -- cgit v1.2.3 From 8ea1597fdbb2eb8ef71e805cf175e88ae05629c0 Mon Sep 17 00:00:00 2001 From: Lucas Declercq Date: Mon, 8 Oct 2018 16:33:02 +0200 Subject: Fix too big line length --- client/src/app/shared/video/video-edit.model.ts | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) (limited to 'client/src/app') diff --git a/client/src/app/shared/video/video-edit.model.ts b/client/src/app/shared/video/video-edit.model.ts index e385004e5..5bb0510f9 100644 --- a/client/src/app/shared/video/video-edit.model.ts +++ b/client/src/app/shared/video/video-edit.model.ts @@ -27,7 +27,15 @@ export class VideoEdit implements VideoUpdate { id?: number scheduleUpdate?: VideoScheduleUpdate - constructor (video?: Video & { tags: string[], commentsEnabled: boolean, downloadEnabled: boolean, support: string, thumbnailUrl: string, previewUrl: string }) { + constructor ( + video?: Video & { + tags: string[], + commentsEnabled: boolean, + downloadEnabled: boolean, + support: string, + thumbnailUrl: string, + previewUrl: string + }) { if (video) { this.id = video.id this.uuid = video.uuid -- cgit v1.2.3 From 5abb9fbbd12e7097e348d6a38622d364b1fa47ed Mon Sep 17 00:00:00 2001 From: Chocobozzz Date: Thu, 10 Jan 2019 15:39:51 +0100 Subject: Add ability to unfederate a local video (on blacklist) --- .../video-blacklist-list/video-blacklist-list.component.html | 6 ++++-- .../video-blacklist-list/video-blacklist-list.component.ts | 6 ++++++ client/src/app/+admin/users/user-list/user-list.component.html | 3 +++ .../src/app/shared/video-blacklist/video-blacklist.service.ts | 7 +++++-- .../videos/+video-watch/modal/video-blacklist.component.html | 7 +++++++ .../app/videos/+video-watch/modal/video-blacklist.component.ts | 10 +++++++--- 6 files changed, 32 insertions(+), 7 deletions(-) (limited to 'client/src/app') 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 7cef787d2..6398af218 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 @@ -7,6 +7,7 @@ Video name Sensitive + Unfederated Date @@ -26,7 +27,8 @@ - {{ videoBlacklist.video.nsfw }} + {{ booleanToText(videoBlacklist.video.nsfw) }} + {{ booleanToText(videoBlacklist.unfederated) }} {{ videoBlacklist.createdAt }} @@ -37,7 +39,7 @@ - + Blacklist reason: {{ videoBlacklist.reason }} 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 a02e84f67..6c6f17f0c 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 @@ -46,6 +46,12 @@ export class VideoBlacklistListComponent extends RestTable implements OnInit { return Video.buildClientUrl(videoBlacklist.video.uuid) } + booleanToText (value: boolean) { + if (value === true) return this.i18n('yes') + + return this.i18n('no') + } + async removeVideoFromBlacklist (entry: VideoBlacklist) { const confirmMessage = this.i18n( 'Do you really want to remove this video from the blacklist? It will be available again in the videos list.' diff --git a/client/src/app/+admin/users/user-list/user-list.component.html b/client/src/app/+admin/users/user-list/user-list.component.html index 556ab3c5d..8c03a924b 100644 --- a/client/src/app/+admin/users/user-list/user-list.component.html +++ b/client/src/app/+admin/users/user-list/user-list.component.html @@ -65,7 +65,9 @@ (banned) + {{ user.email }} + ? {{ user.email }} @@ -76,6 +78,7 @@ + {{ user.videoQuotaUsed }} / {{ user.videoQuota }} {{ user.roleLabel }} {{ user.createdAt }} diff --git a/client/src/app/shared/video-blacklist/video-blacklist.service.ts b/client/src/app/shared/video-blacklist/video-blacklist.service.ts index 7d39fd4f2..94e46d7c2 100644 --- a/client/src/app/shared/video-blacklist/video-blacklist.service.ts +++ b/client/src/app/shared/video-blacklist/video-blacklist.service.ts @@ -36,8 +36,11 @@ export class VideoBlacklistService { ) } - blacklistVideo (videoId: number, reason?: string) { - const body = reason ? { reason } : {} + blacklistVideo (videoId: number, reason: string, unfederate: boolean) { + const body = { + unfederate, + reason + } return this.authHttp.post(VideoBlacklistService.BASE_VIDEOS_URL + videoId + '/blacklist', body) .pipe( diff --git a/client/src/app/videos/+video-watch/modal/video-blacklist.component.html b/client/src/app/videos/+video-watch/modal/video-blacklist.component.html index c436501b4..83600fa81 100644 --- a/client/src/app/videos/+video-watch/modal/video-blacklist.component.html +++ b/client/src/app/videos/+video-watch/modal/video-blacklist.component.html @@ -15,6 +15,13 @@
+
+ +
+
Cancel diff --git a/client/src/app/videos/+video-watch/modal/video-blacklist.component.ts b/client/src/app/videos/+video-watch/modal/video-blacklist.component.ts index 357ce39ce..50a7cadd1 100644 --- a/client/src/app/videos/+video-watch/modal/video-blacklist.component.ts +++ b/client/src/app/videos/+video-watch/modal/video-blacklist.component.ts @@ -34,9 +34,12 @@ export class VideoBlacklistComponent extends FormReactive implements OnInit { } ngOnInit () { + const defaultValues = { unfederate: 'true' } + this.buildForm({ - reason: this.videoBlacklistValidatorsService.VIDEO_BLACKLIST_REASON - }) + reason: this.videoBlacklistValidatorsService.VIDEO_BLACKLIST_REASON, + unfederate: null + }, defaultValues) } show () { @@ -50,8 +53,9 @@ export class VideoBlacklistComponent extends FormReactive implements OnInit { blacklist () { const reason = this.form.value[ 'reason' ] || undefined + const unfederate = this.video.isLocal ? this.form.value[ 'unfederate' ] : undefined - this.videoBlacklistService.blacklistVideo(this.video.id, reason) + this.videoBlacklistService.blacklistVideo(this.video.id, reason, unfederate) .subscribe( () => { this.notifier.success(this.i18n('Video blacklisted.')) -- cgit v1.2.3 From 9b4b15f91c485f9a7fe2ed314b4101f4b7506b38 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aur=C3=A9lien=20B=C3=A9ranger?= <43744761+auberanger@users.noreply.github.com> Date: Mon, 14 Jan 2019 09:06:48 +0100 Subject: WIP : Indicate to users how "trending" works (#1458) * Get the INTERVAL_DAYS const in the video-trending component * Change Trending section title * Add a tooltip to explain how trending section works * Minor CSS fix for the my-feed popover next to the titlepage --- client/src/app/core/server/server.service.ts | 5 +++++ client/src/app/shared/video/abstract-video-list.html | 5 ++++- client/src/app/shared/video/abstract-video-list.scss | 2 +- client/src/app/shared/video/abstract-video-list.ts | 2 ++ client/src/app/videos/video-list/video-trending.component.ts | 12 ++++++++++-- 5 files changed, 22 insertions(+), 4 deletions(-) (limited to 'client/src/app') diff --git a/client/src/app/core/server/server.service.ts b/client/src/app/core/server/server.service.ts index f33e6f20c..4ae72427b 100644 --- a/client/src/app/core/server/server.service.ts +++ b/client/src/app/core/server/server.service.ts @@ -87,6 +87,11 @@ export class ServerService { enabled: false } } + }, + trending: { + videos: { + intervalDays: 0 + } } } private videoCategories: Array> = [] diff --git a/client/src/app/shared/video/abstract-video-list.html b/client/src/app/shared/video/abstract-video-list.html index 29492351b..1f97bc389 100644 --- a/client/src/app/shared/video/abstract-video-list.html +++ b/client/src/app/shared/video/abstract-video-list.html @@ -1,8 +1,11 @@
- {{ titlePage }} +
+ {{ titlePage }} +
+
diff --git a/client/src/app/shared/video/abstract-video-list.scss b/client/src/app/shared/video/abstract-video-list.scss index 9fb3fd4d6..292ede698 100644 --- a/client/src/app/shared/video/abstract-video-list.scss +++ b/client/src/app/shared/video/abstract-video-list.scss @@ -19,8 +19,8 @@ my-feed { display: inline-block; - position: relative; top: 1px; + min-width: 60px; } .moderation-block { diff --git a/client/src/app/shared/video/abstract-video-list.ts b/client/src/app/shared/video/abstract-video-list.ts index d234c8bfa..d74384293 100644 --- a/client/src/app/shared/video/abstract-video-list.ts +++ b/client/src/app/shared/video/abstract-video-list.ts @@ -39,6 +39,8 @@ export abstract class AbstractVideoList implements OnInit, OnDestroy { ownerDisplayType: OwnerDisplayType = 'account' firstLoadedPage: number displayModerationBlock = false + trendingDays: number + titleTooltip: string protected baseVideoWidth = 215 protected baseVideoHeight = 205 diff --git a/client/src/app/videos/video-list/video-trending.component.ts b/client/src/app/videos/video-list/video-trending.component.ts index accc5bfe5..d3c0f5316 100644 --- a/client/src/app/videos/video-list/video-trending.component.ts +++ b/client/src/app/videos/video-list/video-trending.component.ts @@ -8,7 +8,7 @@ import { VideoSortField } from '../../shared/video/sort-field.type' import { VideoService } from '../../shared/video/video.service' import { I18n } from '@ngx-translate/i18n-polyfill' import { ScreenService } from '@app/shared/misc/screen.service' -import { Notifier } from '@app/core' +import { Notifier, ServerService } from '@app/core' @Component({ selector: 'my-videos-trending', @@ -19,6 +19,7 @@ export class VideoTrendingComponent extends AbstractVideoList implements OnInit, titlePage: string currentRoute = '/videos/trending' defaultSort: VideoSortField = '-trending' + trendingDays: number constructor ( protected router: Router, @@ -27,12 +28,19 @@ export class VideoTrendingComponent extends AbstractVideoList implements OnInit, protected authService: AuthService, protected location: Location, protected screenService: ScreenService, + private serverService: ServerService, protected i18n: I18n, private videoService: VideoService ) { super() - this.titlePage = i18n('Trending') + this.trendingDays = this.serverService.getConfig().trending.videos.intervalDays + + this.titlePage = this.i18n('Trending for the last ') + this.trendingDays === 1 ? this.titlePage += '24 hours' : this.titlePage += this.trendingDays + ' days' + + this.titleTooltip = this.i18n('trending videos are those totalizing the greatest number of views during the last ') + this.trendingDays === 1 ? this.titleTooltip += '24 hours.' : this.titleTooltip += this.trendingDays + ' days.' } ngOnInit () { -- cgit v1.2.3 From f242c2e01e3423ad63a9a6d904062256d60b6971 Mon Sep 17 00:00:00 2001 From: Chocobozzz Date: Thu, 10 Jan 2019 16:28:31 +0100 Subject: Improve "no notifications" message --- client/src/app/menu/avatar-notification.component.scss | 1 + client/src/app/shared/users/user-notifications.component.scss | 7 +++++++ 2 files changed, 8 insertions(+) (limited to 'client/src/app') diff --git a/client/src/app/menu/avatar-notification.component.scss b/client/src/app/menu/avatar-notification.component.scss index c86667469..47d04ace3 100644 --- a/client/src/app/menu/avatar-notification.component.scss +++ b/client/src/app/menu/avatar-notification.component.scss @@ -11,6 +11,7 @@ font-family: $main-fonts; overflow-y: auto; max-height: 500px; + min-width: 200px; box-shadow: 0 6px 14px rgba(0, 0, 0, 0.30); .notifications-header { diff --git a/client/src/app/shared/users/user-notifications.component.scss b/client/src/app/shared/users/user-notifications.component.scss index 0493b10d9..0ae26ea39 100644 --- a/client/src/app/shared/users/user-notifications.component.scss +++ b/client/src/app/shared/users/user-notifications.component.scss @@ -1,3 +1,10 @@ +.no-notification { + display: flex; + justify-content: center; + align-items: center; + padding: 20px 0; +} + .notification { display: flex; justify-content: space-between; -- cgit v1.2.3 From 033bc0efc2ab2c517b4d7d53d09930b85f092b50 Mon Sep 17 00:00:00 2001 From: Chocobozzz Date: Fri, 11 Jan 2019 16:58:33 +0100 Subject: Fix NSFW blur on search --- client/src/app/search/search.component.html | 2 +- client/src/app/search/search.component.ts | 9 +++++++-- 2 files changed, 8 insertions(+), 3 deletions(-) (limited to 'client/src/app') diff --git a/client/src/app/search/search.component.html b/client/src/app/search/search.component.html index 3a87ea1de..82a5f0f26 100644 --- a/client/src/app/search/search.component.html +++ b/client/src/app/search/search.component.html @@ -48,7 +48,7 @@
- +
{{ result.name }} diff --git a/client/src/app/search/search.component.ts b/client/src/app/search/search.component.ts index 474b72824..c4a4b1fde 100644 --- a/client/src/app/search/search.component.ts +++ b/client/src/app/search/search.component.ts @@ -1,6 +1,6 @@ import { Component, OnDestroy, OnInit } from '@angular/core' import { ActivatedRoute, Router } from '@angular/router' -import { AuthService, Notifier } from '@app/core' +import { AuthService, Notifier, ServerService } from '@app/core' import { forkJoin, Subscription } from 'rxjs' import { SearchService } from '@app/search/search.service' import { ComponentPagination } from '@app/shared/rest/component-pagination.model' @@ -41,7 +41,8 @@ export class SearchComponent implements OnInit, OnDestroy { private metaService: MetaService, private notifier: Notifier, private searchService: SearchService, - private authService: AuthService + private authService: AuthService, + private serverService: ServerService ) { } ngOnInit () { @@ -75,6 +76,10 @@ export class SearchComponent implements OnInit, OnDestroy { if (this.subActivatedRoute) this.subActivatedRoute.unsubscribe() } + isVideoBlur (video: Video) { + return video.isVideoNSFWForUser(this.authService.getUser(), this.serverService.getConfig()) + } + isVideoChannel (d: VideoChannel | Video): d is VideoChannel { return d instanceof VideoChannel } -- cgit v1.2.3 From 7b95f31385eca59ac18197539de30268acc18986 Mon Sep 17 00:00:00 2001 From: Chocobozzz Date: Mon, 14 Jan 2019 09:11:28 +0100 Subject: Help translators to translate trending title/tooltip --- client/src/app/shared/video/abstract-video-list.ts | 1 - .../videos/video-list/video-trending.component.ts | 22 +++++++++++++--------- 2 files changed, 13 insertions(+), 10 deletions(-) (limited to 'client/src/app') diff --git a/client/src/app/shared/video/abstract-video-list.ts b/client/src/app/shared/video/abstract-video-list.ts index d74384293..b0633be4a 100644 --- a/client/src/app/shared/video/abstract-video-list.ts +++ b/client/src/app/shared/video/abstract-video-list.ts @@ -39,7 +39,6 @@ export abstract class AbstractVideoList implements OnInit, OnDestroy { ownerDisplayType: OwnerDisplayType = 'account' firstLoadedPage: number displayModerationBlock = false - trendingDays: number titleTooltip: string protected baseVideoWidth = 215 diff --git a/client/src/app/videos/video-list/video-trending.component.ts b/client/src/app/videos/video-list/video-trending.component.ts index d3c0f5316..881ab2174 100644 --- a/client/src/app/videos/video-list/video-trending.component.ts +++ b/client/src/app/videos/video-list/video-trending.component.ts @@ -19,7 +19,6 @@ export class VideoTrendingComponent extends AbstractVideoList implements OnInit, titlePage: string currentRoute = '/videos/trending' defaultSort: VideoSortField = '-trending' - trendingDays: number constructor ( protected router: Router, @@ -33,20 +32,25 @@ export class VideoTrendingComponent extends AbstractVideoList implements OnInit, private videoService: VideoService ) { super() - - this.trendingDays = this.serverService.getConfig().trending.videos.intervalDays - - this.titlePage = this.i18n('Trending for the last ') - this.trendingDays === 1 ? this.titlePage += '24 hours' : this.titlePage += this.trendingDays + ' days' - - this.titleTooltip = this.i18n('trending videos are those totalizing the greatest number of views during the last ') - this.trendingDays === 1 ? this.titleTooltip += '24 hours.' : this.titleTooltip += this.trendingDays + ' days.' } ngOnInit () { super.ngOnInit() this.generateSyndicationList() + + const trendingDays = this.serverService.getConfig().trending.videos.intervalDays + + if (trendingDays === 1) { + this.titlePage = this.i18n('Trending for the last 24 hours') + this.titleTooltip = this.i18n('Trending videos are those totalizing the greatest number of views during the last 24 hours.') + } else { + this.titlePage = this.i18n('Trending for the last {{days}} days', { days: trendingDays }) + this.titleTooltip = this.i18n( + 'Trending videos are those totalizing the greatest number of views during the last {{days}} days.', + { days: trendingDays } + ) + } } ngOnDestroy () { -- cgit v1.2.3 From b4593cd7ff34b94b60f6bfa0b57e371d74d63aa2 Mon Sep 17 00:00:00 2001 From: Chocobozzz Date: Mon, 14 Jan 2019 10:24:49 +0100 Subject: Warn user when they want to delete a channel Because they will not be able to create another channel with the same actor name --- .../my-account-video-channels.component.ts | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) (limited to 'client/src/app') diff --git a/client/src/app/+my-account/my-account-video-channels/my-account-video-channels.component.ts b/client/src/app/+my-account/my-account-video-channels/my-account-video-channels.component.ts index 0ab3e2067..da2c5bcd3 100644 --- a/client/src/app/+my-account/my-account-video-channels/my-account-video-channels.component.ts +++ b/client/src/app/+my-account/my-account-video-channels/my-account-video-channels.component.ts @@ -35,10 +35,14 @@ export class MyAccountVideoChannelsComponent implements OnInit { async deleteVideoChannel (videoChannel: VideoChannel) { const res = await this.confirmService.confirmWithInput( this.i18n( - 'Do you really want to delete {{videoChannelName}}? It will delete all videos uploaded in this channel too.', - { videoChannelName: videoChannel.displayName } + 'Do you really want to delete {{channelDisplayName}}? It will delete all videos uploaded in this channel, ' + + 'and you will not be able to create another channel with the same name ({{channelName}})!', + { channelDisplayName: videoChannel.displayName, channelName: videoChannel.name } + ), + this.i18n( + 'Please type the display name of the video channel ({{displayName}}) to confirm', + { displayName: videoChannel.displayName } ), - this.i18n('Please type the name of the video channel to confirm'), videoChannel.displayName, this.i18n('Delete') ) -- cgit v1.2.3 From b5487ff4a5c0bb2acaca79ee00df26a83886c889 Mon Sep 17 00:00:00 2001 From: Chocobozzz Date: Mon, 14 Jan 2019 11:52:15 +0100 Subject: Add error message when trying to upload .ass subtitles --- client/src/app/shared/forms/reactive-file.component.ts | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'client/src/app') diff --git a/client/src/app/shared/forms/reactive-file.component.ts b/client/src/app/shared/forms/reactive-file.component.ts index c3986838f..f60c38e8d 100644 --- a/client/src/app/shared/forms/reactive-file.component.ts +++ b/client/src/app/shared/forms/reactive-file.component.ts @@ -53,6 +53,17 @@ export class ReactiveFileComponent implements OnInit, ControlValueAccessor { return } + const extension = '.' + file.name.split('.').pop() + if (this.extensions.includes(extension) === false) { + const message = this.i18n( + 'PeerTube cannot handle this kind of file. Accepted extensions are {{extensions}}.', + { extensions: this.allowedExtensionsMessage } + ) + this.notifier.error(message) + + return + } + this.file = file this.propagateChange(this.file) -- cgit v1.2.3 From 674a66bbda7ceb7aed3c2e6aefddc2793207d94b Mon Sep 17 00:00:00 2001 From: Chocobozzz Date: Mon, 14 Jan 2019 14:55:43 +0100 Subject: Add unload listener on video upload/update --- .../video-add-components/video-upload.component.html | 4 ++++ .../app/videos/+video-edit/video-add.component.ts | 14 ++++++++++++-- .../app/videos/+video-edit/video-update.component.ts | 20 ++++++++++++++++---- 3 files changed, 32 insertions(+), 6 deletions(-) (limited to 'client/src/app') diff --git a/client/src/app/videos/+video-edit/video-add-components/video-upload.component.html b/client/src/app/videos/+video-edit/video-add-components/video-upload.component.html index 289a28c66..826e54d25 100644 --- a/client/src/app/videos/+video-edit/video-add-components/video-upload.component.html +++ b/client/src/app/videos/+video-edit/video-add-components/video-upload.component.html @@ -42,6 +42,10 @@ {{ error }}
+
+ Congratulations! Your video is now available in your private library. +
+
Date: Mon, 14 Jan 2019 15:12:20 +0100 Subject: Fix scroll in notifications page --- client/src/app/menu/avatar-notification.component.scss | 1 + client/src/app/shared/users/user-notifications.component.ts | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) (limited to 'client/src/app') diff --git a/client/src/app/menu/avatar-notification.component.scss b/client/src/app/menu/avatar-notification.component.scss index 47d04ace3..807385022 100644 --- a/client/src/app/menu/avatar-notification.component.scss +++ b/client/src/app/menu/avatar-notification.component.scss @@ -13,6 +13,7 @@ max-height: 500px; min-width: 200px; box-shadow: 0 6px 14px rgba(0, 0, 0, 0.30); + overflow-y: auto; .notifications-header { display: flex; diff --git a/client/src/app/shared/users/user-notifications.component.ts b/client/src/app/shared/users/user-notifications.component.ts index 682116226..50c495a9a 100644 --- a/client/src/app/shared/users/user-notifications.component.ts +++ b/client/src/app/shared/users/user-notifications.component.ts @@ -21,7 +21,7 @@ export class UserNotificationsComponent implements OnInit { componentPagination: ComponentPagination = { currentPage: 1, - itemsPerPage: 10, + itemsPerPage: 20, totalItems: null } -- cgit v1.2.3 From 9a39392a7e6b3f180104856a4ea893e5baf86a02 Mon Sep 17 00:00:00 2001 From: Chocobozzz Date: Mon, 14 Jan 2019 15:32:09 +0100 Subject: Fix notification socket Should be in core module to share the same subject to all the app --- client/src/app/core/auth/auth.service.ts | 4 +-- client/src/app/core/core.module.ts | 4 ++- client/src/app/core/notification/index.ts | 1 + .../user-notification-socket.service.ts | 41 +++++++++++++++++++++ .../app/menu/avatar-notification.component.html | 2 +- .../src/app/menu/avatar-notification.component.ts | 5 +-- .../app/shared/users/user-notification.service.ts | 42 ++++++---------------- .../shared/users/user-notifications.component.ts | 3 +- 8 files changed, 63 insertions(+), 39 deletions(-) create mode 100644 client/src/app/core/notification/user-notification-socket.service.ts (limited to 'client/src/app') diff --git a/client/src/app/core/auth/auth.service.ts b/client/src/app/core/auth/auth.service.ts index 79ea32ced..eaa822e0f 100644 --- a/client/src/app/core/auth/auth.service.ts +++ b/client/src/app/core/auth/auth.service.ts @@ -3,12 +3,12 @@ import { catchError, map, mergeMap, share, tap } from 'rxjs/operators' import { HttpClient, HttpHeaders, HttpParams } from '@angular/common/http' import { Injectable } from '@angular/core' import { Router } from '@angular/router' -import { Notifier } from '@app/core/notification' +import { Notifier } from '@app/core/notification/notifier.service' import { OAuthClientLocal, User as UserServerModel, UserRefreshToken } from '../../../../../shared' import { User } from '../../../../../shared/models/users' import { UserLogin } from '../../../../../shared/models/users/user-login.model' import { environment } from '../../../environments/environment' -import { RestExtractor } from '../../shared/rest' +import { RestExtractor } from '../../shared/rest/rest-extractor.service' import { AuthStatus } from './auth-status.model' import { AuthUser } from './auth-user.model' import { objectToUrlEncoded } from '@app/shared/misc/utils' diff --git a/client/src/app/core/core.module.ts b/client/src/app/core/core.module.ts index 7c0d4ac8f..3bc0e2885 100644 --- a/client/src/app/core/core.module.ts +++ b/client/src/app/core/core.module.ts @@ -18,6 +18,7 @@ import { CheatSheetComponent } from './hotkeys' import { ToastModule } from 'primeng/toast' import { Notifier } from './notification' import { MessageService } from 'primeng/api' +import { UserNotificationSocket } from '@app/core/notification/user-notification-socket.service' @NgModule({ imports: [ @@ -60,7 +61,8 @@ import { MessageService } from 'primeng/api' UserRightGuard, RedirectService, Notifier, - MessageService + MessageService, + UserNotificationSocket ] }) export class CoreModule { diff --git a/client/src/app/core/notification/index.ts b/client/src/app/core/notification/index.ts index 8b0cfde5f..3e8d9ea65 100644 --- a/client/src/app/core/notification/index.ts +++ b/client/src/app/core/notification/index.ts @@ -1 +1,2 @@ export * from './notifier.service' +export * from './user-notification-socket.service' diff --git a/client/src/app/core/notification/user-notification-socket.service.ts b/client/src/app/core/notification/user-notification-socket.service.ts new file mode 100644 index 000000000..f367d9ae4 --- /dev/null +++ b/client/src/app/core/notification/user-notification-socket.service.ts @@ -0,0 +1,41 @@ +import { Injectable } from '@angular/core' +import { environment } from '../../../environments/environment' +import { UserNotification as UserNotificationServer } from '../../../../../shared' +import { Subject } from 'rxjs' +import * as io from 'socket.io-client' +import { AuthService } from '../auth' + +export type NotificationEvent = 'new' | 'read' | 'read-all' + +@Injectable() +export class UserNotificationSocket { + private notificationSubject = new Subject<{ type: NotificationEvent, notification?: UserNotificationServer }>() + + private socket: SocketIOClient.Socket + + constructor ( + private auth: AuthService + ) {} + + dispatch (type: NotificationEvent, notification?: UserNotificationServer) { + this.notificationSubject.next({ type, notification }) + } + + getMyNotificationsSocket () { + const socket = this.getSocket() + + socket.on('new-notification', (n: UserNotificationServer) => this.dispatch('new', n)) + + return this.notificationSubject.asObservable() + } + + private getSocket () { + if (this.socket) return this.socket + + this.socket = io(environment.apiUrl + '/user-notifications', { + query: { accessToken: this.auth.getAccessToken() } + }) + + return this.socket + } +} diff --git a/client/src/app/menu/avatar-notification.component.html b/client/src/app/menu/avatar-notification.component.html index 2f0b7c669..4ef3f0e89 100644 --- a/client/src/app/menu/avatar-notification.component.html +++ b/client/src/app/menu/avatar-notification.component.html @@ -17,7 +17,7 @@ >
- + See all your notifications diff --git a/client/src/app/menu/avatar-notification.component.ts b/client/src/app/menu/avatar-notification.component.ts index 60e090726..f1af08096 100644 --- a/client/src/app/menu/avatar-notification.component.ts +++ b/client/src/app/menu/avatar-notification.component.ts @@ -2,7 +2,7 @@ import { Component, Input, OnDestroy, OnInit, ViewChild } from '@angular/core' import { User } from '../shared/users/user.model' import { UserNotificationService } from '@app/shared/users/user-notification.service' import { Subscription } from 'rxjs' -import { Notifier } from '@app/core' +import { Notifier, UserNotificationSocket } from '@app/core' import { NgbPopover } from '@ng-bootstrap/ng-bootstrap' import { NavigationEnd, Router } from '@angular/router' import { filter } from 'rxjs/operators' @@ -23,6 +23,7 @@ export class AvatarNotificationComponent implements OnInit, OnDestroy { constructor ( private userNotificationService: UserNotificationService, + private userNotificationSocket: UserNotificationSocket, private notifier: Notifier, private router: Router ) {} @@ -53,7 +54,7 @@ export class AvatarNotificationComponent implements OnInit, OnDestroy { } private subscribeToNotifications () { - this.notificationSub = this.userNotificationService.getMyNotificationsSocket() + this.notificationSub = this.userNotificationSocket.getMyNotificationsSocket() .subscribe(data => { if (data.type === 'new') return this.unreadNotifications++ if (data.type === 'read') return this.unreadNotifications-- diff --git a/client/src/app/shared/users/user-notification.service.ts b/client/src/app/shared/users/user-notification.service.ts index 2dfee8060..67ed8f74e 100644 --- a/client/src/app/shared/users/user-notification.service.ts +++ b/client/src/app/shared/users/user-notification.service.ts @@ -1,30 +1,28 @@ import { Injectable } from '@angular/core' import { HttpClient, HttpParams } from '@angular/common/http' -import { RestExtractor, RestService } from '@app/shared/rest' +import { RestExtractor, RestService } from '../rest' import { catchError, map, tap } from 'rxjs/operators' import { environment } from '../../../environments/environment' import { ResultList, UserNotification as UserNotificationServer, UserNotificationSetting } from '../../../../../shared' -import { UserNotification } from '@app/shared/users/user-notification.model' -import { Subject } from 'rxjs' -import * as io from 'socket.io-client' -import { AuthService } from '@app/core' -import { ComponentPagination } from '@app/shared/rest/component-pagination.model' -import { User } from '@app/shared' +import { UserNotification } from './user-notification.model' +import { AuthService } from '../../core' +import { ComponentPagination } from '../rest/component-pagination.model' +import { User } from '..' +import { UserNotificationSocket } from '@app/core/notification/user-notification-socket.service' @Injectable() export class UserNotificationService { static BASE_NOTIFICATIONS_URL = environment.apiUrl + '/api/v1/users/me/notifications' static BASE_NOTIFICATION_SETTINGS = environment.apiUrl + '/api/v1/users/me/notification-settings' - private notificationSubject = new Subject<{ type: 'new' | 'read' | 'read-all', notification?: UserNotification }>() - private socket: SocketIOClient.Socket constructor ( private auth: AuthService, private authHttp: HttpClient, private restExtractor: RestExtractor, - private restService: RestService + private restService: RestService, + private userNotificationSocket: UserNotificationSocket ) {} listMyNotifications (pagination: ComponentPagination, unread?: boolean, ignoreLoadingBar = false) { @@ -48,16 +46,6 @@ export class UserNotificationService { .pipe(map(n => n.total)) } - getMyNotificationsSocket () { - const socket = this.getSocket() - - socket.on('new-notification', (n: UserNotificationServer) => { - this.notificationSubject.next({ type: 'new', notification: new UserNotification(n) }) - }) - - return this.notificationSubject.asObservable() - } - markAsRead (notification: UserNotification) { const url = UserNotificationService.BASE_NOTIFICATIONS_URL + '/read' @@ -67,7 +55,7 @@ export class UserNotificationService { return this.authHttp.post(url, body, { headers }) .pipe( map(this.restExtractor.extractDataBool), - tap(() => this.notificationSubject.next({ type: 'read' })), + tap(() => this.userNotificationSocket.dispatch('read')), catchError(res => this.restExtractor.handleError(res)) ) } @@ -79,7 +67,7 @@ export class UserNotificationService { return this.authHttp.post(url, {}, { headers }) .pipe( map(this.restExtractor.extractDataBool), - tap(() => this.notificationSubject.next({ type: 'read-all' })), + tap(() => this.userNotificationSocket.dispatch('read-all')), catchError(res => this.restExtractor.handleError(res)) ) } @@ -94,16 +82,6 @@ export class UserNotificationService { ) } - private getSocket () { - if (this.socket) return this.socket - - this.socket = io(environment.apiUrl + '/user-notifications', { - query: { accessToken: this.auth.getAccessToken() } - }) - - return this.socket - } - private formatNotification (notification: UserNotificationServer) { return new UserNotification(notification) } diff --git a/client/src/app/shared/users/user-notifications.component.ts b/client/src/app/shared/users/user-notifications.component.ts index 50c495a9a..e3913ba56 100644 --- a/client/src/app/shared/users/user-notifications.component.ts +++ b/client/src/app/shared/users/user-notifications.component.ts @@ -13,6 +13,7 @@ import { UserNotification } from '@app/shared/users/user-notification.model' export class UserNotificationsComponent implements OnInit { @Input() ignoreLoadingBar = false @Input() infiniteScroll = true + @Input() itemsPerPage = 20 notifications: UserNotification[] = [] @@ -21,7 +22,7 @@ export class UserNotificationsComponent implements OnInit { componentPagination: ComponentPagination = { currentPage: 1, - itemsPerPage: 20, + itemsPerPage: this.itemsPerPage, totalItems: null } -- cgit v1.2.3 From 1506307f2f903ce0f80155072a33345c702b7c76 Mon Sep 17 00:00:00 2001 From: Chocobozzz Date: Mon, 14 Jan 2019 16:48:38 +0100 Subject: Increase abuse length to 3000 And correctly handle new lines --- .../about-instance/about-instance.component.ts | 2 +- .../account-about/account-about.component.ts | 4 +- .../+admin/moderation/moderation.component.scss | 1 + .../video-abuse-list.component.html | 4 +- .../video-abuse-list/video-abuse-list.component.ts | 8 +- .../video-blacklist-list.component.html | 2 +- .../video-blacklist-list.component.ts | 6 ++ .../video-channel-about.component.ts | 2 +- .../video-abuse-validators.service.ts | 8 +- .../shared/forms/markdown-textarea.component.ts | 2 +- client/src/app/shared/misc/help.component.ts | 2 +- client/src/app/shared/misc/utils.ts | 13 ++- .../app/shared/renderer/html-renderer.service.ts | 35 +++++++ client/src/app/shared/renderer/index.ts | 3 + .../src/app/shared/renderer/linkifier.service.ts | 115 +++++++++++++++++++++ client/src/app/shared/renderer/markdown.service.ts | 79 ++++++++++++++ client/src/app/shared/shared.module.ts | 9 +- .../app/shared/video-abuse/video-abuse.service.ts | 4 +- .../+video-watch/comment/linkifier.service.ts | 115 --------------------- .../comment/video-comment.component.ts | 27 +---- .../+video-watch/comment/video-comment.service.ts | 6 +- .../+video-watch/modal/video-support.component.ts | 3 +- .../videos/+video-watch/video-watch.component.ts | 2 +- .../app/videos/+video-watch/video-watch.module.ts | 4 - client/src/app/videos/shared/index.ts | 1 - client/src/app/videos/shared/markdown.service.ts | 79 -------------- 26 files changed, 284 insertions(+), 252 deletions(-) create mode 100644 client/src/app/shared/renderer/html-renderer.service.ts create mode 100644 client/src/app/shared/renderer/index.ts create mode 100644 client/src/app/shared/renderer/linkifier.service.ts create mode 100644 client/src/app/shared/renderer/markdown.service.ts delete mode 100644 client/src/app/videos/+video-watch/comment/linkifier.service.ts delete mode 100644 client/src/app/videos/shared/index.ts delete mode 100644 client/src/app/videos/shared/markdown.service.ts (limited to 'client/src/app') 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 d3ee8a1e4..a1b30fa8c 100644 --- a/client/src/app/+about/about-instance/about-instance.component.ts +++ b/client/src/app/+about/about-instance/about-instance.component.ts @@ -1,9 +1,9 @@ import { Component, OnInit, ViewChild } from '@angular/core' import { Notifier, ServerService } from '@app/core' -import { MarkdownService } from '@app/videos/shared' import { I18n } from '@ngx-translate/i18n-polyfill' import { ContactAdminModalComponent } from '@app/+about/about-instance/contact-admin-modal.component' import { InstanceService } from '@app/shared/instance/instance.service' +import { MarkdownService } from '@app/shared/renderer' @Component({ selector: 'my-about-instance', 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 6f3e6caa0..13890a0ee 100644 --- a/client/src/app/+accounts/account-about/account-about.component.ts +++ b/client/src/app/+accounts/account-about/account-about.component.ts @@ -1,9 +1,9 @@ -import { Component, OnInit, OnDestroy } from '@angular/core' +import { Component, OnDestroy, OnInit } from '@angular/core' import { Account } from '@app/shared/account/account.model' import { AccountService } from '@app/shared/account/account.service' import { I18n } from '@ngx-translate/i18n-polyfill' import { Subscription } from 'rxjs' -import { MarkdownService } from '@app/videos/shared' +import { MarkdownService } from '@app/shared/renderer' @Component({ selector: 'my-account-about', diff --git a/client/src/app/+admin/moderation/moderation.component.scss b/client/src/app/+admin/moderation/moderation.component.scss index 02ccfc8ca..13b019c5b 100644 --- a/client/src/app/+admin/moderation/moderation.component.scss +++ b/client/src/app/+admin/moderation/moderation.component.scss @@ -10,6 +10,7 @@ font-weight: $font-semibold; min-width: 200px; display: inline-block; + vertical-align: top; } .moderation-expanded-text { 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 e862d5162..05b549de6 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 @@
Reason: - {{ videoAbuse.reason }} +
Moderation comment: - {{ videoAbuse.moderationComment }} +
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 f64234b74..00c871659 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 @@ -9,6 +9,7 @@ import { DropdownAction } from '../../../shared/buttons/action-dropdown.componen import { ConfirmService } from '../../../core/index' import { ModerationCommentModalComponent } from './moderation-comment-modal.component' import { Video } from '../../../shared/video/video.model' +import { MarkdownService } from '@app/shared/renderer' @Component({ selector: 'my-video-abuse-list', @@ -30,7 +31,8 @@ export class VideoAbuseListComponent extends RestTable implements OnInit { private notifier: Notifier, private videoAbuseService: VideoAbuseService, private confirmService: ConfirmService, - private i18n: I18n + private i18n: I18n, + private markdownRenderer: MarkdownService ) { super() @@ -108,6 +110,10 @@ export class VideoAbuseListComponent extends RestTable implements OnInit { } + toHtml (text: string) { + return this.markdownRenderer.textMarkdownToHTML(text) + } + protected loadData () { return this.videoAbuseService.getVideoAbuses(this.pagination, this.sort) .subscribe( 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 6398af218..247f441c1 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 @@ Blacklist reason: - {{ videoBlacklist.reason }} + 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 6c6f17f0c..b27bbbfef 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 @@ -7,6 +7,7 @@ import { VideoBlacklist } from '../../../../../../shared' import { I18n } from '@ngx-translate/i18n-polyfill' import { DropdownAction } from '../../../shared/buttons/action-dropdown.component' import { Video } from '../../../shared/video/video.model' +import { MarkdownService } from '@app/shared/renderer' @Component({ selector: 'my-video-blacklist-list', @@ -26,6 +27,7 @@ export class VideoBlacklistListComponent extends RestTable implements OnInit { private notifier: Notifier, private confirmService: ConfirmService, private videoBlacklistService: VideoBlacklistService, + private markdownRenderer: MarkdownService, private i18n: I18n ) { super() @@ -52,6 +54,10 @@ export class VideoBlacklistListComponent extends RestTable implements OnInit { return this.i18n('no') } + toHtml (text: string) { + return this.markdownRenderer.textMarkdownToHTML(text) + } + async removeVideoFromBlacklist (entry: VideoBlacklist) { const confirmMessage = this.i18n( 'Do you really want to remove this video from the blacklist? It will be available again in the videos list.' 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 ea7b0e118..895b19064 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 @@ -3,7 +3,7 @@ import { VideoChannelService } from '@app/shared/video-channel/video-channel.ser import { VideoChannel } from '@app/shared/video-channel/video-channel.model' import { I18n } from '@ngx-translate/i18n-polyfill' import { Subscription } from 'rxjs' -import { MarkdownService } from '@app/videos/shared' +import { MarkdownService } from '@app/shared/renderer' @Component({ selector: 'my-video-channel-about', diff --git a/client/src/app/shared/forms/form-validators/video-abuse-validators.service.ts b/client/src/app/shared/forms/form-validators/video-abuse-validators.service.ts index 6e9806611..fcc966b84 100644 --- a/client/src/app/shared/forms/form-validators/video-abuse-validators.service.ts +++ b/client/src/app/shared/forms/form-validators/video-abuse-validators.service.ts @@ -10,20 +10,20 @@ export class VideoAbuseValidatorsService { constructor (private i18n: I18n) { this.VIDEO_ABUSE_REASON = { - VALIDATORS: [ Validators.required, Validators.minLength(2), Validators.maxLength(300) ], + VALIDATORS: [ Validators.required, Validators.minLength(2), Validators.maxLength(3000) ], MESSAGES: { 'required': this.i18n('Report reason is required.'), 'minlength': this.i18n('Report reason must be at least 2 characters long.'), - 'maxlength': this.i18n('Report reason cannot be more than 300 characters long.') + 'maxlength': this.i18n('Report reason cannot be more than 3000 characters long.') } } this.VIDEO_ABUSE_MODERATION_COMMENT = { - VALIDATORS: [ Validators.required, Validators.minLength(2), Validators.maxLength(300) ], + VALIDATORS: [ Validators.required, Validators.minLength(2), Validators.maxLength(3000) ], MESSAGES: { 'required': this.i18n('Moderation comment is required.'), 'minlength': this.i18n('Moderation comment must be at least 2 characters long.'), - 'maxlength': this.i18n('Moderation comment cannot be more than 300 characters long.') + 'maxlength': this.i18n('Moderation comment cannot be more than 3000 characters long.') } } } diff --git a/client/src/app/shared/forms/markdown-textarea.component.ts b/client/src/app/shared/forms/markdown-textarea.component.ts index b99169ed2..e87aca0d4 100644 --- a/client/src/app/shared/forms/markdown-textarea.component.ts +++ b/client/src/app/shared/forms/markdown-textarea.component.ts @@ -1,10 +1,10 @@ import { debounceTime, distinctUntilChanged } from 'rxjs/operators' import { Component, forwardRef, Input, OnInit } from '@angular/core' import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms' -import { MarkdownService } from '@app/videos/shared' import { Subject } from 'rxjs' import truncate from 'lodash-es/truncate' import { ScreenService } from '@app/shared/misc/screen.service' +import { MarkdownService } from '@app/shared/renderer' @Component({ selector: 'my-markdown-textarea', diff --git a/client/src/app/shared/misc/help.component.ts b/client/src/app/shared/misc/help.component.ts index ba0452e77..f3426f70f 100644 --- a/client/src/app/shared/misc/help.component.ts +++ b/client/src/app/shared/misc/help.component.ts @@ -1,6 +1,6 @@ import { Component, Input, OnChanges, OnInit } from '@angular/core' -import { MarkdownService } from '@app/videos/shared' import { I18n } from '@ngx-translate/i18n-polyfill' +import { MarkdownService } from '@app/shared/renderer' @Component({ selector: 'my-help', diff --git a/client/src/app/shared/misc/utils.ts b/client/src/app/shared/misc/utils.ts index 78e8e9682..7cc6055c2 100644 --- a/client/src/app/shared/misc/utils.ts +++ b/client/src/app/shared/misc/utils.ts @@ -102,12 +102,18 @@ function objectToFormData (obj: any, form?: FormData, namespace?: string) { return fd } -function lineFeedToHtml (obj: any, keyToNormalize: string) { +function objectLineFeedToHtml (obj: any, keyToNormalize: string) { return immutableAssign(obj, { - [keyToNormalize]: obj[keyToNormalize].replace(/\r?\n|\r/g, '
') + [keyToNormalize]: lineFeedToHtml(obj[keyToNormalize]) }) } +function lineFeedToHtml (text: string) { + if (!text) return text + + return text.replace(/\r?\n|\r/g, '
') +} + function removeElementFromArray (arr: T[], elem: T) { const index = arr.indexOf(elem) if (index !== -1) arr.splice(index, 1) @@ -131,6 +137,7 @@ function scrollToTop () { export { sortBy, durationToString, + lineFeedToHtml, objectToUrlEncoded, getParameterByName, populateAsyncUserVideoChannels, @@ -138,7 +145,7 @@ export { dateToHuman, immutableAssign, objectToFormData, - lineFeedToHtml, + objectLineFeedToHtml, removeElementFromArray, scrollToTop } diff --git a/client/src/app/shared/renderer/html-renderer.service.ts b/client/src/app/shared/renderer/html-renderer.service.ts new file mode 100644 index 000000000..d49df9b6d --- /dev/null +++ b/client/src/app/shared/renderer/html-renderer.service.ts @@ -0,0 +1,35 @@ +import { Injectable } from '@angular/core' +import { LinkifierService } from '@app/shared/renderer/linkifier.service' +import * as sanitizeHtml from 'sanitize-html' + +@Injectable() +export class HtmlRendererService { + + constructor (private linkifier: LinkifierService) { + + } + + toSafeHtml (text: string) { + // Convert possible markdown to html + const html = this.linkifier.linkify(text) + + return sanitizeHtml(html, { + allowedTags: [ 'a', 'p', 'span', 'br' ], + allowedSchemes: [ 'http', 'https' ], + allowedAttributes: { + 'a': [ 'href', 'class', 'target' ] + }, + transformTags: { + a: (tagName, attribs) => { + return { + tagName, + attribs: Object.assign(attribs, { + target: '_blank', + rel: 'noopener noreferrer' + }) + } + } + } + }) + } +} diff --git a/client/src/app/shared/renderer/index.ts b/client/src/app/shared/renderer/index.ts new file mode 100644 index 000000000..39202b385 --- /dev/null +++ b/client/src/app/shared/renderer/index.ts @@ -0,0 +1,3 @@ +export * from './html-renderer.service' +export * from './linkifier.service' +export * from './markdown.service' diff --git a/client/src/app/shared/renderer/linkifier.service.ts b/client/src/app/shared/renderer/linkifier.service.ts new file mode 100644 index 000000000..2529c9eaf --- /dev/null +++ b/client/src/app/shared/renderer/linkifier.service.ts @@ -0,0 +1,115 @@ +import { Injectable } from '@angular/core' +import { getAbsoluteAPIUrl } from '@app/shared/misc/utils' +// FIXME: use @types/linkify when https://github.com/DefinitelyTyped/DefinitelyTyped/pull/29682/files is merged? +const linkify = require('linkifyjs') +const linkifyHtml = require('linkifyjs/html') + +@Injectable() +export class LinkifierService { + + static CLASSNAME = 'linkified' + + private linkifyOptions = { + className: { + mention: LinkifierService.CLASSNAME + '-mention', + url: LinkifierService.CLASSNAME + '-url' + } + } + + constructor () { + // Apply plugin + this.mentionWithDomainPlugin(linkify) + } + + linkify (text: string) { + return linkifyHtml(text, this.linkifyOptions) + } + + private mentionWithDomainPlugin (linkify: any) { + const TT = linkify.scanner.TOKENS // Text tokens + const { TOKENS: MT, State } = linkify.parser // Multi tokens, state + const MultiToken = MT.Base + const S_START = linkify.parser.start + + const TT_AT = TT.AT + const TT_DOMAIN = TT.DOMAIN + const TT_LOCALHOST = TT.LOCALHOST + const TT_NUM = TT.NUM + const TT_COLON = TT.COLON + const TT_SLASH = TT.SLASH + const TT_TLD = TT.TLD + const TT_UNDERSCORE = TT.UNDERSCORE + const TT_DOT = TT.DOT + + function MENTION (this: any, value: any) { + this.v = value + } + + linkify.inherits(MultiToken, MENTION, { + type: 'mentionWithDomain', + isLink: true, + toHref () { + return getAbsoluteAPIUrl() + '/services/redirect/accounts/' + this.toString().substr(1) + } + }) + + const S_AT = S_START.jump(TT_AT) // @ + const S_AT_SYMS = new State() + const S_MENTION = new State(MENTION) + const S_MENTION_DIVIDER = new State() + const S_MENTION_DIVIDER_SYMS = new State() + + // @_, + S_AT.on(TT_UNDERSCORE, S_AT_SYMS) + + // @_* + S_AT_SYMS + .on(TT_UNDERSCORE, S_AT_SYMS) + .on(TT_DOT, S_AT_SYMS) + + // Valid mention (not made up entirely of symbols) + S_AT + .on(TT_DOMAIN, S_MENTION) + .on(TT_LOCALHOST, S_MENTION) + .on(TT_TLD, S_MENTION) + .on(TT_NUM, S_MENTION) + + S_AT_SYMS + .on(TT_DOMAIN, S_MENTION) + .on(TT_LOCALHOST, S_MENTION) + .on(TT_TLD, S_MENTION) + .on(TT_NUM, S_MENTION) + + // More valid mentions + S_MENTION + .on(TT_DOMAIN, S_MENTION) + .on(TT_LOCALHOST, S_MENTION) + .on(TT_TLD, S_MENTION) + .on(TT_COLON, S_MENTION) + .on(TT_NUM, S_MENTION) + .on(TT_UNDERSCORE, S_MENTION) + + // Mention with a divider + S_MENTION + .on(TT_AT, S_MENTION_DIVIDER) + .on(TT_SLASH, S_MENTION_DIVIDER) + .on(TT_DOT, S_MENTION_DIVIDER) + + // Mention _ trailing stash plus syms + S_MENTION_DIVIDER.on(TT_UNDERSCORE, S_MENTION_DIVIDER_SYMS) + S_MENTION_DIVIDER_SYMS.on(TT_UNDERSCORE, S_MENTION_DIVIDER_SYMS) + + // Once we get a word token, mentions can start up again + S_MENTION_DIVIDER + .on(TT_DOMAIN, S_MENTION) + .on(TT_LOCALHOST, S_MENTION) + .on(TT_TLD, S_MENTION) + .on(TT_NUM, S_MENTION) + + S_MENTION_DIVIDER_SYMS + .on(TT_DOMAIN, S_MENTION) + .on(TT_LOCALHOST, S_MENTION) + .on(TT_TLD, S_MENTION) + .on(TT_NUM, S_MENTION) + } +} diff --git a/client/src/app/shared/renderer/markdown.service.ts b/client/src/app/shared/renderer/markdown.service.ts new file mode 100644 index 000000000..07017eca5 --- /dev/null +++ b/client/src/app/shared/renderer/markdown.service.ts @@ -0,0 +1,79 @@ +import { Injectable } from '@angular/core' + +import * as MarkdownIt from 'markdown-it' + +@Injectable() +export class MarkdownService { + static TEXT_RULES = [ + 'linkify', + 'autolink', + 'emphasis', + 'link', + 'newline', + 'list' + ] + static ENHANCED_RULES = MarkdownService.TEXT_RULES.concat([ 'image' ]) + + private textMarkdownIt: MarkdownIt.MarkdownIt + private enhancedMarkdownIt: MarkdownIt.MarkdownIt + + constructor () { + this.textMarkdownIt = this.createMarkdownIt(MarkdownService.TEXT_RULES) + this.enhancedMarkdownIt = this.createMarkdownIt(MarkdownService.ENHANCED_RULES) + } + + textMarkdownToHTML (markdown: string) { + if (!markdown) return '' + + const html = this.textMarkdownIt.render(markdown) + return this.avoidTruncatedTags(html) + } + + enhancedMarkdownToHTML (markdown: string) { + if (!markdown) return '' + + const html = this.enhancedMarkdownIt.render(markdown) + return this.avoidTruncatedTags(html) + } + + private createMarkdownIt (rules: string[]) { + const markdownIt = new MarkdownIt('zero', { linkify: true, breaks: true }) + + for (let rule of rules) { + markdownIt.enable(rule) + } + + this.setTargetToLinks(markdownIt) + + return markdownIt + } + + private setTargetToLinks (markdownIt: MarkdownIt.MarkdownIt) { + // Snippet from markdown-it documentation: https://github.com/markdown-it/markdown-it/blob/master/docs/architecture.md#renderer + const defaultRender = markdownIt.renderer.rules.link_open || function (tokens, idx, options, env, self) { + return self.renderToken(tokens, idx, options) + } + + markdownIt.renderer.rules.link_open = function (tokens, index, options, env, self) { + const token = tokens[index] + + const targetIndex = token.attrIndex('target') + if (targetIndex < 0) token.attrPush([ 'target', '_blank' ]) + else token.attrs[targetIndex][1] = '_blank' + + const relIndex = token.attrIndex('rel') + if (relIndex < 0) token.attrPush([ 'rel', 'noopener noreferrer' ]) + else token.attrs[relIndex][1] = 'noopener noreferrer' + + // pass token to default renderer. + return defaultRender(tokens, index, options, env, self) + } + } + + private avoidTruncatedTags (html: string) { + return html.replace(/\*\*?([^*]+)$/, '$1') + .replace(/]+>([^<]+)<\/a>\s*...((<\/p>)|(<\/li>)|(<\/strong>))?$/mi, '$1...') + .replace(/\[[^\]]+\]?\(?([^\)]+)$/, '$1') + + } +} diff --git a/client/src/app/shared/shared.module.ts b/client/src/app/shared/shared.module.ts index d1320aeec..384f5d722 100644 --- a/client/src/app/shared/shared.module.ts +++ b/client/src/app/shared/shared.module.ts @@ -6,7 +6,6 @@ import { RouterModule } from '@angular/router' import { MarkdownTextareaComponent } from '@app/shared/forms/markdown-textarea.component' import { HelpComponent } from '@app/shared/misc/help.component' import { InfiniteScrollerDirective } from '@app/shared/video/infinite-scroller.directive' -import { MarkdownService } from '@app/videos/shared' import { BytesPipe, KeysPipe, NgPipesModule } from 'ngx-pipes' import { SharedModule as PrimeSharedModule } from 'primeng/components/common/shared' @@ -34,10 +33,10 @@ import { I18n } from '@ngx-translate/i18n-polyfill' import { FormValidatorService } from '@app/shared/forms/form-validators/form-validator.service' import { CustomConfigValidatorsService, + InstanceValidatorsService, LoginValidatorsService, ReactiveFileComponent, ResetPasswordValidatorsService, - InstanceValidatorsService, TextareaAutoResizeDirective, UserValidatorsService, VideoAbuseValidatorsService, @@ -67,6 +66,7 @@ import { UserHistoryService } from '@app/shared/users/user-history.service' import { UserNotificationService } from '@app/shared/users/user-notification.service' import { UserNotificationsComponent } from '@app/shared/users/user-notifications.component' import { InstanceService } from '@app/shared/instance/instance.service' +import { HtmlRendererService, LinkifierService, MarkdownService } from '@app/shared/renderer' @NgModule({ imports: [ @@ -167,7 +167,6 @@ import { InstanceService } from '@app/shared/instance/instance.service' UserService, VideoService, AccountService, - MarkdownService, VideoChannelService, VideoCaptionService, VideoImportService, @@ -192,6 +191,10 @@ import { InstanceService } from '@app/shared/instance/instance.service' UserHistoryService, InstanceService, + MarkdownService, + LinkifierService, + HtmlRendererService, + I18nPrimengCalendarService, ScreenService, diff --git a/client/src/app/shared/video-abuse/video-abuse.service.ts b/client/src/app/shared/video-abuse/video-abuse.service.ts index 61b7e1b98..b0b59ea0c 100644 --- a/client/src/app/shared/video-abuse/video-abuse.service.ts +++ b/client/src/app/shared/video-abuse/video-abuse.service.ts @@ -32,9 +32,7 @@ export class VideoAbuseService { reportVideo (id: number, reason: string) { const url = VideoAbuseService.BASE_VIDEO_ABUSE_URL + id + '/abuse' - const body = { - reason - } + const body = { reason } return this.authHttp.post(url, body) .pipe( diff --git a/client/src/app/videos/+video-watch/comment/linkifier.service.ts b/client/src/app/videos/+video-watch/comment/linkifier.service.ts deleted file mode 100644 index 2529c9eaf..000000000 --- a/client/src/app/videos/+video-watch/comment/linkifier.service.ts +++ /dev/null @@ -1,115 +0,0 @@ -import { Injectable } from '@angular/core' -import { getAbsoluteAPIUrl } from '@app/shared/misc/utils' -// FIXME: use @types/linkify when https://github.com/DefinitelyTyped/DefinitelyTyped/pull/29682/files is merged? -const linkify = require('linkifyjs') -const linkifyHtml = require('linkifyjs/html') - -@Injectable() -export class LinkifierService { - - static CLASSNAME = 'linkified' - - private linkifyOptions = { - className: { - mention: LinkifierService.CLASSNAME + '-mention', - url: LinkifierService.CLASSNAME + '-url' - } - } - - constructor () { - // Apply plugin - this.mentionWithDomainPlugin(linkify) - } - - linkify (text: string) { - return linkifyHtml(text, this.linkifyOptions) - } - - private mentionWithDomainPlugin (linkify: any) { - const TT = linkify.scanner.TOKENS // Text tokens - const { TOKENS: MT, State } = linkify.parser // Multi tokens, state - const MultiToken = MT.Base - const S_START = linkify.parser.start - - const TT_AT = TT.AT - const TT_DOMAIN = TT.DOMAIN - const TT_LOCALHOST = TT.LOCALHOST - const TT_NUM = TT.NUM - const TT_COLON = TT.COLON - const TT_SLASH = TT.SLASH - const TT_TLD = TT.TLD - const TT_UNDERSCORE = TT.UNDERSCORE - const TT_DOT = TT.DOT - - function MENTION (this: any, value: any) { - this.v = value - } - - linkify.inherits(MultiToken, MENTION, { - type: 'mentionWithDomain', - isLink: true, - toHref () { - return getAbsoluteAPIUrl() + '/services/redirect/accounts/' + this.toString().substr(1) - } - }) - - const S_AT = S_START.jump(TT_AT) // @ - const S_AT_SYMS = new State() - const S_MENTION = new State(MENTION) - const S_MENTION_DIVIDER = new State() - const S_MENTION_DIVIDER_SYMS = new State() - - // @_, - S_AT.on(TT_UNDERSCORE, S_AT_SYMS) - - // @_* - S_AT_SYMS - .on(TT_UNDERSCORE, S_AT_SYMS) - .on(TT_DOT, S_AT_SYMS) - - // Valid mention (not made up entirely of symbols) - S_AT - .on(TT_DOMAIN, S_MENTION) - .on(TT_LOCALHOST, S_MENTION) - .on(TT_TLD, S_MENTION) - .on(TT_NUM, S_MENTION) - - S_AT_SYMS - .on(TT_DOMAIN, S_MENTION) - .on(TT_LOCALHOST, S_MENTION) - .on(TT_TLD, S_MENTION) - .on(TT_NUM, S_MENTION) - - // More valid mentions - S_MENTION - .on(TT_DOMAIN, S_MENTION) - .on(TT_LOCALHOST, S_MENTION) - .on(TT_TLD, S_MENTION) - .on(TT_COLON, S_MENTION) - .on(TT_NUM, S_MENTION) - .on(TT_UNDERSCORE, S_MENTION) - - // Mention with a divider - S_MENTION - .on(TT_AT, S_MENTION_DIVIDER) - .on(TT_SLASH, S_MENTION_DIVIDER) - .on(TT_DOT, S_MENTION_DIVIDER) - - // Mention _ trailing stash plus syms - S_MENTION_DIVIDER.on(TT_UNDERSCORE, S_MENTION_DIVIDER_SYMS) - S_MENTION_DIVIDER_SYMS.on(TT_UNDERSCORE, S_MENTION_DIVIDER_SYMS) - - // Once we get a word token, mentions can start up again - S_MENTION_DIVIDER - .on(TT_DOMAIN, S_MENTION) - .on(TT_LOCALHOST, S_MENTION) - .on(TT_TLD, S_MENTION) - .on(TT_NUM, S_MENTION) - - S_MENTION_DIVIDER_SYMS - .on(TT_DOMAIN, S_MENTION) - .on(TT_LOCALHOST, S_MENTION) - .on(TT_TLD, S_MENTION) - .on(TT_NUM, S_MENTION) - } -} 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 00f0460a1..aba7f9d1c 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,11 +1,10 @@ import { Component, EventEmitter, Input, OnChanges, OnInit, Output } from '@angular/core' -import { LinkifierService } from '@app/videos/+video-watch/comment/linkifier.service' -import * as sanitizeHtml from 'sanitize-html' import { UserRight } from '../../../../../../shared/models/users' import { VideoCommentThreadTree } from '../../../../../../shared/models/videos/video-comment.model' import { AuthService } from '../../../core/auth' import { Video } from '../../../shared/video/video.model' import { VideoComment } from './video-comment.model' +import { HtmlRendererService } from '@app/shared/renderer' @Component({ selector: 'my-video-comment', @@ -29,7 +28,7 @@ export class VideoCommentComponent implements OnInit, OnChanges { newParentComments: VideoComment[] = [] constructor ( - private linkifierService: LinkifierService, + private htmlRenderer: HtmlRendererService, private authService: AuthService ) {} @@ -87,27 +86,7 @@ export class VideoCommentComponent implements OnInit, OnChanges { } private init () { - // Convert possible markdown to html - const html = this.linkifierService.linkify(this.comment.text) - - this.sanitizedCommentHTML = sanitizeHtml(html, { - allowedTags: [ 'a', 'p', 'span', 'br' ], - allowedSchemes: [ 'http', 'https' ], - allowedAttributes: { - 'a': [ 'href', 'class', 'target' ] - }, - transformTags: { - a: (tagName, attribs) => { - return { - tagName, - attribs: Object.assign(attribs, { - target: '_blank', - rel: 'noopener noreferrer' - }) - } - } - } - }) + this.sanitizedCommentHTML = this.htmlRenderer.toSafeHtml(this.comment.text) this.newParentComments = this.parentComments.concat([ this.comment ]) } 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 921447d5b..b8e5878c5 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 @@ -1,7 +1,7 @@ import { catchError, map } from 'rxjs/operators' import { HttpClient, HttpParams } from '@angular/common/http' import { Injectable } from '@angular/core' -import { lineFeedToHtml } from '@app/shared/misc/utils' +import { objectLineFeedToHtml } from '@app/shared/misc/utils' import { Observable } from 'rxjs' import { ResultList, FeedFormat } from '../../../../../../shared/models' import { @@ -28,7 +28,7 @@ export class VideoCommentService { addCommentThread (videoId: number | string, comment: VideoCommentCreate) { const url = VideoCommentService.BASE_VIDEO_URL + videoId + '/comment-threads' - const normalizedComment = lineFeedToHtml(comment, 'text') + const normalizedComment = objectLineFeedToHtml(comment, 'text') return this.authHttp.post<{ comment: VideoCommentServerModel }>(url, normalizedComment) .pipe( @@ -39,7 +39,7 @@ export class VideoCommentService { addCommentReply (videoId: number | string, inReplyToCommentId: number, comment: VideoCommentCreate) { const url = VideoCommentService.BASE_VIDEO_URL + videoId + '/comments/' + inReplyToCommentId - const normalizedComment = lineFeedToHtml(comment, 'text') + const normalizedComment = objectLineFeedToHtml(comment, 'text') return this.authHttp.post<{ comment: VideoCommentServerModel }>(url, normalizedComment) .pipe( 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 154002120..deb8fbc67 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 @@ -1,8 +1,7 @@ import { Component, Input, ViewChild } from '@angular/core' -import { MarkdownService } from '@app/videos/shared' - import { VideoDetails } from '../../../shared/video/video-details.model' import { NgbModal } from '@ng-bootstrap/ng-bootstrap' +import { MarkdownService } from '@app/shared/renderer' @Component({ selector: 'my-video-support', 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 67c5254b3..ee504bc58 100644 --- a/client/src/app/videos/+video-watch/video-watch.component.ts +++ b/client/src/app/videos/+video-watch/video-watch.component.ts @@ -19,7 +19,6 @@ import { AuthService, ConfirmService } from '../../core' import { RestExtractor, VideoBlacklistService } from '../../shared' import { VideoDetails } from '../../shared/video/video-details.model' import { VideoService } from '../../shared/video/video.service' -import { MarkdownService } from '../shared' import { VideoDownloadComponent } from './modal/video-download.component' import { VideoReportComponent } from './modal/video-report.component' import { VideoShareComponent } from './modal/video-share.component' @@ -30,6 +29,7 @@ import { I18n } from '@ngx-translate/i18n-polyfill' import { environment } from '../../../environments/environment' import { getDevLocale, isOnDevLocale } from '@app/shared/i18n/i18n-utils' import { VideoCaptionService } from '@app/shared/video-caption' +import { MarkdownService } from '@app/shared/renderer' @Component({ selector: 'my-video-watch', diff --git a/client/src/app/videos/+video-watch/video-watch.module.ts b/client/src/app/videos/+video-watch/video-watch.module.ts index 54a12c126..2f448db78 100644 --- a/client/src/app/videos/+video-watch/video-watch.module.ts +++ b/client/src/app/videos/+video-watch/video-watch.module.ts @@ -1,9 +1,7 @@ import { NgModule } from '@angular/core' -import { LinkifierService } from '@app/videos/+video-watch/comment/linkifier.service' import { VideoSupportComponent } from '@app/videos/+video-watch/modal/video-support.component' import { ClipboardModule } from 'ngx-clipboard' import { SharedModule } from '../../shared' -import { MarkdownService } from '../shared' import { VideoCommentAddComponent } from './comment/video-comment-add.component' import { VideoCommentComponent } from './comment/video-comment.component' import { VideoCommentService } from './comment/video-comment.service' @@ -46,8 +44,6 @@ import { RecommendationsModule } from '@app/videos/recommendations/recommendatio ], providers: [ - MarkdownService, - LinkifierService, VideoCommentService ] }) diff --git a/client/src/app/videos/shared/index.ts b/client/src/app/videos/shared/index.ts deleted file mode 100644 index 7a66944b9..000000000 --- a/client/src/app/videos/shared/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from './markdown.service' diff --git a/client/src/app/videos/shared/markdown.service.ts b/client/src/app/videos/shared/markdown.service.ts deleted file mode 100644 index 07017eca5..000000000 --- a/client/src/app/videos/shared/markdown.service.ts +++ /dev/null @@ -1,79 +0,0 @@ -import { Injectable } from '@angular/core' - -import * as MarkdownIt from 'markdown-it' - -@Injectable() -export class MarkdownService { - static TEXT_RULES = [ - 'linkify', - 'autolink', - 'emphasis', - 'link', - 'newline', - 'list' - ] - static ENHANCED_RULES = MarkdownService.TEXT_RULES.concat([ 'image' ]) - - private textMarkdownIt: MarkdownIt.MarkdownIt - private enhancedMarkdownIt: MarkdownIt.MarkdownIt - - constructor () { - this.textMarkdownIt = this.createMarkdownIt(MarkdownService.TEXT_RULES) - this.enhancedMarkdownIt = this.createMarkdownIt(MarkdownService.ENHANCED_RULES) - } - - textMarkdownToHTML (markdown: string) { - if (!markdown) return '' - - const html = this.textMarkdownIt.render(markdown) - return this.avoidTruncatedTags(html) - } - - enhancedMarkdownToHTML (markdown: string) { - if (!markdown) return '' - - const html = this.enhancedMarkdownIt.render(markdown) - return this.avoidTruncatedTags(html) - } - - private createMarkdownIt (rules: string[]) { - const markdownIt = new MarkdownIt('zero', { linkify: true, breaks: true }) - - for (let rule of rules) { - markdownIt.enable(rule) - } - - this.setTargetToLinks(markdownIt) - - return markdownIt - } - - private setTargetToLinks (markdownIt: MarkdownIt.MarkdownIt) { - // Snippet from markdown-it documentation: https://github.com/markdown-it/markdown-it/blob/master/docs/architecture.md#renderer - const defaultRender = markdownIt.renderer.rules.link_open || function (tokens, idx, options, env, self) { - return self.renderToken(tokens, idx, options) - } - - markdownIt.renderer.rules.link_open = function (tokens, index, options, env, self) { - const token = tokens[index] - - const targetIndex = token.attrIndex('target') - if (targetIndex < 0) token.attrPush([ 'target', '_blank' ]) - else token.attrs[targetIndex][1] = '_blank' - - const relIndex = token.attrIndex('rel') - if (relIndex < 0) token.attrPush([ 'rel', 'noopener noreferrer' ]) - else token.attrs[relIndex][1] = 'noopener noreferrer' - - // pass token to default renderer. - return defaultRender(tokens, index, options, env, self) - } - } - - private avoidTruncatedTags (html: string) { - return html.replace(/\*\*?([^*]+)$/, '$1') - .replace(/]+>([^<]+)<\/a>\s*...((<\/p>)|(<\/li>)|(<\/strong>))?$/mi, '$1...') - .replace(/\[[^\]]+\]?\(?([^\)]+)$/, '$1') - - } -} -- cgit v1.2.3 From 3195cd1c118f5e020ab7e635d5a3dcdad2108b1a Mon Sep 17 00:00:00 2001 From: Chocobozzz Date: Tue, 15 Jan 2019 09:25:26 +0100 Subject: Fix notification z-index on modals --- .../video-abuse-list/moderation-comment-modal.component.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'client/src/app') diff --git a/client/src/app/+admin/moderation/video-abuse-list/moderation-comment-modal.component.html b/client/src/app/+admin/moderation/video-abuse-list/moderation-comment-modal.component.html index 3a8424f68..952235c55 100644 --- a/client/src/app/+admin/moderation/video-abuse-list/moderation-comment-modal.component.html +++ b/client/src/app/+admin/moderation/video-abuse-list/moderation-comment-modal.component.html @@ -14,7 +14,7 @@
-
+
This comment can only be seen by you or the other moderators.
@@ -29,4 +29,4 @@
- \ No newline at end of file + -- cgit v1.2.3 From 457bb213b273a9b206cc5654eb085cede4e916ad Mon Sep 17 00:00:00 2001 From: Chocobozzz Date: Wed, 16 Jan 2019 16:05:40 +0100 Subject: Refactor how we use icons Inject them in an angular component so we can easily change their color --- .../contact-admin-modal.component.html | 2 +- .../moderation-comment-modal.component.html | 5 +- .../moderation-comment-modal.component.ts | 4 +- .../users/user-list/user-list.component.html | 2 +- .../users/user-list/user-list.component.scss | 4 +- .../my-account-history.component.scss | 4 +- .../my-account-notifications.component.html | 10 ++- .../my-account-notifications.component.scss | 4 +- .../my-account-accept-ownership.component.html | 3 +- .../my-account-video-channels.component.html | 2 +- .../my-account-video-channels.component.scss | 2 +- .../my-account-videos.component.html | 6 +- .../my-account-videos.component.scss | 11 ++- .../video-change-ownership.component.html | 3 +- client/src/app/app.component.html | 2 + client/src/app/core/confirm/confirm.component.html | 25 ------- client/src/app/core/confirm/confirm.component.scss | 17 ----- client/src/app/core/confirm/confirm.component.ts | 68 ------------------ client/src/app/core/confirm/index.ts | 1 - client/src/app/core/core.module.ts | 4 +- client/src/app/header/header.component.html | 2 +- client/src/app/header/header.component.scss | 10 +-- client/src/app/login/login.component.html | 3 +- .../app/menu/avatar-notification.component.scss | 2 +- .../src/app/menu/language-chooser.component.html | 2 +- client/src/app/search/search.component.scss | 4 +- client/src/app/shared/actor/actor.model.ts | 2 +- .../shared/buttons/action-dropdown.component.html | 2 +- .../shared/buttons/action-dropdown.component.scss | 9 +-- .../src/app/shared/buttons/button.component.html | 2 +- .../src/app/shared/buttons/button.component.scss | 34 ++------- client/src/app/shared/buttons/button.component.ts | 3 +- .../shared/buttons/delete-button.component.html | 2 +- .../app/shared/buttons/edit-button.component.html | 2 +- .../src/app/shared/confirm/confirm.component.html | 26 +++++++ .../src/app/shared/confirm/confirm.component.scss | 17 +++++ client/src/app/shared/confirm/confirm.component.ts | 68 ++++++++++++++++++ .../app/shared/icons/global-icon.component.html | 0 .../app/shared/icons/global-icon.component.scss | 4 ++ .../src/app/shared/icons/global-icon.component.ts | 47 +++++++++++++ client/src/app/shared/misc/help.component.html | 4 +- client/src/app/shared/misc/help.component.scss | 19 +++-- .../moderation/user-ban-modal.component.html | 7 +- .../shared/moderation/user-ban-modal.component.ts | 4 +- client/src/app/shared/shared.module.ts | 8 ++- .../app/shared/users/user-notification.model.ts | 37 +++++----- .../app/shared/users/user-notification.service.ts | 2 - .../shared/users/user-notifications.component.html | 82 ++++++++++++++++------ .../shared/users/user-notifications.component.scss | 46 +++++++----- .../shared/users/user-notifications.component.ts | 14 ++-- client/src/app/shared/video/feed.component.html | 9 +-- client/src/app/shared/video/feed.component.scss | 17 +++-- .../shared/video/video-miniature.component.scss | 4 +- client/src/app/shared/video/video.model.ts | 4 +- .../shared/video-caption-add-modal.component.html | 2 +- .../+video-edit/shared/video-edit.component.html | 2 +- .../+video-edit/shared/video-edit.component.scss | 17 ++--- .../video-import-torrent.component.html | 6 +- .../video-import-torrent.component.scss | 53 +------------- .../video-import-torrent.component.ts | 3 +- .../video-import-url.component.html | 6 +- .../video-import-url.component.scss | 45 ------------ .../video-import-url.component.ts | 2 +- .../video-add-components/video-send.scss | 54 ++++++++++++++ .../video-upload.component.html | 6 +- .../video-upload.component.scss | 44 +----------- .../video-add-components/video-upload.component.ts | 3 +- .../videos/+video-edit/video-update.component.html | 2 +- .../comment/video-comment.component.scss | 6 +- .../modal/video-blacklist.component.html | 2 +- .../modal/video-download.component.html | 2 +- .../+video-watch/modal/video-report.component.html | 2 +- .../+video-watch/modal/video-share.component.html | 2 +- .../modal/video-support.component.html | 2 +- .../videos/+video-watch/video-watch.component.html | 24 ++++--- .../videos/+video-watch/video-watch.component.scss | 80 ++++----------------- 76 files changed, 504 insertions(+), 538 deletions(-) delete mode 100644 client/src/app/core/confirm/confirm.component.html delete mode 100644 client/src/app/core/confirm/confirm.component.scss delete mode 100644 client/src/app/core/confirm/confirm.component.ts create mode 100644 client/src/app/shared/confirm/confirm.component.html create mode 100644 client/src/app/shared/confirm/confirm.component.scss create mode 100644 client/src/app/shared/confirm/confirm.component.ts create mode 100644 client/src/app/shared/icons/global-icon.component.html create mode 100644 client/src/app/shared/icons/global-icon.component.scss create mode 100644 client/src/app/shared/icons/global-icon.component.ts delete mode 100644 client/src/app/videos/+video-edit/video-add-components/video-import-url.component.scss create mode 100644 client/src/app/videos/+video-edit/video-add-components/video-send.scss (limited to 'client/src/app') diff --git a/client/src/app/+about/about-instance/contact-admin-modal.component.html b/client/src/app/+about/about-instance/contact-admin-modal.component.html index 2b3fb32f3..b2cbd0873 100644 --- a/client/src/app/+about/about-instance/contact-admin-modal.component.html +++ b/client/src/app/+about/about-instance/contact-admin-modal.component.html @@ -1,7 +1,7 @@ @@ -53,4 +53,4 @@
- \ No newline at end of file + diff --git a/client/src/app/+my-account/my-account-videos/my-account-videos.component.scss b/client/src/app/+my-account/my-account-videos/my-account-videos.component.scss index a735562f8..39d0cf2f7 100644 --- a/client/src/app/+my-account/my-account-videos/my-account-videos.component.scss +++ b/client/src/app/+my-account/my-account-videos/my-account-videos.component.scss @@ -23,14 +23,11 @@ .action-button-delete-selection { @include peertube-button; @include orange-button; - } - - .icon.icon-delete-white { - @include icon(21px); + @include button-with-icon(21px); - position: relative; - top: -2px; - background-image: url('../../../assets/images/global/delete-white.svg'); + my-global-icon { + @include apply-svg-color(#fff); + } } } } diff --git a/client/src/app/+my-account/my-account-videos/video-change-ownership/video-change-ownership.component.html b/client/src/app/+my-account/my-account-videos/video-change-ownership/video-change-ownership.component.html index 7c0df850d..22f127904 100644 --- a/client/src/app/+my-account/my-account-videos/video-change-ownership/video-change-ownership.component.html +++ b/client/src/app/+my-account/my-account-videos/video-change-ownership/video-change-ownership.component.html @@ -1,7 +1,8 @@ + +
diff --git a/client/src/app/core/confirm/confirm.component.html b/client/src/app/core/confirm/confirm.component.html deleted file mode 100644 index 43f0c6190..000000000 --- a/client/src/app/core/confirm/confirm.component.html +++ /dev/null @@ -1,25 +0,0 @@ - - - - - - - - diff --git a/client/src/app/core/confirm/confirm.component.scss b/client/src/app/core/confirm/confirm.component.scss deleted file mode 100644 index 93dd7926b..000000000 --- a/client/src/app/core/confirm/confirm.component.scss +++ /dev/null @@ -1,17 +0,0 @@ -@import '_variables'; -@import '_mixins'; - -.button { - padding: 0 13px; -} - -input[type=text] { - @include peertube-input-text(100%); - display: block; -} - -.form-group { - margin: 20px 0; -} - - diff --git a/client/src/app/core/confirm/confirm.component.ts b/client/src/app/core/confirm/confirm.component.ts deleted file mode 100644 index 5138b7848..000000000 --- a/client/src/app/core/confirm/confirm.component.ts +++ /dev/null @@ -1,68 +0,0 @@ -import { Component, ElementRef, HostListener, OnInit, ViewChild } from '@angular/core' -import { ConfirmService } from './confirm.service' -import { I18n } from '@ngx-translate/i18n-polyfill' -import { NgbModal } from '@ng-bootstrap/ng-bootstrap' -import { NgbModalRef } from '@ng-bootstrap/ng-bootstrap/modal/modal-ref' - -@Component({ - selector: 'my-confirm', - templateUrl: './confirm.component.html', - styleUrls: [ './confirm.component.scss' ] -}) -export class ConfirmComponent implements OnInit { - @ViewChild('confirmModal') confirmModal: ElementRef - - title = '' - message = '' - expectedInputValue = '' - inputLabel = '' - - inputValue = '' - confirmButtonText = '' - - private openedModal: NgbModalRef - - constructor ( - private modalService: NgbModal, - private confirmService: ConfirmService, - private i18n: I18n - ) { } - - ngOnInit () { - this.confirmService.showConfirm.subscribe( - ({ title, message, expectedInputValue, inputLabel, confirmButtonText }) => { - this.title = title - this.message = message - - this.inputLabel = inputLabel - this.expectedInputValue = expectedInputValue - - this.confirmButtonText = confirmButtonText || this.i18n('Confirm') - - this.showModal() - } - ) - } - - @HostListener('document:keydown.enter') - confirm () { - if (this.openedModal) this.openedModal.close() - } - - isConfirmationDisabled () { - // No input validation - if (!this.inputLabel || !this.expectedInputValue) return false - - return this.expectedInputValue !== this.inputValue - } - - showModal () { - this.inputValue = '' - - this.openedModal = this.modalService.open(this.confirmModal) - - this.openedModal.result - .then(() => this.confirmService.confirmResponse.next(true)) - .catch(() => this.confirmService.confirmResponse.next(false)) - } -} diff --git a/client/src/app/core/confirm/index.ts b/client/src/app/core/confirm/index.ts index 44aabfc13..aca591e1a 100644 --- a/client/src/app/core/confirm/index.ts +++ b/client/src/app/core/confirm/index.ts @@ -1,2 +1 @@ -export * from './confirm.component' export * from './confirm.service' diff --git a/client/src/app/core/core.module.ts b/client/src/app/core/core.module.ts index 3bc0e2885..4ef3b1e73 100644 --- a/client/src/app/core/core.module.ts +++ b/client/src/app/core/core.module.ts @@ -8,7 +8,7 @@ import { LoadingBarHttpClientModule } from '@ngx-loading-bar/http-client' import { LoadingBarRouterModule } from '@ngx-loading-bar/router' import { AuthService } from './auth' -import { ConfirmComponent, ConfirmService } from './confirm' +import { ConfirmService } from './confirm' import { throwIfAlreadyLoaded } from './module-import-guard' import { LoginGuard, RedirectService, UserRightGuard } from './routing' import { ServerService } from './server' @@ -38,7 +38,6 @@ import { UserNotificationSocket } from '@app/core/notification/user-notification ], declarations: [ - ConfirmComponent, CheatSheetComponent ], @@ -48,7 +47,6 @@ import { UserNotificationSocket } from '@app/core/notification/user-notification ToastModule, - ConfirmComponent, CheatSheetComponent ], diff --git a/client/src/app/header/header.component.html b/client/src/app/header/header.component.html index c23e0c55d..46a87c79c 100644 --- a/client/src/app/header/header.component.html +++ b/client/src/app/header/header.component.html @@ -5,6 +5,6 @@ - + Upload diff --git a/client/src/app/header/header.component.scss b/client/src/app/header/header.component.scss index 2f9820665..cdc457b96 100644 --- a/client/src/app/header/header.component.scss +++ b/client/src/app/header/header.component.scss @@ -40,6 +40,7 @@ .upload-button { @include peertube-button-link; @include orange-button; + @include button-with-icon(22px, 3px, -1px); margin-right: 25px; @@ -47,15 +48,6 @@ margin-right: 0; } - .icon.icon-upload { - @include icon(22px); - - background-image: url('../../assets/images/header/upload-white.svg'); - height: 24px; - vertical-align: middle; - margin-right: 6px; - } - @media screen and (max-width: 600px) { margin-right: 10px; padding: 0 10px; diff --git a/client/src/app/login/login.component.html b/client/src/app/login/login.component.html index 9b8146624..4efe3fb22 100644 --- a/client/src/app/login/login.component.html +++ b/client/src/app/login/login.component.html @@ -55,7 +55,8 @@ diff --git a/client/src/app/shared/buttons/action-dropdown.component.scss b/client/src/app/shared/buttons/action-dropdown.component.scss index a4fcceeee..985b2ca88 100644 --- a/client/src/app/shared/buttons/action-dropdown.component.scss +++ b/client/src/app/shared/buttons/action-dropdown.component.scss @@ -24,14 +24,11 @@ } &:hover, &:active, &:focus { - background-color: $grey-color; + background-color: $grey-background-color; } - .icon-action { - @include icon(21px); - - background-image: url('../../../assets/images/video/more.svg'); - top: -1px; + .more-icon { + width: 21px; } &.small { diff --git a/client/src/app/shared/buttons/button.component.html b/client/src/app/shared/buttons/button.component.html index 87a8daccf..b6df67102 100644 --- a/client/src/app/shared/buttons/button.component.html +++ b/client/src/app/shared/buttons/button.component.html @@ -1,4 +1,4 @@ - + {{ label }} diff --git a/client/src/app/shared/buttons/button.component.scss b/client/src/app/shared/buttons/button.component.scss index 168102f09..be41669cd 100644 --- a/client/src/app/shared/buttons/button.component.scss +++ b/client/src/app/shared/buttons/button.component.scss @@ -3,41 +3,19 @@ .action-button { @include peertube-button-link; + @include button-with-icon(21px, 0, -2px); font-size: 15px; font-weight: $font-semibold; - color: #585858; - background-color: #E5E5E5; + color: $grey-foreground-color; + background-color: $grey-background-color; &:hover { - background-color: #EFEFEF; + background-color: $grey-background-hover-color; } - .icon { - @include icon(21px); - - position: relative; - top: -2px; - - &.icon-edit { - background-image: url('../../../assets/images/global/edit-grey.svg'); - } - - &.icon-delete-grey { - background-image: url('../../../assets/images/global/delete-grey.svg'); - } - - &.icon-im-with-her { - background-image: url('../../../assets/images/global/im-with-her.svg'); - } - - &.icon-tick { - background-image: url('../../../assets/images/global/tick.svg'); - } - - &.icon-cross { - background-image: url('../../../assets/images/global/cross.svg'); - } + my-global-icon { + @include apply-svg-color($grey-foreground-color); } } diff --git a/client/src/app/shared/buttons/button.component.ts b/client/src/app/shared/buttons/button.component.ts index 1a1162f09..a91e9c7eb 100644 --- a/client/src/app/shared/buttons/button.component.ts +++ b/client/src/app/shared/buttons/button.component.ts @@ -1,4 +1,5 @@ import { Component, Input } from '@angular/core' +import { GlobalIconName } from '@app/shared/icons/global-icon.component' @Component({ selector: 'my-button', @@ -9,7 +10,7 @@ import { Component, Input } from '@angular/core' export class ButtonComponent { @Input() label = '' @Input() className: string = undefined - @Input() icon: string = undefined + @Input() icon: GlobalIconName = undefined @Input() title: string = undefined getTitle () { diff --git a/client/src/app/shared/buttons/delete-button.component.html b/client/src/app/shared/buttons/delete-button.component.html index 6c55d8104..4d12a84c0 100644 --- a/client/src/app/shared/buttons/delete-button.component.html +++ b/client/src/app/shared/buttons/delete-button.component.html @@ -1,5 +1,5 @@ - + {{ label }} Delete diff --git a/client/src/app/shared/buttons/edit-button.component.html b/client/src/app/shared/buttons/edit-button.component.html index cecb780f3..da3addbae 100644 --- a/client/src/app/shared/buttons/edit-button.component.html +++ b/client/src/app/shared/buttons/edit-button.component.html @@ -1,5 +1,5 @@ - + {{ label }} Edit diff --git a/client/src/app/shared/confirm/confirm.component.html b/client/src/app/shared/confirm/confirm.component.html new file mode 100644 index 000000000..65df1cd4d --- /dev/null +++ b/client/src/app/shared/confirm/confirm.component.html @@ -0,0 +1,26 @@ + + + + + + + + diff --git a/client/src/app/shared/confirm/confirm.component.scss b/client/src/app/shared/confirm/confirm.component.scss new file mode 100644 index 000000000..93dd7926b --- /dev/null +++ b/client/src/app/shared/confirm/confirm.component.scss @@ -0,0 +1,17 @@ +@import '_variables'; +@import '_mixins'; + +.button { + padding: 0 13px; +} + +input[type=text] { + @include peertube-input-text(100%); + display: block; +} + +.form-group { + margin: 20px 0; +} + + diff --git a/client/src/app/shared/confirm/confirm.component.ts b/client/src/app/shared/confirm/confirm.component.ts new file mode 100644 index 000000000..63c163da6 --- /dev/null +++ b/client/src/app/shared/confirm/confirm.component.ts @@ -0,0 +1,68 @@ +import { Component, ElementRef, HostListener, OnInit, ViewChild } from '@angular/core' +import { ConfirmService } from '@app/core/confirm/confirm.service' +import { I18n } from '@ngx-translate/i18n-polyfill' +import { NgbModal } from '@ng-bootstrap/ng-bootstrap' +import { NgbModalRef } from '@ng-bootstrap/ng-bootstrap/modal/modal-ref' + +@Component({ + selector: 'my-confirm', + templateUrl: './confirm.component.html', + styleUrls: [ './confirm.component.scss' ] +}) +export class ConfirmComponent implements OnInit { + @ViewChild('confirmModal') confirmModal: ElementRef + + title = '' + message = '' + expectedInputValue = '' + inputLabel = '' + + inputValue = '' + confirmButtonText = '' + + private openedModal: NgbModalRef + + constructor ( + private modalService: NgbModal, + private confirmService: ConfirmService, + private i18n: I18n + ) { } + + ngOnInit () { + this.confirmService.showConfirm.subscribe( + ({ title, message, expectedInputValue, inputLabel, confirmButtonText }) => { + this.title = title + this.message = message + + this.inputLabel = inputLabel + this.expectedInputValue = expectedInputValue + + this.confirmButtonText = confirmButtonText || this.i18n('Confirm') + + this.showModal() + } + ) + } + + @HostListener('document:keydown.enter') + confirm () { + if (this.openedModal) this.openedModal.close() + } + + isConfirmationDisabled () { + // No input validation + if (!this.inputLabel || !this.expectedInputValue) return false + + return this.expectedInputValue !== this.inputValue + } + + showModal () { + this.inputValue = '' + + this.openedModal = this.modalService.open(this.confirmModal) + + this.openedModal.result + .then(() => this.confirmService.confirmResponse.next(true)) + .catch(() => this.confirmService.confirmResponse.next(false)) + } +} diff --git a/client/src/app/shared/icons/global-icon.component.html b/client/src/app/shared/icons/global-icon.component.html new file mode 100644 index 000000000..e69de29bb diff --git a/client/src/app/shared/icons/global-icon.component.scss b/client/src/app/shared/icons/global-icon.component.scss new file mode 100644 index 000000000..6805fb6f7 --- /dev/null +++ b/client/src/app/shared/icons/global-icon.component.scss @@ -0,0 +1,4 @@ +/deep/ svg { + width: inherit; + height: inherit; +} diff --git a/client/src/app/shared/icons/global-icon.component.ts b/client/src/app/shared/icons/global-icon.component.ts new file mode 100644 index 000000000..5b9377e3e --- /dev/null +++ b/client/src/app/shared/icons/global-icon.component.ts @@ -0,0 +1,47 @@ +import { Component, ElementRef, Input, OnInit } from '@angular/core' + +const icons = { + 'add': require('../../../assets/images/global/add.html'), + 'syndication': require('../../../assets/images/global/syndication.html'), + 'help': require('../../../assets/images/global/help.html'), + 'sparkle': require('../../../assets/images/global/sparkle.html'), + 'alert': require('../../../assets/images/global/alert.html'), + 'cloud-error': require('../../../assets/images/global/cloud-error.html'), + 'user-add': require('../../../assets/images/global/user-add.html'), + 'no': require('../../../assets/images/global/no.html'), + 'cloud-download': require('../../../assets/images/global/cloud-download.html'), + 'undo': require('../../../assets/images/global/undo.html'), + 'circle-tick': require('../../../assets/images/global/circle-tick.html'), + 'cog': require('../../../assets/images/global/cog.html'), + 'download': require('../../../assets/images/global/download.html'), + 'edit': require('../../../assets/images/global/edit.html'), + 'im-with-her': require('../../../assets/images/global/im-with-her.html'), + 'delete': require('../../../assets/images/global/delete.html'), + 'cross': require('../../../assets/images/global/cross.html'), + 'validate': require('../../../assets/images/global/validate.html'), + 'dislike': require('../../../assets/images/video/dislike.html'), + 'heart': require('../../../assets/images/video/heart.html'), + 'like': require('../../../assets/images/video/like.html'), + 'more': require('../../../assets/images/video/more.html'), + 'share': require('../../../assets/images/video/share.html'), + 'upload': require('../../../assets/images/video/upload.html') +} + +export type GlobalIconName = keyof typeof icons + +@Component({ + selector: 'my-global-icon', + template: '', + styleUrls: [ './global-icon.component.scss' ] +}) +export class GlobalIconComponent implements OnInit { + @Input() iconName: GlobalIconName + + constructor (private el: ElementRef) {} + + ngOnInit () { + const nativeElement = this.el.nativeElement + + nativeElement.innerHTML = icons[this.iconName] + } +} diff --git a/client/src/app/shared/misc/help.component.html b/client/src/app/shared/misc/help.component.html index 08a2fc367..444425c9f 100644 --- a/client/src/app/shared/misc/help.component.html +++ b/client/src/app/shared/misc/help.component.html @@ -25,4 +25,6 @@ [autoClose]="true" (onHidden)="onPopoverHidden()" (onShown)="onPopoverShown()" -> +> + + diff --git a/client/src/app/shared/misc/help.component.scss b/client/src/app/shared/misc/help.component.scss index 047e53fab..4565d457a 100644 --- a/client/src/app/shared/misc/help.component.scss +++ b/client/src/app/shared/misc/help.component.scss @@ -2,13 +2,15 @@ @import '_mixins'; .help-tooltip-button { - @include icon(17px); - - position: relative; - top: -2px; - background-image: url('../../../assets/images/global/help.svg'); + cursor: pointer; border: none; - margin: 5px; + + my-global-icon { + width: 17px; + position: relative; + top: -2px; + margin: 5px; + } } /deep/ { @@ -24,8 +26,13 @@ color: #000; box-shadow: 0 0 6px rgba(0, 0, 0, 0.5); + p:last-child { + margin-bottom: 0; + } + ul { padding-left: 20px; + margin-bottom: 0; } } } diff --git a/client/src/app/shared/moderation/user-ban-modal.component.html b/client/src/app/shared/moderation/user-ban-modal.component.html index fa5cb7404..f38ea543d 100644 --- a/client/src/app/shared/moderation/user-ban-modal.component.html +++ b/client/src/app/shared/moderation/user-ban-modal.component.html @@ -1,7 +1,8 @@
- Cancel + Cancel
-
\ No newline at end of file +
diff --git a/client/src/app/shared/moderation/user-ban-modal.component.ts b/client/src/app/shared/moderation/user-ban-modal.component.ts index f755ba0e8..942765301 100644 --- a/client/src/app/shared/moderation/user-ban-modal.component.ts +++ b/client/src/app/shared/moderation/user-ban-modal.component.ts @@ -42,7 +42,7 @@ export class UserBanModalComponent extends FormReactive implements OnInit { this.openedModal = this.modalService.open(this.modal) } - hideBanUserModal () { + hide () { this.usersToBan = undefined this.openedModal.close() } @@ -60,7 +60,7 @@ export class UserBanModalComponent extends FormReactive implements OnInit { this.notifier.success(message) this.userBanned.emit(this.usersToBan) - this.hideBanUserModal() + this.hide() }, err => this.notifier.error(err.message) diff --git a/client/src/app/shared/shared.module.ts b/client/src/app/shared/shared.module.ts index 384f5d722..6f8625c7e 100644 --- a/client/src/app/shared/shared.module.ts +++ b/client/src/app/shared/shared.module.ts @@ -67,6 +67,8 @@ import { UserNotificationService } from '@app/shared/users/user-notification.ser import { UserNotificationsComponent } from '@app/shared/users/user-notifications.component' import { InstanceService } from '@app/shared/instance/instance.service' import { HtmlRendererService, LinkifierService, MarkdownService } from '@app/shared/renderer' +import { ConfirmComponent } from '@app/shared/confirm/confirm.component' +import { GlobalIconComponent } from '@app/shared/icons/global-icon.component' @NgModule({ imports: [ @@ -110,7 +112,9 @@ import { HtmlRendererService, LinkifierService, MarkdownService } from '@app/sha UserBanModalComponent, UserModerationDropdownComponent, TopMenuDropdownComponent, - UserNotificationsComponent + UserNotificationsComponent, + ConfirmComponent, + GlobalIconComponent ], exports: [ @@ -151,6 +155,8 @@ import { HtmlRendererService, LinkifierService, MarkdownService } from '@app/sha UserModerationDropdownComponent, TopMenuDropdownComponent, UserNotificationsComponent, + ConfirmComponent, + GlobalIconComponent, NumberFormatterPipe, ObjectLengthPipe, diff --git a/client/src/app/shared/users/user-notification.model.ts b/client/src/app/shared/users/user-notification.model.ts index 5ff816fb8..c5996a8a1 100644 --- a/client/src/app/shared/users/user-notification.model.ts +++ b/client/src/app/shared/users/user-notification.model.ts @@ -1,4 +1,5 @@ -import { UserNotification as UserNotificationServer, UserNotificationType, VideoInfo } from '../../../../../shared' +import { UserNotification as UserNotificationServer, UserNotificationType, VideoInfo, ActorInfo } from '../../../../../shared' +import { Actor } from '@app/shared/actor/actor.model' export class UserNotification implements UserNotificationServer { id: number @@ -6,10 +7,7 @@ export class UserNotification implements UserNotificationServer { read: boolean video?: VideoInfo & { - channel: { - id: number - displayName: string - } + channel: ActorInfo & { avatarUrl?: string } } videoImport?: { @@ -23,10 +21,7 @@ export class UserNotification implements UserNotificationServer { comment?: { id: number threadId: number - account: { - id: number - displayName: string - } + account: ActorInfo & { avatarUrl?: string } video: VideoInfo } @@ -40,18 +35,11 @@ export class UserNotification implements UserNotificationServer { video: VideoInfo } - account?: { - id: number - displayName: string - name: string - } + account?: ActorInfo & { avatarUrl?: string } actorFollow?: { id: number - follower: { - name: string - displayName: string - } + follower: ActorInfo & { avatarUrl?: string } following: { type: 'account' | 'channel' name: string @@ -76,12 +64,22 @@ export class UserNotification implements UserNotificationServer { this.read = hash.read this.video = hash.video + if (this.video) this.setAvatarUrl(this.video.channel) + this.videoImport = hash.videoImport + this.comment = hash.comment + if (this.comment) this.setAvatarUrl(this.comment.account) + this.videoAbuse = hash.videoAbuse + this.videoBlacklist = hash.videoBlacklist + this.account = hash.account + if (this.account) this.setAvatarUrl(this.account) + this.actorFollow = hash.actorFollow + if (this.actorFollow) this.setAvatarUrl(this.actorFollow.follower) this.createdAt = hash.createdAt this.updatedAt = hash.updatedAt @@ -150,4 +148,7 @@ export class UserNotification implements UserNotificationServer { return videoImport.targetUrl || videoImport.magnetUri || videoImport.torrentName } + private setAvatarUrl (actor: { avatarUrl?: string, avatar?: { path: string } }) { + actor.avatarUrl = Actor.GET_ACTOR_AVATAR_URL(actor) + } } diff --git a/client/src/app/shared/users/user-notification.service.ts b/client/src/app/shared/users/user-notification.service.ts index 67ed8f74e..f8a30955d 100644 --- a/client/src/app/shared/users/user-notification.service.ts +++ b/client/src/app/shared/users/user-notification.service.ts @@ -15,8 +15,6 @@ export class UserNotificationService { static BASE_NOTIFICATIONS_URL = environment.apiUrl + '/api/v1/users/me/notifications' static BASE_NOTIFICATION_SETTINGS = environment.apiUrl + '/api/v1/users/me/notification-settings' - private socket: SocketIOClient.Socket - constructor ( private auth: AuthService, private authHttp: HttpClient, diff --git a/client/src/app/shared/users/user-notifications.component.html b/client/src/app/shared/users/user-notifications.component.html index 86379d941..caa518e7f 100644 --- a/client/src/app/shared/users/user-notifications.component.html +++ b/client/src/app/shared/users/user-notifications.component.html @@ -1,61 +1,101 @@
You don't have notifications.
-
+
-
+ - {{ notification.video.channel.displayName }} published a new video + + +
+ {{ notification.video.channel.displayName }} published a new video +
- Your video {{ notification.video.name }} has been unblacklisted + + +
+ Your video {{ notification.video.name }} has been unblacklisted +
- Your video {{ notification.videoBlacklist.video.name }} has been blacklisted + + +
+ Your video {{ notification.videoBlacklist.video.name }} has been blacklisted +
- A new video abuse has been created on video {{ notification.videoAbuse.video.name }} + + + - {{ notification.comment.account.displayName }} commented your video {{ notification.comment.video.name }} + + +
+ {{ notification.comment.account.displayName }} commented your video {{ notification.comment.video.name }} +
- Your video {{ notification.video.name }} has been published + + +
+ Your video {{ notification.video.name }} has been published +
- Your video import {{ notification.videoImportIdentifier }} succeeded + + +
+ Your video import {{ notification.videoImportIdentifier }} succeeded +
- Your video import {{ notification.videoImportIdentifier }} failed + + +
+ Your video import {{ notification.videoImportIdentifier }} failed +
- User {{ notification.account.name }} registered on your instance + + +
+ User {{ notification.account.name }} registered on your instance +
- {{ notification.actorFollow.follower.displayName }} is following + - - your channel {{ notification.actorFollow.following.displayName }} - - your account +
+ {{ notification.actorFollow.follower.displayName }} is following + + your channel {{ notification.actorFollow.following.displayName }} + your account +
- {{ notification.comment.account.displayName }} mentioned you on video {{ notification.comment.video.name }} + + +
+ {{ notification.comment.account.displayName }} mentioned you on video {{ notification.comment.video.name }} +
-
+ -
-
-
+
{{ notification.createdAt | myFromNow }}
diff --git a/client/src/app/shared/users/user-notifications.component.scss b/client/src/app/shared/users/user-notifications.component.scss index 0ae26ea39..315d504c9 100644 --- a/client/src/app/shared/users/user-notifications.component.scss +++ b/client/src/app/shared/users/user-notifications.component.scss @@ -1,3 +1,6 @@ +@import '_variables'; +@import '_mixins'; + .no-notification { display: flex; justify-content: center; @@ -7,31 +10,42 @@ .notification { display: flex; - justify-content: space-between; align-items: center; font-size: inherit; - padding: 15px 10px; + padding: 15px 5px 15px 10px; border-bottom: 1px solid rgba(0, 0, 0, 0.10); - .mark-as-read { - min-width: 35px; + &.unread { + background-color: rgba(0, 0, 0, 0.05); + } + + my-global-icon { + width: 24px; + margin-right: 11px; + margin-left: 3px; - .glyphicon { - display: none; - cursor: pointer; - color: rgba(20, 20, 20, 0.5) - } + @include apply-svg-color(#333); } - &.unread { - background-color: rgba(0, 0, 0, 0.05); + .avatar { + @include avatar(30px); + + margin-right: 10px; + } - &:hover .mark-as-read .glyphicon { - display: block; + .message { + flex-grow: 1; - &:hover { - color: rgba(20, 20, 20, 0.8); - } + a { + font-weight: $font-semibold; } } + + .from-date { + font-size: 0.85em; + color: $grey-foreground-color; + padding-left: 5px; + min-width: 70px; + text-align: right; + } } diff --git a/client/src/app/shared/users/user-notifications.component.ts b/client/src/app/shared/users/user-notifications.component.ts index e3913ba56..b5f9fd399 100644 --- a/client/src/app/shared/users/user-notifications.component.ts +++ b/client/src/app/shared/users/user-notifications.component.ts @@ -20,11 +20,7 @@ export class UserNotificationsComponent implements OnInit { // So we can access it in the template UserNotificationType = UserNotificationType - componentPagination: ComponentPagination = { - currentPage: 1, - itemsPerPage: this.itemsPerPage, - totalItems: null - } + componentPagination: ComponentPagination constructor ( private userNotificationService: UserNotificationService, @@ -32,6 +28,12 @@ export class UserNotificationsComponent implements OnInit { ) { } ngOnInit () { + this.componentPagination = { + currentPage: 1, + itemsPerPage: this.itemsPerPage, // Reset items per page, because of the @Input() variable + totalItems: null + } + this.loadMoreNotifications() } @@ -58,6 +60,8 @@ export class UserNotificationsComponent implements OnInit { } markAsRead (notification: UserNotification) { + if (notification.read) return + this.userNotificationService.markAsRead(notification) .subscribe( () => { diff --git a/client/src/app/shared/video/feed.component.html b/client/src/app/shared/video/feed.component.html index 16116ba88..f7624ec01 100644 --- a/client/src/app/shared/video/feed.component.html +++ b/client/src/app/shared/video/feed.component.html @@ -1,10 +1,11 @@
- + class="icon-syndication" role="button" iconName="syndication" + > + {{ item.label }} -
\ No newline at end of file +
diff --git a/client/src/app/shared/video/feed.component.scss b/client/src/app/shared/video/feed.component.scss index 385764be0..ed1dc17d3 100644 --- a/client/src/app/shared/video/feed.component.scss +++ b/client/src/app/shared/video/feed.component.scss @@ -1,3 +1,4 @@ +@import '_variables'; @import '_mixins'; .video-feed { @@ -6,14 +7,12 @@ display: block; } - .icon { - @include icon(12px); + my-global-icon { + cursor: pointer; + width: 12px; + position: relative; + top: -2px; - &.icon-syndication { - position: relative; - top: -2px; - background-color: var(--mainForegroundColor); - mask-image: url('../../../assets/images/global/syndication.svg'); - } + @include apply-svg-color(var(--mainForegroundColor)) } -} \ No newline at end of file +} diff --git a/client/src/app/shared/video/video-miniature.component.scss b/client/src/app/shared/video/video-miniature.component.scss index 895879adc..f44bdf9a9 100644 --- a/client/src/app/shared/video/video-miniature.component.scss +++ b/client/src/app/shared/video/video-miniature.component.scss @@ -50,10 +50,10 @@ text-overflow: ellipsis; white-space: nowrap; font-size: 13px; - color: #585858; + color: $grey-foreground-color; &:hover { - color: #303030; + color: $grey-foreground-hover-color; } } } diff --git a/client/src/app/shared/video/video.model.ts b/client/src/app/shared/video/video.model.ts index b92c96450..6ea83d13b 100644 --- a/client/src/app/shared/video/video.model.ts +++ b/client/src/app/shared/video/video.model.ts @@ -53,7 +53,7 @@ export class Video implements VideoServerModel { displayName: string url: string host: string - avatar: Avatar + avatar?: Avatar } channel: { @@ -63,7 +63,7 @@ export class Video implements VideoServerModel { displayName: string url: string host: string - avatar: Avatar + avatar?: Avatar } userHistory?: { diff --git a/client/src/app/videos/+video-edit/shared/video-caption-add-modal.component.html b/client/src/app/videos/+video-edit/shared/video-caption-add-modal.component.html index 30aefdbfc..19043eee6 100644 --- a/client/src/app/videos/+video-edit/shared/video-caption-add-modal.component.html +++ b/client/src/app/videos/+video-edit/shared/video-caption-add-modal.component.html @@ -3,7 +3,7 @@