// Text Selection Menu - Monica AI-like functionality // Provides context menu for selected text with AI features class TextSelectionMenu { constructor() { this.menu = null; this.selectedText = ''; this.init(); } init() { // Create menu element this.createMenu(); // Add event listeners document.addEventListener('mouseup', (e) => this.handleTextSelection(e)); document.addEventListener('mousedown', (e) => this.handleClickOutside(e)); // Hide menu on scroll window.addEventListener('scroll', () => this.hideMenu()); } createMenu() { this.menu = document.createElement('div'); this.menu.id = 'text-selection-menu'; this.menu.className = 'selection-menu'; this.menu.innerHTML = ` `; document.body.appendChild(this.menu); // Add action listeners this.menu.querySelectorAll('.menu-action').forEach(btn => { btn.addEventListener('click', (e) => { e.stopPropagation(); const action = btn.dataset.action; this.handleAction(action); }); }); } handleTextSelection(e) { const selection = window.getSelection(); const text = selection.toString().trim(); if (text.length > 0) { this.selectedText = text; this.showMenu(e.pageX, e.pageY); } else { this.hideMenu(); } } showMenu(x, y) { this.menu.style.display = 'flex'; // Position menu near cursor const menuWidth = this.menu.offsetWidth; const menuHeight = this.menu.offsetHeight; const windowWidth = window.innerWidth; const windowHeight = window.innerHeight; // Adjust position to keep menu in viewport let left = x - menuWidth / 2; let top = y - menuHeight - 10; if (left < 10) left = 10; if (left + menuWidth > windowWidth - 10) left = windowWidth - menuWidth - 10; if (top < 10) top = y + 20; this.menu.style.left = `${left}px`; this.menu.style.top = `${top}px`; // Animate in setTimeout(() => { this.menu.classList.add('visible'); }, 10); } hideMenu() { this.menu.classList.remove('visible'); setTimeout(() => { this.menu.style.display = 'none'; }, 200); } handleClickOutside(e) { if (!this.menu.contains(e.target)) { this.hideMenu(); } } async handleAction(action) { switch (action) { case 'note': this.createNote(); break; case 'search': this.googleSearch(); break; case 'ai': this.askAI(); break; case 'copy': this.copyText(); break; case 'share': this.shareText(); break; } this.hideMenu(); } createNote() { // Save note to localStorage const notes = JSON.parse(localStorage.getItem('newsNotes') || '[]'); const note = { id: Date.now(), text: this.selectedText, timestamp: new Date().toISOString(), url: window.location.href }; notes.unshift(note); localStorage.setItem('newsNotes', JSON.stringify(notes)); // Show notification this.showNotification('📝 Note saved!'); // Optional: Send to backend fetch('/api/save-note', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(note) }).catch(err => console.log('Note saved locally only')); } googleSearch() { const query = encodeURIComponent(this.selectedText); window.open(`https://www.google.com/search?q=${query}`, '_blank'); } async askAI() { // Open chat widget and populate with query const chatWidget = document.getElementById('chat-widget'); const chatInput = document.getElementById('chat-input'); if (chatWidget && chatInput) { chatWidget.classList.remove('chat-closed'); chatWidget.classList.add('chat-open'); chatInput.value = `Explain: "${this.selectedText}"`; chatInput.focus(); } } async copyText() { try { await navigator.clipboard.writeText(this.selectedText); this.showNotification('📋 Copied to clipboard!'); } catch (err) { // Fallback for older browsers const textarea = document.createElement('textarea'); textarea.value = this.selectedText; document.body.appendChild(textarea); textarea.select(); document.execCommand('copy'); document.body.removeChild(textarea); this.showNotification('📋 Copied to clipboard!'); } } async shareText() { const shareData = { title: 'News Intelligence', text: this.selectedText, url: window.location.href }; if (navigator.share) { try { await navigator.share(shareData); } catch (err) { if (err.name !== 'AbortError') { this.fallbackShare(); } } } else { this.fallbackShare(); } } fallbackShare() { // Copy link with selected text const shareUrl = `${window.location.href}#text=${encodeURIComponent(this.selectedText)}`; navigator.clipboard.writeText(shareUrl); this.showNotification('🔗 Share link copied!'); } showNotification(message) { const notification = document.createElement('div'); notification.className = 'selection-notification'; notification.textContent = message; document.body.appendChild(notification); setTimeout(() => { notification.classList.add('visible'); }, 10); setTimeout(() => { notification.classList.remove('visible'); setTimeout(() => { document.body.removeChild(notification); }, 300); }, 2000); } } // Initialize when DOM is ready if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', () => { new TextSelectionMenu(); }); } else { new TextSelectionMenu(); }