使用方法,粘贴到控制台确定,之后点击任意对话标题自动删除! 小心操作!!
// ==UserScript==
// @name Gemini 极速删除助手 (安全版+AltQ开关)
// @namespace http://tampermonkey.net/
// @version 5.0
// @description 绕过 TrustedHTML 限制,按 Alt+Q 显示删除图标,点击直接删除(无确认)。
// @author Frank Salvio & Gemini
// @match https://gemini.google.com/*
// @grant GM_setValue
// @grant GM_getValue
// @grant GM_registerMenuCommand
// ==/UserScript==
(function() {
'use strict';
const STORAGE_KEY = 'gemini_quick_del_mode';
let isEnabled = GM_getValue(STORAGE_KEY, false);
// --- 1. 安全创建 SVG 图标 (绕过 innerHTML) ---
function createTrashIcon() {
const svg = document.createElementNS("http://www.w3.org/2000/svg", "svg");
svg.setAttribute("viewBox", "0 -960 960 960");
svg.setAttribute("height", "20px");
svg.setAttribute("width", "20px");
svg.setAttribute("fill", "currentColor");
const path = document.createElementNS("http://www.w3.org/2000/svg", "path");
path.setAttribute("d", "M280-120q-33 0-56.5-23.5T200-200v-520h-40v-80h200v-40h240v40h200v80h-40v520q0 33-23.5 56.5T680-120H280Zm400-600H280v520h400v-520ZM360-280h80v-360h-80v360Zm160 0h80v-360h-80v360ZM280-720v520-520Z");
svg.appendChild(path);
return svg;
}
// --- 2. 注入 CSS (使用 textContent 安全注入) ---
const style = document.createElement('style');
style.textContent = `
/* 仅在激活模式下,强制显示操作容器 */
body.del-mode-active .conversation-actions-container {
display: flex !important;
opacity: 1 !important;
visibility: visible !important;
padding-right: 4px;
}
/* 默认隐藏删除按钮 */
.safe-del-btn {
display: none;
align-items: center;
justify-content: center;
width: 28px;
height: 28px;
cursor: pointer;
border-radius: 50%;
margin-right: 2px;
color: #ea4335;
background-color: rgba(234, 67, 53, 0.05);
transition: all 0.2s;
}
/* 激活模式下显示按钮 */
body.del-mode-active .safe-del-btn {
display: flex !important;
}
.safe-del-btn:hover {
background-color: #ea4335;
color: white !important;
box-shadow: 0 1px 3px rgba(0,0,0,0.2);
}
`;
document.head.appendChild(style);
// --- 3. 提示框 Toast (DOM 创建) ---
function showToast(text, active) {
const existing = document.getElementById('g-del-toast');
if (existing) existing.remove();
const toast = document.createElement('div');
toast.id = 'g-del-toast';
toast.textContent = text;
Object.assign(toast.style, {
position: 'fixed',
bottom: '30px',
left: '50%',
transform: 'translateX(-50%)',
background: active ? '#188038' : '#5f6368',
color: 'white',
padding: '8px 16px',
borderRadius: '24px',
fontSize: '14px',
zIndex: '999999',
pointerEvents: 'none',
opacity: '0',
transition: 'opacity 0.3s'
});
document.body.appendChild(toast);
requestAnimationFrame(() => toast.style.opacity = '1');
setTimeout(() => {
toast.style.opacity = '0';
setTimeout(() => toast.remove(), 300);
}, 2000);
}
// --- 4. 模式切换 ---
function applyMode() {
if (isEnabled) {
document.body.classList.add('del-mode-active');
} else {
document.body.classList.remove('del-mode-active');
}
}
function toggleMode() {
isEnabled = !isEnabled;
GM_setValue(STORAGE_KEY, isEnabled);
applyMode();
showToast(isEnabled ? "⚡️ 极速删除模式:ON" : "💤 极速删除模式:OFF", isEnabled);
}
// --- 5. 删除逻辑 (无确认弹窗) ---
function executeDelete(container) {
const menuBtn = container.querySelector('button[data-test-id="actions-menu-button"]');
if (!menuBtn) return;
// 视觉反馈
const btn = container.querySelector('.safe-del-btn');
if(btn) btn.style.opacity = '0.5';
menuBtn.click(); // 打开菜单
// 轮询点击删除
const waiter = setInterval(() => {
const delOption = document.querySelector('button[data-test-id="delete-button"]');
if (delOption) {
clearInterval(waiter);
delOption.click();
// 轮询点击确认
const confirmer = setInterval(() => {
const confirmBtn = document.querySelector('button[data-test-id="confirm-button"]');
if (confirmBtn) {
clearInterval(confirmer);
confirmBtn.click();
console.log('Gemini 删除助手:已删除');
}
}, 20);
}
}, 20);
// 超时清除
setTimeout(() => clearInterval(waiter), 2000);
}
// --- 6. 注入按钮 (DOM 操作) ---
function inject() {
// 查找所有尚未注入的容器
const containers = document.querySelectorAll('.conversation-actions-container:not(.has-safe-del)');
containers.forEach(container => {
// 创建按钮容器
const btn = document.createElement('div');
btn.className = 'safe-del-btn';
btn.title = '直接删除 (无确认)';
// 插入 SVG 图标
btn.appendChild(createTrashIcon());
// 绑定点击事件 (无 confirm)
btn.addEventListener('click', (e) => {
e.preventDefault();
e.stopPropagation();
executeDelete(container);
});
// 插入到 DOM
const menuBtn = container.querySelector('button[data-test-id="actions-menu-button"]');
if (menuBtn) {
container.insertBefore(btn, menuBtn);
container.classList.add('has-safe-del');
}
});
}
// --- 7. 初始化与监听 ---
applyMode();
inject();
// 监听 Alt+Q
window.addEventListener('keydown', (e) => {
if (e.altKey && e.key.toLowerCase() === 'q') {
e.preventDefault();
toggleMode();
}
});
// 观察页面变化 (动态加载)
const observer = new MutationObserver(inject);
observer.observe(document.body, { childList: true, subtree: true });
// 菜单命令
GM_registerMenuCommand("切换删除模式 (Alt+Q)", toggleMode);
})();新版
// ==UserScript==
// @name Gemini 效率增强助手 (阻止滚动 + 极速删除 + 划词引用 + 快速跳转)
// @namespace http://tampermonkey.net/
// @version 8.5
// @description 整合版:1. 阻止自动滚动;2. 极速删除图标(Alt+Q);3. 划词悬浮引用;4. 添加面板折叠开关;5. 修复特定容器的顶部/底部快速跳转。(v8.5 解决双通道点击冒泡冲突,完美修复极速删除流)
// @author Gemini & Frank Salvio
// @match https://gemini.google.com/*
// @icon https://www.google.com/s2/favicons?sz=64&domain=gemini.google.com
// @grant none
// ==/UserScript==
(function() {
'use strict';
console.log('%c[Gemini Helper] 脚本已启动 (v8.5)...', 'color: #1a73e8; font-weight: bold;');
// --- 状态管理 (从本地存储读取) ---
let preventScroll = localStorage.getItem('gemini_prevent_scroll') === 'true';
let delModeActive = localStorage.getItem('gemini_del_mode') === 'true';
let quoteModeActive = localStorage.getItem('gemini_quote_mode') === 'true';
let uiVisible = localStorage.getItem('gemini_ui_visible') !== 'false';
// --- 1. 阻止自动滚动逻辑 (保留原生方法引用以便手动调用) ---
const originalWindowScrollTo = window.scrollTo;
const originalElementScrollTo = Element.prototype.scrollTo;
const originalScrollIntoView = Element.prototype.scrollIntoView;
window.scrollTo = function(...args) { if (!preventScroll) originalWindowScrollTo.apply(this, args); };
Element.prototype.scrollTo = function(...args) { if (!preventScroll) originalElementScrollTo.apply(this, args); };
Element.prototype.scrollIntoView = function(...args) { if (!preventScroll) originalScrollIntoView.apply(this, args); };
const scrollTopDescriptor = Object.getOwnPropertyDescriptor(Element.prototype, 'scrollTop');
if (scrollTopDescriptor) {
Object.defineProperty(Element.prototype, 'scrollTop', {
get: function() { return scrollTopDescriptor.get.call(this); },
set: function(val) { if (!preventScroll) scrollTopDescriptor.set.call(this, val); }
});
}
// --- 2. 极速删除逻辑 ---
function createTrashIcon() {
const svg = document.createElementNS("http://www.w3.org/2000/svg", "svg");
svg.setAttribute("viewBox", "0 -960 960 960");
svg.setAttribute("height", "18px");
svg.setAttribute("width", "18px");
svg.setAttribute("fill", "currentColor");
const path = document.createElementNS("http://www.w3.org/2000/svg", "path");
path.setAttribute("d", "M280-120q-33 0-56.5-23.5T200-200v-520h-40v-80h200v-40h240v40h200v80h-40v520q0 33-23.5 56.5T680-120H280Zm400-600H280v520h400v-520ZM360-280h80v-360h-80v360Zm160 0h80v-360h-80v360ZM280-720v520-520Z");
svg.appendChild(path);
return svg;
}
function executeDelete(container) {
// 1. 定位菜单按钮包裹层 (gem-icon-button)
const menuWrapper = container.querySelector('[data-test-id="actions-menu-button"]');
if (!menuWrapper) return;
// 【单点精准冒泡策略】
// 优先点击最内部的原生 button,让事件自然冒泡到包装器上触发 Angular 监听器。
// 绝不能同时调用 menuWrapper.click() 和 innerButton.click(),否则会引发双击冲突导致菜单瞬间关闭!
const realMenuBtn = menuWrapper.querySelector('button') || menuWrapper;
realMenuBtn.click();
const waiter = setInterval(() => {
// 2. 定位弹出的“删除”选项按钮 (通常在 cdk-overlay 中)
const delOption = document.querySelector('[data-test-id="delete-button"]');
if (delOption) {
clearInterval(waiter);
// 同样采用单点精准点击
const realDelBtn = delOption.querySelector('button') || delOption;
realDelBtn.click();
const confirmer = setInterval(() => {
// 3. 定位弹出的“确认删除”确认框按钮 (gem-button)
const confirmWrapper = document.querySelector('[data-test-id="confirm-button"]');
if (confirmWrapper) {
clearInterval(confirmer);
// 同样采用单点精准点击
const realConfirmBtn = confirmWrapper.querySelector('button') || confirmWrapper;
realConfirmBtn.click();
console.log('[Gemini Helper] 消息已通过单点精准冒泡方案安全删除');
}
}, 20);
setTimeout(() => clearInterval(confirmer), 2000);
}
}, 20);
setTimeout(() => clearInterval(waiter), 2000);
}
// --- 3. 样式注入 ---
const style = document.createElement('style');
style.textContent = `
/* 删除按钮样式 */
.safe-del-btn {
display: none; align-items: center; justify-content: center;
width: 28px; height: 28px; cursor: pointer; border-radius: 50%;
margin-right: 6px; color: #ea4335; background: rgba(234, 67, 53, 0.1);
transition: all 0.2s;
z-index: 10;
align-self: center;
vertical-align: middle;
flex-shrink: 0; /* 防止图标被弹性盒压缩 */
}
body.del-mode-on .safe-del-btn { display: inline-flex !important; }
/* 兼容新旧版本的控制容器:强行应用弹性行布局实现左右并排,并垂直居中对齐 */
body.del-mode-on .conversation-actions-container,
body.del-mode-on .hovered-trailing-content {
display: flex !important;
flex-direction: row !important; /* 强行设为水平排列,解决上下并排问题 */
align-items: center !important; /* 强行垂直居中对齐 */
justify-content: flex-end !important;/* 靠右侧对齐 */
opacity: 1 !important;
visibility: visible !important;
}
.safe-del-btn:hover { background: #ea4335; color: white !important; }
/* 面板显示/隐藏开关 */
#gemini-toggle-btn {
position: fixed; top: 65px; right: 20px; z-index: 10000;
width: 32px; height: 32px; border-radius: 50%; border: none;
background: #5f6368; color: white; font-size: 16px; cursor: pointer;
box-shadow: 0 2px 5px rgba(0,0,0,0.2); transition: all 0.3s;
display: flex; justify-content: center; align-items: center;
user-select: none;
}
/* 悬浮按钮组容器 */
#gemini-tools-container {
position: fixed; top: 105px; right: 20px; z-index: 9999;
display: flex; flex-direction: column; gap: 8px;
transition: opacity 0.3s, transform 0.3s; transform-origin: top right;
}
#gemini-tools-container.hidden {
opacity: 0; pointer-events: none; transform: scale(0.9);
}
.gemini-tool-btn {
padding: 6px 12px; border: none; border-radius: 12px;
color: white; font-size: 12px; font-weight: 500; cursor: pointer;
box-shadow: 0 2px 5px rgba(0,0,0,0.2); transition: 0.3s;
font-family: sans-serif; text-align: center; min-width: 110px;
}
/* 底部跳转按钮行 */
.gemini-btn-row {
display: flex; gap: 4px; width: 100%;
}
.gemini-tool-btn-small {
flex: 1; min-width: 0; padding: 6px 4px; font-size: 11px;
background-color: #5f6368; border-radius: 8px; color: white;
border: none; cursor: pointer; box-shadow: 0 2px 5px rgba(0,0,0,0.1);
}
.gemini-tool-btn-small:hover { background-color: #444; }
/* 划词悬浮引用按钮 */
#gemini-quote-popup {
position: absolute; display: none; background: #1a73e8; color: white;
padding: 6px 12px; border-radius: 8px; font-size: 13px; font-weight: bold;
cursor: pointer; box-shadow: 0 4px 10px rgba(0,0,0,0.2); z-index: 10000;
user-select: none; transition: background 0.2s; font-family: sans-serif;
}
`;
document.head.appendChild(style);
// --- 4. 划词引用逻辑 ---
const quotePopup = document.createElement('div');
quotePopup.id = 'gemini-quote-popup';
quotePopup.innerText = '💬 引用';
document.body.appendChild(quotePopup);
document.addEventListener('mouseup', (e) => {
if (!quoteModeActive) return;
const selectedText = window.getSelection().toString().trim();
if (selectedText && e.target.id !== 'gemini-quote-popup') {
quotePopup.style.display = 'block';
quotePopup.style.left = `${e.pageX + 10}px`;
quotePopup.style.top = `${e.pageY + 15}px`;
} else if (e.target.id !== 'gemini-quote-popup') {
quotePopup.style.display = 'none';
}
});
quotePopup.addEventListener('mousedown', (e) => e.preventDefault());
quotePopup.addEventListener('click', () => {
const selectedText = window.getSelection().toString().trim();
if (!selectedText) return;
const editor = document.querySelector('rich-textarea div[contenteditable="true"]') || document.querySelector('[contenteditable="true"]');
if (editor) {
editor.focus();
const quoteStr = `\`\`\`\n${selectedText}\n\`\`\`\n\n`;
document.execCommand('insertText', false, quoteStr);
editor.dispatchEvent(new Event('input', { bubbles: true }));
console.log('[Gemini Helper] 已引用文本');
}
quotePopup.style.display = 'none';
window.getSelection().removeAllRanges();
});
// --- 5. UI 注入与更新 ---
function updateUIVisibility() {
const container = document.getElementById('gemini-tools-container');
const toggleBtn = document.getElementById('gemini-toggle-btn');
if (!container || !toggleBtn) return;
if (uiVisible) {
container.classList.remove('hidden');
toggleBtn.style.background = '#1a73e8';
toggleBtn.title = '隐藏助手面板';
} else {
container.classList.add('hidden');
toggleBtn.style.background = '#5f6368';
toggleBtn.title = '显示助手面板';
}
}
function updateUI() {
const sBtn = document.getElementById('btn-scroll-lock');
const dBtn = document.getElementById('btn-del-mode');
const qBtn = document.getElementById('btn-quote-mode');
if (sBtn) {
sBtn.innerText = preventScroll ? '🚫 滚动已锁定' : '↔️ 自由滚动';
sBtn.style.backgroundColor = preventScroll ? '#d32f2f' : '#5f6368';
}
if (dBtn) {
dBtn.innerText = delModeActive ? '⚡ 极速删除: ON' : '💤 极速删除: OFF';
dBtn.style.backgroundColor = delModeActive ? '#188038' : '#5f6368';
}
if (qBtn) {
qBtn.innerText = quoteModeActive ? '💬 划词引用: ON' : '💬 划词引用: OFF';
qBtn.style.backgroundColor = quoteModeActive ? '#1a73e8' : '#5f6368';
}
if (delModeActive) document.body.classList.add('del-mode-on');
else document.body.classList.remove('del-mode-on');
}
function createUI() {
if (document.getElementById('gemini-helper-wrapper')) return;
const wrapper = document.createElement('div');
wrapper.id = 'gemini-helper-wrapper';
const toggleBtn = document.createElement('button');
toggleBtn.id = 'gemini-toggle-btn';
toggleBtn.innerText = '⚙️';
toggleBtn.onclick = () => {
uiVisible = !uiVisible;
localStorage.setItem('gemini_ui_visible', uiVisible);
updateUIVisibility();
};
const container = document.createElement('div');
container.id = 'gemini-tools-container';
const sBtn = document.createElement('button');
sBtn.id = 'btn-scroll-lock';
sBtn.className = 'gemini-tool-btn';
sBtn.onclick = () => {
preventScroll = !preventScroll;
localStorage.setItem('gemini_prevent_scroll', preventScroll);
updateUI();
};
const dBtn = document.createElement('button');
dBtn.id = 'btn-del-mode';
dBtn.className = 'gemini-tool-btn';
dBtn.onclick = () => {
delModeActive = !delModeActive;
localStorage.setItem('gemini_del_mode', delModeActive);
updateUI();
};
const qBtn = document.createElement('button');
qBtn.id = 'btn-quote-mode';
qBtn.className = 'gemini-tool-btn';
qBtn.onclick = () => {
quoteModeActive = !quoteModeActive;
localStorage.setItem('gemini_quote_mode', quoteModeActive);
updateUI();
};
const btnRow = document.createElement('div');
btnRow.className = 'gemini-btn-row';
const topBtn = document.createElement('button');
topBtn.className = 'gemini-tool-btn-small';
topBtn.innerText = '⬆️ 顶部';
topBtn.onclick = () => {
const targetContainer = document.querySelector("#chat-history > infinite-scroller") || document.documentElement;
if (targetContainer === document.documentElement) {
originalWindowScrollTo.call(window, { top: 0, behavior: 'smooth' });
} else {
originalElementScrollTo.call(targetContainer, { top: 0, behavior: 'smooth' });
}
};
const bottomBtn = document.createElement('button');
bottomBtn.className = 'gemini-tool-btn-small';
bottomBtn.innerText = '⬇️ 底部';
bottomBtn.onclick = () => {
const targetContainer = document.querySelector("#chat-history > infinite-scroller") || document.documentElement;
if (targetContainer === document.documentElement) {
originalWindowScrollTo.call(window, { top: document.body.scrollHeight, behavior: 'smooth' });
} else {
originalElementScrollTo.call(targetContainer, { top: targetContainer.scrollHeight, behavior: 'smooth' });
}
};
btnRow.appendChild(topBtn);
btnRow.appendChild(bottomBtn);
container.appendChild(sBtn);
container.appendChild(dBtn);
container.appendChild(qBtn);
container.appendChild(btnRow);
wrapper.appendChild(toggleBtn);
wrapper.appendChild(container);
document.body.appendChild(wrapper);
updateUI();
updateUIVisibility();
}
// --- 6. 动态注入删除图标 ---
function injectDelIcons() {
// 先定位页面上所有“更多操作”菜单包裹层
const menuBtnWrappers = document.querySelectorAll('[data-test-id="actions-menu-button"]');
menuBtnWrappers.forEach(menuBtnWrapper => {
// 获取它的直接父容器,不管它的 class 变成了什么
const container = menuBtnWrapper.parentElement;
if (!container || container.classList.contains('has-safe-del')) return;
// 创建并插入删除垃圾桶图标
const btn = document.createElement('div');
btn.className = 'safe-del-btn';
btn.appendChild(createTrashIcon());
btn.onclick = (e) => {
e.preventDefault(); e.stopPropagation();
executeDelete(container);
};
// 将按钮插入到三个点菜单前面 (即左侧)
container.insertBefore(btn, menuBtnWrapper);
container.classList.add('has-safe-del');
});
}
// --- 7. 监听与初始化 ---
window.addEventListener('keydown', (e) => {
if (e.altKey && e.key.toLowerCase() === 'q') {
delModeActive = !delModeActive;
localStorage.setItem('gemini_del_mode', delModeActive);
console.log('[Gemini Helper] 快捷键触发 - 极速删除:', delModeActive);
updateUI();
}
});
const observer = new MutationObserver(() => {
createUI();
injectDelIcons();
});
observer.observe(document.body, { childList: true, subtree: true });
createUI();
injectDelIcons();
})();