Add "Copy" Button to ChatGPT Questions

Add copy buttons to your prompts on ChatGPT, in case you need to ask the same question twice

// ==UserScript==
// @name         Add "Copy" Button to ChatGPT Questions
// @namespace    http://tampermonkey.net/
// @version      0.1
// @description  Add copy buttons to your prompts on ChatGPT, in case you need to ask the same question twice
// @author       Lak
// @match        chat.openai.com/*
// @license      MIT
// @grant        none
// ==/UserScript==

(function() {
    'use strict';

    // Function to copy text to clipboard
    function copyTextToClipboard(text) {
        const textArea = document.createElement('textarea');
        textArea.value = text;
        document.body.appendChild(textArea);
        textArea.select();
        document.execCommand('copy');
        document.body.removeChild(textArea);
    }

    // Function to add a copy button to an element
    function addCopyButton(element) {
        const existingCopyButton = element.querySelector('[aria-label="Copier"]');
        if (!existingCopyButton) {
            const copyButton = document.createElement('button');
            copyButton.innerHTML = '<svg stroke="currentColor" fill="none" stroke-width="2" viewBox="0 0 24 24" stroke-linecap="round" stroke-linejoin="round" class="h-4 w-4" height="1em" width="1em" xmlns="http://www.w3.org/2000/svg"><path d="M16 4h2a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2V6a2 2 0 0 1 2-2h"></path><rect x="8" y="2" width="8" height="4" rx="1" ry="1"></rect></svg> ';
            copyButton.className = "flex items-center gap-1.5 rounded-md p-1 text-xs hover:text-gray-950 dark:text-gray-400 dark:hover:text-gray-200 disabled:dark:hover:text-gray-400 md:invisible md:group-hover:visible md:group-[.final-completion]:visible";
            copyButton.ariaLabel = 'Copier';
            const buttonPosition = element.querySelector('.mt-1');
            if (buttonPosition) {
                const firstChild = buttonPosition.firstElementChild;
                if (firstChild) {
                    buttonPosition.insertBefore(copyButton, firstChild);
                } else {
                    buttonPosition.appendChild(copyButton);
                }
            }

            copyButton.addEventListener('click', () => {
                const innerText = element.querySelector('[class*="text-message"]').innerText.trim();
                copyTextToClipboard(innerText);

                // Change the copy button icon to a checkmark temporarily
                const originalIcon = copyButton.innerHTML;
                copyButton.innerHTML = '<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor" class="h-4 w-4"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"></path></svg>';

                setTimeout(() => {
                    // Revert the copy button icon to the original
                    copyButton.innerHTML = originalIcon;
                }, 1500); // 1.5 seconds delay for reverting the button icon
            });
        }
    }

    // Observer callback function
    function observeCallback(mutationsList, observer) {
        for (const mutation of mutationsList) {
            if (mutation.addedNodes) {
                for (const node of mutation.addedNodes) {
                    if (node instanceof Element) {
                        const elements = document.querySelectorAll('[data-testid*="conversation-turn-"]');
                        for (let i = 0; i < elements.length; i += 2) {
                            addCopyButton(elements[i]);
                        }
                    }
                }
            }
        }
    }



    // Create a Mutation Observer
    const observer = new MutationObserver(observeCallback);

    // Start observing the entire document body for changes
    observer.observe(document.body, { childList: true, subtree: true });
})();

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址