Change links to buttons, expose `aria-pressed` for toggles, add `aria-expanded` to send view's "Options" (#1437)

* Change links to buttons, expose `aria-pressed` for toggles

- also make existing `<a routerLink...>` type controls keyboard focusable with the addition of `tabindex="0"`

* Correctly set aria-pressed

now that I have a working build environment, could verify correct way to set this with my limited Angular knowledge

* Change more links to buttons, initial style changes

* Fix layout of <button> elements with .box-content-row

* Update jslib submodule

* Add `aria-expanded` to the send view's "Show options" expand/collapse control

* Fix position of "Edit" pencil when hovering over folders

* Update jslib

* Change sends list links to buttons

* Add `aria-pressed` to vault and send list buttons

Programmatically denote which of the buttons is currently active/shown in the right-most panel

* Fix incorrect "Options" expand/collapse button in add-edit view

Currently, that buttons lacks an accName because the "Options" text is outside of it.

* Add `aria-pressed` to the send left-hand column filters

* Simplify base, list, and vault styles

Since links are now buttons, no need to double up selectors for both types of elements. No need to double-up theming in base, as this also causes incorrect "x" in toasts.

* Remove unnecessary `position:relative`

Fixes issue with cut-off focus outlines, has no other adverse effect

* Fix styling for last child of action buttons

Old approach of making right padding smaller results in unsightly, off-center icon (noticeable when focus outline is visible). This visually remains the same, but reduces right-hand margin instead.
This commit is contained in:
Patrick H. Lauke 2022-04-30 15:09:41 +01:00 committed by GitHub
parent ef60112855
commit 0396d682b1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
24 changed files with 303 additions and 241 deletions

View File

@ -25,7 +25,7 @@
<b [hidden]="form.loading">{{ "submit" | i18n }}</b> <b [hidden]="form.loading">{{ "submit" | i18n }}</b>
<i class="bwi bwi-spinner bwi-spin" [hidden]="!form.loading" aria-hidden="true"></i> <i class="bwi bwi-spinner bwi-spin" [hidden]="!form.loading" aria-hidden="true"></i>
</button> </button>
<a routerLink="/login" class="btn block">{{ "cancel" | i18n }}</a> <a role="button" tabindex="0" routerLink="/login" class="btn block">{{ "cancel" | i18n }}</a>
</div> </div>
</div> </div>
</form> </form>

View File

@ -30,12 +30,11 @@
/> />
</div> </div>
<div class="action-buttons"> <div class="action-buttons">
<a <button
type="button"
class="row-btn" class="row-btn"
href="#"
appStopClick appStopClick
appBlurClick appBlurClick
role="button"
appA11yTitle="{{ 'toggleVisibility' | i18n }}" appA11yTitle="{{ 'toggleVisibility' | i18n }}"
[attr.aria-pressed]="showPassword" [attr.aria-pressed]="showPassword"
(click)="togglePassword()" (click)="togglePassword()"
@ -45,7 +44,7 @@
aria-hidden="true" aria-hidden="true"
[ngClass]="{ 'bwi-eye': !showPassword, 'bwi-eye-slash': showPassword }" [ngClass]="{ 'bwi-eye': !showPassword, 'bwi-eye-slash': showPassword }"
></i> ></i>
</a> </button>
</div> </div>
</div> </div>
</div> </div>

View File

@ -1,7 +1,7 @@
<div id="login-page"> <div id="login-page">
<div class="login-header"> <div class="login-header">
<a <button
href="#" type="button"
appStopClick appStopClick
(click)="settings()" (click)="settings()"
class="environment-urls-settings-icon" class="environment-urls-settings-icon"
@ -9,7 +9,7 @@
> >
<i class="bwi bwi-cog bwi-lg" aria-hidden="true"></i> <i class="bwi bwi-cog bwi-lg" aria-hidden="true"></i>
{{ "settings" | i18n }} {{ "settings" | i18n }}
</a> </button>
</div> </div>
<form <form
id="login-page" id="login-page"
@ -48,12 +48,11 @@
/> />
</div> </div>
<div class="action-buttons"> <div class="action-buttons">
<a <button
type="button"
class="row-btn" class="row-btn"
href="#"
appStopClick appStopClick
appBlurClick appBlurClick
role="button"
appA11yTitle="{{ 'toggleVisibility' | i18n }}" appA11yTitle="{{ 'toggleVisibility' | i18n }}"
[attr.aria-pressed]="showPassword" [attr.aria-pressed]="showPassword"
(click)="togglePassword()" (click)="togglePassword()"
@ -63,7 +62,7 @@
aria-hidden="true" aria-hidden="true"
[ngClass]="{ 'bwi-eye': !showPassword, 'bwi-eye-slash': showPassword }" [ngClass]="{ 'bwi-eye': !showPassword, 'bwi-eye-slash': showPassword }"
></i> ></i>
</a> </button>
</div> </div>
</div> </div>
</div> </div>
@ -83,18 +82,22 @@
> >
<i class="bwi bwi-spinner bwi-spin" [hidden]="!form.loading" aria-hidden="true"></i> <i class="bwi bwi-spinner bwi-spin" [hidden]="!form.loading" aria-hidden="true"></i>
</button> </button>
<a routerLink="/register" class="btn block"> <a role="button" tabindex="0" routerLink="/register" class="btn block">
<i class="bwi bwi-pencil-square" aria-hidden="true"></i> {{ "createAccount" | i18n }} <i class="bwi bwi-pencil-square" aria-hidden="true"></i> {{ "createAccount" | i18n }}
</a> </a>
</div> </div>
<div class="buttons-row"> <div class="buttons-row">
<a (click)="launchSsoBrowser('desktop', 'bitwarden://sso-callback')" class="btn block"> <button
type="button"
(click)="launchSsoBrowser('desktop', 'bitwarden://sso-callback')"
class="btn block"
>
<i class="bwi bwi-bank" aria-hidden="true"></i> {{ "enterpriseSingleSignOn" | i18n }} <i class="bwi bwi-bank" aria-hidden="true"></i> {{ "enterpriseSingleSignOn" | i18n }}
</a> </button>
</div> </div>
</div> </div>
<div class="sub-options"> <div class="sub-options">
<a routerLink="/hint">{{ "getMasterPasswordHint" | i18n }}</a> <a role="button" tabindex="0" routerLink="/hint">{{ "getMasterPasswordHint" | i18n }}</a>
</div> </div>
</div> </div>
</form> </form>

View File

@ -40,12 +40,11 @@
/> />
</div> </div>
<div class="action-buttons"> <div class="action-buttons">
<a <button
type="button"
class="row-btn" class="row-btn"
href="#"
appStopClick appStopClick
appBlurClick appBlurClick
role="button"
appA11yTitle="{{ 'toggleVisibility' | i18n }}" appA11yTitle="{{ 'toggleVisibility' | i18n }}"
[attr.aria-pressed]="showPassword" [attr.aria-pressed]="showPassword"
(click)="togglePassword(false)" (click)="togglePassword(false)"
@ -55,7 +54,7 @@
aria-hidden="true" aria-hidden="true"
[ngClass]="{ 'bwi-eye': !showPassword, 'bwi-eye-slash': showPassword }" [ngClass]="{ 'bwi-eye': !showPassword, 'bwi-eye-slash': showPassword }"
></i> ></i>
</a> </button>
</div> </div>
</div> </div>
<div class="progress"> <div class="progress">
@ -91,12 +90,11 @@
/> />
</div> </div>
<div class="action-buttons"> <div class="action-buttons">
<a <button
type="button"
class="row-btn" class="row-btn"
href="#"
appStopClick appStopClick
appBlurClick appBlurClick
role="button"
appA11yTitle="{{ 'toggleVisibility' | i18n }}" appA11yTitle="{{ 'toggleVisibility' | i18n }}"
[attr.aria-pressed]="showPassword" [attr.aria-pressed]="showPassword"
(click)="togglePassword(true)" (click)="togglePassword(true)"
@ -106,7 +104,7 @@
aria-hidden="true" aria-hidden="true"
[ngClass]="{ 'bwi-eye': !showPassword, 'bwi-eye-slash': showPassword }" [ngClass]="{ 'bwi-eye': !showPassword, 'bwi-eye-slash': showPassword }"
></i> ></i>
</a> </button>
</div> </div>
</div> </div>
<div class="box-content-row" appBoxRow> <div class="box-content-row" appBoxRow>
@ -146,7 +144,7 @@
<b [hidden]="form.loading">{{ "submit" | i18n }}</b> <b [hidden]="form.loading">{{ "submit" | i18n }}</b>
<i class="bwi bwi-spinner bwi-spin" [hidden]="!form.loading" aria-hidden="true"></i> <i class="bwi bwi-spinner bwi-spin" [hidden]="!form.loading" aria-hidden="true"></i>
</button> </button>
<a routerLink="/login" class="btn block">{{ "cancel" | i18n }}</a> <a role="button" tabindex="0" routerLink="/login" class="btn block">{{ "cancel" | i18n }}</a>
</div> </div>
</div> </div>
</form> </form>

