// Content Script Wrapper // This wrapper loads platform-specific handlers without modifying existing code (function() { 'use strict'; console.log('Auto-Draft Extension: Content wrapper initializing...'); // Request draft from background (shared helper) function requestDraftFromBackground(threadMessages, contextPrompt) { return new Promise((resolve, reject) => { chrome.runtime.sendMessage({ action: 'generateDraft', threadMessages, contextPrompt }, (response) => { if (response && response.draft) { resolve(response.draft); } else { reject(new Error(response?.error || 'No draft generated')); } }); }); } // Helper to extract first name from a full name function getFirstName(fullName) { if (!fullName || fullName === 'there') return fullName; // Remove any email addresses if present const nameOnly = fullName.split('<')[0].trim(); // Handle common name formats const parts = nameOnly.split(/\s+/); // If it's a single word, return it if (parts.length === 1) return parts[0]; // Check if first part is a title (Mr., Mrs., Dr., etc.) const titles = ['mr', 'mrs', 'ms', 'miss', 'dr', 'prof', 'professor']; if (titles.includes(parts[0].toLowerCase().replace('.', ''))) { // Return the next part as first name return parts[1] || parts[0]; } // Otherwise, return the first part as the first name return parts[0]; } // Format helpers function hasGreeting(draft) { // Check for common greetings if (/^(hi|hello|hey|dear|good\s*(morning|afternoon|evening))[^\n,]*[,\n]/i.test(draft.trim())) { return true; } // Check if it starts with a name followed by comma or colon if (/^[A-Z][a-zA-Z\s\-']+[,:]\s*$/m.test(draft.trim().split('\n')[0])) { return true; } // Check if it starts with a title and name if (/^(Mr\.|Mrs\.|Ms\.|Dr\.|Prof\.)\s+[A-Za-z\s\-']+[,:]/i.test(draft.trim())) { return true; } return false; } function hasSignature(draft) { return /(best|thanks|thank you|sincerely|regards|cheers|cordially|warmly|respectfully|yours)[^\n]*[\n\r]+[\w\s]+$/i.test(draft.trim()); } // Format the reply as a proper email function formatEmailReplySmart(draft, recipientName = 'there', senderName = 'Curtis') { let result = draft.trim(); // Use only first name for greeting to be more natural const greetingName = getFirstName(recipientName); // Add greeting if needed if (!hasGreeting(result)) { result = `Hi ${greetingName},\n\n${result}`; } // Add signature if needed if (!hasSignature(result)) { result = `${result}\n\nBest,\n${senderName}`; } return result; } // Extract recipient name helper function extractRecipientName(messages) { // Get the last message that's not from Curtis for (let i = messages.length - 1; i >= 0; i--) { const msg = messages[i]; if (msg.sender && !msg.sender.includes('curtis@newfrontierinc.com')) { return msg.senderName || msg.sender.split('@')[0] || 'there'; } } return 'there'; } // Platform detector and instantly extractor are now loaded directly via manifest // so we can use them directly // Detect current platform const platform = PlatformDetector.getCurrentPlatform(); console.log('Detected platform:', platform); if (!PlatformDetector.shouldActivate()) { console.log('Extension not active on this page'); return; } // Load platform-specific handlers if (platform === 'gmail') { // Gmail is already handled by content.js console.log('Gmail platform detected - existing handlers will be used'); } else if (platform === 'instantly') { console.log('Instantly platform detected - initializing Instantly handlers'); // Initialize Instantly-specific UI and handlers initializeInstantly(); } else if (platform === 'plusvibe') { console.log('Plusvibe platform detected - initializing Plusvibe handlers'); // Initialize Plusvibe-specific UI and handlers initializePlusvibe(); } // Initialize Instantly-specific functionality function initializeInstantly() { console.log('Initializing Instantly support...'); // Create a modified version of the UI injection for Instantly let uiContainer = null; let isUIVisible = false; // Function to inject UI for Instantly function injectInstantlyUI() { const replyBox = InstantlyExtractor.findReplyBox(); if (!replyBox || document.querySelector('.gpt-autodraft-ui')) { return; } console.log('Injecting Auto-Draft UI for Instantly'); // Create container with same styling as Gmail version const container = document.createElement('div'); container.className = 'gpt-autodraft-ui'; container.style.cssText = ` background: #ffffff; border: 2px solid #1a4d2e; padding: 8px; margin: 8px 0; border-radius: 8px; position: fixed; bottom: 24px; right: 24px; z-index: 99999; box-shadow: 0 2px 12px rgba(0,0,0,0.15); min-width: 320px; max-width: 400px; `; // Add the same UI elements container.innerHTML = `
`; document.body.appendChild(container); uiContainer = container; isUIVisible = true; // Set up event handlers setupInstantlyEventHandlers(container); } // Set up event handlers for Instantly UI function setupInstantlyEventHandlers(container) { const toggleBtn = container.querySelector('.toggle-btn'); const promptInput = container.querySelector('.prompt-input'); const draftBtn = container.querySelector('.draft-btn'); const errorMsg = container.querySelector('.error-msg'); const promptLabel = container.querySelector('label'); let minimized = false; // Toggle button handler toggleBtn.onclick = () => { minimized = !minimized; if (minimized) { promptLabel.style.display = 'none'; promptInput.style.display = 'none'; errorMsg.style.display = 'none'; container.style.width = '340px'; container.style.minWidth = '340px'; container.style.padding = '0 12px 0 16px'; container.style.display = 'flex'; container.style.alignItems = 'center'; container.style.justifyContent = 'flex-end'; toggleBtn.textContent = '+'; } else { promptLabel.style.display = 'block'; promptInput.style.display = 'block'; container.style.width = ''; container.style.minWidth = '320px'; container.style.padding = '8px'; container.style.display = 'block'; container.style.alignItems = ''; container.style.justifyContent = ''; toggleBtn.textContent = '–'; } }; // Draft button handler draftBtn.onclick = async () => { console.log('Draft button clicked (Instantly)'); draftBtn.disabled = true; errorMsg.style.display = 'none'; errorMsg.textContent = ''; try { // First, let's diagnose the DOM structure console.log('=== INSTANTLY DOM DIAGNOSTIC ==='); // Check what's in the modal/dialog const modal = document.querySelector('[role="dialog"], .modal-content, .reply-modal'); if (modal) { console.log('Modal found, inspecting structure...'); console.log('Modal classes:', modal.className); console.log('Modal ID:', modal.id); // Log all text content that looks like email headers const allText = modal.innerText; const lines = allText.split('\n').filter(line => line.trim()); console.log('Modal text lines:'); lines.forEach((line, i) => { if (line.includes('@') || line.includes('wrote:') || line.includes('On ') || line.includes('From:')) { console.log(`Line ${i}: ${line}`); } }); // Check for specific elements const possibleMessageContainers = modal.querySelectorAll('div, p, section, article'); console.log(`Found ${possibleMessageContainers.length} possible containers`); // Look for containers with email content possibleMessageContainers.forEach((container, i) => { const text = container.textContent; if (text && text.includes('@') && text.length > 50) { console.log(`Container ${i}:`, { tagName: container.tagName, className: container.className, textLength: text.length, hasEmail: text.includes('@'), hasWrote: text.includes('wrote:'), preview: text.substring(0, 100) + '...' }); } }); } else { console.log('No modal found, checking entire page...'); // Log the general page structure const bodyText = document.body.innerText; console.log('Page contains curtis@newfrontierinc.com:', bodyText.includes('curtis@newfrontierinc.com')); console.log('Page contains drferrara@atlantaurgentcare.com:', bodyText.includes('drferrara@atlantaurgentcare.com')); } console.log('=== END DOM DIAGNOSTIC ==='); // Extract thread messages from Instantly const threadMessages = InstantlyExtractor.extractThreadMessages(); if (!threadMessages || threadMessages.length === 0) { throw new Error('No messages found in conversation'); } console.log('Extracted thread messages:', threadMessages); // Get context prompt const contextPrompt = promptInput.value.trim(); // Request draft from background script (reuse existing logic) const draft = await requestDraftFromBackground(threadMessages, contextPrompt); if (draft) { // Format the draft properly const recipientName = extractRecipientName(threadMessages); const formattedDraft = formatEmailReplySmart(draft, recipientName); // Insert draft into Instantly's reply box const inserted = InstantlyExtractor.insertDraft(formattedDraft); if (!inserted) { throw new Error('Failed to insert draft into reply box'); } } } catch (error) { console.error('Draft generation failed:', error); errorMsg.textContent = error.message || 'Failed to generate draft'; errorMsg.style.display = 'block'; } finally { draftBtn.disabled = false; } }; // Auto-resize textarea promptInput.addEventListener('input', function() { this.style.height = 'auto'; this.style.height = (this.scrollHeight) + 'px'; }); } // Monitor for reply box appearance function monitorForReplyBox() { const observer = new MutationObserver(() => { if (!uiContainer && InstantlyExtractor.findReplyBox()) { injectInstantlyUI(); } }); observer.observe(document.body, { childList: true, subtree: true }); // Initial check if (InstantlyExtractor.findReplyBox()) { injectInstantlyUI(); } } // Handle extension icon clicks for Instantly chrome.runtime.onMessage.addListener((message, sender, sendResponse) => { if (message.action === 'toggleUI') { if (isUIVisible && uiContainer) { uiContainer.remove(); uiContainer = null; isUIVisible = false; } else { injectInstantlyUI(); } } }); // Start monitoring monitorForReplyBox(); console.log('Instantly support initialized successfully'); } // Initialize Plusvibe-specific functionality function initializePlusvibe() { console.log('Initializing Plusvibe support...'); let uiContainer = null; let isUIVisible = false; // Function to inject UI for Plusvibe function injectPlusvibeUI() { const replyBox = PlusvibeExtractor.findReplyBox(); if (!replyBox || document.querySelector('.gpt-autodraft-ui')) { return; } console.log('Injecting Auto-Draft UI for Plusvibe'); // Create container with same styling const container = document.createElement('div'); container.className = 'gpt-autodraft-ui'; container.style.cssText = ` background: #ffffff; border: 2px solid #1a4d2e; padding: 8px; margin: 8px 0; border-radius: 8px; position: fixed; bottom: 24px; right: 24px; z-index: 99999; box-shadow: 0 2px 12px rgba(0,0,0,0.15); min-width: 320px; max-width: 400px; `; // Add the same UI elements container.innerHTML = ` `; document.body.appendChild(container); uiContainer = container; isUIVisible = true; // Set up event handlers setupPlusvibeEventHandlers(container); } // Set up event handlers for Plusvibe UI function setupPlusvibeEventHandlers(container) { const toggleBtn = container.querySelector('.toggle-btn'); const promptInput = container.querySelector('.prompt-input'); const draftBtn = container.querySelector('.draft-btn'); const errorMsg = container.querySelector('.error-msg'); const promptLabel = container.querySelector('label'); let minimized = false; // Toggle button handler toggleBtn.onclick = () => { minimized = !minimized; if (minimized) { promptLabel.style.display = 'none'; promptInput.style.display = 'none'; errorMsg.style.display = 'none'; container.style.width = '340px'; container.style.minWidth = '340px'; container.style.padding = '0 12px 0 16px'; container.style.display = 'flex'; container.style.alignItems = 'center'; container.style.justifyContent = 'flex-end'; toggleBtn.textContent = '+'; } else { promptLabel.style.display = 'block'; promptInput.style.display = 'block'; container.style.width = ''; container.style.minWidth = '320px'; container.style.padding = '8px'; container.style.display = 'block'; container.style.alignItems = ''; container.style.justifyContent = ''; toggleBtn.textContent = '–'; } }; // Draft button handler draftBtn.onclick = async () => { console.log('Draft button clicked (Plusvibe)'); draftBtn.disabled = true; errorMsg.style.display = 'none'; errorMsg.textContent = ''; try { // Extract thread messages from Plusvibe console.log('Extracting thread messages...'); const threadMessages = await PlusvibeExtractor.extractThreadMessages(); console.log('Thread messages extracted:', threadMessages); if (!threadMessages || threadMessages.length === 0) { throw new Error('No messages found in conversation'); } console.log('Extracted thread messages:', threadMessages); // Get context prompt const contextPrompt = promptInput.value.trim(); console.log('Context prompt:', contextPrompt); // Request draft from background script console.log('Requesting draft from background...'); const draft = await requestDraftFromBackground(threadMessages, contextPrompt); console.log('Draft received:', draft); if (draft) { // Format the draft properly console.log('Formatting draft...'); const recipientName = extractRecipientName(threadMessages); const formattedDraft = formatEmailReplySmart(draft, recipientName); console.log('Formatted draft:', formattedDraft); // Insert draft into Plusvibe's reply box console.log('Inserting draft into reply box...'); const inserted = PlusvibeExtractor.insertDraft(formattedDraft); if (!inserted) { throw new Error('Failed to insert draft into reply box'); } console.log('Draft inserted successfully'); } } catch (error) { console.error('Draft generation failed:', error); console.error('Error stack:', error.stack); errorMsg.textContent = error.message || 'Failed to generate draft'; errorMsg.style.display = 'block'; } finally { draftBtn.disabled = false; } }; // Auto-resize textarea promptInput.addEventListener('input', function() { this.style.height = 'auto'; this.style.height = (this.scrollHeight) + 'px'; }); } // Monitor for reply box appearance function monitorForReplyBox() { const observer = new MutationObserver(() => { if (!uiContainer && PlusvibeExtractor.findReplyBox()) { injectPlusvibeUI(); } }); observer.observe(document.body, { childList: true, subtree: true }); // Initial check if (PlusvibeExtractor.findReplyBox()) { injectPlusvibeUI(); } } // Handle extension icon clicks for Plusvibe chrome.runtime.onMessage.addListener((message, sender, sendResponse) => { if (message.action === 'toggleUI') { if (isUIVisible && uiContainer) { uiContainer.remove(); uiContainer = null; isUIVisible = false; } else { injectPlusvibeUI(); } } }); // Start monitoring monitorForReplyBox(); console.log('Plusvibe support initialized successfully'); } })();