feat: add hidden char count toggle (#1780)
Co-authored-by: Thomas Rittson <trittson@bitwarden.com>
This commit is contained in:
parent
e802bba99c
commit
8f76e81582
2
jslib
2
jslib
|
@ -1 +1 @@
|
||||||
Subproject commit a6092916d80424b8bf4d34e321a0b58f15c7519d
|
Subproject commit fdaa4f9fa5c6ff8beefcf4d896a8a7f02dc7e3e9
|
|
@ -1866,5 +1866,8 @@
|
||||||
},
|
},
|
||||||
"leftOrganization": {
|
"leftOrganization": {
|
||||||
"message": "You have left the organization."
|
"message": "You have left the organization."
|
||||||
|
},
|
||||||
|
"toggleCharacterCount": {
|
||||||
|
"message": "Toggle character count"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -69,6 +69,7 @@ import { StopClickDirective } from "jslib-angular/directives/stop-click.directiv
|
||||||
import { StopPropDirective } from "jslib-angular/directives/stop-prop.directive";
|
import { StopPropDirective } from "jslib-angular/directives/stop-prop.directive";
|
||||||
import { TrueFalseValueDirective } from "jslib-angular/directives/true-false-value.directive";
|
import { TrueFalseValueDirective } from "jslib-angular/directives/true-false-value.directive";
|
||||||
|
|
||||||
|
import { ColorPasswordCountPipe } from "jslib-angular/pipes/color-password-count.pipe";
|
||||||
import { ColorPasswordPipe } from "jslib-angular/pipes/color-password.pipe";
|
import { ColorPasswordPipe } from "jslib-angular/pipes/color-password.pipe";
|
||||||
import { I18nPipe } from "jslib-angular/pipes/i18n.pipe";
|
import { I18nPipe } from "jslib-angular/pipes/i18n.pipe";
|
||||||
import { SearchCiphersPipe } from "jslib-angular/pipes/search-ciphers.pipe";
|
import { SearchCiphersPipe } from "jslib-angular/pipes/search-ciphers.pipe";
|
||||||
|
@ -207,6 +208,7 @@ registerLocaleData(localeZhTw, "zh-TW");
|
||||||
CipherRowComponent,
|
CipherRowComponent,
|
||||||
CiphersComponent,
|
CiphersComponent,
|
||||||
CollectionsComponent,
|
CollectionsComponent,
|
||||||
|
ColorPasswordCountPipe,
|
||||||
ColorPasswordPipe,
|
ColorPasswordPipe,
|
||||||
CurrentTabComponent,
|
CurrentTabComponent,
|
||||||
EnvironmentComponent,
|
EnvironmentComponent,
|
||||||
|
|
|
@ -120,6 +120,11 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.action-buttons {
|
.action-buttons {
|
||||||
|
&.count {
|
||||||
|
align-self: start;
|
||||||
|
margin-top: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
.row-btn {
|
.row-btn {
|
||||||
padding-left: 5px;
|
padding-left: 5px;
|
||||||
padding-right: 5px;
|
padding-right: 5px;
|
||||||
|
@ -255,6 +260,7 @@
|
||||||
display: block;
|
display: block;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
margin-bottom: 5px;
|
margin-bottom: 5px;
|
||||||
|
min-height: 1em;
|
||||||
|
|
||||||
@include themify($themes) {
|
@include themify($themes) {
|
||||||
color: themed("mutedColor");
|
color: themed("mutedColor");
|
||||||
|
@ -305,6 +311,7 @@
|
||||||
.row-main {
|
.row-main {
|
||||||
flex-grow: 1;
|
flex-grow: 1;
|
||||||
min-width: 0;
|
min-width: 0;
|
||||||
|
align-self: start;
|
||||||
}
|
}
|
||||||
|
|
||||||
&.box-content-row-flex,
|
&.box-content-row-flex,
|
||||||
|
@ -455,6 +462,7 @@
|
||||||
|
|
||||||
.action-buttons {
|
.action-buttons {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
align-self: start;
|
||||||
margin-left: 5px;
|
margin-left: 5px;
|
||||||
|
|
||||||
.row-btn {
|
.row-btn {
|
||||||
|
|
|
@ -164,6 +164,30 @@ p.lead {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.password-character {
|
||||||
|
display: inline-flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
width: 30px;
|
||||||
|
height: 36px;
|
||||||
|
font-weight: 600;
|
||||||
|
|
||||||
|
&:nth-child(odd) {
|
||||||
|
@include themify($themes) {
|
||||||
|
background-color: themed("backgroundColor");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.password-count {
|
||||||
|
white-space: nowrap;
|
||||||
|
font-size: 8px;
|
||||||
|
|
||||||
|
@include themify($themes) {
|
||||||
|
color: themed("mutedColor") !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#duo-frame {
|
#duo-frame {
|
||||||
background: url("../images/loading.svg") 0 0 no-repeat;
|
background: url("../images/loading.svg") 0 0 no-repeat;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
|
|
@ -10,10 +10,14 @@
|
||||||
{{ field.value || " " }}
|
{{ field.value || " " }}
|
||||||
</div>
|
</div>
|
||||||
<div *ngIf="field.type === fieldType.Hidden">
|
<div *ngIf="field.type === fieldType.Hidden">
|
||||||
<span [hidden]="!field.showValue" class="monospaced show-whitespace">{{
|
<span *ngIf="!field.showValue" class="monospaced">{{ field.maskedValue }}</span>
|
||||||
|
<span *ngIf="field.showValue && !field.showCount" class="monospaced show-whitespace">{{
|
||||||
field.value
|
field.value
|
||||||
}}</span>
|
}}</span>
|
||||||
<span [hidden]="field.showValue" class="monospaced">{{ field.maskedValue }}</span>
|
<span
|
||||||
|
*ngIf="field.showValue && field.showCount"
|
||||||
|
[innerHTML]="field.value | colorPasswordCount"
|
||||||
|
></span>
|
||||||
</div>
|
</div>
|
||||||
<div *ngIf="field.type === fieldType.Boolean">
|
<div *ngIf="field.type === fieldType.Boolean">
|
||||||
<i class="bwi bwi-check-square" *ngIf="field.value === 'true'" aria-hidden="true"></i>
|
<i class="bwi bwi-check-square" *ngIf="field.value === 'true'" aria-hidden="true"></i>
|
||||||
|
@ -33,6 +37,18 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="action-buttons">
|
<div class="action-buttons">
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
class="row-btn"
|
||||||
|
appStopClick
|
||||||
|
attr.aria-label="{{ 'toggleCharacterCount' | i18n }} {{ field.name }}"
|
||||||
|
appA11yTitle="{{ 'toggleCharacterCount' | i18n }}"
|
||||||
|
*ngIf="field.type === fieldType.Hidden && cipher.viewPassword && field.showValue"
|
||||||
|
(click)="toggleFieldCount(field)"
|
||||||
|
[attr.aria-pressed]="field.showCount"
|
||||||
|
>
|
||||||
|
<i class="bwi bwi-lg bwi-numbered-list" aria-hidden="true"></i>
|
||||||
|
</button>
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
class="row-btn"
|
class="row-btn"
|
||||||
|
|
|
@ -60,15 +60,19 @@
|
||||||
(dragstart)="setTextDataOnDrag($event, cipher.login.password)"
|
(dragstart)="setTextDataOnDrag($event, cipher.login.password)"
|
||||||
>{{ "password" | i18n }}</span
|
>{{ "password" | i18n }}</span
|
||||||
>
|
>
|
||||||
<div [hidden]="showPassword" class="monospaced">
|
<div *ngIf="!showPassword" class="monospaced">
|
||||||
{{ cipher.login.maskedPassword }}
|
{{ cipher.login.maskedPassword }}
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
[hidden]="!showPassword"
|
*ngIf="showPassword && !showPasswordCount"
|
||||||
class="monospaced password-wrapper"
|
class="monospaced password-wrapper"
|
||||||
appSelectCopy
|
appSelectCopy
|
||||||
[innerHTML]="cipher.login.password | colorPassword"
|
[innerHTML]="cipher.login.password | colorPassword"
|
||||||
></div>
|
></div>
|
||||||
|
<div
|
||||||
|
*ngIf="showPassword && showPasswordCount"
|
||||||
|
[innerHTML]="cipher.login.password | colorPasswordCount"
|
||||||
|
></div>
|
||||||
</div>
|
</div>
|
||||||
<div class="action-buttons">
|
<div class="action-buttons">
|
||||||
<button
|
<button
|
||||||
|
@ -93,6 +97,18 @@
|
||||||
aria-hidden="true"
|
aria-hidden="true"
|
||||||
></i>
|
></i>
|
||||||
</button>
|
</button>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
class="row-btn"
|
||||||
|
appStopClick
|
||||||
|
attr.aria-label="{{ 'toggleCharacterCount' | i18n }} {{ 'password' | i18n }}"
|
||||||
|
appA11yTitle="{{ 'toggleCharacterCount' | i18n }}"
|
||||||
|
(click)="togglePasswordCount()"
|
||||||
|
*ngIf="showPassword"
|
||||||
|
[attr.aria-pressed]="showPasswordCount"
|
||||||
|
>
|
||||||
|
<i class="bwi bwi-lg bwi-numbered-list" aria-hidden="true"></i>
|
||||||
|
</button>
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
class="row-btn"
|
class="row-btn"
|
||||||
|
|
Loading…
Reference in New Issue