View File

@ -56,12 +56,11 @@
/> />
</div> </div>
<div class="action-buttons"> <div class="action-buttons">
<a <button
type="button"
class="row-btn" class="row-btn"
href="#"
appStopClick appStopClick
appBlurClick appBlurClick
role="button"
appA11yTitle="{{ 'toggleVisibility' | i18n }}" appA11yTitle="{{ 'toggleVisibility' | i18n }}"
[attr.aria-pressed]="showPassword" [attr.aria-pressed]="showPassword"
(click)="togglePassword(false)" (click)="togglePassword(false)"
@ -71,7 +70,7 @@
aria-hidden="true" aria-hidden="true"
[ngClass]="{ 'bwi-eye': !showPassword, 'bwi-eye-slash': showPassword }" [ngClass]="{ 'bwi-eye': !showPassword, 'bwi-eye-slash': showPassword }"
></i> ></i>
</a> </button>
</div> </div>
</div> </div>
<div class="progress"> <div class="progress">
@ -109,12 +108,11 @@
/> />
</div> </div>
<div class="action-buttons"> <div class="action-buttons">
<a <button
type="button"
class="row-btn" class="row-btn"
href="#"
appStopClick appStopClick
appBlurClick appBlurClick
role="button"
appA11yTitle="{{ 'toggleVisibility' | i18n }}" appA11yTitle="{{ 'toggleVisibility' | i18n }}"
[attr.aria-pressed]="showPassword" [attr.aria-pressed]="showPassword"
(click)="togglePassword(true)" (click)="togglePassword(true)"
@ -124,7 +122,7 @@
aria-hidden="true" aria-hidden="true"
[ngClass]="{ 'bwi-eye': !showPassword, 'bwi-eye-slash': showPassword }" [ngClass]="{ 'bwi-eye': !showPassword, 'bwi-eye-slash': showPassword }"
></i> ></i>
</a> </button>
</div> </div>
</div> </div>
</div> </div>

View File

@ -7,8 +7,8 @@
{{ "twoStepOptions" | i18n }} {{ "twoStepOptions" | i18n }}
</div> </div>
<div class="box-content"> <div class="box-content">
<a <button
href="#" type="button"
appStopClick appStopClick
*ngFor="let p of providers" *ngFor="let p of providers"
class="box-content-row" class="box-content-row"
@ -17,11 +17,11 @@
<img [src]="'images/two-factor/' + p.type + '.png'" alt="" class="img-right" /> <img [src]="'images/two-factor/' + p.type + '.png'" alt="" class="img-right" />
<span class="text">{{ p.name }}</span> <span class="text">{{ p.name }}</span>
<span class="detail">{{ p.description }}</span> <span class="detail">{{ p.description }}</span>
</a> </button>
<a href="#" appStopClick class="box-content-row" (click)="recover()"> <button type="button" appStopClick class="box-content-row" (click)="recover()">
<span class="text">{{ "recoveryCodeTitle" | i18n }}</span> <span class="text">{{ "recoveryCodeTitle" | i18n }}</span>
<span class="detail">{{ "recoveryCodeDesc" | i18n }}</span> <span class="detail">{{ "recoveryCodeDesc" | i18n }}</span>
</a> </button>
</div> </div>
</div> </div>
</div> </div>

View File

@ -124,22 +124,21 @@
> >
<i class="bwi bwi-spinner bwi-spin" [hidden]="!form.loading" aria-hidden="true"></i> <i class="bwi bwi-spinner bwi-spin" [hidden]="!form.loading" aria-hidden="true"></i>
</button> </button>
<a routerLink="/login" class="btn block">{{ "cancel" | i18n }}</a> <a role="button" tabindex="0" routerLink="/login" class="btn block">{{ "cancel" | i18n }}</a>
</div> </div>
<div class="sub-options"> <div class="sub-options">
<a href="#" appStopClick (click)="anotherMethod()" role="button">{{ <button type="button" appStopClick (click)="anotherMethod()">
"useAnotherTwoStepMethod" | i18n {{ "useAnotherTwoStepMethod" | i18n }}
}}</a> </button>
<a <button
href="#" type="button"
appStopClick appStopClick
(click)="sendEmail(true)" (click)="sendEmail(true)"
[appApiAction]="emailPromise" [appApiAction]="emailPromise"
role="button"
*ngIf="selectedProviderType === providerType.Email" *ngIf="selectedProviderType === providerType.Email"
> >
{{ "sendVerificationCodeEmailAgain" | i18n }} {{ "sendVerificationCodeEmailAgain" | i18n }}
</a> </button>
</div> </div>
</div> </div>
</form> </form>

View File

@ -36,12 +36,11 @@
/> />
</div> </div>
<div class="action-buttons"> <div class="action-buttons">
<a <button
type="button"
class="row-btn" class="row-btn"
href="#"
appStopClick appStopClick
appBlurClick appBlurClick
role="button"
appA11yTitle="{{ 'toggleVisibility' | i18n }}" appA11yTitle="{{ 'toggleVisibility' | i18n }}"
[attr.aria-pressed]="showPassword" [attr.aria-pressed]="showPassword"
(click)="togglePassword(false)" (click)="togglePassword(false)"
@ -51,7 +50,7 @@
aria-hidden="true" aria-hidden="true"
[ngClass]="{ 'bwi-eye': !showPassword, 'bwi-eye-slash': showPassword }" [ngClass]="{ 'bwi-eye': !showPassword, 'bwi-eye-slash': showPassword }"
></i> ></i>
</a> </button>
</div> </div>
</div> </div>
<div class="progress"> <div class="progress">
@ -84,12 +83,11 @@
/> />
</div> </div>
<div class="action-buttons"> <div class="action-buttons">
<a <button
type="button"
class="row-btn" class="row-btn"
href="#"
appStopClick appStopClick
appBlurClick appBlurClick
role="button"
appA11yTitle="{{ 'toggleVisibility' | i18n }}" appA11yTitle="{{ 'toggleVisibility' | i18n }}"
[attr.aria-pressed]="showPassword" [attr.aria-pressed]="showPassword"
(click)="togglePassword(true)" (click)="togglePassword(true)"
@ -99,7 +97,7 @@
aria-hidden="true" aria-hidden="true"
[ngClass]="{ 'bwi-eye': !showPassword, 'bwi-eye-slash': showPassword }" [ngClass]="{ 'bwi-eye': !showPassword, 'bwi-eye-slash': showPassword }"
></i> ></i>
</a> </button>
</div> </div>
</div> </div>
</div> </div>
@ -120,7 +118,7 @@
<b [hidden]="form.loading">{{ "submit" | i18n }}</b> <b [hidden]="form.loading">{{ "submit" | i18n }}</b>
<i class="bwi bwi-spinner bwi-spin" [hidden]="!form.loading" aria-hidden="true"></i> <i class="bwi bwi-spinner bwi-spin" [hidden]="!form.loading" aria-hidden="true"></i>
</button> </button>
<a (click)="logOut()" class="btn block">{{ "logOut" | i18n }}</a> <button type="button" (click)="logOut()" class="btn block">{{ "logOut" | i18n }}</button>
</div> </div>
</div> </div>
</form> </form>

