From: Volker Theile Date: Tue, 22 Sep 2020 12:09:52 +0000 (+0200) Subject: mgr/dashboard: Copy to clipboard does not work in Firefox X-Git-Tag: v16.1.0~953^2 X-Git-Url: http://git-server-git.apps.pok.os.sepia.ceph.com/?a=commitdiff_plain;h=8b9d881a63aac8ed3d7d1a7fc80be5e3d3d0b3b1;p=ceph.git mgr/dashboard: Copy to clipboard does not work in Firefox Fixes: https://tracker.ceph.com/issues/47578 Signed-off-by: Volker Theile --- diff --git a/src/pybind/mgr/dashboard/frontend/src/app/shared/directives/copy2clipboard-button.directive.spec.ts b/src/pybind/mgr/dashboard/frontend/src/app/shared/directives/copy2clipboard-button.directive.spec.ts index e50fd86332c4..1b31727fcce9 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/shared/directives/copy2clipboard-button.directive.spec.ts +++ b/src/pybind/mgr/dashboard/frontend/src/app/shared/directives/copy2clipboard-button.directive.spec.ts @@ -1,8 +1,65 @@ +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', () => { - const directive = new Copy2ClipboardButtonDirective(null, null, null); + 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(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((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(); + }); + }); }); diff --git a/src/pybind/mgr/dashboard/frontend/src/app/shared/directives/copy2clipboard-button.directive.ts b/src/pybind/mgr/dashboard/frontend/src/app/shared/directives/copy2clipboard-button.directive.ts index 78e4767e5394..2a42f19b0773 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/shared/directives/copy2clipboard-button.directive.ts +++ b/src/pybind/mgr/dashboard/frontend/src/app/shared/directives/copy2clipboard-button.directive.ts @@ -1,5 +1,6 @@ import { Directive, ElementRef, HostListener, Input, OnInit, Renderer2 } from '@angular/core'; +import { detect } from 'detect-browser'; import { ToastrService } from 'ngx-toastr'; @Directive({ @@ -23,24 +24,34 @@ export class Copy2ClipboardButtonDirective implements OnInit { this.renderer.appendChild(this.elementRef.nativeElement, iElement); } - private getInputElement() { - return document.getElementById(this.cdCopy2ClipboardButton) as HTMLInputElement; + private getText(): string { + const element = document.getElementById(this.cdCopy2ClipboardButton) as HTMLInputElement; + return element.value; } @HostListener('click') onClick() { try { - // 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') { - // Copy text to clipboard. - navigator.clipboard.writeText(this.getInputElement().value); - } - }); - this.toastr.success('Copied text to the clipboard successfully.'); - } catch (err) { + const browser = detect(); + const text = this.getText(); + 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.'); } }