Skip to content

Instantly share code, notes, and snippets.

@simonw
Created March 26, 2025 02:12
Show Gist options
  • Select an option

  • Save simonw/760e3a376e9fa9cef3cbbb56abda2e8e to your computer and use it in GitHub Desktop.

Select an option

Save simonw/760e3a376e9fa9cef3cbbb56abda2e8e to your computer and use it in GitHub Desktop.

2025-03-26T02:07:00 conversation: 01jq83ad1qpvthsf5a6ftp5810 id: 01jq83ad1yka2xbf1sfq8mbevh

Model: gemini-2.5-pro-exp-03-25

Prompt

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Clipboard Format Viewer</title>
    <style>
        * {
            box-sizing: border-box;
        }
        body {
            font-family: Arial, sans-serif;
            line-height: 1.6;
            margin: 0;
            padding: 20px;
            background-color: #f0f0f0;
        }
        h1 {
            text-align: center;
            color: #333;
        }
        #paste-area {
            width: 100%;
            height: 100px;
            margin-bottom: 20px;
            padding: 10px;
            border: 2px dashed #aaa;
            border-radius: 5px;
            resize: vertical;
        }
        #output {
            background-color: white;
            border: 1px solid #ddd;
            border-radius: 5px;
            padding: 20px;
            max-height: 70vh;
            overflow-y: auto;
        }
        .format {
            margin-bottom: 20px;
            border-bottom: 1px solid #eee;
            padding-bottom: 10px;
        }
        .format h2 {
            color: #0066cc;
            margin-bottom: 10px;
        }
        .format-content {
            max-height: 200px;
            overflow-y: auto;
            background-color: #f5f5f5;
            border: 1px solid #ddd;
            border-radius: 3px;
            padding: 10px;
        }
        pre {
            margin: 0;
            white-space: pre-wrap;
            word-wrap: break-word;
        }
    </style>
</head>
<body>
    <h1>Clipboard Format Viewer</h1>
    <textarea id="paste-area" placeholder="Paste here or anywhere on the page"></textarea>
    <div id="output"></div>

    <script>
        const pasteArea = document.getElementById('paste-area');
        const output = document.getElementById('output');

        function handlePaste(event) {
            event.preventDefault();
            const clipboardData = event.clipboardData || window.clipboardData;
            output.innerHTML = '';

            // Get available formats
            const formats = clipboardData.types;
            
            formats.forEach(format => {
                const formatDiv = document.createElement('div');
                formatDiv.className = 'format';
                
                const formatTitle = document.createElement('h2');
                formatTitle.textContent = format;
                formatDiv.appendChild(formatTitle);

                const formatContentWrapper = document.createElement('div');
                formatContentWrapper.className = 'format-content';
                
                const formatContent = document.createElement('pre');
                let content = clipboardData.getData(format);
                
                // Special handling for certain formats
                if (format === 'text/html') {
                    const tempElement = document.createElement('div');
                    tempElement.innerHTML = content;
                    content = tempElement.innerHTML;
                } else if (format === 'Files') {
                    const files = clipboardData.files;
                    content = Array.from(files).map(file => `${file.name} (${file.type}, ${file.size} bytes)`).join('\n');
                }

                formatContent.textContent = content;
                formatContentWrapper.appendChild(formatContent);
                formatDiv.appendChild(formatContentWrapper);

                output.appendChild(formatDiv);
            });

            // Additional information about the clipboard event
            const eventInfo = document.createElement('div');
            eventInfo.className = 'format';
            eventInfo.innerHTML = `
                <h2>Clipboard Event Information</h2>
                <div class="format-content">
                    <pre>
Event type: ${event.type}
Formats available: ${formats.join(', ')}
                    </pre>
                </div>
            `;
            output.appendChild(eventInfo);
        }

        // Listen for paste events on the textarea
        pasteArea.addEventListener('paste', handlePaste);

        // Listen for paste events on the entire document
        document.addEventListener('paste', handlePaste);
    </script>
</body>
</html>

System

Output a new version of this tool where any files that start with image/ are displayed on the page as max-width 100% images underneath the text that says image.png (image/png, 1522480 bytes)

