let originTabId = null; // Function to show loading overlay directly in the page function showLoadingOverlay(tabId) { chrome.scripting.executeScript({ target: { tabId: tabId }, function: () => { // Create overlay elements if they don't exist let overlay = document.getElementById('real-chatgpt-overlay'); if (!overlay) { // Create styles const style = document.createElement('style'); style.textContent = ` #real-chatgpt-overlay { position: fixed; top: 0; left: 0; width: 100%; height: 100%; background-color: rgba(0, 0, 0, 0.7); display: flex; flex-direction: column; justify-content: center; align-items: center; z-index: 9999; font-family: Arial, sans-serif; } #real-chatgpt-message { color: white; font-size: 18px; margin-top: 20px; padding: 10px 20px; background-color: rgba(0, 0, 0, 0.5); border-radius: 5px; text-align: center; max-width: 80%; } #real-chatgpt-message.completion { background-color: #28a745; font-weight: bold; } #real-chatgpt-spinner { width: 50px; height: 50px; border: 5px solid rgba(255, 255, 255, 0.3); border-radius: 50%; border-top-color: #fff; animation: spin 1s ease-in-out infinite; } @keyframes spin { to { transform: rotate(360deg); } } `; document.head.appendChild(style); // Create overlay overlay = document.createElement('div'); overlay.id = 'real-chatgpt-overlay'; // Create spinner const spinner = document.createElement('div'); spinner.id = 'real-chatgpt-spinner'; // Create message const message = document.createElement('div'); message.id = 'real-chatgpt-message'; message.textContent = 'Processing with ChatGPT...'; // Assemble overlay overlay.appendChild(spinner); overlay.appendChild(message); document.body.appendChild(overlay); } } }); } // Function to show completion message function showCompletionMessage(tabId) { chrome.scripting.executeScript({ target: { tabId: tabId }, function: () => { // Update existing overlay or create a new one let overlay = document.getElementById('real-chatgpt-overlay'); let spinner = document.getElementById('real-chatgpt-spinner'); let message = document.getElementById('real-chatgpt-message'); if (!overlay) { // If overlay doesn't exist, create it const style = document.createElement('style'); style.textContent = ` #real-chatgpt-overlay { position: fixed; top: 0; left: 0; width: 100%; height: 100%; background-color: rgba(0, 0, 0, 0.7); display: flex; flex-direction: column; justify-content: center; align-items: center; z-index: 9999; font-family: Arial, sans-serif; } #real-chatgpt-message { color: white; font-size: 18px; margin-top: 20px; padding: 10px 20px; background-color: #28a745; border-radius: 5px; text-align: center; max-width: 80%; font-weight: bold; } `; document.head.appendChild(style); overlay = document.createElement('div'); overlay.id = 'real-chatgpt-overlay'; message = document.createElement('div'); message.id = 'real-chatgpt-message'; overlay.appendChild(message); document.body.appendChild(overlay); } else if (spinner) { // Hide spinner if it exists spinner.style.display = 'none'; } // Update message if (message) { message.textContent = 'Finished, please paste from clipboard'; message.classList.add('completion'); } // Remove overlay after 1 second setTimeout(() => { const overlay = document.getElementById('real-chatgpt-overlay'); if (overlay) { overlay.remove(); } }, 1000); } }); } // Create context menus from settings or defaults function createContextMenus(menuItems) { // Remove all existing context menus chrome.contextMenus.removeAll(); // Create new context menus from settings menuItems.forEach(item => { chrome.contextMenus.create({ id: item.id, title: item.title, contexts: ["selection"], // Show only when text is selected }); }); } // Initialize context menus on installation chrome.runtime.onInstalled.addListener(() => { // Initialize storage with default values if not already set chrome.storage.sync.get(['menuItems'], (result) => { const menuItems = result.menuItems || defaultMenuItems; // Save to storage if not already set if (!result.menuItems) { chrome.storage.sync.set({ menuItems: defaultMenuItems }); } // Create context menus createContextMenus(menuItems); }); }); // Handle context menu clicks chrome.contextMenus.onClicked.addListener((info, tab) => { // Get menu items from storage chrome.storage.sync.get(['menuItems'], (result) => { const menuItems = result.menuItems || defaultMenuItems; const selectedItem = menuItems.find(item => item.id === info.menuItemId); if (selectedItem) { handleMenuItemClick(info, tab, selectedItem.prompt, selectedItem.model); } }); }); // Listen for messages from popup.js chrome.runtime.onMessage.addListener((message, sender, sendResponse) => { if (message.action === 'updateContextMenus') { chrome.storage.sync.get(['menuItems'], (result) => { const menuItems = result.menuItems || defaultMenuItems; createContextMenus(menuItems); }); } }); // Utility function to handle menu item click dynamically function handleMenuItemClick(info, tab, prefixText, model = 'gpt-4o') { originTabId = tab.id; if (info.selectionText) { // Show loading indicator in the original tab showLoadingOverlay(originTabId); const selectedText = prefixText + info.selectionText; chrome.tabs.create({ url: `https://chatgpt.com/?model=${model}&temporary-chat=true`, active: false }, (newTab) => { chrome.tabs.onUpdated.addListener(function listener(tabId, info) { if (tabId === newTab.id && info.status === "complete") { chrome.tabs.onUpdated.removeListener(listener); chrome.scripting.executeScript({ target: { tabId: newTab.id }, func: pasteToChatGPT, args: [selectedText, newTab.id], }); } }); }); } } // Listen for a message to close the current tab and switch back chrome.runtime.onMessage.addListener((message, sender) => { if (message.action === "closeGPTAndSwitchBack") { const currentTabId = sender.tab.id; // Close the current tab chrome.tabs.remove(currentTabId, () => { console.log("Closed current tab:", currentTabId); // Switch back to the original tab and show completion message if (originTabId) { chrome.tabs.update(originTabId, { active: true }, () => { // Show completion message in the original tab setTimeout(() => { showCompletionMessage(originTabId); }, 100); // Small delay to ensure tab is active }); } }); } }); // Function to paste text into ChatGPT input and send it function pasteToChatGPT(text, gptTab) { const newChatButton = document.querySelector('a[href="/"]'); if (newChatButton) newChatButton.click(); let sendInterval; const interval = setInterval(() => { const contentEditableDiv = document.querySelector('div[contenteditable="true"]'); if (contentEditableDiv) { clearInterval(interval); // Stop retrying once the div is found // Insert text into the contenteditable div contentEditableDiv.innerHTML = `

