1
0
mirror of https://github.com/bitwarden/browser.git synced 2024-09-27 04:03:00 +02:00
bitwarden-browser/apps/browser/src/platform/services/browser-clipboard.service.ts
Cesar Gonzalez 51f482dde9
[PM-5880] Refactor browser platform utils service to remove window references (#7885)
* [PM-5880] Refactor Browser Platform Utils Service to Remove Window Service

* [PM-5880] Implementing BrowserClipboardService to handle clipboard logic between the BrowserPlatformUtils and offscreen document

* [PM-5880] Adjusting how readText is handled within BrowserClipboardService

* [PM-5880] Adjusting how readText is handled within BrowserClipboardService

* [PM-5880] Working through implementation of chrome offscreen API usage

* [PM-5880] Implementing jest tests for the methods added to the BrowserApi class

* [PM-5880] Implementing jest tests for the OffscreenDocument class

* [PM-5880] Working through jest tests for BrowserClipboardService

* [PM-5880] Adding typing information to the clipboard methods present within the BrowserPlatformUtilsService

* [PM-5880] Working on adding ServiceWorkerGlobalScope typing information

* [PM-5880] Updating window references when calling BrowserPlatformUtils methods

* [PM-5880] Finishing out jest tests for the BrowserClipboardService

* [PM-5880] Finishing out jest tests for the BrowserClipboardService

* [PM-5880] Implementing jest tests to validate the changes within BrowserApi

* [PM-5880] Implementing jest tests to ensure coverage within OffscreenDocument

* [PM-5880] Implementing jest tests for the BrowserPlatformUtilsService

* [PM-5880] Removing unused catch statements

* [PM-5880] Implementing jest tests for the BrowserPlatformUtilsService

* [PM-5880] Implementing jest tests for the BrowserPlatformUtilsService

* [PM-5880] Fixing broken tests
2024-03-06 16:33:38 +00:00

131 lines
4.6 KiB
TypeScript

import { ConsoleLogService } from "@bitwarden/common/platform/services/console-log.service";
class BrowserClipboardService {
private static consoleLogService: ConsoleLogService = new ConsoleLogService(false);
/**
* Copies the given text to the user's clipboard.
*
* @param globalContext - The global window context.
* @param text - The text to copy.
*/
static async copy(globalContext: Window, text: string) {
if (!BrowserClipboardService.isClipboardApiSupported(globalContext, "writeText")) {
this.useLegacyCopyMethod(globalContext, text);
return;
}
try {
await globalContext.navigator.clipboard.writeText(text);
} catch (error) {
BrowserClipboardService.consoleLogService.debug(
`Error copying to clipboard using the clipboard API, attempting legacy method: ${error}`,
);
this.useLegacyCopyMethod(globalContext, text);
}
}
/**
* Reads the user's clipboard and returns the text.
*
* @param globalContext - The global window context.
*/
static async read(globalContext: Window): Promise<string> {
if (!BrowserClipboardService.isClipboardApiSupported(globalContext, "readText")) {
return this.useLegacyReadMethod(globalContext);
}
try {
return await globalContext.navigator.clipboard.readText();
} catch (error) {
BrowserClipboardService.consoleLogService.debug(
`Error reading from clipboard using the clipboard API, attempting legacy method: ${error}`,
);
return this.useLegacyReadMethod(globalContext);
}
}
/**
* Copies the given text to the user's clipboard using the legacy `execCommand` method. This
* method is used as a fallback when the clipboard API is not supported or fails.
*
* @param globalContext - The global window context.
* @param text - The text to copy.
*/
private static useLegacyCopyMethod(globalContext: Window, text: string) {
if (!BrowserClipboardService.isLegacyClipboardMethodSupported(globalContext, "copy")) {
BrowserClipboardService.consoleLogService.warning("Legacy copy method not supported");
return;
}
const textareaElement = globalContext.document.createElement("textarea");
textareaElement.textContent = !text ? " " : text;
textareaElement.style.position = "fixed";
globalContext.document.body.appendChild(textareaElement);
textareaElement.select();
try {
globalContext.document.execCommand("copy");
} catch (error) {
BrowserClipboardService.consoleLogService.warning(`Error writing to clipboard: ${error}`);
} finally {
globalContext.document.body.removeChild(textareaElement);
}
}
/**
* Reads the user's clipboard using the legacy `execCommand` method. This method is used as a
* fallback when the clipboard API is not supported or fails.
*
* @param globalContext - The global window context.
*/
private static useLegacyReadMethod(globalContext: Window): string {
if (!BrowserClipboardService.isLegacyClipboardMethodSupported(globalContext, "paste")) {
BrowserClipboardService.consoleLogService.warning("Legacy paste method not supported");
return "";
}
const textareaElement = globalContext.document.createElement("textarea");
textareaElement.style.position = "fixed";
globalContext.document.body.appendChild(textareaElement);
textareaElement.focus();
try {
return globalContext.document.execCommand("paste") ? textareaElement.value : "";
} catch (error) {
BrowserClipboardService.consoleLogService.warning(`Error reading from clipboard: ${error}`);
} finally {
globalContext.document.body.removeChild(textareaElement);
}
return "";
}
/**
* Checks if the clipboard API is supported in the current environment.
*
* @param globalContext - The global window context.
* @param method - The clipboard API method to check for support.
*/
private static isClipboardApiSupported(globalContext: Window, method: "writeText" | "readText") {
return "clipboard" in globalContext.navigator && method in globalContext.navigator.clipboard;
}
/**
* Checks if the legacy clipboard method is supported in the current environment.
*
* @param globalContext - The global window context.
* @param method - The legacy clipboard method to check for support.
*/
private static isLegacyClipboardMethodSupported(globalContext: Window, method: "copy" | "paste") {
return (
"queryCommandSupported" in globalContext.document &&
globalContext.document.queryCommandSupported(method)
);
}
}
export default BrowserClipboardService;