Lazy description and previews to video form
This commit is contained in:
parent
8bf89b095a
commit
2de96f4d6b
|
@ -81,7 +81,7 @@ styles:
|
||||||
dropdowns: true
|
dropdowns: true
|
||||||
button-groups: true
|
button-groups: true
|
||||||
input-groups: true
|
input-groups: true
|
||||||
navs: false
|
navs: true
|
||||||
navbar: false
|
navbar: false
|
||||||
breadcrumbs: false
|
breadcrumbs: false
|
||||||
pagination: true
|
pagination: true
|
||||||
|
|
|
@ -3,6 +3,8 @@ import { Router } from '@angular/router'
|
||||||
import { Observable } from 'rxjs/Observable'
|
import { Observable } from 'rxjs/Observable'
|
||||||
import { Subject } from 'rxjs/Subject'
|
import { Subject } from 'rxjs/Subject'
|
||||||
import { HttpClient, HttpHeaders, HttpParams } from '@angular/common/http'
|
import { HttpClient, HttpHeaders, HttpParams } from '@angular/common/http'
|
||||||
|
import { ReplaySubject } from 'rxjs/ReplaySubject'
|
||||||
|
import 'rxjs/add/operator/do'
|
||||||
import 'rxjs/add/operator/map'
|
import 'rxjs/add/operator/map'
|
||||||
import 'rxjs/add/operator/mergeMap'
|
import 'rxjs/add/operator/mergeMap'
|
||||||
import 'rxjs/add/observable/throw'
|
import 'rxjs/add/observable/throw'
|
||||||
|
@ -54,6 +56,7 @@ export class AuthService {
|
||||||
private static BASE_USER_INFORMATION_URL = API_URL + '/api/v1/users/me'
|
private static BASE_USER_INFORMATION_URL = API_URL + '/api/v1/users/me'
|
||||||
|
|
||||||
loginChangedSource: Observable<AuthStatus>
|
loginChangedSource: Observable<AuthStatus>
|
||||||
|
userInformationLoaded = new ReplaySubject<boolean>(1)
|
||||||
|
|
||||||
private clientId: string
|
private clientId: string
|
||||||
private clientSecret: string
|
private clientSecret: string
|
||||||
|
@ -199,16 +202,17 @@ export class AuthService {
|
||||||
}
|
}
|
||||||
|
|
||||||
this.mergeUserInformation(obj)
|
this.mergeUserInformation(obj)
|
||||||
.subscribe(
|
.do(() => this.userInformationLoaded.next(true))
|
||||||
res => {
|
.subscribe(
|
||||||
this.user.displayNSFW = res.displayNSFW
|
res => {
|
||||||
this.user.role = res.role
|
this.user.displayNSFW = res.displayNSFW
|
||||||
this.user.videoChannels = res.videoChannels
|
this.user.role = res.role
|
||||||
this.user.author = res.author
|
this.user.videoChannels = res.videoChannels
|
||||||
|
this.user.author = res.author
|
||||||
|
|
||||||
this.user.save()
|
this.user.save()
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private mergeUserInformation (obj: UserLoginWithUsername): Observable<UserLoginWithUserInformation> {
|
private mergeUserInformation (obj: UserLoginWithUsername): Observable<UserLoginWithUserInformation> {
|
||||||
|
|
|
@ -36,11 +36,11 @@ export const VIDEO_CHANNEL = {
|
||||||
}
|
}
|
||||||
|
|
||||||
export const VIDEO_DESCRIPTION = {
|
export const VIDEO_DESCRIPTION = {
|
||||||
VALIDATORS: [ Validators.required, Validators.minLength(3), Validators.maxLength(250) ],
|
VALIDATORS: [ Validators.required, Validators.minLength(3), Validators.maxLength(3000) ],
|
||||||
MESSAGES: {
|
MESSAGES: {
|
||||||
'required': 'Video description is required.',
|
'required': 'Video description is required.',
|
||||||
'minlength': 'Video description must be at least 3 characters long.',
|
'minlength': 'Video description must be at least 3 characters long.',
|
||||||
'maxlength': 'Video description cannot be more than 250 characters long.'
|
'maxlength': 'Video description cannot be more than 3000 characters long.'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -28,7 +28,6 @@
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="category">Channel</label>
|
<label for="category">Channel</label>
|
||||||
<select class="form-control" id="channelId" formControlName="channelId">
|
<select class="form-control" id="channelId" formControlName="channelId">
|
||||||
<option></option>
|
|
||||||
<option *ngFor="let channel of userVideoChannels" [value]="channel.id">{{ channel.label }}</option>
|
<option *ngFor="let channel of userVideoChannels" [value]="channel.id">{{ channel.label }}</option>
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
|
@ -103,11 +102,8 @@
|
||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="description">Description</label>
|
<label for="description">Description</label>
|
||||||
<textarea
|
<my-video-description formControlName="description"></my-video-description>
|
||||||
id="description" class="form-control" placeholder="Description..."
|
|
||||||
formControlName="description"
|
|
||||||
>
|
|
||||||
</textarea>
|
|
||||||
<div *ngIf="formErrors.description" class="alert alert-danger">
|
<div *ngIf="formErrors.description" class="alert alert-danger">
|
||||||
{{ formErrors.description }}
|
{{ formErrors.description }}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -82,7 +82,7 @@ export class VideoAddComponent extends FormReactive implements OnInit {
|
||||||
category: [ '', VIDEO_CATEGORY.VALIDATORS ],
|
category: [ '', VIDEO_CATEGORY.VALIDATORS ],
|
||||||
licence: [ '', VIDEO_LICENCE.VALIDATORS ],
|
licence: [ '', VIDEO_LICENCE.VALIDATORS ],
|
||||||
language: [ '', VIDEO_LANGUAGE.VALIDATORS ],
|
language: [ '', VIDEO_LANGUAGE.VALIDATORS ],
|
||||||
channelId: [ this.userVideoChannels[0].id, VIDEO_CHANNEL.VALIDATORS ],
|
channelId: [ '', VIDEO_CHANNEL.VALIDATORS ],
|
||||||
description: [ '', VIDEO_DESCRIPTION.VALIDATORS ],
|
description: [ '', VIDEO_DESCRIPTION.VALIDATORS ],
|
||||||
videofile: [ '', VIDEO_FILE.VALIDATORS ],
|
videofile: [ '', VIDEO_FILE.VALIDATORS ],
|
||||||
tags: [ '' ]
|
tags: [ '' ]
|
||||||
|
@ -96,10 +96,22 @@ export class VideoAddComponent extends FormReactive implements OnInit {
|
||||||
this.videoLicences = this.serverService.getVideoLicences()
|
this.videoLicences = this.serverService.getVideoLicences()
|
||||||
this.videoLanguages = this.serverService.getVideoLanguages()
|
this.videoLanguages = this.serverService.getVideoLanguages()
|
||||||
|
|
||||||
const user = this.authService.getUser()
|
|
||||||
this.userVideoChannels = user.videoChannels.map(v => ({ id: v.id, label: v.name }))
|
|
||||||
|
|
||||||
this.buildForm()
|
this.buildForm()
|
||||||
|
|
||||||
|
this.authService.userInformationLoaded
|
||||||
|
.subscribe(
|
||||||
|
() => {
|
||||||
|
const user = this.authService.getUser()
|
||||||
|
if (!user) return
|
||||||
|
|
||||||
|
const videoChannels = user.videoChannels
|
||||||
|
if (Array.isArray(videoChannels) === false) return
|
||||||
|
|
||||||
|
this.userVideoChannels = videoChannels.map(v => ({ id: v.id, label: v.name }))
|
||||||
|
|
||||||
|
this.form.patchValue({ channelId: this.userVideoChannels[0].id })
|
||||||
|
}
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// The goal is to keep reactive form validation (required field)
|
// The goal is to keep reactive form validation (required field)
|
||||||
|
|
|
@ -1,17 +1,14 @@
|
||||||
import { NgModule } from '@angular/core'
|
import { NgModule } from '@angular/core'
|
||||||
|
|
||||||
import { TagInputModule } from 'ngx-chips'
|
|
||||||
|
|
||||||
import { VideoAddRoutingModule } from './video-add-routing.module'
|
import { VideoAddRoutingModule } from './video-add-routing.module'
|
||||||
import { VideoAddComponent } from './video-add.component'
|
import { VideoAddComponent } from './video-add.component'
|
||||||
import { VideoService } from '../shared'
|
import { VideoEditModule } from './video-edit.module'
|
||||||
import { SharedModule } from '../../shared'
|
import { SharedModule } from '../../shared'
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
imports: [
|
imports: [
|
||||||
TagInputModule,
|
|
||||||
|
|
||||||
VideoAddRoutingModule,
|
VideoAddRoutingModule,
|
||||||
|
VideoEditModule,
|
||||||
SharedModule
|
SharedModule
|
||||||
],
|
],
|
||||||
|
|
||||||
|
@ -23,8 +20,6 @@ import { SharedModule } from '../../shared'
|
||||||
VideoAddComponent
|
VideoAddComponent
|
||||||
],
|
],
|
||||||
|
|
||||||
providers: [
|
providers: [ ]
|
||||||
VideoService
|
|
||||||
]
|
|
||||||
})
|
})
|
||||||
export class VideoAddModule { }
|
export class VideoAddModule { }
|
||||||
|
|
|
@ -0,0 +1,33 @@
|
||||||
|
import { NgModule } from '@angular/core'
|
||||||
|
|
||||||
|
import { TagInputModule } from 'ngx-chips'
|
||||||
|
import { TabsModule } from 'ngx-bootstrap/tabs'
|
||||||
|
|
||||||
|
import { VideoService, MarkdownService, VideoDescriptionComponent } from '../shared'
|
||||||
|
import { SharedModule } from '../../shared'
|
||||||
|
|
||||||
|
@NgModule({
|
||||||
|
imports: [
|
||||||
|
TagInputModule,
|
||||||
|
TabsModule.forRoot(),
|
||||||
|
|
||||||
|
SharedModule
|
||||||
|
],
|
||||||
|
|
||||||
|
declarations: [
|
||||||
|
VideoDescriptionComponent
|
||||||
|
],
|
||||||
|
|
||||||
|
exports: [
|
||||||
|
TagInputModule,
|
||||||
|
TabsModule,
|
||||||
|
|
||||||
|
VideoDescriptionComponent
|
||||||
|
],
|
||||||
|
|
||||||
|
providers: [
|
||||||
|
VideoService,
|
||||||
|
MarkdownService
|
||||||
|
]
|
||||||
|
})
|
||||||
|
export class VideoEditModule { }
|
|
@ -62,7 +62,7 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="tags" class="label-tags">Tags</label> <span class="little-information">(press enter to add the tag)</span>
|
<label class="label-tags">Tags</label> <span class="little-information">(press enter to add the tag)</span>
|
||||||
<tag-input
|
<tag-input
|
||||||
[ngModel]="tags" [validators]="tagValidators" [errorMessages]="tagValidatorsMessages"
|
[ngModel]="tags" [validators]="tagValidators" [errorMessages]="tagValidatorsMessages"
|
||||||
formControlName="tags" maxItems="5" modelAsStrings="true"
|
formControlName="tags" maxItems="5" modelAsStrings="true"
|
||||||
|
@ -71,11 +71,8 @@
|
||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="description">Description</label>
|
<label for="description">Description</label>
|
||||||
<textarea
|
<my-video-description formControlName="description"></my-video-description>
|
||||||
id="description" class="form-control" placeholder="Description..."
|
|
||||||
formControlName="description"
|
|
||||||
>
|
|
||||||
</textarea>
|
|
||||||
<div *ngIf="formErrors.description" class="alert alert-danger">
|
<div *ngIf="formErrors.description" class="alert alert-danger">
|
||||||
{{ formErrors.description }}
|
{{ formErrors.description }}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
import { Component, OnInit } from '@angular/core'
|
import { Component, OnInit } from '@angular/core'
|
||||||
import { FormBuilder, FormGroup } from '@angular/forms'
|
import { FormBuilder, FormGroup } from '@angular/forms'
|
||||||
import { ActivatedRoute, Router } from '@angular/router'
|
import { ActivatedRoute, Router } from '@angular/router'
|
||||||
|
import { Observable } from 'rxjs/Observable'
|
||||||
|
import 'rxjs/add/observable/forkJoin'
|
||||||
|
|
||||||
import { NotificationsService } from 'angular2-notifications'
|
import { NotificationsService } from 'angular2-notifications'
|
||||||
|
|
||||||
|
@ -84,19 +86,26 @@ export class VideoUpdateComponent extends FormReactive implements OnInit {
|
||||||
this.videoLanguages = this.serverService.getVideoLanguages()
|
this.videoLanguages = this.serverService.getVideoLanguages()
|
||||||
|
|
||||||
const uuid: string = this.route.snapshot.params['uuid']
|
const uuid: string = this.route.snapshot.params['uuid']
|
||||||
|
|
||||||
this.videoService.getVideo(uuid)
|
this.videoService.getVideo(uuid)
|
||||||
.subscribe(
|
.switchMap(video => {
|
||||||
video => {
|
return this.videoService
|
||||||
this.video = new VideoEdit(video)
|
.loadCompleteDescription(video.descriptionPath)
|
||||||
|
.do(description => video.description = description)
|
||||||
|
.map(() => video)
|
||||||
|
})
|
||||||
|
.subscribe(
|
||||||
|
video => {
|
||||||
|
this.video = new VideoEdit(video)
|
||||||
|
|
||||||
this.hydrateFormFromVideo()
|
this.hydrateFormFromVideo()
|
||||||
},
|
},
|
||||||
|
|
||||||
err => {
|
err => {
|
||||||
console.error(err)
|
console.error(err)
|
||||||
this.error = 'Cannot fetch video.'
|
this.error = 'Cannot fetch video.'
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
checkForm () {
|
checkForm () {
|
||||||
|
|
|
@ -1,17 +1,14 @@
|
||||||
import { NgModule } from '@angular/core'
|
import { NgModule } from '@angular/core'
|
||||||
|
|
||||||
import { TagInputModule } from 'ngx-chips'
|
|
||||||
|
|
||||||
import { VideoUpdateRoutingModule } from './video-update-routing.module'
|
import { VideoUpdateRoutingModule } from './video-update-routing.module'
|
||||||
import { VideoUpdateComponent } from './video-update.component'
|
import { VideoUpdateComponent } from './video-update.component'
|
||||||
import { VideoService } from '../shared'
|
import { VideoEditModule } from './video-edit.module'
|
||||||
import { SharedModule } from '../../shared'
|
import { SharedModule } from '../../shared'
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
imports: [
|
imports: [
|
||||||
TagInputModule,
|
|
||||||
|
|
||||||
VideoUpdateRoutingModule,
|
VideoUpdateRoutingModule,
|
||||||
|
VideoEditModule,
|
||||||
SharedModule
|
SharedModule
|
||||||
],
|
],
|
||||||
|
|
||||||
|
@ -23,8 +20,6 @@ import { SharedModule } from '../../shared'
|
||||||
VideoUpdateComponent
|
VideoUpdateComponent
|
||||||
],
|
],
|
||||||
|
|
||||||
providers: [
|
providers: [ ]
|
||||||
VideoService
|
|
||||||
]
|
|
||||||
})
|
})
|
||||||
export class VideoUpdateModule { }
|
export class VideoUpdateModule { }
|
||||||
|
|
|
@ -13,7 +13,7 @@
|
||||||
|
|
||||||
<form novalidate [formGroup]="form">
|
<form novalidate [formGroup]="form">
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="description">Reason</label>
|
<label for="reason">Reason</label>
|
||||||
<textarea
|
<textarea
|
||||||
id="reason" class="form-control" placeholder="Reason..."
|
id="reason" class="form-control" placeholder="Reason..."
|
||||||
formControlName="reason"
|
formControlName="reason"
|
||||||
|
|
|
@ -129,6 +129,16 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="video-details-description" [innerHTML]="videoHTMLDescription"></div>
|
<div class="video-details-description" [innerHTML]="videoHTMLDescription"></div>
|
||||||
|
|
||||||
|
<div *ngIf="completeDescriptionShown === false && video.description.length === 250" (click)="showMoreDescription()" class="video-details-description-more">
|
||||||
|
Show more
|
||||||
|
<span class="glyphicon glyphicon-menu-down"></span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div *ngIf="completeDescriptionShown === true" (click)="showLessDescription()" class="video-details-description-more">
|
||||||
|
Show less
|
||||||
|
<span class="glyphicon glyphicon-menu-up"></span>
|
||||||
|
</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">
|
||||||
|
|
|
@ -170,6 +170,18 @@
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
margin-bottom: 30px;
|
margin-bottom: 30px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.video-details-description-more {
|
||||||
|
cursor: pointer;
|
||||||
|
margin-top: 15px;
|
||||||
|
font-weight: bold;
|
||||||
|
color: #acaeb7;
|
||||||
|
|
||||||
|
.glyphicon {
|
||||||
|
position: relative;
|
||||||
|
top: 2px;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.video-details-attributes {
|
.video-details-attributes {
|
||||||
|
|
|
@ -38,6 +38,10 @@ export class VideoWatchComponent implements OnInit, OnDestroy {
|
||||||
video: VideoDetails = null
|
video: VideoDetails = null
|
||||||
videoPlayerLoaded = false
|
videoPlayerLoaded = false
|
||||||
videoNotFound = false
|
videoNotFound = false
|
||||||
|
|
||||||
|
completeDescriptionShown = false
|
||||||
|
completeVideoDescription: string
|
||||||
|
shortVideoDescription: string
|
||||||
videoHTMLDescription = ''
|
videoHTMLDescription = ''
|
||||||
|
|
||||||
private paramsSub: Subscription
|
private paramsSub: Subscription
|
||||||
|
@ -154,6 +158,36 @@ export class VideoWatchComponent implements OnInit, OnDestroy {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
showMoreDescription () {
|
||||||
|
this.completeDescriptionShown = true
|
||||||
|
|
||||||
|
if (this.completeVideoDescription === undefined) {
|
||||||
|
return this.loadCompleteDescription()
|
||||||
|
}
|
||||||
|
|
||||||
|
this.updateVideoDescription(this.completeVideoDescription)
|
||||||
|
}
|
||||||
|
|
||||||
|
showLessDescription () {
|
||||||
|
this.completeDescriptionShown = false
|
||||||
|
|
||||||
|
this.updateVideoDescription(this.shortVideoDescription)
|
||||||
|
}
|
||||||
|
|
||||||
|
loadCompleteDescription () {
|
||||||
|
this.videoService.loadCompleteDescription(this.video.descriptionPath)
|
||||||
|
.subscribe(
|
||||||
|
description => {
|
||||||
|
this.shortVideoDescription = this.video.description
|
||||||
|
this.completeVideoDescription = description
|
||||||
|
|
||||||
|
this.updateVideoDescription(this.completeVideoDescription)
|
||||||
|
},
|
||||||
|
|
||||||
|
error => this.notificationsService.error('Error', error.text)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
showReportModal (event: Event) {
|
showReportModal (event: Event) {
|
||||||
event.preventDefault()
|
event.preventDefault()
|
||||||
this.videoReportModal.show()
|
this.videoReportModal.show()
|
||||||
|
@ -184,6 +218,15 @@ export class VideoWatchComponent implements OnInit, OnDestroy {
|
||||||
return this.video.isBlackistableBy(this.authService.getUser())
|
return this.video.isBlackistableBy(this.authService.getUser())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private updateVideoDescription (description: string) {
|
||||||
|
this.video.description = description
|
||||||
|
this.setVideoDescriptionHTML()
|
||||||
|
}
|
||||||
|
|
||||||
|
private setVideoDescriptionHTML () {
|
||||||
|
this.videoHTMLDescription = this.markdownService.markdownToHTML(this.video.description)
|
||||||
|
}
|
||||||
|
|
||||||
private handleError (err: any) {
|
private handleError (err: any) {
|
||||||
const errorMessage: string = typeof err === 'string' ? err : err.message
|
const errorMessage: string = typeof err === 'string' ? err : err.message
|
||||||
let message = ''
|
let message = ''
|
||||||
|
@ -264,7 +307,7 @@ export class VideoWatchComponent implements OnInit, OnDestroy {
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
this.videoHTMLDescription = this.markdownService.markdownToHTML(this.video.description)
|
this.setVideoDescriptionHTML()
|
||||||
|
|
||||||
this.setOpenGraphTags()
|
this.setOpenGraphTags()
|
||||||
this.checkUserRating()
|
this.checkUserRating()
|
||||||
|
|
|
@ -4,4 +4,5 @@ export * from './video.model'
|
||||||
export * from './video-details.model'
|
export * from './video-details.model'
|
||||||
export * from './video-edit.model'
|
export * from './video-edit.model'
|
||||||
export * from './video.service'
|
export * from './video.service'
|
||||||
|
export * from './video-description.component'
|
||||||
export * from './video-pagination.model'
|
export * from './video-pagination.model'
|
||||||
|
|
|
@ -0,0 +1,9 @@
|
||||||
|
<textarea
|
||||||
|
[(ngModel)]="description" (ngModelChange)="onModelChange()"
|
||||||
|
id="description" class="form-control" placeholder="My super video">
|
||||||
|
</textarea>
|
||||||
|
|
||||||
|
<tabset #staticTabs class="previews">
|
||||||
|
<tab heading="Truncated description preview" [innerHTML]="truncatedDescriptionHTML"></tab>
|
||||||
|
<tab heading="Complete description preview" [innerHTML]="descriptionHTML"></tab>
|
||||||
|
</tabset>
|
|
@ -0,0 +1,15 @@
|
||||||
|
textarea {
|
||||||
|
height: 150px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.previews /deep/ {
|
||||||
|
.nav {
|
||||||
|
margin-top: 10px;
|
||||||
|
font-size: 0.9em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tab-content {
|
||||||
|
min-height: 75px;
|
||||||
|
padding: 5px;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,68 @@
|
||||||
|
import { Component, forwardRef, Input, OnInit } from '@angular/core'
|
||||||
|
import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms'
|
||||||
|
import { Subject } from 'rxjs/Subject'
|
||||||
|
import 'rxjs/add/operator/debounceTime'
|
||||||
|
import 'rxjs/add/operator/distinctUntilChanged'
|
||||||
|
|
||||||
|
import { truncate } from 'lodash'
|
||||||
|
|
||||||
|
import { MarkdownService } from './markdown.service'
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'my-video-description',
|
||||||
|
templateUrl: './video-description.component.html',
|
||||||
|
styleUrls: [ './video-description.component.scss' ],
|
||||||
|
providers: [
|
||||||
|
{
|
||||||
|
provide: NG_VALUE_ACCESSOR,
|
||||||
|
useExisting: forwardRef(() => VideoDescriptionComponent),
|
||||||
|
multi: true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
})
|
||||||
|
|
||||||
|
export class VideoDescriptionComponent implements ControlValueAccessor, OnInit {
|
||||||
|
@Input() description = ''
|
||||||
|
truncatedDescriptionHTML = ''
|
||||||
|
descriptionHTML = ''
|
||||||
|
|
||||||
|
private descriptionChanged = new Subject<string>()
|
||||||
|
|
||||||
|
constructor (private markdownService: MarkdownService) {}
|
||||||
|
|
||||||
|
ngOnInit () {
|
||||||
|
this.descriptionChanged
|
||||||
|
.debounceTime(150)
|
||||||
|
.distinctUntilChanged()
|
||||||
|
.subscribe(() => this.updateDescriptionPreviews())
|
||||||
|
|
||||||
|
this.descriptionChanged.next(this.description)
|
||||||
|
}
|
||||||
|
|
||||||
|
propagateChange = (_: any) => { /* empty */ }
|
||||||
|
|
||||||
|
writeValue (description: string) {
|
||||||
|
this.description = description
|
||||||
|
|
||||||
|
this.descriptionChanged.next(this.description)
|
||||||
|
}
|
||||||
|
|
||||||
|
registerOnChange (fn: (_: any) => void) {
|
||||||
|
this.propagateChange = fn
|
||||||
|
}
|
||||||
|
|
||||||
|
registerOnTouched () {
|
||||||
|
// Unused
|
||||||
|
}
|
||||||
|
|
||||||
|
onModelChange () {
|
||||||
|
this.propagateChange(this.description)
|
||||||
|
|
||||||
|
this.descriptionChanged.next(this.description)
|
||||||
|
}
|
||||||
|
|
||||||
|
private updateDescriptionPreviews () {
|
||||||
|
this.truncatedDescriptionHTML = this.markdownService.markdownToHTML(truncate(this.description, { length: 250 }))
|
||||||
|
this.descriptionHTML = this.markdownService.markdownToHTML(this.description)
|
||||||
|
}
|
||||||
|
}
|
|
@ -38,12 +38,14 @@ export class VideoDetails extends Video implements VideoDetailsServerModel {
|
||||||
likes: number
|
likes: number
|
||||||
dislikes: number
|
dislikes: number
|
||||||
nsfw: boolean
|
nsfw: boolean
|
||||||
|
descriptionPath: string
|
||||||
files: VideoFile[]
|
files: VideoFile[]
|
||||||
channel: VideoChannel
|
channel: VideoChannel
|
||||||
|
|
||||||
constructor (hash: VideoDetailsServerModel) {
|
constructor (hash: VideoDetailsServerModel) {
|
||||||
super(hash)
|
super(hash)
|
||||||
|
|
||||||
|
this.descriptionPath = hash.descriptionPath
|
||||||
this.files = hash.files
|
this.files = hash.files
|
||||||
this.channel = hash.channel
|
this.channel = hash.channel
|
||||||
}
|
}
|
||||||
|
|
|
@ -99,15 +99,11 @@ export class VideoService {
|
||||||
.catch((res) => this.restExtractor.handleError(res))
|
.catch((res) => this.restExtractor.handleError(res))
|
||||||
}
|
}
|
||||||
|
|
||||||
reportVideo (id: number, reason: string) {
|
loadCompleteDescription (descriptionPath: string) {
|
||||||
const url = VideoService.BASE_VIDEO_URL + id + '/abuse'
|
return this.authHttp
|
||||||
const body: VideoAbuseCreate = {
|
.get(API_URL + descriptionPath)
|
||||||
reason
|
.map(res => res['description'])
|
||||||
}
|
.catch((res) => this.restExtractor.handleError(res))
|
||||||
|
|
||||||
return this.authHttp.post(url, body)
|
|
||||||
.map(this.restExtractor.extractDataBool)
|
|
||||||
.catch(res => this.restExtractor.handleError(res))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
setVideoLike (id: number) {
|
setVideoLike (id: number) {
|
||||||
|
|
|
@ -21,7 +21,7 @@
|
||||||
"no-attribute-parameter-decorator": true,
|
"no-attribute-parameter-decorator": true,
|
||||||
"no-input-rename": true,
|
"no-input-rename": true,
|
||||||
"no-output-rename": true,
|
"no-output-rename": true,
|
||||||
"no-forward-ref": true,
|
"no-forward-ref": false,
|
||||||
"use-life-cycle-interface": true,
|
"use-life-cycle-interface": true,
|
||||||
"use-pipe-transform-interface": true,
|
"use-pipe-transform-interface": true,
|
||||||
"pipe-naming": [true, "camelCase", "my"],
|
"pipe-naming": [true, "camelCase", "my"],
|
||||||
|
|
|
@ -138,7 +138,7 @@ export interface VideoInstance extends VideoClass, VideoAttributes, Sequelize.In
|
||||||
getOriginalFileHeight: VideoMethods.GetOriginalFileHeight
|
getOriginalFileHeight: VideoMethods.GetOriginalFileHeight
|
||||||
getEmbedPath: VideoMethods.GetEmbedPath
|
getEmbedPath: VideoMethods.GetEmbedPath
|
||||||
getDescriptionPath: VideoMethods.GetDescriptionPath
|
getDescriptionPath: VideoMethods.GetDescriptionPath
|
||||||
getTruncatedDescription : VideoMethods.GetTruncatedDescription
|
getTruncatedDescription: VideoMethods.GetTruncatedDescription
|
||||||
|
|
||||||
setTags: Sequelize.HasManySetAssociationsMixin<TagAttributes, string>
|
setTags: Sequelize.HasManySetAssociationsMixin<TagAttributes, string>
|
||||||
addVideoFile: Sequelize.HasManyAddAssociationMixin<VideoFileAttributes, string>
|
addVideoFile: Sequelize.HasManyAddAssociationMixin<VideoFileAttributes, string>
|
||||||
|
|
|
@ -280,9 +280,7 @@ describe('Test videos API validator', function () {
|
||||||
licence: 1,
|
licence: 1,
|
||||||
language: 6,
|
language: 6,
|
||||||
nsfw: false,
|
nsfw: false,
|
||||||
description: 'my super description which is very very very very very very very very very very very very very very' +
|
description: 'my super description which is very very very very very very very very very very very very very very long'.repeat(35),
|
||||||
'very very very very very very very very very very very very very very very very very very very very very' +
|
|
||||||
'very very very very very very very very very very very very very very very long',
|
|
||||||
tags: [ 'tag1', 'tag2' ],
|
tags: [ 'tag1', 'tag2' ],
|
||||||
channelId
|
channelId
|
||||||
}
|
}
|
||||||
|
@ -617,9 +615,7 @@ describe('Test videos API validator', function () {
|
||||||
licence: 2,
|
licence: 2,
|
||||||
language: 6,
|
language: 6,
|
||||||
nsfw: false,
|
nsfw: false,
|
||||||
description: 'my super description which is very very very very very very very very very very very very very very' +
|
description: 'my super description which is very very very very very very very very very very very very very long'.repeat(35),
|
||||||
'very very very very very very very very very very very very very very very very very very very very very' +
|
|
||||||
'very very very very very very very very very very very very very very very long',
|
|
||||||
tags: [ 'tag1', 'tag2' ]
|
tags: [ 'tag1', 'tag2' ]
|
||||||
}
|
}
|
||||||
await makePutBodyRequest({ url: server.url, path: path + videoId, token: server.accessToken, fields })
|
await makePutBodyRequest({ url: server.url, path: path + videoId, token: server.accessToken, fields })
|
||||||
|
|
Loading…
Reference in New Issue