"@angularclass/hmr-loader": "^3.0.2",
"@ngx-meta/core": "^4.0.1",
"@types/core-js": "^0.9.28",
+ "@types/markdown-it": "^0.0.4",
"@types/node": "^8.0.33",
"@types/source-map": "^0.5.1",
"@types/uglify-js": "^2.0.27",
"inline-manifest-webpack-plugin": "^3.0.1",
"intl": "^1.2.4",
"json-loader": "^0.5.4",
+ "markdown-it": "^8.4.0",
"ng-router-loader": "^2.0.0",
"ngc-webpack": "3.2.2",
"ngx-bootstrap": "1.9.3",
this.videoService.getVideo(uuid)
.subscribe(
video => {
- this.video = video
+ this.video = new VideoEdit(video)
this.hydrateFormFromVideo()
},
Published on {{ video.createdAt | date:'short' }}
</div>
- <div class="video-details-description">
- {{ video.description }}
- </div>
+ <div class="video-details-description" [innerHTML]="videoHTMLDescription"></div>
</div>
<div class="video-details-attributes col-xs-4 col-md-3">
import { VideoDownloadComponent } from './video-download.component'
import { VideoShareComponent } from './video-share.component'
import { VideoReportComponent } from './video-report.component'
-import { VideoDetails, VideoService } from '../shared'
+import { VideoDetails, VideoService, MarkdownService } from '../shared'
import { VideoBlacklistService } from '../../shared'
import { UserVideoRateType, VideoRateType } from '../../../../../shared'
video: VideoDetails = null
videoPlayerLoaded = false
videoNotFound = false
+ videoHTMLDescription = ''
private paramsSub: Subscription
private confirmService: ConfirmService,
private metaService: MetaService,
private authService: AuthService,
- private notificationsService: NotificationsService
+ private notificationsService: NotificationsService,
+ private markdownService: MarkdownService
) {}
ngOnInit () {
})
})
+ this.videoHTMLDescription = this.markdownService.markdownToHTML(this.video.description)
+
this.setOpenGraphTags()
this.checkUserRating()
}
import { NgModule } from '@angular/core'
import { VideoWatchRoutingModule } from './video-watch-routing.module'
-import { VideoService } from '../shared'
+import { VideoService, MarkdownService } from '../shared'
import { SharedModule } from '../../shared'
import { VideoWatchComponent } from './video-watch.component'
],
providers: [
+ MarkdownService,
VideoService
]
})
export * from './sort-field.type'
+export * from './markdown.service'
export * from './video.model'
export * from './video-details.model'
export * from './video-edit.model'
--- /dev/null
+import { Injectable } from '@angular/core'
+
+import * as MarkdownIt from 'markdown-it'
+
+@Injectable()
+export class MarkdownService {
+ private markdownIt: MarkdownIt.MarkdownIt
+
+ constructor () {
+ this.markdownIt = new MarkdownIt('zero', { linkify: true })
+ .enable('linkify')
+ .enable('autolink')
+ .enable('emphasis')
+ .enable('link')
+ .enable('newline')
+
+ // Snippet from markdown-it documentation: https://github.com/markdown-it/markdown-it/blob/master/docs/architecture.md#renderer
+ const defaultRender = this.markdownIt.renderer.rules.link_open || function (tokens, idx, options, env, self) {
+ return self.renderToken(tokens, idx, options)
+ }
+
+ this.markdownIt.renderer.rules.link_open = function (tokens, idx, options, env, self) {
+ // If you are sure other plugins can't add `target` - drop check below
+ const aIndex = tokens[idx].attrIndex('target')
+
+ if (aIndex < 0) {
+ tokens[idx].attrPush(['target', '_blank']) // add new attribute
+ } else {
+ tokens[idx].attrs[aIndex][1] = '_blank' // replace value of existing attr
+ }
+
+ // pass token to default renderer.
+ return defaultRender(tokens, idx, options, env, self)
+ }
+ }
+
+ markdownToHTML (markdown: string) {
+ return this.markdownIt.render(markdown)
+ }
+}
+import { VideoDetails } from './video-details.model'
+
export class VideoEdit {
category: number
licence: number
uuid?: string
id?: number
+ constructor (videoDetails: VideoDetails) {
+ this.id = videoDetails.id
+ this.uuid = videoDetails.uuid
+ this.category = videoDetails.category
+ this.licence = videoDetails.licence
+ this.language = videoDetails.language
+ this.description = videoDetails.description
+ this.name = videoDetails.name
+ this.tags = videoDetails.tags
+ this.nsfw = videoDetails.nsfw
+ this.channel = videoDetails.channel.id
+ }
+
patch (values: Object) {
Object.keys(values).forEach((key) => {
this[key] = values[key]
private restService: RestService
) {}
- getVideo (uuid: string) {
+ getVideo (uuid: string): Observable<VideoDetails> {
return this.authHttp.get<VideoDetailsServerModel>(VideoService.BASE_VIDEO_URL + uuid)
.map(videoHash => new VideoDetails(videoHash))
.catch((res) => this.restExtractor.handleError(res))
dependencies:
"@types/node" "*"
+"@types/markdown-it@^0.0.4":
+ version "0.0.4"
+ resolved "https://registry.yarnpkg.com/@types/markdown-it/-/markdown-it-0.0.4.tgz#c5f67365916044b342dae8d702724788ba0b5b74"
+
"@types/node@*":
version "8.0.25"
resolved "https://registry.yarnpkg.com/@types/node/-/node-8.0.25.tgz#66ecaf4df93f5281b48427ee96fbcdfc4f0cdce1"
prelude-ls "~1.1.2"
type-check "~0.3.2"
+linkify-it@^2.0.0:
+ version "2.0.3"
+ resolved "https://registry.yarnpkg.com/linkify-it/-/linkify-it-2.0.3.tgz#d94a4648f9b1c179d64fa97291268bdb6ce9434f"
+ dependencies:
+ uc.micro "^1.0.1"
+
load-ip-set@^1.2.7:
version "1.3.1"
resolved "https://registry.yarnpkg.com/load-ip-set/-/load-ip-set-1.3.1.tgz#cfd050c6916e7ba0ca85d0b566e7854713eb495e"
lazy-cache "^2.0.1"
object-visit "^0.3.4"
+markdown-it@^8.4.0:
+ version "8.4.0"
+ resolved "https://registry.yarnpkg.com/markdown-it/-/markdown-it-8.4.0.tgz#e2400881bf171f7018ed1bd9da441dac8af6306d"
+ dependencies:
+ argparse "^1.0.7"
+ entities "~1.1.1"
+ linkify-it "^2.0.0"
+ mdurl "^1.0.1"
+ uc.micro "^1.0.3"
+
marked-terminal@^1.6.2:
version "1.7.0"
resolved "https://registry.yarnpkg.com/marked-terminal/-/marked-terminal-1.7.0.tgz#c8c460881c772c7604b64367007ee5f77f125904"
hash-base "^3.0.0"
inherits "^2.0.1"
+mdurl@^1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/mdurl/-/mdurl-1.0.1.tgz#fe85b2ec75a59037f2adfec100fd6c601761152e"
+
media-typer@0.3.0:
version "0.3.0"
resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748"
version "2.5.3"
resolved "https://registry.yarnpkg.com/typescript/-/typescript-2.5.3.tgz#df3dcdc38f3beb800d4bc322646b04a3f6ca7f0d"
+uc.micro@^1.0.1, uc.micro@^1.0.3:
+ version "1.0.3"
+ resolved "https://registry.yarnpkg.com/uc.micro/-/uc.micro-1.0.3.tgz#7ed50d5e0f9a9fb0a573379259f2a77458d50192"
+
uglify-js@3.0.x, uglify-js@^3.0.6:
version "3.0.28"
resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.0.28.tgz#96b8495f0272944787b5843a1679aa326640d5f7"