| |
|
|
| import * as state from './state.js'; |
| import * as api from './api.js'; |
| import * as db from './db.js'; |
|
|
| |
| import { dom } from './ui/dom.js'; |
| import * as chatUI from './ui/chat.js'; |
| import * as modalUI from './ui/modals.js'; |
| import * as toolUI from './ui/tools.js'; |
| import * as ttsUI from './ui/tts.js'; |
|
|
|
|
| let currentUserStatus = { |
| isPremium: false, |
| hasBeenChecked: false, |
| fingerprint: null |
| }; |
|
|
| const MAX_CHAT_SESSIONS = 150; |
|
|
| function checkUserPremiumStatus() { |
| return currentUserStatus.isPremium; |
| } |
|
|
| async function handleFileSelection(event) { |
| const file = event.target.files[0]; |
| if (!file) return; |
| |
| chatUI.showFileUploading(file.name); |
| dom.submitButton.disabled = true; |
|
|
| try { |
| const uploadedFileData = await api.processAndUploadFile(file); |
| state.setAttachedFile(uploadedFileData); |
| chatUI.showFileReady(file.name, file.type, uploadedFileData.blobUrl); |
| } catch (error) { |
| console.error("خطا در پردازش فایل:", error); |
| chatUI.showFileError(error.message); |
| } finally { |
| event.target.value = ''; |
| toolUI.toggleFilePopupMenu(false); |
| dom.submitButton.disabled = false; |
| dom.messageInput.dispatchEvent(new Event('input')); |
| } |
| } |
|
|
| function handleNewChat() { |
| if (state.chatSessions.length >= MAX_CHAT_SESSIONS) { |
| state.chatSessions.pop(); |
| } |
|
|
| const newSession = { id: Date.now().toString(), title: 'چت جدید', messages: [], showThoughts: false }; |
| state.chatSessions.unshift(newSession); |
| state.setActiveChatId(newSession.id); |
| chatUI.renderActiveChat(); |
| chatUI.renderHistoryList(); |
| toolUI.updateToolsButton(null); |
| state.setActiveToolPrefix(null); |
| state.setActiveTool(null); |
| state.saveSessions(); |
| ttsUI.clearAllCache(); |
| ttsUI.stopAudio(); |
| } |
|
|
| function getFullChatText(session) { |
| if (!session || !session.messages) return ""; |
| return session.messages |
| .map(msg => { |
| const prefix = msg.role === 'user' ? 'کاربر' : 'مدل'; |
| const textContent = msg.parts?.find(p => p.text)?.text || '[محتوای غیر متنی]'; |
| return `${prefix}:\n${textContent}`; |
| }) |
| .join('\n\n---\n\n'); |
| } |
|
|
| function handlePremiumFeatureClick(element) { |
| if (checkUserPremiumStatus()) { |
| return true; |
| } |
| |
| const parentContainer = element.closest('.premium-locked-item'); |
| if (parentContainer) { |
| parentContainer.classList.add('animate-premium-lock'); |
| setTimeout(() => { |
| parentContainer.classList.remove('animate-premium-lock'); |
| }, 800); |
| } |
| |
| modalUI.togglePremiumFeatureModal(true); |
| |
| return false; |
| } |
|
|
| document.addEventListener('DOMContentLoaded', async () => { |
| await db.initDB(); |
| await db.cleanupOldFiles(); |
|
|
| chatUI.initTheme(); |
| ttsUI.initTtsPlayer(); |
| state.loadSessions(); |
|
|
| currentUserStatus.fingerprint = await api.getBrowserFingerprint(); |
|
|
| if (state.chatSessions.length > MAX_CHAT_SESSIONS) { |
| state.chatSessions.length = MAX_CHAT_SESSIONS; |
| state.saveSessions(); |
| } |
|
|
| if (state.chatSessions.length === 0 || !state.getActiveChat()) { |
| handleNewChat(); |
| } else { |
| state.setActiveChatId(state.activeChatId || state.chatSessions[0].id); |
| chatUI.renderActiveChat(); |
| chatUI.renderHistoryList(); |
| } |
| |
| chatUI.setupMobileKeyboardFix(); |
| |
| dom.newChatButton.addEventListener('click', handleNewChat); |
| dom.menuButton.addEventListener('click', () => modalUI.toggleSidebar(true)); |
| dom.sidebarOverlay.addEventListener('click', () => modalUI.toggleSidebar(false)); |
|
|
| dom.deleteAllChatsButton.addEventListener('click', () => { |
| modalUI.showConfirmModal('آیا از حذف تمام چتها مطمئن هستید؟', () => { |
| state.setChatSessions([]); |
| state.setActiveChatId(null); |
| state.saveSessions(); |
| handleNewChat(); |
| modalUI.toggleSidebar(false); |
| }); |
| }); |
|
|
| dom.settingsButton.addEventListener('click', () => { |
| modalUI.updateSettingsUI(checkUserPremiumStatus()); |
| modalUI.toggleSettingsModal(true); |
| }); |
| dom.settingsModal.addEventListener('click', (e) => { |
| if (e.target === dom.settingsModal) modalUI.toggleSettingsModal(false); |
| }); |
| dom.themeToggle.addEventListener('change', (e) => { |
| const newTheme = e.target.checked ? 'dark' : 'light'; |
| localStorage.setItem('theme', newTheme); |
| chatUI.applyTheme(newTheme); |
| }); |
|
|
| dom.toolsButton.addEventListener('click', (e) => { |
| if (dom.toolsButton.classList.contains('tool-selected')) return; |
| e.stopPropagation(); |
| const activeChat = state.getActiveChat(); |
| const toggleSwitch = dom.toolsMenu.querySelector('.toggle-switch'); |
| if (activeChat && toggleSwitch) { |
| toggleSwitch.classList.toggle('active', activeChat.showThoughts); |
| } |
| toolUI.toggleToolsMenu(!dom.toolsMenu.classList.contains('active')); |
| }); |
| dom.attachFileButton.addEventListener('click', (e) => { |
| e.stopPropagation(); |
| toolUI.toggleFilePopupMenu(!dom.filePopupMenu.classList.contains('active')); |
| }); |
|
|
| dom.toolsMenu.addEventListener('click', (e) => { |
| const toggleSwitch = e.target.closest('.toggle-switch'); |
| if (toggleSwitch) { |
| e.stopPropagation(); |
| if (!handlePremiumFeatureClick(toggleSwitch)) return; |
| toggleSwitch.classList.toggle('active'); |
| const activeChat = state.getActiveChat(); |
| if (activeChat) { |
| activeChat.showThoughts = toggleSwitch.classList.contains('active'); |
| state.saveSessions(); |
| } |
| return; |
| } |
| |
| const toolItem = e.target.closest('.tool-item'); |
| if (!toolItem) return; |
| if (toolItem.parentElement.classList.contains('premium-locked-item') && !handlePremiumFeatureClick(toolItem)) { |
| toolUI.toggleToolsMenu(false); |
| return; |
| } |
|
|
| const tool = toolItem.dataset.tool; |
| const toolName = toolItem.dataset.toolName; |
| |
| toolUI.toggleToolsMenu(false); |
| toolUI.updateToolsButton(toolName); |
| state.setActiveTool(tool); |
| |
| if (tool === 'deep-think') { |
| state.setActiveToolPrefix("شما یک محقق حرفهای هستید. با بررسی عمیق و جامع، به سوال زیر یک پاسخ کامل، ساختاریافته و دقیق بدهید: "); |
| dom.messageInput.placeholder = "موضوع برای تفکر عمیق..."; |
| } else if (tool === 'reasoning') { |
| state.setActiveToolPrefix("شما یک استدلالگر منطقی هستید. با تحلیل گام به گام و ارائه دلایل روشن، به سوال زیر پاسخ دهید: "); |
| dom.messageInput.placeholder = "موضوع برای استدلال..."; |
| } else { |
| state.setActiveToolPrefix(null); |
| state.setActiveTool(null); |
| } |
| dom.messageInput.focus(); |
| }); |
|
|
| dom.clearToolSelection.addEventListener('click', (e) => { |
| e.stopPropagation(); |
| state.setActiveToolPrefix(null); |
| state.setActiveTool(null); |
| toolUI.updateToolsButton(null); |
| dom.messageInput.focus(); |
| }); |
|
|
| window.addEventListener('click', (e) => { |
| if (dom.toolsMenu.classList.contains('active') && !dom.toolsMenu.contains(e.target) && !dom.toolsButton.contains(e.target)) { |
| toolUI.toggleToolsMenu(false); |
| } |
| if (dom.filePopupMenu.classList.contains('active') && !dom.filePopupMenu.contains(e.target) && !dom.attachFileButton.contains(e.target)) { |
| toolUI.toggleFilePopupMenu(false); |
| } |
| }); |
| |
| dom.selectImageOption.addEventListener('click', (e) => { |
| toolUI.toggleFilePopupMenu(false); |
| if (handlePremiumFeatureClick(e.currentTarget)) dom.imageFileInput.click(); |
| }); |
| |
| dom.selectFileOption.addEventListener('click', (e) => { |
| toolUI.toggleFilePopupMenu(false); |
| if (handlePremiumFeatureClick(e.currentTarget)) dom.generalFileInput.click(); |
| }); |
| |
| dom.premiumModalCloseBtn.addEventListener('click', () => modalUI.togglePremiumFeatureModal(false)); |
| dom.premiumFeatureModal.addEventListener('click', (e) => { |
| if(e.target === dom.premiumFeatureModal) modalUI.togglePremiumFeatureModal(false); |
| }); |
| dom.premiumModalUpgradeBtn.addEventListener('click', () => { |
| parent.postMessage({ type: 'NAVIGATE_TO_PREMIUM', payload: { url: chatUI.PREMIUM_URL } }, '*'); |
| modalUI.togglePremiumFeatureModal(false); |
| }); |
|
|
| dom.plusModalCloseBtn.addEventListener('click', () => modalUI.togglePlusRequiredModal(false)); |
| dom.plusRequiredModal.addEventListener('click', (e) => { |
| if(e.target === dom.plusRequiredModal) modalUI.togglePlusRequiredModal(false); |
| }); |
|
|
| dom.imageFileInput.addEventListener('change', handleFileSelection); |
| dom.generalFileInput.addEventListener('change', handleFileSelection); |
|
|
| dom.removeImageButton.addEventListener('click', () => { |
| state.setAttachedFile(null); |
| chatUI.hideFilePreview(); |
| dom.messageInput.dispatchEvent(new Event('input')); |
| }); |
|
|
| dom.htmlPreviewCloseBtn.addEventListener('click', () => modalUI.toggleHtmlPreviewModal(false)); |
| dom.htmlPreviewOverlay.addEventListener('click', () => modalUI.toggleHtmlPreviewModal(false)); |
| |
| dom.messageForm.addEventListener('submit', async (e) => { |
| e.preventDefault(); |
| |
| if (state.isGenerating) { |
| if (state.globalAbortController) state.globalAbortController.abort(); |
| return; |
| } |
|
|
| if (state.isMessageLimitReached(checkUserPremiumStatus())) { |
| chatUI.showLimitReachedUpgrade(); |
| return; |
| } |
|
|
| const activeChat = state.getActiveChat(); |
| if (!activeChat) return; |
| |
| const userMessageText = dom.messageInput.value.trim(); |
| if (!userMessageText && !state.attachedFile) return; |
|
|
| chatUI.setGeneratingState(true); |
| let modelBubbleOuterDiv; |
|
|
| try { |
| const isFirstMessageOfChat = activeChat.messages.length === 0; |
| if (isFirstMessageOfChat && dom.chatWindow.querySelector('.welcome-screen')) { |
| dom.chatWindow.querySelector('.welcome-screen').remove(); |
| } |
|
|
| const userParts = []; |
| let fileAttachedInThisTurn = null; |
| if (state.attachedFile) { |
| fileAttachedInThisTurn = { ...state.attachedFile }; |
| userParts.push({ |
| id: fileAttachedInThisTurn.id, blobUrl: fileAttachedInThisTurn.blobUrl, |
| mimeType: fileAttachedInThisTurn.mimeType, name: fileAttachedInThisTurn.name, |
| base64Data: fileAttachedInThisTurn.base64Data |
| }); |
| chatUI.hideFilePreview(); |
| state.setAttachedFile(null); |
| } |
| if (userMessageText) userParts.push({ text: userMessageText }); |
| |
| const newUserMessage = { role: 'user', parts: userParts, tool: state.getActiveTool() }; |
| activeChat.messages.push(newUserMessage); |
|
|
| state.incrementMessageCount(checkUserPremiumStatus()); |
| |
| await chatUI.addMessageToUI(newUserMessage, activeChat.messages.length - 1, {isLastUser: true, animate: true}); |
| |
| const modelPlaceholderMessage = { role: 'assistant', isTemporary: true, parts: [] }; |
| activeChat.messages.push(modelPlaceholderMessage); |
| modelBubbleOuterDiv = await chatUI.addMessageToUI(modelPlaceholderMessage, activeChat.messages.length - 1, {animate: true}); |
| |
| const historyForApi = activeChat.messages.map((msg, index) => { |
| const isLastMessage = index === activeChat.messages.length - 1; |
| const isUserMessageJustSent = index === activeChat.messages.length - 2; |
|
|
| if (isUserMessageJustSent) { |
| return JSON.parse(JSON.stringify(msg)); |
| } |
| if (isLastMessage) { |
| return msg; |
| } |
|
|
| const cleanMsg = { role: msg.role, parts: [] }; |
| if (msg.parts) { |
| msg.parts.forEach(part => { |
| if (part.text) { |
| cleanMsg.parts.push({ text: part.text }); |
| } |
| }); |
| } |
| return cleanMsg; |
| }); |
|
|
| const toolPrefix = state.getActiveToolPrefix(); |
| const lastUserMsgInHistory = historyForApi.findLast(m => m.role === 'user'); |
| const textPartInHistory = lastUserMsgInHistory.parts.find(p => p.text); |
| if (textPartInHistory) { |
| textPartInHistory.text = (toolPrefix ? toolPrefix : '') + (textPartInHistory.text || ''); |
| } else if (toolPrefix) { |
| lastUserMsgInHistory.parts.push({ text: toolPrefix }); |
| } |
|
|
| if (isFirstMessageOfChat && userMessageText) { |
| activeChat.title = userMessageText.substring(0, 30); |
| chatUI.renderHistoryList(); |
| } |
| |
| dom.messageInput.value = ''; |
| dom.messageInput.dispatchEvent(new Event('input')); |
|
|
| const activeTool = state.getActiveTool(); |
| if (activeTool === 'deep-think' || activeTool === 'reasoning') { |
| if (activeTool === 'deep-think') toolUI.updateDeepThinkPanel({ topic: userMessageText || 'فایل ضمیمه شده' }, modelBubbleOuterDiv); |
| else if (activeTool === 'reasoning') toolUI.updateReasoningPanel({ topic: userMessageText || 'فایل ضمیمه شده' }, modelBubbleOuterDiv); |
| |
| const progressBar = modelBubbleOuterDiv.querySelector('.bar'); |
|
|
| if (progressBar) { |
| requestAnimationFrame(() => { |
| progressBar.style.transition = 'width 30s ease-out'; |
| progressBar.style.width = '100%'; |
| }); |
| } |
| } |
| |
| |
| |
| |
| |
| const response = await api.getChatStream(historyForApi, state.globalAbortController.signal); |
| await api.readStreamAndDisplay(response, modelBubbleOuterDiv); |
|
|
| } catch (error) { |
| if (error.name !== 'AbortError') { |
| console.error("خطا در هنگام تولید پیام:", error); |
| |
| |
| if (modelBubbleOuterDiv) { |
| |
| |
| } |
| } else { |
| if (modelBubbleOuterDiv && !modelBubbleOuterDiv.querySelector('.message-content')?.innerText.includes('متوقف شد')) { |
| const contentArea = modelBubbleOuterDiv.querySelector('.message-content') || modelBubbleOuterDiv; |
| contentArea.innerHTML += '<p class="text-xs text-slate-500 mt-2 text-center p-4">-- عملیات متوقف شد --</p>'; |
| } |
| } |
| } finally { |
| chatUI.resetState(); |
| state.saveSessions(); |
| state.setActiveToolPrefix(null); |
| state.setActiveTool(null); |
| toolUI.updateToolsButton(null); |
| } |
| }); |
| |
| dom.chatWindow.addEventListener('click', async (e) => { |
| const button = e.target.closest('.action-button'); |
| if (!button) return; |
| const action = button.dataset.action; |
| const messageEntry = button.closest('.message-entry'); |
| if (!messageEntry) return; |
| const messageIndex = parseInt(messageEntry.dataset.index, 10); |
| const activeChat = state.getActiveChat(); |
| if (!activeChat || isNaN(messageIndex)) return; |
| const message = activeChat.messages[messageIndex]; |
| if (action === 'copy') { |
| const textToCopy = message.parts?.find(p => p.text)?.text || ''; |
| if (textToCopy) navigator.clipboard.writeText(textToCopy).then(() => chatUI.showCopyFeedback(button)); |
| } else if (action === 'like' || action === 'dislike') { |
| chatUI.handleLikeDislike(button, messageEntry); |
| } else if (action === 'speak') { |
| const audioState = ttsUI.getAudioState(); |
| if (audioState.messageIndex === messageIndex && (audioState.status === 'running' || audioState.status === 'suspended')) { |
| ttsUI.stopAudio(); |
| return; |
| } |
| if (ttsUI.hasCacheForMessage(messageIndex)) { |
| ttsUI.playFromCache(messageIndex, button); |
| return; |
| } |
| const fullText = message.parts?.find(p => p.text)?.text; |
| if (!fullText) return; |
| const codeBlockRegex = /```[\s\S]*?```/g; |
| const textToSpeak = fullText.replace(codeBlockRegex, '').trim(); |
| if (!textToSpeak) { |
| alert("محتوای متنی برای خواندن وجود ندارد (فقط کد شناسایی شد)."); |
| return; |
| } |
| ttsUI.stream(messageIndex, textToSpeak, button); |
| } else if (action === 'regenerate') { |
| if (state.isGenerating) return; |
| chatUI.setGeneratingState(true); |
| const lastModelMessageIndex = state.findLastIndex(activeChat.messages, msg => msg.role === 'assistant'); |
| if (messageIndex === lastModelMessageIndex) { |
| ttsUI.clearCacheForMessage(messageIndex); |
| activeChat.messages.length = messageIndex; |
| messageEntry.remove(); |
| const lastUserMessageIndex = state.findLastIndex(activeChat.messages, msg => msg.role === 'user'); |
| if (lastUserMessageIndex !== -1) { |
| const lastUserMessageElement = dom.chatWindow.querySelector(`.message-entry[data-index="${lastUserMessageIndex}"]`); |
| if (lastUserMessageElement) chatUI.updateMessageActions(lastUserMessageElement, activeChat.messages[lastUserMessageIndex], true, false); |
| } |
| const modelPlaceholderMessage = { role: 'assistant', isTemporary: true, parts: [] }; |
| activeChat.messages.push(modelPlaceholderMessage); |
| const newModelBubble = await chatUI.addMessageToUI(modelPlaceholderMessage, activeChat.messages.length - 1, { animate: true }); |
| try { |
| const lastUserMessage = activeChat.messages.findLast(m => m.role === 'user'); |
| const lastTool = lastUserMessage?.tool; |
|
|
| const historyForApi = activeChat.messages.map((msg, index) => { |
| if (index === activeChat.messages.length - 1) return msg; |
| if (index === activeChat.messages.length - 2) return JSON.parse(JSON.stringify(msg)); |
| const cleanMsg = { role: msg.role, parts: [] }; |
| if (msg.parts) msg.parts.forEach(part => { if (part.text) cleanMsg.parts.push({ text: part.text }); }); |
| return cleanMsg; |
| }); |
| |
| if (lastTool === 'deep-think' || lastTool === 'reasoning') { |
| if (lastTool === 'deep-think') toolUI.updateDeepThinkPanel({ topic: lastUserMessage.parts.find(p=>p.text)?.text || 'فایل ضمیمه شده' }, newModelBubble); |
| if (lastTool === 'reasoning') toolUI.updateReasoningPanel({ topic: lastUserMessage.parts.find(p=>p.text)?.text || 'فایل ضمیمه شده' }, newModelBubble); |
| const progressBar = newModelBubble.querySelector('.bar'); |
| if (progressBar) { |
| requestAnimationFrame(() => { |
| progressBar.style.transition = 'width 30s ease-out'; |
| progressBar.style.width = '100%'; |
| }); |
| } |
| } |
| |
| const response = await api.getChatStream(historyForApi, state.globalAbortController.signal); |
| await api.readStreamAndDisplay(response, newModelBubble); |
| |
| } catch(error) { |
| if (error.name !== 'AbortError') console.error("Regeneration failed:", error); |
| } finally { |
| chatUI.resetState(); |
| state.saveSessions(); |
| } |
| } else { |
| chatUI.resetState(); |
| } |
| } else if (action === 'edit') { |
| if (state.isGenerating) return; |
| const lastUserMessageIndex = state.findLastIndex(activeChat.messages, msg => msg.role === 'user'); |
| if (messageIndex === lastUserMessageIndex) { |
| const textPart = message.parts.find(p => p.text); |
| const filePart = message.parts.find(p => p.id); |
| if (textPart || filePart) { |
| modalUI.showEditModal(textPart ? textPart.text : '', async (newText) => { |
| chatUI.setGeneratingState(true); |
| try { |
| const allMessagesInDOM = dom.chatWindow.querySelectorAll('.message-entry'); |
| allMessagesInDOM.forEach(msgEl => { |
| const idx = parseInt(msgEl.dataset.index, 10); |
| if (idx >= messageIndex) { |
| ttsUI.clearCacheForMessage(idx); |
| msgEl.remove(); |
| } |
| }); |
| activeChat.messages.length = messageIndex; |
| const newParts = []; |
| if (filePart) { |
| const file = await db.getFile(filePart.id); |
| const blobUrl = URL.createObjectURL(file); |
| const base64 = await api.processAndUploadFile(file).then(d => d.base64Data); |
| newParts.push({ ...filePart, blobUrl, base64Data: base64 }); |
| } |
| if (newText.trim()) newParts.push({ text: newText }); |
| if (newParts.length > 0) { |
| const editedUserMessage = { role: 'user', parts: newParts }; |
| activeChat.messages.push(editedUserMessage); |
| await chatUI.addMessageToUI(editedUserMessage, activeChat.messages.length - 1, { isLastUser: true, animate: true }); |
| } |
| const modelPlaceholderMessage = { role: 'assistant', isTemporary: true, parts: [] }; |
| activeChat.messages.push(modelPlaceholderMessage); |
| const newModelBubble = await chatUI.addMessageToUI(modelPlaceholderMessage, activeChat.messages.length - 1, { animate: true }); |
| |
| const historyForApi = activeChat.messages.map((msg, index) => { |
| if (index >= activeChat.messages.length - 2) return JSON.parse(JSON.stringify(msg)); |
| const cleanMsg = { role: msg.role, parts: [] }; |
| if (msg.parts) msg.parts.forEach(part => { if (part.text) cleanMsg.parts.push({ text: part.text }); }); |
| return cleanMsg; |
| }); |
|
|
| const response = await api.getChatStream(historyForApi, state.globalAbortController.signal); |
| await api.readStreamAndDisplay(response, newModelBubble); |
| } catch (error) { |
| if (error.name !== 'AbortError') console.error("Edit failed:", error); |
| } finally { |
| chatUI.resetState(); |
| state.saveSessions(); |
| } |
| }); |
| } |
| } |
| } |
| else if (action === 'show-message-menu') { |
| modalUI.showMessageMenu(e, messageIndex, activeChat, chatUI.escapeHTML); |
| } |
| }); |
|
|
| dom.historyItemMenu.addEventListener('click', (e) => { |
| const button = e.target.closest('.menu-item'); |
| if (!button) return; |
| const action = button.dataset.action; |
| const format = button.dataset.format; |
| const sessionId = dom.historyItemMenu.dataset.sessionId; |
| const session = state.chatSessions.find(s => s.id === sessionId); |
| if (!session) return; |
| if (action === 'rename') { |
| modalUI.showRenameModal(session.title, (newTitle) => { |
| session.title = newTitle; |
| state.saveSessions(); |
| chatUI.renderHistoryList(); |
| }); |
| } else if (action === 'delete') { |
| modalUI.showConfirmModal(`آیا از حذف گفتگوی "${session.title}" مطمئن هستید؟`, () => { |
| state.setChatSessions(state.chatSessions.filter(s => s.id !== sessionId)); |
| state.saveSessions(); |
| if (state.activeChatId === sessionId) { |
| if (state.chatSessions.length > 0) { |
| state.setActiveChatId(state.chatSessions[0].id); |
| chatUI.renderActiveChat(); |
| } else { |
| handleNewChat(); |
| } |
| } |
| chatUI.renderHistoryList(); |
| }); |
| } else if (action === 'convert-chat') { |
| const fullText = getFullChatText(session); |
| api.convertTextToFile(fullText, format, button); |
| } |
| dom.historyItemMenu.classList.remove('visible'); |
| }); |
|
|
| dom.messageItemMenu.addEventListener('click', (e) => { |
| const menu = dom.messageItemMenu; |
| const closeMenu = () => { |
| menu.classList.remove('visible'); |
| setTimeout(() => { menu.classList.add('hidden'); }, 300); |
| }; |
| if (e.target === dom.messageItemMenuOverlay) { |
| closeMenu(); |
| return; |
| } |
| const button = e.target.closest('.menu-item'); |
| if (!button) return; |
| const action = button.dataset.action; |
| const format = button.dataset.format; |
| const messageIndex = parseInt(menu.dataset.messageIndex, 10); |
| const activeChat = state.getActiveChat(); |
| if (!activeChat || isNaN(messageIndex)) { |
| closeMenu(); |
| return; |
| } |
| const message = activeChat.messages[messageIndex]; |
| if (action === 'delete-message') { |
| modalUI.showConfirmModal('آیا از حذف این پیام مطمئن هستید؟', () => { |
| state.deleteMessage(activeChat.id, messageIndex); |
| ttsUI.clearCacheForMessage(messageIndex); |
| chatUI.renderActiveChat(); |
| }); |
| } else if (action === 'convert-message') { |
| const textContent = message.parts?.find(p => p.text)?.text || ''; |
| if (textContent) api.convertTextToFile(textContent, format, button); |
| else alert('محتوای متنی برای تبدیل وجود ندارد.'); |
| } |
| closeMenu(); |
| }); |
| |
| dom.messageInput.addEventListener('input', () => { |
| chatUI.adjustTextareaHeight(dom.messageInput); |
| if (dom.messageInput.value.trim().length > 0 || state.attachedFile) { |
| dom.submitButton.classList.add('active'); |
| } else { |
| dom.submitButton.classList.remove('active'); |
| } |
| }); |
|
|
| dom.editInput.addEventListener('input', () => { |
| chatUI.adjustTextareaHeight(dom.editInput); |
| }); |
| |
| window.addEventListener('message', (event) => { |
| if (event.data && event.data.type === 'USER_DATA_RESPONSE_SIMPLE_CHECK') { |
| const PREMIUM_PAGE_ID = '1149636'; |
| let isUserPremium = false; |
| if (event.data.payload) { |
| try { |
| const userObject = JSON.parse(event.data.payload); |
| if (userObject && userObject.isLogin && userObject.accessible_pages) { |
| if (userObject.accessible_pages.includes(PREMIUM_PAGE_ID) || userObject.accessible_pages.includes(parseInt(PREMIUM_PAGE_ID))) { |
| isUserPremium = true; |
| } |
| } |
| } catch (e) { console.error("Error parsing user data from parent:", e); } |
| } |
| currentUserStatus.isPremium = isUserPremium; |
| currentUserStatus.hasBeenChecked = true; |
| if (!dom.settingsModal.classList.contains('hidden')) { |
| modalUI.updateSettingsUI(isUserPremium); |
| } |
| } |
| }); |
|
|
| parent.postMessage({ type: 'REQUEST_USER_DATA_SIMPLE_CHECK' }, '*'); |
| }); |
|
|
| window.handleSuggestionClick = chatUI.handleSuggestionClick; |
|
|