[PS-1692] Use `aria-describedby` for all help blocks/hints (#3802)

* Use aria-describedby for all help blocks/hints

* Add label to send notes textfield

* Use aria-describedby for all help blocks/hints / browser

* Tweak help block for confirming identity

* Remove aria-describedby for general login form

Seems unnecessary / doesn't need an extra description

* Fix compiler error

* Remove unnecessary aria-describedby

After testing, turns out the addition here was unnecessary, as the help block is already part of the `<label>`

* Fix aria-describedby reference for user verification component

* Remove redundant aria-describedby and generated id for radio buttons

* Fix aria-describedby for send editing in Safari

> When editing a send, the text below the deletion date is not recognized by the screen reader reliably (send-add-edit.component.html / efflux-dates.component.html). There might be an issues depending on which browser is used (deletionDateHelp vs. deletionDateCustomHelp

* Make custom environment container role="group", give it a label and description

> In the Environment Url Settings, the text “For advanced users…….“ is not not recognized by the screen reader. Not sure how to best solve this one, as it's below all individual url inputs. Ideally it gets announced with the baseUrl part or when focusing Custom Environment)
This commit is contained in:
Patrick H. Lauke 2022-12-21 19:48:22 +00:00 committed by GitHub
parent 9ed195c9f9
commit 7d3063942e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
36 changed files with 269 additions and 111 deletions

View File

@ -36,13 +36,14 @@
id="baseUrl"
type="text"
name="BaseUrl"
aria-describedby="baseUrlHelp"
[(ngModel)]="baseUrl"
placeholder="ex. https://bitwarden.company.com"
appInputVerbatim
/>
</div>
</div>
<div class="box-footer">
<div id="baseUrlHelp" class="box-footer">
{{ "selfHostedEnvironmentFooter" | i18n }}
</div>
</div>
@ -50,7 +51,13 @@
<h2 class="box-header">
{{ "customEnvironment" | i18n }}
</h2>
<div class="box-content" [hidden]="!showCustom">
<div
role="group"
attr.aria-label="{{ 'customEnvironment' | i18n }}"
aria-describedby="customEnvironmentHelp"
class="box-content"
[hidden]="!showCustom"
>
<div class="box-content-row" appBoxRow>
<label for="webVaultUrl">{{ "webVaultUrl" | i18n }}</label>
<input
@ -107,7 +114,7 @@
/>
</div>
</div>
<div class="box-footer" [hidden]="!showCustom">
<div id="customEnvironmentHelp" class="box-footer" [hidden]="!showCustom">
{{ "customEnvironmentFooter" | i18n }}
</div>
</div>

View File

@ -24,6 +24,7 @@
id="email"
type="text"
name="Email"
aria-describedby="emailHelp"
[(ngModel)]="email"
required
appAutofocus
@ -32,7 +33,7 @@
/>
</div>
</div>
<div class="box-footer">
<div id="emailHelp" class="box-footer">
{{ "enterEmailToGetHint" | i18n }}
</div>
</div>

View File

@ -30,6 +30,7 @@
id="masterPassword"
type="{{ showPassword ? 'text' : 'password' }}"
name="MasterPassword"
aria-describedby="masterPasswordHelp"
class="monospaced"
[(ngModel)]="masterPassword"
required
@ -54,7 +55,7 @@
</div>
</div>
</div>
<div class="box-footer">
<div id="masterPasswordHelp" class="box-footer">
<p>{{ "yourVaultIsLocked" | i18n }}</p>
{{ "loggedInAsOn" | i18n: email:webVaultHostname }}
</div>

View File

@ -32,6 +32,7 @@
<input
id="masterPassword"
type="{{ showPassword ? 'text' : 'password' }}"
aria-describedby="masterPasswordHelp"
class="monospaced"
formControlName="masterPassword"
appInputVerbatim
@ -64,7 +65,7 @@
</app-password-strength>
</div>
</div>
<div class="box-footer">
<div id="masterPasswordHelp" class="box-footer">
{{ "masterPassDesc" | i18n }}
</div>
</div>
@ -100,10 +101,10 @@
</div>
<div class="box-content-row" appBoxRow>
<label for="hint">{{ "masterPassHint" | i18n }}</label>
<input id="hint" type="text" formControlName="hint" />
<input id="hint" type="text" aria-describedby="hintHelp" formControlName="hint" />
</div>
</div>
<div class="box-footer">
<div id="hintHelp" class="box-footer">
{{ "masterPassHintDesc" | i18n }}
</div>
</div>

View File

@ -49,6 +49,7 @@
id="masterPassword"
type="{{ showPassword ? 'text' : 'password' }}"
name="MasterPassword"
aria-describedby="masterPasswordHelp"
class="monospaced"
[(ngModel)]="masterPassword"
required
@ -82,7 +83,7 @@
</app-password-strength>
</div>
</div>
<div class="box-footer">
<div id="masterPasswordHelp" class="box-footer">
{{ "masterPassDesc" | i18n }}
</div>
</div>
@ -127,10 +128,16 @@
<div class="box-content">
<div class="box-content-row" appBoxRow>
<label for="hint">{{ "masterPassHint" | i18n }}</label>
<input id="hint" type="text" name="Hint" [(ngModel)]="hint" />
<input
id="hint"
type="text"
name="Hint"
aria-describedby="hintHelp"
[(ngModel)]="hint"
/>
</div>
</div>
<div class="box-footer">
<div id="hintHelp" class="box-footer">
{{ "masterPassHintDesc" | i18n }}
</div>
</div>

View File

@ -109,10 +109,10 @@
<div class="box-content">
<div class="box-content-row" appBoxRow>
<label for="hint">{{ "masterPassHint" | i18n }}</label>
<input id="hint" type="text" name="Hint" [(ngModel)]="hint" />
<input id="hint" type="text" name="Hint" aria-describedby="hintHelp" [(ngModel)]="hint" />
</div>
</div>
<div class="box-footer">
<div id="hintHelp" class="box-footer">
{{ "masterPassHintDesc" | i18n }}
</div>
</div>

View File

@ -12,6 +12,7 @@
id="masterPassword"
type="{{ showPassword ? 'text' : 'password' }}"
name="MasterPassword"
aria-describedby="masterPasswordHelp"
class="monospaced"
[(ngModel)]="masterPassword"
required
@ -36,7 +37,7 @@
</div>
</div>
</div>
<div class="box-footer">
<div id="masterPasswordHelp" class="box-footer">
{{ "passwordConfirmationDesc" | i18n }}
</div>
</div>

View File

@ -5,6 +5,7 @@
id="masterPassword"
type="password"
name="MasterPasswordHash"
aria-describedby="confirmIdentityHelp"
class="form-control"
[formControl]="secret"
required

View File

@ -312,7 +312,9 @@
/>
<label for="type_{{ o.value }}">
{{ o.name }}
<div class="small text-muted" *ngIf="o.desc">{{ o.desc }}</div>
<div class="small text-muted" *ngIf="o.desc">
{{ o.desc }}
</div>
</label>
</div>
</div>

View File

@ -7,6 +7,7 @@
<select
id="deletionDate"
name="DeletionDateSelect"
aria-describedby="deletionDateHelp"
formControlName="selectedDeletionDatePreset"
required
>
@ -22,7 +23,7 @@
<ng-container *ngTemplateOutlet="deletionDateCustom"></ng-container>
</div>
</div>
<div class="box-footer">
<div id="deletionDateHelp" class="box-footer">
{{ "deletionDateDesc" | i18n }}
<ng-container
*ngIf="
@ -45,6 +46,7 @@
<select
id="expirationDate"
name="ExpirationDateSelect"
aria-describedby="expirationDateHelp"
formControlName="selectedExpirationDatePreset"
required
>
@ -67,7 +69,7 @@
<ng-container *ngTemplateOutlet="expirationDateCustom"></ng-container>
</div>
</div>
<div class="box-footer">
<div id="expirationDateHelp" class="box-footer">
{{ "expirationDateDesc" | i18n }}
<ng-container
*ngIf="
@ -90,6 +92,7 @@
id="deletionDateCustomFallback"
type="date"
name="DeletionDateFallback"
aria-describedby="deletionDateHelp"
formControlName="fallbackDeletionDate"
required
placeholder="MM/DD/YYYY"
@ -113,6 +116,7 @@
id="deletionDateCustomFallback"
type="date"
name="DeletionDateFallback"
aria-describedby="deletionDateHelp"
formControlName="fallbackDeletionDate"
required
placeholder="MM/DD/YYYY"
@ -135,6 +139,7 @@
id="deletionDateCustom"
type="datetime-local"
name="DeletionDate"
aria-describedby="deletionDateHelp"
formControlName="defaultDeletionDateTime"
required
placeholder="MM/DD/YYYY HH:MM AM/PM"
@ -150,6 +155,7 @@
id="expirationDateCustomFallback"
type="date"
name="ExpirationDateFallback"
aria-describedby="expirationDateHelp"
formControlName="fallbackExpirationDate"
[required]="!editMode"
placeholder="MM/DD/YYYY"
@ -173,6 +179,7 @@
id="expirationDateCustomFallback"
type="date"
name="ExpirationDateFallback"
aria-describedby="expirationDateHelp"
formControlName="fallbackExpirationDate"
[required]="!editMode"
placeholder="MM/DD/YYYY"
@ -198,6 +205,7 @@
id="expirationDateCustom"
type="datetime-local"
name="ExpirationDate"
aria-describedby="expirationDateHelp"
formControlName="defaultExpirationDateTime"
required
placeholder="MM/DD/YYYY HH:MM AM/PM"

View File

@ -43,12 +43,13 @@
id="name"
type="text"
name="Name"
aria-describedby="nameHelp"
[(ngModel)]="send.name"
[readonly]="disableSend"
/>
</div>
</div>
<div class="box-footer">
<div id="nameHelp" class="box-footer">
{{ "sendNameDesc" | i18n }}
</div>
</div>
@ -89,10 +90,17 @@
</div>
<div class="box-content-row" *ngIf="showFileSelector">
<label for="file">{{ "file" | i18n }}</label>
<input type="file" id="file" name="file" required [readonly]="disableSend" />
<input
type="file"
id="file"
name="file"
aria-describedby="fileHelp"
required
[readonly]="disableSend"
/>
</div>
</div>
<div class="box-footer" *ngIf="showFileSelector">
<div id="fileHelp" class="box-footer" *ngIf="showFileSelector">
{{ "sendFileDesc" | i18n }} {{ "maxFileSize" | i18n }}
</div>
</div>
@ -104,13 +112,14 @@
<textarea
id="text"
name="Text"
aria-describedby="textHelp"
rows="6"
[(ngModel)]="send.text.text"
[readonly]="disableSend"
></textarea>
</div>
</div>
<div class="box-footer">
<div id="textHelp" class="box-footer">
{{ "sendTextDesc" | i18n }}
</div>
<div class="box-content">
@ -180,12 +189,13 @@
min="1"
type="number"
name="MaximumAccessCount"
aria-describedby="maximumAccessCountHelp"
[(ngModel)]="send.maxAccessCount"
[readonly]="disableSend"
/>
</div>
</div>
<div class="box-footer">
<div id="maximumAccessCountHelp" class="box-footer">
{{ "maximumAccessCountDesc" | i18n }}
</div>
</div>
@ -215,6 +225,7 @@
id="password"
type="{{ showPassword ? 'text' : 'password' }}"
name="Password"
aria-describedby="passwordHelp"
class="monospaced"
[(ngModel)]="password"
appInputVerbatim
@ -239,7 +250,7 @@
</div>
</div>
</div>
<div class="box-footer">
<div id="passwordHelp" class="box-footer">
{{ "sendPasswordDesc" | i18n }}
</div>
</div>
@ -251,13 +262,14 @@
<textarea
id="notes"
name="Notes"
aria-describedby="notesHelp"
rows="6"
[(ngModel)]="send.notes"
[readonly]="disableSend"
></textarea>
</div>
</div>
<div class="box-footer">
<div id="notesHelp" class="box-footer">
{{ "sendNotesDesc" | i18n }}
</div>
</div>

View File

@ -32,7 +32,7 @@
<app-user-verification ngDefaultControl formControlName="secret" name="Secret">
</app-user-verification>
</div>
<div class="box-footer">
<div id="confirmIdentityHelp" class="box-footer">
<p>{{ "confirmIdentity" | i18n }}</p>
</div>
</div>

View File

@ -33,6 +33,7 @@
<select
id="defaultUriMatch"
name="DefaultUriMatch"
aria-describedby="defaultUriMatchHelp"
[(ngModel)]="defaultUriMatch"
(change)="saveDefaultUriMatch()"
>
@ -40,7 +41,9 @@
</select>
</div>
</div>
<div class="box-footer">{{ "defaultUriMatchDetectionDesc" | i18n }}</div>
<div id="defaultUriMatchHelp" class="box-footer">
{{ "defaultUriMatchDetectionDesc" | i18n }}
</div>
</div>
<div class="box" *ngIf="showClearClipboard">
<div class="box-content">
@ -49,6 +52,7 @@
<select
id="clearClipboard"
name="ClearClipboard"
aria-describedby="clearClipboardHelp"
[(ngModel)]="clearClipboard"
(change)="saveClearClipboard()"
>
@ -58,7 +62,7 @@
</select>
</div>
</div>
<div class="box-footer">{{ "clearClipboardDesc" | i18n }}</div>
<div id="clearClipboardHelp" class="box-footer">{{ "clearClipboardDesc" | i18n }}</div>
</div>
<div class="box">
<div class="box-content">
@ -67,12 +71,13 @@
<input
id="totp"
type="checkbox"
aria-describedby="totpHelp"
(change)="updateAutoTotpCopy()"
[(ngModel)]="enableAutoTotpCopy"
/>
</div>
</div>
<div class="box-footer">{{ "disableAutoTotpCopyDesc" | i18n }}</div>
<div id="totpHelp" class="box-footer">{{ "disableAutoTotpCopyDesc" | i18n }}</div>
</div>
<div class="box">
<div class="box-content">
@ -81,12 +86,15 @@
<input
id="addlogin-notification-bar"
type="checkbox"
aria-describedby="addlogin-notification-barHelp"
(change)="updateAddLoginNotification()"
[(ngModel)]="enableAddLoginNotification"
/>
</div>
</div>
<div class="box-footer">{{ "addLoginNotificationDesc" | i18n }}</div>
<div id="addlogin-notification-barHelp" class="box-footer">
{{ "addLoginNotificationDesc" | i18n }}
</div>
</div>
<div class="box">
<div class="box-content">
@ -97,12 +105,15 @@
<input
id="changedpass-notification-bar"
type="checkbox"
aria-describedby="changedpass-notification-barHelp"
(change)="updateChangedPasswordNotification()"
[(ngModel)]="enableChangedPasswordNotification"
/>
</div>
</div>
<div class="box-footer">{{ "changedPasswordNotificationDesc" | i18n }}</div>
<div id="changedpass-notification-barHelp" class="box-footer">
{{ "changedPasswordNotificationDesc" | i18n }}
</div>
</div>
<div class="box">
<div class="box-content">
@ -111,12 +122,13 @@
<input
id="context-menu"
type="checkbox"
aria-describedby="context-menuHelp"
(change)="updateContextMenuItem()"
[(ngModel)]="enableContextMenuItem"
/>
</div>
</div>
<div class="box-footer">{{ "contextMenuItemDesc" | i18n }}</div>
<div id="context-menuHelp" class="box-footer">{{ "contextMenuItemDesc" | i18n }}</div>
</div>
</ng-container>
<div class="box box-section-divider">
@ -141,12 +153,15 @@
<input
id="showCardsCurrentTab"
type="checkbox"
aria-describedby="showCardsCurrentTabHelp"
(change)="updateShowCardsCurrentTab()"
[(ngModel)]="showCardsCurrentTab"
/>
</div>
</div>
<div class="box-footer">{{ "showCardsCurrentTabDesc" | i18n }}</div>
<div id="showCardsCurrentTabHelp" class="box-footer">
{{ "showCardsCurrentTabDesc" | i18n }}
</div>
</div>
<div class="box">
<div class="box-content">
@ -155,12 +170,15 @@
<input
id="showIdentitiesCurrentTab"
type="checkbox"
aria-describedby="showIdentitiesCurrentTabHelp"
(change)="updateShowIdentitiesCurrentTab()"
[(ngModel)]="showIdentitiesCurrentTab"
/>
</div>
</div>
<div class="box-footer">{{ "showIdentitiesCurrentTabDesc" | i18n }}</div>
<div id="showIdentitiesCurrentTabHelp" class="box-footer">
{{ "showIdentitiesCurrentTabDesc" | i18n }}
</div>
</div>
<div class="box">
<div class="box-content">
@ -169,12 +187,13 @@
<input
id="favicon"
type="checkbox"
aria-describedby="faviconHelp"
(change)="updateFavicon()"
[(ngModel)]="enableFavicon"
/>
</div>
</div>
<div class="box-footer">{{ "faviconDesc" | i18n }}</div>
<div id="faviconHelp" class="box-footer">{{ "faviconDesc" | i18n }}</div>
</div>
<div class="box">
<div class="box-content">
@ -183,23 +202,30 @@
<input
id="badge"
type="checkbox"
aria-describedby="badgeHelp"
(change)="updateBadgeCounter()"
[(ngModel)]="enableBadgeCounter"
/>
</div>
</div>
<div class="box-footer">{{ "badgeCounterDesc" | i18n }}</div>
<div id="badgeHelp" class="box-footer">{{ "badgeCounterDesc" | i18n }}</div>
</div>
<div class="box">
<div class="box-content">
<div class="box-content-row" appBoxRow>
<label for="theme">{{ "theme" | i18n }}</label>
<select id="theme" name="Theme" [(ngModel)]="theme" (change)="saveTheme()">
<select
id="theme"
name="Theme"
aria-describedby="themeHelp"
[(ngModel)]="theme"
(change)="saveTheme()"
>
<option *ngFor="let o of themeOptions" [ngValue]="o.value">{{ o.name }}</option>
</select>
</div>
</div>
<div class="box-footer">{{ "themeDesc" | i18n }}</div>
<div id="themeHelp" class="box-footer">{{ "themeDesc" | i18n }}</div>
</div>
</ng-container>
<div class="box box-section-divider">
@ -224,12 +250,13 @@
<input
id="autofill"
type="checkbox"
aria-describedby="autofillHelp"
(change)="updateAutoFillOnPageLoad()"
[(ngModel)]="enableAutoFillOnPageLoad"
/>
</div>
</div>
<div class="box-footer">
<div id="autofillHelp" class="box-footer">
{{ "enableAutoFillOnPageLoadDesc" | i18n }}
<b>{{ "warning" | i18n }}</b
>: {{ "experimentalFeature" | i18n }}
@ -242,6 +269,7 @@
<select
id="defaultAutofill"
name="DefaultAutofill"
aria-describedby="defaultAutofillHelp"
[(ngModel)]="autoFillOnPageLoadDefault"
(change)="updateAutoFillOnPageLoadDefault()"
[disabled]="!enableAutoFillOnPageLoad"
@ -252,7 +280,9 @@
</select>
</div>
</div>
<div class="box-footer">{{ "defaultAutoFillOnPageLoadDesc" | i18n }}</div>
<div id="defaultAutofillHelp" class="box-footer">
{{ "defaultAutoFillOnPageLoadDesc" | i18n }}
</div>
</div>
</ng-container>
</main>

View File

@ -221,6 +221,7 @@
</button>
<button
type="button"
aria-describedby="rateExtensionHelp"
class="box-content-row box-content-row-flex text-default"
appStopClick
(click)="rate()"
@ -229,6 +230,6 @@
<i class="bwi bwi-angle-right bwi-lg row-sub-icon" aria-hidden="true"></i>
</button>
</div>
<div class="box-footer">{{ "rateExtensionDesc" | i18n }}</div>
<div id="rateExtensionHelp" class="box-footer">{{ "rateExtensionDesc" | i18n }}</div>
</div>
</main>

View File

@ -15,6 +15,7 @@
<button
type="button"
class="btn block primary"
aria-describedby="lastSyncHint"
(click)="sync()"
#syncBtn
[disabled]="$any(syncBtn).loading"
@ -27,6 +28,8 @@
aria-hidden="true"
></i>
</button>
<p class="text-center text-muted small">{{ "lastSync" | i18n }} {{ lastSync }}</p>
<p id="lastSyncHint" class="text-center text-muted small">
{{ "lastSync" | i18n }} {{ lastSync }}
</p>
</div>
</main>

View File

@ -61,10 +61,10 @@
<div class="box-content no-hover">
<div class="box-content-row">
<label for="file">{{ "file" | i18n }}</label>
<input type="file" id="file" name="file" required />
<input type="file" id="file" name="file" aria-describedby="fileHelp" required />
</div>
</div>
<div class="box-footer">
<div id="fileHelp" class="box-footer">
{{ "maxFileSize" | i18n }}
</div>
</div>

View File

@ -35,6 +35,7 @@
<select
id="organization"
name="OrganizationId"
aria-describedby="organizationHelp"
[(ngModel)]="organizationId"
(change)="filterCollections()"
>
@ -42,7 +43,7 @@
</select>
</div>
</div>
<div class="box-footer">
<div id="organizationHelp" class="box-footer">
{{ "moveToOrgDesc" | i18n }}
</div>
</div>

View File

@ -14,6 +14,7 @@
id="link"
type="text"
name="Link"
aria-describedby="linkHelp"
formControlName="link"
placeholder="{{ 'ex' | i18n }} https://accounts.hcaptcha.com/verify_email"
appAutofocus
@ -21,7 +22,7 @@
/>
</div>
</div>
<div class="box-footer">{{ "enterhCaptchaUrl" | i18n }}</div>
<div id="linkHelp" class="box-footer">{{ "enterhCaptchaUrl" | i18n }}</div>
</div>
<div class="buttons">
<button type="submit" class="btn primary block" [disabled]="!accessibilityForm.valid">

View File

@ -24,6 +24,9 @@
>
</app-user-verification>
</div>
<div id="confirmIdentityHelp" class="box-footer">
<p>{{ "confirmIdentity" | i18n }}</p>
</div>
</div>
</div>
<div class="modal-footer">

View File

@ -13,13 +13,14 @@
id="baseUrl"
type="text"
name="BaseUrl"
aria-describedby="baseUrlHelp"
[(ngModel)]="baseUrl"
placeholder="{{ 'ex' | i18n }} https://bitwarden.company.com"
appInputVerbatim
/>
</div>
</div>
<div class="box-footer">
<div id="baseUrlHelp" class="box-footer">
{{ "selfHostedEnvironmentFooter" | i18n }}
</div>
</div>
@ -34,7 +35,13 @@
{{ "customEnvironment" | i18n }}
</button>
</h2>
<div class="box-content" [hidden]="!showCustom">
<div
role="group"
attr.aria-label="{{ 'customEnvironment' | i18n }}"
aria-describedby="customEnvironmentHelp"
class="box-content"
[hidden]="!showCustom"
>
<div class="box-content-row" appBoxRow>
<label for="webVaultUrl">{{ "webVaultUrl" | i18n }}</label>
<input
@ -80,7 +87,7 @@
/>
</div>
</div>
<div class="box-footer" [hidden]="!showCustom">
<div id="customEnvironmentHelp" class="box-footer" [hidden]="!showCustom">
{{ "customEnvironmentFooter" | i18n }}
</div>
</div>

View File

@ -9,6 +9,7 @@
id="email"
type="text"
name="Email"
aria-describedby="emailHelp"
[(ngModel)]="email"
required
appAutofocus
@ -16,7 +17,7 @@
/>
</div>
</div>
<div class="box-footer">
<div id="emailHelp" class="box-footer">
{{ "enterEmailToGetHint" | i18n }}
</div>
</div>

View File

@ -23,6 +23,7 @@
id="masterPassword"
type="{{ showPassword ? 'text' : 'password' }}"
name="MasterPassword"
aria-describedby="masterPasswordHelp"
class="monospaced"
[(ngModel)]="masterPassword"
required
@ -47,7 +48,7 @@
</div>
</div>
</div>
<div class="box-footer">
<div id="masterPasswordHelp" class="box-footer">
{{ "loggedInAsOn" | i18n: email:webVaultHostname }}
</div>
</div>

View File

@ -26,6 +26,7 @@
id="masterPassword"
type="{{ showPassword ? 'text' : 'password' }}"
class="monospaced"
aria-describedby="masterPasswordHelp"
formControlName="masterPassword"
appInputVerbatim
/>
@ -57,7 +58,7 @@
</app-password-strength>
</div>
</div>
<div class="box-footer">
<div id="masterPasswordHelp" class="box-footer">
{{ "masterPassDesc" | i18n }}
</div>
</div>
@ -93,7 +94,7 @@
</div>
<div class="box-content-row" appBoxRow>
<label for="hint">{{ "masterPassHint" | i18n }}</label>
<input id="hint" type="text" formControlName="hint" />
<input id="hint" type="text" aria-describedby="hintHelp" formControlName="hint" />
</div>
<div class="box last" [hidden]="!showCaptcha()">
<div class="box-content">
@ -107,7 +108,7 @@
</div>
</div>
</div>
<div class="box-footer">
<div id="hintHelp" class="box-footer">
{{ "masterPassHintDesc" | i18n }}
</div>
</div>

View File

@ -46,6 +46,7 @@
type="{{ showPassword ? 'text' : 'password' }}"
name="MasterPassword"
class="monospaced"
aria-describedby="masterPasswordHelp"
[(ngModel)]="masterPassword"
required
appInputVerbatim
@ -77,7 +78,7 @@
</app-password-strength>
</div>
</div>
<div class="box-footer">
<div id="masterPasswordHelp" class="box-footer">
{{ "masterPassDesc" | i18n }}
</div>
</div>
@ -122,10 +123,16 @@
<div class="box-content">
<div class="box-content-row" appBoxRow>
<label for="hint">{{ "masterPassHint" | i18n }}</label>
<input id="hint" type="text" name="Hint" [(ngModel)]="hint" />
<input
id="hint"
type="text"
name="Hint"
aria-describedby="hintHelp"
[(ngModel)]="hint"
/>
</div>
</div>
<div class="box-footer">
<div id="hintHelp" class="box-footer">
{{ "masterPassHintDesc" | i18n }}
</div>
</div>

View File

@ -44,13 +44,16 @@
name="VaultTimeoutAction"
id="vaultTimeoutActionLock"
value="lock"
aria-describedby="vaultTimeoutActionLockHelp"
[(ngModel)]="vaultTimeoutAction"
(change)="saveVaultTimeoutOptions()"
/>
{{ "lock" | i18n }}
</label>
</div>
<small class="help-block">{{ "vaultTimeoutActionLockDesc" | i18n }}</small>
<small id="vaultTimeoutActionLockHelp" class="help-block">{{
"vaultTimeoutActionLockDesc" | i18n
}}</small>
<div class="radio">
<label for="vaultTimeoutActionLogOut">
<input
@ -58,13 +61,16 @@
name="VaultTimeoutAction"
id="vaultTimeoutActionLogOut"
value="logOut"
aria-describedby="vaultTimeoutActionLogOutHelp"
[(ngModel)]="vaultTimeoutAction"
(change)="saveVaultTimeoutOptions()"
/>
{{ "logOut" | i18n }}
</label>
</div>
<small class="help-block">{{ "vaultTimeoutActionLogOutDesc" | i18n }}</small>
<small id="vaultTimeoutActionLogOutHelp" class="help-block">{{
"vaultTimeoutActionLogOutDesc" | i18n
}}</small>
</div>
<div class="form-group">
<div class="checkbox">
@ -139,6 +145,7 @@
<select
id="clearClipboard"
name="ClearClipboard"
aria-describedby="clearClipboardHelp"
[(ngModel)]="clearClipboard"
(change)="saveClearClipboard()"
>
@ -146,7 +153,9 @@
{{ o.name }}
</option>
</select>
<small class="help-block">{{ "clearClipboardDesc" | i18n }}</small>
<small id="clearClipboardHelp" class="help-block">{{
"clearClipboardDesc" | i18n
}}</small>
</div>
<div class="form-group">
<div class="checkbox">
@ -155,13 +164,16 @@
id="minimizeOnCopyToClipboard"
type="checkbox"
name="MinimizeOnCopyToClipboard"
aria-describedby="minimizeOnCopyToClipboardHelp"
[(ngModel)]="minimizeOnCopyToClipboard"
(change)="saveMinOnCopyToClipboard()"
/>
{{ "minimizeOnCopyToClipboard" | i18n }}
</label>
</div>
<small class="help-block">{{ "minimizeOnCopyToClipboardDesc" | i18n }}</small>
<small id="minimizeOnCopyToClipboardHelp" class="help-block">{{
"minimizeOnCopyToClipboardDesc" | i18n
}}</small>
</div>
<div class="form-group">
<div class="checkbox">
@ -170,13 +182,14 @@
id="enableFavicons"
type="checkbox"
name="enableFavicons"
aria-describedby="enableFaviconsHelp"
[(ngModel)]="enableFavicons"
(change)="saveFavicons()"
/>
{{ "enableFavicon" | i18n }}
</label>
</div>
<small class="help-block">{{ "faviconDesc" | i18n }}</small>
<small id="enableFaviconsHelp" class="help-block">{{ "faviconDesc" | i18n }}</small>
</div>
</ng-container>
</div>
@ -211,13 +224,14 @@
id="enableTray"
type="checkbox"
name="EnableTray"
aria-describedby="enableTrayHelp"
[(ngModel)]="enableTray"
(change)="saveTray()"
/>
{{ enableTrayText }}
</label>
</div>
<small class="help-block">{{ enableTrayDescText }}</small>
<small id="enableTrayHelp" class="help-block">{{ enableTrayDescText }}</small>
</div>
<div class="form-group" *ngIf="showMinToTray">
<div class="checkbox">
@ -226,13 +240,16 @@
id="enableMinToTray"
type="checkbox"
name="EnableMinToTray"
aria-describedby="enableMinToTrayHelp"
[(ngModel)]="enableMinToTray"
(change)="saveMinToTray()"
/>
{{ enableMinToTrayText }}
</label>
</div>
<small class="help-block">{{ enableMinToTrayDescText }}</small>
<small id="enableMinToTrayHelp" class="help-block">{{
enableMinToTrayDescText
}}</small>
</div>
<div class="form-group">
<div class="checkbox">
@ -241,13 +258,16 @@
id="enableCloseToTray"
type="checkbox"
name="EnableCloseToTray"
aria-describedby="enableCloseToTrayHelp"
[(ngModel)]="enableCloseToTray"
(change)="saveCloseToTray()"
/>
{{ enableCloseToTrayText }}
</label>
</div>
<small class="help-block">{{ enableCloseToTrayDescText }}</small>
<small id="enableCloseToTrayHelp" class="help-block">{{
enableCloseToTrayDescText
}}</small>
</div>
<div class="form-group">
<div class="checkbox">
@ -256,13 +276,14 @@
id="startToTray"
type="checkbox"
name="StartToTray"
aria-describedby="startToTrayHelp"
[(ngModel)]="startToTray"
(change)="saveStartToTray()"
/>
{{ startToTrayText }}
</label>
</div>
<small class="help-block">{{ startToTrayDescText }}</small>
<small id="startToTrayHelp" class="help-block">{{ startToTrayDescText }}</small>
</div>
<div class="form-group">
<div class="checkbox">
@ -271,13 +292,16 @@
id="openAtLogin"
type="checkbox"
name="OpenAtLogin"
aria-describedby="openAtLoginHelp"
[(ngModel)]="openAtLogin"
(change)="saveOpenAtLogin()"
/>
{{ "openAtLogin" | i18n }}
</label>
</div>
<small class="help-block">{{ "openAtLoginDesc" | i18n }}</small>
<small id="openAtLoginHelp" class="help-block">{{
"openAtLoginDesc" | i18n
}}</small>
</div>
<div class="form-group" *ngIf="showAlwaysShowDock">
<div class="checkbox">
@ -286,13 +310,16 @@
id="alwaysShowDock"
type="checkbox"
name="AlwaysShowDock"
aria-describedby="alwaysShowDockHelp"
[(ngModel)]="alwaysShowDock"
(change)="saveAlwaysShowDock()"
/>
{{ "alwaysShowDock" | i18n }}
</label>
</div>
<small class="help-block">{{ "alwaysShowDockDesc" | i18n }}</small>
<small id="alwaysShowDockHelp" class="help-block">{{
"alwaysShowDockDesc" | i18n
}}</small>
</div>
<div class="form-group">
<div class="checkbox">
@ -301,13 +328,16 @@
id="enableBrowserIntegration"
type="checkbox"
name="EnableBrowserIntegration"
aria-describedby="enableBrowserIntegrationHelp"
[(ngModel)]="enableBrowserIntegration"
(change)="saveBrowserIntegration()"
/>
{{ "enableBrowserIntegration" | i18n }}
</label>
</div>
<small class="help-block">{{ "enableBrowserIntegrationDesc" | i18n }}</small>
<small id="enableBrowserIntegrationHelp" class="help-block">{{
"enableBrowserIntegrationDesc" | i18n
}}</small>
</div>
<div class="form-group">
<div class="checkbox">
@ -316,6 +346,7 @@
id="enableBrowserIntegrationFingerprint"
type="checkbox"
name="EnableBrowserIntegrationFingerprint"
aria-describedby="enableBrowserIntegrationFingerprintHelp"
[(ngModel)]="enableBrowserIntegrationFingerprint"
(change)="saveBrowserIntegrationFingerprint()"
[disabled]="!enableBrowserIntegration"
@ -323,7 +354,7 @@
{{ "enableBrowserIntegrationFingerprint" | i18n }}
</label>
</div>
<small class="help-block">{{
<small id="enableBrowserIntegrationFingerprintHelp" class="help-block">{{
"enableBrowserIntegrationFingerprintDesc" | i18n
}}</small>
</div>
@ -346,17 +377,29 @@
</div>
<div class="form-group">
<label for="theme">{{ "theme" | i18n }}</label>
<select id="theme" name="Theme" [(ngModel)]="theme" (change)="saveTheme()">
<select
id="theme"
name="Theme"
aria-describedby="themeHelp"
[(ngModel)]="theme"
(change)="saveTheme()"
>
<option *ngFor="let o of themeOptions" [ngValue]="o.value">{{ o.name }}</option>
</select>
<small class="help-block">{{ "themeDesc" | i18n }}</small>
<small id="themeHelp" class="help-block">{{ "themeDesc" | i18n }}</small>
</div>
<div class="form-group">
<label for="locale">{{ "language" | i18n }}</label>
<select id="locale" name="Locale" [(ngModel)]="locale" (change)="saveLocale()">
<select
id="locale"
name="Locale"
aria-describedby="localeHelp"
[(ngModel)]="locale"
(change)="saveLocale()"
>
<option *ngFor="let o of localeOptions" [ngValue]="o.value">{{ o.name }}</option>
</select>
<small class="help-block">{{ "languageDesc" | i18n }}</small>
<small id="localeHelp" class="help-block">{{ "languageDesc" | i18n }}</small>
</div>
</ng-container>
</div>

View File

@ -96,10 +96,10 @@
<div class="box-content">
<div class="box-content-row" appBoxRow>
<label for="hint">{{ "masterPassHint" | i18n }}</label>
<input id="hint" type="text" name="Hint" [(ngModel)]="hint" />
<input id="hint" type="text" name="Hint" aria-describedby="hintHelp" [(ngModel)]="hint" />
</div>
</div>
<div class="box-footer">
<div id="hintHelp" class="box-footer">
{{ "masterPassHintDesc" | i18n }}
</div>
</div>

View File

@ -8,12 +8,13 @@
<select
id="vaultTimeout"
name="VaultTimeout"
aria-describedby="vaultTimeoutHelp"
formControlName="vaultTimeout"
class="form-control"
>
<option *ngFor="let o of vaultTimeouts" [ngValue]="o.value">{{ o.name }}</option>
</select>
<small class="form-text text-muted">{{ "vaultTimeoutDesc" | i18n }}</small>
<small id="vaultTimeoutHelp" class="help-block">{{ "vaultTimeoutDesc" | i18n }}</small>
</div>
<div class="form-group row" *ngIf="showCustom" formGroupName="custom">
<div class="col">

View File

@ -14,6 +14,7 @@
id="masterPassword"
type="{{ showPassword ? 'text' : 'password' }}"
name="MasterPassword"
aria-describedby="masterPasswordHelp"
class="monospaced"
[(ngModel)]="masterPassword"
required
@ -38,7 +39,7 @@
</div>
</div>
</div>
<div class="box-footer">
<div id="masterPasswordHelp" class="box-footer">
{{ "passwordConfirmationDesc" | i18n }}
</div>
</div>

View File

@ -5,6 +5,7 @@
id="masterPassword"
type="password"
name="MasterPasswordHash"
aria-describedby="confirmIdentityHelp"
class="form-control"
[formControl]="secret"
required
@ -36,6 +37,7 @@
id="verificationCode"
type="input"
name="verificationCode"
aria-describedby="confirmIdentityHelp"
class="form-control"
[formControl]="secret"
required

View File

@ -51,6 +51,7 @@
id="file"
class="form-control-file"
name="file"
aria-describedby="fileHelp"
required
[disabled]="disableSend"
/>
@ -64,16 +65,17 @@
<textarea
id="text"
name="text"
aria-describedby="textHelp"
[(ngModel)]="send.text.text"
rows="6"
[readOnly]="disableSend"
></textarea>
</div>
</div>
<div class="box-footer" *ngIf="!editMode && send.type === sendType.File">
<div id="fileHelp" class="box-footer" *ngIf="!editMode && send.type === sendType.File">
{{ "sendFileDesc" | i18n }} {{ "maxFileSize" | i18n }}
</div>
<div class="box-footer" *ngIf="send.type === sendType.Text">
<div id="textHelp" class="box-footer" *ngIf="send.type === sendType.Text">
{{ "sendTextDesc" | i18n }}
</div>
</div>
@ -126,15 +128,16 @@
id="maxAccessCount"
type="number"
name="maxAccessCount"
aria-describedby="maxAccessCountHelp"
[(ngModel)]="send.maxAccessCount"
[readOnly]="disableSend"
/>
</div>
</div>
<div class="box-footer" *ngIf="!editMode">
<div id="maxAccessCountHelp" class="box-footer" *ngIf="!editMode">
{{ "maxAccessCountDesc" | i18n }}
</div>
<div class="box-footer" *ngIf="editMode">
<div id="maxAccessCountHelp" class="box-footer" *ngIf="editMode">
<p>{{ "maxAccessCountDesc" | i18n }}</p>
{{ "currentAccessCount" | i18n }}: <strong>{{ send.accessCount }}</strong>
</div>
@ -149,6 +152,7 @@
<input
id="password"
name="password"
aria-describedby="passwordHelp"
type="{{ showPassword ? 'text' : 'password' }}"
[(ngModel)]="password"
[readOnly]="disableSend"
@ -174,26 +178,27 @@
</div>
</div>
</div>
<div class="box-footer">
<div id="passwordHelp" class="box-footer">
{{ "sendPasswordDesc" | i18n }}
</div>
</div>
<div class="box">
<h2 class="box-header">
{{ "notes" | i18n }}
<label for="notes">{{ "notes" | i18n }}</label>
</h2>
<div class="box-content">
<div class="box-content-row" appBoxRow>
<textarea
id="notes"
name="notes"
aria-describedby="notesHelp"
[(ngModel)]="send.notes"
rows="6"
[readOnly]="disableSend"
></textarea>
</div>
</div>
<div class="box-footer">
<div id="notesHelp" class="box-footer">
{{ "sendNotesDesc" | i18n }}
</div>
</div>

View File

@ -6,12 +6,13 @@
<select
id="deletionDate"
name="DeletionDateSelect"
aria-describedby="deletionDateHelp"
formControlName="selectedDeletionDatePreset"
required
>
<option *ngFor="let o of deletionDatePresets" [ngValue]="o.value">{{ o.name }}</option>
</select>
<small class="help-block">{{ "deletionDateDesc" | i18n }}</small>
<small id="deletionDateHelp" class="help-block">{{ "deletionDateDesc" | i18n }}</small>
</div>
<div class="box-content-row" *ngIf="selectedDeletionDatePreset.value === 0 || editMode">
<label *ngIf="editMode" for="deletionDateCustom">{{ "deletionDate" | i18n }}</label>
@ -19,23 +20,27 @@
id="deletionDateCustom"
type="datetime-local"
name="deletionDate"
aria-describedby="deletionDateCustomHelp"
formControlName="defaultDeletionDateTime"
required
placeholder="MM/DD/YYYY HH:MM AM/PM"
/>
<small class="help-block" *ngIf="editMode">{{ "deletionDateDesc" | i18n }}</small>
<small id="deletionDateCustomHelp" class="help-block" *ngIf="editMode">{{
"deletionDateDesc" | i18n
}}</small>
</div>
<div class="box-content-row" appBoxRow *ngIf="!editMode">
<label for="expirationDate">{{ "expirationDate" | i18n }}</label>
<select
id="expirationDate"
name="expirationDateSelect"
aria-describedby="expirationDateHelp"
formControlName="selectedExpirationDatePreset"
required
>
<option *ngFor="let o of expirationDatePresets" [ngValue]="o.value">{{ o.name }}</option>
</select>
<small class="help-block">{{ "expirationDateDesc" | i18n }}</small>
<small id="expirationDateHelp" class="help-block">{{ "expirationDateDesc" | i18n }}</small>
</div>
<div class="box-content-row" *ngIf="selectedExpirationDatePreset.value === 0 || editMode">
<label *ngIf="editMode" for="expirationDateCustom">{{ "expirationDate" | i18n }}</label>
@ -43,11 +48,14 @@
id="expirationDateCustom"
type="datetime-local"
name="expirationDate"
aria-describedby="expirationDateCustomHelp"
formControlName="defaultExpirationDateTime"
required
placeholder="MM/DD/YYYY HH:MM AM/PM"
/>
<small *ngIf="editMode" class="help-block">{{ "expirationDateDesc" | i18n }}</small>
<small *ngIf="editMode" id="expirationDateCustomHelp" class="help-block">{{
"expirationDateDesc" | i18n
}}</small>
</div>
</div>
</div>

View File

@ -45,10 +45,10 @@
<div class="box-content no-hover">
<div class="box-content-row">
<label for="file">{{ "file" | i18n }}</label>
<input type="file" id="file" name="file" required />
<input type="file" id="file" name="file" aria-describedby="fileHelp" required />
</div>
</div>
<div class="box-footer">
<div id="fileHelp" class="box-footer">
{{ "maxFileSize" | i18n }}
</div>
</div>

View File

@ -24,7 +24,7 @@
<app-user-verification ngDefaultControl formControlName="secret" name="secret">
</app-user-verification>
</div>
<div class="box-footer">
<div id="confirmIdentityHelp" class="box-footer">
<p>{{ "confirmIdentity" | i18n }}</p>
</div>
</div>

View File

@ -341,7 +341,7 @@
/>
<label class="unstyled" for="usernameType_{{ o.value }}">
{{ o.name }}
<div class="small text-muted" *ngIf="o.desc">{{ o.desc }}</div>
<small class="help-block" *ngIf="o.desc">{{ o.desc }}</small>
</label>
</div>
</div>

View File

@ -18,6 +18,7 @@
<select
id="organization"
name="OrganizationId"
aria-describedby="organizationHelp"
[(ngModel)]="organizationId"
(change)="filterCollections()"
>
@ -25,7 +26,7 @@
</select>
</div>
</div>
<div class="box-footer">
<div id="organizationHelp" class="box-footer">
{{ "moveToOrgDesc" | i18n }}
</div>
</div>

View File

@ -361,31 +361,31 @@ form,
margin-left: -18px;
}
}
}
.help-block {
margin-top: 3px;
display: block;
.help-block {
margin-top: 3px;
display: block;
@include themify($themes) {
color: themed("mutedColor");
}
a {
@extend .btn;
@extend .link;
padding: 0;
font-size: inherit;
font-weight: bold;
@include themify($themes) {
color: themed("mutedColor");
}
a {
@extend .btn;
@extend .link;
padding: 0;
font-size: inherit;
font-weight: bold;
&:hover {
@include themify($themes) {
color: themed("mutedColor");
}
&:hover {
@include themify($themes) {
color: darken(themed("mutedColor"), 6%);
}
color: darken(themed("mutedColor"), 6%);
}
}
}