Response

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Clipboard Format Viewer</title>
    <style>
        * {
            box-sizing: border-box;
        }
        body {
            font-family: Arial, sans-serif;
            line-height: 1.6;
            margin: 0;
            padding: 20px;
            background-color: #f0f0f0;
        }
        h1 {
            text-align: center;
            color: #333;
        }
        #paste-area {
            width: 100%;
            height: 100px;
            margin-bottom: 20px;
            padding: 10px;
            border: 2px dashed #aaa;
            border-radius: 5px;
            resize: vertical;
            background-color: #fff;
        }
        #output {
            background-color: white;
            border: 1px solid #ddd;
            border-radius: 5px;
            padding: 20px;
            max-height: 75vh; /* Increased max-height slightly */
            overflow-y: auto;
        }
        .format {
            margin-bottom: 20px;
            border-bottom: 1px solid #eee;
            padding-bottom: 10px;
        }
        .format:last-child {
             border-bottom: none; /* Remove border for the last item */
             margin-bottom: 0;
             padding-bottom: 0;
        }
        .format h2 {
            color: #0066cc;
            margin-top: 0;
            margin-bottom: 10px;
            font-size: 1.1em;
        }
        .format-content {
            max-height: 300px; /* Increased max-height for text content */
            overflow-y: auto;
            background-color: #f9f9f9; /* Slightly adjusted background */
            border: 1px solid #e0e0e0; /* Slightly adjusted border */
            border-radius: 3px;
            padding: 10px;
            font-size: 0.9em; /* Slightly smaller font for content */
        }
        /* Style for the container holding file info + image */
        .file-entry {
             margin-bottom: 15px;
             padding-bottom: 10px;
             border-bottom: 1px dotted #ddd;
        }
        .file-entry:last-child {
             margin-bottom: 0;
             padding-bottom: 0;
             border-bottom: none;
        }
        /* Style for displayed images */
        .pasted-image {
            max-width: 100%;
            height: auto; /* Maintain aspect ratio */
            display: block; /* Ensure it takes its own line */
            margin-top: 10px; /* Space below the text info */
            border: 1px solid #ccc; /* Add a light border around images */
        }
        pre {
            margin: 0;
            white-space: pre-wrap;
            word-wrap: break-word;
            font-family: Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace; /* Use monospace font */
        }
        .empty-format-note {
             font-style: italic;
             color: #888;
             padding: 10px;
        }
    </style>