${text}

`; // Dispatch input events to trigger the mirroring mechanism contentEditableDiv.dispatchEvent(new Event('input', { bubbles: true })); sendInterval = setInterval(() => { // Simulate clicking the Send button const sendButton = document.querySelector('button[data-testid="send-button"]'); if (sendButton) { clearInterval(sendInterval); sendButton.click(); function fallbackCopyTextToClipboard(text) { const textArea = document.createElement("textarea"); textArea.value = text; textArea.style.position = "fixed"; // Prevent scrolling document.body.appendChild(textArea); textArea.focus(); textArea.select(); try { const successful = document.execCommand('copy'); console.log(successful ? "Fallback: Copied to clipboard!" : "Fallback: Failed to copy!"); } catch (err) { console.error("Fallback: Could not copy text:", err); } document.body.removeChild(textArea); } function waitForElement(selector, checkForDisappearance = false) { return new Promise((resolve) => { const observer = new MutationObserver(() => { const element = document.querySelector(selector); if ((element && !checkForDisappearance) || (!element && checkForDisappearance)) { observer.disconnect(); resolve(element); } }); observer.observe(document.body, { childList: true, subtree: true }); }); } // Function to copy text to the clipboard with fallback function copyTextToClipboard(text) { function fallbackCopyTextToClipboard(text) { const textArea = document.createElement("textarea"); textArea.value = text.trim(); // Ensure plain text without leading/trailing whitespace textArea.style.position = "fixed"; // Prevent scrolling document.body.appendChild(textArea); textArea.focus(); textArea.select(); try { const successful = document.execCommand("copy"); console.log(successful ? "Fallback: Copied to clipboard!" : "Fallback: Failed to copy!"); } catch (err) { console.error("Fallback: Could not copy text:", err); } document.body.removeChild(textArea); } if (navigator.clipboard && document.hasFocus()) { navigator.clipboard.writeText(text.trim()) .then(() => console.log("Copied to clipboard!")) .catch((err) => { console.error("Clipboard API failed, falling back:", err); fallbackCopyTextToClipboard(text); }); } else { fallbackCopyTextToClipboard(text); } } waitForElement('button[data-testid="stop-button"]').then(() => { return new Promise((resolve) => { const observer = new MutationObserver(() => { const stopButton = document.querySelector('button[data-testid="stop-button"]'); if (!stopButton) { observer.disconnect(); setTimeout(() => { resolve(); }, 1500); } }); observer.observe(document.body, { childList: true, subtree: true }); }); }).then(() => { const assistantMessages = document.querySelectorAll('div[data-message-author-role="assistant"]'); const latestResponse = assistantMessages[assistantMessages.length - 1]?.innerText || ""; if (latestResponse) { setTimeout(() => { copyTextToClipboard(latestResponse) console.log("Action complete. Closing tab..."); chrome.runtime.sendMessage({ action: "closeGPTAndSwitchBack" }); }, 1000); } }); } else { console.error("Send button not found!"); } }, 100); // Check every 100ms } }, 100); // Check every 100ms let timeout = setTimeout(() => { clearInterval(interval); clearInterval(sendInterval); }, 5000); }