1
0
mirror of https://github.com/bitwarden/browser.git synced 2024-12-11 14:48:46 +01:00

[PM-14345] Enabling drag and drop for cipher fields (#12067)

* enabling drag and drop for cipher fields

* adding drag and drop to totp and fido

* removing code changes to wrong file

* undoing uneeded change

* Changes suggested by Shane

* fixes

* fixes

* moving export to the correct spot

---------

Co-authored-by: --global <>
This commit is contained in:
cd-bitwarden 2024-12-10 12:55:02 -05:00 committed by GitHub
parent 4003d30b46
commit 83dc66dd56
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
8 changed files with 105 additions and 30 deletions

View File

@ -0,0 +1,22 @@
import { Directive, HostListener, Input } from "@angular/core";
@Directive({
selector: "[appTextDrag]",
standalone: true,
host: {
draggable: "true",
class: "tw-cursor-move",
},
})
export class TextDragDirective {
@Input({
alias: "appTextDrag",
required: true,
})
data = "";
@HostListener("dragstart", ["$event"])
onDragStart(event: DragEvent) {
event.dataTransfer.setData("text", this.data);
}
}

View File

@ -43,6 +43,7 @@ import { LaunchClickDirective } from "./directives/launch-click.directive";
import { NotPremiumDirective } from "./directives/not-premium.directive"; import { NotPremiumDirective } from "./directives/not-premium.directive";
import { StopClickDirective } from "./directives/stop-click.directive"; import { StopClickDirective } from "./directives/stop-click.directive";
import { StopPropDirective } from "./directives/stop-prop.directive"; import { StopPropDirective } from "./directives/stop-prop.directive";
import { TextDragDirective } from "./directives/text-drag.directive";
import { TrueFalseValueDirective } from "./directives/true-false-value.directive"; import { TrueFalseValueDirective } from "./directives/true-false-value.directive";
import { CreditCardNumberPipe } from "./pipes/credit-card-number.pipe"; import { CreditCardNumberPipe } from "./pipes/credit-card-number.pipe";
import { PluralizePipe } from "./pipes/pluralize.pipe"; import { PluralizePipe } from "./pipes/pluralize.pipe";
@ -81,6 +82,7 @@ import { IconComponent } from "./vault/components/icon.component";
IconModule, IconModule,
LinkModule, LinkModule,
IconModule, IconModule,
TextDragDirective,
], ],
declarations: [ declarations: [
A11yInvalidDirective, A11yInvalidDirective,
@ -150,6 +152,7 @@ import { IconComponent } from "./vault/components/icon.component";
NoInvoicesComponent, NoInvoicesComponent,
ManageTaxInformationComponent, ManageTaxInformationComponent,
TwoFactorIconComponent, TwoFactorIconComponent,
TextDragDirective,
], ],
providers: [ providers: [
CreditCardNumberPipe, CreditCardNumberPipe,

View File

@ -4,8 +4,8 @@
</bit-section-header> </bit-section-header>
<bit-card class="[&_bit-form-field:last-of-type]:tw-mb-0"> <bit-card class="[&_bit-form-field:last-of-type]:tw-mb-0">
<bit-form-field disableReadOnlyBorder> <bit-form-field disableReadOnlyBorder>
<bit-label>{{ "note" | i18n }}</bit-label> <bit-label [appTextDrag]="notes">{{ "note" | i18n }}</bit-label>
<textarea readonly bitInput rows="5" aria-readonly="true">{{ notes }}</textarea> <textarea readonly id="notes" bitInput rows="5" aria-readonly="true">{{ notes }}</textarea>
<button <button
bitSuffix bitSuffix
bitIconButton="bwi-clone" bitIconButton="bwi-clone"

View File

@ -4,8 +4,9 @@
</bit-section-header> </bit-section-header>
<read-only-cipher-card> <read-only-cipher-card>
<bit-form-field *ngIf="card.cardholderName"> <bit-form-field *ngIf="card.cardholderName">
<bit-label>{{ "cardholderName" | i18n }}</bit-label> <bit-label [appTextDrag]="card.cardholderName">{{ "cardholderName" | i18n }}</bit-label>
<input <input
id="cardholderName"
readonly readonly
bitInput bitInput
type="text" type="text"
@ -15,8 +16,9 @@
/> />
</bit-form-field> </bit-form-field>
<bit-form-field *ngIf="card.number"> <bit-form-field *ngIf="card.number">
<bit-label>{{ "number" | i18n }}</bit-label> <bit-label [appTextDrag]="card.number">{{ "number" | i18n }}</bit-label>
<input <input
id="cardNumber"
readonly readonly
bitInput bitInput
type="password" type="password"
@ -45,8 +47,9 @@
></button> ></button>
</bit-form-field> </bit-form-field>
<bit-form-field *ngIf="card.expiration"> <bit-form-field *ngIf="card.expiration">
<bit-label>{{ "expiration" | i18n }}</bit-label> <bit-label [appTextDrag]="card.expiration">{{ "expiration" | i18n }}</bit-label>
<input <input
id="expiration"
readonly readonly
bitInput bitInput
type="text" type="text"
@ -56,8 +59,9 @@
/> />
</bit-form-field> </bit-form-field>
<bit-form-field *ngIf="card.code"> <bit-form-field *ngIf="card.code">
<bit-label>{{ "securityCode" | i18n }}</bit-label> <bit-label [appTextDrag]="card.code">{{ "securityCode" | i18n }}</bit-label>
<input <input
id="securityCode"
readonly readonly
bitInput bitInput
type="password" type="password"

View File

@ -10,7 +10,7 @@
data-testid="custom-field" data-testid="custom-field"
> >
<bit-form-field *ngIf="field.type === fieldType.Text" [disableReadOnlyBorder]="last"> <bit-form-field *ngIf="field.type === fieldType.Text" [disableReadOnlyBorder]="last">
<bit-label>{{ field.name }}</bit-label> <bit-label [appTextDrag]="field.value">{{ field.name }}</bit-label>
<input readonly bitInput type="text" [value]="field.value" aria-readonly="true" /> <input readonly bitInput type="text" [value]="field.value" aria-readonly="true" />
<button <button
bitIconButton="bwi-clone" bitIconButton="bwi-clone"
@ -24,7 +24,7 @@
></button> ></button>
</bit-form-field> </bit-form-field>
<bit-form-field *ngIf="field.type === fieldType.Hidden" [disableReadOnlyBorder]="last"> <bit-form-field *ngIf="field.type === fieldType.Hidden" [disableReadOnlyBorder]="last">
<bit-label>{{ field.name }}</bit-label> <bit-label [appTextDrag]="field.value">{{ field.name }}</bit-label>
<input <input
readonly readonly
bitInput bitInput
@ -59,7 +59,9 @@
aria-readonly="true" aria-readonly="true"
disabled disabled
/> />
<bit-label> {{ field.name }} </bit-label> <bit-label [appTextDrag]="field.value">
{{ field.name }}
</bit-label>
</bit-form-control> </bit-form-control>
<bit-form-field *ngIf="field.type === fieldType.Linked" [disableReadOnlyBorder]="last"> <bit-form-field *ngIf="field.type === fieldType.Linked" [disableReadOnlyBorder]="last">
<bit-label> {{ "cfTypeLinked" | i18n }}: {{ field.name }} </bit-label> <bit-label> {{ "cfTypeLinked" | i18n }}: {{ field.name }} </bit-label>

View File

@ -7,11 +7,12 @@
[disableMargin]="!cipher.collectionIds?.length && !showOwnership && !cipher.folderId" [disableMargin]="!cipher.collectionIds?.length && !showOwnership && !cipher.folderId"
[disableReadOnlyBorder]="!cipher.collectionIds?.length && !showOwnership && !cipher.folderId" [disableReadOnlyBorder]="!cipher.collectionIds?.length && !showOwnership && !cipher.folderId"
> >
<bit-label> <bit-label [appTextDrag]="cipher.name">
{{ "itemName" | i18n }} {{ "itemName" | i18n }}
</bit-label> </bit-label>
<input <input
readonly readonly
id="itemName"
bitInput bitInput
type="text" type="text"
[value]="cipher.name" [value]="cipher.name"

View File

@ -4,10 +4,11 @@
</bit-section-header> </bit-section-header>
<read-only-cipher-card> <read-only-cipher-card>
<bit-form-field *ngIf="cipher.login.username"> <bit-form-field *ngIf="cipher.login.username">
<bit-label> <bit-label [appTextDrag]="cipher.login.username">
{{ "username" | i18n }} {{ "username" | i18n }}
</bit-label> </bit-label>
<input <input
id="userName"
readonly readonly
bitInput bitInput
type="text" type="text"
@ -27,8 +28,9 @@
></button> ></button>
</bit-form-field> </bit-form-field>
<bit-form-field *ngIf="cipher.login.password"> <bit-form-field *ngIf="cipher.login.password">
<bit-label>{{ "password" | i18n }}</bit-label> <bit-label [appTextDrag]="cipher.login.password">{{ "password" | i18n }}</bit-label>
<input <input
id="password"
readonly readonly
bitInput bitInput
type="password" type="password"
@ -80,8 +82,11 @@
></bit-color-password> ></bit-color-password>
</div> </div>
<bit-form-field *ngIf="cipher.login?.fido2Credentials?.length > 0"> <bit-form-field *ngIf="cipher.login?.fido2Credentials?.length > 0">
<bit-label>{{ "typePasskey" | i18n }} </bit-label> <bit-label [appTextDrag]="fido2CredentialCreationDateValue"
>{{ "typePasskey" | i18n }}
</bit-label>
<input <input
id="fido"
readonly readonly
bitInput bitInput
type="text" type="text"
@ -91,7 +96,7 @@
/> />
</bit-form-field> </bit-form-field>
<bit-form-field *ngIf="cipher.login.totp"> <bit-form-field *ngIf="cipher.login.totp">
<bit-label <bit-label [appTextDrag]="totpCodeCopyObj?.totpCode"
>{{ "verificationCodeTotp" | i18n }} >{{ "verificationCodeTotp" | i18n }}
<span <span
*ngIf="!(isPremium$ | async)" *ngIf="!(isPremium$ | async)"
@ -105,6 +110,7 @@
</span> </span>
</bit-label> </bit-label>
<input <input
id="totp"
readonly readonly
bitInput bitInput
[type]="!(isPremium$ | async) ? 'password' : 'text'" [type]="!(isPremium$ | async) ? 'password' : 'text'"

View File

@ -5,8 +5,14 @@
<read-only-cipher-card> <read-only-cipher-card>
<bit-form-field *ngIf="cipher.identity.fullName"> <bit-form-field *ngIf="cipher.identity.fullName">
<bit-label>{{ "name" | i18n }}</bit-label> <bit-label [appTextDrag]="cipher.identity.fullName">{{ "name" | i18n }}</bit-label>
<input bitInput [value]="cipher.identity.fullName" readonly data-testid="name" /> <input
bitInput
id="fullName"
[value]="cipher.identity.fullName"
readonly
data-testid="name"
/>
<button <button
type="button" type="button"
bitIconButton="bwi-clone" bitIconButton="bwi-clone"
@ -19,8 +25,14 @@
></button> ></button>
</bit-form-field> </bit-form-field>
<bit-form-field *ngIf="cipher.identity.username"> <bit-form-field *ngIf="cipher.identity.username">
<bit-label>{{ "username" | i18n }}</bit-label> <bit-label [appTextDrag]="cipher.identity.username">{{ "username" | i18n }}</bit-label>
<input bitInput [value]="cipher.identity.username" readonly data-testid="username" /> <input
bitInput
id="username"
[value]="cipher.identity.username"
readonly
data-testid="username"
/>
<button <button
type="button" type="button"
bitIconButton="bwi-clone" bitIconButton="bwi-clone"
@ -32,8 +44,14 @@
></button> ></button>
</bit-form-field> </bit-form-field>
<bit-form-field *ngIf="cipher.identity.company"> <bit-form-field *ngIf="cipher.identity.company">
<bit-label>{{ "company" | i18n }}</bit-label> <bit-label [appTextDrag]="cipher.identity.company">{{ "company" | i18n }}</bit-label>
<input bitInput [value]="cipher.identity.company" readonly data-testid="company" /> <input
bitInput
id="company"
[value]="cipher.identity.company"
readonly
data-testid="company"
/>
<button <button
type="button" type="button"
bitIconButton="bwi-clone" bitIconButton="bwi-clone"
@ -55,8 +73,15 @@
<read-only-cipher-card> <read-only-cipher-card>
<bit-form-field *ngIf="cipher.identity.ssn"> <bit-form-field *ngIf="cipher.identity.ssn">
<bit-label>{{ "ssn" | i18n }}</bit-label> <bit-label [appTextDrag]="cipher.identity.ssn">{{ "ssn" | i18n }}</bit-label>
<input bitInput type="password" [value]="cipher.identity.ssn" readonly data-testid="ssn" /> <input
bitInput
id="ssn"
type="password"
[value]="cipher.identity.ssn"
readonly
data-testid="ssn"
/>
<button <button
type="button" type="button"
bitIconButton bitIconButton
@ -76,8 +101,11 @@
></button> ></button>
</bit-form-field> </bit-form-field>
<bit-form-field *ngIf="cipher.identity.passportNumber"> <bit-form-field *ngIf="cipher.identity.passportNumber">
<bit-label>{{ "passportNumber" | i18n }}</bit-label> <bit-label [appTextDrag]="cipher.identity.passportNumber">{{
"passportNumber" | i18n
}}</bit-label>
<input <input
id="passportNumber"
bitInput bitInput
type="password" type="password"
[value]="cipher.identity.passportNumber" [value]="cipher.identity.passportNumber"
@ -103,8 +131,16 @@
></button> ></button>
</bit-form-field> </bit-form-field>
<bit-form-field *ngIf="cipher.identity.licenseNumber"> <bit-form-field *ngIf="cipher.identity.licenseNumber">
<bit-label>{{ "licenseNumber" | i18n }}</bit-label> <bit-label [appTextDrag]="cipher.identity.licenseNumber">{{
<input bitInput [value]="cipher.identity.licenseNumber" readonly data-testid="license" /> "licenseNumber" | i18n
}}</bit-label>
<input
bitInput
id="licenseNumber"
[value]="cipher.identity.licenseNumber"
readonly
data-testid="license"
/>
<button <button
type="button" type="button"
bitIconButton="bwi-clone" bitIconButton="bwi-clone"
@ -126,8 +162,8 @@
<read-only-cipher-card> <read-only-cipher-card>
<bit-form-field *ngIf="cipher.identity.email"> <bit-form-field *ngIf="cipher.identity.email">
<bit-label>{{ "email" | i18n }}</bit-label> <bit-label [appTextDrag]="cipher.identity.email">{{ "email" | i18n }}</bit-label>
<input bitInput [value]="cipher.identity.email" readonly data-testid="email" /> <input bitInput id="email" [value]="cipher.identity.email" readonly data-testid="email" />
<button <button
type="button" type="button"
bitIconButton="bwi-clone" bitIconButton="bwi-clone"
@ -140,8 +176,8 @@
></button> ></button>
</bit-form-field> </bit-form-field>
<bit-form-field *ngIf="cipher.identity.phone"> <bit-form-field *ngIf="cipher.identity.phone">
<bit-label>{{ "phone" | i18n }}</bit-label> <bit-label [appTextDrag]="cipher.identity.phone">{{ "phone" | i18n }}</bit-label>
<input bitInput [value]="cipher.identity.phone" readonly data-testid="phone" /> <input bitInput id="phone" [value]="cipher.identity.phone" readonly data-testid="phone" />
<button <button
type="button" type="button"
bitIconButton="bwi-clone" bitIconButton="bwi-clone"
@ -154,9 +190,10 @@
></button> ></button>
</bit-form-field> </bit-form-field>
<bit-form-field *ngIf="addressFields"> <bit-form-field *ngIf="addressFields">
<bit-label>{{ "address" | i18n }}</bit-label> <bit-label [appTextDrag]="addressFields">{{ "address" | i18n }}</bit-label>
<textarea <textarea
bitInput bitInput
id="address"
class="tw-resize-none" class="tw-resize-none"
[value]="addressFields" [value]="addressFields"
[rows]="addressRows" [rows]="addressRows"