Migrate client to eslint

This commit is contained in:
Chocobozzz 2021-08-17 14:42:53 +02:00
parent adb8809d43
commit 9df52d660f
No known key found for this signature in database
GPG Key ID: 583A612D890159BE
215 changed files with 2052 additions and 1196 deletions

169
client/.eslintrc.json Normal file
View File

@ -0,0 +1,169 @@
{
"root": true,
"ignorePatterns": [
"projects/**/*",
"node_modules/"
],
"overrides": [
{
"files": [
"*.ts"
],
"parserOptions": {
"project": [
"tsconfig.json",
"e2e/tsconfig.json"
],
"createDefaultProgram": true
},
"extends": [
"../.eslintrc.json",
"plugin:@angular-eslint/ng-cli-compat",
"plugin:@angular-eslint/ng-cli-compat--formatting-add-on",
"plugin:@angular-eslint/template/process-inline-templates"
],
"rules": {
"lines-between-class-members": "off",
"@typescript-eslint/lines-between-class-members": [ "off" ],
"arrow-body-style": "off",
"import/no-webpack-loader-syntax": "off",
"no-underscore-dangle": "off",
"node/no-callback-literal": "off",
"@angular-eslint/component-selector": [
"error",
{
"type": [ "element", "attribute" ],
"prefix": "my",
"style": "kebab-case"
}
],
"@angular-eslint/directive-selector": [
"error",
{
"type": [ "element", "attribute" ],
"prefix": "my",
"style": "camelCase"
}
],
"@typescript-eslint/no-this-alias": [
"error",
{
"allowDestructuring": true,
"allowedNames": ["self", "player"]
}
],
"@typescript-eslint/prefer-readonly": "off",
"@angular-eslint/use-component-view-encapsulation": "error",
"prefer-arrow/prefer-arrow-functions": "off",
"@typescript-eslint/await-thenable": "error",
"@typescript-eslint/consistent-type-definitions": "off",
"@typescript-eslint/dot-notation": "off",
"@typescript-eslint/explicit-member-accessibility": [
"off",
{
"accessibility": "explicit"
}
],
"@typescript-eslint/member-ordering": [
"off"
],
"@typescript-eslint/member-delimiter-style": [
"error",
{
"multiline": {
"delimiter": "none",
"requireLast": true
},
"singleline": {
"delimiter": "comma",
"requireLast": false
}
}
],
"@typescript-eslint/prefer-for-of": "off",
"@typescript-eslint/no-empty-function": "error",
"@typescript-eslint/no-floating-promises": "off",
"@typescript-eslint/no-inferrable-types": "error",
"@typescript-eslint/no-shadow": [
"off",
{
"hoist": "all"
}
],
"@typescript-eslint/no-unnecessary-qualifier": "error",
"@typescript-eslint/no-unnecessary-type-assertion": "error",
"@typescript-eslint/no-unused-expressions": [
"error",
{
"allowTaggedTemplates": true,
"allowShortCircuit": true
}
],
"@typescript-eslint/quotes": [
"error",
"single",
{
"avoidEscape": true,
"allowTemplateLiterals": true
}
],
"@typescript-eslint/semi": [
"error",
"never"
],
"brace-style": [
"error",
"1tbs"
],
"comma-dangle": "error",
"curly": [
"error",
"multi-line"
],
"dot-notation": "off",
"no-useless-return": "off",
"indent": "off",
"no-bitwise": "off",
"no-console": "off",
"no-return-assign": "off",
"no-constant-condition": "error",
"no-control-regex": "error",
"no-duplicate-imports": "error",
"no-empty": "error",
"no-empty-function": [
"error",
{ "allow": [ "constructors" ] }
],
"no-invalid-regexp": "error",
"no-multiple-empty-lines": "error",
"no-redeclare": "error",
"no-regex-spaces": "error",
"no-return-await": "error",
"no-shadow": "off",
"no-unused-expressions": "error",
"semi": "error",
"space-before-function-paren": [
"error",
"always"
],
"space-in-parens": [
"error",
"never"
],
"object-shorthand": [
"error",
"properties"
]
}
},
{
"files": [
"*.html"
],
"extends": [
"plugin:@angular-eslint/template/recommended"
],
"rules": {}
}
]
}

View File

@ -203,7 +203,9 @@
] ]
}, },
"ar-locale": { "ar-locale": {
"localize": ["ar"], "localize": [
"ar"
],
"budgets": [ "budgets": [
{ {
"type": "anyComponentStyle", "type": "anyComponentStyle",
@ -295,13 +297,11 @@
} }
}, },
"lint": { "lint": {
"builder": "@angular-devkit/build-angular:tslint", "builder": "@angular-eslint/builder:lint",
"options": { "options": {
"tsConfig": [ "lintFilePatterns": [
"tsconfig.json" "src/**/*.ts",
], "src/**/*.html"
"exclude": [
"**/node_modules/**"
] ]
} }
}, },
@ -378,17 +378,6 @@
"protractorConfig": "e2e/local-protractor.conf.js" "protractorConfig": "e2e/local-protractor.conf.js"
} }
} }
},
"lint": {
"builder": "@angular-devkit/build-angular:tslint",
"options": {
"tsConfig": [
"e2e/tsconfig.e2e.json"
],
"exclude": [
"**/node_modules/**"
]
}
} }
} }
} }

View File

