// ==UserScript== // @name Pre ChatGPT // @namespace http://tampermonkey.net/ // @version 1.0 // @description Handle multiple questions for ChatGPT // @author zizhan // @match https://chat.openai.com/* // @grant GM_addStyle // @license MIT // @downloadURL none // ==/UserScript== (function () { 'use strict'; // 添加 CSS 样式 GM_addStyle(` #sidebar { position: fixed; right: 0; top: 50%; transform: translateY(-50%); width: 300px; padding: 20px; background-color: #fafafa; border: 1px solid #ccc; border-radius: 10px; box-shadow: 0 0 15px rgba(0, 0, 0, 0.1); transition: all 0.3s ease-in-out; overflow: hidden; } #toggleSidebar { position: absolute; top: 50%; left: 0; transform: translateY(-50%); width: 30px; height: 30px; background: #fafafa; border: 1px solid #ccc; border-radius: 50%; box-shadow: 0 0 15px rgba(0, 0, 0, 0.1); cursor: pointer; transition: left 0.3s, border 0.3s, background 0.3s; display: flex; align-items: center; justify-content: center; } #sidebar.collapsed #sidebarContent { display: none; } #sidebar.collapsed #toggleSidebar { left: 15px; } #sidebarWrapper { position: relative; /* New wrapper */ } #toggleSidebar:hover { border-color: #007BFF; /* Change border color on hover */ background: #e6e6e6; /* Change background color on hover */ } #toggleSidebar svg { height: 15px; width: 15px; transition: all 0.3s ease-in-out; } #sidebar.collapsed { width: 60px; } #sidebar.collapsed #toggleSidebar { left: 15px; /* Position it to the right when sidebar is collapsed */ } #sidebar h2 { text-align: center; color: #333; font-size: 1.4em; padding-bottom: 10px; border-bottom: 1px solid #ccc; margin-bottom: 10px; } #sidebar textarea { width: 100%; height: 100px; margin-bottom: 10px; padding: 10px; border: 1px solid #ccc; border-radius: 5px; transition: border-color 0.3s; resize: none; } #sidebar textarea:focus { border-color: #007BFF; outline: none; } #sidebar button { width: 100%; padding: 10px; margin-bottom: 10px; border: none; border-radius: 5px; color: white; cursor: pointer; transition: background-color 0.3s; } #submitQuestion { background-color: #4CAF50; } #submitQuestion:hover { background-color: #45a049; } #start { background-color: #008CBA; margin-bottom: 20px; } #start:hover { background-color: #007B99; } #questionList { max-height: 200px; overflow-y: auto; } .question { margin-bottom: 10px; padding: 10px; border: 1px solid #ccc; border-radius: 5px; background-color: #fff; display: flex; justify-content: space-between; align-items: center; transition: background-color 0.3s; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; } .question:hover { background-color: #f0f0f0; } .question:before { content: '❓'; margin-right: 4px; } .question.answered { color: #aaa; } .question.answered:before { content: '✅'; } .question button { margin-left: 0px; background: none; border: 1px solid #000; /* 新增此行 */ box-sizing: border-box; /* 新增此行 */ cursor: pointer; transition: color 0.3s; display: flex; justify-content: center; align-items: center; } .question button:hover { color: #007BFF; } .question .button-container { margin-left: auto; display: flex; gap: 0px; } .button-container button { width: 24px; /* Increase the size of the button */ height: 24px; /* Increase the size of the button */ padding: 0; border: 2px solid red; /* Use a more visible border */ } .question button svg { width: 18px; height: 18px; margin: auto; pointer-events: none; /* Let click events pass through the SVG to the button */ } .button-group { display: flex; justify-content: space-between; } .question-text { flex-grow: 1; flex-shrink: 1; flex-basis: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; border: none; outline: none; } `); // 修改 HTML const sidebar = document.createElement('div'); sidebar.id = 'sidebar'; sidebar.innerHTML = `

Pre ChatGPT

