Accessibility fixes for #2149
authorRigel Kent <sendmemail@rigelk.eu>
Fri, 10 Jan 2020 18:50:48 +0000 (19:50 +0100)
committerChocobozzz <chocobozzz@cpy.re>
Tue, 21 Jan 2020 09:08:10 +0000 (10:08 +0100)
14 files changed:
client/src/app/+admin/users/user-edit/user-edit.component.html
client/src/app/+my-account/my-account-settings/my-account-change-email/my-account-change-email.component.html
client/src/app/+my-account/my-account-settings/my-account-change-password/my-account-change-password.component.html
client/src/app/+signup/+register/register-step-user.component.html
client/src/app/+video-channels/video-channel-videos/video-channel-videos.component.ts
client/src/app/+video-channels/video-channels.component.html
client/src/app/header/header.component.html
client/src/app/header/header.component.ts
client/src/app/login/login.component.html
client/src/app/reset-password/reset-password.component.html
client/src/app/shared/images/global-icon.component.ts
client/src/app/shared/video/video-thumbnail.component.html
client/src/sass/primeng-custom.scss
server/lib/client-html.ts

index 6282d48a4407caf0ec2fe48f739752c797098bfe..4ff4d0d1228ac5b7dfdc5ce54e2cc2eb4dc041a8 100644 (file)
@@ -30,7 +30,7 @@
   <div class="form-group" *ngIf="isCreation()">
     <label i18n for="password">Password</label>
     <input
-      type="password" id="password"
+      type="password" id="password" autocomplete="new-password"
       formControlName="password" [ngClass]="{ 'input-error': formErrors['password'] }"
     >
     <div *ngIf="formErrors.password" class="form-error">
index 5492cdf226c4145f8fd871659c64e66afd62c15b..76886c73e21ef054a8b4a0647f6547a2e428234c 100644 (file)
@@ -24,7 +24,7 @@
 
   <div class="form-group">
     <input
-      type="password" id="password" i18n-placeholder placeholder="Your password"
+      type="password" id="password" i18n-placeholder placeholder="Your password" autocomplete="off"
       formControlName="password" [ngClass]="{ 'input-error': formErrors['password'] }"
     >
     <div *ngIf="formErrors['password']" class="form-error">
index a39061ee3a466203e478e46950c565428384ba55..cec70c6b57f3ea1487070f4537668c875685491c 100644 (file)
@@ -4,7 +4,7 @@
 
   <label i18n for="current-password">Change password</label>
   <input
-    type="password" id="current-password" i18n-placeholder placeholder="Current password"
+    type="password" id="current-password" i18n-placeholder placeholder="Current password" autocomplete="current-password"
     formControlName="current-password" [ngClass]="{ 'input-error': formErrors['current-password'] }"
   >
   <div *ngIf="formErrors['current-password']" class="form-error">
@@ -12,7 +12,7 @@
   </div>
 
   <input
-    type="password" id="new-password" i18n-placeholder placeholder="New password"
+    type="password" id="new-password" i18n-placeholder placeholder="New password" autocomplete="new-password"
     formControlName="new-password" [ngClass]="{ 'input-error': formErrors['new-password'] }"
   >
   <div *ngIf="formErrors['new-password']" class="form-error">
@@ -20,7 +20,7 @@
   </div>
 
   <input
-    type="password" id="new-confirmed-password" i18n-placeholder placeholder="Confirm new password"
+    type="password" id="new-confirmed-password" i18n-placeholder placeholder="Confirm new password" autocomplete="new-password"
     formControlName="new-confirmed-password"
   >
   <div *ngIf="formErrors['new-confirmed-password']" class="form-error">
index 4381702ae525be0255005b466a236f2f1a574d92..a2a657660e58a2e89392f62bc1b7ad13f4491ec6 100644 (file)
@@ -51,7 +51,7 @@
   <div class="form-group">
     <label for="password" i18n>Password</label>
     <input
-      type="password" id="password" i18n-placeholder placeholder="Password"
+      type="password" id="password" i18n-placeholder placeholder="Password" autocomplete="new-password"
       formControlName="password" [ngClass]="{ 'input-error': formErrors['password'] }"
     >
     <div *ngIf="formErrors.password" class="form-error">
