</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>
<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">
<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>
<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>
<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">
</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>
font-size: 100%;
}
-input[type=password],
+my-input-toggle-hidden {
+ width: 340px;
+ display: block;
+}
+
input[type=email] {
@include peertube-input-text(340px);
.current-email,
.pending-email {
- font-size: 16px;
margin-bottom: 15px;
.email {
font-weight: $font-semibold;
}
}
+
+.form-group {
+ width: max-content;
+}
<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>
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] {
margin-top: 15px;
}
-
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'
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
})
@import '_mixins';
.delete-me {
- font-size: 15px;
-
button {
@include peertube-button;
@include danger-button;
<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>
<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>
<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>
<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>
}
}
+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,
<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>
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'
+++ /dev/null
-<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>
+++ /dev/null
-input.readonly {
- font-size: 15px;
-}
+++ /dev/null
-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`)
- }
-}
--- /dev/null
+<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>
--- /dev/null
+@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;
+}
--- /dev/null
+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)
+ }
+}
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'
],
declarations: [
- InputReadonlyCopyComponent,
+ InputToggleHiddenComponent,
MarkdownTextareaComponent,
PeertubeCheckboxComponent,
PreviewUploadComponent,
InputMaskModule,
NgSelectModule,
- InputReadonlyCopyComponent,
+ InputToggleHiddenComponent,
MarkdownTextareaComponent,
PeertubeCheckboxComponent,
PreviewUploadComponent,
<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>
<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).
<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>
<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).
@import '_mixins';
@import '_variables';
-my-input-readonly-copy {
+my-input-toggle-hidden {
width: 100%;
}
<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>
margin-top: 5px;
}
-.input-error {
+.input-error
+my-input-toggle-hidden ::ng-deep input {
border-color: $red !important;
}