paper-burner/js/chatbot/core/chat-message-event-manager.js

308 lines
10 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// js/chatbot/core/chat-message-event-manager.js
/**
* 聊天消息事件管理器
*
* Phase 3: 使用事件委托Event Delegation处理所有消息操作
*
* 核心优势:
* 1. 内存占用减少 40-60%(从 N×8 个监听器降至 2 个)
* 2. 动态内容无需重新绑定事件
* 3. 集中管理所有事件逻辑,提升可维护性
* 4. 减少 DOM 操作,提升渲染速度
*
* @class ChatMessageEventManager
* @version 1.0.0
* @date 2025-01-12
*/
class ChatMessageEventManager {
/**
* 构造函数
* @param {string} containerSelector - 聊天消息容器的选择器
*/
constructor(containerSelector) {
this.containerSelector = containerSelector;
this.container = document.querySelector(containerSelector);
if (!this.container) {
console.warn(`[EventManager] 容器未找到: ${containerSelector},将在 DOM 加载后重试`);
// 如果容器还未加载,等待 DOM 加载完成
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', () => this._init());
}
return;
}
this._init();
}
/**
* 初始化事件管理器
* @private
*/
_init() {
this.container = document.querySelector(this.containerSelector);
if (!this.container) {
console.error(`[EventManager] 容器仍未找到: ${this.containerSelector}`);
return;
}
this._setupEventDelegation();
console.log('[EventManager] ✅ 事件委托已初始化');
}
/**
* 设置事件委托
* @private
*/
_setupEventDelegation() {
// ==========================================
// 单一点击事件监听器(所有按钮点击)
// ==========================================
this.container.addEventListener('click', (e) => {
// 查找最近的带有 data-action 的元素
const target = e.target.closest('[data-action]');
if (!target) return;
const action = target.dataset.action;
const index = target.dataset.index ? parseInt(target.dataset.index) : null;
console.log(`[EventManager] 触发操作: ${action}, 索引: ${index}`);
// 根据 action 分发到对应处理器
switch (action) {
case 'delete':
this._handleDelete(index, e);
break;
case 'resend':
this._handleResend(index, e);
break;
case 'copy':
this._handleCopy(index, e);
break;
case 'export-png':
this._handleExportPng(index, e);
break;
case 'toggle-reasoning':
this._handleToggleReasoning(index, e);
break;
case 'show-image':
this._handleShowImage(target.dataset.imageUrl, e);
break;
case 'open-mindmap':
this._handleOpenMindmap(target.dataset.mindmapUrl, e);
break;
case 'open-drawio':
this._handleOpenDrawio(target.dataset.drawioUrl, e);
break;
default:
console.warn(`[EventManager] 未知操作: ${action}`);
}
});
// ==========================================
// 键盘快捷键
// ==========================================
this.container.addEventListener('keydown', (e) => {
// Delete 键删除消息
if (e.key === 'Delete' && e.target.closest('.message-container')) {
const container = e.target.closest('.message-container');
const index = this._getMessageIndex(container);
if (index !== null) {
console.log(`[EventManager] 键盘删除消息 #${index}`);
this._handleDelete(index, e);
}
}
});
console.log('[EventManager] 事件监听器已绑定');
}
/**
* 从消息容器获取索引
* @param {HTMLElement} container - 消息容器元素
* @returns {number|null} 消息索引
* @private
*/
_getMessageIndex(container) {
const btn = container.querySelector('[data-index]');
return btn ? parseInt(btn.dataset.index) : null;
}
// ==========================================
// 事件处理器
// ==========================================
/**
* 删除消息
* @param {number} index - 消息索引
* @param {Event} event - 原始事件对象
* @private
*/
_handleDelete(index, event) {
event.stopPropagation();
console.log(`[EventManager] 🗑️ 删除消息 #${index}`);
if (window.ChatbotActions && typeof window.ChatbotActions.deleteMessage === 'function') {
window.ChatbotActions.deleteMessage(index);
} else {
console.error('[EventManager] ChatbotActions.deleteMessage 未定义');
}
}
/**
* 重新发送消息
* @param {number} index - 消息索引
* @param {Event} event - 原始事件对象
* @private
*/
_handleResend(index, event) {
event.stopPropagation();
console.log(`[EventManager] 🔄 重发消息 #${index}`);
if (window.ChatbotActions && typeof window.ChatbotActions.resendUserMessage === 'function') {
window.ChatbotActions.resendUserMessage(index);
} else {
console.error('[EventManager] ChatbotActions.resendUserMessage 未定义');
}
}
/**
* 复制消息内容
* @param {number} index - 消息索引
* @param {Event} event - 原始事件对象
* @private
*/
_handleCopy(index, event) {
event.stopPropagation();
console.log(`[EventManager] 📋 复制消息 #${index}`);
if (window.ChatbotUtils && typeof window.ChatbotUtils.copyAssistantMessage === 'function') {
window.ChatbotUtils.copyAssistantMessage(index);
} else {
console.error('[EventManager] ChatbotUtils.copyAssistantMessage 未定义');
}
}
/**
* 导出消息为 PNG
* @param {number} index - 消息索引
* @param {Event} event - 原始事件对象
* @private
*/
_handleExportPng(index, event) {
event.stopPropagation();
console.log(`[EventManager] 📸 导出消息 #${index} 为 PNG`);
if (window.ChatbotUtils && typeof window.ChatbotUtils.exportMessageAsPng === 'function') {
window.ChatbotUtils.exportMessageAsPng(index);
} else {
console.error('[EventManager] ChatbotUtils.exportMessageAsPng 未定义');
}
}
/**
* 切换思考过程显示/隐藏
* @param {number} index - 消息索引
* @param {Event} event - 原始事件对象
* @private
*/
_handleToggleReasoning(index, event) {
event.stopPropagation();
console.log(`[EventManager] 🧠 切换思考过程 #${index}`);
// 切换折叠状态
const collapseKey = `reasoningCollapsed_${index}`;
window[collapseKey] = !window[collapseKey];
// 更新 UI
if (window.ChatbotUI && typeof window.ChatbotUI.updateChatbotUI === 'function') {
window.ChatbotUI.updateChatbotUI();
} else {
console.error('[EventManager] ChatbotUI.updateChatbotUI 未定义');
}
}
/**
* 显示图片模态框
* @param {string} imageUrl - 图片 URL
* @param {Event} event - 原始事件对象
* @private
*/
_handleShowImage(imageUrl, event) {
event.stopPropagation();
console.log(`[EventManager] 🖼️ 显示图片: ${imageUrl}`);
if (window.ChatbotImageUtils && typeof window.ChatbotImageUtils.showImageModal === 'function') {
window.ChatbotImageUtils.showImageModal(imageUrl);
} else {
console.error('[EventManager] ChatbotImageUtils.showImageModal 未定义');
}
}
/**
* 打开思维导图
* @param {string} mindmapUrl - 思维导图 URL
* @param {Event} event - 原始事件对象
* @private
*/
_handleOpenMindmap(mindmapUrl, event) {
event.stopPropagation();
console.log(`[EventManager] 🗺️ 打开思维导图: ${mindmapUrl}`);
if (mindmapUrl) {
window.open(mindmapUrl, '_blank');
} else {
console.error('[EventManager] 思维导图 URL 为空');
}
}
/**
* 打开 draw.io 配图编辑器
* @param {string} drawioUrl - draw.io 视图 URL
* @param {Event} event - 原始事件对象
* @private
*/
_handleOpenDrawio(drawioUrl, event) {
event.stopPropagation();
console.log(`[EventManager] 🧩 打开配图编辑器: ${drawioUrl}`);
if (drawioUrl) {
window.open(drawioUrl, '_blank');
} else {
console.error('[EventManager] 配图编辑器 URL 为空');
}
}
// ==========================================
// 公共方法
// ==========================================
/**
* 销毁事件管理器
* (事件委托会自动清理,无需手动移除)
*/
destroy() {
console.log('[EventManager] 🧹 已销毁');
// 事件委托模式下,只需要移除容器上的监听器即可
// 由于我们在容器上绑定GC 会自动处理
}
/**
* 重新初始化(用于动态更换容器)
* @param {string} newContainerSelector - 新容器选择器
*/
reinit(newContainerSelector) {
console.log(`[EventManager] 🔄 重新初始化: ${newContainerSelector}`);
this.containerSelector = newContainerSelector;
this._init();
}
}
// ==========================================
// 导出到全局
// ==========================================
window.ChatMessageEventManager = ChatMessageEventManager;
console.log('[ChatMessageEventManager] 类定义已加载');