View File

@ -19,12 +19,11 @@
/> />
</div> </div>
<div class="action-buttons"> <div class="action-buttons">
<a <button
type="button"
class="row-btn" class="row-btn"
href="#"
appStopClick appStopClick
appBlurClick appBlurClick
role="button"
appA11yTitle="{{ 'toggleVisibility' | i18n }}" appA11yTitle="{{ 'toggleVisibility' | i18n }}"
[attr.aria-pressed]="showPassword" [attr.aria-pressed]="showPassword"
(click)="togglePassword()" (click)="togglePassword()"
@ -34,7 +33,7 @@
aria-hidden="true" aria-hidden="true"
[ngClass]="{ 'bwi-eye': !showPassword, 'bwi-eye-slash': showPassword }" [ngClass]="{ 'bwi-eye': !showPassword, 'bwi-eye-slash': showPassword }"
></i> ></i>
</a> </button>
</div> </div>
</div> </div>
</div> </div>

View File

@ -22,9 +22,9 @@
/> />
</div> </div>
<div class="action-buttons"> <div class="action-buttons">
<a <button
type="button"
class="row-btn" class="row-btn"
href="#"
appStopClick appStopClick
appBlurClick appBlurClick
appA11yTitle="{{ 'toggleVisibility' | i18n }}" appA11yTitle="{{ 'toggleVisibility' | i18n }}"
@ -36,7 +36,7 @@
aria-hidden="true" aria-hidden="true"
[ngClass]="{ 'bwi-eye': !showPin, 'bwi-eye-slash': showPin }" [ngClass]="{ 'bwi-eye': !showPin, 'bwi-eye-slash': showPin }"
></i> ></i>
</a> </button>
</div> </div>
</div> </div>
</div> </div>

View File

@ -93,21 +93,21 @@
</div> </div>
<div class="box"> <div class="box">
<div class="box-header"> <div class="box-header">
{{ "options" | i18n }} <button
<a type="button"
class="toggle" class="toggle"
href="#"
appStopClick appStopClick
appBlurClick appBlurClick
role="button"
(click)="toggleOptions()" (click)="toggleOptions()"
[attr.aria-expanded]="showOptions"
> >
{{ "options" | i18n }}
<i <i
class="bwi bwi-lg" class="bwi bwi-lg"
aria-hidden="true" aria-hidden="true"
[ngClass]="{ 'bwi-angle-down': !showOptions, 'bwi-chevron-up': showOptions }" [ngClass]="{ 'bwi-angle-down': !showOptions, 'bwi-chevron-up': showOptions }"
></i> ></i>
</a> </button>
</div> </div>
</div> </div>
<div [hidden]="!showOptions"> <div [hidden]="!showOptions">
@ -157,12 +157,11 @@
/> />
</div> </div>
<div class="action-buttons"> <div class="action-buttons">
<a <button
type="button"
class="row-btn" class="row-btn"
href="#"
appStopClick appStopClick
appBlurClick appBlurClick
role="button"
appA11yTitle="{{ 'toggleVisibility' | i18n }}" appA11yTitle="{{ 'toggleVisibility' | i18n }}"
[attr.aria-pressed]="showPassword" [attr.aria-pressed]="showPassword"
(click)="togglePasswordVisible()" (click)="togglePasswordVisible()"
@ -173,7 +172,7 @@
aria-hidden="true" aria-hidden="true"
[ngClass]="{ 'bwi-eye': !showPassword, 'bwi-eye-slash': showPassword }" [ngClass]="{ 'bwi-eye': !showPassword, 'bwi-eye-slash': showPassword }"
></i> ></i>
</a> </button>
</div> </div>
</div> </div>
</div> </div>

View File

@ -5,26 +5,44 @@
<h2 class="sr-only">{{ "filters" | i18n }}</h2> <h2 class="sr-only">{{ "filters" | i18n }}</h2>
<ul> <ul>
<li [ngClass]="{ active: selectedAll }"> <li [ngClass]="{ active: selectedAll }">
<a href="#" appStopClick appBlurClick (click)="selectAll()"> <button
type="button"
appStopClick
appBlurClick
(click)="selectAll()"
[attr.aria-pressed]="selectedAll"
>
<i class="bwi bwi-fw bwi-filter" aria-hidden="true"></i>&nbsp;{{ "allSends" | i18n }} <i class="bwi bwi-fw bwi-filter" aria-hidden="true"></i>&nbsp;{{ "allSends" | i18n }}
</a> </button>
</li> </li>
</ul> </ul>
<h2>{{ "types" | i18n }}</h2> <h2>{{ "types" | i18n }}</h2>
<ul> <ul>
<li [ngClass]="{ active: selectedType === sendType.Text }"> <li [ngClass]="{ active: selectedType === sendType.Text }">
<a href="#" appStopClick appBlurClick (click)="selectType(sendType.Text)"> <button
type="button"
appStopClick
appBlurClick
(click)="selectType(sendType.Text)"
[attr.aria-pressed]="selectedType === sendType.Text"
>
<i class="bwi bwi-fw bwi-file-text" aria-hidden="true"></i>&nbsp;{{ <i class="bwi bwi-fw bwi-file-text" aria-hidden="true"></i>&nbsp;{{
"sendTypeText" | i18n "sendTypeText" | i18n
}} }}
</a> </button>
</li> </li>
<li [ngClass]="{ active: selectedType === sendType.File }"> <li [ngClass]="{ active: selectedType === sendType.File }">
<a href="#" appStopClick appBlurClick (click)="selectType(sendType.File)"> <button
type="button"
appStopClick
appBlurClick
(click)="selectType(sendType.File)"
[attr.aria-pressed]="selectedType === sendType.File"
>
<i class="bwi bwi-fw bwi-file" aria-hidden="true"></i>&nbsp;{{ <i class="bwi bwi-fw bwi-file" aria-hidden="true"></i>&nbsp;{{
"sendTypeFile" | i18n "sendTypeFile" | i18n
}} }}
</a> </button>
</li> </li>
</ul> </ul>
</div> </div>
@ -36,20 +54,21 @@
<div id="items" class="items"> <div id="items" class="items">
<div class="content"> <div class="content">
<div class="list" *ngIf="filteredSends.length"> <div class="list" *ngIf="filteredSends.length">
<a <button
*ngFor="let s of filteredSends" *ngFor="let s of filteredSends"
appStopClick appStopClick
(click)="selectSend(s.id)" (click)="selectSend(s.id)"
title="{{ 'viewItem' | i18n }}" title="{{ 'viewItem' | i18n }}"
(contextmenu)="viewSendMenu(s)" (contextmenu)="viewSendMenu(s)"
[ngClass]="{ active: s.id === sendId }" [ngClass]="{ active: s.id === sendId }"
[attr.aria-pressed]="s.id === sendId"
class="flex-list-item" class="flex-list-item"
> >
<div class="item-icon" aria-hidden="true"> <span class="item-icon" aria-hidden="true">
<i class="bwi bwi-fw bwi-lg" [ngClass]="s.type == 0 ? 'bwi-file-text' : 'bwi-file'"></i> <i class="bwi bwi-fw bwi-lg" [ngClass]="s.type == 0 ? 'bwi-file-text' : 'bwi-file'"></i>
</div> </span>
<div class="item-content"> <span class="item-content">
<div class="item-title"> <span class="item-title">
{{ s.name }} {{ s.name }}
<span class="title-badges"> <span class="title-badges">
<ng-container *ngIf="s.disabled"> <ng-container *ngIf="s.disabled">
@ -98,10 +117,10 @@
<span class="sr-only">{{ "pendingDeletion" | i18n }}</span> <span class="sr-only">{{ "pendingDeletion" | i18n }}</span>
</ng-container> </ng-container>
</span> </span>
</div> </span>
<span class="item-details">{{ s.deletionDate | date }}</span> <span class="item-details">{{ s.deletionDate | date }}</span>
</div> </span>
</a> </button>
</div> </div>
<div class="no-items" *ngIf="!filteredSends.length"> <div class="no-items" *ngIf="!filteredSends.length">
<i class="bwi bwi-spinner bwi-spin bwi-3x" *ngIf="!loaded" aria-hidden="true"></i> <i class="bwi bwi-spinner bwi-spin bwi-3x" *ngIf="!loaded" aria-hidden="true"></i>

