Add "Copy QR Code" button with clipboard support

Implemented a copy-to-clipboard button for QR codes, including Blazor logic for feedback and disabled states. Injected IJSRuntime for JS interop and added supporting JS functions for image copying and fallback download. Reduced QR code image size for better compatibility. Added responsive and accessible CSS for the new button. Cleaned up timers and feedback state on component disposal.
This commit is contained in:
Michal Vrba
2026-01-07 14:48:45 +01:00
parent 37cd000d16
commit 373ca0cf9f
3 changed files with 320 additions and 7 deletions
+148
View File
@@ -54,6 +54,154 @@
<a href="." class="reload">Reload</a>
<span class="dismiss">🗙</span>
</div>
<!-- JavaScript functions for clipboard operations -->
<script>
// Original function for normal copy (kept for compatibility)
window.copyImageToClipboard = async function (imageId) {
try {
// Check if Clipboard API is supported
if (!navigator.clipboard || !navigator.clipboard.write) {
console.warn('Clipboard API not supported');
return false;
}
const img = document.getElementById(imageId);
if (!img) {
console.error('Image element not found');
return false;
}
// Create a canvas to convert the image to blob
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
// Set canvas dimensions to match image
canvas.width = img.naturalWidth || img.width;
canvas.height = img.naturalHeight || img.height;
// Draw the image on canvas
ctx.drawImage(img, 0, 0);
// Convert canvas to blob
return new Promise((resolve) => {
canvas.toBlob(async (blob) => {
if (!blob) {
console.error('Failed to create blob from canvas');
resolve(false);
return;
}
try {
// Create ClipboardItem and write to clipboard
const clipboardItem = new ClipboardItem({ 'image/png': blob });
await navigator.clipboard.write([clipboardItem]);
console.log('Image copied to clipboard successfully');
resolve(true);
} catch (error) {
console.error('Failed to copy image to clipboard:', error);
resolve(false);
}
}, 'image/png');
});
} catch (error) {
console.error('Error copying image to clipboard:', error);
return false;
}
};
// New function for copying smaller images to clipboard
window.copyImageToClipboardSmall = async function (imageId) {
try {
// Check if Clipboard API is supported
if (!navigator.clipboard || !navigator.clipboard.write) {
console.warn('Clipboard API not supported');
return false;
}
const img = document.getElementById(imageId);
if (!img) {
console.error('Image element not found');
return false;
}
// Create a canvas to convert the image to blob
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
// Set smaller canvas dimensions (max 512x512 for better clipboard handling)
const maxSize = 512;
let { width, height } = img.naturalWidth && img.naturalHeight ?
{ width: img.naturalWidth, height: img.naturalHeight } :
{ width: img.width, height: img.height };
// Scale down if image is too large
if (width > maxSize || height > maxSize) {
const scale = Math.min(maxSize / width, maxSize / height);
width = Math.floor(width * scale);
height = Math.floor(height * scale);
}
canvas.width = width;
canvas.height = height;
// Draw the image on canvas with scaling
ctx.drawImage(img, 0, 0, width, height);
// Convert canvas to blob with higher compression
return new Promise((resolve) => {
canvas.toBlob(async (blob) => {
if (!blob) {
console.error('Failed to create blob from canvas');
resolve(false);
return;
}
try {
// Create ClipboardItem and write to clipboard
const clipboardItem = new ClipboardItem({ 'image/png': blob });
await navigator.clipboard.write([clipboardItem]);
console.log('Smaller image copied to clipboard successfully');
resolve(true);
} catch (error) {
console.error('Failed to copy image to clipboard:', error);
resolve(false);
}
}, 'image/png', 0.8); // Lower quality for smaller size
});
} catch (error) {
console.error('Error copying image to clipboard:', error);
return false;
}
};
// Fallback function for browsers that don't support Clipboard API
window.downloadQRCode = function (imageId, filename = 'qrcode.png') {
try {
const img = document.getElementById(imageId);
if (!img) {
console.error('Image element not found');
return false;
}
// Create a temporary link element
const link = document.createElement('a');
link.href = img.src;
link.download = filename;
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
return true;
} catch (error) {
console.error('Error downloading image:', error);
return false;
}
};
</script>
<script src="_framework/blazor.webassembly#[.{fingerprint}].js"></script>
</body>