wrap the hotkeys component to allow templating :art:
[oweals/peertube.git] / client / src / app / shared / forms / markdown-textarea.component.ts
1 import { debounceTime, distinctUntilChanged } from 'rxjs/operators'
2 import { Component, forwardRef, Input, OnInit } from '@angular/core'
3 import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms'
4 import { MarkdownService } from '@app/videos/shared'
5 import { Subject } from 'rxjs'
6 import truncate from 'lodash-es/truncate'
7 import { ScreenService } from '@app/shared/misc/screen.service'
8
9 @Component({
10   selector: 'my-markdown-textarea',
11   templateUrl: './markdown-textarea.component.html',
12   styleUrls: [ './markdown-textarea.component.scss' ],
13   providers: [
14     {
15       provide: NG_VALUE_ACCESSOR,
16       useExisting: forwardRef(() => MarkdownTextareaComponent),
17       multi: true
18     }
19   ]
20 })
21
22 export class MarkdownTextareaComponent implements ControlValueAccessor, OnInit {
23   @Input() content = ''
24   @Input() classes: string[] = []
25   @Input() textareaWidth = '100%'
26   @Input() textareaHeight = '150px'
27   @Input() previewColumn = false
28   @Input() truncate: number
29   @Input() markdownType: 'text' | 'enhanced' = 'text'
30
31   textareaMarginRight = '0'
32   flexDirection = 'column'
33   truncatedPreviewHTML = ''
34   previewHTML = ''
35
36   private contentChanged = new Subject<string>()
37
38   constructor (
39     private screenService: ScreenService,
40     private markdownService: MarkdownService
41 ) {}
42
43   ngOnInit () {
44     this.contentChanged
45         .pipe(
46           debounceTime(150),
47           distinctUntilChanged()
48         )
49         .subscribe(() => this.updatePreviews())
50
51     this.contentChanged.next(this.content)
52
53     if (this.previewColumn) {
54       this.flexDirection = 'row'
55       this.textareaMarginRight = '15px'
56     }
57   }
58
59   propagateChange = (_: any) => { /* empty */ }
60
61   writeValue (description: string) {
62     this.content = description
63
64     this.contentChanged.next(this.content)
65   }
66
67   registerOnChange (fn: (_: any) => void) {
68     this.propagateChange = fn
69   }
70
71   registerOnTouched () {
72     // Unused
73   }
74
75   onModelChange () {
76     this.propagateChange(this.content)
77
78     this.contentChanged.next(this.content)
79   }
80
81   arePreviewsDisplayed () {
82     return this.screenService.isInSmallView() === false
83   }
84
85   private updatePreviews () {
86     if (this.content === null || this.content === undefined) return
87
88     this.truncatedPreviewHTML = this.markdownRender(truncate(this.content, { length: this.truncate }))
89     this.previewHTML = this.markdownRender(this.content)
90   }
91
92   private markdownRender (text: string) {
93     if (this.markdownType === 'text') return this.markdownService.textMarkdownToHTML(text)
94
95     return this.markdownService.enhancedMarkdownToHTML(text)
96   }
97 }