Replaces Directive-Based copy2ClipboardButton with a Component-based version.
Further replaces all instances of Directive use with Component version.
Similar toastr logic used.
Fixes: https://tracker.ceph.com/issues/44960
Signed-off-by: Courtney Caldwell <ccaldwel@redhat.com>
class="btn btn-light"
cdPasswordButton="password">
</button>
- <button type="button"
- class="btn btn-light"
- cdCopy2ClipboardButton="password">
- </button>
+ <cd-copy-2-clipboard-button source="password">
+ </cd-copy-2-clipboard-button>
</span>
</div>
<span class="invalid-feedback"
class="btn btn-light"
cdPasswordButton="mutual_password">
</button>
- <button type="button"
- class="btn btn-light"
- cdCopy2ClipboardButton="mutual_password">
- </button>
+ <cd-copy-2-clipboard-button source="mutual_password">
+ </cd-copy-2-clipboard-button>
</span>
</div>
<span class="invalid-feedback"
class="btn btn-light"
cdPasswordButton="target_password">
</button>
- <button type="button"
- class="btn btn-light"
- cdCopy2ClipboardButton="target_password">
- </button>
+ <cd-copy-2-clipboard-button source="target_password">
+ </cd-copy-2-clipboard-button>
</span>
</div>
class="btn btn-light"
cdPasswordButton="target_mutual_password">
</button>
- <button type="button"
- class="btn btn-light"
- cdCopy2ClipboardButton="target_mutual_password">
- </button>
+ <cd-copy-2-clipboard-button source="target_mutual_password">
+ </cd-copy-2-clipboard-button>
</span>
</div>
class="btn btn-light"
[cdPasswordButton]="'password' + ii">
</button>
- <button type="button"
- class="btn btn-light"
- [cdCopy2ClipboardButton]="'password' + ii">
- </button>
+ <cd-copy-2-clipboard-button [source]="'password' + ii">
+ </cd-copy-2-clipboard-button>
</span>
</div>
<span class="invalid-feedback"
class="btn btn-light"
[cdPasswordButton]="'mutual_password' + ii">
</button>
- <button type="button"
- class="btn btn-light"
- [cdCopy2ClipboardButton]="'mutual_password' + ii">
- </button>
+ <cd-copy-2-clipboard-button [source]="'mutual_password' + ii">
+ </cd-copy-2-clipboard-button>
</span>
</div>
<span class="invalid-feedback"
readonly>
</textarea>
</div>
- <button class="btn btn-primary mb-3 float-right"
- aria-label="Copy to Clipboard"
- i18n-aria-label
- title="Copy to Clipboard"
- i18n-title
- cdCopy2ClipboardButton="token">
- <ng-container i18n>Copy to Clipboard</ng-container>
- </button>
+ <cd-copy-2-clipboard-button class="float-right"
+ source="token">
+ </cd-copy-2-clipboard-button>
</div>
<div class="modal-footer">
[textItem]="logText"
fileName="cluster_log">
</cd-download-button>
- <button type="button"
- class="btn btn-light"
- [cdCopy2ClipboardButton]="logText"
- [byId]="false"></button>
+ <cd-copy-2-clipboard-button
+ [source]="logText"
+ [byId]="false">
+ </cd-copy-2-clipboard-button>
</div>
<div class="card-body">
<p *ngFor="let line of clog">
[textItem]="logText"
fileName="audit_log">
</cd-download-button>
- <button type="button"
- class="btn btn-light"
- [cdCopy2ClipboardButton]="logText"
- [byId]="false"></button>
+ <cd-copy-2-clipboard-button
+ [source]="logText"
+ [byId]="false">
+ </cd-copy-2-clipboard-button>
</div>
<div class="card-body">
<p *ngFor="let line of audit_log">
class="btn btn-light"
cdPasswordButton="api_password">
</button>
- <button type="button"
- class="btn btn-light"
- cdCopy2ClipboardButton="api_password">
- </button>
+ <cd-copy-2-clipboard-button source="api_password">
+ </cd-copy-2-clipboard-button>
</span>
<span class="invalid-feedback"
*ngIf="serviceForm.showError('api_password', frm, 'required')"
<button type="button"
class="btn btn-light"
(click)="next()">
- <ng-container i18n>{{ actionLabels.NEXT }}</ng-container>
+ <ng-container>{{ actionLabels.NEXT }}</ng-container>
</button>
</div>
</div>
<cd-download-button [objectItem]="report"
fileName="telemetry_report">
</cd-download-button>
- <button type="button"
- class="btn btn-light"
- cdCopy2ClipboardButton="report">
- </button>
+ <cd-copy-2-clipboard-button source="report">
+ </cd-copy-2-clipboard-button>
</div>
</div>
</div>
class="btn btn-light"
cdPasswordButton="access_key">
</button>
- <button type="button"
- class="btn btn-light"
- cdCopy2ClipboardButton="access_key">
- </button>
+ <cd-copy-2-clipboard-button source="access_key">
+ </cd-copy-2-clipboard-button>
</span>
</div>
<span class="invalid-feedback"
class="btn btn-light"
cdPasswordButton="secret_key">
</button>
- <button type="button"
- class="btn btn-light"
- cdCopy2ClipboardButton="secret_key">
- </button>
+ <cd-copy-2-clipboard-button source="secret_key">
+ </cd-copy-2-clipboard-button>
</span>
</div>
<span class="invalid-feedback"
class="btn btn-light"
cdPasswordButton="access_key">
</button>
- <button type="button"
- class="btn btn-light"
- cdCopy2ClipboardButton="access_key">
- </button>
+ <cd-copy-2-clipboard-button source="access_key">
+ </cd-copy-2-clipboard-button>
</span>
</div>
<span class="invalid-feedback"
class="btn btn-light"
cdPasswordButton="secret_key">
</button>
- <button type="button"
- class="btn btn-light"
- cdCopy2ClipboardButton="secret_key">
- </button>
+ <cd-copy-2-clipboard-button source="secret_key">
+ </cd-copy-2-clipboard-button>
</span>
</div>
<span class="invalid-feedback"
class="btn btn-light"
cdPasswordButton="secret_key">
</button>
- <button type="button"
- class="btn btn-light"
- cdCopy2ClipboardButton="secret_key">
- </button>
+ <cd-copy-2-clipboard-button source="secret_key">
+ </cd-copy-2-clipboard-button>
</span>
</div>
<span class="invalid-feedback"
class="btn btn-light"
cdPasswordButton="secret_key">
</button>
- <button type="button"
- class="btn btn-light"
- cdCopy2ClipboardButton="secret_key">
- </button>
+ <cd-copy-2-clipboard-button source="secret_key">
+ </cd-copy-2-clipboard-button>
</span>
</div>
</div>
import { BackButtonComponent } from './back-button/back-button.component';
import { ConfigOptionComponent } from './config-option/config-option.component';
import { ConfirmationModalComponent } from './confirmation-modal/confirmation-modal.component';
+import { Copy2ClipboardButtonComponent } from './copy2clipboard-button/copy2clipboard-button.component';
import { CriticalConfirmationModalComponent } from './critical-confirmation-modal/critical-confirmation-modal.component';
import { DateTimePickerComponent } from './date-time-picker/date-time-picker.component';
import { DocComponent } from './doc/doc.component';
OrchestratorDocPanelComponent,
DateTimePickerComponent,
DocComponent,
+ Copy2ClipboardButtonComponent,
DownloadButtonComponent,
FormButtonPanelComponent
],
OrchestratorDocPanelComponent,
DateTimePickerComponent,
DocComponent,
+ Copy2ClipboardButtonComponent,
DownloadButtonComponent,
FormButtonPanelComponent
]
--- /dev/null
+<button (click)="onClick()"
+ type="button"
+ class="btn btn-light"
+ i18n-title
+ title="Copy to Clipboard">
+ <i [ngClass]="[icons.clipboard]"></i>
+</button>
--- /dev/null
+import { TestBed } from '@angular/core/testing';
+
+import * as BrowserDetect from 'detect-browser';
+import { ToastrService } from 'ngx-toastr';
+
+import { configureTestBed } from '~/testing/unit-test-helper';
+import { Copy2ClipboardButtonComponent } from './copy2clipboard-button.component';
+
+describe('Copy2ClipboardButtonComponent', () => {
+ let component: Copy2ClipboardButtonComponent;
+
+ configureTestBed({
+ providers: [
+ {
+ provide: ToastrService,
+ useValue: {
+ error: () => true,
+ success: () => true
+ }
+ }
+ ]
+ });
+
+ it('should create an instance', () => {
+ component = new Copy2ClipboardButtonComponent(null);
+ expect(component).toBeTruthy();
+ });
+
+ describe('test onClick behaviours', () => {
+ let toastrService: ToastrService;
+ let queryFn: jasmine.Spy;
+ let writeTextFn: jasmine.Spy;
+
+ beforeEach(() => {
+ toastrService = TestBed.inject(ToastrService);
+ component = new Copy2ClipboardButtonComponent(toastrService);
+ spyOn<any>(component, 'getText').and.returnValue('foo');
+ Object.assign(navigator, {
+ permissions: { query: jest.fn() },
+ clipboard: {
+ writeText: jest.fn()
+ }
+ });
+ queryFn = spyOn(navigator.permissions, 'query');
+ });
+
+ it('should not call permissions API', () => {
+ spyOn(BrowserDetect, 'detect').and.returnValue({ name: 'firefox' });
+ writeTextFn = spyOn(navigator.clipboard, 'writeText').and.returnValue(
+ new Promise<void>((resolve, _) => {
+ resolve();
+ })
+ );
+ component.onClick();
+ expect(queryFn).not.toHaveBeenCalled();
+ expect(writeTextFn).toHaveBeenCalledWith('foo');
+ });
+
+ it('should call permissions API', () => {
+ spyOn(BrowserDetect, 'detect').and.returnValue({ name: 'chrome' });
+ component.onClick();
+ expect(queryFn).toHaveBeenCalled();
+ });
+ });
+});
--- /dev/null
+import { Component, HostListener, Input } from '@angular/core';
+
+import { detect } from 'detect-browser';
+import { ToastrService } from 'ngx-toastr';
+
+import { Icons } from '~/app/shared/enum/icons.enum';
+
+@Component({
+ selector: 'cd-copy-2-clipboard-button',
+ templateUrl: './copy2clipboard-button.component.html',
+ styleUrls: ['./copy2clipboard-button.component.scss']
+})
+export class Copy2ClipboardButtonComponent {
+ @Input()
+ private source: string;
+
+ @Input()
+ byId = true;
+
+ icons = Icons;
+
+ constructor(private toastr: ToastrService) {}
+
+ private getText(): string {
+ const element = document.getElementById(this.source) as HTMLInputElement;
+ return element.value;
+ }
+
+ @HostListener('click')
+ onClick() {
+ try {
+ const browser = detect();
+ const text = this.byId ? this.getText() : this.source;
+ const toastrFn = () => {
+ this.toastr.success('Copied text to the clipboard successfully.');
+ };
+ if (['firefox', 'ie', 'ios', 'safari'].includes(browser.name)) {
+ // Various browsers do not support the `Permissions API`.
+ // https://developer.mozilla.org/en-US/docs/Web/API/Permissions_API#Browser_compatibility
+ navigator.clipboard.writeText(text).then(() => toastrFn());
+ } else {
+ // Checking if we have the clipboard-write permission
+ navigator.permissions
+ .query({ name: 'clipboard-write' as PermissionName })
+ .then((result: any) => {
+ if (result.state === 'granted' || result.state === 'prompt') {
+ navigator.clipboard.writeText(text).then(() => toastrFn());
+ }
+ });
+ }
+ } catch (_) {
+ this.toastr.error('Failed to copy text to the clipboard.');
+ }
+ }
+}
+++ /dev/null
-import { TestBed } from '@angular/core/testing';
-
-import * as BrowserDetect from 'detect-browser';
-import { ToastrService } from 'ngx-toastr';
-
-import { configureTestBed } from '~/testing/unit-test-helper';
-import { Copy2ClipboardButtonDirective } from './copy2clipboard-button.directive';
-
-describe('Copy2clipboardButtonDirective', () => {
- let directive: Copy2ClipboardButtonDirective;
-
- configureTestBed({
- providers: [
- {
- provide: ToastrService,
- useValue: {
- error: () => true,
- success: () => true
- }
- }
- ]
- });
-
- it('should create an instance', () => {
- directive = new Copy2ClipboardButtonDirective(null, null, null);
- expect(directive).toBeTruthy();
- });
-
- describe('test onClick behaviours', () => {
- let toastrService: ToastrService;
- let queryFn: jasmine.Spy;
- let writeTextFn: jasmine.Spy;
-
- beforeEach(() => {
- toastrService = TestBed.inject(ToastrService);
- directive = new Copy2ClipboardButtonDirective(null, null, toastrService);
- spyOn<any>(directive, 'getText').and.returnValue('foo');
- Object.assign(navigator, {
- permissions: { query: jest.fn() },
- clipboard: {
- writeText: jest.fn()
- }
- });
- queryFn = spyOn(navigator.permissions, 'query');
- });
-
- it('should not call permissions API', () => {
- spyOn(BrowserDetect, 'detect').and.returnValue({ name: 'firefox' });
- writeTextFn = spyOn(navigator.clipboard, 'writeText').and.returnValue(
- new Promise<void>((resolve, _) => {
- resolve();
- })
- );
- directive.onClick();
- expect(queryFn).not.toHaveBeenCalled();
- expect(writeTextFn).toHaveBeenCalledWith('foo');
- });
-
- it('should call permissions API', () => {
- spyOn(BrowserDetect, 'detect').and.returnValue({ name: 'chrome' });
- directive.onClick();
- expect(queryFn).toHaveBeenCalled();
- });
- });
-});
+++ /dev/null
-import { Directive, ElementRef, HostListener, Input, OnInit, Renderer2 } from '@angular/core';
-
-import { detect } from 'detect-browser';
-import { ToastrService } from 'ngx-toastr';
-
-@Directive({
- selector: '[cdCopy2ClipboardButton]'
-})
-export class Copy2ClipboardButtonDirective implements OnInit {
- @Input()
- private cdCopy2ClipboardButton: string;
- @Input()
- byId = true;
-
- constructor(
- private elementRef: ElementRef,
- private renderer: Renderer2,
- private toastr: ToastrService
- ) {}
-
- ngOnInit() {
- const iElement = this.renderer.createElement('i');
- this.renderer.addClass(iElement, 'fa');
- this.renderer.addClass(iElement, 'fa-clipboard');
- this.renderer.setAttribute(iElement, 'title', $localize`Copy to clipboard`);
- this.renderer.appendChild(this.elementRef.nativeElement, iElement);
- }
-
- private getText(): string {
- const element = document.getElementById(this.cdCopy2ClipboardButton) as HTMLInputElement;
- return element.value;
- }
-
- @HostListener('click')
- onClick() {
- try {
- const browser = detect();
- const text = this.byId ? this.getText() : this.cdCopy2ClipboardButton;
- const toastrFn = () => {
- this.toastr.success('Copied text to the clipboard successfully.');
- };
- if (['firefox', 'ie', 'ios', 'safari'].includes(browser.name)) {
- // Various browsers do not support the `Permissions API`.
- // https://developer.mozilla.org/en-US/docs/Web/API/Permissions_API#Browser_compatibility
- navigator.clipboard.writeText(text).then(() => toastrFn());
- } else {
- // Checking if we have the clipboard-write permission
- navigator.permissions
- .query({ name: 'clipboard-write' as PermissionName })
- .then((result: any) => {
- if (result.state === 'granted' || result.state === 'prompt') {
- navigator.clipboard.writeText(text).then(() => toastrFn());
- }
- });
- }
- } catch (_) {
- this.toastr.error('Failed to copy text to the clipboard.');
- }
- }
-}
import { NgModule } from '@angular/core';
import { AutofocusDirective } from './autofocus.directive';
-import { Copy2ClipboardButtonDirective } from './copy2clipboard-button.directive';
import { DimlessBinaryPerSecondDirective } from './dimless-binary-per-second.directive';
import { DimlessBinaryDirective } from './dimless-binary.directive';
import { FormInputDisableDirective } from './form-input-disable.directive';
imports: [],
declarations: [
AutofocusDirective,
- Copy2ClipboardButtonDirective,
DimlessBinaryDirective,
DimlessBinaryPerSecondDirective,
PasswordButtonDirective,
],
exports: [
AutofocusDirective,
- Copy2ClipboardButtonDirective,
DimlessBinaryDirective,
DimlessBinaryPerSecondDirective,
PasswordButtonDirective,