View File

@ -10,15 +10,14 @@
*ngFor="let f of cipher.fields; let i = index; trackBy: trackByFunction" *ngFor="let f of cipher.fields; let i = index; trackBy: trackByFunction"
[ngClass]="{ 'box-content-row-checkbox': f.type === fieldType.Boolean }" [ngClass]="{ 'box-content-row-checkbox': f.type === fieldType.Boolean }"
> >
<a <button
href="#" type="button"
appStopClick appStopClick
(click)="removeField(f)" (click)="removeField(f)"
appA11yTitle="{{ 'remove' | i18n }}" appA11yTitle="{{ 'remove' | i18n }}"
role="button"
> >
<i class="bwi bwi-minus-circle bwi-lg" aria-hidden="true"></i> <i class="bwi bwi-minus-circle bwi-lg" aria-hidden="true"></i>
</a> </button>
<label for="fieldName{{ i }}" class="sr-only">{{ "name" | i18n }}</label> <label for="fieldName{{ i }}" class="sr-only">{{ "name" | i18n }}</label>
<label for="fieldValue{{ i }}" class="sr-only">{{ "value" | i18n }}</label> <label for="fieldValue{{ i }}" class="sr-only">{{ "value" | i18n }}</label>
<div class="row-main"> <div class="row-main">
@ -78,12 +77,11 @@
class="action-buttons" class="action-buttons"
*ngIf="f.type === fieldType.Hidden && (cipher.viewPassword || f.newField)" *ngIf="f.type === fieldType.Hidden && (cipher.viewPassword || f.newField)"
> >
<a <button
type="button"
class="row-btn" class="row-btn"
href="#"
appStopClick appStopClick
appBlurClick appBlurClick
role="button"
appA11yTitle="{{ 'toggleVisibility' | i18n }}" appA11yTitle="{{ 'toggleVisibility' | i18n }}"
[attr.aria-pressed]="f.showValue" [attr.aria-pressed]="f.showValue"
(click)="toggleFieldValue(f)" (click)="toggleFieldValue(f)"
@ -93,7 +91,7 @@
aria-hidden="true" aria-hidden="true"
[ngClass]="{ 'bwi-eye': !f.showValue, 'bwi-eye-slash': f.showValue }" [ngClass]="{ 'bwi-eye': !f.showValue, 'bwi-eye-slash': f.showValue }"
></i> ></i>
</a> </button>
</div> </div>
<div class="drag-handle" appA11yTitle="{{ 'dragToSort' | i18n }}" cdkDragHandle> <div class="drag-handle" appA11yTitle="{{ 'dragToSort' | i18n }}" cdkDragHandle>
<i class="bwi bwi-hamburger" aria-hidden="true"></i> <i class="bwi bwi-hamburger" aria-hidden="true"></i>
@ -102,10 +100,10 @@
</div> </div>
<!-- Add new custom field --> <!-- Add new custom field -->
<div class="box-content-row" appBoxRow> <div class="box-content-row" appBoxRow>
<a href="#" appStopClick (click)="addField()" role="button"> <button type="button" appStopClick (click)="addField()">
<i class="bwi bwi-plus-circle bwi-fw bwi-lg" aria-hidden="true"></i> <i class="bwi bwi-plus-circle bwi-fw bwi-lg" aria-hidden="true"></i>
{{ "newCustomField" | i18n }} {{ "newCustomField" | i18n }}
</a> </button>
<label for="addFieldType" class="sr-only">{{ "type" | i18n }}</label> <label for="addFieldType" class="sr-only">{{ "type" | i18n }}</label>
<select id="addFieldType" name="AddFieldType" [(ngModel)]="addFieldType" class="field-type"> <select id="addFieldType" name="AddFieldType" [(ngModel)]="addFieldType" class="field-type">
<option *ngFor="let o of addFieldTypeOptions" [ngValue]="o.value">{{ o.name }}</option> <option *ngFor="let o of addFieldTypeOptions" [ngValue]="o.value">{{ o.name }}</option>

View File

