Correctly truncate HTML
We can because we don't use the video truncated description since v5.0
This commit is contained in:
parent
e4f82eaa8b
commit
c5f8dc0533
|
@ -55,7 +55,7 @@
|
|||
|
||||
<my-markdown-textarea
|
||||
formControlName="description" [markdownVideo]="videoToUpdate"
|
||||
[formError]="formErrors.description" [truncate]="250"
|
||||
[formError]="formErrors.description" [truncateTo3Lines]="true"
|
||||
></my-markdown-textarea>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -1,25 +1,26 @@
|
|||
<div class="video-info-description">
|
||||
<div
|
||||
#descriptionHTML
|
||||
class="video-info-description-html"
|
||||
[innerHTML]="getHTMLDescription()"
|
||||
[ngClass]="{ 'ellipsis-multiline-3': !completeDescriptionShown }"
|
||||
[innerHTML]="videoHTMLDescription"
|
||||
(timestampClicked)="onTimestampClicked($event)"
|
||||
myTimestampRouteTransformer
|
||||
></div>
|
||||
|
||||
<button
|
||||
*ngIf="completeDescriptionShown === false && video.description?.length >= 250"
|
||||
(click)="showMoreDescription()" class="video-info-description-more button-unstyle"
|
||||
*ngIf="(hasEllipsis() && !completeDescriptionShown) || completeDescriptionShown"
|
||||
(click)="completeDescriptionShown = !completeDescriptionShown"
|
||||
class="video-info-description-more button-unstyle"
|
||||
>
|
||||
<ng-container *ngIf="!completeDescriptionShown">
|
||||
<ng-container i18n>Show more</ng-container>
|
||||
<span *ngIf="descriptionLoading === false" class="chevron-down"></span>
|
||||
<my-loader size="sm" class="description-loading" [loading]="descriptionLoading"></my-loader>
|
||||
</button>
|
||||
<span class="chevron-down"></span>
|
||||
</ng-container>
|
||||
|
||||
<button
|
||||
*ngIf="completeDescriptionShown === true"
|
||||
(click)="showLessDescription()" class="video-info-description-more button-unstyle"
|
||||
>
|
||||
<ng-container *ngIf="completeDescriptionShown">
|
||||
<ng-container i18n>Show less</ng-container>
|
||||
<span *ngIf="descriptionLoading === false" class="chevron-up"></span>
|
||||
<span class="chevron-up"></span>
|
||||
</ng-container>
|
||||
</button>
|
||||
</div>
|
||||
|
|
|
@ -11,9 +11,15 @@
|
|||
.video-info-description-html {
|
||||
@include peertube-word-wrap;
|
||||
|
||||
::ng-deep a {
|
||||
::ng-deep {
|
||||
a {
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
p:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.description-loading {
|
||||
|
@ -21,10 +27,12 @@
|
|||
}
|
||||
|
||||
.video-info-description-more {
|
||||
@include font-size(14px);
|
||||
|
||||
cursor: pointer;
|
||||
font-weight: $font-semibold;
|
||||
color: pvar(--greyForegroundColor);
|
||||
font-size: 14px;
|
||||
margin-top: 1rem;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
import { Component, EventEmitter, Input, OnChanges, Output } from '@angular/core'
|
||||
import { MarkdownService, Notifier } from '@app/core'
|
||||
import { VideoDetails, VideoService } from '@app/shared/shared-main'
|
||||
import { logger } from '@root-helpers/logger'
|
||||
import { Component, EventEmitter, Input, OnChanges, Output, ViewChild, ElementRef } from '@angular/core'
|
||||
import { MarkdownService } from '@app/core'
|
||||
import { VideoDetails } from '@app/shared/shared-main'
|
||||
|
||||
@Component({
|
||||
selector: 'my-video-description',
|
||||
|
@ -9,36 +8,34 @@ import { logger } from '@root-helpers/logger'
|
|||
styleUrls: [ './video-description.component.scss' ]
|
||||
})
|
||||
export class VideoDescriptionComponent implements OnChanges {
|
||||
@ViewChild('descriptionHTML') descriptionHTML: ElementRef<HTMLElement>
|
||||
|
||||
@Input() video: VideoDetails
|
||||
|
||||
@Output() timestampClicked = new EventEmitter<number>()
|
||||
|
||||
descriptionLoading = false
|
||||
completeDescriptionShown = false
|
||||
|
||||
completeVideoDescriptionLoaded = false
|
||||
|
||||
videoHTMLTruncatedDescription = ''
|
||||
videoHTMLDescription = ''
|
||||
|
||||
constructor (
|
||||
private videoService: VideoService,
|
||||
private notifier: Notifier,
|
||||
private markdownService: MarkdownService
|
||||
) { }
|
||||
|
||||
ngOnChanges () {
|
||||
this.descriptionLoading = false
|
||||
this.completeDescriptionShown = false
|
||||
|
||||
this.setVideoDescriptionHTML()
|
||||
}
|
||||
|
||||
showMoreDescription () {
|
||||
if (!this.completeVideoDescriptionLoaded) {
|
||||
return this.loadCompleteDescription()
|
||||
hasEllipsis () {
|
||||
const el = this.descriptionHTML?.nativeElement
|
||||
if (!el) return false
|
||||
|
||||
return el.offsetHeight < el.scrollHeight
|
||||
}
|
||||
|
||||
showMoreDescription () {
|
||||
this.completeDescriptionShown = true
|
||||
}
|
||||
|
||||
|
@ -46,51 +43,13 @@ export class VideoDescriptionComponent implements OnChanges {
|
|||
this.completeDescriptionShown = false
|
||||
}
|
||||
|
||||
loadCompleteDescription () {
|
||||
this.descriptionLoading = true
|
||||
|
||||
this.videoService.loadCompleteDescription(this.video.descriptionPath)
|
||||
.subscribe({
|
||||
next: description => {
|
||||
this.completeDescriptionShown = true
|
||||
this.descriptionLoading = false
|
||||
|
||||
this.video.description = description
|
||||
|
||||
this.setVideoDescriptionHTML()
|
||||
.catch(err => logger.error(err))
|
||||
},
|
||||
|
||||
error: err => {
|
||||
this.descriptionLoading = false
|
||||
this.notifier.error(err.message)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
onTimestampClicked (timestamp: number) {
|
||||
this.timestampClicked.emit(timestamp)
|
||||
}
|
||||
|
||||
getHTMLDescription () {
|
||||
if (this.completeDescriptionShown) {
|
||||
return this.videoHTMLDescription
|
||||
}
|
||||
|
||||
return this.videoHTMLTruncatedDescription
|
||||
}
|
||||
|
||||
private async setVideoDescriptionHTML () {
|
||||
{
|
||||
const html = await this.markdownService.textMarkdownToHTML({ markdown: this.video.description })
|
||||
|
||||
this.videoHTMLDescription = this.markdownService.processVideoTimestamps(this.video.shortUUID, html)
|
||||
}
|
||||
|
||||
{
|
||||
const html = await this.markdownService.textMarkdownToHTML({ markdown: this.video.truncatedDescription })
|
||||
|
||||
this.videoHTMLTruncatedDescription = this.markdownService.processVideoTimestamps(this.video.shortUUID, html)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -138,8 +138,7 @@ export class MarkdownService {
|
|||
}
|
||||
}
|
||||
|
||||
let html = this.markdownParsers[name].render(markdown)
|
||||
html = this.avoidTruncatedTags(html)
|
||||
const html = this.markdownParsers[name].render(markdown)
|
||||
|
||||
if (config.escape) return this.htmlRenderer.toSafeHtml(html, additionalAllowedTags)
|
||||
|
||||
|
@ -181,11 +180,4 @@ export class MarkdownService {
|
|||
return defaultRender(tokens, index, options, env, self)
|
||||
}
|
||||
}
|
||||
|
||||
private avoidTruncatedTags (html: string) {
|
||||
return html.replace(/\*\*?([^*]+)$/, '$1')
|
||||
.replace(/<a[^>]+>([^<]+)<\/a>\s*...((<\/p>)|(<\/li>)|(<\/strong>))?$/mi, '$1...')
|
||||
.replace(/\[[^\]]+\]\(([^)]+)$/m, '$1')
|
||||
.replace(/\s?\[[^\]]+\]?[.]{3}<\/p>$/m, '...</p>')
|
||||
}
|
||||
}
|
||||
|
|
|
@ -96,7 +96,7 @@
|
|||
<strong i18n>Comment:</strong>
|
||||
</div>
|
||||
|
||||
<div [innerHTML]="abuse.commentHtml"></div>
|
||||
<div [innerHTML]="abuse.commentHTML"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -90,7 +90,8 @@
|
|||
|
||||
<ng-container *ngIf="abuse.comment">
|
||||
<td>
|
||||
<a [href]="getCommentUrl(abuse)" [innerHTML]="abuse.truncatedCommentHtml" class="table-comment-link"
|
||||
<a
|
||||
[href]="getCommentUrl(abuse)" [innerHTML]="abuse.commentHTML" class="table-comment-link ellipsis-multiline-1"
|
||||
[title]="abuse.comment.video.name" target="_blank" rel="noopener noreferrer"
|
||||
></a>
|
||||
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
import * as debug from 'debug'
|
||||
import truncate from 'lodash-es/truncate'
|
||||
import { SortMeta } from 'primeng/api'
|
||||
import { Component, Input, OnInit, ViewChild } from '@angular/core'
|
||||
import { ActivatedRoute, Router } from '@angular/router'
|
||||
|
@ -211,11 +210,9 @@ export class AbuseListTableComponent extends RestTable implements OnInit {
|
|||
|
||||
if (abuse.comment) {
|
||||
if (abuse.comment.deleted) {
|
||||
abuse.truncatedCommentHtml = abuse.commentHtml = $localize`Deleted comment`
|
||||
abuse.commentHTML = $localize`Deleted comment`
|
||||
} else {
|
||||
const truncated = truncate(abuse.comment.text, { length: 100 })
|
||||
abuse.truncatedCommentHtml = await this.markdownRenderer.textMarkdownToHTML({ markdown: truncated, withHtml: true })
|
||||
abuse.commentHtml = await this.markdownRenderer.textMarkdownToHTML({ markdown: abuse.comment.text, withHtml: true })
|
||||
abuse.commentHTML = await this.markdownRenderer.textMarkdownToHTML({ markdown: abuse.comment.text, withHtml: true })
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -12,8 +12,7 @@ export type ProcessedAbuse = AdminAbuse & {
|
|||
reporterAccount?: Account
|
||||
flaggedAccount?: Account
|
||||
|
||||
truncatedCommentHtml?: string
|
||||
commentHtml?: string
|
||||
commentHTML?: string
|
||||
|
||||
video: AdminAbuse['video'] & {
|
||||
channel: AdminAbuse['video']['channel'] & {
|
||||
|
|
|
@ -8,11 +8,11 @@
|
|||
</textarea>
|
||||
|
||||
<div ngbNav #nav="ngbNav" class="nav-pills nav-preview">
|
||||
<ng-container ngbNavItem *ngIf="truncate !== undefined">
|
||||
<ng-container ngbNavItem *ngIf="truncateTo3Lines">
|
||||
<a ngbNavLink i18n>Truncated preview</a>
|
||||
|
||||
<ng-template ngbNavContent>
|
||||
<div [innerHTML]="truncatedPreviewHTML"></div>
|
||||
<div class="ellipsis-multiline-3" [innerHTML]="previewHTML"></div>
|
||||
</ng-template>
|
||||
</ng-container>
|
||||
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
import truncate from 'lodash-es/truncate'
|
||||
import { Subject } from 'rxjs'
|
||||
import { debounceTime, distinctUntilChanged } from 'rxjs/operators'
|
||||
import { ViewportScroller } from '@angular/common'
|
||||
|
@ -26,7 +25,7 @@ export class MarkdownTextareaComponent implements ControlValueAccessor, OnInit {
|
|||
|
||||
@Input() formError: string
|
||||
|
||||
@Input() truncate: number
|
||||
@Input() truncateTo3Lines: boolean
|
||||
|
||||
@Input() markdownType: 'text' | 'enhanced' | 'to-unsafe-html' = 'text'
|
||||
@Input() customMarkdownRenderer?: (text: string) => Promise<string | HTMLElement>
|
||||
|
@ -42,7 +41,6 @@ export class MarkdownTextareaComponent implements ControlValueAccessor, OnInit {
|
|||
@ViewChild('textarea') textareaElement: ElementRef
|
||||
@ViewChild('previewElement') previewElement: ElementRef
|
||||
|
||||
truncatedPreviewHTML: SafeHtml | string = ''
|
||||
previewHTML: SafeHtml | string = ''
|
||||
|
||||
isMaximized = false
|
||||
|
@ -129,7 +127,6 @@ export class MarkdownTextareaComponent implements ControlValueAccessor, OnInit {
|
|||
private async updatePreviews () {
|
||||
if (this.content === null || this.content === undefined) return
|
||||
|
||||
this.truncatedPreviewHTML = await this.markdownRender(truncate(this.content, { length: this.truncate }))
|
||||
this.previewHTML = await this.markdownRender(this.content)
|
||||
}
|
||||
|
||||
|
|
|
@ -36,6 +36,10 @@
|
|||
overflow: hidden;
|
||||
}
|
||||
|
||||
.ellipsis-multiline-1 {
|
||||
@include ellipsis-multiline(1);
|
||||
}
|
||||
|
||||
.ellipsis-multiline-2 {
|
||||
@include ellipsis-multiline(2);
|
||||
}
|
||||
|
@ -45,3 +49,7 @@
|
|||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
.ellipsis {
|
||||
@include ellipsis;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue