[PS-329] A11y: make view, copy, etc controls for ciphers/items keyboard focusable/operable, add screen reader improvements (#2507)

This commit is contained in:
Patrick H. Lauke 2022-04-28 17:24:13 +01:00 committed by GitHub
parent 17c3fdd68b
commit 9df22d3601
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 46 additions and 25 deletions

View File

@ -1,4 +1,5 @@
<span <button
type="button"
class="row-btn" class="row-btn"
(click)="view()" (click)="view()"
appStopClick appStopClick
@ -7,9 +8,10 @@
*ngIf="showView" *ngIf="showView"
> >
<i class="bwi bwi-lg bwi-list-alt" aria-hidden="true"></i> <i class="bwi bwi-lg bwi-list-alt" aria-hidden="true"></i>
</span> </button>
<ng-container *ngIf="cipher.type === cipherType.Login"> <ng-container *ngIf="cipher.type === cipherType.Login">
<span <button
type="button"
class="row-btn" class="row-btn"
appStopClick appStopClick
appStopProp appStopProp
@ -17,71 +19,84 @@
(click)="launchCipher()" (click)="launchCipher()"
*ngIf="!showView" *ngIf="!showView"
[ngClass]="{ disabled: !cipher.login.canLaunch }" [ngClass]="{ disabled: !cipher.login.canLaunch }"
[attr.disabled]="!cipher.login.canLaunch ? '' : null"
> >
<i class="bwi bwi-lg bwi-share-square" aria-hidden="true"></i> <i class="bwi bwi-lg bwi-share-square" aria-hidden="true"></i>
</span> </button>
<span <button
type="button"
class="row-btn" class="row-btn"
appStopClick appStopClick
appStopProp appStopProp
appA11yTitle="{{ 'copyUsername' | i18n }}" appA11yTitle="{{ 'copyUsername' | i18n }}"
(click)="copy(cipher, cipher.login.username, 'username', 'Username')" (click)="copy(cipher, cipher.login.username, 'username', 'Username')"
[ngClass]="{ disabled: !cipher.login.username }" [ngClass]="{ disabled: !cipher.login.username }"
[attr.disabled]="!cipher.login.username ? '' : null"
> >
<i class="bwi bwi-lg bwi-user" aria-hidden="true"></i> <i class="bwi bwi-lg bwi-user" aria-hidden="true"></i>
</span> </button>
<span <button
type="button"
class="row-btn" class="row-btn"
appStopClick appStopClick
appStopProp appStopProp
appA11yTitle="{{ 'copyPassword' | i18n }}" appA11yTitle="{{ 'copyPassword' | i18n }}"
(click)="copy(cipher, cipher.login.password, 'password', 'Password')" (click)="copy(cipher, cipher.login.password, 'password', 'Password')"
[ngClass]="{ disabled: !cipher.login.password || !cipher.viewPassword }" [ngClass]="{ disabled: !cipher.login.password || !cipher.viewPassword }"
[attr.disabled]="!cipher.login.password ? '' : null"
> >
<i class="bwi bwi-lg bwi-key" aria-hidden="true"></i> <i class="bwi bwi-lg bwi-key" aria-hidden="true"></i>
</span> </button>
<span <button
type="button"
class="row-btn" class="row-btn"
appStopClick appStopClick
appStopProp appStopProp
appA11yTitle="{{ 'copyVerificationCode' | i18n }}" appA11yTitle="{{ 'copyVerificationCode' | i18n }}"
(click)="copy(cipher, cipher.login.totp, 'verificationCodeTotp', 'TOTP')" (click)="copy(cipher, cipher.login.totp, 'verificationCodeTotp', 'TOTP')"
[ngClass]="{ disabled: !displayTotpCopyButton(cipher) }" [ngClass]="{ disabled: !displayTotpCopyButton(cipher) }"
[attr.disabled]="!displayTotpCopyButton(cipher) ? '' : null"
> >
<i class="bwi bwi-lg bwi-clock" aria-hidden="true"></i> <i class="bwi bwi-lg bwi-clock" aria-hidden="true"></i>
</span> </button>
</ng-container> </ng-container>
<ng-container *ngIf="cipher.type === cipherType.Card"> <ng-container *ngIf="cipher.type === cipherType.Card">
<span <button
type="button"
class="row-btn" class="row-btn"
appStopClick appStopClick
appStopProp appStopProp
appA11yTitle="{{ 'copyNumber' | i18n }}" appA11yTitle="{{ 'copyNumber' | i18n }}"
(click)="copy(cipher, cipher.card.number, 'number', 'Card Number')" (click)="copy(cipher, cipher.card.number, 'number', 'Card Number')"
[ngClass]="{ disabled: !cipher.card.number }" [ngClass]="{ disabled: !cipher.card.number }"
[attr.disabled]="!cipher.card.number ? '' : null"
> >
<i class="bwi bwi-lg bwi-hashtag" aria-hidden="true"></i> <i class="bwi bwi-lg bwi-hashtag" aria-hidden="true"></i>
</span> </button>
<span <button
type="button"
class="row-btn" class="row-btn"
appStopClick appStopClick
appStopProp appStopProp
appA11yTitle="{{ 'copySecurityCode' | i18n }}" appA11yTitle="{{ 'copySecurityCode' | i18n }}"
(click)="copy(cipher, cipher.card.code, 'securityCode', 'Security Code')" (click)="copy(cipher, cipher.card.code, 'securityCode', 'Security Code')"
[ngClass]="{ disabled: !cipher.card.code }" [ngClass]="{ disabled: !cipher.card.code }"
[attr.disabled]="!cipher.card.code ? '' : null"
> >
<i class="bwi bwi-lg bwi-key" aria-hidden="true"></i> <i class="bwi bwi-lg bwi-key" aria-hidden="true"></i>
</span> </button>
</ng-container> </ng-container>
<ng-container *ngIf="cipher.type === cipherType.SecureNote"> <ng-container *ngIf="cipher.type === cipherType.SecureNote">
<span <button
type="button"
class="row-btn" class="row-btn"
appStopClick appStopClick
appStopProp appStopProp
appA11yTitle="{{ 'copyNote' | i18n }}" appA11yTitle="{{ 'copyNote' | i18n }}"
(click)="copy(cipher, cipher.notes, 'note', 'Note')" (click)="copy(cipher, cipher.notes, 'note', 'Note')"
[ngClass]="{ disabled: !cipher.notes }" [ngClass]="{ disabled: !cipher.notes }"
[attr.disabled]="!cipher.notes ? '' : null"
> >
<i class="bwi bwi-lg bwi-clone" aria-hidden="true"></i> <i class="bwi bwi-lg bwi-clone" aria-hidden="true"></i>
</span> </button>
</ng-container> </ng-container>

View File

@ -1,13 +1,17 @@
<button <div
type="button" role="group"
(click)="selectCipher(cipher)" appA11yTitle="{{ cipher.name }}"
(dblclick)="launchCipher(cipher)"
appStopClick
title="{{ title }} - {{ cipher.name }}"
class="box-content-row box-content-row-flex virtual-scroll-item" class="box-content-row box-content-row-flex virtual-scroll-item"
[ngClass]="{ 'override-last': !last }" [ngClass]="{ 'override-last': !last }"
> >
<div class="row-main"> <button
type="button"
(click)="selectCipher(cipher)"
(dblclick)="launchCipher(cipher)"
appStopClick
title="{{ title }} - {{ cipher.name }}"
class="row-main"
>
<app-vault-icon [cipher]="cipher"></app-vault-icon> <app-vault-icon [cipher]="cipher"></app-vault-icon>
<div class="row-main-content"> <div class="row-main-content">
<span class="text"> <span class="text">
@ -31,7 +35,7 @@
</span> </span>
<span class="detail">{{ cipher.subTitle }}</span> <span class="detail">{{ cipher.subTitle }}</span>
</div> </div>
</div> </button>
<app-action-buttons <app-action-buttons
[cipher]="cipher" [cipher]="cipher"
[showView]="showView" [showView]="showView"
@ -40,4 +44,4 @@
class="action-buttons" class="action-buttons"
> >
</app-action-buttons> </app-action-buttons>
</button> </div>

View File

@ -136,6 +136,7 @@
.row-main { .row-main {
display: flex; display: flex;
min-width: 0; min-width: 0;
align-items: normal;
.row-main-content { .row-main-content {
min-width: 0; min-width: 0;
@ -283,6 +284,7 @@
.text, .text,
.detail { .detail {
display: block; display: block;
text-align: left;
@include themify($themes) { @include themify($themes) {
color: themed("textColor"); color: themed("textColor");