@ -87,12 +87,11 @@
aria-hidden="true" aria-hidden="true"
></i> ></i>
</button> </button>
<a <button
type="button"
class="row-btn" class="row-btn"
href="#"
appStopClick appStopClick
appBlurClick appBlurClick
role="button"
appA11yTitle="{{ 'toggleVisibility' | i18n }}" appA11yTitle="{{ 'toggleVisibility' | i18n }}"
[attr.aria-pressed]="showPassword" [attr.aria-pressed]="showPassword"
(click)="togglePassword()" (click)="togglePassword()"
@ -102,18 +101,17 @@
aria-hidden="true" aria-hidden="true"
[ngClass]="{ 'bwi-eye': !showPassword, 'bwi-eye-slash': showPassword }" [ngClass]="{ 'bwi-eye': !showPassword, 'bwi-eye-slash': showPassword }"
></i> ></i>
</a> </button>
<a <button
type="button"
class="row-btn" class="row-btn"
href="#"
appStopClick appStopClick
appBlurClick appBlurClick
role="button"
appA11yTitle="{{ 'generatePassword' | i18n }}" appA11yTitle="{{ 'generatePassword' | i18n }}"
(click)="generatePassword()" (click)="generatePassword()"
> >
<i class="bwi bwi-lg bwi-generate" aria-hidden="true"></i> <i class="bwi bwi-lg bwi-generate" aria-hidden="true"></i>
</a> </button>
</div> </div>
</div> </div>
<div class="box-content-row" appBoxRow> <div class="box-content-row" appBoxRow>
@ -153,12 +151,11 @@
/> />
</div> </div>
<div class="action-buttons"> <div class="action-buttons">
<a <button
type="button"
class="row-btn" class="row-btn"
href="#"
appStopClick appStopClick
appBlurClick appBlurClick
role="button"
appA11yTitle="{{ 'toggleVisibility' | i18n }}" appA11yTitle="{{ 'toggleVisibility' | i18n }}"
[attr.aria-pressed]="showCardNumber" [attr.aria-pressed]="showCardNumber"
(click)="toggleCardNumber()" (click)="toggleCardNumber()"
@ -168,7 +165,7 @@
aria-hidden="true" aria-hidden="true"
[ngClass]="{ 'bwi-eye': !showCardNumber, 'bwi-eye-slash': showCardNumber }" [ngClass]="{ 'bwi-eye': !showCardNumber, 'bwi-eye-slash': showCardNumber }"
></i> ></i>
</a> </button>
</div> </div>
</div> </div>
<div class="box-content-row" appBoxRow> <div class="box-content-row" appBoxRow>
@ -208,12 +205,11 @@
/> />
</div> </div>
<div class="action-buttons"> <div class="action-buttons">
<a <button
type="button"
class="row-btn" class="row-btn"
href="#"
appStopClick appStopClick
appBlurClick appBlurClick
role="button"
appA11yTitle="{{ 'toggleVisibility' | i18n }}" appA11yTitle="{{ 'toggleVisibility' | i18n }}"
[attr.aria-pressed]="showCardCode" [attr.aria-pressed]="showCardCode"
(click)="toggleCardCode()" (click)="toggleCardCode()"
@ -223,7 +219,7 @@
aria-hidden="true" aria-hidden="true"
[ngClass]="{ 'bwi-eye': !showCardCode, 'bwi-eye-slash': showCardCode }" [ngClass]="{ 'bwi-eye': !showCardCode, 'bwi-eye-slash': showCardCode }"
></i> ></i>
</a> </button>
</div> </div>
</div> </div>
</div> </div>
@ -406,9 +402,14 @@
appBoxRow appBoxRow
*ngFor="let u of cipher.login.uris; let i = index; trackBy: trackByFunction" *ngFor="let u of cipher.login.uris; let i = index; trackBy: trackByFunction"
> >
<a href="#" appStopClick (click)="removeUri(u)" appA11yTitle="{{ 'remove' | i18n }}"> <button
<i class="bwi bwi-minus-circle bwi-lg" aria-hidden="true" role="button"></i> type="button"
</a> appStopClick
(click)="removeUri(u)"
appA11yTitle="{{ 'remove' | i18n }}"
>
<i class="bwi bwi-minus-circle bwi-lg" aria-hidden="true"></i>
</button>
<div class="row-main"> <div class="row-main">
<label for="loginUri{{ i }}">{{ "uriPosition" | i18n: i + 1 }}</label> <label for="loginUri{{ i }}">{{ "uriPosition" | i18n: i + 1 }}</label>
<input <input
@ -435,31 +436,29 @@
</select> </select>
</div> </div>
<div class="action-buttons"> <div class="action-buttons">
<a <button
type="button"
class="row-btn" class="row-btn"
href="#"
appStopClick appStopClick
appBlurClick appBlurClick
role="button"
appA11yTitle="{{ 'toggleOptions' | i18n }}" appA11yTitle="{{ 'toggleOptions' | i18n }}"
(click)="toggleUriOptions(u)" (click)="toggleUriOptions(u)"
> >
<i class="bwi bwi-lg bwi-cog" aria-hidden="true"></i> <i class="bwi bwi-lg bwi-cog" aria-hidden="true"></i>
</a> </button>
</div> </div>
</div> </div>
</ng-container> </ng-container>
<a <button
href="#" type="button"
appStopClick appStopClick
appBlurClick appBlurClick
(click)="addUri()" (click)="addUri()"
class="box-content-row" class="box-content-row"
role="button"
> >
<i class="bwi bwi-plus-circle bwi-fw bwi-lg" aria-hidden="true"></i> <i class="bwi bwi-plus-circle bwi-fw bwi-lg" aria-hidden="true"></i>
{{ "newUri" | i18n }} {{ "newUri" | i18n }}
</a> </button>
</div> </div>
</div> </div>
<div class="box"> <div class="box">
@ -477,9 +476,13 @@
<div class="box-content-row box-content-row-checkbox" appBoxRow *ngIf="canUseReprompt"> <div class="box-content-row box-content-row-checkbox" appBoxRow *ngIf="canUseReprompt">
<label for="passwordPrompt" <label for="passwordPrompt"
>{{ "passwordPrompt" | i18n }} >{{ "passwordPrompt" | i18n }}
<a href="#" appA11yTitle="{{ 'learnMore' | i18n }}" (click)="openHelpReprompt()"> <button
type="button"
appA11yTitle="{{ 'learnMore' | i18n }}"
(click)="openHelpReprompt()"
>
<i class="bwi bwi-question-circle" aria-hidden="true"></i> <i class="bwi bwi-question-circle" aria-hidden="true"></i>
</a> </button>
</label> </label>
<input <input
id="passwordPrompt" id="passwordPrompt"
@ -489,30 +492,28 @@
(change)="repromptChanged()" (change)="repromptChanged()"
/> />
</div> </div>
<a <button
type="button"
class="box-content-row box-content-row-flex text-default" class="box-content-row box-content-row-flex text-default"
href="#"
appStopClick appStopClick
appBlurClick appBlurClick
(click)="attachments()" (click)="attachments()"
*ngIf="editMode && !cloneMode" *ngIf="editMode && !cloneMode"
role="button"
> >
<div class="row-main">{{ "attachments" | i18n }}</div> <div class="row-main">{{ "attachments" | i18n }}</div>
<i class="bwi bwi-angle-right row-sub-icon" aria-hidden="true"></i> <i class="bwi bwi-angle-right row-sub-icon" aria-hidden="true"></i>
</a> </button>
<a <button
type="button"
class="box-content-row box-content-row-flex text-default" class="box-content-row box-content-row-flex text-default"
href="#"
appStopClick appStopClick
appBlurClick appBlurClick
(click)="editCollections()" (click)="editCollections()"
*ngIf="editMode && !cloneMode && cipher.organizationId" *ngIf="editMode && !cloneMode && cipher.organizationId"
role="button"
> >
<div class="row-main">{{ "collections" | i18n }}</div> <div class="row-main">{{ "collections" | i18n }}</div>
<i class="bwi bwi-angle-right row-sub-icon" aria-hidden="true"></i> <i class="bwi bwi-angle-right row-sub-icon" aria-hidden="true"></i>
</a> </button>
</div> </div>
</div> </div>
<div class="box"> <div class="box">

View File

@ -6,14 +6,15 @@
*ngIf="ciphers.length" *ngIf="ciphers.length"
> >
<div class="list"> <div class="list">
<a <button
type="button"
*cdkVirtualFor="let c of ciphers; trackBy: trackByFn" *cdkVirtualFor="let c of ciphers; trackBy: trackByFn"
appStopClick appStopClick
(click)="selectCipher(c)" (click)="selectCipher(c)"
(contextmenu)="rightClickCipher(c)" (contextmenu)="rightClickCipher(c)"
href="#"
title="{{ 'viewItem' | i18n }}" title="{{ 'viewItem' | i18n }}"
[ngClass]="{ active: c.id === activeCipherId }" [ngClass]="{ active: c.id === activeCipherId }"
[attr.aria-pressed]="c.id === activeCipherId"
class="flex-list-item virtual-scroll-item" class="flex-list-item virtual-scroll-item"
> >
<app-vault-icon [cipher]="c"></app-vault-icon> <app-vault-icon [cipher]="c"></app-vault-icon>
@ -39,7 +40,7 @@
</span> </span>
<span *ngIf="c.subTitle" class="detail">{{ c.subTitle }}</span> <span *ngIf="c.subTitle" class="detail">{{ c.subTitle }}</span>
</div> </div>
</a> </button>
</div> </div>
</cdk-virtual-scroll-viewport> </cdk-virtual-scroll-viewport>
<div class="no-items" *ngIf="!ciphers.length"> <div class="no-items" *ngIf="!ciphers.length">

View File

