unify inputs requiring buttons like password inputs

pull/3401/head
Rigel Kent 2020-12-04 15:58:55 +01:00
parent aa5ee5017a
commit f8b530e0a5
No known key found for this signature in database
GPG Key ID: 5E53E96A494E452F
26 changed files with 177 additions and 100 deletions

View File

@ -122,10 +122,9 @@
</ng-container>
</ng-template>
</my-help>
<input
type="password" id="password" autocomplete="new-password" class="form-control"
formControlName="password" [ngClass]="{ 'input-error': formErrors['password'] }"
>
<my-input-toggle-hidden formControlName="password" id="password"
[ngClass]="{ 'input-error': formErrors['password'] }"
autocomplete="new-password"></my-input-toggle-hidden>
<div *ngIf="formErrors.password" class="form-error">
{{ formErrors.password }}
</div>

View File

@ -50,10 +50,10 @@
<div class="form-group">
<label i18n for="password">Password</label>
<div>
<input
type="password" name="password" id="password" i18n-placeholder placeholder="Password" required tabindex="2" autocomplete="current-password"
formControlName="password" class="form-control" [ngClass]="{ 'input-error': formErrors['password'] }"
>
<my-input-toggle-hidden formControlName="password" id="password"
i18n-placeholder placeholder="Password"
[ngClass]="{ 'input-error': formErrors['password'] }"
autocomplete="current-password"></my-input-toggle-hidden>
<a i18n-title class="forgot-password-button" (click)="openForgotPasswordModal()" title="Click here to reset your password">I forgot my password</a>
</div>
<div *ngIf="formErrors.password" class="form-error">

View File

@ -8,7 +8,7 @@
<h2 i18n class="applications-title">SUBSCRIPTION FEED</h2>
<div i18n class="applications-description">
Use third-party feed aggregators to retrieve the list of videos from
channels you subscribed to. Make sure to keep your token private.
channels you subscribed to.
</div>
</div>
@ -16,12 +16,14 @@
<div class="form-group">
<label i18n for="feed-url">Feed URL</label>
<my-input-readonly-copy [value]="feedUrl"></my-input-readonly-copy>
<my-input-toggle-hidden [value]="feedUrl" [withToggle]="false" [withCopy]="true" [show]="true" [readonly]="true"></my-input-toggle-hidden>
</div>
<div class="form-group">
<label i18n for="feed-token">Feed Token</label>
<my-input-readonly-copy [value]="feedToken"></my-input-readonly-copy>
<my-input-toggle-hidden [value]="feedToken" [withCopy]="true" [readonly]="true"></my-input-toggle-hidden>
<div class="form-group-description" i18n>⚠️ Never share your feed token with anyone.</div>
</div>
</div>

View File

@ -12,9 +12,8 @@
<form role="form" class="change-email" (ngSubmit)="changeEmail()" [formGroup]="form" *ngIf="user.pluginAuth === null">
<div class="form-group">
<label i18n for="new-email">New email</label>
<input
type="email" id="new-email" i18n-placeholder placeholder="Your new email" class="form-control"
type="email" id="new-email" i18n-placeholder placeholder="New email" class="form-control"
formControlName="new-email" [ngClass]="{ 'input-error': formErrors['new-email'] }"
>
<div *ngIf="formErrors['new-email']" class="form-error">
@ -23,11 +22,11 @@
</div>
<div class="form-group">
<label i18n for="new-email">Your current password</label>
<input
type="password" id="password" i18n-placeholder placeholder="Your password" autocomplete="off"
formControlName="password" [ngClass]="{ 'input-error': formErrors['password'] }" class="form-control"
>
<my-input-toggle-hidden formControlName="password"
id="password"
i18n-placeholder placeholder="Current password"
[ngClass]="{ 'input-error': formErrors['password'] }"
autocomplete="current-password"></my-input-toggle-hidden>
<div *ngIf="formErrors['password']" class="form-error">
{{ formErrors['password'] }}
</div>

View File

