diff options
author | Chocobozzz <florian.bigard@gmail.com> | 2017-10-26 15:01:47 +0200 |
---|---|---|
committer | Chocobozzz <florian.bigard@gmail.com> | 2017-10-26 15:01:47 +0200 |
commit | 9d9597df427542eb5c7d3ba8ff5aeb146fab40e2 (patch) | |
tree | 5098facc5f2d70d4ad7871e6736e6f9d9d9a797a | |
parent | 4077df72c634ff17aaf69cc612fc6bb8d68b1ed8 (diff) | |
download | PeerTube-9d9597df427542eb5c7d3ba8ff5aeb146fab40e2.tar.gz PeerTube-9d9597df427542eb5c7d3ba8ff5aeb146fab40e2.tar.zst PeerTube-9d9597df427542eb5c7d3ba8ff5aeb146fab40e2.zip |
Add markdown support to video description
-rw-r--r-- | client/package.json | 2 | ||||
-rw-r--r-- | client/src/app/videos/+video-edit/video-update.component.ts | 2 | ||||
-rw-r--r-- | client/src/app/videos/+video-watch/video-watch.component.html | 4 | ||||
-rw-r--r-- | client/src/app/videos/+video-watch/video-watch.component.ts | 8 | ||||
-rw-r--r-- | client/src/app/videos/+video-watch/video-watch.module.ts | 3 | ||||
-rw-r--r-- | client/src/app/videos/shared/index.ts | 1 | ||||
-rw-r--r-- | client/src/app/videos/shared/markdown.service.ts | 40 | ||||
-rw-r--r-- | client/src/app/videos/shared/video-edit.model.ts | 15 | ||||
-rw-r--r-- | client/src/app/videos/shared/video.service.ts | 2 | ||||
-rw-r--r-- | client/yarn.lock | 28 |
10 files changed, 97 insertions, 8 deletions
diff --git a/client/package.json b/client/package.json index 8b949ef80..8d42e0c87 100644 --- a/client/package.json +++ b/client/package.json | |||
@@ -35,6 +35,7 @@ | |||
35 | "@angularclass/hmr-loader": "^3.0.2", | 35 | "@angularclass/hmr-loader": "^3.0.2", |
36 | "@ngx-meta/core": "^4.0.1", | 36 | "@ngx-meta/core": "^4.0.1", |
37 | "@types/core-js": "^0.9.28", | 37 | "@types/core-js": "^0.9.28", |
38 | "@types/markdown-it": "^0.0.4", | ||
38 | "@types/node": "^8.0.33", | 39 | "@types/node": "^8.0.33", |
39 | "@types/source-map": "^0.5.1", | 40 | "@types/source-map": "^0.5.1", |
40 | "@types/uglify-js": "^2.0.27", | 41 | "@types/uglify-js": "^2.0.27", |
@@ -66,6 +67,7 @@ | |||
66 | "inline-manifest-webpack-plugin": "^3.0.1", | 67 | "inline-manifest-webpack-plugin": "^3.0.1", |
67 | "intl": "^1.2.4", | 68 | "intl": "^1.2.4", |
68 | "json-loader": "^0.5.4", | 69 | "json-loader": "^0.5.4", |
70 | "markdown-it": "^8.4.0", | ||
69 | "ng-router-loader": "^2.0.0", | 71 | "ng-router-loader": "^2.0.0", |
70 | "ngc-webpack": "3.2.2", | 72 | "ngc-webpack": "3.2.2", |
71 | "ngx-bootstrap": "1.9.3", | 73 | "ngx-bootstrap": "1.9.3", |
diff --git a/client/src/app/videos/+video-edit/video-update.component.ts b/client/src/app/videos/+video-edit/video-update.component.ts index 70cb334fd..30390ac05 100644 --- a/client/src/app/videos/+video-edit/video-update.component.ts +++ b/client/src/app/videos/+video-edit/video-update.component.ts | |||
@@ -87,7 +87,7 @@ export class VideoUpdateComponent extends FormReactive implements OnInit { | |||
87 | this.videoService.getVideo(uuid) | 87 | this.videoService.getVideo(uuid) |
88 | .subscribe( | 88 | .subscribe( |
89 | video => { | 89 | video => { |
90 | this.video = video | 90 | this.video = new VideoEdit(video) |
91 | 91 | ||
92 | this.hydrateFormFromVideo() | 92 | this.hydrateFormFromVideo() |
93 | }, | 93 | }, |
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 5d5827344..6e502aae2 100644 --- a/client/src/app/videos/+video-watch/video-watch.component.html +++ b/client/src/app/videos/+video-watch/video-watch.component.html | |||
@@ -128,9 +128,7 @@ | |||
128 | Published on {{ video.createdAt | date:'short' }} | 128 | Published on {{ video.createdAt | date:'short' }} |
129 | </div> | 129 | </div> |
130 | 130 | ||
131 | <div class="video-details-description"> | 131 | <div class="video-details-description" [innerHTML]="videoHTMLDescription"></div> |
132 | {{ video.description }} | ||
133 | </div> | ||
134 | </div> | 132 | </div> |
135 | 133 | ||
136 | <div class="video-details-attributes col-xs-4 col-md-3"> | 134 | <div class="video-details-attributes col-xs-4 col-md-3"> |
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 529e2e84f..2e1adb043 100644 --- a/client/src/app/videos/+video-watch/video-watch.component.ts +++ b/client/src/app/videos/+video-watch/video-watch.component.ts | |||
@@ -13,7 +13,7 @@ import { AuthService, ConfirmService } from '../../core' | |||
13 | import { VideoDownloadComponent } from './video-download.component' | 13 | import { VideoDownloadComponent } from './video-download.component' |
14 | import { VideoShareComponent } from './video-share.component' | 14 | import { VideoShareComponent } from './video-share.component' |
15 | import { VideoReportComponent } from './video-report.component' | 15 | import { VideoReportComponent } from './video-report.component' |
16 | import { VideoDetails, VideoService } from '../shared' | 16 | import { VideoDetails, VideoService, MarkdownService } from '../shared' |
17 | import { VideoBlacklistService } from '../../shared' | 17 | import { VideoBlacklistService } from '../../shared' |
18 | import { UserVideoRateType, VideoRateType } from '../../../../../shared' | 18 | import { UserVideoRateType, VideoRateType } from '../../../../../shared' |
19 | 19 | ||
@@ -38,6 +38,7 @@ export class VideoWatchComponent implements OnInit, OnDestroy { | |||
38 | video: VideoDetails = null | 38 | video: VideoDetails = null |
39 | videoPlayerLoaded = false | 39 | videoPlayerLoaded = false |
40 | videoNotFound = false | 40 | videoNotFound = false |
41 | videoHTMLDescription = '' | ||
41 | 42 | ||
42 | private paramsSub: Subscription | 43 | private paramsSub: Subscription |
43 | 44 | ||
@@ -50,7 +51,8 @@ export class VideoWatchComponent implements OnInit, OnDestroy { | |||
50 | private confirmService: ConfirmService, | 51 | private confirmService: ConfirmService, |
51 | private metaService: MetaService, | 52 | private metaService: MetaService, |
52 | private authService: AuthService, | 53 | private authService: AuthService, |
53 | private notificationsService: NotificationsService | 54 | private notificationsService: NotificationsService, |
55 | private markdownService: MarkdownService | ||
54 | ) {} | 56 | ) {} |
55 | 57 | ||
56 | ngOnInit () { | 58 | ngOnInit () { |
@@ -259,6 +261,8 @@ export class VideoWatchComponent implements OnInit, OnDestroy { | |||
259 | }) | 261 | }) |
260 | }) | 262 | }) |
261 | 263 | ||
264 | this.videoHTMLDescription = this.markdownService.markdownToHTML(this.video.description) | ||
265 | |||
262 | this.setOpenGraphTags() | 266 | this.setOpenGraphTags() |
263 | this.checkUserRating() | 267 | this.checkUserRating() |
264 | } | 268 | } |
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 c6c1344ce..1b983200d 100644 --- a/client/src/app/videos/+video-watch/video-watch.module.ts +++ b/client/src/app/videos/+video-watch/video-watch.module.ts | |||
@@ -1,7 +1,7 @@ | |||
1 | import { NgModule } from '@angular/core' | 1 | import { NgModule } from '@angular/core' |
2 | 2 | ||
3 | import { VideoWatchRoutingModule } from './video-watch-routing.module' | 3 | import { VideoWatchRoutingModule } from './video-watch-routing.module' |
4 | import { VideoService } from '../shared' | 4 | import { VideoService, MarkdownService } from '../shared' |
5 | import { SharedModule } from '../../shared' | 5 | import { SharedModule } from '../../shared' |
6 | 6 | ||
7 | import { VideoWatchComponent } from './video-watch.component' | 7 | import { VideoWatchComponent } from './video-watch.component' |
@@ -28,6 +28,7 @@ import { VideoDownloadComponent } from './video-download.component' | |||
28 | ], | 28 | ], |
29 | 29 | ||
30 | providers: [ | 30 | providers: [ |
31 | MarkdownService, | ||
31 | VideoService | 32 | VideoService |
32 | ] | 33 | ] |
33 | }) | 34 | }) |
diff --git a/client/src/app/videos/shared/index.ts b/client/src/app/videos/shared/index.ts index dcaa4e090..09d961dd3 100644 --- a/client/src/app/videos/shared/index.ts +++ b/client/src/app/videos/shared/index.ts | |||
@@ -1,4 +1,5 @@ | |||
1 | export * from './sort-field.type' | 1 | export * from './sort-field.type' |
2 | export * from './markdown.service' | ||
2 | export * from './video.model' | 3 | export * from './video.model' |
3 | export * from './video-details.model' | 4 | export * from './video-details.model' |
4 | export * from './video-edit.model' | 5 | export * from './video-edit.model' |
diff --git a/client/src/app/videos/shared/markdown.service.ts b/client/src/app/videos/shared/markdown.service.ts new file mode 100644 index 000000000..d8b5b76b6 --- /dev/null +++ b/client/src/app/videos/shared/markdown.service.ts | |||
@@ -0,0 +1,40 @@ | |||
1 | import { Injectable } from '@angular/core' | ||
2 | |||
3 | import * as MarkdownIt from 'markdown-it' | ||
4 | |||
5 | @Injectable() | ||
6 | export class MarkdownService { | ||
7 | private markdownIt: MarkdownIt.MarkdownIt | ||
8 | |||
9 | constructor () { | ||
10 | this.markdownIt = new MarkdownIt('zero', { linkify: true }) | ||
11 | .enable('linkify') | ||
12 | .enable('autolink') | ||
13 | .enable('emphasis') | ||
14 | .enable('link') | ||
15 | .enable('newline') | ||
16 | |||
17 | // Snippet from markdown-it documentation: https://github.com/markdown-it/markdown-it/blob/master/docs/architecture.md#renderer | ||
18 | const defaultRender = this.markdownIt.renderer.rules.link_open || function (tokens, idx, options, env, self) { | ||
19 | return self.renderToken(tokens, idx, options) | ||
20 | } | ||
21 | |||
22 | this.markdownIt.renderer.rules.link_open = function (tokens, idx, options, env, self) { | ||
23 | // If you are sure other plugins can't add `target` - drop check below | ||
24 | const aIndex = tokens[idx].attrIndex('target') | ||
25 | |||
26 | if (aIndex < 0) { | ||
27 | tokens[idx].attrPush(['target', '_blank']) // add new attribute | ||
28 | } else { | ||
29 | tokens[idx].attrs[aIndex][1] = '_blank' // replace value of existing attr | ||
30 | } | ||
31 | |||
32 | // pass token to default renderer. | ||
33 | return defaultRender(tokens, idx, options, env, self) | ||
34 | } | ||
35 | } | ||
36 | |||
37 | markdownToHTML (markdown: string) { | ||
38 | return this.markdownIt.render(markdown) | ||
39 | } | ||
40 | } | ||
diff --git a/client/src/app/videos/shared/video-edit.model.ts b/client/src/app/videos/shared/video-edit.model.ts index f30d8feba..e0b7bf130 100644 --- a/client/src/app/videos/shared/video-edit.model.ts +++ b/client/src/app/videos/shared/video-edit.model.ts | |||
@@ -1,3 +1,5 @@ | |||
1 | import { VideoDetails } from './video-details.model' | ||
2 | |||
1 | export class VideoEdit { | 3 | export class VideoEdit { |
2 | category: number | 4 | category: number |
3 | licence: number | 5 | licence: number |
@@ -10,6 +12,19 @@ export class VideoEdit { | |||
10 | uuid?: string | 12 | uuid?: string |
11 | id?: number | 13 | id?: number |
12 | 14 | ||
15 | constructor (videoDetails: VideoDetails) { | ||
16 | this.id = videoDetails.id | ||
17 | this.uuid = videoDetails.uuid | ||
18 | this.category = videoDetails.category | ||
19 | this.licence = videoDetails.licence | ||
20 | this.language = videoDetails.language | ||
21 | this.description = videoDetails.description | ||
22 | this.name = videoDetails.name | ||
23 | this.tags = videoDetails.tags | ||
24 | this.nsfw = videoDetails.nsfw | ||
25 | this.channel = videoDetails.channel.id | ||
26 | } | ||
27 | |||
13 | patch (values: Object) { | 28 | patch (values: Object) { |
14 | Object.keys(values).forEach((key) => { | 29 | Object.keys(values).forEach((key) => { |
15 | this[key] = values[key] | 30 | this[key] = values[key] |
diff --git a/client/src/app/videos/shared/video.service.ts b/client/src/app/videos/shared/video.service.ts index 06fb3313e..8fdc1f213 100644 --- a/client/src/app/videos/shared/video.service.ts +++ b/client/src/app/videos/shared/video.service.ts | |||
@@ -36,7 +36,7 @@ export class VideoService { | |||
36 | private restService: RestService | 36 | private restService: RestService |
37 | ) {} | 37 | ) {} |
38 | 38 | ||
39 | getVideo (uuid: string) { | 39 | getVideo (uuid: string): Observable<VideoDetails> { |
40 | return this.authHttp.get<VideoDetailsServerModel>(VideoService.BASE_VIDEO_URL + uuid) | 40 | return this.authHttp.get<VideoDetailsServerModel>(VideoService.BASE_VIDEO_URL + uuid) |
41 | .map(videoHash => new VideoDetails(videoHash)) | 41 | .map(videoHash => new VideoDetails(videoHash)) |
42 | .catch((res) => this.restExtractor.handleError(res)) | 42 | .catch((res) => this.restExtractor.handleError(res)) |
diff --git a/client/yarn.lock b/client/yarn.lock index b63c76e2f..23ab3a3df 100644 --- a/client/yarn.lock +++ b/client/yarn.lock | |||
@@ -102,6 +102,10 @@ | |||
102 | dependencies: | 102 | dependencies: |
103 | "@types/node" "*" | 103 | "@types/node" "*" |
104 | 104 | ||
105 | "@types/markdown-it@^0.0.4": | ||
106 | version "0.0.4" | ||
107 | resolved "https://registry.yarnpkg.com/@types/markdown-it/-/markdown-it-0.0.4.tgz#c5f67365916044b342dae8d702724788ba0b5b74" | ||
108 | |||
105 | "@types/node@*": | 109 | "@types/node@*": |
106 | version "8.0.25" | 110 | version "8.0.25" |
107 | resolved "https://registry.yarnpkg.com/@types/node/-/node-8.0.25.tgz#66ecaf4df93f5281b48427ee96fbcdfc4f0cdce1" | 111 | resolved "https://registry.yarnpkg.com/@types/node/-/node-8.0.25.tgz#66ecaf4df93f5281b48427ee96fbcdfc4f0cdce1" |
@@ -3842,6 +3846,12 @@ levn@^0.3.0, levn@~0.3.0: | |||
3842 | prelude-ls "~1.1.2" | 3846 | prelude-ls "~1.1.2" |
3843 | type-check "~0.3.2" | 3847 | type-check "~0.3.2" |
3844 | 3848 | ||
3849 | linkify-it@^2.0.0: | ||
3850 | version "2.0.3" | ||
3851 | resolved "https://registry.yarnpkg.com/linkify-it/-/linkify-it-2.0.3.tgz#d94a4648f9b1c179d64fa97291268bdb6ce9434f" | ||
3852 | dependencies: | ||
3853 | uc.micro "^1.0.1" | ||
3854 | |||
3845 | load-ip-set@^1.2.7: | 3855 | load-ip-set@^1.2.7: |
3846 | version "1.3.1" | 3856 | version "1.3.1" |
3847 | resolved "https://registry.yarnpkg.com/load-ip-set/-/load-ip-set-1.3.1.tgz#cfd050c6916e7ba0ca85d0b566e7854713eb495e" | 3857 | resolved "https://registry.yarnpkg.com/load-ip-set/-/load-ip-set-1.3.1.tgz#cfd050c6916e7ba0ca85d0b566e7854713eb495e" |
@@ -4169,6 +4179,16 @@ map-visit@^0.1.5: | |||
4169 | lazy-cache "^2.0.1" | 4179 | lazy-cache "^2.0.1" |
4170 | object-visit "^0.3.4" | 4180 | object-visit "^0.3.4" |
4171 | 4181 | ||
4182 | markdown-it@^8.4.0: | ||
4183 | version "8.4.0" | ||
4184 | resolved "https://registry.yarnpkg.com/markdown-it/-/markdown-it-8.4.0.tgz#e2400881bf171f7018ed1bd9da441dac8af6306d" | ||
4185 | dependencies: | ||
4186 | argparse "^1.0.7" | ||
4187 | entities "~1.1.1" | ||
4188 | linkify-it "^2.0.0" | ||
4189 | mdurl "^1.0.1" | ||
4190 | uc.micro "^1.0.3" | ||
4191 | |||
4172 | marked-terminal@^1.6.2: | 4192 | marked-terminal@^1.6.2: |
4173 | version "1.7.0" | 4193 | version "1.7.0" |
4174 | resolved "https://registry.yarnpkg.com/marked-terminal/-/marked-terminal-1.7.0.tgz#c8c460881c772c7604b64367007ee5f77f125904" | 4194 | resolved "https://registry.yarnpkg.com/marked-terminal/-/marked-terminal-1.7.0.tgz#c8c460881c772c7604b64367007ee5f77f125904" |
@@ -4194,6 +4214,10 @@ md5.js@^1.3.4: | |||
4194 | hash-base "^3.0.0" | 4214 | hash-base "^3.0.0" |
4195 | inherits "^2.0.1" | 4215 | inherits "^2.0.1" |
4196 | 4216 | ||
4217 | mdurl@^1.0.1: | ||
4218 | version "1.0.1" | ||
4219 | resolved "https://registry.yarnpkg.com/mdurl/-/mdurl-1.0.1.tgz#fe85b2ec75a59037f2adfec100fd6c601761152e" | ||
4220 | |||
4197 | media-typer@0.3.0: | 4221 | media-typer@0.3.0: |
4198 | version "0.3.0" | 4222 | version "0.3.0" |
4199 | resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748" | 4223 | resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748" |
@@ -6824,6 +6848,10 @@ typescript@^2.5.2: | |||
6824 | version "2.5.3" | 6848 | version "2.5.3" |
6825 | resolved "https://registry.yarnpkg.com/typescript/-/typescript-2.5.3.tgz#df3dcdc38f3beb800d4bc322646b04a3f6ca7f0d" | 6849 | resolved "https://registry.yarnpkg.com/typescript/-/typescript-2.5.3.tgz#df3dcdc38f3beb800d4bc322646b04a3f6ca7f0d" |
6826 | 6850 | ||
6851 | uc.micro@^1.0.1, uc.micro@^1.0.3: | ||
6852 | version "1.0.3" | ||
6853 | resolved "https://registry.yarnpkg.com/uc.micro/-/uc.micro-1.0.3.tgz#7ed50d5e0f9a9fb0a573379259f2a77458d50192" | ||
6854 | |||
6827 | uglify-js@3.0.x, uglify-js@^3.0.6: | 6855 | uglify-js@3.0.x, uglify-js@^3.0.6: |
6828 | version "3.0.28" | 6856 | version "3.0.28" |
6829 | resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.0.28.tgz#96b8495f0272944787b5843a1679aa326640d5f7" | 6857 | resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.0.28.tgz#96b8495f0272944787b5843a1679aa326640d5f7" |