@ -3,44 +3,86 @@
<h2 class="sr-only">{{ "filters" | i18n }}</h2> <h2 class="sr-only">{{ "filters" | i18n }}</h2>
<ul> <ul>
<li [ngClass]="{ active: selectedAll }"> <li [ngClass]="{ active: selectedAll }">
<a href="#" appStopClick appBlurClick (click)="selectAll()"> <button
type="button"
[attr.aria-pressed]="selectedAll"
appStopClick
appBlurClick
(click)="selectAll()"
>
<i class="bwi bwi-fw bwi-filter" aria-hidden="true"></i>&nbsp;{{ "allItems" | i18n }} <i class="bwi bwi-fw bwi-filter" aria-hidden="true"></i>&nbsp;{{ "allItems" | i18n }}
</a> </button>
</li> </li>
<li [ngClass]="{ active: selectedFavorites }"> <li [ngClass]="{ active: selectedFavorites }">
<a href="#" appStopClick appBlurClick (click)="selectFavorites()"> <button
type="button"
[attr.aria-pressed]="selectedFavorites"
appStopClick
appBlurClick
(click)="selectFavorites()"
>
<i class="bwi bwi-fw bwi-star" aria-hidden="true"></i>&nbsp;{{ "favorites" | i18n }} <i class="bwi bwi-fw bwi-star" aria-hidden="true"></i>&nbsp;{{ "favorites" | i18n }}
</a> </button>
</li> </li>
<li [ngClass]="{ active: selectedTrash }"> <li [ngClass]="{ active: selectedTrash }">
<a href="#" appStopClick appBlurClick (click)="selectTrash()"> <button
type="button"
[attr.aria-pressed]="selectedTrash"
appStopClick
appBlurClick
(click)="selectTrash()"
>
<i class="bwi bwi-fw bwi-trash" aria-hidden="true"></i>&nbsp;{{ "trash" | i18n }} <i class="bwi bwi-fw bwi-trash" aria-hidden="true"></i>&nbsp;{{ "trash" | i18n }}
</a> </button>
</li> </li>
</ul> </ul>
<h2>{{ "types" | i18n }}</h2> <h2>{{ "types" | i18n }}</h2>
<ul> <ul>
<li [ngClass]="{ active: selectedType === cipherType.Login }"> <li [ngClass]="{ active: selectedType === cipherType.Login }">
<a href="#" appStopClick appBlurClick (click)="selectType(cipherType.Login)"> <button
type="button"
[attr.aria-pressed]="selectedType === cipherType.Login"
appStopClick
appBlurClick
(click)="selectType(cipherType.Login)"
>
<i class="bwi bwi-fw bwi-globe" aria-hidden="true"></i>&nbsp;{{ "typeLogin" | i18n }} <i class="bwi bwi-fw bwi-globe" aria-hidden="true"></i>&nbsp;{{ "typeLogin" | i18n }}
</a> </button>
</li> </li>
<li [ngClass]="{ active: selectedType === cipherType.Card }"> <li [ngClass]="{ active: selectedType === cipherType.Card }">
<a href="#" appStopClick appBlurClick (click)="selectType(cipherType.Card)"> <button
type="button"
[attr.aria-pressed]="selectedType === cipherType.Card"
appStopClick
appBlurClick
(click)="selectType(cipherType.Card)"
>
<i class="bwi bwi-fw bwi-credit-card" aria-hidden="true"></i>&nbsp;{{ "typeCard" | i18n }} <i class="bwi bwi-fw bwi-credit-card" aria-hidden="true"></i>&nbsp;{{ "typeCard" | i18n }}
</a> </button>
</li> </li>
<li [ngClass]="{ active: selectedType === cipherType.Identity }"> <li [ngClass]="{ active: selectedType === cipherType.Identity }">
<a href="#" appStopClick appBlurClick (click)="selectType(cipherType.Identity)"> <button
type="button"
[attr.aria-pressed]="selectedType === cipherType.Identity"
appStopClick
appBlurClick
(click)="selectType(cipherType.Identity)"
>
<i class="bwi bwi-fw bwi-id-card" aria-hidden="true"></i>&nbsp;{{ "typeIdentity" | i18n }} <i class="bwi bwi-fw bwi-id-card" aria-hidden="true"></i>&nbsp;{{ "typeIdentity" | i18n }}
</a> </button>
</li> </li>
<li [ngClass]="{ active: selectedType === cipherType.SecureNote }"> <li [ngClass]="{ active: selectedType === cipherType.SecureNote }">
<a href="#" appStopClick appBlurClick (click)="selectType(cipherType.SecureNote)"> <button
type="button"
[attr.aria-pressed]="selectedType === cipherType.SecureNote"
appStopClick
appBlurClick
(click)="selectType(cipherType.SecureNote)"
>
<i class="bwi bwi-fw bwi-sticky-note" aria-hidden="true"></i>&nbsp;{{ <i class="bwi bwi-fw bwi-sticky-note" aria-hidden="true"></i>&nbsp;{{
"typeSecureNote" | i18n "typeSecureNote" | i18n
}} }}
</a> </button>
</li> </li>
</ul> </ul>
<p *ngIf="!loaded" class="text-muted">{{ "loading" | i18n }}</p> <p *ngIf="!loaded" class="text-muted">{{ "loading" | i18n }}</p>
@ -57,7 +99,13 @@
*ngFor="let f of folders" *ngFor="let f of folders"
[ngClass]="{ active: selectedFolder && f.node.id === selectedFolderId }" [ngClass]="{ active: selectedFolder && f.node.id === selectedFolderId }"
> >
<a href="#" appStopClick appBlurClick (click)="selectFolder(f.node)"> <button
type="button"
[attr.aria-pressed]="selectedFolder && f.node.id === selectedFolderId"
appStopClick
appBlurClick
(click)="selectFolder(f.node)"
>
<i <i
*ngIf="f.children.length" *ngIf="f.children.length"
class="bwi bwi-fw" class="bwi bwi-fw"
@ -86,7 +134,7 @@
> >
<i class="bwi bwi-pencil bwi-fw" aria-hidden="true"></i> <i class="bwi bwi-pencil bwi-fw" aria-hidden="true"></i>
</span> </span>
</a> </button>
<ul class="bwi-ul" *ngIf="f.children.length && !isCollapsed(f.node)"> <ul class="bwi-ul" *ngIf="f.children.length && !isCollapsed(f.node)">
<ng-container <ng-container
*ngTemplateOutlet="recursiveFolders; context: { $implicit: f.children }" *ngTemplateOutlet="recursiveFolders; context: { $implicit: f.children }"
@ -107,7 +155,14 @@
*ngFor="let c of collections" *ngFor="let c of collections"
[ngClass]="{ active: c.node.id === selectedCollectionId }" [ngClass]="{ active: c.node.id === selectedCollectionId }"
> >
<a href="#" appStopClick appBlurClick (click)="selectCollection(c.node)"> <button
*ngIf="c.children.length == 0"
type="button"
[attr.aria-pressed]="c.node.id === selectedCollectionId"
appStopClick
appBlurClick
(click)="selectCollection(c.node)"
>
<i <i
*ngIf="c.children.length" *ngIf="c.children.length"
class="bwi bwi-fw" class="bwi bwi-fw"
@ -126,7 +181,7 @@
aria-hidden="true" aria-hidden="true"
></i> ></i>
&nbsp;{{ c.node.name }} &nbsp;{{ c.node.name }}
</a> </button>
<ul class="bwi-ul" *ngIf="c.children.length && !isCollapsed(c.node)"> <ul class="bwi-ul" *ngIf="c.children.length && !isCollapsed(c.node)">
<ng-container <ng-container
*ngTemplateOutlet="recursiveCollections; context: { $implicit: c.children }" *ngTemplateOutlet="recursiveCollections; context: { $implicit: c.children }"

View File

@ -17,16 +17,15 @@
<span class="detail">{{ h.date | date: "medium" }}</span> <span class="detail">{{ h.date | date: "medium" }}</span>
</div> </div>
<div class="action-buttons"> <div class="action-buttons">
<a <button
type="button"
class="row-btn" class="row-btn"
href="#"
appStopClick appStopClick
appA11yTitle="{{ 'copyPassword' | i18n }}" appA11yTitle="{{ 'copyPassword' | i18n }}"
(click)="copy(h.password)" (click)="copy(h.password)"
role="button"
> >
<i class="bwi bwi-lg bwi-clone" aria-hidden="true"></i> <i class="bwi bwi-lg bwi-clone" aria-hidden="true"></i>
</a> </button>
</div> </div>
</div> </div>
<div class="box-content-row" *ngIf="!history.length"> <div class="box-content-row" *ngIf="!history.length">

View File

@ -15,16 +15,15 @@
<span class="detail">{{ h.lastUsedDate | date: "medium" }}</span> <span class="detail">{{ h.lastUsedDate | date: "medium" }}</span>
</div> </div>
<div class="action-buttons"> <div class="action-buttons">
<a <button
type="button"
class="row-btn" class="row-btn"
href="#"
appStopClick appStopClick
appA11yTitle="{{ 'copyPassword' | i18n }}" appA11yTitle="{{ 'copyPassword' | i18n }}"
(click)="copy(h.password)" (click)="copy(h.password)"
role="button"
> >
<i class="bwi bwi-lg bwi-clone" aria-hidden="true"></i> <i class="bwi bwi-lg bwi-clone" aria-hidden="true"></i>
</a> </button>
</div> </div>
</div> </div>
<div class="box-content-row" *ngIf="!history.length"> <div class="box-content-row" *ngIf="!history.length">

View File

