diff --git a/client/src/app/+admin/moderation/video-auto-blacklist-list/video-auto-blacklist-list.component.html b/client/src/app/+admin/moderation/video-auto-blacklist-list/video-auto-blacklist-list.component.html
index 5ef497fa7..62dde60bb 100644
--- a/client/src/app/+admin/moderation/video-auto-blacklist-list/video-auto-blacklist-list.component.html
+++ b/client/src/app/+admin/moderation/video-auto-blacklist-list/video-auto-blacklist-list.component.html
@@ -1,33 +1,19 @@
-
No results.
+
+
+
+
+ Unblacklist
+
+
-
-
-
-
-
+
+
+
-
-
-
-
-
-
- Cancel
-
-
-
-
- Unblacklist
-
-
-
-
-
-
-
+
diff --git a/client/src/app/+admin/moderation/video-auto-blacklist-list/video-auto-blacklist-list.component.scss b/client/src/app/+admin/moderation/video-auto-blacklist-list/video-auto-blacklist-list.component.scss
index e43a2aa7b..85ebc6041 100644
--- a/client/src/app/+admin/moderation/video-auto-blacklist-list/video-auto-blacklist-list.component.scss
+++ b/client/src/app/+admin/moderation/video-auto-blacklist-list/video-auto-blacklist-list.component.scss
@@ -1,67 +1,14 @@
@import '_variables';
@import '_mixins';
-.action-selection-mode {
- width: 194px;
- display: flex;
- justify-content: flex-end;
+.action-button-unblacklist-selection {
+ display: inline-block;
- .action-selection-mode-child {
- position: fixed;
+ @include peertube-button;
+ @include orange-button;
+ @include button-with-icon(21px);
- .action-button {
- display: inline-block;
- }
-
- .action-button-cancel-selection {
- @include peertube-button;
- @include grey-button;
-
- margin-right: 10px;
- }
-
- .action-button-unblacklist-selection {
- @include peertube-button;
- @include orange-button;
- @include button-with-icon(21px);
-
- my-global-icon {
- @include apply-svg-color(#fff);
- }
- }
- }
-}
-
-.video {
- @include row-blocks;
-
- &:first-child {
- margin-top: 47px;
- }
-
- .checkbox-container {
- display: flex;
- align-items: center;
- margin-right: 20px;
- margin-left: 12px;
- }
-
- my-video-miniature {
- flex-grow: 1;
- }
-}
-
-@media screen and (max-width: $small-view) {
- .video {
- flex-direction: column;
- height: auto;
-
- .checkbox-container {
- display: none;
- }
-
- my-button {
- margin-top: 10px;
- }
+ my-global-icon {
+ @include apply-svg-color(#fff);
}
}
diff --git a/client/src/app/+admin/moderation/video-auto-blacklist-list/video-auto-blacklist-list.component.ts b/client/src/app/+admin/moderation/video-auto-blacklist-list/video-auto-blacklist-list.component.ts
index d66a6dcae..fb2962b47 100644
--- a/client/src/app/+admin/moderation/video-auto-blacklist-list/video-auto-blacklist-list.component.ts
+++ b/client/src/app/+admin/moderation/video-auto-blacklist-list/video-auto-blacklist-list.component.ts
@@ -1,29 +1,23 @@
-import { Component, OnDestroy, OnInit } from '@angular/core'
+import { Component } from '@angular/core'
import { I18n } from '@ngx-translate/i18n-polyfill'
import { ActivatedRoute, Router } from '@angular/router'
-import { AbstractVideoList } from '@app/shared/video/abstract-video-list'
import { ComponentPagination } from '@app/shared/rest/component-pagination.model'
import { AuthService, Notifier, ServerService } from '@app/core'
-import { Video } from '@shared/models'
import { VideoBlacklistService } from '@app/shared'
import { immutableAssign } from '@app/shared/misc/utils'
import { ScreenService } from '@app/shared/misc/screen.service'
import { MiniatureDisplayOptions } from '@app/shared/video/video-miniature.component'
+import { SelectionType } from '@app/shared/video/videos-selection.component'
+import { Video } from '@app/shared/video/video.model'
@Component({
selector: 'my-video-auto-blacklist-list',
templateUrl: './video-auto-blacklist-list.component.html',
styleUrls: [ './video-auto-blacklist-list.component.scss' ]
})
-export class VideoAutoBlacklistListComponent extends AbstractVideoList implements OnInit, OnDestroy {
+export class VideoAutoBlacklistListComponent {
titlePage: string
- checkedVideos: { [ id: number ]: boolean } = {}
- pagination: ComponentPagination = {
- currentPage: 1,
- itemsPerPage: 5,
- totalItems: null
- }
-
+ selection: SelectionType = {}
miniatureDisplayOptions: MiniatureDisplayOptions = {
date: true,
views: false,
@@ -34,6 +28,13 @@ export class VideoAutoBlacklistListComponent extends AbstractVideoList implement
blacklistInfo: false,
nsfw: true
}
+ pagination: ComponentPagination = {
+ currentPage: 1,
+ itemsPerPage: 5,
+ totalItems: null
+ }
+ videos: Video[] = []
+ getVideosObservableFunction = this.getVideosObservable.bind(this)
constructor (
protected router: Router,
@@ -45,42 +46,21 @@ export class VideoAutoBlacklistListComponent extends AbstractVideoList implement
private i18n: I18n,
private videoBlacklistService: VideoBlacklistService
) {
- super()
-
this.titlePage = this.i18n('Auto-blacklisted videos')
}
- ngOnInit () {
- super.ngOnInit()
- }
-
- ngOnDestroy () {
- super.ngOnDestroy()
- }
-
- abortSelectionMode () {
- this.checkedVideos = {}
- }
-
- isInSelectionMode () {
- return Object.keys(this.checkedVideos).some(k => this.checkedVideos[k] === true)
- }
-
getVideosObservable (page: number) {
const newPagination = immutableAssign(this.pagination, { currentPage: page })
return this.videoBlacklistService.getAutoBlacklistedAsVideoList(newPagination)
}
- generateSyndicationList () {
- throw new Error('Method not implemented.')
- }
-
removeVideoFromBlacklist (entry: Video) {
this.videoBlacklistService.removeVideoFromBlacklist(entry.id).subscribe(
() => {
this.notifier.success(this.i18n('Video {{name}} removed from blacklist.', { name: entry.name }))
- this.reloadVideos()
+
+ this.videos = this.videos.filter(v => v.id !== entry.id)
},
error => this.notifier.error(error.message)
@@ -88,16 +68,16 @@ export class VideoAutoBlacklistListComponent extends AbstractVideoList implement
}
removeSelectedVideosFromBlacklist () {
- const toReleaseVideosIds = Object.keys(this.checkedVideos)
- .filter(k => this.checkedVideos[ k ] === true)
+ const toReleaseVideosIds = Object.keys(this.selection)
+ .filter(k => this.selection[ k ] === true)
.map(k => parseInt(k, 10))
this.videoBlacklistService.removeVideoFromBlacklist(toReleaseVideosIds).subscribe(
() => {
this.notifier.success(this.i18n('{{num}} videos removed from blacklist.', { num: toReleaseVideosIds.length }))
- this.abortSelectionMode()
- this.reloadVideos()
+ this.selection = {}
+ this.videos = this.videos.filter(v => toReleaseVideosIds.includes(v.id) === false)
},
error => this.notifier.error(error.message)
diff --git a/client/src/app/+my-account/my-account-videos/my-account-videos.component.html b/client/src/app/+my-account/my-account-videos/my-account-videos.component.html
index 3a4054de8..d7993fdc2 100644
--- a/client/src/app/+my-account/my-account-videos/my-account-videos.component.html
+++ b/client/src/app/+my-account/my-account-videos/my-account-videos.component.html
@@ -1,39 +1,30 @@
-No results.
+
+
+
+
+ Delete
+
+
-
-
-
-
-
+
+
-
+
-
-
-
-
- Cancel
-
+
+
+
-
-
- Delete
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/client/src/app/+my-account/my-account-videos/my-account-videos.component.scss b/client/src/app/+my-account/my-account-videos/my-account-videos.component.scss
index 405ded3f8..87398e7c8 100644
--- a/client/src/app/+my-account/my-account-videos/my-account-videos.component.scss
+++ b/client/src/app/+my-account/my-account-videos/my-account-videos.component.scss
@@ -1,75 +1,19 @@
@import '_variables';
@import '_mixins';
-.action-selection-mode {
- width: 174px;
- display: flex;
- justify-content: flex-end;
+.action-button-delete-selection {
+ display: inline-block;
- .action-selection-mode-child {
- position: fixed;
+ @include peertube-button;
+ @include orange-button;
+ @include button-with-icon(21px);
- .action-button {
- display: inline-block;
- }
-
- .action-button-cancel-selection {
- @include peertube-button;
- @include grey-button;
-
- margin-right: 10px;
- }
-
- .action-button-delete-selection {
- @include peertube-button;
- @include orange-button;
- @include button-with-icon(21px);
-
- my-global-icon {
- @include apply-svg-color(#fff);
- }
- }
+ my-global-icon {
+ @include apply-svg-color(#fff);
}
}
-.video {
- @include row-blocks;
-
- &:first-child {
- margin-top: 47px;
- }
-
- .checkbox-container {
- display: flex;
- align-items: center;
- margin-right: 20px;
- margin-left: 12px;
- }
-
- my-video-miniature {
- flex-grow: 1;
- }
-
- .video-buttons {
- min-width: 190px;
-
- *:not(:last-child) {
- margin-right: 10px;
- }
- }
-}
-
-@media screen and (max-width: $small-view) {
- .video {
- flex-direction: column;
- height: auto;
-
- .checkbox-container {
- display: none;
- }
-
- .video-buttons {
- margin-top: 10px;
- }
- }
+my-delete-button,
+my-edit-button {
+ margin-right: 10px;
}
diff --git a/client/src/app/+my-account/my-account-videos/my-account-videos.component.ts b/client/src/app/+my-account/my-account-videos/my-account-videos.component.ts
index bbe86af73..5f29364a8 100644
--- a/client/src/app/+my-account/my-account-videos/my-account-videos.component.ts
+++ b/client/src/app/+my-account/my-account-videos/my-account-videos.component.ts
@@ -1,31 +1,33 @@
import { concat, Observable } from 'rxjs'
import { tap, toArray } from 'rxjs/operators'
-import { Component, Inject, LOCALE_ID, OnDestroy, OnInit, ViewChild } from '@angular/core'
+import { Component, ViewChild } from '@angular/core'
import { ActivatedRoute, Router } from '@angular/router'
import { immutableAssign } from '@app/shared/misc/utils'
import { ComponentPagination } from '@app/shared/rest/component-pagination.model'
import { Notifier, ServerService } from '@app/core'
import { AuthService } from '../../core/auth'
import { ConfirmService } from '../../core/confirm'
-import { AbstractVideoList } from '../../shared/video/abstract-video-list'
import { Video } from '../../shared/video/video.model'
import { VideoService } from '../../shared/video/video.service'
import { I18n } from '@ngx-translate/i18n-polyfill'
-import { VideoPrivacy, VideoState } from '../../../../../shared/models/videos'
import { ScreenService } from '@app/shared/misc/screen.service'
import { VideoChangeOwnershipComponent } from './video-change-ownership/video-change-ownership.component'
import { MiniatureDisplayOptions } from '@app/shared/video/video-miniature.component'
+import { SelectionType, VideosSelectionComponent } from '@app/shared/video/videos-selection.component'
+import { VideoSortField } from '@app/shared/video/sort-field.type'
+import { DisableForReuseHook } from '@app/core/routing/disable-for-reuse-hook'
@Component({
selector: 'my-account-videos',
templateUrl: './my-account-videos.component.html',
styleUrls: [ './my-account-videos.component.scss' ]
})
-export class MyAccountVideosComponent extends AbstractVideoList implements OnInit, OnDestroy {
+export class MyAccountVideosComponent implements DisableForReuseHook {
+ @ViewChild('videosSelection') videosSelection: VideosSelectionComponent
@ViewChild('videoChangeOwnershipModal') videoChangeOwnershipModal: VideoChangeOwnershipComponent
titlePage: string
- checkedVideos: { [ id: number ]: boolean } = {}
+ selection: SelectionType = {}
pagination: ComponentPagination = {
currentPage: 1,
itemsPerPage: 5,
@@ -40,6 +42,8 @@ export class MyAccountVideosComponent extends AbstractVideoList implements OnIni
state: true,
blacklistInfo: true
}
+ videos: Video[] = []
+ getVideosObservableFunction = this.getVideosObservable.bind(this)
constructor (
protected router: Router,
@@ -50,43 +54,28 @@ export class MyAccountVideosComponent extends AbstractVideoList implements OnIni
protected screenService: ScreenService,
private i18n: I18n,
private confirmService: ConfirmService,
- private videoService: VideoService,
- @Inject(LOCALE_ID) private localeId: string
+ private videoService: VideoService
) {
- super()
-
this.titlePage = this.i18n('My videos')
}
- ngOnInit () {
- super.ngOnInit()
+ disableForReuse () {
+ this.videosSelection.disableForReuse()
}
- ngOnDestroy () {
- super.ngOnDestroy()
+ enabledForReuse () {
+ this.videosSelection.enabledForReuse()
}
- abortSelectionMode () {
- this.checkedVideos = {}
- }
-
- isInSelectionMode () {
- return Object.keys(this.checkedVideos).some(k => this.checkedVideos[ k ] === true)
- }
-
- getVideosObservable (page: number) {
+ getVideosObservable (page: number, sort: VideoSortField) {
const newPagination = immutableAssign(this.pagination, { currentPage: page })
- return this.videoService.getMyVideos(newPagination, this.sort)
- }
-
- generateSyndicationList () {
- throw new Error('Method not implemented.')
+ return this.videoService.getMyVideos(newPagination, sort)
}
async deleteSelectedVideos () {
- const toDeleteVideosIds = Object.keys(this.checkedVideos)
- .filter(k => this.checkedVideos[ k ] === true)
+ const toDeleteVideosIds = Object.keys(this.selection)
+ .filter(k => this.selection[ k ] === true)
.map(k => parseInt(k, 10))
const res = await this.confirmService.confirm(
@@ -109,7 +98,7 @@ export class MyAccountVideosComponent extends AbstractVideoList implements OnIni
() => {
this.notifier.success(this.i18n('{{deleteLength}} videos deleted.', { deleteLength: toDeleteVideosIds.length }))
- this.abortSelectionMode()
+ this.selection = {}
},
err => this.notifier.error(err.message)
@@ -127,7 +116,7 @@ export class MyAccountVideosComponent extends AbstractVideoList implements OnIni
.subscribe(
() => {
this.notifier.success(this.i18n('Video {{videoName}} deleted.', { videoName: video.name }))
- this.reloadVideos()
+ this.removeVideoFromArray(video.id)
},
error => this.notifier.error(error.message)
@@ -139,27 +128,6 @@ export class MyAccountVideosComponent extends AbstractVideoList implements OnIni
this.videoChangeOwnershipModal.show(video)
}
- getStateLabel (video: Video) {
- let suffix: string
-
- if (video.privacy.id !== VideoPrivacy.PRIVATE && video.state.id === VideoState.PUBLISHED) {
- suffix = this.i18n('Published')
- } else if (video.scheduledUpdate) {
- const updateAt = new Date(video.scheduledUpdate.updateAt.toString()).toLocaleString(this.localeId)
- suffix = this.i18n('Publication scheduled on ') + updateAt
- } else if (video.state.id === VideoState.TO_TRANSCODE && video.waitTranscoding === true) {
- suffix = this.i18n('Waiting transcoding')
- } else if (video.state.id === VideoState.TO_TRANSCODE) {
- suffix = this.i18n('To transcode')
- } else if (video.state.id === VideoState.TO_IMPORT) {
- suffix = this.i18n('To import')
- } else {
- return ''
- }
-
- return ' - ' + suffix
- }
-
private removeVideoFromArray (id: number) {
this.videos = this.videos.filter(v => v.id !== id)
}
diff --git a/client/src/app/shared/misc/from-now.pipe.ts b/client/src/app/shared/angular/from-now.pipe.ts
similarity index 100%
rename from client/src/app/shared/misc/from-now.pipe.ts
rename to client/src/app/shared/angular/from-now.pipe.ts
diff --git a/client/src/app/shared/misc/number-formatter.pipe.ts b/client/src/app/shared/angular/number-formatter.pipe.ts
similarity index 100%
rename from client/src/app/shared/misc/number-formatter.pipe.ts
rename to client/src/app/shared/angular/number-formatter.pipe.ts
diff --git a/client/src/app/shared/misc/object-length.pipe.ts b/client/src/app/shared/angular/object-length.pipe.ts
similarity index 100%
rename from client/src/app/shared/misc/object-length.pipe.ts
rename to client/src/app/shared/angular/object-length.pipe.ts
diff --git a/client/src/app/shared/angular/peertube-template.directive.ts b/client/src/app/shared/angular/peertube-template.directive.ts
new file mode 100644
index 000000000..a514b6057
--- /dev/null
+++ b/client/src/app/shared/angular/peertube-template.directive.ts
@@ -0,0 +1,12 @@
+import { Directive, Input, TemplateRef } from '@angular/core'
+
+@Directive({
+ selector: '[ptTemplate]'
+})
+export class PeerTubeTemplateDirective {
+ @Input('ptTemplate') name: string
+
+ constructor (public template: TemplateRef) {
+ // empty
+ }
+}
diff --git a/client/src/app/shared/shared.module.ts b/client/src/app/shared/shared.module.ts
index 3647fc786..68225b457 100644
--- a/client/src/app/shared/shared.module.ts
+++ b/client/src/app/shared/shared.module.ts
@@ -14,10 +14,7 @@ import { AUTH_INTERCEPTOR_PROVIDER } from './auth'
import { ButtonComponent } from './buttons/button.component'
import { DeleteButtonComponent } from './buttons/delete-button.component'
import { EditButtonComponent } from './buttons/edit-button.component'
-import { FromNowPipe } from './misc/from-now.pipe'
import { LoaderComponent } from './misc/loader.component'
-import { NumberFormatterPipe } from './misc/number-formatter.pipe'
-import { ObjectLengthPipe } from './misc/object-length.pipe'
import { RestExtractor, RestService } from './rest'
import { UserService } from './users'
import { VideoAbuseService } from './video-abuse'
@@ -78,6 +75,11 @@ import { VideoPlaylistMiniatureComponent } from '@app/shared/video-playlist/vide
import { VideoAddToPlaylistComponent } from '@app/shared/video-playlist/video-add-to-playlist.component'
import { TimestampInputComponent } from '@app/shared/forms/timestamp-input.component'
import { VideoPlaylistElementMiniatureComponent } from '@app/shared/video-playlist/video-playlist-element-miniature.component'
+import { VideosSelectionComponent } from '@app/shared/video/videos-selection.component'
+import { NumberFormatterPipe } from '@app/shared/angular/number-formatter.pipe'
+import { ObjectLengthPipe } from '@app/shared/angular/object-length.pipe'
+import { FromNowPipe } from '@app/shared/angular/from-now.pipe'
+import { PeerTubeTemplateDirective } from '@app/shared/angular/peertube-template.directive'
@NgModule({
imports: [
@@ -107,6 +109,7 @@ import { VideoPlaylistElementMiniatureComponent } from '@app/shared/video-playli
VideoPlaylistMiniatureComponent,
VideoAddToPlaylistComponent,
VideoPlaylistElementMiniatureComponent,
+ VideosSelectionComponent,
FeedComponent,
@@ -114,10 +117,12 @@ import { VideoPlaylistElementMiniatureComponent } from '@app/shared/video-playli
DeleteButtonComponent,
EditButtonComponent,
- ActionDropdownComponent,
NumberFormatterPipe,
ObjectLengthPipe,
FromNowPipe,
+ PeerTubeTemplateDirective,
+
+ ActionDropdownComponent,
MarkdownTextareaComponent,
InfiniteScrollerDirective,
TextareaAutoResizeDirective,
@@ -166,6 +171,7 @@ import { VideoPlaylistElementMiniatureComponent } from '@app/shared/video-playli
VideoPlaylistMiniatureComponent,
VideoAddToPlaylistComponent,
VideoPlaylistElementMiniatureComponent,
+ VideosSelectionComponent,
FeedComponent,
@@ -197,7 +203,8 @@ import { VideoPlaylistElementMiniatureComponent } from '@app/shared/video-playli
NumberFormatterPipe,
ObjectLengthPipe,
- FromNowPipe
+ FromNowPipe,
+ PeerTubeTemplateDirective
],
providers: [
diff --git a/client/src/app/shared/video/abstract-video-list.ts b/client/src/app/shared/video/abstract-video-list.ts
index 467f629ea..099650129 100644
--- a/client/src/app/shared/video/abstract-video-list.ts
+++ b/client/src/app/shared/video/abstract-video-list.ts
@@ -102,6 +102,8 @@ export abstract class AbstractVideoList implements OnInit, OnDestroy, DisableFor
({ videos, totalVideos }) => {
this.pagination.totalItems = totalVideos
this.videos = this.videos.concat(videos)
+
+ this.onMoreVideos()
},
error => this.notifier.error(error.message)
@@ -118,6 +120,9 @@ export abstract class AbstractVideoList implements OnInit, OnDestroy, DisableFor
throw new Error('toggleModerationDisplay is not implemented')
}
+ // On videos hook for children that want to do something
+ protected onMoreVideos () { /* empty */ }
+
protected loadRouteParams (routeParams: { [ key: string ]: any }) {
this.sort = routeParams[ 'sort' ] as VideoSortField || this.defaultSort
this.categoryOneOf = routeParams[ 'categoryOneOf' ]
diff --git a/client/src/app/shared/video/videos-selection.component.html b/client/src/app/shared/video/videos-selection.component.html
new file mode 100644
index 000000000..6f3401b4b
--- /dev/null
+++ b/client/src/app/shared/video/videos-selection.component.html
@@ -0,0 +1,26 @@
+No results.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/client/src/app/shared/video/videos-selection.component.scss b/client/src/app/shared/video/videos-selection.component.scss
new file mode 100644
index 000000000..d3cbabf23
--- /dev/null
+++ b/client/src/app/shared/video/videos-selection.component.scss
@@ -0,0 +1,57 @@
+@import '_variables';
+@import '_mixins';
+
+.action-selection-mode {
+ display: flex;
+ justify-content: flex-end;
+ flex-grow: 1;
+
+ .action-selection-mode-child {
+ position: fixed;
+
+ .action-button {
+ display: inline-block;
+ }
+
+ .action-button-cancel-selection {
+ @include peertube-button;
+ @include grey-button;
+
+ margin-right: 10px;
+ }
+ }
+}
+
+.video {
+ @include row-blocks;
+
+ &:first-child {
+ margin-top: 47px;
+ }
+
+ .checkbox-container {
+ display: flex;
+ align-items: center;
+ margin-right: 20px;
+ margin-left: 12px;
+ }
+
+ my-video-miniature {
+ flex-grow: 1;
+ }
+}
+
+@media screen and (max-width: $small-view) {
+ .video {
+ flex-direction: column;
+ height: auto;
+
+ .checkbox-container {
+ display: none;
+ }
+
+ my-button {
+ margin-top: 10px;
+ }
+ }
+}
diff --git a/client/src/app/shared/video/videos-selection.component.ts b/client/src/app/shared/video/videos-selection.component.ts
new file mode 100644
index 000000000..b6bedafd8
--- /dev/null
+++ b/client/src/app/shared/video/videos-selection.component.ts
@@ -0,0 +1,112 @@
+import {
+ AfterContentInit,
+ Component,
+ ContentChildren,
+ EventEmitter,
+ Input,
+ OnDestroy,
+ OnInit,
+ Output,
+ QueryList,
+ TemplateRef
+} from '@angular/core'
+import { ActivatedRoute, Router } from '@angular/router'
+import { AbstractVideoList } from '@app/shared/video/abstract-video-list'
+import { AuthService, Notifier, ServerService } from '@app/core'
+import { ScreenService } from '@app/shared/misc/screen.service'
+import { MiniatureDisplayOptions } from '@app/shared/video/video-miniature.component'
+import { Observable } from 'rxjs'
+import { Video } from '@app/shared/video/video.model'
+import { PeerTubeTemplateDirective } from '@app/shared/angular/peertube-template.directive'
+import { VideoSortField } from '@app/shared/video/sort-field.type'
+
+export type SelectionType = { [ id: number ]: boolean }
+
+@Component({
+ selector: 'my-videos-selection',
+ templateUrl: './videos-selection.component.html',
+ styleUrls: [ './videos-selection.component.scss' ]
+})
+export class VideosSelectionComponent extends AbstractVideoList implements OnInit, OnDestroy, AfterContentInit {
+ @Input() titlePage: string
+ @Input() miniatureDisplayOptions: MiniatureDisplayOptions
+ @Input() getVideosObservableFunction: (page: number, sort?: VideoSortField) => Observable<{ videos: Video[], totalVideos: number }>
+ @ContentChildren(PeerTubeTemplateDirective) templates: QueryList
+
+ @Output() selectionChange = new EventEmitter()
+ @Output() videosModelChange = new EventEmitter