您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Adds a "Copy Code" button, centered at the bottom of specified code block structures.
当前为
// ==UserScript== // @name gemini 代码底部增加复制按钮 // @namespace http://tampermonkey.net/ // @version 0.3 // @description Adds a "Copy Code" button, centered at the bottom of specified code block structures. // @author cores // @match https://gemini.google.com/app/* // @grant GM_addStyle // @grant GM_setClipboard // @license MIT // ==/UserScript== (function() { 'use strict'; const CUSTOM_BUTTON_CLASS = 'custom-bottom-copy-button'; const FOOTER_CLASS = 'custom-code-block-footer'; const PROCESSED_MARKER_CLASS = 'custom-centered-copy-added'; // Renamed for clarity function createAndAddButton(codeBlockElement) { // Check if already processed by this version of the script if (codeBlockElement.classList.contains(PROCESSED_MARKER_CLASS)) { return; } const codeContentElement = codeBlockElement.querySelector('code[data-test-id="code-content"], pre code'); if (!codeContentElement) { // console.warn('[Centered Copy Button] Code content element not found in:', codeBlockElement); return; } const copyButton = document.createElement('button'); copyButton.textContent = '复制'; copyButton.className = CUSTOM_BUTTON_CLASS; copyButton.setAttribute('aria-label', '复制'); copyButton.addEventListener('click', async (event) => { event.stopPropagation(); const codeText = codeContentElement.innerText; const originalButtonText = copyButton.textContent; try { await navigator.clipboard.writeText(codeText); copyButton.textContent = '已复制'; } catch (err) { try { GM_setClipboard(codeText); copyButton.textContent = '已复制 (GM)!'; } catch (gmErr) { copyButton.textContent = '复制失败'; alert('无法复制代码到剪贴板。请手动复制。'); } } setTimeout(() => { copyButton.textContent = originalButtonText; }, 2500); }); let footerDiv = codeBlockElement.querySelector('.' + FOOTER_CLASS); if (!footerDiv) { footerDiv = document.createElement('div'); footerDiv.className = FOOTER_CLASS; codeBlockElement.appendChild(footerDiv); } // Clear previous content if any (e.g. from old version of script if classname was same) // footerDiv.innerHTML = ''; footerDiv.appendChild(copyButton); codeBlockElement.classList.add(PROCESSED_MARKER_CLASS); } function processAllCodeBlocks() { const codeBlocks = document.querySelectorAll('div.code-block'); codeBlocks.forEach(block => { createAndAddButton(block); }); } // Add styles for the new button and its centering container (footer) GM_addStyle(` .${FOOTER_CLASS} { display: flex; justify-content: center; /* MODIFIED: Center the button */ align-items: center; /* Vertically center if footer has extra height */ padding: 8px 0px; /* Padding top/bottom; no side padding needed for centering one item */ margin-top: 8px; /* Space between code block content and button area */ /* border-top: 1px solid #e0e0e0; */ /* Optional: Uncomment for a separator line */ /* background-color: #f9f9f9; */ /* Optional: Uncomment for a distinct footer background */ } .${CUSTOM_BUTTON_CLASS} { background-color: transparent; /* MODIFIED: Transparent background */ color: #007bff; /* MODIFIED: Text color (e.g., blue) */ border: 1px solid #007bff; /* MODIFIED: Border to make button visible */ padding: 7px 15px; /* Adjusted padding for border */ text-align: center; text-decoration: none; display: inline-block; font-size: 13px; border-radius: 4px; cursor: pointer; transition: color 0.3s ease, border-color 0.3s ease, transform 0.1s ease; /*MODIFIED: transition properties */ } .${CUSTOM_BUTTON_CLASS}:hover { color: #0056b3; /* MODIFIED: Darker text color on hover */ border-color: #0056b3; /* MODIFIED: Darker border color on hover */ /* background-color: rgba(0, 123, 255, 0.05); */ /* Optional: very subtle background on hover */ } .${CUSTOM_BUTTON_CLASS}:active { color: #004085; /* MODIFIED: Even darker text when clicked */ border-color: #004085; /* MODIFIED: Even darker border when clicked */ transform: scale(0.98); /* Slight press effect */ } `); // Initial run to add buttons to existing code blocks processAllCodeBlocks(); // Use MutationObserver to handle dynamically loaded code blocks const observer = new MutationObserver((mutationsList) => { for (const mutation of mutationsList) { if (mutation.type === 'childList' && mutation.addedNodes.length > 0) { mutation.addedNodes.forEach(node => { if (node.nodeType === Node.ELEMENT_NODE) { if (node.matches && node.matches('div.code-block')) { createAndAddButton(node); } node.querySelectorAll('div.code-block').forEach(createAndAddButton); } }); } } }); observer.observe(document.body, { childList: true, subtree: true }); })();