Add markdown support to video description

pull/125/head
Chocobozzz 2017-10-26 15:01:47 +02:00
parent 4077df72c6
commit 9d9597df42
No known key found for this signature in database
GPG Key ID: 583A612D890159BE
10 changed files with 97 additions and 8 deletions

View File

@ -35,6 +35,7 @@
"@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",
@ -66,6 +67,7 @@
"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",

View File

@ -87,7 +87,7 @@ export class VideoUpdateComponent extends FormReactive implements OnInit {
this.videoService.getVideo(uuid)
.subscribe(
video => {
this.video = video
this.video = new VideoEdit(video)
this.hydrateFormFromVideo()
},

View File

@ -128,9 +128,7 @@
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">

View File

@ -13,7 +13,7 @@ import { AuthService, ConfirmService } from '../../core'
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'
@ -38,6 +38,7 @@ export class VideoWatchComponent implements OnInit, OnDestroy {
video: VideoDetails = null
videoPlayerLoaded = false
videoNotFound = false
videoHTMLDescription = ''
private paramsSub: Subscription
@ -50,7 +51,8 @@ export class VideoWatchComponent implements OnInit, OnDestroy {
private confirmService: ConfirmService,
private metaService: MetaService,
private authService: AuthService,
private notificationsService: NotificationsService
private notificationsService: NotificationsService,
private markdownService: MarkdownService
) {}
ngOnInit () {
@ -259,6 +261,8 @@ export class VideoWatchComponent implements OnInit, OnDestroy {
})
})
this.videoHTMLDescription = this.markdownService.markdownToHTML(this.video.description)
this.setOpenGraphTags()
this.checkUserRating()
}

View File

@ -1,7 +1,7 @@
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'
@ -28,6 +28,7 @@ import { VideoDownloadComponent } from './video-download.component'
],
providers: [
MarkdownService,
VideoService
]
})

View File

@ -1,4 +1,5 @@
export * from './sort-field.type'
export * from './markdown.service'
export * from './video.model'
export * from './video-details.model'
export * from './video-edit.model'

View 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)
}
}

View File

@ -1,3 +1,5 @@
import { VideoDetails } from './video-details.model'
export class VideoEdit {
category: number
licence: number
@ -10,6 +12,19 @@ export class VideoEdit {
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]

View File

@ -36,7 +36,7 @@ export class VideoService {
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))

View File

@ -102,6 +102,10 @@
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"
@ -3842,6 +3846,12 @@ levn@^0.3.0, levn@~0.3.0:
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"
@ -4169,6 +4179,16 @@ map-visit@^0.1.5:
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"
@ -4194,6 +4214,10 @@ md5.js@^1.3.4:
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"
@ -6824,6 +6848,10 @@ typescript@^2.5.2:
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"