`; document.body.appendChild(sidebar); // Toggle logic document.getElementById('toggleSidebar').addEventListener('click', function () { var sidebar = document.getElementById('sidebar'); var iconExpand = document.getElementById('icon-expand'); var iconCollapse = document.getElementById('icon-collapse'); sidebar.classList.toggle('collapsed'); if (sidebar.classList.contains('collapsed')) { iconCollapse.style.display = 'none'; iconExpand.style.display = ''; } else { iconExpand.style.display = 'none'; iconCollapse.style.display = ''; } }); document.getElementById('submitQuestion').addEventListener('click', function () { const input = document.getElementById('questionInput'); const questionList = document.getElementById('questionList'); const questions = input.value.split('\n').filter(question => question.trim() !== ''); for (let question of questions) { const div = document.createElement('div'); div.className = 'question'; const questionText = document.createElement('input'); questionText.type = 'text'; questionText.className = 'question-text'; questionText.value = question; questionText.readOnly = true; div.appendChild(questionText); questionText.style.border = 'none'; // Hide the textarea box border questionText.rows = 1; // Initially show as single line const buttonContainer = document.createElement('div'); buttonContainer.className = 'button-container'; const editButton = document.createElement('button'); editButton.innerHTML = ` `; editButton.addEventListener('click', function () { if (questionText.readOnly) { questionText.readOnly = false; questionText.style.border = '1px solid'; // Show border when editing questionText.rows = 'auto'; // Expand the textarea box to show all text questionText.focus(); // Move the cursor to the end of the text questionText.selectionStart = questionText.selectionEnd = questionText.value.length; } else { questionText.readOnly = true; questionText.style.border = 'none'; // Hide the textarea box border again after editing questionText.rows = 1; // Collapse the textarea box back to single line // Update the question text in localStorage let storedQuestions = localStorage.getItem('questions'); storedQuestions = storedQuestions ? JSON.parse(storedQuestions) : []; let questionToUpdate = storedQuestions.find(q => q.text === question.text); if (questionToUpdate) { questionToUpdate.text = questionText.value; localStorage.setItem('questions', JSON.stringify(storedQuestions)); } } }); buttonContainer.appendChild(editButton); const deleteButton = document.createElement('button'); deleteButton.innerHTML = ` `; // SVG for delete button deleteButton.addEventListener('click', function () { // Remove the question from the DOM div.remove(); // Remove the question from localStorage let storedQuestions = localStorage.getItem('questions'); storedQuestions = storedQuestions ? JSON.parse(storedQuestions) : []; storedQuestions = storedQuestions.filter(q => q.text !== questionText.value); localStorage.setItem('questions', JSON.stringify(storedQuestions)); }); buttonContainer.appendChild(deleteButton); const sortButton = document.createElement('button'); sortButton.className = 'sort-handle'; // add this line sortButton.innerHTML = ` `; // SVG for sort button buttonContainer.appendChild(sortButton); div.appendChild(buttonContainer); questionList.appendChild(div); let storedQuestions = localStorage.getItem('questions'); storedQuestions = storedQuestions ? JSON.parse(storedQuestions) : []; storedQuestions.push({ text: question, answered: false }); localStorage.setItem('questions', JSON.stringify(storedQuestions)); } input.value = ''; new Sortable(questionList, { handle: '.sort-handle', animation: 150 }); }); // Add an event listener to the question list to handle click events on the question text questionList.addEventListener('click', function (event) { if (event.target.classList.contains('question-text')) { const questionText = event.target; if (questionText.style.whiteSpace === 'nowrap') { questionText.style.whiteSpace = 'normal'; } else { questionText.style.whiteSpace = 'nowrap'; } } }); // When the page loads, load the questions from localStorage window.addEventListener('load', function () { const questionList = document.getElementById('questionList'); // Get the existing questions from localStorage let storedQuestions = localStorage.getItem('questions'); // Parse the string back into an array storedQuestions = storedQuestions ? JSON.parse(storedQuestions) : []; for (let question of storedQuestions) { const div = document.createElement('div'); div.className = 'question'; const questionText = document.createElement('input'); questionText.type = 'text'; questionText.className = 'question-text'; questionText.value = question.text; // Use question.text instead of question questionText.readOnly = true; div.appendChild(questionText); questionText.style.border = 'none'; // Hide the textarea box border questionText.rows = 1; // Initially show as single line const buttonContainer = document.createElement('div'); buttonContainer.className = 'button-container'; const editButton = document.createElement('button'); editButton.innerHTML = ` `; editButton.addEventListener('click', function () { if (questionText.readOnly) { questionText.readOnly = false; questionText.style.border = '1px solid'; // Show border when editing questionText.rows = 'auto'; // Expand the textarea box to show all text questionText.focus(); // Move the cursor to the end of the text questionText.selectionStart = questionText.selectionEnd = questionText.value.length; } else { questionText.readOnly = true; questionText.style.border = 'none'; // Hide the textarea box border again after editing questionText.rows = 1; // Collapse the textarea box back to single line // Update the question text in localStorage let storedQuestions = localStorage.getItem('questions'); storedQuestions = storedQuestions ? JSON.parse(storedQuestions) : []; let questionToUpdate = storedQuestions.find(q => q.text === question.text); if (questionToUpdate) { questionToUpdate.text = questionText.value; localStorage.setItem('questions', JSON.stringify(storedQuestions)); } } }); buttonContainer.appendChild(editButton); const deleteButton = document.createElement('button'); deleteButton.innerHTML = ` `; // SVG for delete button deleteButton.addEventListener('click', function () { // Remove the question from the DOM div.remove(); // Remove the question from localStorage let storedQuestions = localStorage.getItem('questions'); storedQuestions = storedQuestions ? JSON.parse(storedQuestions) : []; storedQuestions = storedQuestions.filter(q => q.text !== questionText.value); localStorage.setItem('questions', JSON.stringify(storedQuestions)); }); buttonContainer.appendChild(deleteButton); const sortButton = document.createElement('button'); sortButton.className = 'sort-handle'; // add this line sortButton.innerHTML = ` `; // SVG for sort button buttonContainer.appendChild(sortButton); div.appendChild(buttonContainer); questionList.appendChild(div); // Use the answered property from localStorage if (question.answered) { div.classList.add('answered'); } } }); document.getElementById('start').addEventListener('click', async function () { const questions = document.getElementsByClassName('question'); for (let i = 0; i < questions.length; i++) { let questionDiv = questions[i]; let questionInput = questionDiv.querySelector('input.question-text'); // Get the input element if (!questionDiv.classList.contains('answered')) { await askQuestion(questionInput.value); questionDiv.classList.add('answered'); // Update the answered status in localStorage let storedQuestions = localStorage.getItem('questions'); storedQuestions = storedQuestions ? JSON.parse(storedQuestions) : []; let questionToUpdate = storedQuestions.find(q => q.text === questionInput.value); if (questionToUpdate) { questionToUpdate.answered = true; localStorage.setItem('questions', JSON.stringify(storedQuestions)); } await new Promise(resolve => setTimeout(resolve, 1000)); // Wait for 1 second before starting the next question } } }); function findParent(el, selector, level = 5) { let parent = el.parentNode; let count = 1; while (parent && count <= level) { if (parent && parent.constructor !== HTMLDocument && parent.matches(selector)) { return parent; } parent = parent.parentNode; count++; } return null; } async function askQuestion(question) { return new Promise((resolve, reject) => { // Find the input box and the send button const inputBox = document.querySelector('textarea'); const sendButton = inputBox.nextElementSibling; // Input the question inputBox.value = question; const event = new Event('input', { bubbles: true }); inputBox.dispatchEvent(event); // Click the send button after a short delay setTimeout(() => sendButton.click(), 500); // Create a MutationObserver to wait for the answer const observer = new MutationObserver((mutations, observer) => { for (let mutation of mutations) { if (mutation.type === 'childList' && mutation.addedNodes.length > 0) { for (let node of mutation.addedNodes) { if (node.nodeType === Node.ELEMENT_NODE && node.textContent.includes('Regenerate response')) { // Check if the "Continue generating" button is present const continueSvg = document.querySelector('form.stretch .justify-center polygon[points="11 19 2 12 11 5 11 19"]'); if (continueSvg) { const continueButton = findParent(continueSvg, 'button'); if (continueButton) { continueButton.click(); } } else { // The answer has finished generating, stop observing observer.disconnect(); resolve(); } return; } } } } }); const observerConfig = { childList: true, subtree: true }; observer.observe(document.body, observerConfig); }); } })();