// ==UserScript== // @name 🤤Claude - Prompt便签 // @version 1.2 // @description 一个帮助用户在Claude原生网页添加可移动且大小可调的便签,用于快速选择和添加prompt的脚本。 // @author futureo0 // @license MIT // @require https://ajax.aspnetcdn.com/ajax/jQuery/jquery-3.6.4.min.js // @match https://claude.ai/* // @match https://claude.ai/chats/* // @run-at document-idle // @grant GM_setValue // @grant GM_getValue // @namespace https://greasyfork.org/users/1242018 // @downloadURL https://update.greasyfork.icu/scripts/518680/%F0%9F%A4%A4Claude%20-%20Prompt%E4%BE%BF%E7%AD%BE.user.js // @updateURL https://update.greasyfork.icu/scripts/518680/%F0%9F%A4%A4Claude%20-%20Prompt%E4%BE%BF%E7%AD%BE.meta.js // ==/UserScript== (function () { 'use strict'; // 等待页面完全加载并确保输入框存在 function waitForElement(selector) { return new Promise(resolve => { if (document.querySelector(selector)) { return resolve(document.querySelector(selector)); } const observer = new MutationObserver(() => { if (document.querySelector(selector)) { resolve(document.querySelector(selector)); observer.disconnect(); } }); observer.observe(document.body, { childList: true, subtree: true }); }); } // 获取当前活动的输入区域 function getActiveInputField() { // 获取当前焦点元素 let activeElement = document.activeElement; // 如果是textarea或可编辑div,直接返回 if ((activeElement.tagName.toLowerCase() === 'textarea') || (activeElement.classList.contains('ProseMirror') && activeElement.isContentEditable)) { return activeElement; } // 获取所有可能的输入区域 const allInputs = Array.from(document.querySelectorAll('textarea, .ProseMirror[contenteditable="true"]')) .filter(input => input.offsetParent !== null); // 检查是否有输入框包含当前选区 const sel = window.getSelection(); if (sel.rangeCount > 0) { const range = sel.getRangeAt(0); for (const input of allInputs) { if (input.contains(range.commonAncestorContainer)) { return input; } } } // 如果没有找到,返回最后一个可见的输入框 return allInputs[allInputs.length - 1] || null; } function insertAtCursor(myField, myValue) { // 确保输入区域获得焦点 myField.focus(); if (myField.classList.contains('ProseMirror') && myField.isContentEditable) { // 处理 ProseMirror 编辑器 const sel = window.getSelection(); if (sel.rangeCount > 0) { const range = sel.getRangeAt(0); // 确保选区在目标输入框内 if (myField.contains(range.commonAncestorContainer)) { // 删除当前选中内容 range.deleteContents(); // 创建并插入文本节点 const textNode = document.createTextNode(myValue); range.insertNode(textNode); // 移动光标到插入文本之后 range.setStartAfter(textNode); range.setEndAfter(textNode); sel.removeAllRanges(); sel.addRange(range); } else { // 如果选区不在输入框内,在末尾插入 const newRange = document.createRange(); const lastChild = myField.lastChild; if (lastChild) { if (lastChild.nodeType === Node.TEXT_NODE) { newRange.setStartAfter(lastChild); newRange.setEndAfter(lastChild); } else { newRange.selectNodeContents(myField); newRange.collapse(false); } } else { newRange.selectNodeContents(myField); newRange.collapse(false); } const textNode = document.createTextNode(myValue); newRange.insertNode(textNode); // 移动光标到插入文本之后 newRange.setStartAfter(textNode); newRange.setEndAfter(textNode); sel.removeAllRanges(); sel.addRange(newRange); } } } else if (myField.tagName.toLowerCase() === 'textarea') { // 处理普通 textarea const startPos = myField.selectionStart; const endPos = myField.selectionEnd; // 在光标位置插入文本 myField.value = myField.value.substring(0, startPos) + myValue + myField.value.substring(endPos); // 更新光标位置 myField.selectionStart = myField.selectionEnd = startPos + myValue.length; } // 触发输入事件 const event = new Event('input', { bubbles: true }); myField.dispatchEvent(event); } // 初始化便签 async function initStickyNote() { // 等待输入框加载完成 await waitForElement('.ProseMirror[contenteditable="true"]'); // 检查是否已存在便签 if (document.getElementById('stickyNoteContainer')) { return; } const stickyNoteHtml = `