[PM-2043] Fix additional space and characters copied to clipboard (#5312)
* Change appSelectCopy to accept a dynamic input on what to copy * Renamed select-copy directive to copy-text directive to be more accurate with the new behaviour Signed-off-by: Andre Rosado <arosado@bitwarden.com> * Moved CopyTextDirective on jslib module to be in alphabetic ordering --------- Signed-off-by: Andre Rosado <arosado@bitwarden.com> Co-authored-by: Andre Rosado <arosado@bitwarden.com>
This commit is contained in:
parent
c3adf96da7
commit
906c11acb1
|
@ -19,7 +19,11 @@
|
|||
{{ "passwordGeneratorPolicyInEffect" | i18n }}
|
||||
</app-callout>
|
||||
<div class="generated-block" *ngIf="type === 'password'">
|
||||
<div class="generated-wrapper" [innerHTML]="password | colorPassword" appSelectCopy></div>
|
||||
<div
|
||||
class="generated-wrapper"
|
||||
[innerHTML]="password | colorPassword"
|
||||
[appCopyText]="password"
|
||||
></div>
|
||||
<div class="action-buttons">
|
||||
<button
|
||||
type="button"
|
||||
|
@ -41,7 +45,11 @@
|
|||
</div>
|
||||
</div>
|
||||
<div class="generated-block" *ngIf="type === 'username'">
|
||||
<div class="generated-wrapper" [innerHTML]="username | colorPassword" appSelectCopy></div>
|
||||
<div
|
||||
class="generated-wrapper"
|
||||
[innerHTML]="username | colorPassword"
|
||||
[appCopyText]="username"
|
||||
></div>
|
||||
<div class="action-buttons" #form [appApiAction]="usernameGeneratingPromise">
|
||||
<button
|
||||
type="button"
|
||||
|
|
|
@ -22,7 +22,7 @@
|
|||
<div class="row-main-content">
|
||||
<div
|
||||
class="monospaced password-wrapper"
|
||||
appSelectCopy
|
||||
[appCopyText]="h.password"
|
||||
[innerHTML]="h.password | colorPassword"
|
||||
></div>
|
||||
<span class="detail">{{ h.date | date : "medium" }}</span>
|
||||
|
|
|
@ -72,7 +72,7 @@
|
|||
<div
|
||||
*ngIf="showPassword && !showPasswordCount"
|
||||
class="monospaced password-wrapper"
|
||||
appSelectCopy
|
||||
[appCopyText]="cipher.login.password"
|
||||
[innerHTML]="cipher.login.password | colorPassword"
|
||||
></div>
|
||||
<div
|
||||
|
|
|
@ -12,7 +12,11 @@
|
|||
{{ "passwordGeneratorPolicyInEffect" | i18n }}
|
||||
</app-callout>
|
||||
<div class="generated-block" *ngIf="type === 'password'">
|
||||
<div class="generated-wrapper" [innerHTML]="password | colorPassword" appSelectCopy></div>
|
||||
<div
|
||||
class="generated-wrapper"
|
||||
[innerHTML]="password | colorPassword"
|
||||
[appCopyText]="password"
|
||||
></div>
|
||||
<div class="action-buttons">
|
||||
<button
|
||||
type="button"
|
||||
|
@ -35,7 +39,11 @@
|
|||
</div>
|
||||
</div>
|
||||
<div class="generated-block" *ngIf="type === 'username'">
|
||||
<div class="generated-wrapper" [innerHTML]="username | colorPassword" appSelectCopy></div>
|
||||
<div
|
||||
class="generated-wrapper"
|
||||
[innerHTML]="username | colorPassword"
|
||||
[appCopyText]="username"
|
||||
></div>
|
||||
<div class="action-buttons" #form [appApiAction]="usernameGeneratingPromise">
|
||||
<button
|
||||
type="button"
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
<div class="row-main">
|
||||
<div
|
||||
class="password-wrapper monospaced"
|
||||
appSelectCopy
|
||||
[appCopyText]="h.password"
|
||||
[innerHTML]="h.password | colorPassword"
|
||||
></div>
|
||||
<span class="detail">{{ h.date | date : "medium" }}</span>
|
||||
|
|
|
@ -52,7 +52,7 @@
|
|||
<div
|
||||
*ngIf="showPassword && !showPasswordCount"
|
||||
class="monospaced password-wrapper"
|
||||
appSelectCopy
|
||||
[appCopyText]="cipher.login.password"
|
||||
[innerHTML]="cipher.login.password | colorPassword"
|
||||
></div>
|
||||
<div
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
<div class="card-body">
|
||||
<bit-color-password
|
||||
[password]="type === 'password' ? password : username"
|
||||
appSelectCopy
|
||||
[appCopyText]="type === 'password' ? password : username"
|
||||
></bit-color-password>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
<bit-color-password
|
||||
[password]="h.password"
|
||||
class="tw-block tw-font-mono"
|
||||
appSelectCopy
|
||||
[appCopyText]="h.password"
|
||||
></bit-color-password>
|
||||
<small bitTypography="body2" class="tw-text-muted">
|
||||
{{ h.date | date : "medium" }}
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
import { Directive, ElementRef, HostListener, Input } from "@angular/core";
|
||||
|
||||
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
||||
|
||||
@Directive({
|
||||
selector: "[appCopyText]",
|
||||
})
|
||||
export class CopyTextDirective {
|
||||
constructor(private el: ElementRef, private platformUtilsService: PlatformUtilsService) {}
|
||||
|
||||
@Input("appCopyText") copyText: string;
|
||||
|
||||
@HostListener("copy") onCopy() {
|
||||
if (window == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.platformUtilsService.copyToClipboard(this.copyText, { window: window });
|
||||
}
|
||||
}
|
|
@ -1,37 +0,0 @@
|
|||
import { Directive, ElementRef, HostListener } from "@angular/core";
|
||||
|
||||
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
||||
|
||||
@Directive({
|
||||
selector: "[appSelectCopy]",
|
||||
})
|
||||
export class SelectCopyDirective {
|
||||
constructor(private el: ElementRef, private platformUtilsService: PlatformUtilsService) {}
|
||||
|
||||
@HostListener("copy") onCopy() {
|
||||
if (window == null) {
|
||||
return;
|
||||
}
|
||||
let copyText = "";
|
||||
const selection = window.getSelection();
|
||||
for (let i = 0; i < selection.rangeCount; i++) {
|
||||
const range = selection.getRangeAt(i);
|
||||
const text = range.toString();
|
||||
|
||||
// The selection should only contain one line of text. In some cases however, the
|
||||
// selection contains newlines and space characters from the indentation of following
|
||||
// sibling nodes. To avoid copying passwords containing trailing newlines and spaces
|
||||
// that aren't part of the password, the selection has to be trimmed.
|
||||
let stringEndPos = text.length;
|
||||
const newLinePos = text.search(/(?:\r\n|\r|\n)/);
|
||||
if (newLinePos > -1) {
|
||||
const otherPart = text.substr(newLinePos).trim();
|
||||
if (otherPart === "") {
|
||||
stringEndPos = newLinePos;
|
||||
}
|
||||
}
|
||||
copyText += text.substring(0, stringEndPos);
|
||||
}
|
||||
this.platformUtilsService.copyToClipboard(copyText, { window: window });
|
||||
}
|
||||
}
|
|
@ -10,13 +10,13 @@ import { ApiActionDirective } from "./directives/api-action.directive";
|
|||
import { AutofocusDirective } from "./directives/autofocus.directive";
|
||||
import { BoxRowDirective } from "./directives/box-row.directive";
|
||||
import { CopyClickDirective } from "./directives/copy-click.directive";
|
||||
import { CopyTextDirective } from "./directives/copy-text.directive";
|
||||
import { FallbackSrcDirective } from "./directives/fallback-src.directive";
|
||||
import { IfFeatureDirective } from "./directives/if-feature.directive";
|
||||
import { InputStripSpacesDirective } from "./directives/input-strip-spaces.directive";
|
||||
import { InputVerbatimDirective } from "./directives/input-verbatim.directive";
|
||||
import { LaunchClickDirective } from "./directives/launch-click.directive";
|
||||
import { NotPremiumDirective } from "./directives/not-premium.directive";
|
||||
import { SelectCopyDirective } from "./directives/select-copy.directive";
|
||||
import { StopClickDirective } from "./directives/stop-click.directive";
|
||||
import { StopPropDirective } from "./directives/stop-prop.directive";
|
||||
import { TrueFalseValueDirective } from "./directives/true-false-value.directive";
|
||||
|
@ -50,6 +50,7 @@ import { IconComponent } from "./vault/components/icon.component";
|
|||
AutofocusDirective,
|
||||
BoxRowDirective,
|
||||
CalloutComponent,
|
||||
CopyTextDirective,
|
||||
CreditCardNumberPipe,
|
||||
EllipsisPipe,
|
||||
ExportScopeCalloutComponent,
|
||||
|
@ -61,7 +62,6 @@ import { IconComponent } from "./vault/components/icon.component";
|
|||
NotPremiumDirective,
|
||||
SearchCiphersPipe,
|
||||
SearchPipe,
|
||||
SelectCopyDirective,
|
||||
StopClickDirective,
|
||||
StopPropDirective,
|
||||
TrueFalseValueDirective,
|
||||
|
@ -81,6 +81,7 @@ import { IconComponent } from "./vault/components/icon.component";
|
|||
BitwardenToastModule,
|
||||
BoxRowDirective,
|
||||
CalloutComponent,
|
||||
CopyTextDirective,
|
||||
CreditCardNumberPipe,
|
||||
EllipsisPipe,
|
||||
ExportScopeCalloutComponent,
|
||||
|
@ -92,7 +93,6 @@ import { IconComponent } from "./vault/components/icon.component";
|
|||
NotPremiumDirective,
|
||||
SearchCiphersPipe,
|
||||
SearchPipe,
|
||||
SelectCopyDirective,
|
||||
StopClickDirective,
|
||||
StopPropDirective,
|
||||
TrueFalseValueDirective,
|
||||
|
|
Loading…
Reference in New Issue