@ -6,7 +6,11 @@ label {
font-size: 100%;
}
input[type=password],
my-input-toggle-hidden {
width: 340px;
display: block;
}
input[type=email] {
@include peertube-input-text(340px);
@ -20,10 +24,13 @@ input[type=submit] {
.current-email,
.pending-email {
font-size: 16px;
margin-bottom: 15px;
.email {
font-weight: $font-semibold;
}
}
.form-group {
width: max-content;
}

View File

@ -3,26 +3,29 @@
<form role="form" (ngSubmit)="changePassword()" [formGroup]="form">
<label i18n for="current-password">Change password</label>
<input
type="password" id="current-password" i18n-placeholder placeholder="Current password" autocomplete="current-password"
formControlName="current-password" [ngClass]="{ 'input-error': formErrors['current-password'] }" class="form-control"
>
<my-input-toggle-hidden formControlName="current-password"
id="current-password"
i18n-placeholder placeholder="Current password"
[ngClass]="{ 'input-error': formErrors['current-password'] }"
autocomplete="current-password"></my-input-toggle-hidden>
<div *ngIf="formErrors['current-password']" class="form-error">
{{ formErrors['current-password'] }}
</div>
<input
type="password" id="new-password" i18n-placeholder placeholder="New password" autocomplete="new-password"
formControlName="new-password" [ngClass]="{ 'input-error': formErrors['new-password'] }" class="form-control"
>
<my-input-toggle-hidden formControlName="new-password"
id="new-password"
i18n-placeholder placeholder="New password"
[ngClass]="{ 'input-error': formErrors['new-password'] }"
autocomplete="new-password"></my-input-toggle-hidden>
<div *ngIf="formErrors['new-password']" class="form-error">
{{ formErrors['new-password'] }}
</div>
<input
type="password" id="new-confirmed-password" i18n-placeholder placeholder="Confirm new password" autocomplete="new-password"
formControlName="new-confirmed-password" class="form-control"
>
<my-input-toggle-hidden formControlName="new-confirmed-password"
id="new-confirmed-password"
i18n-placeholder placeholder="Confirm new password"
[ngClass]="{ 'input-error': formErrors['new-confirmed-password'] }"
autocomplete="new-password"></my-input-toggle-hidden>
<div *ngIf="formErrors['new-confirmed-password']" class="form-error">
{{ formErrors['new-confirmed-password'] }}
</div>

View File

@ -6,14 +6,14 @@ label {
font-size: 100%;
}
input[type=password] {
@include peertube-input-text(340px);
my-input-toggle-hidden {
width: 340px;
display: block;
}
&#new-password,
&#new-confirmed-password {
margin-top: 15px;
}
#new-password,
#new-confirmed-password {
margin-top: 15px;
}
input[type=submit] {
@ -22,4 +22,3 @@ input[type=submit] {
margin-top: 15px;
}

View File

@ -1,7 +1,7 @@
import { filter } from 'rxjs/operators'
import { Component, OnInit } from '@angular/core'
import { AuthService, Notifier, UserService } from '@app/core'
import { USER_CONFIRM_PASSWORD_VALIDATOR, USER_PASSWORD_VALIDATOR } from '@app/shared/form-validators/user-validators'
import { USER_CONFIRM_PASSWORD_VALIDATOR, USER_PASSWORD_VALIDATOR, USER_EXISTING_PASSWORD_VALIDATOR } from '@app/shared/form-validators/user-validators'
import { FormReactive, FormValidatorService } from '@app/shared/shared-forms'
import { User } from '@shared/models'
@ -25,7 +25,7 @@ export class MyAccountChangePasswordComponent extends FormReactive implements On
ngOnInit () {
this.buildForm({
'current-password': USER_PASSWORD_VALIDATOR,
'current-password': USER_EXISTING_PASSWORD_VALIDATOR,
'new-password': USER_PASSWORD_VALIDATOR,
'new-confirmed-password': USER_CONFIRM_PASSWORD_VALIDATOR
})

View File

@ -2,8 +2,6 @@
@import '_mixins';
.delete-me {
font-size: 15px;
button {
@include peertube-button;
@include danger-button;

View File

@ -6,10 +6,10 @@
<form role="form" (ngSubmit)="resetPassword()" [formGroup]="form">
<div class="form-group">
<label i18n for="password">Password</label>
<input
type="password" name="password" id="password" i18n-placeholder placeholder="Password" required autocomplete="new-password"
formControlName="password" [ngClass]="{ 'input-error': formErrors['password'] }"
>
<my-input-toggle-hidden formControlName="password" id="password"
i18n-placeholder placeholder="Password"
[ngClass]="{ 'input-error': formErrors['password'] }"
autocomplete="new-password"></my-input-toggle-hidden>
<div *ngIf="formErrors.password" class="form-error">
{{ formErrors.password }}
</div>
@ -17,10 +17,10 @@
<div class="form-group">
<label i18n for="password-confirm">Confirm password</label>
<input
type="password" name="password-confirm" id="password-confirm" i18n-placeholder placeholder="Confirmed password" required autocomplete="new-password"
formControlName="password-confirm" [ngClass]="{ 'input-error': formErrors['password-confirm'] }"
>
<my-input-toggle-hidden formControlName="password-confirm" id="password-confirm"
i18n-placeholder placeholder="Confirmed password"
[ngClass]="{ 'input-error': formErrors['password-confirm'] }"
autocomplete="new-password"></my-input-toggle-hidden>
<div *ngIf="formErrors['password-confirm']" class="form-error">
{{ formErrors['password-confirm'] }}
</div>

View File

@ -54,10 +54,10 @@
<div class="form-group">
<label for="password" i18n>Password</label>
<input
type="password" id="password" i18n-placeholder placeholder="Password" autocomplete="new-password"
formControlName="password" class="form-control" [ngClass]="{ 'input-error': formErrors['password'] }"
>
<my-input-toggle-hidden formControlName="password" id="password"
i18n-placeholder placeholder="Password"
[ngClass]="{ 'input-error': formErrors['password'] }"
autocomplete="new-password"></my-input-toggle-hidden>
<div *ngIf="formErrors.password" class="form-error">
{{ formErrors.password }}
</div>

View File

@ -213,12 +213,12 @@
<div class="form-group">
<label for="liveVideoRTMPUrl" i18n>Live RTMP Url</label>
<my-input-readonly-copy id="liveVideoRTMPUrl" [value]="liveVideo.rtmpUrl"></my-input-readonly-copy>
<my-input-toggle-hidden id="liveVideoRTMPUrl" [value]="liveVideo.rtmpUrl" [withToggle]="false" [withCopy]="true" [show]="true" [readonly]="true"></my-input-toggle-hidden>
</div>
<div class="form-group">
<label for="liveVideoStreamKey" i18n>Live stream key</label>
<my-input-readonly-copy id="liveVideoStreamKey" [value]="liveVideo.streamKey"></my-input-readonly-copy>
<my-input-toggle-hidden id="liveVideoStreamKey" [value]="liveVideo.streamKey" [withCopy]="true" [readonly]="true"></my-input-toggle-hidden>
<div class="form-group-description" i18n>⚠️ Never share your stream key with anyone.</div>
</div>

View File

@ -39,6 +39,15 @@ export const USER_EMAIL_VALIDATOR: BuildFormValidator = {
}
}
export const USER_EXISTING_PASSWORD_VALIDATOR: BuildFormValidator = {
VALIDATORS: [
Validators.required
],
MESSAGES: {
'required': $localize`Password is required.`
}
}
export const USER_PASSWORD_VALIDATOR: BuildFormValidator = {
VALIDATORS: [
Validators.required,

View File

@ -5,7 +5,7 @@
<input *ngIf="setting.type === 'input'" type="text" [id]="setting.name" [formControlName]="setting.name" />
<input *ngIf="setting.type === 'input-password'" type="password" [id]="setting.name" [formControlName]="setting.name" />
<my-input-toggle-hidden *ngIf="setting.type === 'input-password'" [formControlName]="setting.name" [id]="setting.name"></my-input-toggle-hidden>
<textarea *ngIf="setting.type === 'input-textarea'" type="text" [id]="setting.name" [formControlName]="setting.name"></textarea>

View File

@ -1,7 +1,7 @@
export * from './form-validator.service'
export * from './form-reactive'
export * from './select'
export * from './input-readonly-copy.component'
export * from './input-toggle-hidden.component'
export * from './input-switch.component'
export * from './markdown-textarea.component'
export * from './peertube-checkbox.component'

View File

@ -1,9 +0,0 @@
<div class="input-group input-group-sm">
<input [id]="id" #urlInput (click)="urlInput.select()" type="text" class="form-control readonly" readonly [value]="value" />
<div class="input-group-append">
<button [cdkCopyToClipboard]="urlInput.value" (click)="activateCopiedMessage()" type="button" class="btn btn-outline-secondary">
<span class="glyphicon glyphicon-copy"></span>
</button>
</div>
</div>

View File

@ -1,3 +0,0 @@
input.readonly {
font-size: 15px;
}

View File

@ -1,18 +0,0 @@
import { Component, Input } from '@angular/core'
import { Notifier } from '@app/core'
@Component({
selector: 'my-input-readonly-copy',
templateUrl: './input-readonly-copy.component.html',
styleUrls: [ './input-readonly-copy.component.scss' ]
})
export class InputReadonlyCopyComponent {
@Input() id: string
@Input() value = ''
constructor (private notifier: Notifier) { }
activateCopiedMessage () {
this.notifier.success($localize`Copied`)
}
}

View File

@ -0,0 +1,13 @@
<div class="input-group input-group-sm">
<input [id]="id" [autocomplete]="autocomplete" [value]="value" [placeholder]="placeholder" [(ngModel)]="value" (ngModelChange)="update()" [ngClass]="{ 'readonly': readonly }" [readonly]="readonly"
#input (click)="input.select()" (input)="update()" (change)="update()" [type]="inputType" class="form-control" />
<div *ngIf="withToggle || withCopy" class="input-group-append">
<button *ngIf="withToggle" (click)="toggle()" type="button" class="btn btn-outline-secondary" [title]="toggleTitle">
<span class="glyphicon glyphicon-eye-{{ show ? 'open' : 'close' }}"></span>
</button>
<button *ngIf="withCopy" [cdkCopyToClipboard]="input.value" (click)="activateCopiedMessage()" type="button" class="btn btn-outline-secondary" i18n-title title="Copy">
<span class="glyphicon glyphicon-copy"></span>
</button>
</div>
</div>

View File

@ -0,0 +1,11 @@
@import '_variables';
@import '_mixins';
input {
@include peertube-input-text(auto);
// set again properties of peertube-input-text that are overriden by .input-group
font-size: 15px !important;
padding-left: 15px !important;
padding-right: 15px !important;
}

View File

@ -0,0 +1,66 @@
import { Component, forwardRef, Input } from '@angular/core'
import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms'
import { Notifier } from '@app/core'
@Component({
selector: 'my-input-toggle-hidden',
templateUrl: './input-toggle-hidden.component.html',
styleUrls: [ './input-toggle-hidden.component.scss' ],
providers: [
{
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => InputToggleHiddenComponent),
multi: true
}
]
})
export class InputToggleHiddenComponent implements ControlValueAccessor {
@Input() id = Math.random().toString(11).slice(2, 8) // id cannot be left empty or undefined
@Input() value = ''
@Input() autocomplete = 'off'
@Input() placeholder = ''
@Input() withToggle = true
@Input() withCopy = false
@Input() readonly = false
@Input() show = false
constructor (private notifier: Notifier) { }
get inputType () {
return this.show
? 'text'
: 'password'
}
get toggleTitle () {
return this.show
? $localize`Hide`
: $localize`Show`
}
toggle () {
this.show = !this.show
}
activateCopiedMessage () {
this.notifier.success($localize`Copied`)
}
propagateChange = (_: any) => { /* empty */ }
writeValue (value: string) {
this.value = value
}
registerOnChange (fn: (_: any) => void) {
this.propagateChange = fn
}
registerOnTouched () {
// Unused
}
update () {
this.propagateChange(this.value)
}
}

View File

@ -7,7 +7,7 @@ import { SharedGlobalIconModule } from '../shared-icons'
import { SharedMainModule } from '../shared-main/shared-main.module'
import { DynamicFormFieldComponent } from './dynamic-form-field.component'
import { FormValidatorService } from './form-validator.service'
import { InputReadonlyCopyComponent } from './input-readonly-copy.component'
import { InputToggleHiddenComponent } from './input-toggle-hidden.component'
import { InputSwitchComponent } from './input-switch.component'
import { MarkdownTextareaComponent } from './markdown-textarea.component'
import { PeertubeCheckboxComponent } from './peertube-checkbox.component'
@ -30,7 +30,7 @@ import { TimestampInputComponent } from './timestamp-input.component'
],
declarations: [
InputReadonlyCopyComponent,
InputToggleHiddenComponent,
MarkdownTextareaComponent,
PeertubeCheckboxComponent,
PreviewUploadComponent,
@ -55,7 +55,7 @@ import { TimestampInputComponent } from './timestamp-input.component'
InputMaskModule,
NgSelectModule,
InputReadonlyCopyComponent,
InputToggleHiddenComponent,
MarkdownTextareaComponent,
PeertubeCheckboxComponent,
PreviewUploadComponent,

View File

@ -18,7 +18,7 @@
<ng-template ngbNavContent>
<div class="nav-content">
<my-input-readonly-copy [value]="getPlaylistUrl()"></my-input-readonly-copy>
<my-input-toggle-hidden [value]="getPlaylistUrl()" [withToggle]="false" [withCopy]="true" [show]="true" [readonly]="true"></my-input-toggle-hidden>
</div>
</ng-template>
</ng-container>
@ -38,7 +38,7 @@
<ng-template ngbNavContent>
<div class="nav-content">
<my-input-readonly-copy [value]="getPlaylistIframeCode()"></my-input-readonly-copy>
<my-input-toggle-hidden [value]="getPlaylistIframeCode()" [withToggle]="false" [withCopy]="true" [show]="true" [readonly]="true"></my-input-toggle-hidden>
<div i18n *ngIf="notSecure()" class="alert alert-warning">
The url is not secured (no HTTPS), so the embed video won't work on HTTPS websites (web browsers block non secured HTTP requests on HTTPS websites).
@ -72,7 +72,7 @@
<ng-template ngbNavContent>
<div class="nav-content">
<my-input-readonly-copy [value]="getVideoUrl()"></my-input-readonly-copy>
<my-input-toggle-hidden [value]="getVideoUrl()" [withToggle]="false" [withCopy]="true" [show]="true" [readonly]="true"></my-input-toggle-hidden>
</div>
</ng-template>
</ng-container>
@ -92,7 +92,7 @@
<ng-template ngbNavContent>
<div class="nav-content">
<my-input-readonly-copy [value]="getVideoIframeCode()"></my-input-readonly-copy>
<my-input-toggle-hidden [value]="getVideoIframeCode()" [withToggle]="false" [withCopy]="true" [show]="true" [readonly]="true"></my-input-toggle-hidden>
<div i18n *ngIf="notSecure()" class="alert alert-warning">
The url is not secured (no HTTPS), so the embed video won't work on HTTPS websites (web browsers block non secured HTTP requests on HTTPS websites).

View File

@ -1,7 +1,7 @@
@import '_mixins';
@import '_variables';
my-input-readonly-copy {
my-input-toggle-hidden {
width: 100%;
}

View File

@ -13,12 +13,12 @@
<div class="form-group">
<label for="liveVideoRTMPUrl" i18n>Live RTMP Url</label>
<my-input-readonly-copy id="liveVideoRTMPUrl" [value]="live.rtmpUrl"></my-input-readonly-copy>
<my-input-toggle-hidden id="liveVideoRTMPUrl" [value]="live.rtmpUrl" [withToggle]="false" [withCopy]="true" [show]="true" [readonly]="true"></my-input-toggle-hidden>
</div>
<div class="form-group">
<label for="liveVideoStreamKey" i18n>Live stream key</label>
<my-input-readonly-copy id="liveVideoStreamKey" [value]="live.streamKey"></my-input-readonly-copy>
<my-input-toggle-hidden id="liveVideoStreamKey" [value]="live.streamKey" [withCopy]="true" [readonly]="true"></my-input-toggle-hidden>
<div class="form-group-description" i18n>⚠️ Never share your stream key with anyone.</div>
</div>

View File

@ -120,7 +120,8 @@ code {
margin-top: 5px;
}
.input-error {
.input-error
my-input-toggle-hidden ::ng-deep input {
border-color: $red !important;
}