Greasy Fork is available in English.

ChatGPT Bouton de copie du code de chat

exister chatgpt.com Ajoutez une animation dans le coin inférieur droit du bloc de code supérieur“Copier le code”bouton

À partir de 2024-09-22. Voir la dernière version.

// ==UserScript==
// @name                                        ChatGPT Chat Copy Code Button
// @description                             Add a 'Copy Code' button to the bottom right hand of code blocks on chatgpt.com with animation
// @name:zh-CN                          ChatGPT 聊天复制代码按钮和下载代码按钮
// @description:zh-CN               在 chatgpt.com 上代码块的右下角添加一个带有动画的“复制代码”按钮和下载代码按钮
// @name:ar                          ChatGPT زر نسخ رمز الدردشة
// @description:ar               يخرج chatgpt.com أضف رسمًا متحركًا في الركن الأيمن السفلي من كتلة التعليمات البرمجية العلوية“نسخ الرمز”زر
// @name:bg                          ChatGPT Бутон за копиране на код за чат
// @description:bg               съществуват chatgpt.com Добавете анимация в долния десен ъгъл на горния кодов блок“Копирайте кода”бутон
// @name:cs                          ChatGPT Tlačítko pro kopírování kódu chatu
// @description:cs               existovat chatgpt.com Přidejte animaci do pravého dolního rohu horního bloku kódu“Kopírovat kód”tlačítko
// @name:da                          ChatGPT Chat kopi kode knap
// @description:da               eksistere chatgpt.com Tilføj en animation i nederste højre hjørne af den øverste kodeblok“Kopiér kode”knap
// @name:de                          ChatGPT Schaltfläche zum Kopieren des Chat-Codes
// @description:de               existieren chatgpt.com Fügen Sie in der unteren rechten Ecke des oberen Codeblocks eine Animation hinzu“Code kopieren”Taste
// @name:el                          ChatGPT Κουμπί αντιγραφής κωδικού συνομιλίας
// @description:el               υπάρχω chatgpt.com Προσθέστε μια κινούμενη εικόνα στην κάτω δεξιά γωνία του επάνω μπλοκ κώδικα“Αντιγραφή κωδικού”κουμπί
// @name:en                          ChatGPT Chat copy code button
// @description:en               exist chatgpt.com Add an animation in the lower right corner of the upper code block“Copy code”button
// @name:eo                          ChatGPT Babilejo kopia kodo butono
// @description:eo               ekzisti chatgpt.com Aldonu animacion en la malsupra dekstra angulo de la supra kodbloko“Kopiu kodon”butonon
// @name:es                          ChatGPT Botón de copiar código de chat
// @description:es               existir chatgpt.com Agregue una animación en la esquina inferior derecha del bloque de código superior“Copiar código”botón
// @name:fi                          ChatGPT Chat-koodin kopiointipainike
// @description:fi               olemassa chatgpt.com Lisää animaatio ylemmän koodilohkon oikeaan alakulmaan“Kopioi koodi”-painiketta
// @name:fr                          ChatGPT Bouton de copie du code de chat
// @description:fr               exister chatgpt.com Ajoutez une animation dans le coin inférieur droit du bloc de code supérieur“Copier le code”bouton
// @name:he                          ChatGPT לחצן העתקת קוד צ’אט
// @description:he               לְהִתְקַיֵם chatgpt.com הוסף אנימציה בפינה הימנית התחתונה של גוש הקוד העליון“העתק קוד”לַחְצָן
// @name:hr                          ChatGPT Gumb za kopiranje koda za chat
// @description:hr               postojati chatgpt.com Dodajte animaciju u donji desni kut gornjeg bloka koda“Kopiraj kod”dugme
// @name:hu                          ChatGPT Csevegési kódmásolás gomb
// @description:hu               létezik chatgpt.com Adjon hozzá animációt a felső kódblokk jobb alsó sarkába“Kód másolása”gomb
// @name:id                          ChatGPT Tombol salin kode obrolan
// @description:id               ada chatgpt.com Tambahkan animasi di sudut kanan bawah blok kode atas“Salin kode”tombol
// @name:it                          ChatGPT Pulsante copia codice chat
// @description:it               esistere chatgpt.com Aggiungi un’animazione nell’angolo in basso a destra del blocco di codice superiore“Copia il codice”pulsante
// @name:ja                          ChatGPT チャットコードコピーボタン
// @description:ja               存在する chatgpt.com 上部のコード ブロックの右下隅にアニメーションを追加します。“コードをコピーする”ボタン
// @name:ka                          ChatGPT ჩეთის კოპირების კოდის ღილაკი
// @description:ka               არსებობს chatgpt.com დაამატეთ ანიმაცია ზედა კოდის ბლოკის ქვედა მარჯვენა კუთხეში“დააკოპირეთ კოდი”ღილაკი
// @name:ko                          ChatGPT 채팅 코드 복사 버튼
// @description:ko               존재하다 chatgpt.com 상단 코드 블록의 오른쪽 하단에 애니메이션을 추가합니다.“코드 복사”단추
// @name:nl                          ChatGPT Knop voor chatkopieercode
// @description:nl               bestaan chatgpt.com Voeg een animatie toe in de rechter benedenhoek van het bovenste codeblok“Kopieer code”knop
// @name:nb                          ChatGPT Chat kopi kode knapp
// @description:nb               eksistere chatgpt.com Legg til en animasjon i nedre høyre hjørne av den øvre kodeblokken“Kopier koden”knapp
// @name:pl                          ChatGPT Przycisk kopiowania kodu czatu
// @description:pl               istnieć chatgpt.com Dodaj animację w prawym dolnym rogu górnego bloku kodu“Skopiuj kod”przycisk
// @name:pt-BR                          ChatGPT Botão copiar código do bate-papo
// @description:pt-BR               existir chatgpt.com Adicione uma animação no canto inferior direito do bloco de código superior“Copiar código”botão
// @name:ro                          ChatGPT Butonul de copiere a codului de chat
// @description:ro               exista chatgpt.com Adăugați o animație în colțul din dreapta jos al blocului de cod de sus“Copiați codul”buton
// @name:ru                          ChatGPT Кнопка копирования кода в чате
// @description:ru               существовать chatgpt.com Добавьте анимацию в правом нижнем углу верхнего блока кода.“Скопировать код”кнопка
// @name:sk                          ChatGPT Tlačidlo na kopírovanie kódu chatu
// @description:sk               existujú chatgpt.com Pridajte animáciu do pravého dolného rohu horného bloku kódu“Kopírovať kód”tlačidlo
// @name:sr                          ChatGPT Дугме за копирање кода за ћаскање
// @description:sr               постоје chatgpt.com Додајте анимацију у доњи десни угао горњег кодног блока“Копирај код”дугме
// @name:sv                          ChatGPT Knapp för chattkopiering
// @description:sv               existera chatgpt.com Lägg till en animation i det nedre högra hörnet av det övre kodblocket“Kopiera kod”knapp
// @name:th                          ChatGPT ปุ่มคัดลอกรหัสแชท
// @description:th               มีอยู่ chatgpt.com เพิ่มภาพเคลื่อนไหวที่มุมขวาล่างของบล็อกโค้ดด้านบน“คัดลอกรหัส”ปุ่ม
// @name:tr                          ChatGPT Sohbet kodunu kopyala düğmesi
// @description:tr               var olmak chatgpt.com Üst kod bloğunun sağ alt köşesine bir animasyon ekleyin“Kodu kopyala”düğme
// @name:ug                          ChatGPT پاراڭلىشىش كودى كۇنۇپكىسى
// @description:ug               مەۋجۇت chatgpt.com ئۈستۈنكى كود توپىنىڭ ئوڭ ئوڭ بۇلۇڭىغا كارتون قوشۇڭ“كودنى كۆچۈرۈڭ”كۇنۇپكا
// @name:uk                          ChatGPT Кнопка копіювання коду чату
// @description:uk               існують chatgpt.com Додайте анімацію в нижній правий кут верхнього блоку коду“Скопіюйте код”кнопку
// @name:vi                          ChatGPT Nút sao chép mã trò chuyện
// @description:vi               hiện hữu chatgpt.com Thêm hình động ở góc dưới bên phải của khối mã phía trên“Sao chép mã”cái nút
// @name:zh-TW                          ChatGPT 聊天複製代碼按鈕
// @description:zh-TW               在 chatgpt.com 上代碼區塊的右下角添加一個帶有動畫的“複製程式碼”按鈕
// @name:zh-HK                          ChatGPT 聊天複製代碼按鈕
// @description:zh-HK               在 chatgpt.com 上代碼區塊的右下角添加一個帶有動畫的“複製程式碼”按鈕
// @name:fr-CA                          ChatGPT Bouton de copie du code de chat
// @description:fr-CA               exister chatgpt.com Ajoutez une animation dans le coin inférieur droit du bloc de code supérieur“Copier le code”bouton
// @match                   https://chatgpt.com/*
// @match                   https://share.nezhagpt.cloud/*
// @author             YodaBets,人民的勤务员 <[email protected]>
// @namespace    https://github.com/ChinaGodMan/UserScripts
// @supportURL    https://github.com/ChinaGodMan/UserScripts/issues
// @homepageURL   https://github.com/ChinaGodMan/UserScripts
// @license      MIT
// @icon data:image/png;base64,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
// @compatible     chrome
// @compatible     firefox
// @compatible     edge
// @compatible     opera
// @compatible     safari
// @version         1.1.0.0
// @Created         2024-09-22 07:06:07
// @modified        2024-09-22 07:06:07
// ==/UserScript==
(function () {
    'use strict'
    var EXPORT = true
    const copyToClipboard = (text, button) => {
        navigator.clipboard.writeText(text).then(() => {
            console.log('Copied code to clipboard')
            button.innerHTML = 'Copied!'
            setTimeout(() => {
                button.innerHTML = '' // Clear the text
                const svgIcon = getSVGIcon() // Re-add the SVG icon
                button.appendChild(svgIcon)
            }, 2000)
        }, (err) => {
            console.error('Failed to copy code: ', err)
        })
    }
    function getSVGIcon(isEx = false) {
        const svgIcon = document.createElementNS('http://www.w3.org/2000/svg', 'svg')
        svgIcon.setAttribute('width', '24')
        svgIcon.setAttribute('height', '24')
        svgIcon.setAttribute('fill', 'none')
        svgIcon.setAttribute('viewBox', '0 0 24 24')
        svgIcon.classList.add('icon-sm')
        const path = document.createElementNS('http://www.w3.org/2000/svg', 'path')
        path.setAttribute('fill', 'currentColor')
        path.setAttribute('fill-rule', 'evenodd')
        if (isEx) {
            path.setAttribute('transform', 'rotate(180 12 12)')
            path.setAttribute('d', 'M5 20a1 1 0 0 1 1-1h12a1 1 0 1 1 0 2H6a1 1 0 0 1-1-1zm7-2a1 1 0 0 1-1-1V8.414L9.707 10.707a1 1 0 1 1-1.414-1.414l4-4a1 1 0 0 1 1.414 0l4 4a1 1 0 0 1-1.414 1.414L13 8.414V17a1 1 0 0 1-1 1z')
        } else {
            path.setAttribute('d', 'M7 5a3 3 0 0 1 3-3h9a3 3 0 0 1 3 3v9a3 3 0 0 1-3 3h-2v2a3 3 0 0 1-3 3H5a3 3 0 0 1-3-3v-9a3 3 0 0 1 3-3h2zm2 2h5a3 3 0 0 1 3 3v5h2a1 1 0 0 0 1-1V5a1 1 0 0 0-1-1h-9a1 1 0 0 0-1 1zM5 9a1 1 0 0 0-1 1v9a1 1 0 0 0 1 1h9a1 1 0 0 0 1-1v-9a1 1 0 0 0-1-1z')
        }
        path.setAttribute('clip-rule', 'evenodd')
        svgIcon.appendChild(path)
        return svgIcon
    }
    const addButton = (elem) => {
        const button = document.createElement('button')
        const svgIcon = getSVGIcon()
        button.appendChild(svgIcon)
        button.style.position = 'absolute'
        button.style.bottom = '8px'
        button.style.right = '8px'
        button.style.fontSize = '12px'
        button.style.padding = '4px 8px'
        button.style.border = '1px solid #ccc'
        button.style.borderRadius = '3px'
        button.style.background = 'rgba(0,0,0,0.1)'
        button.style.color = 'white'
        button.style.cursor = 'pointer'
        button.style.zIndex = '10'
        button.style.transition = 'background-color 0.3s ease'
        button.addEventListener('click', (e) => {
            e.stopPropagation()
            copyToClipboard(elem.querySelector('code').textContent, button)
        })
        button.addEventListener('mouseover', () => {
            button.style.backgroundColor = 'rgba(0,0,0,0.2)'
        })
        button.addEventListener('mouseout', () => {
            button.style.backgroundColor = 'rgba(0,0,0,0.1)'
        })
        elem.style.position = 'relative'
        elem.appendChild(button)
    }
    const addexButton = (elem) => {
        const button = document.createElement('button')
        const svgIcon = getSVGIcon(true)
        button.appendChild(svgIcon)
        button.style.position = 'absolute'
        button.style.bottom = '8px'
        button.style.right = '48px'
        button.style.fontSize = '12px'
        button.style.padding = '4px 8px'
        button.style.border = '1px solid #ccc'
        button.style.borderRadius = '3px'
        button.style.background = 'rgba(0,0,0,0.1)'
        button.style.color = 'white'
        button.style.cursor = 'pointer'
        button.style.zIndex = '10'
        button.style.transition = 'background-color 0.3s ease'
        button.addEventListener('click', (e) => {
            var languageDiv = elem.parentElement.parentElement.querySelector('div.flex.items-center.text-token-text-secondary')
            e.stopPropagation()
            exportCode(elem, languageDiv.textContent)
            //copyToClipboard(elem.querySelector('code').textContent, button)
        })
        elem.style.position = 'relative'
        elem.appendChild(button)
    }
    const observeCodeBlocks = () => {
        const codeBlocks = document.querySelectorAll('pre:not(.copy-code-processed)')
        if (codeBlocks.length) {
            codeBlocks.forEach(block => {
                addButton(block)
                if (EXPORT) {
                    addexButton(block)
                }
                block.classList.add('copy-code-processed')
            })
        }
    }
    async function exportCode(codeBlock, language) {
        let fileName
        let fileExtension
        let mimeType
        // Determine filename, extension, and MIME type based on language
        switch (language) {
            case 'javascript':
            case 'js':
                fileName = 'script'
                fileExtension = '.js'
                mimeType = 'application/javascript'
                break
            case 'html':
                fileName = 'index'
                fileExtension = '.html'
                mimeType = 'text/html'
                break
            case 'css':
                fileName = 'styles'
                fileExtension = '.css'
                mimeType = 'text/css'
                break
            case 'python':
            case 'py':
                fileName = 'main'
                fileExtension = '.py'
                mimeType = 'text/x-python'
                break
            default:
                // If language cannot be determined from <span>, fallback to provided language
                switch (language.toLowerCase()) {
                    case 'javascript':
                    case 'js':
                        fileName = 'script'
                        fileExtension = '.js'
                        mimeType = 'application/javascript'
                        break
                    case 'html':
                        fileName = 'index'
                        fileExtension = '.html'
                        mimeType = 'text/html'
                        break
                    case 'css':
                        fileName = 'styles'
                        fileExtension = '.css'
                        mimeType = 'text/css'
                        break
                    case 'python':
                    case 'py':
                        fileName = 'main'
                        fileExtension = '.py'
                        mimeType = 'text/x-python'
                        break
                    case 'java':
                        fileName = 'Main'
                        fileExtension = '.java'
                        mimeType = 'text/x-java-source'
                        break
                    case 'kotlin':
                        fileName = 'Main'
                        fileExtension = '.kt'
                        mimeType = 'text/x-kotlin'
                        break
                    case 'c++':
                    case 'cpp':
                        fileName = 'main'
                        fileExtension = '.cpp'
                        mimeType = 'text/x-c++src'
                        break
                    case 'c#':
                    case 'csharp':
                        fileName = 'Program'
                        fileExtension = '.cs'
                        mimeType = 'text/x-csharp'
                        break
                    case 'c':
                        fileName = 'main'
                        fileExtension = '.c'
                        mimeType = 'text/x-csrc'
                        break
                    case 'ruby':
                        fileName = 'script'
                        fileExtension = '.rb'
                        mimeType = 'text/x-ruby'
                        break
                    case 'rust':
                        fileName = 'main'
                        fileExtension = '.rs'
                        mimeType = 'text/x-rustsrc'
                        break
                    case 'php':
                        fileName = 'script'
                        fileExtension = '.php'
                        mimeType = 'text/x-php'
                        break
                    case 'swift':
                        fileName = 'main'
                        fileExtension = '.swift'
                        mimeType = 'text/x-swift'
                        break
                    case 'typescript':
                    case 'ts':
                        fileName = 'script'
                        fileExtension = '.ts'
                        mimeType = 'application/typescript'
                        break
                    case 'go':
                        fileName = 'main'
                        fileExtension = '.go'
                        mimeType = 'text/x-go'
                        break
                    case 'perl':
                        fileName = 'script'
                        fileExtension = '.pl'
                        mimeType = 'text/x-perl'
                        break
                    case 'lua':
                        fileName = 'script'
                        fileExtension = '.lua'
                        mimeType = 'text/x-lua'
                        break
                    default:
                        fileName = 'code'
                        fileExtension = '.txt'
                        mimeType = 'text/plain'
                        break
                }
                break
        }
        // Create a Blob object with the code content
        const blob = new Blob([codeBlock.querySelector('code').textContent], { type: mimeType })
        try {
            if (window.showSaveFilePicker) {
                // Use File System Access API if available
                const fileHandle = await window.showSaveFilePicker({
                    suggestedName: fileName + fileExtension,
                    types: [
                        {
                            description: language,
                            accept: {
                                [mimeType]: [fileExtension],
                            },
                        },
                    ],
                })
                const writable = await fileHandle.createWritable()
                await writable.write(blob)
                await writable.close()
            } else {
                // Fallback for browsers that do not support showSaveFilePicker
                const downloadLink = document.createElement('a')
                downloadLink.href = URL.createObjectURL(blob)
                downloadLink.download = fileName + fileExtension
                downloadLink.style.display = 'none'
                document.body.appendChild(downloadLink)
                downloadLink.click()
                URL.revokeObjectURL(downloadLink.href)
                document.body.removeChild(downloadLink)
            }
        } catch (error) {
            console.error('Save file dialog was canceled or failed', error)
        }
    }
    setTimeout(() => {
        const observer = new MutationObserver(observeCodeBlocks)
        observer.observe(document.body, { childList: true, subtree: true })
        observeCodeBlocks()
    }, 5000)
})()