@ -49,7 +49,7 @@ exports.config = {
onPrepare() { onPrepare() {
require('ts-node').register({ require('ts-node').register({
project: require('path').join(__dirname, './tsconfig.e2e.json') project: require('path').join(__dirname, './tsconfig.json')
}) })
jasmine.getEnv().addReporter(new SpecReporter({ spec: { displayStacktrace: true } })) jasmine.getEnv().addReporter(new SpecReporter({ spec: { displayStacktrace: true } }))
} }

View File

@ -83,7 +83,7 @@ exports.config = {
onPrepare() { onPrepare() {
require('ts-node').register({ require('ts-node').register({
project: require('path').join(__dirname, './tsconfig.e2e.json') project: require('path').join(__dirname, './tsconfig.json')
}) })
jasmine.getEnv().addReporter(new SpecReporter({ jasmine.getEnv().addReporter(new SpecReporter({
spec: { displayStacktrace: 'raw' } spec: { displayStacktrace: 'raw' }

View File

@ -14,10 +14,10 @@
}, },
"scripts": { "scripts": {
"lint": "npm run lint-ts && npm run lint-scss", "lint": "npm run lint-ts && npm run lint-scss",
"lint-ts": "tslint --project ./tsconfig.json -c ./tslint.json 'src/app/**/*.ts' 'src/standalone/**/*.ts'", "lint-ts": "eslint --ext .ts src/standalone/**/*.ts && npm run ng lint",
"lint-scss": "stylelint 'src/**/*.scss'", "lint-scss": "stylelint 'src/**/*.scss'",
"webpack": "webpack", "webpack": "webpack",
"tslint": "tslint", "eslint": "eslint",
"ng": "ng", "ng": "ng",
"webpack-bundle-analyzer": "webpack-bundle-analyzer", "webpack-bundle-analyzer": "webpack-bundle-analyzer",
"webdriver-manager": "webdriver-manager", "webdriver-manager": "webdriver-manager",
@ -27,6 +27,11 @@
"typings": "*.d.ts", "typings": "*.d.ts",
"devDependencies": { "devDependencies": {
"@angular-devkit/build-angular": "^12.0.0", "@angular-devkit/build-angular": "^12.0.0",
"@angular-eslint/builder": "12.3.1",
"@angular-eslint/eslint-plugin": "12.3.1",
"@angular-eslint/eslint-plugin-template": "12.3.1",
"@angular-eslint/schematics": "12.3.1",
"@angular-eslint/template-parser": "12.3.1",
"@angular/animations": "^12.0.0", "@angular/animations": "^12.0.0",
"@angular/cdk": "^12.0.0", "@angular/cdk": "^12.0.0",
"@angular/cli": "^12.0.0", "@angular/cli": "^12.0.0",
@ -64,17 +69,22 @@
"@types/sha.js": "^2.4.0", "@types/sha.js": "^2.4.0",
"@types/video.js": "^7.3.8", "@types/video.js": "^7.3.8",
"@types/webtorrent": "^0.109.0", "@types/webtorrent": "^0.109.0",
"@typescript-eslint/eslint-plugin": "4.28.2",
"@typescript-eslint/parser": "4.28.2",
"angular2-hotkeys": "^2.1.2", "angular2-hotkeys": "^2.1.2",
"angularx-qrcode": "11.0.0", "angularx-qrcode": "11.0.0",
"bootstrap": "^4.1.3", "bootstrap": "^4.1.3",
"buffer": "^6.0.3", "buffer": "^6.0.3",
"cache-chunk-store": "^3.0.0", "cache-chunk-store": "^3.0.0",
"chart.js": "^2.9.3", "chart.js": "^2.9.3",
"codelyzer": "^6.0.0",
"core-js": "^3.1.4", "core-js": "^3.1.4",
"css-loader": "^6.2.0", "css-loader": "^6.2.0",
"debug": "^4.3.1", "debug": "^4.3.1",
"dexie": "^3.0.0", "dexie": "^3.0.0",
"eslint": "^7.26.0",
"eslint-plugin-import": "latest",
"eslint-plugin-jsdoc": "latest",
"eslint-plugin-prefer-arrow": "latest",
"focus-visible": "^5.0.2", "focus-visible": "^5.0.2",
"hls.js": "^1.0.7", "hls.js": "^1.0.7",
"html-loader": "^2.1.2", "html-loader": "^2.1.2",
@ -112,9 +122,6 @@
"terser-webpack-plugin": "^5.1.2", "terser-webpack-plugin": "^5.1.2",
"ts-loader": "^9.2.2", "ts-loader": "^9.2.2",
"tslib": "^2.0.0", "tslib": "^2.0.0",
"tslint": "~6.1.0",
"tslint-angular": "^3.0.2",
"tslint-config-standard": "^9.0.0",
"typescript": "~4.3.4", "typescript": "~4.3.4",
"video.js": "^7", "video.js": "^7",
"videojs-contextmenu-pt": "^5.4.1", "videojs-contextmenu-pt": "^5.4.1",

View File

@ -90,7 +90,7 @@ export class AboutFollowsComponent implements OnInit {
private loadMoreFollowers (reset = false) { private loadMoreFollowers (reset = false) {
const pagination = this.restService.componentPaginationToRestPagination(this.followersPagination) const pagination = this.restService.componentPaginationToRestPagination(this.followersPagination)
this.followService.getFollowers({ pagination: pagination, sort: this.sort, state: 'accepted' }) this.followService.getFollowers({ pagination, sort: this.sort, state: 'accepted' })
.subscribe({ .subscribe({
next: resultList => { next: resultList => {
if (reset) this.followers = [] if (reset) this.followers = []

View File

@ -95,6 +95,6 @@ export class AboutInstanceComponent implements OnInit, AfterViewChecked {
onClickCopyLink (anchor: HTMLAnchorElement) { onClickCopyLink (anchor: HTMLAnchorElement) {
const link = anchor.href const link = anchor.href
copyToClipboard(link) copyToClipboard(link)
this.notifier.success(link, $localize `Link copied`) this.notifier.success(link, $localize`Link copied`)
} }
} }

View File

@ -77,10 +77,10 @@ export class ContactAdminModalComponent extends FormReactive implements OnInit {
} }
sendForm () { sendForm () {
const fromName = this.form.value[ 'fromName' ] const fromName = this.form.value['fromName']
const fromEmail = this.form.value[ 'fromEmail' ] const fromEmail = this.form.value['fromEmail']
const subject = this.form.value[ 'subject' ] const subject = this.form.value['subject']
const body = this.form.value[ 'body' ] const body = this.form.value['body']
this.instanceService.contactAdministrator(fromEmail, fromName, subject, body) this.instanceService.contactAdministrator(fromEmail, fromName, subject, body)
.subscribe({ .subscribe({

View File

@ -3,7 +3,6 @@ import { RouterModule, Routes } from '@angular/router'
import { AboutFollowsComponent } from '@app/+about/about-follows/about-follows.component' import { AboutFollowsComponent } from '@app/+about/about-follows/about-follows.component'
import { AboutInstanceComponent } from '@app/+about/about-instance/about-instance.component' import { AboutInstanceComponent } from '@app/+about/about-instance/about-instance.component'
import { AboutInstanceResolver } from '@app/+about/about-instance/about-instance.resolver' import { AboutInstanceResolver } from '@app/+about/about-instance/about-instance.resolver'
import { ContactAdminModalComponent } from '@app/+about/about-instance/contact-admin-modal.component'
import { AboutPeertubeComponent } from '@app/+about/about-peertube/about-peertube.component' import { AboutPeertubeComponent } from '@app/+about/about-peertube/about-peertube.component'
import { AboutComponent } from './about.component' import { AboutComponent } from './about.component'

View File

@ -1,10 +1,10 @@
import { from, Subject, Subscription } from 'rxjs' import { from, Subject, Subscription } from 'rxjs'
import { concatMap, map, switchMap, tap } from 'rxjs/operators' import { concatMap, map, switchMap, tap } from 'rxjs/operators'
import { Component, OnDestroy, OnInit } from '@angular/core' import { Component, OnDestroy, OnInit } from '@angular/core'
import { ComponentPagination, hasMoreItems, MarkdownService, ScreenService, User, UserService } from '@app/core' import { ComponentPagination, hasMoreItems, MarkdownService, User, UserService } from '@app/core'
import { Account, AccountService, Video, VideoChannel, VideoChannelService, VideoService } from '@app/shared/shared-main' import { Account, AccountService, Video, VideoChannel, VideoChannelService, VideoService } from '@app/shared/shared-main'
import { NSFWPolicyType, VideoSortField } from '@shared/models'
import { MiniatureDisplayOptions } from '@app/shared/shared-video-miniature' import { MiniatureDisplayOptions } from '@app/shared/shared-video-miniature'
import { NSFWPolicyType, VideoSortField } from '@shared/models'
@Component({ @Component({
selector: 'my-account-video-channels', selector: 'my-account-video-channels',
@ -87,7 +87,9 @@ export class AccountVideoChannelsComponent implements OnInit, OnDestroy {
this.videoChannelService.listAccountVideoChannels(options) this.videoChannelService.listAccountVideoChannels(options)
.pipe( .pipe(
tap(res => this.channelPagination.totalItems = res.total), tap(res => {
this.channelPagination.totalItems = res.total
}),
switchMap(res => from(res.data)), switchMap(res => from(res.data)),
concatMap(videoChannel => { concatMap(videoChannel => {
const options = { const options = {
@ -113,14 +115,14 @@ export class AccountVideoChannelsComponent implements OnInit, OnDestroy {
} }
getVideosOf (videoChannel: VideoChannel) { getVideosOf (videoChannel: VideoChannel) {
const obj = this.videos[ videoChannel.id ] const obj = this.videos[videoChannel.id]
if (!obj) return [] if (!obj) return []
return obj.videos return obj.videos
} }
getTotalVideosOf (videoChannel: VideoChannel) { getTotalVideosOf (videoChannel: VideoChannel) {
const obj = this.videos[ videoChannel.id ] const obj = this.videos[videoChannel.id]
if (!obj) return undefined if (!obj) return undefined
return obj.total return obj.total

View File

@ -1,5 +1,5 @@
import { forkJoin, Subscription } from 'rxjs' import { forkJoin, Subscription } from 'rxjs'
import { first, tap } from 'rxjs/operators' import { first } from 'rxjs/operators'
import { Component, ComponentFactoryResolver, OnDestroy, OnInit } from '@angular/core' import { Component, ComponentFactoryResolver, OnDestroy, OnInit } from '@angular/core'
import { ActivatedRoute, Router } from '@angular/router' import { ActivatedRoute, Router } from '@angular/router'
import { AuthService, ConfirmService, LocalStorageService, Notifier, ScreenService, ServerService, UserService } from '@app/core' import { AuthService, ConfirmService, LocalStorageService, Notifier, ScreenService, ServerService, UserService } from '@app/core'

View File

@ -71,14 +71,14 @@
<a [routerLink]="item.routerLink" routerLinkActive="active" class="title-page">{{ item.label }}</a> <a [routerLink]="item.routerLink" routerLinkActive="active" class="title-page">{{ item.label }}</a>
</ng-template> </ng-template>
<list-overflow [hidden]="hideMenu" [items]="links" [itemTemplate]="linkTemplate"></list-overflow> <my-list-overflow [hidden]="hideMenu" [items]="links" [itemTemplate]="linkTemplate"></my-list-overflow>
<simple-search-input <my-simple-search-input
[alwaysShow]="!isInSmallView()" (searchChanged)="searchChanged($event)" [alwaysShow]="!isInSmallView()" (searchChanged)="searchChanged($event)"
(inputDisplayChanged)="onSearchInputDisplayChanged($event)" name="search-videos" (inputDisplayChanged)="onSearchInputDisplayChanged($event)" name="search-videos"
i18n-iconTitle icon-title="Search account videos" i18n-iconTitle icon-title="Search account videos"
i18n-placeholder placeholder="Search account videos" i18n-placeholder placeholder="Search account videos"
></simple-search-input> ></my-simple-search-input>
</div> </div>
<router-outlet (activate)="onOutletLoaded($event)"></router-outlet> <router-outlet (activate)="onOutletLoaded($event)"></router-outlet>

View File

@ -61,7 +61,7 @@ export class AccountsComponent implements OnInit, OnDestroy {
ngOnInit () { ngOnInit () {
this.routeSub = this.route.params this.routeSub = this.route.params
.pipe( .pipe(
map(params => params[ 'accountId' ]), map(params => params['accountId']),
distinctUntilChanged(), distinctUntilChanged(),
switchMap(accountId => this.accountService.getAccount(accountId)), switchMap(accountId => this.accountService.getAccount(accountId)),
tap(account => this.onAccount(account)), tap(account => this.onAccount(account)),
@ -72,7 +72,9 @@ export class AccountsComponent implements OnInit, OnDestroy {
])) ]))
) )
.subscribe({ .subscribe({
next: videoChannels => this.videoChannels = videoChannels.data, next: videoChannels => {
this.videoChannels = videoChannels.data
},
error: err => this.notifier.error(err.message) error: err => this.notifier.error(err.message)
}) })
@ -176,7 +178,9 @@ export class AccountsComponent implements OnInit, OnDestroy {
if (user.hasRight(UserRight.MANAGE_USERS)) { if (user.hasRight(UserRight.MANAGE_USERS)) {
this.userService.getUser(account.userId) this.userService.getUser(account.userId)
.subscribe({ .subscribe({
next: accountUser => this.accountUser = accountUser, next: accountUser => {
this.accountUser = accountUser
},
error: err => this.notifier.error(err.message) error: err => this.notifier.error(err.message)
}) })
@ -209,6 +213,8 @@ export class AccountsComponent implements OnInit, OnDestroy {
itemsPerPage: 0 itemsPerPage: 0
}, },
sort: '-publishedAt' sort: '-publishedAt'
}).subscribe(res => this.accountVideosCount = res.total) }).subscribe(res => {
this.accountVideosCount = res.total
})
} }
} }

View File

@ -97,7 +97,7 @@ export class EditBasicConfigurationComponent implements OnInit, OnChanges {
.pipe(pairwise()) .pipe(pairwise())
.subscribe(([ oldValue, newValue ]) => { .subscribe(([ oldValue, newValue ]) => {
if (oldValue !== true && newValue === true) { if (oldValue !== true && newValue === true) {
// tslint:disable:max-line-length /* eslint-disable max-len */
this.signupAlertMessage = $localize`You enabled signup: we automatically enabled the "Block new videos automatically" checkbox of the "Videos" section just below.` this.signupAlertMessage = $localize`You enabled signup: we automatically enabled the "Block new videos automatically" checkbox of the "Videos" section just below.`
this.form.patchValue({ this.form.patchValue({

View File

@ -277,7 +277,9 @@ export class EditCustomConfigComponent extends FormReactive implements OnInit {
// Reload general configuration // Reload general configuration
this.serverService.resetConfig() this.serverService.resetConfig()
.subscribe(config => this.serverConfig = config) .subscribe(config => {
this.serverConfig = config
})
this.updateForm() this.updateForm()

View File

@ -1,4 +1,4 @@
import { Component, Input, OnInit } from '@angular/core' import { Component, Input } from '@angular/core'
import { FormGroup } from '@angular/forms' import { FormGroup } from '@angular/forms'
import { CustomMarkupService } from '@app/shared/shared-custom-markup' import { CustomMarkupService } from '@app/shared/shared-custom-markup'

View File

@ -2,7 +2,6 @@ import { SortMeta } from 'primeng/api'
import { Component, OnInit, ViewChild } from '@angular/core' import { Component, OnInit, ViewChild } from '@angular/core'
import { ConfirmService, Notifier, RestPagination, RestTable } from '@app/core' import { ConfirmService, Notifier, RestPagination, RestTable } from '@app/core'
import { InstanceFollowService } from '@app/shared/shared-instance' import { InstanceFollowService } from '@app/shared/shared-instance'
import { BatchDomainsModalComponent } from '@app/shared/shared-moderation'
import { ActorFollow } from '@shared/models' import { ActorFollow } from '@shared/models'
import { FollowModalComponent } from './follow-modal.component' import { FollowModalComponent } from './follow-modal.component'

View File

@ -21,7 +21,7 @@ export class VideoRedundanciesListComponent extends RestTable implements OnInit
pagination: RestPagination = { count: this.rowsPerPage, start: 0 } pagination: RestPagination = { count: this.rowsPerPage, start: 0 }
displayType: VideoRedundanciesTarget = 'my-videos' displayType: VideoRedundanciesTarget = 'my-videos'
redundanciesGraphsData: { stats: VideosRedundancyStats, graphData: object, options: object }[] = [] redundanciesGraphsData: { stats: VideosRedundancyStats, graphData: any, options: any }[] = []
noRedundancies = false noRedundancies = false

View File

@ -21,7 +21,7 @@
<ng-template pTemplate="header"> <ng-template pTemplate="header">
<tr> <tr>
<th style="width: 40px"></th> <th style="width: 40px;"></th>
<th style="width: 150px;"></th> <th style="width: 150px;"></th>
<th i18n pSortableColumn="name">Video <p-sortIcon field="name"></p-sortIcon></th> <th i18n pSortableColumn="name">Video <p-sortIcon field="name"></p-sortIcon></th>
<th style="width: 100px;" i18n>Sensitive</th> <th style="width: 100px;" i18n>Sensitive</th>
@ -54,7 +54,7 @@
</div> </div>
<div class="table-video-text"> <div class="table-video-text">
<div> <div>
<my-global-icon i18n-title title="The video was blocked due to automatic blocking of new videos" *ngIf="videoBlock.type == 2" iconName="robot"></my-global-icon> <my-global-icon i18n-title title="The video was blocked due to automatic blocking of new videos" *ngIf="videoBlock.type === 2" iconName="robot"></my-global-icon>
{{ videoBlock.video.name }} {{ videoBlock.video.name }}
</div> </div>
<div class="text-muted">by {{ videoBlock.video.channel?.displayName }} on {{ videoBlock.video.channel?.host }} </div> <div class="text-muted">by {{ videoBlock.video.channel?.displayName }} on {{ videoBlock.video.channel?.host }} </div>

View File

@ -28,11 +28,11 @@ export class VideoBlockListComponent extends RestTable implements OnInit {
inputFilters: AdvancedInputFilter[] = [ inputFilters: AdvancedInputFilter[] = [
{ {
queryParams: { 'search': 'type:auto' }, queryParams: { search: 'type:auto' },
label: $localize`Automatic blocks` label: $localize`Automatic blocks`
}, },
{ {
queryParams: { 'search': 'type:manual' }, queryParams: { search: 'type:manual' },
label: $localize`Manual blocks` label: $localize`Manual blocks`
} }
] ]

View File

@ -44,11 +44,11 @@ export class VideoCommentListComponent extends RestTable implements OnInit {
inputFilters: AdvancedInputFilter[] = [ inputFilters: AdvancedInputFilter[] = [
{ {
queryParams: { 'search': 'local:true' }, queryParams: { search: 'local:true' },
label: $localize`Local comments` label: $localize`Local comments`
}, },
{ {
queryParams: { 'search': 'local:false' }, queryParams: { search: 'local:false' },
label: $localize`Remote comments` label: $localize`Remote comments`
} }
] ]

View File

@ -3,7 +3,7 @@
</div> </div>
<div class="search-bar"> <div class="search-bar">
<input type="text" (input)="onSearchChange($event)" i18n-placeholder placeholder="Search..." autofocus /> <input type="text" (input)="onSearchChange($event)" i18n-placeholder placeholder="Search..." myAutofocus />
</div> </div>
<div class="alert alert-info" i18n *ngIf="pluginInstalled"> <div class="alert alert-info" i18n *ngIf="pluginInstalled">

View File

@ -103,8 +103,8 @@ export class PluginShowInstalledComponent extends FormReactive implements OnInit
const settingsValues: any = {} const settingsValues: any = {}
for (const setting of this.registeredSettings) { for (const setting of this.registeredSettings) {
buildOptions[ setting.name ] = null buildOptions[setting.name] = null
settingsValues[ setting.name ] = this.getSetting(setting.name) settingsValues[setting.name] = this.getSetting(setting.name)
} }
this.buildForm(buildOptions) this.buildForm(buildOptions)
@ -117,7 +117,7 @@ export class PluginShowInstalledComponent extends FormReactive implements OnInit
private getSetting (name: string) { private getSetting (name: string) {
const settings = this.plugin.settings const settings = this.plugin.settings
if (settings && settings[name] !== undefined) return settings[name] if (settings?.[name] !== undefined) return settings[name]
const registered = this.registeredSettings.find(r => r.name === name) const registered = this.registeredSettings.find(r => r.name === name)

View File

@ -1,10 +1,8 @@
import { Observable } from 'rxjs' import { catchError } from 'rxjs/operators'
import { catchError, map, switchMap } from 'rxjs/operators'
import { HttpClient, HttpParams } from '@angular/common/http' import { HttpClient, HttpParams } from '@angular/common/http'
import { Injectable } from '@angular/core' import { Injectable } from '@angular/core'
import { ComponentPagination, RestExtractor, RestService } from '@app/core' import { ComponentPagination, RestExtractor, RestService } from '@app/core'
import { PluginService } from '@app/core/plugins/plugin.service' import { PluginService } from '@app/core/plugins/plugin.service'
import { peertubeTranslate } from '@shared/core-utils/i18n'
import { import {
InstallOrUpdatePlugin, InstallOrUpdatePlugin,
ManagePlugin, ManagePlugin,

View File

@ -20,9 +20,9 @@ export class JobService {
) {} ) {}
getJobs (options: { getJobs (options: {
jobState?: JobStateClient, jobState?: JobStateClient
jobType: JobTypeClient, jobType: JobTypeClient
pagination: RestPagination, pagination: RestPagination
sort: SortMeta sort: SortMeta
}): Observable<ResultList<Job>> { }): Observable<ResultList<Job>> {
const { jobState, jobType, pagination, sort } = options const { jobState, jobType, pagination, sort } = options
@ -32,7 +32,7 @@ export class JobService {
if (jobType !== 'all') params = params.append('jobType', jobType) if (jobType !== 'all') params = params.append('jobType', jobType)
return this.authHttp.get<ResultList<Job>>(JobService.BASE_JOB_URL + `/${jobState ? jobState : ''}`, { params }) return this.authHttp.get<ResultList<Job>>(JobService.BASE_JOB_URL + `/${jobState || ''}`, { params })
.pipe( .pipe(
map(res => { map(res => {
return this.restExtractor.convertResultListDateToHuman(res, [ 'createdAt', 'processedOn', 'finishedOn' ]) return this.restExtractor.convertResultListDateToHuman(res, [ 'createdAt', 'processedOn', 'finishedOn' ])

View File

@ -18,9 +18,9 @@ export class LogsService {
) {} ) {}
getLogs (options: { getLogs (options: {
isAuditLog: boolean, isAuditLog: boolean
startDate: string, startDate: string
level?: LogLevel, level?: LogLevel
endDate?: string endDate?: string
}): Observable<any[]> { }): Observable<any[]> {
const { isAuditLog, startDate } = options const { isAuditLog, startDate } = options

View File

@ -78,7 +78,9 @@ export class UserCreateComponent extends UserEdit implements OnInit {
this.router.navigate([ '/admin/users/list' ]) this.router.navigate([ '/admin/users/list' ])
}, },
error: err => this.error = err.message error: err => {
this.error = err.message
}
}) })
} }

View File

@ -7,7 +7,7 @@ import { HTMLServerConfig, UserAdminFlag, UserRole, VideoResolution } from '@sha
import { SelectOptionsItem } from '../../../../types/select-options-item.model' import { SelectOptionsItem } from '../../../../types/select-options-item.model'
@Directive() @Directive()
// tslint:disable-next-line: directive-class-suffix // eslint-disable-next-line @angular-eslint/directive-class-suffix
export abstract class UserEdit extends FormReactive implements OnInit { export abstract class UserEdit extends FormReactive implements OnInit {
videoQuotaOptions: SelectOptionsItem[] = [] videoQuotaOptions: SelectOptionsItem[] = []
videoQuotaDailyOptions: SelectOptionsItem[] = [] videoQuotaDailyOptions: SelectOptionsItem[] = []

View File

@ -39,7 +39,9 @@ export class UserPasswordComponent extends FormReactive implements OnInit {
.subscribe({ .subscribe({
next: () => this.notifier.success($localize`Password changed for user ${this.username}.`), next: () => this.notifier.success($localize`Password changed for user ${this.username}.`),
error: err => this.error = err.message error: err => {
this.error = err.message
}
}) })
} }

View File

@ -63,7 +63,9 @@ export class UserUpdateComponent extends UserEdit implements OnInit, OnDestroy {
.subscribe({ .subscribe({
next: user => this.onUserFetched(user), next: user => this.onUserFetched(user),
error: err => this.error = err.message error: err => {
this.error = err.message
}
}) })
}) })
} }
@ -91,7 +93,9 @@ export class UserUpdateComponent extends UserEdit implements OnInit, OnDestroy {
this.router.navigate([ '/admin/users/list' ]) this.router.navigate([ '/admin/users/list' ])
}, },
error: err => this.error = err.message error: err => {
this.error = err.message
}
}) })
} }
@ -114,7 +118,9 @@ export class UserUpdateComponent extends UserEdit implements OnInit, OnDestroy {
this.notifier.success($localize`An email asking for password reset has been sent to ${this.user.username}.`) this.notifier.success($localize`An email asking for password reset has been sent to ${this.user.username}.`)
}, },
error: err => this.error = err.message error: err => {
this.error = err.message
}
}) })
} }

View File

@ -36,7 +36,7 @@ export class UserListComponent extends RestTable implements OnInit {
inputFilters: AdvancedInputFilter[] = [ inputFilters: AdvancedInputFilter[] = [
{ {
queryParams: { 'search': 'banned:true' }, queryParams: { search: 'banned:true' },
label: $localize`Banned users` label: $localize`Banned users`
} }
] ]

View File

@ -21,7 +21,7 @@
<label i18n for="username">User</label> <label i18n for="username">User</label>
<input <input
type="text" id="username" i18n-placeholder placeholder="Username or email address" required tabindex="1" type="text" id="username" i18n-placeholder placeholder="Username or email address" required tabindex="1"
formControlName="username" class="form-control" [ngClass]="{ 'input-error': formErrors['username'] }" autofocus formControlName="username" class="form-control" [ngClass]="{ 'input-error': formErrors['username'] }" myAutofocus
> >
</div> </div>

View File

@ -36,6 +36,7 @@ export class MyAccountApplicationsComponent implements OnInit {
async renewToken () { async renewToken () {
const res = await this.confirmService.confirm( const res = await this.confirmService.confirm(
// eslint-disable-next-line max-len
$localize`Renewing the token will disallow previously configured clients from retrieving the feed until they use the new token. Proceed?`, $localize`Renewing the token will disallow previously configured clients from retrieving the feed until they use the new token. Proceed?`,
$localize`Renew token` $localize`Renew token`
) )

View File

@ -28,7 +28,7 @@ export class MyAccountChangeEmailComponent extends FormReactive implements OnIni
ngOnInit () { ngOnInit () {
this.buildForm({ this.buildForm({
'new-email': USER_EMAIL_VALIDATOR, 'new-email': USER_EMAIL_VALIDATOR,
'password': USER_PASSWORD_VALIDATOR password: USER_PASSWORD_VALIDATOR
}) })
this.user = this.authService.getUser() this.user = this.authService.getUser()
@ -38,8 +38,8 @@ export class MyAccountChangeEmailComponent extends FormReactive implements OnIni
this.error = null this.error = null
this.success = null this.success = null
const password = this.form.value[ 'password' ] const password = this.form.value['password']
const email = this.form.value[ 'new-email' ] const email = this.form.value['new-email']
forkJoin([ forkJoin([
this.serverService.getConfig(), this.serverService.getConfig(),

View File

@ -1,7 +1,11 @@
import { filter } from 'rxjs/operators' import { filter } from 'rxjs/operators'
import { Component, OnInit } from '@angular/core' import { Component, OnInit } from '@angular/core'
import { AuthService, Notifier, UserService } from '@app/core' import { AuthService, Notifier, UserService } from '@app/core'
import { USER_CONFIRM_PASSWORD_VALIDATOR, USER_PASSWORD_VALIDATOR, USER_EXISTING_PASSWORD_VALIDATOR } from '@app/shared/form-validators/user-validators' import {
USER_CONFIRM_PASSWORD_VALIDATOR,
USER_EXISTING_PASSWORD_VALIDATOR,
USER_PASSWORD_VALIDATOR
} from '@app/shared/form-validators/user-validators'
import { FormReactive, FormValidatorService } from '@app/shared/shared-forms' import { FormReactive, FormValidatorService } from '@app/shared/shared-forms'
import { User } from '@shared/models' import { User } from '@shared/models'
@ -35,13 +39,13 @@ export class MyAccountChangePasswordComponent extends FormReactive implements On
const confirmPasswordControl = this.form.get('new-confirmed-password') const confirmPasswordControl = this.form.get('new-confirmed-password')
confirmPasswordControl.valueChanges confirmPasswordControl.valueChanges
.pipe(filter(v => v !== this.form.value[ 'new-password' ])) .pipe(filter(v => v !== this.form.value['new-password']))
.subscribe(() => confirmPasswordControl.setErrors({ matchPassword: true })) .subscribe(() => confirmPasswordControl.setErrors({ matchPassword: true }))
} }
changePassword () { changePassword () {
const currentPassword = this.form.value[ 'current-password' ] const currentPassword = this.form.value['current-password']
const newPassword = this.form.value[ 'new-password' ] const newPassword = this.form.value['new-password']
this.userService.changePassword(currentPassword, newPassword) this.userService.changePassword(currentPassword, newPassword)
.subscribe({ .subscribe({

View File

@ -19,6 +19,7 @@ export class MyAccountDangerZoneComponent {
async deleteMe () { async deleteMe () {
const res = await this.confirmService.confirmWithInput( const res = await this.confirmService.confirmWithInput(
// eslint-disable-next-line max-len
$localize`Are you sure you want to delete your account? This will delete all your data, including channels, videos and comments. Content cached by other servers and other third-parties might make longer to be deleted.`, $localize`Are you sure you want to delete your account? This will delete all your data, including channels, videos and comments. Content cached by other servers and other third-parties might make longer to be deleted.`,
$localize`Type your username to confirm`, $localize`Type your username to confirm`,
this.user.username, this.user.username,

View File

@ -64,7 +64,7 @@ export class MyVideoChannelCreateComponent extends MyVideoChannelEdit implements
this.authService.refreshUserInformation() this.authService.refreshUserInformation()
this.notifier.success($localize`Video channel ${videoChannelCreate.displayName} created.`) this.notifier.success($localize`Video channel ${videoChannelCreate.displayName} created.`)
this.router.navigate(['/my-library', 'video-channels']) this.router.navigate([ '/my-library', 'video-channels' ])
}, },
error: err => { error: err => {

View File

@ -66,7 +66,9 @@ export class MyVideoChannelUpdateComponent extends MyVideoChannelEdit implements
}) })
}, },
error: err => this.error = err.message error: err => {
this.error = err.message
}
}) })
}) })
} }
@ -96,7 +98,9 @@ export class MyVideoChannelUpdateComponent extends MyVideoChannelEdit implements
this.router.navigate([ '/my-library', 'video-channels' ]) this.router.navigate([ '/my-library', 'video-channels' ])
}, },
error: err => this.error = err.message error: err => {
this.error = err.message
}
}) })
} }

View File

@ -121,16 +121,16 @@ channel with the same name (${videoChannel.name})!`,
display: false display: false
}, },
scales: { scales: {
xAxes: [{ xAxes: [ {
display: false display: false
}], } ],
yAxes: [{ yAxes: [ {
display: false, display: false,
ticks: { ticks: {
min: Math.max(0, this.videoChannelsMinimumDailyViews - (3 * this.videoChannelsMaximumDailyViews / 100)), min: Math.max(0, this.videoChannelsMinimumDailyViews - (3 * this.videoChannelsMaximumDailyViews / 100)),
max: Math.max(1, this.videoChannelsMaximumDailyViews) max: Math.max(1, this.videoChannelsMaximumDailyViews)
} }
}] } ]
}, },
layout: { layout: {
padding: { padding: {

View File

@ -1,4 +1,3 @@
import { Subject } from 'rxjs'
import { tap } from 'rxjs/operators' import { tap } from 'rxjs/operators'
import { Component, ComponentFactoryResolver, OnInit, ViewChild } from '@angular/core' import { Component, ComponentFactoryResolver, OnInit, ViewChild } from '@angular/core'
import { ActivatedRoute, Router } from '@angular/router' import { ActivatedRoute, Router } from '@angular/router'
@ -109,9 +108,9 @@ export class MyHistoryComponent implements OnInit, DisableForReuseHook {
this.userService.updateMyProfile({ videosHistoryEnabled: this.videosHistoryEnabled }) this.userService.updateMyProfile({ videosHistoryEnabled: this.videosHistoryEnabled })
.subscribe({ .subscribe({
next: () => { next: () => {
const message = this.videosHistoryEnabled === true ? const message = this.videosHistoryEnabled === true
$localize`Videos history is enabled` : ? $localize`Videos history is enabled`
$localize`Videos history is disabled` : $localize`Videos history is disabled`
this.notifier.success(message) this.notifier.success(message)

View File

@ -78,7 +78,9 @@ export class MyVideoPlaylistCreateComponent extends MyVideoPlaylistEdit implemen
this.router.navigate([ '/my-library', 'video-playlists' ]) this.router.navigate([ '/my-library', 'video-playlists' ])
}, },
error: err => this.error = err.message error: err => {
this.error = err.message
}
}) })
} }

View File

@ -57,7 +57,7 @@ export class MyVideoPlaylistElementsComponent implements OnInit, OnDestroy {
] ]
this.paramsSub = this.route.params.subscribe(routeParams => { this.paramsSub = this.route.params.subscribe(routeParams => {
this.videoPlaylistId = routeParams[ 'videoPlaylistId' ] this.videoPlaylistId = routeParams['videoPlaylistId']
this.loadElements() this.loadElements()
this.loadPlaylistInfo() this.loadPlaylistInfo()
@ -145,8 +145,6 @@ export class MyVideoPlaylistElementsComponent implements OnInit, OnDestroy {
* we add a delay to prevent unwanted drag&drop. * we add a delay to prevent unwanted drag&drop.
* *
* @see {@link https://github.com/Chocobozzz/PeerTube/issues/2078} * @see {@link https://github.com/Chocobozzz/PeerTube/issues/2078}
*
* @returns {null|number} Null for no delay, or a number in milliseconds.
*/ */
getDragStartDelay (): null | number { getDragStartDelay (): null | number {
if (this.screenService.isInTouchScreen()) { if (this.screenService.isInTouchScreen()) {

View File

@ -65,14 +65,16 @@ export class MyVideoPlaylistUpdateComponent extends MyVideoPlaylistEdit implemen
}) })
) )
.subscribe({ .subscribe({
next: ([ videoPlaylistToUpdate, videoPlaylistPrivacies]) => { next: ([ videoPlaylistToUpdate, videoPlaylistPrivacies ]) => {
this.videoPlaylistToUpdate = videoPlaylistToUpdate this.videoPlaylistToUpdate = videoPlaylistToUpdate
this.videoPlaylistPrivacies = videoPlaylistPrivacies this.videoPlaylistPrivacies = videoPlaylistPrivacies
this.hydrateFormFromPlaylist() this.hydrateFormFromPlaylist()
}, },
error: err => this.error = err.message error: err => {
this.error = err.message
}
}) })
} }
@ -99,7 +101,9 @@ export class MyVideoPlaylistUpdateComponent extends MyVideoPlaylistEdit implemen
this.router.navigate([ '/my-library', 'video-playlists' ]) this.router.navigate([ '/my-library', 'video-playlists' ])
}, },
error: err => this.error = err.message error: err => {
this.error = err.message
}
}) })
} }

View File

@ -49,7 +49,9 @@ export class VideoChangeOwnershipComponent extends FormReactive implements OnIni
const query = event.query const query = event.query
this.userService.autocomplete(query) this.userService.autocomplete(query)
.subscribe({ .subscribe({
next: usernames => this.usernamePropositions = usernames, next: usernames => {
this.usernamePropositions = usernames
},
error: err => this.notifier.error(err.message) error: err => this.notifier.error(err.message)
}) })

View File

@ -49,7 +49,7 @@ export class MyVideosComponent implements OnInit, DisableForReuseHook {
inputFilters: AdvancedInputFilter[] = [ inputFilters: AdvancedInputFilter[] = [
{ {
queryParams: { 'search': 'isLive:true' }, queryParams: { search: 'isLive:true' },
label: $localize`Only live videos` label: $localize`Only live videos`
} }
] ]
@ -107,7 +107,7 @@ export class MyVideosComponent implements OnInit, DisableForReuseHook {
async deleteSelectedVideos () { async deleteSelectedVideos () {
const toDeleteVideosIds = Object.keys(this.selection) const toDeleteVideosIds = Object.keys(this.selection)
.filter(k => this.selection[ k ] === true) .filter(k => this.selection[k] === true)
.map(k => parseInt(k, 10)) .map(k => parseInt(k, 10))
const res = await this.confirmService.confirm( const res = await this.confirmService.confirm(

View File

@ -7,7 +7,7 @@ import { SearchService } from '@app/shared/shared-search'
@Component({ @Component({
selector: 'my-remote-interaction', selector: 'my-remote-interaction',
templateUrl: './remote-interaction.component.html', templateUrl: './remote-interaction.component.html',
styleUrls: ['./remote-interaction.component.scss'] styleUrls: [ './remote-interaction.component.scss' ]
}) })
export class RemoteInteractionComponent implements OnInit { export class RemoteInteractionComponent implements OnInit {
error = '' error = ''

View File

@ -1,5 +1,5 @@
import { Component } from '@angular/core'
import { CdkStep, CdkStepper } from '@angular/cdk/stepper' import { CdkStep, CdkStepper } from '@angular/cdk/stepper'
import { Component } from '@angular/core'
@Component({ @Component({
selector: 'my-custom-stepper', selector: 'my-custom-stepper',
@ -14,13 +14,13 @@ export class CustomStepperComponent extends CdkStepper {
} }
isCompleted (step: CdkStep) { isCompleted (step: CdkStep) {
return step.stepControl && step.stepControl.dirty && step.stepControl.valid return step.stepControl?.dirty && step.stepControl.valid
} }
isAccessible (index: number) { isAccessible (index: number) {
const stepsCompletedMap = this.steps.map(step => this.isCompleted(step)) const stepsCompletedMap = this.steps.map(step => this.isCompleted(step))
return index === 0 return index === 0
? true ? true
: stepsCompletedMap[ index - 1 ] : stepsCompletedMap[index - 1]
} }
} }

View File

@ -49,8 +49,7 @@ export class RegisterComponent implements OnInit {
private authService: AuthService, private authService: AuthService,
private userService: UserService, private userService: UserService,
private hooks: HooksService private hooks: HooksService
) { ) { }
}
get requiresEmailVerification () { get requiresEmailVerification () {
return this.serverConfig.signup.requiresEmailVerification return this.serverConfig.signup.requiresEmailVerification
@ -138,11 +137,15 @@ export class RegisterComponent implements OnInit {
this.success = $localize`You are now logged in as ${body.username}!` this.success = $localize`You are now logged in as ${body.username}!`
}, },
error: err => this.error = err.message error: err => {
this.error = err.message
}
}) })
}, },
error: err => this.error = err.message error: err => {
this.error = err.message
}
}) })
} }
} }

View File

@ -1,5 +1,5 @@
import { forkJoin, Subscription } from 'rxjs' import { forkJoin, Subscription } from 'rxjs'
import { first, tap } from 'rxjs/operators' import { first } from 'rxjs/operators'
import { Component, ComponentFactoryResolver, OnDestroy, OnInit } from '@angular/core' import { Component, ComponentFactoryResolver, OnDestroy, OnInit } from '@angular/core'
import { ActivatedRoute, Router } from '@angular/router' import { ActivatedRoute, Router } from '@angular/router'
import { AuthService, ConfirmService, LocalStorageService, Notifier, ScreenService, ServerService, UserService } from '@app/core' import { AuthService, ConfirmService, LocalStorageService, Notifier, ScreenService, ServerService, UserService } from '@app/core'

View File

@ -114,7 +114,7 @@
<a [routerLink]="item.routerLink" routerLinkActive="active" class="title-page">{{ item.label }}</a> <a [routerLink]="item.routerLink" routerLinkActive="active" class="title-page">{{ item.label }}</a>
</ng-template> </ng-template>
<list-overflow [items]="links" [itemTemplate]="linkTemplate"></list-overflow> <my-list-overflow [items]="links" [itemTemplate]="linkTemplate"></my-list-overflow>
</div> </div>
<router-outlet></router-outlet> <router-outlet></router-outlet>

View File

@ -44,7 +44,7 @@ export class VideoChannelsComponent implements OnInit, OnDestroy {
ngOnInit () { ngOnInit () {
this.routeSub = this.route.params this.routeSub = this.route.params
.pipe( .pipe(
map(params => params[ 'videoChannelName' ]), map(params => params['videoChannelName']),
distinctUntilChanged(), distinctUntilChanged(),
switchMap(videoChannelName => this.videoChannelService.getVideoChannel(videoChannelName)), switchMap(videoChannelName => this.videoChannelService.getVideoChannel(videoChannelName)),
catchError(err => this.restExtractor.redirectTo404IfNotFound(err, 'other', [ catchError(err => this.restExtractor.redirectTo404IfNotFound(err, 'other', [
@ -64,9 +64,9 @@ export class VideoChannelsComponent implements OnInit, OnDestroy {
this.hotkeys = [ this.hotkeys = [
new Hotkey('S', (event: KeyboardEvent): boolean => { new Hotkey('S', (event: KeyboardEvent): boolean => {
this.subscribeButton.subscribed ? if (this.subscribeButton.subscribed) this.subscribeButton.unsubscribe()
this.subscribeButton.unsubscribe() : else this.subscribeButton.subscribe()
this.subscribeButton.subscribe()
return false return false
}, undefined, $localize`Subscribe to the account`) }, undefined, $localize`Subscribe to the account`)
] ]

View File

@ -73,7 +73,7 @@ export class I18nPrimengCalendarService {
} }
getTimezone () { getTimezone () {
const gmt = new Date().toString().match(/([A-Z]+[\+-][0-9]+)/)[1] const gmt = new Date().toString().match(/([A-Z]+[+-][0-9]+)/)[1]
const timezone = Intl.DateTimeFormat().resolvedOptions().timeZone const timezone = Intl.DateTimeFormat().resolvedOptions().timeZone
return `${timezone} - ${gmt}` return `${timezone} - ${gmt}`

View File

@ -66,18 +66,18 @@ export class VideoCaptionAddModalComponent extends FormReactive implements OnIni
isReplacingExistingCaption () { isReplacingExistingCaption () {
if (this.closingModal === true) return false if (this.closingModal === true) return false
const languageId = this.form.value[ 'language' ] const languageId = this.form.value['language']
return languageId && this.existingCaptions.indexOf(languageId) !== -1 return languageId && this.existingCaptions.includes(languageId)
} }
async addCaption () { async addCaption () {
const languageId = this.form.value[ 'language' ] const languageId = this.form.value['language']
const languageObject = this.videoCaptionLanguages.find(l => l.id === languageId) const languageObject = this.videoCaptionLanguages.find(l => l.id === languageId)
this.captionAdded.emit({ this.captionAdded.emit({
language: languageObject, language: languageObject,
captionfile: this.form.value[ 'captionfile' ] captionfile: this.form.value['captionfile']
}) })
this.hide() this.hide()

View File

@ -24,7 +24,7 @@ function hydrateFormFromVideo (formGroup: FormGroup, video: VideoEdit, thumbnail
.then(response => response.blob()) .then(response => response.blob())
.then(data => { .then(data => {
formGroup.patchValue({ formGroup.patchValue({
[ obj.name ]: data [obj.name]: data
}) })
}) })
} }

View File

@ -233,7 +233,7 @@ export class VideoEditComponent implements OnInit, OnDestroy {
async deleteCaption (caption: VideoCaptionEdit) { async deleteCaption (caption: VideoCaptionEdit) {
// Caption recovers his former state // Caption recovers his former state
if (caption.action && this.initialVideoCaptions.indexOf(caption.language.id) !== -1) { if (caption.action && this.initialVideoCaptions.includes(caption.language.id)) {
caption.action = undefined caption.action = undefined
return return
} }
@ -297,7 +297,7 @@ export class VideoEditComponent implements OnInit, OnDestroy {
private trackPrivacyChange () { private trackPrivacyChange () {
// We will update the schedule input and the wait transcoding checkbox validators // We will update the schedule input and the wait transcoding checkbox validators
this.form.controls[ 'privacy' ] this.form.controls['privacy']
.valueChanges .valueChanges
.pipe(map(res => parseInt(res.toString(), 10))) .pipe(map(res => parseInt(res.toString(), 10)))
.subscribe( .subscribe(
@ -336,12 +336,12 @@ export class VideoEditComponent implements OnInit, OnDestroy {
private trackChannelChange () { private trackChannelChange () {
// We will update the "support" field depending on the channel // We will update the "support" field depending on the channel
this.form.controls[ 'channelId' ] this.form.controls['channelId']
.valueChanges .valueChanges
.pipe(map(res => parseInt(res.toString(), 10))) .pipe(map(res => parseInt(res.toString(), 10)))
.subscribe( .subscribe(
newChannelId => { newChannelId => {
const oldChannelId = parseInt(this.form.value[ 'channelId' ], 10) const oldChannelId = parseInt(this.form.value['channelId'], 10)
// Not initialized yet // Not initialized yet
if (isNaN(newChannelId)) return if (isNaN(newChannelId)) return
@ -350,7 +350,7 @@ export class VideoEditComponent implements OnInit, OnDestroy {
// Wait support field update // Wait support field update
setTimeout(() => { setTimeout(() => {
const currentSupport = this.form.value[ 'support' ] const currentSupport = this.form.value['support']
// First time we set the channel? // First time we set the channel?
if (isNaN(oldChannelId)) { if (isNaN(oldChannelId)) {

View File

@ -1,26 +1,26 @@
import { Directive, Output, EventEmitter, HostBinding, HostListener } from '@angular/core' import { Directive, Output, EventEmitter, HostBinding, HostListener } from '@angular/core'
@Directive({ @Directive({
selector: '[dragDrop]' selector: '[myDragDrop]'
}) })
export class DragDropDirective { export class DragDropDirective {
@Output() fileDropped = new EventEmitter<FileList>() @Output() fileDropped = new EventEmitter<FileList>()
@HostBinding('class.dragover') dragover = false @HostBinding('class.dragover') dragover = false
@HostListener('dragover', ['$event']) onDragOver (e: Event) { @HostListener('dragover', [ '$event' ]) onDragOver (e: Event) {
e.preventDefault() e.preventDefault()
e.stopPropagation() e.stopPropagation()
this.dragover = true this.dragover = true
} }
@HostListener('dragleave', ['$event']) public onDragLeave (e: Event) { @HostListener('dragleave', [ '$event' ]) public onDragLeave (e: Event) {
e.preventDefault() e.preventDefault()
e.stopPropagation() e.stopPropagation()
this.dragover = false this.dragover = false
} }
@HostListener('drop', ['$event']) public ondrop (e: DragEvent) { @HostListener('drop', [ '$event' ]) public ondrop (e: DragEvent) {
e.preventDefault() e.preventDefault()
e.stopPropagation() e.stopPropagation()
this.dragover = false this.dragover = false

View File

@ -1,4 +1,4 @@
<div *ngIf="!hasImportedVideo" class="upload-video-container" dragDrop (fileDropped)="setTorrentFile($event)"> <div *ngIf="!hasImportedVideo" class="upload-video-container" myDragDrop (fileDropped)="setTorrentFile($event)">
<div class="first-step-block"> <div class="first-step-block">
<my-global-icon class="upload-icon" iconName="upload" aria-hidden="true"></my-global-icon> <my-global-icon class="upload-icon" iconName="upload" aria-hidden="true"></my-global-icon>

View File

@ -5,7 +5,7 @@ import { scrollToTop } from '@app/helpers'
import { FormValidatorService } from '@app/shared/shared-forms' import { FormValidatorService } from '@app/shared/shared-forms'
import { VideoCaptionService, VideoEdit, VideoImportService, VideoService } from '@app/shared/shared-main' import { VideoCaptionService, VideoEdit, VideoImportService, VideoService } from '@app/shared/shared-main'
import { LoadingBarService } from '@ngx-loading-bar/core' import { LoadingBarService } from '@ngx-loading-bar/core'
import { PeerTubeProblemDocument, ServerErrorCode, VideoPrivacy, VideoUpdate } from '@shared/models' import { PeerTubeProblemDocument, ServerErrorCode, VideoUpdate } from '@shared/models'
import { hydrateFormFromVideo } from '../shared/video-edit-utils' import { hydrateFormFromVideo } from '../shared/video-edit-utils'
import { VideoSend } from './video-send' import { VideoSend } from './video-send'

View File

@ -59,7 +59,7 @@ export class VideoImportUrlComponent extends VideoSend implements OnInit, AfterV
} }
isTargetUrlValid () { isTargetUrlValid () {
return this.targetUrl && this.targetUrl.match(/https?:\/\//) return this.targetUrl?.match(/https?:\/\//)
} }
importVideo () { importVideo () {

View File

@ -9,7 +9,7 @@ import { LoadingBarService } from '@ngx-loading-bar/core'
import { HTMLServerConfig, VideoConstant, VideoPrivacy } from '@shared/models' import { HTMLServerConfig, VideoConstant, VideoPrivacy } from '@shared/models'
@Directive() @Directive()
// tslint:disable-next-line: directive-class-suffix // eslint-disable-next-line @angular-eslint/directive-class-suffix
export abstract class VideoSend extends FormReactive implements OnInit { export abstract class VideoSend extends FormReactive implements OnInit {
userVideoChannels: SelectChannelItem[] = [] userVideoChannels: SelectChannelItem[] = []
videoPrivacies: VideoConstant<VideoPrivacy>[] = [] videoPrivacies: VideoConstant<VideoPrivacy>[] = []

View File

@ -1,4 +1,4 @@
<div *ngIf="!isUploadingVideo" class="upload-video-container" dragDrop (fileDropped)="onFileDropped($event)"> <div *ngIf="!isUploadingVideo" class="upload-video-container" myDragDrop (fileDropped)="onFileDropped($event)">
<div class="first-step-block"> <div class="first-step-block">
<my-global-icon class="upload-icon" iconName="upload" aria-hidden="true"></my-global-icon> <my-global-icon class="upload-icon" iconName="upload" aria-hidden="true"></my-global-icon>

View File

@ -128,7 +128,7 @@ export class VideoUploadComponent extends VideoSend implements OnInit, OnDestroy
onUploadVideoOngoing (state: UploadState) { onUploadVideoOngoing (state: UploadState) {
switch (state.status) { switch (state.status) {
case 'error': case 'error': {
const error = state.response?.error || 'Unknow error' const error = state.response?.error || 'Unknow error'
this.handleUploadError({ this.handleUploadError({
@ -143,6 +143,7 @@ export class VideoUploadComponent extends VideoSend implements OnInit, OnDestroy
url: state.url url: state.url
}) })
break break
}
case 'cancelled': case 'cancelled':
this.isUploadingVideo = false this.isUploadingVideo = false
@ -323,6 +324,7 @@ export class VideoUploadComponent extends VideoSend implements OnInit, OnDestroy
const videoQuotaUsedBytes = bytePipes.transform(this.userVideoQuotaUsed, 0) const videoQuotaUsedBytes = bytePipes.transform(this.userVideoQuotaUsed, 0)
const videoQuotaBytes = bytePipes.transform(videoQuota, 0) const videoQuotaBytes = bytePipes.transform(videoQuota, 0)
// eslint-disable-next-line max-len
const msg = $localize`Your video quota is exceeded with this video (video size: ${videoSizeBytes}, used: ${videoQuotaUsedBytes}, quota: ${videoQuotaBytes})` const msg = $localize`Your video quota is exceeded with this video (video size: ${videoSizeBytes}, used: ${videoQuotaUsedBytes}, quota: ${videoQuotaBytes})`
this.notifier.error(msg) this.notifier.error(msg)
@ -341,6 +343,7 @@ export class VideoUploadComponent extends VideoSend implements OnInit, OnDestroy
const videoSizeBytes = bytePipes.transform(videofile.size, 0) const videoSizeBytes = bytePipes.transform(videofile.size, 0)
const quotaUsedDailyBytes = bytePipes.transform(this.userVideoQuotaUsedDaily, 0) const quotaUsedDailyBytes = bytePipes.transform(this.userVideoQuotaUsedDaily, 0)
const quotaDailyBytes = bytePipes.transform(videoQuotaDaily, 0) const quotaDailyBytes = bytePipes.transform(videoQuotaDaily, 0)
// eslint-disable-next-line max-len
const msg = $localize`Your daily video quota is exceeded with this video (video size: ${videoSizeBytes}, used: ${quotaUsedDailyBytes}, quota: ${quotaDailyBytes})` const msg = $localize`Your daily video quota is exceeded with this video (video size: ${videoSizeBytes}, used: ${quotaUsedDailyBytes}, quota: ${quotaDailyBytes})`
this.notifier.error(msg) this.notifier.error(msg)

View File

@ -119,8 +119,7 @@ export class VideoUpdateComponent extends FormReactive implements OnInit {
} }
update () { update () {
if (this.checkForm() === false if (this.checkForm() === false || this.isUpdatingVideo === true) {
|| this.isUpdatingVideo === true) {
return return
} }

View File

@ -18,7 +18,7 @@ export class VideoUpdateResolver implements Resolve<any> {
} }
resolve (route: ActivatedRouteSnapshot) { resolve (route: ActivatedRouteSnapshot) {
const uuid: string = route.params[ 'uuid' ] const uuid: string = route.params['uuid']
return this.videoService.getVideo({ videoId: uuid }) return this.videoService.getVideo({ videoId: uuid })
.pipe( .pipe(

View File

@ -8,7 +8,7 @@ import { Component, ViewEncapsulation } from '@angular/core'
selector: 'my-player-styles', selector: 'my-player-styles',
template: '', template: '',
styleUrls: [ './player-styles.component.scss' ], styleUrls: [ './player-styles.component.scss' ],
// tslint:disable:use-component-view-encapsulation /* eslint-disable @angular-eslint/use-component-view-encapsulation */
encapsulation: ViewEncapsulation.None encapsulation: ViewEncapsulation.None
}) })
export class PlayerStylesComponent { export class PlayerStylesComponent {

View File

@ -25,7 +25,7 @@ import { VideoCommentCreate } from '@shared/models'
@Component({ @Component({
selector: 'my-video-comment-add', selector: 'my-video-comment-add',
templateUrl: './video-comment-add.component.html', templateUrl: './video-comment-add.component.html',
styleUrls: ['./video-comment-add.component.scss'] styleUrls: [ './video-comment-add.component.scss' ]
}) })
export class VideoCommentAddComponent extends FormReactive implements OnChanges, OnInit { export class VideoCommentAddComponent extends FormReactive implements OnChanges, OnInit {
@Input() user: User @Input() user: User
@ -64,7 +64,7 @@ export class VideoCommentAddComponent extends FormReactive implements OnChanges,
for (const emojiMarkupName in emojiMarkupObjectList) { for (const emojiMarkupName in emojiMarkupObjectList) {
if (emojiMarkupName) { if (emojiMarkupName) {
const emoji = emojiMarkupObjectList[emojiMarkupName] const emoji = emojiMarkupObjectList[emojiMarkupName]
emojiMarkupArrayList.push([emoji, emojiMarkupName]) emojiMarkupArrayList.push([ emoji, emojiMarkupName ])
} }
} }
@ -91,7 +91,7 @@ export class VideoCommentAddComponent extends FormReactive implements OnChanges,
// Not initialized yet // Not initialized yet
if (!this.form) return if (!this.form) return
if (changes.textValue && changes.textValue.currentValue && changes.textValue.currentValue !== changes.textValue.previousValue) { if (changes.textValue?.currentValue && changes.textValue.currentValue !== changes.textValue.previousValue) {
this.patchTextValue(changes.textValue.currentValue, true) this.patchTextValue(changes.textValue.currentValue, true)
} }
} }

View File

@ -29,7 +29,7 @@
class="comment-html" class="comment-html"
[innerHTML]="sanitizedCommentHTML" [innerHTML]="sanitizedCommentHTML"
(timestampClicked)="handleTimestampClicked($event)" (timestampClicked)="handleTimestampClicked($event)"
timestampRouteTransformer myTimestampRouteTransformer
></div> ></div>
<div class="comment-actions"> <div class="comment-actions">

View File

@ -10,7 +10,7 @@ import { User, UserRight } from '@shared/models'
@Component({ @Component({
selector: 'my-video-comment', selector: 'my-video-comment',
templateUrl: './video-comment.component.html', templateUrl: './video-comment.component.html',
styleUrls: ['./video-comment.component.scss'] styleUrls: [ './video-comment.component.scss' ]
}) })
export class VideoCommentComponent implements OnInit, OnChanges { export class VideoCommentComponent implements OnInit, OnChanges {
@ViewChild('commentReportModal') commentReportModal: CommentReportComponent @ViewChild('commentReportModal') commentReportModal: CommentReportComponent

View File

@ -9,7 +9,7 @@ import { VideoComment, VideoCommentService, VideoCommentThreadTree } from '@app/
@Component({ @Component({
selector: 'my-video-comments', selector: 'my-video-comments',
templateUrl: './video-comments.component.html', templateUrl: './video-comments.component.html',
styleUrls: ['./video-comments.component.scss'] styleUrls: [ './video-comments.component.scss' ]
}) })
export class VideoCommentsComponent implements OnInit, OnChanges, OnDestroy { export class VideoCommentsComponent implements OnInit, OnChanges, OnDestroy {
@ViewChild('commentHighlightBlock') commentHighlightBlock: ElementRef @ViewChild('commentHighlightBlock') commentHighlightBlock: ElementRef
@ -200,7 +200,11 @@ export class VideoCommentsComponent implements OnInit, OnChanges, OnDestroy {
} }
async onWantedToRedraft (commentToRedraft: VideoComment) { async onWantedToRedraft (commentToRedraft: VideoComment) {
const confirm = await this.onWantedToDelete(commentToRedraft, $localize`Delete and re-draft`, $localize`Do you really want to delete and re-draft this comment?`) const confirm = await this.onWantedToDelete(
commentToRedraft,
$localize`Delete and re-draft`,
$localize`Do you really want to delete and re-draft this comment?`
)
if (confirm) { if (confirm) {
this.inReplyToCommentId = commentToRedraft.inReplyToCommentId this.inReplyToCommentId = commentToRedraft.inReplyToCommentId

View File

@ -23,7 +23,7 @@ export class VideoAlertComponent {
} }
hasVideoScheduledPublication () { hasVideoScheduledPublication () {
return this.video && this.video.scheduledUpdate !== undefined return this.video?.scheduledUpdate !== undefined
} }
isWaitingForLive () { isWaitingForLive () {

View File

@ -3,7 +3,7 @@
class="video-info-description-html" class="video-info-description-html"
[innerHTML]="videoHTMLDescription" [innerHTML]="videoHTMLDescription"
(timestampClicked)="onTimestampClicked($event)" (timestampClicked)="onTimestampClicked($event)"
timestampRouteTransformer myTimestampRouteTransformer
></div> ></div>
<div class="video-info-description-more" *ngIf="completeDescriptionShown === false && video.description?.length >= 250" (click)="showMoreDescription()"> <div class="video-info-description-more" *ngIf="completeDescriptionShown === false && video.description?.length >= 250" (click)="showMoreDescription()">

View File

@ -39,7 +39,7 @@ export class VideoWatchPlaylistComponent {
private notifier: Notifier, private notifier: Notifier,
private videoPlaylist: VideoPlaylistService, private videoPlaylist: VideoPlaylistService,
private localStorageService: LocalStorageService, private localStorageService: LocalStorageService,
private sessionStorageService: SessionStorageService, private sessionStorage: SessionStorageService,
private router: Router private router: Router
) { ) {
// defaults to true // defaults to true
@ -50,7 +50,7 @@ export class VideoWatchPlaylistComponent {
this.setAutoPlayNextVideoPlaylistSwitchText() this.setAutoPlayNextVideoPlaylistSwitchText()
// defaults to false // defaults to false
this.loopPlaylist = this.sessionStorageService.getItem(VideoWatchPlaylistComponent.SESSION_STORAGE_AUTO_PLAY_NEXT_VIDEO_PLAYLIST) === 'true' this.loopPlaylist = this.sessionStorage.getItem(VideoWatchPlaylistComponent.SESSION_STORAGE_AUTO_PLAY_NEXT_VIDEO_PLAYLIST) === 'true'
this.setLoopPlaylistSwitchText() this.setLoopPlaylistSwitchText()
} }
@ -145,7 +145,7 @@ export class VideoWatchPlaylistComponent {
const start = previous.startTimestamp const start = previous.startTimestamp
const stop = previous.stopTimestamp const stop = previous.stopTimestamp
this.router.navigate([],{ queryParams: { playlistPosition: previous.position, start, stop } }) this.router.navigate([], { queryParams: { playlistPosition: previous.position, start, stop } })
} }
findPlaylistVideo (position: number, type: 'previous' | 'next'): VideoPlaylistElement { findPlaylistVideo (position: number, type: 'previous' | 'next'): VideoPlaylistElement {
@ -163,7 +163,7 @@ export class VideoWatchPlaylistComponent {
} }
const found = this.playlistElements.find(e => e.position === position) const found = this.playlistElements.find(e => e.position === position)
if (found && found.video) return found if (found?.video) return found
const newPosition = type === 'previous' const newPosition = type === 'previous'
? position - 1 ? position - 1
@ -178,7 +178,7 @@ export class VideoWatchPlaylistComponent {
const start = next.startTimestamp const start = next.startTimestamp
const stop = next.stopTimestamp const stop = next.stopTimestamp
this.router.navigate([],{ queryParams: { playlistPosition: next.position, start, stop } }) this.router.navigate([], { queryParams: { playlistPosition: next.position, start, stop } })
} }
switchAutoPlayNextVideoPlaylist () { switchAutoPlayNextVideoPlaylist () {

View File

@ -20,7 +20,7 @@
> >
</my-video-miniature> </my-video-miniature>
<hr *ngIf="!playlist && i == 0 && length > 1" /> <hr *ngIf="!playlist && i === 0 && length > 1" />
</ng-container> </ng-container>
</ng-container> </ng-container>
</div> </div>

View File

@ -51,7 +51,7 @@ export class RecommendedVideosComponent implements OnInit, OnChanges {
} else { } else {
this.autoPlayNextVideo = this.sessionStorageService.getItem(UserLocalStorageKeys.SESSION_STORAGE_AUTO_PLAY_NEXT_VIDEO) === 'true' this.autoPlayNextVideo = this.sessionStorageService.getItem(UserLocalStorageKeys.SESSION_STORAGE_AUTO_PLAY_NEXT_VIDEO) === 'true'
this.sessionStorageService.watch([UserLocalStorageKeys.SESSION_STORAGE_AUTO_PLAY_NEXT_VIDEO]).subscribe( this.sessionStorageService.watch([ UserLocalStorageKeys.SESSION_STORAGE_AUTO_PLAY_NEXT_VIDEO ]).subscribe(
() => { () => {
this.autoPlayNextVideo = this.sessionStorageService.getItem(UserLocalStorageKeys.SESSION_STORAGE_AUTO_PLAY_NEXT_VIDEO) === 'true' this.autoPlayNextVideo = this.sessionStorageService.getItem(UserLocalStorageKeys.SESSION_STORAGE_AUTO_PLAY_NEXT_VIDEO) === 'true'
} }

View File

@ -1,12 +1,12 @@
import { Directive, EventEmitter, HostListener, Output } from '@angular/core' import { Directive, EventEmitter, HostListener, Output } from '@angular/core'
@Directive({ @Directive({
selector: '[timestampRouteTransformer]' selector: '[myTimestampRouteTransformer]'
}) })
export class TimestampRouteTransformerDirective { export class TimestampRouteTransformerDirective {
@Output() timestampClicked = new EventEmitter<number>() @Output() timestampClicked = new EventEmitter<number>()
@HostListener('click', ['$event']) @HostListener('click', [ '$event' ])
public onClick ($event: Event) { public onClick ($event: Event) {
const target = $event.target as HTMLLinkElement const target = $event.target as HTMLLinkElement
@ -21,10 +21,10 @@ export class TimestampRouteTransformerDirective {
const ngxLinkParams = new URLSearchParams(ngxLink.search) const ngxLinkParams = new URLSearchParams(ngxLink.search)
if (ngxLinkParams.has('start') !== true) return if (ngxLinkParams.has('start') !== true) return
const separators = ['h', 'm', 's'] const separators = [ 'h', 'm', 's' ]
const start = ngxLinkParams const start = ngxLinkParams
.get('start') .get('start')
.match(new RegExp('(\\d{1,9}[' + separators.join('') + '])','g')) // match digits before any given separator .match(new RegExp('(\\d{1,9}[' + separators.join('') + '])', 'g')) // match digits before any given separator
.map(t => { .map(t => {
if (t.includes('h')) return parseInt(t, 10) * 3600 if (t.includes('h')) return parseInt(t, 10) * 3600
if (t.includes('m')) return parseInt(t, 10) * 60 if (t.includes('m')) return parseInt(t, 10) * 60

View File

@ -195,10 +195,10 @@ export class VideoWatchComponent implements OnInit, OnDestroy {
private loadRouteParams () { private loadRouteParams () {
this.paramsSub = this.route.params.subscribe(routeParams => { this.paramsSub = this.route.params.subscribe(routeParams => {
const videoId = routeParams[ 'videoId' ] const videoId = routeParams['videoId']
if (videoId) return this.loadVideo(videoId) if (videoId) return this.loadVideo(videoId)
const playlistId = routeParams[ 'playlistId' ] const playlistId = routeParams['playlistId']
if (playlistId) return this.loadPlaylist(playlistId) if (playlistId) return this.loadPlaylist(playlistId)
}) })
} }
@ -206,7 +206,7 @@ export class VideoWatchComponent implements OnInit, OnDestroy {
private loadRouteQuery () { private loadRouteQuery () {
this.queryParamsSub = this.route.queryParams.subscribe(queryParams => { this.queryParamsSub = this.route.queryParams.subscribe(queryParams => {
// Handle the ?playlistPosition // Handle the ?playlistPosition
const positionParam = queryParams[ 'playlistPosition' ] ?? 1 const positionParam = queryParams['playlistPosition'] ?? 1
this.playlistPosition = positionParam === 'last' this.playlistPosition = positionParam === 'last'
? -1 // Handle the "last" index ? -1 // Handle the "last" index
@ -219,7 +219,7 @@ export class VideoWatchComponent implements OnInit, OnDestroy {
this.videoWatchPlaylist.updatePlaylistIndex(this.playlistPosition) this.videoWatchPlaylist.updatePlaylistIndex(this.playlistPosition)
const start = queryParams[ 'start' ] const start = queryParams['start']
if (this.player && start) this.player.currentTime(parseInt(start, 10)) if (this.player && start) this.player.currentTime(parseInt(start, 10))
}) })
} }
@ -237,7 +237,7 @@ export class VideoWatchComponent implements OnInit, OnDestroy {
'filter:api.video-watch.video.get.result' 'filter:api.video-watch.video.get.result'
) )
forkJoin([ videoObs, this.videoCaptionService.listCaptions(videoId)]) forkJoin([ videoObs, this.videoCaptionService.listCaptions(videoId) ])
.subscribe({ .subscribe({
next: ([ video, captionsResult ]) => { next: ([ video, captionsResult ]) => {
const queryParams = this.route.snapshot.queryParams const queryParams = this.route.snapshot.queryParams
@ -292,6 +292,7 @@ export class VideoWatchComponent implements OnInit, OnDestroy {
const originUrl = errorBody.originUrl + (window.location.search ?? '') const originUrl = errorBody.originUrl + (window.location.search ?? '')
const res = await this.confirmService.confirm( const res = await this.confirmService.confirm(
// eslint-disable-next-line max-len
$localize`This video is not available on this instance. Do you want to be redirected on the origin instance: <a href="${originUrl}">${originUrl}</a>?`, $localize`This video is not available on this instance. Do you want to be redirected on the origin instance: <a href="${originUrl}">${originUrl}</a>?`,
$localize`Redirection` $localize`Redirection`
) )
@ -312,7 +313,7 @@ export class VideoWatchComponent implements OnInit, OnDestroy {
if (!errorMessage) return if (!errorMessage) return
// Display a message in the video player instead of a notification // Display a message in the video player instead of a notification
if (errorMessage.indexOf('from xs param') !== -1) { if (errorMessage.includes('from xs param')) {
this.flushPlayer() this.flushPlayer()
this.remoteServerDown = true this.remoteServerDown = true
@ -466,7 +467,6 @@ export class VideoWatchComponent implements OnInit, OnDestroy {
if (this.nextVideoUUID) { if (this.nextVideoUUID) {
this.router.navigate([ '/w', this.nextVideoUUID ]) this.router.navigate([ '/w', this.nextVideoUUID ])
return
} }
} }
@ -483,14 +483,14 @@ export class VideoWatchComponent implements OnInit, OnDestroy {
private isAutoPlayNext () { private isAutoPlayNext () {
return ( return (
(this.user && this.user.autoPlayNextVideo) || (this.user?.autoPlayNextVideo) ||
this.anonymousUser.autoPlayNextVideo this.anonymousUser.autoPlayNextVideo
) )
} }
private isPlaylistAutoPlayNext () { private isPlaylistAutoPlayNext () {
return ( return (
(this.user && this.user.autoPlayNextVideoPlaylist) || (this.user?.autoPlayNextVideoPlaylist) ||
this.anonymousUser.autoPlayNextVideoPlaylist this.anonymousUser.autoPlayNextVideoPlaylist
) )
} }
@ -508,9 +508,9 @@ export class VideoWatchComponent implements OnInit, OnDestroy {
} }
private buildPlayerManagerOptions (params: { private buildPlayerManagerOptions (params: {
video: VideoDetails, video: VideoDetails
videoCaptions: VideoCaption[], videoCaptions: VideoCaption[]
urlOptions: CustomizationOptions & { playerMode: PlayerMode }, urlOptions: CustomizationOptions & { playerMode: PlayerMode }
user?: AuthUser user?: AuthUser
}) { }) {
const { video, videoCaptions, urlOptions, user } = params const { video, videoCaptions, urlOptions, user } = params
@ -573,10 +573,12 @@ export class VideoWatchComponent implements OnInit, OnDestroy {
language: this.localeId, language: this.localeId,
userWatching: user && user.videosHistoryEnabled === true ? { userWatching: user && user.videosHistoryEnabled === true
? {
url: this.videoService.getUserWatchingVideoUrl(video.uuid), url: this.videoService.getUserWatchingVideoUrl(video.uuid),
authorizationHeader: this.authService.getRequestHeaderValue() authorizationHeader: this.authService.getRequestHeaderValue()
} : undefined, }
: undefined,
serverUrl: environment.apiUrl, serverUrl: environment.apiUrl,
@ -704,9 +706,8 @@ export class VideoWatchComponent implements OnInit, OnDestroy {
if (this.isUserLoggedIn()) { if (this.isUserLoggedIn()) {
this.hotkeys = this.hotkeys.concat([ this.hotkeys = this.hotkeys.concat([
new Hotkey('shift+s', () => { new Hotkey('shift+s', () => {
this.subscribeButton.isSubscribedToAll() if (this.subscribeButton.isSubscribedToAll()) this.subscribeButton.unsubscribe()
? this.subscribeButton.unsubscribe() else this.subscribeButton.subscribe()
: this.subscribeButton.subscribe()
return false return false
}, undefined, $localize`Subscribe to the account`) }, undefined, $localize`Subscribe to the account`)

View File

@ -43,7 +43,7 @@ export class OverviewService {
// Build videos objects // Build videos objects
for (const key of Object.keys(serverVideosOverview)) { for (const key of Object.keys(serverVideosOverview)) {
for (const object of serverVideosOverview[ key ]) { for (const object of serverVideosOverview[key]) {
observables.push( observables.push(
of(object.videos) of(object.videos)
.pipe( .pipe(

View File

@ -15,7 +15,7 @@ interface VideoTrendingHeaderItem {
} }
@Component({ @Component({
selector: 'video-trending-title-page', selector: 'my-video-trending-title-page',
styleUrls: [ './video-trending-header.component.scss' ], styleUrls: [ './video-trending-header.component.scss' ],
templateUrl: './video-trending-header.component.html' templateUrl: './video-trending-header.component.html'
}) })

View File

@ -97,12 +97,12 @@ export class VideoTrendingComponent extends AbstractVideoList implements OnInit,
getInjector () { getInjector () {
return Injector.create({ return Injector.create({
providers: [{ providers: [ {
provide: 'data', provide: 'data',
useValue: { useValue: {
model: this.defaultSort model: this.defaultSort
} }
}] } ]
}) })
} }

View File

@ -5,7 +5,7 @@ import { HooksService } from '@app/core/plugins/hooks.service'
import { immutableAssign } from '@app/helpers' import { immutableAssign } from '@app/helpers'
import { VideoService } from '@app/shared/shared-main' import { VideoService } from '@app/shared/shared-main'
import { AbstractVideoList } from '@app/shared/shared-video-miniature' import { AbstractVideoList } from '@app/shared/shared-video-miniature'
import { UserRight, VideoFilter, VideoSortField } from '@shared/models' import { VideoFilter, VideoSortField } from '@shared/models'
@Component({ @Component({
selector: 'my-videos-local', selector: 'my-videos-local',

View File

@ -243,7 +243,7 @@ export class AppComponent implements OnInit, AfterViewInit {
// Inject JS // Inject JS
if (this.serverConfig.instance.customizations.javascript) { if (this.serverConfig.instance.customizations.javascript) {
try { try {
// tslint:disable:no-eval /* eslint-disable no-eval */
eval(this.serverConfig.instance.customizations.javascript) eval(this.serverConfig.instance.customizations.javascript)
} catch (err) { } catch (err) {
console.error('Cannot eval custom JavaScript.', err) console.error('Cannot eval custom JavaScript.', err)
@ -294,7 +294,7 @@ export class AppComponent implements OnInit, AfterViewInit {
private initHotkeys () { private initHotkeys () {
this.hotkeysService.add([ this.hotkeysService.add([
new Hotkey(['/', 's'], (event: KeyboardEvent): boolean => { new Hotkey([ '/', 's' ], (event: KeyboardEvent): boolean => {
document.getElementById('search-video').focus() document.getElementById('search-video').focus()
return false return false
}, undefined, $localize`Focus the search bar`), }, undefined, $localize`Focus the search bar`),

View File

@ -206,7 +206,9 @@ Ensure you have correctly configured PeerTube (config/ directory), in particular
this.refreshingTokenObservable = this.http.post<UserRefreshToken>(AuthService.BASE_TOKEN_URL, body, { headers }) this.refreshingTokenObservable = this.http.post<UserRefreshToken>(AuthService.BASE_TOKEN_URL, body, { headers })
.pipe( .pipe(
map(res => this.handleRefreshToken(res)), map(res => this.handleRefreshToken(res)),
tap(() => { this.refreshingTokenObservable = null }), tap(() => {
this.refreshingTokenObservable = null
}),
catchError(err => { catchError(err => {
this.refreshingTokenObservable = null this.refreshingTokenObservable = null

View File

@ -3,8 +3,8 @@ import { Subscription } from 'rxjs'
import { Component, Input, OnDestroy, OnInit } from '@angular/core' import { Component, Input, OnDestroy, OnInit } from '@angular/core'
@Component({ @Component({
selector : 'my-hotkeys-cheatsheet', selector: 'my-hotkeys-cheatsheet',
templateUrl : './hotkeys.component.html', templateUrl: './hotkeys.component.html',
styleUrls: [ './hotkeys.component.scss' ] styleUrls: [ './hotkeys.component.scss' ]
}) })
export class CheatSheetComponent implements OnInit, OnDestroy { export class CheatSheetComponent implements OnInit, OnDestroy {

View File

@ -55,7 +55,7 @@ export class MenuService {
// On touch screens, lock body scroll and display content overlay when memu is opened // On touch screens, lock body scroll and display content overlay when memu is opened
if (this.isMenuDisplayed) { if (this.isMenuDisplayed) {
document.body.classList.add('menu-open') document.body.classList.add('menu-open')
this.screenService.onFingerSwipe('left', () => { this.setMenuDisplay(false) }) this.screenService.onFingerSwipe('left', () => this.setMenuDisplay(false))
return return
} }

View File

@ -27,8 +27,7 @@ export class HooksService {
}) })
} }
wrapObsFun wrapObsFun <P, R, H1 extends ClientFilterHookName, H2 extends ClientFilterHookName>
<P, R, H1 extends ClientFilterHookName, H2 extends ClientFilterHookName>
(fun: ObservableFunction<P, R>, params: P, scope: PluginClientScope, hookParamName: H1, hookResultName: H2) { (fun: ObservableFunction<P, R>, params: P, scope: PluginClientScope, hookParamName: H1, hookResultName: H2) {
return from(this.pluginService.ensurePluginsAreLoaded(scope)) return from(this.pluginService.ensurePluginsAreLoaded(scope))
.pipe( .pipe(
@ -38,8 +37,7 @@ export class HooksService {
) )
} }
async wrapFun async wrapFun <P, R, H1 extends ClientFilterHookName, H2 extends ClientFilterHookName>
<P, R, H1 extends ClientFilterHookName, H2 extends ClientFilterHookName>
(fun: RawFunction<P, R>, params: P, scope: PluginClientScope, hookParamName: H1, hookResultName: H2) { (fun: RawFunction<P, R>, params: P, scope: PluginClientScope, hookParamName: H1, hookResultName: H2) {
await this.pluginService.ensurePluginsAreLoaded(scope) await this.pluginService.ensurePluginsAreLoaded(scope)

View File

@ -188,7 +188,7 @@ export class PluginService implements ClientHook {
if (!this.authService.isLoggedIn()) return undefined if (!this.authService.isLoggedIn()) return undefined
const value = this.authService.getRequestHeaderValue() const value = this.authService.getRequestHeaderValue()
return { 'Authorization': value } return { Authorization: value }
}, },
notifier: { notifier: {
@ -198,10 +198,10 @@ export class PluginService implements ClientHook {
}, },
showModal: (input: { showModal: (input: {
title: string, title: string
content: string, content: string
close?: boolean, close?: boolean
cancel?: { value: string, action?: () => void }, cancel?: { value: string, action?: () => void }
confirm?: { value: string, action?: () => void } confirm?: { value: string, action?: () => void }
}) => { }) => {
this.zone.run(() => this.customModal.show(input)) this.zone.run(() => this.customModal.show(input))

View File

@ -103,20 +103,20 @@ export class MarkdownService {
const { name, markdown, withEmoji, additionalAllowedTags } = options const { name, markdown, withEmoji, additionalAllowedTags } = options
if (!markdown) return '' if (!markdown) return ''
const config = this.parsersConfig[ name ] const config = this.parsersConfig[name]
if (!this.markdownParsers[ name ]) { if (!this.markdownParsers[name]) {
this.markdownParsers[ name ] = await this.createMarkdownIt(config) this.markdownParsers[name] = await this.createMarkdownIt(config)
if (withEmoji) { if (withEmoji) {
if (!this.emojiModule) { if (!this.emojiModule) {
this.emojiModule = (await import('markdown-it-emoji/light')).default this.emojiModule = (await import('markdown-it-emoji/light')).default
} }
this.markdownParsers[ name ].use(this.emojiModule) this.markdownParsers[name].use(this.emojiModule)
} }
} }
let html = this.markdownParsers[ name ].render(markdown) let html = this.markdownParsers[name].render(markdown)
html = this.avoidTruncatedTags(html) html = this.avoidTruncatedTags(html)
if (config.escape) return this.htmlRenderer.toSafeHtml(html, additionalAllowedTags) if (config.escape) return this.htmlRenderer.toSafeHtml(html, additionalAllowedTags)
@ -156,7 +156,7 @@ export class MarkdownService {
if (relIndex < 0) token.attrPush([ 'rel', 'noopener noreferrer' ]) if (relIndex < 0) token.attrPush([ 'rel', 'noopener noreferrer' ])
else token.attrs[relIndex][1] = 'noopener noreferrer' else token.attrs[relIndex][1] = 'noopener noreferrer'
// pass token to default renderer. // pass token to default renderer.*
return defaultRender(tokens, index, options, env, self) return defaultRender(tokens, index, options, env, self)
} }
} }
@ -164,7 +164,7 @@ export class MarkdownService {
private avoidTruncatedTags (html: string) { private avoidTruncatedTags (html: string) {
return html.replace(/\*\*?([^*]+)$/, '$1') return html.replace(/\*\*?([^*]+)$/, '$1')
.replace(/<a[^>]+>([^<]+)<\/a>\s*...((<\/p>)|(<\/li>)|(<\/strong>))?$/mi, '$1...') .replace(/<a[^>]+>([^<]+)<\/a>\s*...((<\/p>)|(<\/li>)|(<\/strong>))?$/mi, '$1...')
.replace(/\[[^\]]+\]\(([^\)]+)$/m, '$1') .replace(/\[[^\]]+\]\(([^)]+)$/m, '$1')
.replace(/\s?\[[^\]]+\]?[.]{3}<\/p>$/m, '...</p>') .replace(/\s?\[[^\]]+\]?[.]{3}<\/p>$/m, '...</p>')
} }
} }

View File

@ -13,15 +13,16 @@ export class RestExtractor {
return true return true
} }
applyToResultListData <T> (result: ResultList<T>, fun: Function, additionalArgs?: any[]): ResultList<T> { applyToResultListData <T, A, U> (
result: ResultList<T>,
fun: (data: T, ...args: A[]) => U,
additionalArgs: A[] = []
): ResultList<U> {
const data: T[] = result.data const data: T[] = result.data
const newData: T[] = []
data.forEach(d => newData.push(fun.apply(this, [ d ].concat(additionalArgs))))
return { return {
total: result.total, total: result.total,
data: newData data: data.map(d => fun.apply(this, [ d, ...additionalArgs ]))
} }
} }
@ -29,8 +30,10 @@ export class RestExtractor {
return this.applyToResultListData(result, this.convertDateToHuman, [ fieldsToConvert ]) return this.applyToResultListData(result, this.convertDateToHuman, [ fieldsToConvert ])
} }
convertDateToHuman (target: { [ id: string ]: string }, fieldsToConvert: string[]) { convertDateToHuman (target: any, fieldsToConvert: string[]) {
fieldsToConvert.forEach(field => target[field] = dateToHuman(target[field])) fieldsToConvert.forEach(field => {
target[field] = dateToHuman(target[field])
})
return target return target
} }
@ -46,7 +49,7 @@ export class RestExtractor {
errorMessage = err.error errorMessage = err.error
} else if (err.status !== undefined) { } else if (err.status !== undefined) {
// A server-side error occurred. // A server-side error occurred.
if (err.error && err.error.errors) { if (err.error?.errors) {
const errors = err.error.errors const errors = err.error.errors
const errorsArray: string[] = [] const errorsArray: string[] = []
@ -55,9 +58,10 @@ export class RestExtractor {
}) })
errorMessage = errorsArray.join('. ') errorMessage = errorsArray.join('. ')
} else if (err.error && err.error.error) { } else if (err.error?.error) {
errorMessage = err.error.error errorMessage = err.error.error
} else if (err.status === HttpStatusCode.PAYLOAD_TOO_LARGE_413) { } else if (err.status === HttpStatusCode.PAYLOAD_TOO_LARGE_413) {
// eslint-disable-next-line max-len
errorMessage = $localize`Media is too large for the server. Please contact you administrator if you want to increase the limit size.` errorMessage = $localize`Media is too large for the server. Please contact you administrator if you want to increase the limit size.`
} else if (err.status === HttpStatusCode.TOO_MANY_REQUESTS_429) { } else if (err.status === HttpStatusCode.TOO_MANY_REQUESTS_429) {
const secondsLeft = err.headers.get('retry-after') const secondsLeft = err.headers.get('retry-after')
@ -71,7 +75,7 @@ export class RestExtractor {
errorMessage = $localize`Server error. Please retry later.` errorMessage = $localize`Server error. Please retry later.`
} }
errorMessage = errorMessage ? errorMessage : 'Unknown error.' errorMessage = errorMessage || 'Unknown error.'
console.error(`Backend returned code ${err.status}, errorMessage is: ${errorMessage}`) console.error(`Backend returned code ${err.status}, errorMessage is: ${errorMessage}`)
} else { } else {
console.error(err) console.error(err)
@ -93,7 +97,7 @@ export class RestExtractor {
} }
redirectTo404IfNotFound (obj: { status: number }, type: 'video' | 'other', status = [ HttpStatusCode.NOT_FOUND_404 ]) { redirectTo404IfNotFound (obj: { status: number }, type: 'video' | 'other', status = [ HttpStatusCode.NOT_FOUND_404 ]) {
if (obj && obj.status && status.indexOf(obj.status) !== -1) { if (obj?.status && status.includes(obj.status)) {
// Do not use redirectService to avoid circular dependencies // Do not use redirectService to avoid circular dependencies
this.router.navigate([ '/404' ], { state: { type, obj }, skipLocationChange: true }) this.router.navigate([ '/404' ], { state: { type, obj }, skipLocationChange: true })
} }

View File

@ -1,5 +1,5 @@
import { ActivatedRouteSnapshot, DetachedRouteHandle, RouteReuseStrategy } from '@angular/router'
import { Injectable } from '@angular/core' import { Injectable } from '@angular/core'
import { ActivatedRouteSnapshot, DetachedRouteHandle, RouteReuseStrategy } from '@angular/router'
@Injectable() @Injectable()
export class CustomReuseStrategy implements RouteReuseStrategy { export class CustomReuseStrategy implements RouteReuseStrategy {
@ -78,6 +78,6 @@ export class CustomReuseStrategy implements RouteReuseStrategy {
} }
private isReuseEnabled (route: ActivatedRouteSnapshot) { private isReuseEnabled (route: ActivatedRouteSnapshot) {
return route.data.reuse && route.data.reuse.enabled && route.queryParams[ 'a-state' ] return route.data.reuse?.enabled && route.queryParams['a-state']
} }
} }

View File

@ -17,33 +17,43 @@ abstract class MenuGuard implements CanActivate, CanDeactivate<any> {
if (!this.screen.isInMobileView() && this.screen.isInMediumView()) { if (!this.screen.isInMobileView() && this.screen.isInMediumView()) {
this.menu.setMenuDisplay(this.display) this.menu.setMenuDisplay(this.display)
} }
return true return true
} }
} }
@Injectable() @Injectable()
export class OpenMenuGuard extends MenuGuard { export class OpenMenuGuard extends MenuGuard {
constructor (menu: MenuService, screen: ScreenService) { super(menu, screen, true) } constructor (menu: MenuService, screen: ScreenService) {
super(menu, screen, true)
}
} }
@Injectable() @Injectable()
export class OpenMenuAlwaysGuard extends MenuGuard { export class OpenMenuAlwaysGuard extends MenuGuard {
constructor (menu: MenuService, screen: ScreenService) { super(menu, screen, true) } constructor (menu: MenuService, screen: ScreenService) {
super(menu, screen, true)
}
canActivate (): boolean { canActivate (): boolean {
this.menu.setMenuDisplay(this.display) this.menu.setMenuDisplay(this.display)
return true return true
} }
} }
@Injectable() @Injectable()
export class CloseMenuGuard extends MenuGuard { export class CloseMenuGuard extends MenuGuard {
constructor (menu: MenuService, screen: ScreenService) { super(menu, screen, false) } constructor (menu: MenuService, screen: ScreenService) {
super(menu, screen, false)
}
} }
@Injectable() @Injectable()
export class CloseMenuAlwaysGuard extends MenuGuard { export class CloseMenuAlwaysGuard extends MenuGuard {
constructor (menu: MenuService, screen: ScreenService) { super(menu, screen, false) } constructor (menu: MenuService, screen: ScreenService) {
super(menu, screen, false)
}
canActivate (): boolean { canActivate (): boolean {
this.menu.setMenuDisplay(this.display) this.menu.setMenuDisplay(this.display)

View File

@ -1,5 +1,5 @@
import { Injectable } from '@angular/core' import { Injectable } from '@angular/core'
import { ActivatedRouteSnapshot, CanActivate, CanActivateChild, RouterStateSnapshot } from '@angular/router' import { ActivatedRouteSnapshot, CanActivate, CanActivateChild } from '@angular/router'
import { MetaService } from './meta.service' import { MetaService } from './meta.service'
@Injectable() @Injectable()

View File

@ -6,7 +6,7 @@ import { Injectable } from '@angular/core'
@Injectable() @Injectable()
export class PreloadSelectedModulesList implements PreloadingStrategy { export class PreloadSelectedModulesList implements PreloadingStrategy {
preload (route: Route, load: Function): Observable<any> { preload (route: Route, load: () => Observable<any>): Observable<any> {
if (!route.data || !route.data.preload) return ofObservable(null) if (!route.data || !route.data.preload) return ofObservable(null)
if (typeof route.data.preload === 'number') { if (typeof route.data.preload === 'number') {

View File

@ -1,9 +1,8 @@
import { Injectable } from '@angular/core'
import { HttpClient } from '@angular/common/http'
import { environment } from '../../../environments/environment'
import { AuthService } from '../auth'
import { ScopedToken } from '@shared/models/users/user-scoped-token'
import { catchError } from 'rxjs/operators' import { catchError } from 'rxjs/operators'
import { HttpClient } from '@angular/common/http'
import { Injectable } from '@angular/core'
import { ScopedToken } from '@shared/models/users/user-scoped-token'
import { environment } from '../../../environments/environment'
import { RestExtractor } from '../rest' import { RestExtractor } from '../rest'
@Injectable() @Injectable()

View File

@ -4,7 +4,7 @@ import { HttpClient } from '@angular/common/http'
import { Inject, Injectable, LOCALE_ID } from '@angular/core' import { Inject, Injectable, LOCALE_ID } from '@angular/core'
import { getDevLocale, isOnDevLocale, sortBy } from '@app/helpers' import { getDevLocale, isOnDevLocale, sortBy } from '@app/helpers'
import { getCompleteLocale, isDefaultLocale, peertubeTranslate } from '@shared/core-utils/i18n' import { getCompleteLocale, isDefaultLocale, peertubeTranslate } from '@shared/core-utils/i18n'
import { HTMLServerConfig, SearchTargetType, ServerConfig, ServerStats, VideoConstant } from '@shared/models' import { HTMLServerConfig, ServerConfig, ServerStats, VideoConstant } from '@shared/models'
import { environment } from '../../../environments/environment' import { environment } from '../../../environments/environment'
@Injectable() @Injectable()
@ -171,7 +171,7 @@ export class ServerService {
map(({ data, translations }) => { map(({ data, translations }) => {
const hashToPopulate: VideoConstant<T>[] = Object.keys(data) const hashToPopulate: VideoConstant<T>[] = Object.keys(data)
.map(dataKey => { .map(dataKey => {
const label = data[ dataKey ] const label = data[dataKey]
const id = attributeName === 'languages' const id = attributeName === 'languages'
? dataKey as T ? dataKey as T

View File

@ -95,8 +95,8 @@ export class ThemeService {
private loadTheme (name: string) { private loadTheme (name: string) {
const links = document.getElementsByTagName('link') const links = document.getElementsByTagName('link')
for (let i = 0; i < links.length; i++) { for (let i = 0; i < links.length; i++) {
const link = links[ i ] const link = links[i]
if (link.getAttribute('rel').indexOf('style') !== -1 && link.getAttribute('title')) { if (link.getAttribute('rel').includes('style') && link.getAttribute('title')) {
link.disabled = link.getAttribute('title') !== name link.disabled = link.getAttribute('title') !== name
} }
} }

View File

@ -266,7 +266,7 @@ export class UserService {
getUserWithCache (userId: number) { getUserWithCache (userId: number) {
if (!this.userCache[userId]) { if (!this.userCache[userId]) {
this.userCache[ userId ] = this.getUser(userId).pipe(shareReplay()) this.userCache[userId] = this.getUser(userId).pipe(shareReplay())
} }
return this.userCache[userId] return this.userCache[userId]

View File

@ -199,7 +199,7 @@ export class SearchTypeaheadComponent implements OnInit, AfterViewChecked, OnDes
} }
private loadUserLanguagesIfNeeded (queryParams: any) { private loadUserLanguagesIfNeeded (queryParams: any) {
if (queryParams && queryParams.languageOneOf) return of(queryParams) if (queryParams?.languageOneOf) return of(queryParams)
return this.authService.userInformationLoaded return this.authService.userInformationLoaded
.pipe( .pipe(

View File

@ -12,16 +12,16 @@ function plural (n: number): number {
export default [ export default [
'oc', 'oc',
[['a. m.', 'p. m.'], u, u], [ [ 'a. m.', 'p. m.' ], u, u ],
u, u,
[ [
['dg', 'dl', 'dm', 'dc', 'dj', 'dv', 'ds'], ['dg.', 'dl.', 'dm.', 'dc.', 'dj.', 'dv.', 'ds.'], [ 'dg', 'dl', 'dm', 'dc', 'dj', 'dv', 'ds' ], [ 'dg.', 'dl.', 'dm.', 'dc.', 'dj.', 'dv.', 'ds.' ],
['dimenge', 'diluns', 'dimars', 'dimècres', 'dijòus', 'divendres', 'dissabte'], [ 'dimenge', 'diluns', 'dimars', 'dimècres', 'dijòus', 'divendres', 'dissabte' ],
['dg.', 'dl.', 'dm.', 'dc.', 'dj.', 'dv.', 'ds.'] [ 'dg.', 'dl.', 'dm.', 'dc.', 'dj.', 'dv.', 'ds.' ]
], ],
u, u,
[ [
['GN', 'FB', 'MÇ', 'AB', 'MA', 'JN', 'JL', 'AG', 'ST', 'OC', 'NV', 'DC'], [ 'GN', 'FB', 'MÇ', 'AB', 'MA', 'JN', 'JL', 'AG', 'ST', 'OC', 'NV', 'DC' ],
[ [
'de gen.', 'de febr.', 'de març', 'dabr.', 'de mai', 'de junh', 'de jul.', 'dag.', 'de gen.', 'de febr.', 'de març', 'dabr.', 'de mai', 'de junh', 'de jul.', 'dag.',
'de set.', 'doct.', 'de nov.', 'de dec.' 'de set.', 'doct.', 'de nov.', 'de dec.'
@ -32,7 +32,7 @@ export default [
] ]
], ],
[ [
['GN', 'FB', 'MÇ', 'AB', 'MA', 'JN', 'JL', 'AG', 'ST', 'OC', 'NV', 'DC'], [ 'GN', 'FB', 'MÇ', 'AB', 'MA', 'JN', 'JL', 'AG', 'ST', 'OC', 'NV', 'DC' ],
[ [
'gen.', 'febr.', 'març', 'abr.', 'mai', 'junh', 'jul.', 'ag.', 'set.', 'oct.', 'nov.', 'gen.', 'febr.', 'març', 'abr.', 'mai', 'junh', 'jul.', 'ag.', 'set.', 'oct.', 'nov.',
'dec.' 'dec.'
@ -42,62 +42,62 @@ export default [
'novembre', 'decembre' 'novembre', 'decembre'
] ]
], ],
[['aC', 'dC'], u, ['abans Jèsus-Crist', 'aprèp Jèsus-Crist']], [ [ 'aC', 'dC' ], u, [ 'abans Jèsus-Crist', 'aprèp Jèsus-Crist' ] ],
1, 1,
[6, 0], [ 6, 0 ],
['d/M/yy', 'd MMM y', 'd MMMM \'de\' y', 'EEEE, d MMMM \'de\' y'], [ 'd/M/yy', 'd MMM y', 'd MMMM \'de\' y', 'EEEE, d MMMM \'de\' y' ],
['H:mm', 'H:mm:ss', 'H:mm:ss z', 'H:mm:ss zzzz'], [ 'H:mm', 'H:mm:ss', 'H:mm:ss z', 'H:mm:ss zzzz' ],
['{1} {0}', '{1}, {0}', '{1} \'a\' \'les\' {0}', u], [ '{1} {0}', '{1}, {0}', '{1} \'a\' \'les\' {0}', u ],
[',', '.', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], [ ',', '.', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':' ],
['#,##0.###', '#,##0%', '#,##0.00 ¤', '#E0'], [ '#,##0.###', '#,##0%', '#,##0.00 ¤', '#E0' ],
'EUR', 'EUR',
'€', '€',
'euro', 'euro',
{ {
'ARS': ['$AR', '$'], ARS: [ '$AR', '$' ],
'AUD': ['$AU', '$'], AUD: [ '$AU', '$' ],
'BEF': ['FB'], BEF: [ 'FB' ],
'BMD': ['$BM', '$'], BMD: [ '$BM', '$' ],
'BND': ['$BN', '$'], BND: [ '$BN', '$' ],
'BZD': ['$BZ', '$'], BZD: [ '$BZ', '$' ],
'CAD': ['$CA', '$'], CAD: [ '$CA', '$' ],
'CLP': ['$CL', '$'], CLP: [ '$CL', '$' ],
'CNY': [u, '¥'], CNY: [ u, '¥' ],
'COP': ['$CO', '$'], COP: [ '$CO', '$' ],
'CYP': ['£CY'], CYP: [ '£CY' ],
'EGP': [u, '£E'], EGP: [ u, '£E' ],
'FJD': ['$FJ', '$'], FJD: [ '$FJ', '$' ],
'FKP': ['£FK', '£'], FKP: [ '£FK', '£' ],
'FRF': ['F'], FRF: [ 'F' ],
'GBP': ['£GB', '£'], GBP: [ '£GB', '£' ],
'GIP': ['£GI', '£'], GIP: [ '£GI', '£' ],
'HKD': [u, '$'], HKD: [ u, '$' ],
'IEP': ['£IE'], IEP: [ '£IE' ],
'ILP': ['£IL'], ILP: [ '£IL' ],
'ITL': ['₤IT'], ITL: [ '₤IT' ],
'JPY': [u, '¥'], JPY: [ u, '¥' ],
'KMF': [u, 'FC'], KMF: [ u, 'FC' ],
'LBP': ['£LB', '£L'], LBP: [ '£LB', '£L' ],
'MTP': ['£MT'], MTP: [ '£MT' ],
'MXN': ['$MX', '$'], MXN: [ '$MX', '$' ],
'NAD': ['$NA', '$'], NAD: [ '$NA', '$' ],
'NIO': [u, '$C'], NIO: [ u, '$C' ],
'NZD': ['$NZ', '$'], NZD: [ '$NZ', '$' ],
'RHD': ['$RH'], RHD: [ '$RH' ],
'RON': [u, 'L'], RON: [ u, 'L' ],
'RWF': [u, 'FR'], RWF: [ u, 'FR' ],
'SBD': ['$SB', '$'], SBD: [ '$SB', '$' ],
'SGD': ['$SG', '$'], SGD: [ '$SG', '$' ],
'SRD': ['$SR', '$'], SRD: [ '$SR', '$' ],
'TOP': [u, '$T'], TOP: [ u, '$T' ],
'TTD': ['$TT', '$'], TTD: [ '$TT', '$' ],
'TWD': [u, 'NT$'], TWD: [ u, 'NT$' ],
'USD': ['$US', '$'], USD: [ '$US', '$' ],
'UYU': ['$UY', '$'], UYU: [ '$UY', '$' ],
'WST': ['$WS'], WST: [ '$WS' ],
'XCD': [u, '$'], XCD: [ u, '$' ],
'XPF': ['FCFP'], XPF: [ 'FCFP' ],
'ZMW': [u, 'Kw'] ZMW: [ u, 'Kw' ]
}, },
'ltr', 'ltr',
plural plural

View File

@ -10,7 +10,7 @@ import { AuthService } from '../core/auth'
// Thanks: https://stackoverflow.com/questions/901115/how-can-i-get-query-string-values-in-javascript // Thanks: https://stackoverflow.com/questions/901115/how-can-i-get-query-string-values-in-javascript
function getParameterByName (name: string, url: string) { function getParameterByName (name: string, url: string) {
if (!url) url = window.location.href if (!url) url = window.location.href
name = name.replace(/[\[\]]/g, '\\$&') name = name.replace(/[[\]]/g, '\\$&')
const regex = new RegExp('[?&]' + name + '(=([^&#]*)|&|#|$)') const regex = new RegExp('[?&]' + name + '(=([^&#]*)|&|#|$)')
const results = regex.exec(url) const results = regex.exec(url)
@ -110,10 +110,10 @@ function objectToFormData (obj: any, form?: FormData, namespace?: string) {
continue continue
} }
if (obj[key] !== null && typeof obj[ key ] === 'object' && !(obj[ key ] instanceof File)) { if (obj[key] !== null && typeof obj[key] === 'object' && !(obj[key] instanceof File)) {
objectToFormData(obj[ key ], fd, formKey) objectToFormData(obj[key], fd, formKey)
} else { } else {
fd.append(formKey, obj[ key ]) fd.append(formKey, obj[key])
} }
} }

Some files were not shown because too many files have changed in this diff Show More