index c1dc25aaf3b2706410ffc25e8562805ef3e05c5e..f4fe146628f6df89226f259f093925b5a33b7251 100644 (file)
@@ -72,7 +72,7 @@ export class VideoChannelVideosComponent extends AbstractVideoList implements On
                .getVideoChannelVideos(this.videoChannel, newPagination, this.sort)
                .pipe(
                  tap(({ total }) => {
-                   this.titlePage = this.i18n('Published {{total}} videos', { total })
+                   this.titlePage = this.i18n(`{total, plural, =1 {Published 1 video} other {Published ${total} videos}}`, { total })
                  })
                )
   }
index 8ab79526d02c48d12d5ddd7c2e19779ae84ace96..065fc2c04bdb57dc5272021aeefa284a5f9b5e07 100644 (file)
@@ -20,7 +20,7 @@
             <my-subscribe-button #subscribeButton [videoChannels]="[videoChannel]"></my-subscribe-button>
           </div>
         </div>
-        <div i18n class="actor-followers">{{ videoChannel.followersCount }} subscribers</div>
+        <div class="actor-followers" i18n>{videoChannel.followersCount, plural, =1 {1 subscriber} other {{{ videoChannel.followersCount }} subscribers}}</div>
 
         <a [routerLink]="[ '/accounts', videoChannel.ownerBy ]" i18n-title title="Go the owner account page" class="actor-owner">
           <span i18n>Created by {{ videoChannel.ownerBy }}</span>
index 5998618174b8138dc86f711a01c64392a1736edb..1bdfe9858292ad36480e699c308414a2cbb3c835 100644 (file)
@@ -1,5 +1,5 @@
 <input
-  type="text" id="search-video" name="search-video" i18n-placeholder placeholder="Search videos, channels…"
+  type="text" id="search-video" name="search-video" [attr.aria-label]="ariaLabelTextForSearch" i18n-placeholder placeholder="Search videos, channels…"
   [(ngModel)]="searchValue" (keyup.enter)="doSearch()"
 >
 <span (click)="doSearch()" class="icon icon-search"></span>
index 5805356691ec261bf1f423ad97cf36140cb14239..5fd1229307a9207a8870e3dc1cf99f39803fb3c2 100644 (file)
@@ -5,6 +5,7 @@ import { getParameterByName } from '../shared/misc/utils'
 import { AuthService, ServerService, Notifier } from '@app/core'
 import { of } from 'rxjs'
 import { ServerConfig } from '@shared/models'
