// ==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 = `
`;
$('#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);
}
})();