Merge branch 'master' into PS-80-add-deviceid-2fa-email-resend

* master:
  [PS-497] Change `<content>` to `<main>`, make it explicitly non-focusable (#2245)
  [PS-329] A11y: make view, copy, etc controls for ciphers/items keyboard focusable/operable, add screen reader improvements (#2507)
This commit is contained in:
Federico Maccaroni 2022-04-29 13:18:16 -03:00
commit dfc238ed62
38 changed files with 122 additions and 101 deletions

View File

@ -13,7 +13,7 @@
</button>
</div>
</header>
<content>
<main tabindex="-1">
<div class="box">
<h2 class="box-header">
{{ "selfHostedEnvironment" | i18n }}
@ -100,5 +100,5 @@
{{ "customEnvironmentFooter" | i18n }}
</div>
</div>
</content>
</main>
</form>

View File

@ -13,7 +13,7 @@
</button>
</div>
</header>
<content>
<main tabindex="-1">
<div class="box">
<div class="box-content">
<div class="box-content-row" appBoxRow>
@ -34,5 +34,5 @@
{{ "enterEmailToGetHint" | i18n }}
</div>
</div>
</content>
</main>
</form>

View File

@ -8,7 +8,7 @@
<button type="submit" appBlurClick *ngIf="!hideInput">{{ "unlock" | i18n }}</button>
</div>
</header>
<content>
<main tabindex="-1">
<div class="box">
<div class="box-content">
<div class="box-content-row box-content-row-flex" appBoxRow *ngIf="!hideInput">
@ -81,5 +81,5 @@
<p class="text-center text-muted" *ngIf="pendingBiometric">
<i class="bwi bwi-spinner bwi-spin" aria-hidden="true"></i> {{ "awaitDesktop" | i18n }}
</p>
</content>
</main>
</form>

View File

@ -13,7 +13,7 @@
</button>
</div>
</header>
<content>
<main tabindex="-1">
<div class="box">
<div class="box-content">
<div class="box-content-row" appBoxRow>
@ -68,5 +68,5 @@
<a routerLink="/hint">{{ "getMasterPasswordHint" | i18n }}</a>
</p>
<app-private-mode-warning></app-private-mode-warning>
</content>
</main>
</form>

View File

@ -13,7 +13,7 @@
</button>
</div>
</header>
<content>
<main tabindex="-1">
<div class="box">
<div class="box-content">
<div class="box-content-row" appBoxRow>
@ -156,5 +156,5 @@
</div>
</div>
</div>
</content>
</main>
</form>

View File

@ -6,7 +6,7 @@
<div class="right"></div>
</header>
<content>
<main tabindex="-1">
<div class="box">
<div class="box-content">
<div class="box-content-row" appBoxRow>
@ -46,4 +46,4 @@
</div>
</div>
</div>
</content>
</main>

View File

@ -13,7 +13,7 @@
</button>
</div>
</header>
<content>
<main tabindex="-1">
<div class="full-loading-spinner" *ngIf="syncLoading">
<i class="bwi bwi-spinner bwi-spin bwi-3x" aria-hidden="true"></i>
</div>
@ -144,5 +144,5 @@
</div>
</div>
</div>
</content>
</main>
</form>

View File

@ -7,7 +7,7 @@
</h1>
<div class="right"></div>
</header>
<content>
<main tabindex="-1">
<div class="box">
<div class="box-content">
<button
@ -26,4 +26,4 @@
</button>
</div>
</div>
</content>
</main>

View File

@ -23,7 +23,7 @@
</button>
</div>
</header>
<content>
<main tabindex="-1">
<ng-container
*ngIf="
selectedProviderType === providerType.Authenticator ||
@ -140,5 +140,5 @@
</button>
</p>
</div>
</content>
</main>
</form>

View File

@ -13,7 +13,7 @@
</button>
</div>
</header>
<content>
<main tabindex="-1">
<app-callout type="warning" title="{{ 'updateMasterPassword' | i18n }}">
{{ "updateMasterPasswordWarning" | i18n }}
</app-callout>
@ -126,5 +126,5 @@
{{ "masterPassHintDesc" | i18n }}
</div>
</div>
</content>
</main>
</form>

View File

@ -19,9 +19,9 @@ import { routerTransition } from "./app-routing.animations";
selector: "app-root",
styles: [],
animations: [routerTransition],
template: ` <main [@routerTransition]="getState(o)">
template: ` <div [@routerTransition]="getState(o)">
<router-outlet #o="outlet"></router-outlet>
</main>`,
</div>`,
})
export class AppComponent implements OnInit {
private lastActivity: number = null;

View File

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

View File

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

View File

@ -14,7 +14,7 @@
</button>
</div>
</header>
<content>
<main tabindex="-1">
<app-callout type="info" *ngIf="enforcedPasswordPolicyOptions?.inEffect() && type === 'password'">
{{ "passwordGeneratorPolicyInEffect" | i18n }}
</app-callout>
@ -453,4 +453,4 @@
</div>
</div>
</ng-container>
</content>
</main>

View File

@ -14,7 +14,7 @@
</button>
</div>
</header>
<content>
<main tabindex="-1">
<div class="box list full-list" *ngIf="history && history.length">
<div class="box-content">
<div class="box-content-row box-content-row-flex" *ngFor="let h of history">
@ -45,4 +45,4 @@
<div class="no-items" *ngIf="!history || !history.length">
<p>{{ "noPasswordsInList" | i18n }}</p>
</div>
</content>
</main>

View File

@ -107,17 +107,17 @@ textarea {
resize: vertical;
}
main {
app-root > div {
height: 100%;
}
content::-webkit-scrollbar,
main::-webkit-scrollbar,
cdk-virtual-scroll-viewport::-webkit-scrollbar {
width: 10px;
height: 10px;
}
content::-webkit-scrollbar-track {
main::-webkit-scrollbar-track {
background-color: transparent;
}
@ -127,7 +127,7 @@ cdk-virtual-scroll-viewport::-webkit-scrollbar-track {
}
}
content::-webkit-scrollbar-thumb,
main::-webkit-scrollbar-thumb,
cdk-virtual-scroll-viewport::-webkit-scrollbar-thumb {
border-radius: 10px;
margin-right: 1px;
@ -373,7 +373,7 @@ app-root {
padding: 0 calc((100% - 500px) / 2);
}
app-login content {
app-login main {
padding: 0 calc((100% - 500px) / 2);
}
@ -381,7 +381,7 @@ app-root {
padding: 0 calc((100% - 500px) / 2);
}
app-two-factor content {
app-two-factor main {
padding: 0 calc((100% - 500px) / 2);
}
@ -389,12 +389,12 @@ app-root {
padding: 0 calc((100% - 500px) / 2);
}
app-lock content {
app-lock main {
padding: 0 calc((100% - 500px) / 2);
}
}
content {
main {
position: absolute;
top: 44px;
bottom: 0;
@ -423,7 +423,7 @@ content {
}
.tab-page {
content {
main {
bottom: 55px;
}
}

View File

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

View File

@ -1,7 +1,7 @@
@import "variables.scss";
app-sync {
content {
main {
.btn {
margin-bottom: 10px;
}

View File

@ -13,7 +13,7 @@
</button>
</div>
</header>
<content *ngIf="send">
<main tabindex="-1" *ngIf="send">
<!-- Policy Banner -->
<app-callout type="warning" title="{{ 'sendDisabled' | i18n }}" *ngIf="disableSend">
{{ "sendDisabledWarning" | i18n }}
@ -315,5 +315,5 @@
</button>
</div>
</div>
</content>
</main>
</form>

View File

@ -27,7 +27,7 @@
</button>
</div>
</header>
<content [ngClass]="{ flex: disableSend, 'tab-page': disableSend }">
<main tabindex="-1" [ngClass]="{ flex: disableSend, 'tab-page': disableSend }">
<app-callout type="warning" title="{{ 'sendDisabled' | i18n }}" *ngIf="disableSend">
{{ "sendDisabledWarning" | i18n }}
</app-callout>
@ -119,4 +119,4 @@
</div>
</div>
</ng-container>
</content>
</main>

View File

@ -30,7 +30,7 @@
</button>
</div>
</header>
<content [ngClass]="{ flex: disableSend }">
<main tabindex="-1" [ngClass]="{ flex: disableSend }">
<app-callout type="warning" title="{{ 'sendDisabled' | i18n }}" *ngIf="disableSend">
{{ "sendDisabledWarning" | i18n }}
</app-callout>
@ -66,4 +66,4 @@
</app-send-list>
</div>
</div>
</content>
</main>

View File

@ -13,7 +13,7 @@
<button type="submit" appBlurClick>{{ "save" | i18n }}</button>
</div>
</header>
<content>
<main tabindex="-1">
<div class="box">
<div class="box-content">
<ng-container *ngIf="excludedDomains">
@ -84,5 +84,5 @@
{{ "excludedDomainsDesc" | i18n }}
</div>
</div>
</content>
</main>
</form>

View File

@ -15,7 +15,7 @@
</button>
</div>
</header>
<content>
<main tabindex="-1">
<app-callout type="warning" title="{{ 'vaultExportDisabled' | i18n }}" *ngIf="disabledByPolicy">
{{ "personalVaultExportPolicyInEffect" | i18n }}
</app-callout>
@ -36,5 +36,5 @@
<p>{{ "confirmIdentity" | i18n }}</p>
</div>
</div>
</content>
</main>
</form>

View File

@ -13,7 +13,7 @@
</button>
</div>
</header>
<content *ngIf="folder">
<main tabindex="-1" *ngIf="folder">
<div class="box">
<div class="box-content">
<div class="box-content-row" appBoxRow>
@ -49,5 +49,5 @@
</button>
</div>
</div>
</content>
</main>
</form>

View File

@ -19,7 +19,7 @@
</button>
</div>
</header>
<content>
<main tabindex="-1">
<div class="box list full-list" *ngIf="folders && folders.length">
<div class="box-content">
<button
@ -36,4 +36,4 @@
<div class="no-items" *ngIf="!folders || !folders.length">
<p>{{ "noFolders" | i18n }}</p>
</div>
</content>
</main>

View File

@ -10,7 +10,7 @@
</h1>
<div class="right"></div>
</header>
<content>
<main tabindex="-1">
<div class="box">
<h2>
<button
@ -255,4 +255,4 @@
<div class="box-footer">{{ "defaultAutoFillOnPageLoadDesc" | i18n }}</div>
</div>
</ng-container>
</content>
</main>

View File

@ -10,7 +10,7 @@
</h1>
<div class="right"></div>
</header>
<content>
<main tabindex="-1">
<div class="content">
<ng-container *ngIf="!isPremium">
<p class="text-center lead">{{ "premiumNotCurrentMember" | i18n }}</p>
@ -70,4 +70,4 @@
</button>
</ng-container>
</div>
</content>
</main>

View File

@ -7,7 +7,7 @@
</h1>
<div class="right"></div>
</header>
<content>
<main tabindex="-1">
<div class="box list">
<h2 class="box-header">{{ "manage" | i18n }}</h2>
<div class="box-content single-line">
@ -223,4 +223,4 @@
</div>
<div class="box-footer">{{ "rateExtensionDesc" | i18n }}</div>
</div>
</content>
</main>

View File

@ -10,7 +10,7 @@
</h1>
<div class="right"></div>
</header>
<content>
<main tabindex="-1">
<div class="content center-content">
<button
type="button"
@ -25,4 +25,4 @@
</button>
<p class="text-center text-muted small">{{ "lastSync" | i18n }} {{ lastSync }}</p>
</div>
</content>
</main>

View File

@ -13,7 +13,7 @@
</button>
</div>
</header>
<content *ngIf="cipher">
<main tabindex="-1" *ngIf="cipher">
<app-callout type="info" *ngIf="allowOwnershipOptions() && !allowPersonal">
{{ "personalOwnershipPolicyInEffect" | i18n }}
</app-callout>
@ -656,5 +656,5 @@
</button>
</div>
</div>
</content>
</main>
</form>

View File

@ -19,7 +19,7 @@
</button>
</div>
</header>
<content>
<main tabindex="-1">
<div class="box" *ngIf="cipher && cipher.hasAttachments">
<div class="box-content no-hover">
<div class="box-content-row box-content-row-flex" *ngFor="let a of cipher.attachments">
@ -69,5 +69,5 @@
{{ "maxFileSize" | i18n }}
</div>
</div>
</content>
</main>
</form>

View File

@ -24,7 +24,7 @@
</button>
</div>
</header>
<content [ngClass]="{ 'stacked-boxes': showGroupings() }">
<main tabindex="-1" [ngClass]="{ 'stacked-boxes': showGroupings() }">
<ng-container *ngIf="showGroupings()">
<div class="box list" *ngIf="nestedFolders && nestedFolders.length">
<h2 class="box-header">
@ -108,4 +108,4 @@
</div>
</cdk-virtual-scroll-viewport>
</ng-container>
</content>
</main>

View File

@ -16,7 +16,7 @@
</button>
</div>
</header>
<content>
<main tabindex="-1">
<div class="box">
<div class="box-content" *ngIf="!collections || !collections.length">
<div class="box-content-row padded no-hover">
@ -39,5 +39,5 @@
</div>
</div>
</div>
</content>
</main>
</form>

View File

@ -30,7 +30,7 @@
</button>
</div>
</header>
<content>
<main tabindex="-1">
<div class="no-items" *ngIf="!loaded">
<i class="bwi bwi-spinner bwi-spin bwi-3x" aria-hidden="true"></i>
</div>
@ -91,4 +91,4 @@
</div>
</div>
</ng-container>
</content>
</main>

View File

@ -22,7 +22,7 @@
</button>
</div>
</header>
<content>
<main tabindex="-1">
<div class="no-items" *ngIf="(!ciphers || !ciphers.length) && !showSearching()">
<i class="bwi bwi-spinner bwi-spin bwi-3x" *ngIf="!loaded"></i>
<ng-container *ngIf="loaded">
@ -227,4 +227,4 @@
</div>
</cdk-virtual-scroll-viewport>
</ng-container>
</content>
</main>

View File

@ -7,7 +7,7 @@
</h1>
<div class="right"></div>
</header>
<content>
<main tabindex="-1">
<div class="box list full-list" *ngIf="history && history.length">
<div class="box-content">
<div class="box-content-row box-content-row-flex" *ngFor="let h of history">
@ -36,4 +36,4 @@
<div class="no-items" *ngIf="!history || !history.length">
<p>{{ "noPasswordsInList" | i18n }}</p>
</div>
</content>
</main>

View File

@ -18,7 +18,7 @@
</button>
</div>
</header>
<content>
<main tabindex="-1">
<div class="box">
<div class="box-content" *ngIf="!organizations || !organizations.length">
<div class="box-content-row padded no-hover">
@ -67,5 +67,5 @@
</div>
</div>
</div>
</content>
</main>
</form>

View File

@ -11,7 +11,7 @@
</button>
</div>
</header>
<content *ngIf="cipher">
<main tabindex="-1" *ngIf="cipher">
<div class="box">
<h2 class="box-header">
{{ "itemInformation" | i18n }}
@ -521,4 +521,4 @@
</div>
</div>
</div>
</content>
</main>