@ -35,24 +35,23 @@
</div> </div>
</div> </div>
<div class="action-buttons"> <div class="action-buttons">
<a <button
type="button"
class="row-btn" class="row-btn"
href="#"
appStopClick appStopClick
appA11yTitle="{{ 'toggleVisibility' | i18n }}" appA11yTitle="{{ 'toggleVisibility' | i18n }}"
*ngIf="field.type === fieldType.Hidden && cipher.viewPassword" *ngIf="field.type === fieldType.Hidden && cipher.viewPassword"
(click)="toggleFieldValue(field)" (click)="toggleFieldValue(field)"
role="button"
> >
<i <i
class="bwi bwi-lg" class="bwi bwi-lg"
aria-hidden="true" aria-hidden="true"
[ngClass]="{ 'bwi-eye': !field.showValue, 'bwi-eye-slash': field.showValue }" [ngClass]="{ 'bwi-eye': !field.showValue, 'bwi-eye-slash': field.showValue }"
></i> ></i>
</a> </button>
<a <button
type="button"
class="row-btn" class="row-btn"
href="#"
appStopClick appStopClick
appA11yTitle="{{ 'copyValue' | i18n }}" appA11yTitle="{{ 'copyValue' | i18n }}"
*ngIf=" *ngIf="
@ -64,10 +63,9 @@
(click)=" (click)="
copy(field.value, 'value', field.type === fieldType.Hidden ? 'H_Field' : 'Field') copy(field.value, 'value', field.type === fieldType.Hidden ? 'H_Field' : 'Field')
" "
role="button"
> >
<i class="bwi bwi-lg bwi-clone" aria-hidden="true"></i> <i class="bwi bwi-lg bwi-clone" aria-hidden="true"></i>
</a> </button>
</div> </div>
</div> </div>
</div> </div>

View File

@ -22,16 +22,15 @@
{{ cipher.login.username }} {{ cipher.login.username }}
</div> </div>
<div class="action-buttons"> <div class="action-buttons">
<a <button
type="button"
class="row-btn" class="row-btn"
href="#"
appStopClick appStopClick
appA11yTitle="{{ 'copyUsername' | i18n }}" appA11yTitle="{{ 'copyUsername' | i18n }}"
(click)="copy(cipher.login.username, 'username', 'Username')" (click)="copy(cipher.login.username, 'username', 'Username')"
role="button"
> >
<i class="bwi bwi-lg bwi-clone" aria-hidden="true"></i> <i class="bwi bwi-lg bwi-clone" aria-hidden="true"></i>
</a> </button>
</div> </div>
</div> </div>
<div class="box-content-row box-content-row-flex" *ngIf="cipher.login.password"> <div class="box-content-row box-content-row-flex" *ngIf="cipher.login.password">
@ -74,31 +73,29 @@
aria-hidden="true" aria-hidden="true"
></i> ></i>
</button> </button>
<a <button
type="button"
class="row-btn" class="row-btn"
href="#"
appStopClick appStopClick
appA11yTitle="{{ 'toggleVisibility' | i18n }}" appA11yTitle="{{ 'toggleVisibility' | i18n }}"
[attr.aria-pressed]="showPassword" [attr.aria-pressed]="showPassword"
(click)="togglePassword()" (click)="togglePassword()"
role="button"
> >
<i <i
class="bwi bwi-lg" class="bwi bwi-lg"
aria-hidden="true" aria-hidden="true"
[ngClass]="{ 'bwi-eye': !showPassword, 'bwi-eye-slash': showPassword }" [ngClass]="{ 'bwi-eye': !showPassword, 'bwi-eye-slash': showPassword }"
></i> ></i>
</a> </button>
<a <button
type="button"
class="row-btn" class="row-btn"
href="#"
appStopClick appStopClick
appA11yTitle="{{ 'copyPassword' | i18n }}" appA11yTitle="{{ 'copyPassword' | i18n }}"
(click)="copy(cipher.login.password, 'password', 'Password')" (click)="copy(cipher.login.password, 'password', 'Password')"
role="button"
> >
<i class="bwi bwi-lg bwi-clone" aria-hidden="true"></i> <i class="bwi bwi-lg bwi-clone" aria-hidden="true"></i>
</a> </button>
</div> </div>
</div> </div>
<div <div
@ -131,16 +128,15 @@
</svg> </svg>
</span> </span>
<div class="action-buttons"> <div class="action-buttons">
<a <button
type="button"
class="row-btn" class="row-btn"
href="#"
appStopClick appStopClick
appA11yTitle="{{ 'copyValue' | i18n }}" appA11yTitle="{{ 'copyValue' | i18n }}"
(click)="copy(totpCode, 'verificationCodeTotp', 'TOTP')" (click)="copy(totpCode, 'verificationCodeTotp', 'TOTP')"
role="button"
> >
<i class="bwi bwi-lg bwi-clone" aria-hidden="true"></i> <i class="bwi bwi-lg bwi-clone" aria-hidden="true"></i>
</a> </button>
</div> </div>
</div> </div>
</div> </div>
@ -157,31 +153,29 @@
<span *ngIf="showCardNumber" class="monospaced">{{ cipher.card.number }}</span> <span *ngIf="showCardNumber" class="monospaced">{{ cipher.card.number }}</span>
</div> </div>
<div class="action-buttons"> <div class="action-buttons">
<a <button
type="button"
class="row-btn" class="row-btn"
href="#"
appStopClick appStopClick
appA11yTitle="{{ 'toggleVisibility' | i18n }}" appA11yTitle="{{ 'toggleVisibility' | i18n }}"
[attr.aria-pressed]="showCardNumber" [attr.aria-pressed]="showCardNumber"
(click)="toggleCardNumber()" (click)="toggleCardNumber()"
role="button"
> >
<i <i
class="bwi bwi-lg" class="bwi bwi-lg"
aria-hidden="true" aria-hidden="true"
[ngClass]="{ 'bwi-eye': !showCardNumber, 'bwi-eye-slash': showCardNumber }" [ngClass]="{ 'bwi-eye': !showCardNumber, 'bwi-eye-slash': showCardNumber }"
></i> ></i>
</a> </button>
<a <button
type="button"
class="row-btn" class="row-btn"
href="#"
appStopClick appStopClick
appA11yTitle="{{ 'copyNumber' | i18n }}" appA11yTitle="{{ 'copyNumber' | i18n }}"
(click)="copy(cipher.card.number, 'number', 'Card Number')" (click)="copy(cipher.card.number, 'number', 'Card Number')"
role="button"
> >
<i class="bwi bwi-lg bwi-clone" aria-hidden="true"></i> <i class="bwi bwi-lg bwi-clone" aria-hidden="true"></i>
</a> </button>
</div> </div>
</div> </div>
<div class="box-content-row" *ngIf="cipher.card.brand"> <div class="box-content-row" *ngIf="cipher.card.brand">
@ -199,31 +193,29 @@
<span *ngIf="showCardCode" class="monospaced">{{ cipher.card.code }}</span> <span *ngIf="showCardCode" class="monospaced">{{ cipher.card.code }}</span>
</div> </div>
<div class="action-buttons"> <div class="action-buttons">
<a <button
type="button"
class="row-btn" class="row-btn"
href="#"
appStopClick appStopClick
appA11yTitle="{{ 'toggleVisibility' | i18n }}" appA11yTitle="{{ 'toggleVisibility' | i18n }}"
[attr.aria-pressed]="showCardCode" [attr.aria-pressed]="showCardCode"
(click)="toggleCardCode()" (click)="toggleCardCode()"
role="button"
> >
<i <i
class="bwi bwi-lg" class="bwi bwi-lg"
aria-hidden="true" aria-hidden="true"
[ngClass]="{ 'bwi-eye': !showCardCode, 'bwi-eye-slash': showCardCode }" [ngClass]="{ 'bwi-eye': !showCardCode, 'bwi-eye-slash': showCardCode }"
></i> ></i>
</a> </button>
<a <button
type="button"
class="row-btn" class="row-btn"
href="#"
appStopClick appStopClick
appA11yTitle="{{ 'copySecurityCode' | i18n }}" appA11yTitle="{{ 'copySecurityCode' | i18n }}"
(click)="copy(cipher.card.code, 'securityCode', 'Security Code')" (click)="copy(cipher.card.code, 'securityCode', 'Security Code')"
role="button"
> >
<i class="bwi bwi-lg bwi-clone" aria-hidden="true"></i> <i class="bwi bwi-lg bwi-clone" aria-hidden="true"></i>
</a> </button>
</div> </div>
</div> </div>
</div> </div>
@ -289,27 +281,25 @@
<span title="{{ u.uri }}">{{ u.hostOrUri }}</span> <span title="{{ u.uri }}">{{ u.hostOrUri }}</span>
</div> </div>
<div class="action-buttons"> <div class="action-buttons">
<a <button
type="button"
class="row-btn" class="row-btn"
href="#"
appStopClick appStopClick
appA11yTitle="{{ 'launch' | i18n }}" appA11yTitle="{{ 'launch' | i18n }}"
*ngIf="u.canLaunch" *ngIf="u.canLaunch"
(click)="launch(u)" (click)="launch(u)"
role="button"
> >
<i class="bwi bwi-lg bwi-share-square" aria-hidden="true"></i> <i class="bwi bwi-lg bwi-share-square" aria-hidden="true"></i>
</a> </button>
<a <button
type="button"
class="row-btn" class="row-btn"
href="#"
appStopClick appStopClick
appA11yTitle="{{ 'copyUri' | i18n }}" appA11yTitle="{{ 'copyUri' | i18n }}"
(click)="copy(u.uri, u.isWebsite ? 'website' : 'uri', 'URI')" (click)="copy(u.uri, u.isWebsite ? 'website' : 'uri', 'URI')"
role="button"
> >
<i class="bwi bwi-lg bwi-clone" aria-hidden="true"></i> <i class="bwi bwi-lg bwi-clone" aria-hidden="true"></i>
</a> </button>
</div> </div>
</div> </div>
</div> </div>
@ -334,10 +324,10 @@
{{ "attachments" | i18n }} {{ "attachments" | i18n }}
</div> </div>
<div class="box-content"> <div class="box-content">
<a <button
type="button"
class="box-content-row box-content-row-flex text-default" class="box-content-row box-content-row-flex text-default"
*ngFor="let attachment of cipher.attachments" *ngFor="let attachment of cipher.attachments"
href="#"
appStopClick appStopClick
appBlurCLick appBlurCLick
(click)="downloadAttachment(attachment)" (click)="downloadAttachment(attachment)"
@ -354,7 +344,7 @@
*ngIf="attachment.downloading" *ngIf="attachment.downloading"
aria-hidden="true" aria-hidden="true"
></i> ></i>
</a> </button>
</div> </div>
</div> </div>
<div class="box"> <div class="box">
@ -369,15 +359,14 @@
</div> </div>
<div *ngIf="cipher.hasPasswordHistory"> <div *ngIf="cipher.hasPasswordHistory">
<b class="font-weight-semibold">{{ "passwordHistory" | i18n }}:</b> <b class="font-weight-semibold">{{ "passwordHistory" | i18n }}:</b>
<a <button
href="#" type="button"
(click)="viewHistory()" (click)="viewHistory()"
appStopClick appStopClick
role="button"
appA11yTitle="{{ 'passwordHistory' | i18n }}, {{ cipher.passwordHistory.length }}" appA11yTitle="{{ 'passwordHistory' | i18n }}, {{ cipher.passwordHistory.length }}"
> >
<span aria-hidden="true">{{ cipher.passwordHistory.length }}</span> <span aria-hidden="true">{{ cipher.passwordHistory.length }}</span>
</a> </button>
</div> </div>
</div> </div>
</div> </div>

