// ==UserScript== // @name 😍ChatGPT - Prompt便签 // @version 6.0 // @description 一个帮助用户在ChatGPT原生网页添加可移动且大小可调的便签,用于快速选择和添加prompt的脚本。 // @author futureo0 // @require https://ajax.aspnetcdn.com/ajax/jQuery/jquery-3.6.4.min.js // @match https://chat.openai.com/* // @match https://chat.openai.com/c/* // @match https://chat.openai.com/?* // @match https://neu.learnwithgpt.beauty/ // @match https://neu.learnwithgpt.beauty/c // @match https://neu.learnwithgpt.beauty/c/* // @match *://chatgpt.com/* // @run-at document-start // @grant GM_setValue // @grant GM_getValue // @namespace https://greasyfork.org/users/1242018 // @downloadURL https://update.greasyfork.icu/scripts/483640/%F0%9F%98%8DChatGPT%20-%20Prompt%E4%BE%BF%E7%AD%BE.user.js // @updateURL https://update.greasyfork.icu/scripts/483640/%F0%9F%98%8DChatGPT%20-%20Prompt%E4%BE%BF%E7%AD%BE.meta.js // ==/UserScript== (function () { 'use strict'; $(document).ready(function() { const stickyNoteHtml = `
`; $('body').append(stickyNoteHtml); dragElement(document.getElementById("stickyNoteContainer"), document.getElementById("stickyNoteHeader")); loadPrompts(); $('#savePromptButton').click(function() { const newPrompt = $('#newPromptInput').val().trim(); if(newPrompt) { addPromptToStickyNote(newPrompt); savePrompt(newPrompt); $('#newPromptInput').val(''); } }); // MutationObserver to monitor DOM changes and re-insert the sticky note if it’s removed const observer = new MutationObserver(() => { if (!document.getElementById("stickyNoteContainer")) { $('body').append(stickyNoteHtml); // Re-append the sticky note dragElement(document.getElementById("stickyNoteContainer"), document.getElementById("stickyNoteHeader")); loadPrompts(); } }); // Start observing the body for changes observer.observe(document.body, { childList: true, subtree: true }); }); function loadPrompts() { const prompts = JSON.parse(GM_getValue('prompts', '[]')); prompts.forEach(prompt => { addPromptToStickyNote(prompt); }); } function addPromptToStickyNote(promptText) { const promptHtml = `
${promptText}
`; $('#promptsList').prepend(promptHtml); $('#promptsList .deletePromptButton:first').click(function() { const promptText = $(this).siblings('div').text(); // 获取被点击的Prompt的文本内容 removePromptByText(promptText); // 用文本内容删除Prompt $(this).parent().remove(); // 从UI中删除 }); // Use mousedown event to prevent focus loss $('#promptsList div:first').on('mousedown', function(e) { e.preventDefault(); // Prevent the div from stealing focus const inputField = getActiveInputField(); if (inputField) { insertAtCursor(inputField, promptText); } else { console.error('No input field found to insert text into.'); } }); } function removePromptByText(promptText) { let prompts = JSON.parse(GM_getValue('prompts', '[]')); const promptIndex = prompts.indexOf(promptText); // 根据文本内容找到Prompt的索引 if (promptIndex !== -1) { prompts.splice(promptIndex, 1); // 删除匹配的Prompt GM_setValue('prompts', JSON.stringify(prompts)); // 更新存储 } } function savePrompt(promptText) { let prompts = JSON.parse(GM_getValue('prompts', '[]')); prompts.push(promptText); GM_setValue('prompts', JSON.stringify(prompts)); } function dragElement(elmnt, header) { var pos1 = 0, pos2 = 0, pos3 = 0, pos4 = 0; header.onmousedown = dragMouseDown; function dragMouseDown(e) { if (e.target === header) { e = e || window.event; e.preventDefault(); pos3 = e.clientX; pos4 = e.clientY; document.onmouseup = closeDragElement; document.onmousemove = elementDrag; } } function elementDrag(e) { e = e || window.event; e.preventDefault(); pos1 = pos3 - e.clientX; pos2 = pos4 - e.clientY; pos3 = e.clientX; pos4 = e.clientY; elmnt.style.top = (elmnt.offsetTop - pos2) + "px"; elmnt.style.left = (elmnt.offsetLeft - pos1) + "px"; } function closeDragElement() { document.onmouseup = null; document.onmousemove = null; } } function getActiveInputField() { // Get the currently focused element let activeElement = document.activeElement; // If it's a textarea or contenteditable div, return it if ((activeElement.tagName.toLowerCase() === 'textarea') || activeElement.isContentEditable) { return activeElement; } // No suitable input field found return null; } function insertAtCursor(myField, myValue) { // Ensure the field is focused myField.focus(); if (myField.isContentEditable) { // For contenteditable elements var sel = window.getSelection(); if (sel.rangeCount > 0) { var range = sel.getRangeAt(0); // Ensure the selection is within myField if (myField.contains(range.commonAncestorContainer)) { range.deleteContents(); var textNode = document.createTextNode(myValue); range.insertNode(textNode); // Move the cursor after the inserted text node range.setStartAfter(textNode); range.setEndAfter(textNode); sel.removeAllRanges(); sel.addRange(range); } else { // If selection is not in myField, place cursor at the end var newRange = document.createRange(); newRange.selectNodeContents(myField); newRange.collapse(false); // collapse to end var textNode = document.createTextNode(myValue); newRange.insertNode(textNode); // Move the cursor after the inserted text node newRange.setStartAfter(textNode); newRange.setEndAfter(textNode); sel.removeAllRanges(); sel.addRange(newRange); } } else { // No selection, insert at end var newRange = document.createRange(); newRange.selectNodeContents(myField); newRange.collapse(false); // collapse to end var textNode = document.createTextNode(myValue); newRange.insertNode(textNode); // Move the cursor after the inserted text node newRange.setStartAfter(textNode); newRange.setEndAfter(textNode); var sel = window.getSelection(); sel.removeAllRanges(); sel.addRange(newRange); } } else if (myField.tagName.toLowerCase() === 'textarea' || myField.tagName.toLowerCase() === 'input') { // For input or textarea elements if (myField.selectionStart || myField.selectionStart == '0') { var startPos = myField.selectionStart; var endPos = myField.selectionEnd; myField.value = myField.value.substring(0, startPos) + myValue + myField.value.substring(endPos, myField.value.length); myField.selectionStart = myField.selectionEnd = startPos + myValue.length; } else { myField.value += myValue; } } else { console.error('Unsupported input field.'); } // Trigger input event to ensure changes are recognized var event = new Event('input', { bubbles: true }); myField.dispatchEvent(event); } })();