Improve frontend accessibility
In particular checkboxes, likes/dislikes, share button, video thumbnails and help buttons
This commit is contained in:
parent
4bdd9473fd
commit
0f7fedc398
|
@ -85,12 +85,10 @@
|
|||
|
||||
<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>
|
||||
|
@ -152,33 +150,24 @@
|
|||
</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()">
|
||||
|
||||
|
@ -197,12 +186,11 @@ Check this checkbox, save the configuration and test with a video URL of your in
|
|||
</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>
|
||||
|
||||
|
|
|
@ -15,14 +15,10 @@
|
|||
</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>
|
||||
|
|
|
@ -1,10 +1,6 @@
|
|||
@import '_variables';
|
||||
@import '_mixins';
|
||||
|
||||
input[type=checkbox] {
|
||||
@include peertube-checkbox(1px);
|
||||
}
|
||||
|
||||
input[type=submit] {
|
||||
@include peertube-button;
|
||||
@include orange-button;
|
||||
|
|
|
@ -9,8 +9,7 @@
|
|||
<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>
|
||||
|
|
|
@ -52,17 +52,6 @@
|
|||
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;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
<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>
|
|
@ -0,0 +1,23 @@
|
|||
@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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,45 @@
|
|||
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
|
||||
}
|
||||
}
|
|
@ -13,10 +13,14 @@
|
|||
</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>
|
||||
|
|
|
@ -15,6 +15,7 @@ export class HelpComponent implements OnInit, OnChanges {
|
|||
@Input() helpType: 'custom' | 'markdownText' | 'markdownEnhanced' = 'custom'
|
||||
@Input() tooltipPlacement = 'right'
|
||||
|
||||
isPopoverOpened = false
|
||||
mainHtml = ''
|
||||
|
||||
constructor (private i18n: I18n) { }
|
||||
|
@ -27,6 +28,14 @@ export class HelpComponent implements OnInit, OnChanges {
|
|||
this.init()
|
||||
}
|
||||
|
||||
onPopoverHidden () {
|
||||
this.isPopoverOpened = false
|
||||
}
|
||||
|
||||
onPopoverShown () {
|
||||
this.isPopoverOpened = true
|
||||
}
|
||||
|
||||
private init () {
|
||||
if (this.helpType === 'custom') {
|
||||
this.mainHtml = this.customHtml
|
||||
|
|
|
@ -45,6 +45,7 @@ import { I18nPrimengCalendarService } from '@app/shared/i18n/i18n-primeng-calend
|
|||
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: [
|
||||
|
@ -77,7 +78,8 @@ import { VideoCaptionService } from '@app/shared/video-caption'
|
|||
MarkdownTextareaComponent,
|
||||
InfiniteScrollerDirective,
|
||||
HelpComponent,
|
||||
ReactiveFileComponent
|
||||
ReactiveFileComponent,
|
||||
PeertubeCheckboxComponent
|
||||
],
|
||||
|
||||
exports: [
|
||||
|
@ -106,6 +108,7 @@ import { VideoCaptionService } from '@app/shared/video-caption'
|
|||
InfiniteScrollerDirective,
|
||||
HelpComponent,
|
||||
ReactiveFileComponent,
|
||||
PeertubeCheckboxComponent,
|
||||
|
||||
NumberFormatterPipe,
|
||||
ObjectLengthPipe,
|
||||
|
|
|
@ -42,8 +42,6 @@ export class VideoCaptionService {
|
|||
}
|
||||
|
||||
updateCaptions (videoId: number | string, videoCaptions: VideoCaptionEdit[]) {
|
||||
if (videoCaptions.length === 0) return of(true)
|
||||
|
||||
const observables: Observable<any>[] = []
|
||||
|
||||
for (const videoCaption of videoCaptions) {
|
||||
|
@ -58,6 +56,8 @@ export class VideoCaptionService {
|
|||
}
|
||||
}
|
||||
|
||||
if (observables.length === 0) return of(true)
|
||||
|
||||
return forkJoin(observables)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
|
||||
<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 }}
|
||||
|
|
|
@ -110,31 +110,22 @@
|
|||
</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>
|
||||
<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>
|
||||
|
||||
<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>
|
||||
<my-peertube-checkbox
|
||||
inputName="commentsEnabled" formControlName="commentsEnabled"
|
||||
i18n-labelText labelText="Enable video comments"
|
||||
></my-peertube-checkbox>
|
||||
|
||||
<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="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>
|
||||
|
|
|
@ -16,31 +16,12 @@
|
|||
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;
|
||||
}
|
||||
|
|
|
@ -49,6 +49,7 @@ export class VideoEditComponent implements OnInit, OnDestroy {
|
|||
calendarDateFormat: string
|
||||
|
||||
private schedulerInterval
|
||||
private firstPatchDone = false
|
||||
|
||||
constructor (
|
||||
private formValidatorService: FormValidatorService,
|
||||
|
@ -167,6 +168,7 @@ export class VideoEditComponent implements OnInit, OnDestroy {
|
|||
.pipe(map(res => parseInt(res.toString(), 10)))
|
||||
.subscribe(
|
||||
newPrivacyId => {
|
||||
|
||||
this.schedulePublicationEnabled = newPrivacyId === this.SPECIAL_SCHEDULED_PRIVACY
|
||||
|
||||
// Value changed
|
||||
|
@ -182,11 +184,18 @@ export class VideoEditComponent implements OnInit, OnDestroy {
|
|||
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
|
||||
|
||||
}
|
||||
)
|
||||
}
|
||||
|
|
|
@ -107,6 +107,7 @@ export class VideoUpdateComponent extends FormReactive implements OnInit {
|
|||
},
|
||||
|
||||
err => {
|
||||
this.loadingBar.complete()
|
||||
this.isUpdatingVideo = false
|
||||
this.notificationsService.error(this.i18n('Error'), err.message)
|
||||
console.error(err)
|
||||
|
|
|
@ -48,15 +48,15 @@
|
|||
<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>
|
||||
|
@ -66,12 +66,12 @@
|
|||
<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>
|
||||
|
|
|
@ -314,7 +314,7 @@ export class VideoWatchComponent implements OnInit, OnDestroy {
|
|||
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
|
||||
|
|
|
@ -269,7 +269,7 @@ class PeerTubePlugin extends Plugin {
|
|||
}
|
||||
|
||||
// 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)
|
||||
}
|
||||
|
||||
|
|
|
@ -240,7 +240,7 @@
|
|||
@mixin peertube-checkbox ($border-width) {
|
||||
display: none;
|
||||
|
||||
& + label {
|
||||
& + span {
|
||||
position: relative;
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
|
@ -263,7 +263,7 @@
|
|||
}
|
||||
}
|
||||
|
||||
&:checked + label {
|
||||
&:checked + span {
|
||||
border-color: transparent;
|
||||
background: $orange-color;
|
||||
animation: jelly 0.6s ease;
|
||||
|
@ -274,7 +274,7 @@
|
|||
}
|
||||
}
|
||||
|
||||
& + label + label {
|
||||
& + span + span {
|
||||
font-size: 15px;
|
||||
font-weight: $font-regular;
|
||||
margin-left: 5px;
|
||||
|
@ -282,8 +282,8 @@
|
|||
display: inline;
|
||||
}
|
||||
|
||||
&[disabled] + label,
|
||||
&[disabled] + label + label{
|
||||
&[disabled] + span,
|
||||
&[disabled] + span + span{
|
||||
opacity: 0.5;
|
||||
cursor: default;
|
||||
}
|
||||
|
|
|
@ -321,7 +321,7 @@ class PeerTubeEmbed {
|
|||
}
|
||||
|
||||
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.')
|
||||
|
|
Loading…
Reference in New Issue