reorganize clipboard code

This commit is contained in:
Aran-Fey
2024-05-30 09:57:13 +02:00
parent d1cab2575a
commit c53c034a20
7 changed files with 79 additions and 78 deletions

View File

@@ -9,7 +9,7 @@ import { Language } from 'highlight.js';
import { LayoutContext } from '../layouting';
import { getElementHeight, getElementWidth } from '../layoutHelpers';
import { copyToClipboard, firstDefined } from '../utils';
import { setClipboard, firstDefined } from '../utils';
import { applyIcon } from '../designApplication';
export type CodeBlockState = ComponentState & {
@@ -109,7 +109,7 @@ export function convertDivToCodeBlock(
copyButton.addEventListener('click', (event) => {
const codeToCopy = (preElement as HTMLPreElement).textContent ?? '';
copyToClipboard(codeToCopy);
setClipboard(codeToCopy);
copyButton.title = 'Copied!';
applyIcon(

View File

@@ -5,7 +5,7 @@ import {
import { ComponentId } from '../dataModels';
import { getTextDimensions } from '../layoutHelpers';
import { LayoutContext } from '../layouting';
import { copyToClipboard } from '../utils';
import { setClipboard } from '../utils';
import { ComponentBase, ComponentState } from './componentBase';
export type ScrollTargetState = ComponentState & {
@@ -106,7 +106,7 @@ export class ScrollTargetComponent extends ComponentBase {
let url = new URL(window.location.href);
url.hash = this.state.id;
copyToClipboard(url.toString());
setClipboard(url.toString());
}
updateNaturalWidth(ctx: LayoutContext): void {

View File

@@ -6,10 +6,8 @@ import {
registerFont,
closeSession,
setTitle,
setClipboard,
getClipboard,
ClipboardError,
} from './rpcFunctions';
import { setClipboard, getClipboard, ClipboardError } from './utils';
import { AsyncQueue, commitCss } from './utils';
let websocket: WebSocket | null = null;

View File

@@ -132,34 +132,3 @@ export function setTitle(title: string): void {
export function closeSession(): void {
window.close(); // TODO: What if the browser doesn't allow this?
}
export class ClipboardError extends Error {
constructor(message: string) {
super(message);
this.name = this.constructor.name;
}
}
export async function setClipboard(text: string): Promise<void> {
if (!navigator.clipboard) {
throw new ClipboardError('Clipboard API is not available');
}
try {
await navigator.clipboard.writeText(text);
} catch (error) {
console.warn(`Failed to set clipboard content: ${error}`);
throw new ClipboardError(`Failed to set clipboard content: ${error}`);
}
}
export async function getClipboard(): Promise<string> {
if (!navigator.clipboard) {
throw new ClipboardError('Clipboard API is not available');
}
try {
return await navigator.clipboard.readText();
} catch (error) {
console.warn(`Failed to get clipboard content: ${error}`);
throw new ClipboardError(`Failed to get clipboard content: ${error}`);
}
}

View File

@@ -120,28 +120,56 @@ export class TimeoutError extends Error {
}
}
/// Copies the given text to the clipboard
export function copyToClipboard(text: string): void {
if (navigator.clipboard) {
navigator.clipboard.writeText(text).catch((error) => {
console.warn(
`Failed to set clipboard content using navigator.clipboard: ${error}`
);
fallbackCopyToClipboard(text);
});
} else {
fallbackCopyToClipboard(text);
export class ClipboardError extends Error {
constructor(message: string) {
super(message);
this.name = this.constructor.name;
}
}
function fallbackCopyToClipboard(text: string): void {
const textArea = document.createElement('textarea');
textArea.value = text;
export async function setClipboard(text: string): Promise<void> {
if (navigator.clipboard) {
try {
await navigator.clipboard.writeText(text);
return;
} catch (error) {
console.warn(`Failed to set clipboard content: ${error}`);
throw new ClipboardError(
`Failed to set clipboard content: ${error}`
);
}
}
document.body.appendChild(textArea);
textArea.select();
document.execCommand('copy');
document.body.removeChild(textArea);
// Fallback in case `navigator.clipboard` isn't available or didn't work
if (document.execCommand) {
const textArea = document.createElement('textarea');
textArea.value = text;
document.body.appendChild(textArea);
textArea.select();
document.execCommand('copy');
document.body.removeChild(textArea);
}
console.warn('Failed to set clipboard content: No clipboard API available');
throw new ClipboardError(
'Failed to set clipboard content: No clipboard API available'
);
}
export async function getClipboard(): Promise<string> {
if (navigator.clipboard) {
try {
return await navigator.clipboard.readText();
} catch (error) {
console.warn(`Failed to get clipboard content: ${error}`);
throw new ClipboardError(
`Failed to get clipboard content: ${error}`
);
}
}
throw new ClipboardError('Clipboard API is not available');
}
/// Checks if there's an #url-fragment, and if so, scrolls the corresponding

View File

@@ -33,3 +33,16 @@ class NavigationFailed(Exception):
will simply display their fallback in that case. Thus this exception will
not be raised in that case.
"""
class ClipboardError(Exception):
"""
Exception raised for errors related to clipboard operations.
"""
def __init__(self, message: str):
super().__init__(message)
@property
def message(self) -> str:
return self.args[0]

View File

@@ -67,19 +67,6 @@ class WontSerialize(Exception):
pass
class ClipboardError(Exception):
"""
Exception raised for errors related to clipboard operations.
"""
def __init__(self, message: str):
super().__init__(message)
@property
def message(self) -> str:
return self.args[0]
async def dummy_send_message(message: Jsonable) -> None:
raise NotImplementedError() # pragma: no cover
@@ -2483,26 +2470,32 @@ a.remove();
async def set_clipboard(self, text: str) -> None:
"""
Set the client's clipboard to the given text.
Copies the given text to the client's clipboard.
## Parameters
`text`: The text to set on the clipboard.
`text`: The text to copy to the clipboard.
## Raises
`ClipboardError`: If the user's browser doesn't allow or support
clipboard operations.
"""
try:
await self._remote_set_clipboard(text)
except Exception as e:
raise ClipboardError(f"Failed to set clipboard content: {str(e)}")
except unicall.RpcError as e:
raise errors.ClipboardError(e.message) from None
async def get_clipboard(self) -> str:
"""
Get the current text from the client's clipboard.
Gets the current text from the client's clipboard.
## Returns
## Raises
The text currently on the clipboard.
`ClipboardError`: If the user's browser doesn't allow or support
clipboard operations.
"""
try:
return await self._remote_get_clipboard()
except Exception as e:
raise ClipboardError(f"Failed to get clipboard content: {str(e)}")
except unicall.RpcError as e:
raise errors.ClipboardError(e.message) from None