Skip to content
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
71 changes: 64 additions & 7 deletions src/utils/copy-code.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ function handleCopyClick(event: Event): void {
const codeContent = button.getAttribute('data-code');

if (!codeContent) {
console.error('No code content found to copy');
showErrorFeedback(button, 'No content to copy');
return;
}

Expand All @@ -28,37 +28,94 @@ async function copyToClipboard(
text: string,
button: HTMLElement,
): Promise<void> {
// Check if clipboard API is available and we're in a secure context
if (navigator.clipboard && window.isSecureContext) {
try {
await navigator.clipboard.writeText(text);
showSuccessMessage(button);
return;
} catch {
// Fall through to legacy method
}
}

// Fallback for older browsers or insecure contexts
try {
await navigator.clipboard.writeText(text);
showSuccessMessage(button);
} catch {
// Fallback for older browsers
const textarea = document.createElement('textarea');
textarea.value = text;
textarea.style.cssText =
'position:fixed;left:-999999px;top:-999999px;opacity:0;';
'position:fixed;left:-999999px;top:-999999px;opacity:0;pointer-events:none;';

document.body.appendChild(textarea);
textarea.focus();
textarea.select();

// For mobile devices
textarea.setSelectionRange(0, 99999);

const success = document.execCommand('copy');
document.body.removeChild(textarea);

if (success) showSuccessMessage(button);
if (success) {
showSuccessMessage(button);
} else {
showErrorFeedback(button, 'Copy failed - please copy manually');
}
} catch {
showErrorFeedback(button, 'Copy not supported in this browser');
}
}

/**
* Show success message
*/
function showSuccessMessage(button: HTMLElement): void {
// Update button text temporarily
const originalText = button.textContent;
button.textContent = 'Copied!';
button.style.backgroundColor = '#10b981';
button.style.color = 'white';

setTimeout(() => {
button.textContent = originalText;
button.style.backgroundColor = '';
button.style.color = '';
}, 2000);

// Also check for success message element
const successMessage = button.nextElementSibling as HTMLElement;
if (successMessage?.classList.contains('copy-success-message')) {
successMessage.classList.remove('hidden');
setTimeout(() => successMessage.classList.add('hidden'), 2000);
}
}

/**
* Show error feedback to user
*/
function showErrorFeedback(button: HTMLElement, message: string): void {
// Update button text temporarily
const originalText = button.textContent;
button.textContent = 'Failed';
button.style.backgroundColor = '#ef4444';
button.style.color = 'white';

setTimeout(() => {
button.textContent = originalText;
button.style.backgroundColor = '';
button.style.color = '';
}, 2000);

// Show tooltip or alert as fallback
if ('title' in button) {
const originalTitle = button.title;
button.title = message;
setTimeout(() => {
button.title = originalTitle;
}, 3000);
}
}

/**
* Initialize copy code functionality
*/
Expand Down