<div i18n class="inner-form-title">Signup</div>
- <div class="form-group">
- <input type="checkbox" id="signupEnabled" formControlName="signupEnabled">
-
- <label for="signupEnabled"></label>
- <label i18n for="signupEnabled">Signup enabled</label>
- </div>
+ <my-peertube-checkbox
+ inputName="signupEnabled" formControlName="signupEnabled"
+ i18n-labelText labelText="Signup enabled"
+ ></my-peertube-checkbox>
<div *ngIf="isSignupEnabled()" class="form-group">
<label i18n for="signupLimit">Signup limit</label>
</div>
</div>
- <div class="form-group">
- <input type="checkbox" id="servicesTwitterWhitelisted" formControlName="servicesTwitterWhitelisted">
-
- <label for="servicesTwitterWhitelisted"></label>
- <label i18n for="servicesTwitterWhitelisted">Instance whitelisted by Twitter</label>
- <my-help
- helpType="custom" i18n-customHtml
- customHtml="If your instance is whitelisted by Twitter, a video player will be embedded in the Twitter feed on PeerTube video share.<br />
+ <my-peertube-checkbox
+ inputName="servicesTwitterWhitelisted" formControlName="servicesTwitterWhitelisted"
+ i18n-labelText labelText="Instance whitelisted by Twitter"
+ i18n-helpHtml helpHtml="If your instance is whitelisted by Twitter, a video player will be embedded in the Twitter feed on PeerTube video share.<br />
If the instance is not whitelisted, we use an image link card that will redirect on your PeerTube instance.<br /><br />
Check this checkbox, save the configuration and test with a video URL of your instance (https://example.com/videos/watch/blabla) on <a target='_blank' rel='noopener noreferrer' href='https://cards-dev.twitter.com/validator'>https://cards-dev.twitter.com/validator</a> to see if you instance is whitelisted."
- ></my-help>
-
- </div>
+ ></my-peertube-checkbox>
</tab>
<tab i18n-heading heading="Advanced configuration">
<div i18n class="inner-form-title">Transcoding</div>
- <div class="form-group">
- <input type="checkbox" id="transcodingEnabled" formControlName="transcodingEnabled">
-
- <label for="transcodingEnabled"></label>
- <label i18n for="transcodingEnabled">Transcoding enabled</label>
-
- <my-help helpType="custom" i18n-customHtml customHtml="If you disable transcoding, many videos from your users will not work!"></my-help>
- </div>
+ <my-peertube-checkbox
+ inputName="transcodingEnabled" formControlName="transcodingEnabled"
+ i18n-labelText labelText="Transcoding enabled"
+ i18n-helpHtml helpHtml="If you disable transcoding, many videos from your users will not work!"
+ ></my-peertube-checkbox>
<ng-template [ngIf]="isTranscodingEnabled()">
</div>
<div class="form-group" *ngFor="let resolution of resolutions">
- <input
- type="checkbox" [id]="getResolutionKey(resolution)"
- [formControlName]="getResolutionKey(resolution)"
- >
- <label [for]="getResolutionKey(resolution)"></label>
- <label i18n [for]="getResolutionKey(resolution)">Resolution {{ resolution }} enabled</label>
+ <my-peertube-checkbox
+ [inputName]="getResolutionKey(resolution)" [formControlName]="getResolutionKey(resolution)"
+ i18n-labelText labelText="Resolution {{resolution}} enabled"
+ ></my-peertube-checkbox>
+
</div>
</ng-template>
</div>
</div>
- <div class="form-group">
- <input
- type="checkbox" id="autoPlayVideo"
- formControlName="autoPlayVideo"
- >
- <label for="autoPlayVideo"></label>
- <label i18n for="autoPlayVideo">Automatically plays video</label>
- </div>
+ <my-peertube-checkbox
+ inputName="autoPlayVideo" formControlName="autoPlayVideo"
+ i18n-labelText labelText="Automatically plays video"
+ ></my-peertube-checkbox>
<input type="submit" i18n-value value="Save" [disabled]="!form.valid">
</form>
@import '_variables';
@import '_mixins';
-input[type=checkbox] {
- @include peertube-checkbox(1px);
-}
-
input[type=submit] {
@include peertube-button;
@include orange-button;
<div *ngFor="let videos of videoPages; let i = index" class="videos-page">
<div class="video" *ngFor="let video of videos; let j = index">
<div class="checkbox-container">
- <input [id]="'video-check-' + video.id" type="checkbox" [(ngModel)]="checkedVideos[video.id]" />
- <label [for]="'video-check-' + video.id"></label>
+ <my-peertube-checkbox [inputName]="'video-check-' + video.id" [(ngModel)]="checkedVideos[video.id]"></my-peertube-checkbox>
</div>
<my-video-thumbnail [video]="video"></my-video-thumbnail>
margin-top: 47px;
}
- .checkbox-container {
- display: flex;
- align-items: center;
- margin-right: 20px;
- margin-left: 12px;
-
- input[type=checkbox] {
- @include peertube-checkbox(2px);
- }
- }
-
my-video-thumbnail {
margin-right: 10px;
}
--- /dev/null
+<div class="form-group">
+ <label class="form-group-checkbox">
+ <input type="checkbox" [(ngModel)]="checked" (ngModelChange)="onModelChange()" [id]="inputName" [disabled]="isDisabled" />
+ <span role="checkbox" [attr.aria-checked]="checked"></span>
+ <span *ngIf="labelText">{{ labelText }}</span>
+ </label>
+
+ <my-help *ngIf="helpHtml" tooltipPlacement="top" helpType="custom" i18n-customHtml [customHtml]="helpHtml"></my-help>
+</div>
\ No newline at end of file
--- /dev/null
+@import '_variables';
+@import '_mixins';
+
+.form-group {
+ display: flex;
+ align-items: center;
+
+ .form-group-checkbox {
+ display: flex;
+
+ span {
+ font-weight: $font-regular;
+ margin: 0;
+ }
+
+ input {
+ @include peertube-checkbox(1px);
+
+ width: 10px;
+ margin-right: 10px;
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+import { Component, forwardRef, Input } from '@angular/core'
+import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms'
+
+@Component({
+ selector: 'my-peertube-checkbox',
+ styleUrls: [ './peertube-checkbox.component.scss' ],
+ templateUrl: './peertube-checkbox.component.html',
+ providers: [
+ {
+ provide: NG_VALUE_ACCESSOR,
+ useExisting: forwardRef(() => PeertubeCheckboxComponent),
+ multi: true
+ }
+ ]
+})
+export class PeertubeCheckboxComponent implements ControlValueAccessor {
+ @Input() checked = false
+ @Input() inputName: string
+ @Input() labelText: string
+ @Input() helpHtml: string
+
+ isDisabled = false
+
+ propagateChange = (_: any) => { /* empty */ }
+
+ writeValue (checked: boolean) {
+ this.checked = checked
+ }
+
+ registerOnChange (fn: (_: any) => void) {
+ this.propagateChange = fn
+ }
+
+ registerOnTouched () {
+ // Unused
+ }
+
+ onModelChange () {
+ this.propagateChange(this.checked)
+ }
+
+ setDisabledState (isDisabled: boolean) {
+ this.isDisabled = isDisabled
+ }
+}
</ng-template>
<span
+ role="button"
class="help-tooltip-button"
title="Get help"
i18n-title
+ [attr.aria-pressed]="isPopoverOpened"
[popover]="tooltipTemplate"
[placement]="tooltipPlacement"
[outsideClick]="true"
+ (onHidden)="onPopoverHidden()"
+ (onShown)="onPopoverShown()"
></span>
@Input() helpType: 'custom' | 'markdownText' | 'markdownEnhanced' = 'custom'
@Input() tooltipPlacement = 'right'
+ isPopoverOpened = false
mainHtml = ''
constructor (private i18n: I18n) { }
this.init()
}
+ onPopoverHidden () {
+ this.isPopoverOpened = false
+ }
+
+ onPopoverShown () {
+ this.isPopoverOpened = true
+ }
+
private init () {
if (this.helpType === 'custom') {
this.mainHtml = this.customHtml
import { ScreenService } from '@app/shared/misc/screen.service'
import { VideoCaptionsValidatorsService } from '@app/shared/forms/form-validators/video-captions-validators.service'
import { VideoCaptionService } from '@app/shared/video-caption'
+import { PeertubeCheckboxComponent } from '@app/shared/forms/peertube-checkbox.component'
@NgModule({
imports: [
MarkdownTextareaComponent,
InfiniteScrollerDirective,
HelpComponent,
- ReactiveFileComponent
+ ReactiveFileComponent,
+ PeertubeCheckboxComponent
],
exports: [
InfiniteScrollerDirective,
HelpComponent,
ReactiveFileComponent,
+ PeertubeCheckboxComponent,
NumberFormatterPipe,
ObjectLengthPipe,
}
updateCaptions (videoId: number | string, videoCaptions: VideoCaptionEdit[]) {
- if (videoCaptions.length === 0) return of(true)
-
const observables: Observable<any>[] = []
for (const videoCaption of videoCaptions) {
}
}
+ if (observables.length === 0) return of(true)
+
return forkJoin(observables)
}
}
<div class="video-miniature-information">
<a
- class="video-miniature-name"
+ class="video-miniature-name" alt=""
[routerLink]="[ '/videos/watch', video.uuid ]" [attr.title]="video.name" [ngClass]="{ 'blur-filter': isVideoBlur() }"
>
{{ video.name }}
</div>
</div>
- <div class="form-group form-group-checkbox">
- <input type="checkbox" id="nsfw" formControlName="nsfw" />
- <label for="nsfw"></label>
- <label i18n for="nsfw">This video contains mature or explicit content</label>
- <my-help
- tooltipPlacement="top" helpType="custom" i18n-customHtml
- customHtml="Some instances do not list videos containing mature or explicit content by default."
- ></my-help>
- </div>
-
- <div class="form-group form-group-checkbox">
- <input type="checkbox" id="commentsEnabled" formControlName="commentsEnabled" />
- <label for="commentsEnabled"></label>
- <label i18n for="commentsEnabled">Enable video comments</label>
- </div>
-
- <div class="form-group form-group-checkbox">
- <input type="checkbox" id="waitTranscoding" formControlName="waitTranscoding" />
- <label for="waitTranscoding"></label>
- <label i18n for="waitTranscoding">Wait transcoding before publishing the video</label>
- <my-help
- tooltipPlacement="top" helpType="custom" i18n-customHtml
- customHtml="If you decide not to wait for transcoding before publishing the video, it could be unplayable until transcoding ends."
- ></my-help>
- </div>
+ <my-peertube-checkbox
+ inputName="nsfw" formControlName="nsfw"
+ i18n-labelText labelText="This video contains mature or explicit content"
+ i18n-helpHtml helpHtml="Some instances do not list videos containing mature or explicit content by default."
+ ></my-peertube-checkbox>
+
+ <my-peertube-checkbox
+ inputName="commentsEnabled" formControlName="commentsEnabled"
+ i18n-labelText labelText="Enable video comments"
+ ></my-peertube-checkbox>
+
+ <my-peertube-checkbox
+ inputName="waitTranscoding" formControlName="waitTranscoding"
+ i18n-labelText labelText="Wait transcoding before publishing the video"
+ i18n-helpHtml helpHtml="If you decide not to wait for transcoding before publishing the video, it could be unplayable until transcoding ends."
+ ></my-peertube-checkbox>
</div>
</tab>
input {
@include peertube-input-text(100%);
display: block;
-
- &[type=checkbox] {
- @include peertube-checkbox(1px);
- }
}
input, select {
font-size: 15px
}
- .form-group-checkbox {
- display: flex;
- align-items: center;
-
- label {
- font-weight: $font-regular;
- margin: 0;
- }
-
- input {
- width: 10px;
- margin-right: 10px;
- }
- }
-
.label-tags + span {
font-size: 15px;
}
calendarDateFormat: string
private schedulerInterval
+ private firstPatchDone = false
constructor (
private formValidatorService: FormValidatorService,
.pipe(map(res => parseInt(res.toString(), 10)))
.subscribe(
newPrivacyId => {
+
this.schedulePublicationEnabled = newPrivacyId === this.SPECIAL_SCHEDULED_PRIVACY
// Value changed
scheduleControl.clearValidators()
waitTranscodingControl.enable()
- waitTranscodingControl.setValue(true)
+
+ // Do not update the control value on first patch (values come from the server)
+ if (this.firstPatchDone === true) {
+ waitTranscodingControl.setValue(true)
+ }
}
scheduleControl.updateValueAndValidity()
waitTranscodingControl.updateValueAndValidity()
+
+ this.firstPatchDone = true
+
}
)
}
},
err => {
+ this.loadingBar.complete()
this.isUpdatingVideo = false
this.notificationsService.error(this.i18n('Error'), err.message)
console.error(err)
<div class="video-actions-rates">
<div class="video-actions">
<div
- *ngIf="isUserLoggedIn()" [ngClass]="{ 'activated': userRating === 'like' }" (click)="setLike()"
- class="action-button action-button-like"
+ *ngIf="isUserLoggedIn()" [ngClass]="{ 'activated': userRating === 'like' }" (click)="setLike()"
+ class="action-button action-button-like" role="button" [attr.aria-pressed]="userRating === 'like'"
>
<span class="icon icon-like" i18n-title title="Like this video" ></span>
</div>
<div
- *ngIf="isUserLoggedIn()" [ngClass]="{ 'activated': userRating === 'dislike' }" (click)="setDislike()"
- class="action-button action-button-dislike"
+ *ngIf="isUserLoggedIn()" [ngClass]="{ 'activated': userRating === 'dislike' }" (click)="setDislike()"
+ class="action-button action-button-dislike" role="button" [attr.aria-pressed]="userRating === 'dislike'"
>
<span class="icon icon-dislike" i18n-title title="Dislike this video"></span>
</div>
<span class="icon-text" i18n>Support</span>
</div>
- <div (click)="showShareModal()" class="action-button action-button-share">
+ <div (click)="showShareModal()" class="action-button action-button-share" role="button">
<span class="icon icon-share"></span>
<span class="icon-text" i18n>Share</span>
</div>
- <div class="action-more" dropdown dropup="true" placement="right">
+ <div class="action-more" dropdown dropup="true" placement="right" role="button">
<div class="action-button" dropdownToggle>
<span class="icon icon-more"></span>
</div>
if (!errorMessage) return
// Display a message in the video player instead of a notification
- if (errorMessage.indexOf('http error') !== -1) {
+ if (errorMessage.indexOf('from xs param') !== -1) {
this.flushPlayer()
this.remoteServerDown = true
return
}
// Remote instance is down
- if (err.message.indexOf('http error from xs param') !== -1) {
+ if (err.message.indexOf('from xs param') !== -1) {
this.handleError(err)
}
@mixin peertube-checkbox ($border-width) {
display: none;
- & + label {
+ & + span {
position: relative;
width: 18px;
height: 18px;
}
}
- &:checked + label {
+ &:checked + span {
border-color: transparent;
background: $orange-color;
animation: jelly 0.6s ease;
}
}
- & + label + label {
+ & + span + span {
font-size: 15px;
font-weight: $font-regular;
margin-left: 5px;
display: inline;
}
- &[disabled] + label,
- &[disabled] + label + label{
+ &[disabled] + span,
+ &[disabled] + span + span{
opacity: 0.5;
cursor: default;
}
}
private handleError (err: Error) {
- if (err.message.indexOf('http error') !== -1) {
+ if (err.message.indexOf('from xs param') !== -1) {
this.player.dispose()
this.videoElement = null
this.displayError('This video is not available because the remote instance is not responding.')