Add markdown support to video description
This commit is contained in:
parent
4077df72c6
commit
9d9597df42
|
@ -35,6 +35,7 @@
|
||||||
"@angularclass/hmr-loader": "^3.0.2",
|
"@angularclass/hmr-loader": "^3.0.2",
|
||||||
"@ngx-meta/core": "^4.0.1",
|
"@ngx-meta/core": "^4.0.1",
|
||||||
"@types/core-js": "^0.9.28",
|
"@types/core-js": "^0.9.28",
|
||||||
|
"@types/markdown-it": "^0.0.4",
|
||||||
"@types/node": "^8.0.33",
|
"@types/node": "^8.0.33",
|
||||||
"@types/source-map": "^0.5.1",
|
"@types/source-map": "^0.5.1",
|
||||||
"@types/uglify-js": "^2.0.27",
|
"@types/uglify-js": "^2.0.27",
|
||||||
|
@ -66,6 +67,7 @@
|
||||||
"inline-manifest-webpack-plugin": "^3.0.1",
|
"inline-manifest-webpack-plugin": "^3.0.1",
|
||||||
"intl": "^1.2.4",
|
"intl": "^1.2.4",
|
||||||
"json-loader": "^0.5.4",
|
"json-loader": "^0.5.4",
|
||||||
|
"markdown-it": "^8.4.0",
|
||||||
"ng-router-loader": "^2.0.0",
|
"ng-router-loader": "^2.0.0",
|
||||||
"ngc-webpack": "3.2.2",
|
"ngc-webpack": "3.2.2",
|
||||||
"ngx-bootstrap": "1.9.3",
|
"ngx-bootstrap": "1.9.3",
|
||||||
|
|
|
@ -87,7 +87,7 @@ export class VideoUpdateComponent extends FormReactive implements OnInit {
|
||||||
this.videoService.getVideo(uuid)
|
this.videoService.getVideo(uuid)
|
||||||
.subscribe(
|
.subscribe(
|
||||||
video => {
|
video => {
|
||||||
this.video = video
|
this.video = new VideoEdit(video)
|
||||||
|
|
||||||
this.hydrateFormFromVideo()
|
this.hydrateFormFromVideo()
|
||||||
},
|
},
|
||||||
|
|
|
@ -128,9 +128,7 @@
|
||||||
Published on {{ video.createdAt | date:'short' }}
|
Published on {{ video.createdAt | date:'short' }}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="video-details-description">
|
<div class="video-details-description" [innerHTML]="videoHTMLDescription"></div>
|
||||||
{{ video.description }}
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="video-details-attributes col-xs-4 col-md-3">
|
<div class="video-details-attributes col-xs-4 col-md-3">
|
||||||
|
|
|
@ -13,7 +13,7 @@ import { AuthService, ConfirmService } from '../../core'
|
||||||
import { VideoDownloadComponent } from './video-download.component'
|
import { VideoDownloadComponent } from './video-download.component'
|
||||||
import { VideoShareComponent } from './video-share.component'
|
import { VideoShareComponent } from './video-share.component'
|
||||||
import { VideoReportComponent } from './video-report.component'
|
import { VideoReportComponent } from './video-report.component'
|
||||||
import { VideoDetails, VideoService } from '../shared'
|
import { VideoDetails, VideoService, MarkdownService } from '../shared'
|
||||||
import { VideoBlacklistService } from '../../shared'
|
import { VideoBlacklistService } from '../../shared'
|
||||||
import { UserVideoRateType, VideoRateType } from '../../../../../shared'
|
import { UserVideoRateType, VideoRateType } from '../../../../../shared'
|
||||||
|
|
||||||
|
@ -38,6 +38,7 @@ export class VideoWatchComponent implements OnInit, OnDestroy {
|
||||||
video: VideoDetails = null
|
video: VideoDetails = null
|
||||||
videoPlayerLoaded = false
|
videoPlayerLoaded = false
|
||||||
videoNotFound = false
|
videoNotFound = false
|
||||||
|
videoHTMLDescription = ''
|
||||||
|
|
||||||
private paramsSub: Subscription
|
private paramsSub: Subscription
|
||||||
|
|
||||||
|
@ -50,7 +51,8 @@ export class VideoWatchComponent implements OnInit, OnDestroy {
|
||||||
private confirmService: ConfirmService,
|
private confirmService: ConfirmService,
|
||||||
private metaService: MetaService,
|
private metaService: MetaService,
|
||||||
private authService: AuthService,
|
private authService: AuthService,
|
||||||
private notificationsService: NotificationsService
|
private notificationsService: NotificationsService,
|
||||||
|
private markdownService: MarkdownService
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
ngOnInit () {
|
ngOnInit () {
|
||||||
|
@ -259,6 +261,8 @@ export class VideoWatchComponent implements OnInit, OnDestroy {
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
this.videoHTMLDescription = this.markdownService.markdownToHTML(this.video.description)
|
||||||
|
|
||||||
this.setOpenGraphTags()
|
this.setOpenGraphTags()
|
||||||
this.checkUserRating()
|
this.checkUserRating()
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import { NgModule } from '@angular/core'
|
import { NgModule } from '@angular/core'
|
||||||
|
|
||||||
import { VideoWatchRoutingModule } from './video-watch-routing.module'
|
import { VideoWatchRoutingModule } from './video-watch-routing.module'
|
||||||
import { VideoService } from '../shared'
|
import { VideoService, MarkdownService } from '../shared'
|
||||||
import { SharedModule } from '../../shared'
|
import { SharedModule } from '../../shared'
|
||||||
|
|
||||||
import { VideoWatchComponent } from './video-watch.component'
|
import { VideoWatchComponent } from './video-watch.component'
|
||||||
|
@ -28,6 +28,7 @@ import { VideoDownloadComponent } from './video-download.component'
|
||||||
],
|
],
|
||||||
|
|
||||||
providers: [
|
providers: [
|
||||||
|
MarkdownService,
|
||||||
VideoService
|
VideoService
|
||||||
]
|
]
|
||||||
})
|
})
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
export * from './sort-field.type'
|
export * from './sort-field.type'
|
||||||
|
export * from './markdown.service'
|
||||||
export * from './video.model'
|
export * from './video.model'
|
||||||
export * from './video-details.model'
|
export * from './video-details.model'
|
||||||
export * from './video-edit.model'
|
export * from './video-edit.model'
|
||||||
|
|
40
client/src/app/videos/shared/markdown.service.ts
Normal file
40
client/src/app/videos/shared/markdown.service.ts
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,3 +1,5 @@
|
||||||
|
import { VideoDetails } from './video-details.model'
|
||||||
|
|
||||||
export class VideoEdit {
|
export class VideoEdit {
|
||||||
category: number
|
category: number
|
||||||
licence: number
|
licence: number
|
||||||
|
@ -10,6 +12,19 @@ export class VideoEdit {
|
||||||
uuid?: string
|
uuid?: string
|
||||||
id?: number
|
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) {
|
patch (values: Object) {
|
||||||
Object.keys(values).forEach((key) => {
|
Object.keys(values).forEach((key) => {
|
||||||
this[key] = values[key]
|
this[key] = values[key]
|
||||||
|
|
|
@ -36,7 +36,7 @@ export class VideoService {
|
||||||
private restService: RestService
|
private restService: RestService
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
getVideo (uuid: string) {
|
getVideo (uuid: string): Observable<VideoDetails> {
|
||||||
return this.authHttp.get<VideoDetailsServerModel>(VideoService.BASE_VIDEO_URL + uuid)
|
return this.authHttp.get<VideoDetailsServerModel>(VideoService.BASE_VIDEO_URL + uuid)
|
||||||
.map(videoHash => new VideoDetails(videoHash))
|
.map(videoHash => new VideoDetails(videoHash))
|
||||||
.catch((res) => this.restExtractor.handleError(res))
|
.catch((res) => this.restExtractor.handleError(res))
|
||||||
|
|
|
@ -102,6 +102,10 @@
|
||||||
dependencies:
|
dependencies:
|
||||||
"@types/node" "*"
|
"@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@*":
|
"@types/node@*":
|
||||||
version "8.0.25"
|
version "8.0.25"
|
||||||
resolved "https://registry.yarnpkg.com/@types/node/-/node-8.0.25.tgz#66ecaf4df93f5281b48427ee96fbcdfc4f0cdce1"
|
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:
|
||||||
prelude-ls "~1.1.2"
|
prelude-ls "~1.1.2"
|
||||||
type-check "~0.3.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:
|
load-ip-set@^1.2.7:
|
||||||
version "1.3.1"
|
version "1.3.1"
|
||||||
resolved "https://registry.yarnpkg.com/load-ip-set/-/load-ip-set-1.3.1.tgz#cfd050c6916e7ba0ca85d0b566e7854713eb495e"
|
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:
|
||||||
lazy-cache "^2.0.1"
|
lazy-cache "^2.0.1"
|
||||||
object-visit "^0.3.4"
|
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:
|
marked-terminal@^1.6.2:
|
||||||
version "1.7.0"
|
version "1.7.0"
|
||||||
resolved "https://registry.yarnpkg.com/marked-terminal/-/marked-terminal-1.7.0.tgz#c8c460881c772c7604b64367007ee5f77f125904"
|
resolved "https://registry.yarnpkg.com/marked-terminal/-/marked-terminal-1.7.0.tgz#c8c460881c772c7604b64367007ee5f77f125904"
|
||||||
|
@ -4194,6 +4214,10 @@ md5.js@^1.3.4:
|
||||||
hash-base "^3.0.0"
|
hash-base "^3.0.0"
|
||||||
inherits "^2.0.1"
|
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:
|
media-typer@0.3.0:
|
||||||
version "0.3.0"
|
version "0.3.0"
|
||||||
resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748"
|
resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748"
|
||||||
|
@ -6824,6 +6848,10 @@ typescript@^2.5.2:
|
||||||
version "2.5.3"
|
version "2.5.3"
|
||||||
resolved "https://registry.yarnpkg.com/typescript/-/typescript-2.5.3.tgz#df3dcdc38f3beb800d4bc322646b04a3f6ca7f0d"
|
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:
|
uglify-js@3.0.x, uglify-js@^3.0.6:
|
||||||
version "3.0.28"
|
version "3.0.28"
|
||||||
resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.0.28.tgz#96b8495f0272944787b5843a1679aa326640d5f7"
|
resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.0.28.tgz#96b8495f0272944787b5843a1679aa326640d5f7"
|
||||||
|
|
Loading…
Reference in New Issue
Block a user