+import { I18n } from '@ngx-translate/i18n-polyfill'
 
 @Component({
   selector: 'my-header',
@@ -14,6 +15,7 @@ import { ServerConfig } from '@shared/models'
 
 export class HeaderComponent implements OnInit {
   searchValue = ''
+  ariaLabelTextForSearch = ''
 
   private serverConfig: ServerConfig
 
@@ -23,10 +25,13 @@ export class HeaderComponent implements OnInit {
     private auth: AuthService,
     private serverService: ServerService,
     private authService: AuthService,
-    private notifier: Notifier
+    private notifier: Notifier,
+    private i18n: I18n
   ) {}
 
   ngOnInit () {
+    this.ariaLabelTextForSearch = this.i18n('Search videos, channels')
+
     this.router.events
         .pipe(
           filter(e => e instanceof NavigationEnd),
index 162f44ded8a7d0c2b36b0d04af7128adff35f9cb..6c6a41c4a040a529950e54645fe708482fb2ae43 100644 (file)
@@ -51,7 +51,7 @@
       <label i18n for="password">Password</label>
       <div>
         <input
-          type="password" name="password" id="password" i18n-placeholder placeholder="Password" required tabindex="2"
+          type="password" name="password" id="password" i18n-placeholder placeholder="Password" required tabindex="2" autocomplete="current-password"
           formControlName="password" [ngClass]="{ 'input-error': formErrors['password'] }"
         >
         <a i18n class="forgot-password-button" (click)="openForgotPasswordModal()" title="Click here to reset your password">I forgot my password</a>
index 8398be09148ef7d696d2600cad05674ea8492e0e..af30af4a0daefe8345fcb640f3326ae07470e8ac 100644 (file)
@@ -7,7 +7,7 @@
     <div class="form-group">
       <label i18n for="password">Password</label>
       <input
-        type="password" name="password" id="password" i18n-placeholder placeholder="Password" required
+        type="password" name="password" id="password" i18n-placeholder placeholder="Password" required autocomplete="new-password"
         formControlName="password" [ngClass]="{ 'input-error': formErrors['password'] }"
       >
       <div *ngIf="formErrors.password" class="form-error">
@@ -18,7 +18,7 @@
     <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
+        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'] }"
       >
       <div *ngIf="formErrors['password-confirm']" class="form-error">
index 17186cff4ae1401f45adecc3916ff1ad10f2a72c..806aca347237b9ebc8208f7a6b8657f3a6cf5ed4 100644 (file)
@@ -1,5 +1,6 @@
 import { ChangeDetectionStrategy, Component, ElementRef, Input, OnInit } from '@angular/core'
 import { HooksService } from '@app/core/plugins/hooks.service'
+import { I18n } from '@ngx-translate/i18n-polyfill'
 
 const icons = {
   'add': require('!!raw-loader?!../../../assets/images/global/add.svg'),
@@ -70,8 +71,7 @@ export class GlobalIconComponent implements OnInit {
   ) { }
 
   async ngOnInit () {
-    const nativeElement = this.el.nativeElement
-
+    const nativeElement = this.el.nativeElement as HTMLElement
     nativeElement.innerHTML = await this.hooks.wrapFun(
       this.getSVGContent.bind(this),
       { name: this.iconName },
index 7e71a390b668c0134f7e132fa352819cc4f1b9f8..b63085b816be3a2f1b74b4ce3a469e477ce39c64 100644 (file)
@@ -1,8 +1,8 @@
 <a
-  [routerLink]="getVideoRouterLink()" [queryParams]="queryParams" [attr.title]="video.name"
+  [routerLink]="getVideoRouterLink()" [queryParams]="queryParams" [title]="video.name"
   class="video-thumbnail"
 >
-  <img alt="" [attr.aria-labelledby]="video.name" [attr.src]="getImageUrl()" [ngClass]="{ 'blur-filter': nsfw }" />
+  <img alt="" [attr.aria-label]="video.name" [attr.src]="getImageUrl()" [ngClass]="{ 'blur-filter': nsfw }" />
 
   <div *ngIf="displayWatchLaterPlaylist" class="video-thumbnail-actions-overlay">
     <ng-container *ngIf="inWatchLaterPlaylist !== true">
index 9aa4d980cd52006b2435b486619a7c2a412c2647..238cb84546f196eb7b9cade5d0e1314c7d7658a6 100644 (file)
@@ -8,6 +8,7 @@
   font-family: 'Glyphicons Halflings';
   text-decoration: none !important;
   color: var(--mainForegroundColor) !important;
+  font-display: swap;
 }
 
 my-edit-button,
index e5950561445015452d4d0ea8e7dc45bdcda5aa87..1d8a08ed0bfc59a891dab5cfa8aea0031baf4284 100644 (file)
@@ -26,7 +26,9 @@ export class ClientHtml {
   }
 
   static async getDefaultHTMLPage (req: express.Request, res: express.Response, paramLang?: string) {
-    const html = await ClientHtml.getIndexHTML(req, res, paramLang)
+    const html = paramLang
+      ? await ClientHtml.getIndexHTML(req, res, paramLang)
+      : await ClientHtml.getIndexHTML(req, res)
 
     let customHtml = ClientHtml.addTitleTag(html)
     customHtml = ClientHtml.addDescriptionTag(customHtml)
@@ -98,6 +100,7 @@ export class ClientHtml {
 
     let html = buffer.toString()
 
+    if (paramLang) html = ClientHtml.addHtmlLang(html, paramLang)
     html = ClientHtml.addCustomCSS(html)
     html = await ClientHtml.addAsyncPluginCSS(html)
 
@@ -106,7 +109,7 @@ export class ClientHtml {
     return html
   }
 
-  private static getIndexPath (req: express.Request, res: express.Response, paramLang?: string) {
+  private static getIndexPath (req: express.Request, res: express.Response, paramLang: string) {
     let lang: string
 
     // Check param lang validity
@@ -129,6 +132,10 @@ export class ClientHtml {
     return join(__dirname, '../../../client/dist/' + buildFileLocale(lang) + '/index.html')
   }
 
+  private static addHtmlLang (htmlStringPage: string, paramLang: string) {
+    return htmlStringPage.replace('<html>', `<html lang="${paramLang}">`)
+  }
+
   private static addTitleTag (htmlStringPage: string, title?: string) {
     let text = title || CONFIG.INSTANCE.NAME
     if (title) text += ` - ${CONFIG.INSTANCE.NAME}`