View File

@ -84,6 +84,9 @@ button {
} }
button { button {
border: none;
background: transparent;
color: inherit;
white-space: nowrap; white-space: nowrap;
cursor: pointer; cursor: pointer;
} }

View File

@ -105,9 +105,11 @@
.box-content-row { .box-content-row {
display: block; display: block;
width: 100%;
padding: 10px 15px; padding: 10px 15px;
position: relative; position: relative;
z-index: 1; z-index: 1;
text-align: left;
&:before { &:before {
content: ""; content: "";
@ -232,7 +234,8 @@
margin-top: 5px; margin-top: 5px;
} }
> a { > a,
> button {
padding: 8px 8px 8px 4px; padding: 8px 8px 8px 4px;
margin: 0; margin: 0;
@ -366,7 +369,7 @@
&:not(.box-draggable-row) { &:not(.box-draggable-row) {
.action-buttons .row-btn:last-child { .action-buttons .row-btn:last-child {
padding-right: 2px !important; margin-right: -6px !important;
} }
} }

View File

@ -1,10 +1,8 @@
@import "variables.scss"; @import "variables.scss";
.list > a { .list > button {
display: block;
padding: 3px 10px; padding: 3px 10px;
text-decoration: none; text-decoration: none;
position: relative;
user-select: none; user-select: none;
z-index: 1; z-index: 1;
@ -105,11 +103,14 @@
} }
} }
.list > a.flex-list-item { .list > button.flex-list-item {
display: flex; display: flex;
align-items: center; align-items: center;
width: 100%;
text-align: left;
.item-icon { .item-icon {
display: block;
margin-left: -5px; margin-left: -5px;
margin-right: 4px; margin-right: 4px;
@include themify($themes) { @include themify($themes) {
@ -118,7 +119,9 @@
} }
.item-content { .item-content {
display: block;
.item-title { .item-title {
display: block;
.title-badges { .title-badges {
@include themify($themes) { @include themify($themes) {
color: themed("mutedColor"); color: themed("mutedColor");
@ -135,12 +138,12 @@
} }
.flex-cipher-list-item { .flex-cipher-list-item {
flex-direction: column;
flex-wrap: nowrap;
justify-content: center;
align-items: flex-start;
white-space: nowrap; white-space: nowrap;
overflow: hidden; overflow: hidden;
text-overflow: ellipsis; text-overflow: ellipsis;
> * {
text-align: left;
}
} }
} }

View File

@ -129,7 +129,7 @@ app-root {
ul.bwi-ul { ul.bwi-ul {
// Level 1 // Level 1
li { li {
> a { > button {
padding-left: 12px; padding-left: 12px;
} }
@ -137,14 +137,14 @@ app-root {
left: -4px; left: -4px;
} }
&.active > a .bwi-li { &.active > button .bwi-li {
left: 11px; left: 11px;
} }
} }
// Level 2 // Level 2
ul li { ul li {
> a { > button {
padding-left: 23px; padding-left: 23px;
} }
@ -152,14 +152,14 @@ app-root {
left: 7px; left: 7px;
} }
&.active > a .bwi-li { &.active > button .bwi-li {
left: 22px; left: 22px;
} }
} }
// Level 3 // Level 3
ul ul li { ul ul li {
> a { > button {
padding-left: 34px; padding-left: 34px;
} }
@ -167,14 +167,14 @@ app-root {
left: 18px; left: 18px;
} }
&.active > a .bwi-li { &.active > button .bwi-li {
left: 33px; left: 33px;
} }
} }
// Level 4 // Level 4
ul ul ul li { ul ul ul li {
> a { > button {
padding-left: 45px; padding-left: 45px;
} }
@ -182,14 +182,14 @@ app-root {
left: 29px; left: 29px;
} }
&.active > a .bwi-li { &.active > button .bwi-li {
left: 44px; left: 44px;
} }
} }
// Level 5 // Level 5
ul ul ul ul li { ul ul ul ul li {
> a { > button {
padding-left: 56px; padding-left: 56px;
} }
@ -197,14 +197,14 @@ app-root {
left: 40px; left: 40px;
} }
&.active > a .bwi-li { &.active > button .bwi-li {
left: 55px; left: 55px;
} }
} }
// Level 6 // Level 6
ul ul ul ul ul li { ul ul ul ul ul li {
> a { > button {
padding-left: 67px; padding-left: 67px;
} }
@ -212,14 +212,14 @@ app-root {
left: 51px; left: 51px;
} }
&.active > a .bwi-li { &.active > button .bwi-li {
left: 66px; left: 66px;
} }
} }
// Level 7 // Level 7
ul ul ul ul ul ul li { ul ul ul ul ul ul li {
> a { > button {
padding-left: 78px; padding-left: 78px;
} }
@ -227,7 +227,7 @@ app-root {
left: 62px; left: 62px;
} }
&.active > a .bwi-li { &.active > button .bwi-li {
left: 77px; left: 77px;
} }
} }
@ -238,10 +238,11 @@ app-root {
margin: 0; margin: 0;
li { li {
a { button {
padding: 5px 0; padding: 5px 0;
display: flex; display: flex;
align-items: center; align-items: center;
width: 100%;
@include themify($themes) { @include themify($themes) {
color: themed("textColor"); color: themed("textColor");