</head>
<body>
    <h1>Clipboard Format Viewer</h1>
    <textarea id="paste-area" placeholder="Paste anywhere on the page (Ctrl+V or Cmd+V)"></textarea>
    <div id="output"><p>Paste content to see the available clipboard formats and data.</p></div>

    <script>
        const pasteArea = document.getElementById('paste-area');
        const output = document.getElementById('output');

        function handlePaste(event) {
            // Prevent the default paste behavior (e.g., pasting into the textarea)
            event.preventDefault();
            const clipboardData = event.clipboardData || window.clipboardData;
            output.innerHTML = ''; // Clear previous output

            if (!clipboardData) {
                output.innerHTML = '<p>Could not access clipboard data. Your browser might not support this feature or requires user permission.</p>';
                return;
            }

            const formats = clipboardData.types;
            const files = clipboardData.files; // Get files list once (for Files format)
            const items = clipboardData.items; // Get items list once (for modern API access, especially images)

            console.log("Clipboard Data:", clipboardData);
            console.log("Available Formats:", formats);
            console.log("Number of Files:", files.length);
            console.log("Number of Items:", items ? items.length : 'N/A');

            if (formats.length === 0 && files.length === 0 && (!items || items.length === 0)) {
                 output.innerHTML = '<p>Paste detected, but no standard formats, files, or items were found in the clipboard data.</p>';
                 return;
            }

            // --- Iterate through detected formats ---
            formats.forEach(format => {
                const formatDiv = document.createElement('div');
                formatDiv.className = 'format';

                const formatTitle = document.createElement('h2');
                formatTitle.textContent = format;
                formatDiv.appendChild(formatTitle);

                // Wrapper for content (text or image)
                const formatContentWrapper = document.createElement('div');
                let contentDisplayed = false; // Flag to check if content was handled by special cases

                // --- 1. Special Handling for "Files" format ---
                // This is common when pasting files from the OS.
                if (format === 'Files' && files.length > 0) {
                    const fileListContent = document.createElement('div');
                    fileListContent.className = 'format-content'; // Apply styling

                    Array.from(files).forEach(file => {
                        const fileContainer = document.createElement('div');
                        fileContainer.className = 'file-entry'; // Container for each file's info + image

                        // Display file information text
                        const fileInfo = document.createElement('div');
                        fileInfo.textContent = `${file.name} (${file.type || 'unknown type'}, ${file.size} bytes)`;
                        fileContainer.appendChild(fileInfo);

                        // Check if the file is an image and display it below the text
                        if (file.type.startsWith('image/')) {
                            try {
                                const img = document.createElement('img');
                                const objectURL = URL.createObjectURL(file);

                                img.src = objectURL;
                                img.alt = `${file.name} (Pasted Image)`;
                                img.className = 'pasted-image'; // Apply image styles

                                // IMPORTANT: Revoke the object URL once the image is loaded (or fails)
                                // to prevent memory leaks.
                                img.onload = () => {
                                    console.log(`Image ${file.name} loaded, revoking ${objectURL}`);
                                    URL.revokeObjectURL(objectURL);
                                };
                                img.onerror = () => {
                                    console.error("Error loading image:", file.name);
                                    URL.revokeObjectURL(objectURL); // Revoke even on error
                                    img.alt += ' (Error loading)'; // Update alt text
                                    // Optionally add an error message element
                                    const errorMsg = document.createElement('div');
                                    errorMsg.textContent = 'Could not load image preview.';
                                    errorMsg.style.color = 'red';
                                    fileContainer.appendChild(errorMsg);
                                };

                                fileContainer.appendChild(img); // Append the image below the file info
                            } catch (err) {
                                 console.error(`Error creating object URL for ${file.name}:`, err);
                                 const errorMsg = document.createElement('div');
                                 errorMsg.textContent = 'Error creating image preview.';
                                 errorMsg.style.color = 'red';
                                 fileContainer.appendChild(errorMsg);
                            }
                        }
                        fileListContent.appendChild(fileContainer); // Append container for this file
                    });
                    formatContentWrapper.appendChild(fileListContent);
                    contentDisplayed = true;
                }
                // --- 2. Special Handling for "image/*" types (if not already handled by Files) ---
                // This is common when pasting image data directly (e.g., screenshots, copy image)
                // We use clipboardData.items for this, which is more reliable than getData for blobs.
                else if (format.startsWith('image/') && files.length === 0 && items) {
                    // Check items only if Files format wasn't present or empty
                    let imageFromItemsDisplayed = false;
                    for (let i = 0; i < items.length; i++) {
                        const item = items[i];
                        // Find the first item matching the current format that is a file/blob
                        if (item.kind === 'file' && item.type === format) {
                            const file = item.getAsFile(); // This gets the image data as a Blob
                            if (file) {
                                try {
                                    // Display image from item
                                    const img = document.createElement('img');
                                    const objectURL = URL.createObjectURL(file);

                                    img.src = objectURL;
                                    img.alt = `Pasted image (${format}, ${file.size} bytes)`;
                                    img.className = 'pasted-image'; // Apply image styles

                                    img.onload = () => {
                                        console.log(`Image from item ${format} loaded, revoking ${objectURL}`);
                                        URL.revokeObjectURL(objectURL);
                                    };
                                    img.onerror = () => {
                                        console.error("Error loading image from item:", format);
                                        URL.revokeObjectURL(objectURL);
                                        img.alt += ' (Error loading)';
                                        const errorMsg = document.createElement('div');
                                        errorMsg.textContent = 'Could not load image preview.';
                                        errorMsg.style.color = 'red';
                                         formatContentWrapper.appendChild(errorMsg);
                                    };

                                    // Add a descriptive text above the image
                                    const imgInfo = document.createElement('div');
                                    // Use file.size if available, otherwise indicate unknown size
                                    const sizeText = file.size ? `, ${file.size} bytes` : '';
                                    imgInfo.textContent = `Image data (${format}${sizeText})`;
                                    // No 'format-content' class needed here, just simple text
                                    formatContentWrapper.appendChild(imgInfo);

                                    formatContentWrapper.appendChild(img); // Append image
                                    imageFromItemsDisplayed = true;
                                    contentDisplayed = true;
                                    break; // Handle only the first matching item for this format
                                } catch (err) {
                                    console.error(`Error creating object URL for image item ${format}:`, err);
                                    const errorMsg = document.createElement('div');
                                    errorMsg.textContent = 'Error creating image preview.';
                                    errorMsg.style.color = 'red';
                                    formatContentWrapper.appendChild(errorMsg);
                                }
                            }
                        }
                    }
                     // If image wasn't found via items, fall through to default text handling below
                }

                // --- 3. Default Handling (Text, HTML, Fallbacks) ---
                // Handles text/*, application/*, and serves as fallback if image handling failed
                if (!contentDisplayed) {
                    const formatContent = document.createElement('pre');
                    let content = '';
                    let retrievalError = false;

                    try {
                        content = clipboardData.getData(format);

                        if (format === 'Files' && files.length === 0) {
                            // Explicitly handle Files format reported but with no actual files
                            content = '(No files found in clipboard)';
                        } else if (format.startsWith('image/') && files.length > 0) {
                            // If it's an image format but Files were present, assume handled there
                            content = '(Image data likely shown in the "Files" section above)';
                        } else if (content === '' && !format.startsWith('text/')) {
                            // If getData returns empty for non-text, it might be intentional or unavailable
                            content = '(Empty or non-retrievable data for this format)';
                        }
                         // Note: text/html is displayed as raw source by default in <pre>
                        formatContent.textContent = content;

                    } catch (e) {
                        retrievalError = true;
                        console.warn(`Could not getData for format: ${format}`, e);
                        // Provide more context based on format type
                         if (format.startsWith('image/')) {
                             content = '(Could not retrieve image data directly. It might be available via "Files" or Items API if present.)';
                         } else if (format === 'Files'){
                              content = '(Error accessing file list details.)';
                         } else {
                             content = `(Unable to retrieve data directly: ${e.message})`;
                         }
                        formatContent.textContent = content;
                    }

                    // Only add the <pre> element if there's content or an error message
                    if (content || retrievalError) {
                        formatContentWrapper.appendChild(formatContent);
                        formatContentWrapper.className = 'format-content'; // Add class for styling text content
                    } else {
                         // If formatContentWrapper is still empty, it means getData returned empty string
                         // and it wasn't an explicit Files/Image fallback case. Add a note.
                         const emptyNote = document.createElement('div');
                         emptyNote.textContent = '(No data retrieved or data is empty string)';
                         emptyNote.className = 'empty-format-note';
                         formatContentWrapper.appendChild(emptyNote);
                    }
                }

                // Append the content wrapper (containing text or image) to the format div
                formatDiv.appendChild(formatContentWrapper);
                output.appendChild(formatDiv); // Append the whole section for this format
            });

            // --- Additional Clipboard Event Information ---
            const eventInfo = document.createElement('div');
            eventInfo.className = 'format'; // Reuse format styling
            eventInfo.innerHTML = `
                <h2>Clipboard Event Information</h2>
                <div class="format-content">
                    <pre>
Event type: ${event.type}
Formats available (${formats.length}): ${formats.join(', ') || 'None'}
Number of files reported: ${files.length}
Number of clipboard items: ${items ? items.length : 'N/A (Items API not supported/available)'}
                    </pre>
                </div>
            `;
            // Append event info only if there was some content pasted initially
            if (output.hasChildNodes()){
                 output.appendChild(eventInfo);
            } else if (!output.innerHTML) { // Double check if output is truly empty
                output.innerHTML = '<p>Paste detected, but no data could be read or displayed.</p>';
            }
        }

        // Listen for paste events on the textarea (useful if focused)
        pasteArea.addEventListener('paste', handlePaste);

        // Listen for paste events on the entire document (allows pasting anywhere)
        document.addEventListener('paste', handlePaste);

        // Initial message update
        if (navigator.clipboard && typeof navigator.clipboard.read !== 'function') {
            const warning = document.createElement('p');
            warning.style.color = 'orange';
            warning.textContent = 'Warning: Your browser might not fully support the modern Clipboard API (read permission). Pasting might rely on the legacy event method.';
            output.appendChild(warning);
        }
    </script>
</body>
</html>

Token usage:

1,121 input, 3,656 output, {"promptTokensDetails": [{"modality": "TEXT", "tokenCount": 1121}]}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment