| |
| |
| |
| |
|
|
| export interface CopyResult { |
| success: boolean; |
| method: 'clipboard-api' | 'execCommand' | 'manual-select' | 'fallback'; |
| error?: string; |
| } |
|
|
| |
| |
| |
| |
| |
| export async function copyToClipboard(text: string): Promise<CopyResult> { |
| if (!text || text.trim() === '') { |
| return { |
| success: false, |
| method: 'fallback', |
| error: 'No text provided' |
| }; |
| } |
|
|
| |
| if (navigator.clipboard && typeof navigator.clipboard.writeText === 'function') { |
| try { |
| await navigator.clipboard.writeText(text); |
| return { |
| success: true, |
| method: 'clipboard-api' |
| }; |
| } catch (error) { |
| console.warn('Clipboard API failed:', error); |
| |
| } |
| } |
|
|
| |
| try { |
| const result = await copyWithExecCommand(text); |
| if (result.success) { |
| return result; |
| } |
| } catch (error) { |
| console.warn('execCommand failed:', error); |
| |
| } |
|
|
| |
| try { |
| const result = await copyWithManualSelection(text); |
| if (result.success) { |
| return result; |
| } |
| } catch (error) { |
| console.warn('Manual selection failed:', error); |
| } |
|
|
| |
| return { |
| success: false, |
| method: 'fallback', |
| error: 'All copy methods failed. Please copy the text manually.' |
| }; |
| } |
|
|
| |
| |
| |
| async function copyWithExecCommand(text: string): Promise<CopyResult> { |
| return new Promise((resolve) => { |
| const textarea = document.createElement('textarea'); |
| textarea.value = text; |
| textarea.style.position = 'fixed'; |
| textarea.style.left = '-9999px'; |
| textarea.style.top = '-9999px'; |
| textarea.style.opacity = '0'; |
| textarea.setAttribute('readonly', ''); |
|
|
| document.body.appendChild(textarea); |
|
|
| try { |
| textarea.select(); |
| textarea.setSelectionRange(0, text.length); |
|
|
| const successful = document.execCommand('copy'); |
|
|
| if (successful) { |
| resolve({ |
| success: true, |
| method: 'execCommand' |
| }); |
| } else { |
| resolve({ |
| success: false, |
| method: 'execCommand', |
| error: 'execCommand returned false' |
| }); |
| } |
| } catch (error) { |
| resolve({ |
| success: false, |
| method: 'execCommand', |
| error: error instanceof Error ? error.message : 'execCommand failed' |
| }); |
| } finally { |
| document.body.removeChild(textarea); |
| } |
| }); |
| } |
|
|
| |
| |
| |
| async function copyWithManualSelection(text: string): Promise<CopyResult> { |
| return new Promise((resolve) => { |
| const textarea = document.createElement('textarea'); |
| textarea.value = text; |
| textarea.style.position = 'absolute'; |
| textarea.style.left = '-9999px'; |
| textarea.style.top = '-9999px'; |
| textarea.style.opacity = '0'; |
| textarea.style.pointerEvents = 'none'; |
| textarea.setAttribute('readonly', ''); |
| textarea.setAttribute('tabindex', '-1'); |
|
|
| document.body.appendChild(textarea); |
|
|
| try { |
| |
| textarea.focus(); |
| textarea.select(); |
| textarea.setSelectionRange(0, text.length); |
|
|
| |
| const copyEvent = new ClipboardEvent('copy', { |
| clipboardData: new DataTransfer() |
| }); |
|
|
| if (copyEvent.clipboardData) { |
| copyEvent.clipboardData.setData('text/plain', text); |
| document.dispatchEvent(copyEvent); |
|
|
| resolve({ |
| success: true, |
| method: 'manual-select' |
| }); |
| } else { |
| |
| resolve({ |
| success: false, |
| method: 'manual-select', |
| error: 'Manual selection prepared, but automatic copy failed' |
| }); |
| } |
| } catch (error) { |
| resolve({ |
| success: false, |
| method: 'manual-select', |
| error: error instanceof Error ? error.message : 'Manual selection failed' |
| }); |
| } finally { |
| |
| setTimeout(() => { |
| if (document.body.contains(textarea)) { |
| document.body.removeChild(textarea); |
| } |
| }, 100); |
| } |
| }); |
| } |
|
|
| |
| |
| |
| export function isClipboardSupported(): boolean { |
| return !!( |
| (navigator.clipboard && typeof navigator.clipboard.writeText === 'function') || |
| typeof document !== 'undefined' |
| ); |
| } |
|
|
| |
| |
| |
| export function getBestClipboardMethod(): 'clipboard-api' | 'execCommand' | 'manual-select' | 'none' { |
| if (navigator.clipboard && typeof navigator.clipboard.writeText === 'function') { |
| return 'clipboard-api'; |
| } |
|
|
| if (typeof document !== 'undefined') { |
| return 'execCommand'; |
| } |
|
|
| return 'none'; |
| } |
|
|