213 lines
8.7 KiB
JavaScript
213 lines
8.7 KiB
JavaScript
/**
|
||
* messageEditing.js
|
||
*
|
||
* Обработка событий редактирования сообщений через WebSocket.
|
||
* Обновляет DOM когда сообщение было отредактировано другим пользователем
|
||
* или в другой вкладке.
|
||
*/
|
||
|
||
import { MessageRendererV2 } from '../renderers/messageRendererV2.js';
|
||
|
||
/**
|
||
* Инициализация обработки редактирования сообщений
|
||
*/
|
||
export function initMessageEditing() {
|
||
console.log('[MessageEditing] Initializing message editing handler...');
|
||
|
||
// Слушаем событие редактирования от WebSocket
|
||
window.addEventListener('chat:message-edited', handleMessageEdited);
|
||
|
||
console.log('[MessageEditing] Handler initialized successfully');
|
||
}
|
||
|
||
/**
|
||
* Обработчик события редактирования сообщения
|
||
* @param {CustomEvent} event - событие с данными отредактированного сообщения
|
||
*/
|
||
function handleMessageEdited(event) {
|
||
const data = event.detail;
|
||
console.log('[MessageEditing] Message edited event received:', data);
|
||
|
||
const message = data.payload || data.message;
|
||
if (!message || !message.id) {
|
||
console.warn('[MessageEditing] Invalid message data:', data);
|
||
return;
|
||
}
|
||
|
||
// Подробный лог того что пришло
|
||
console.log('[MessageEditing] ========== MESSAGE DATA ==========');
|
||
console.log('[MessageEditing] ID:', message.id);
|
||
console.log('[MessageEditing] Content:', message.content);
|
||
console.log('[MessageEditing] has_attachments:', message.has_attachments);
|
||
console.log('[MessageEditing] attachments:', message.attachments);
|
||
console.log('[MessageEditing] attachments length:', message.attachments?.length);
|
||
console.log('[MessageEditing] reply_to:', message.reply_to);
|
||
console.log('[MessageEditing] poll:', message.poll);
|
||
console.log('[MessageEditing] is_forwarded:', message.is_forwarded);
|
||
console.log('[MessageEditing] forwarded_from:', message.forwarded_from);
|
||
console.log('[MessageEditing] reactions_summary:', message.reactions_summary);
|
||
console.log('[MessageEditing] is_edited:', message.is_edited);
|
||
console.log('[MessageEditing] ===================================');
|
||
|
||
updateMessageInDOM(message);
|
||
}
|
||
|
||
/**
|
||
* Обновляет сообщение в DOM после редактирования
|
||
* ИСПОЛЬЗУЕТ ПОЛНУЮ ПЕРЕРИСОВКУ через MessageRenderer
|
||
* @param {Object} message - данные сообщения
|
||
*/
|
||
function updateMessageInDOM(message) {
|
||
// Ищем все элементы с этим message_id (может быть несколько копий)
|
||
const messageElements = document.querySelectorAll(`[data-message-id="${message.id}"]`);
|
||
|
||
if (messageElements.length === 0) {
|
||
console.log('[MessageEditing] Message element not found in DOM:', message.id);
|
||
return;
|
||
}
|
||
|
||
console.log('[MessageEditing] Updating message elements:', messageElements.length);
|
||
console.log('[MessageEditing] Message data:', {
|
||
id: message.id,
|
||
content: message.content,
|
||
has_attachments: message.has_attachments,
|
||
attachments: message.attachments?.length || 0,
|
||
reply_to: !!message.reply_to,
|
||
poll: !!message.poll,
|
||
reactions: Object.keys(message.reactions_summary || {}).length,
|
||
is_edited: message.is_edited
|
||
});
|
||
|
||
messageElements.forEach(oldMessageEl => {
|
||
try {
|
||
// Получаем данные для рендера
|
||
const chatScroll = document.getElementById('chatScroll');
|
||
const currentUserId = parseInt(chatScroll?.dataset.meId || oldMessageEl.dataset.currentUserId);
|
||
|
||
if (!currentUserId) {
|
||
console.warn('[MessageEditing] Cannot determine current user ID');
|
||
return;
|
||
}
|
||
|
||
// Создаём renderer V2
|
||
const renderer = new MessageRendererV2({
|
||
containerId: 'chatScroll',
|
||
currentUserId: currentUserId,
|
||
currentUserAvatar: window.currentUserAvatar || '',
|
||
profileUrl: '/employees/profile/',
|
||
detailUrlTemplate: '/employees/detail/0/'
|
||
});
|
||
|
||
// Определяем является ли сообщение своим
|
||
const isOwn = message.author_id === currentUserId;
|
||
|
||
// Генерируем новый HTML
|
||
const newMessageHtml = renderer.buildMessageHtml(message, isOwn);
|
||
|
||
console.log('[MessageEditing] Generated HTML length:', newMessageHtml.length);
|
||
console.log('[MessageEditing] HTML contains "attachment":', newMessageHtml.includes('attachment'));
|
||
console.log('[MessageEditing] HTML contains "reply-reference":', newMessageHtml.includes('reply-reference'));
|
||
console.log('[MessageEditing] HTML sample:', newMessageHtml.substring(0, 500));
|
||
|
||
// Создаём временный контейнер для парсинга HTML
|
||
const tempDiv = document.createElement('div');
|
||
tempDiv.innerHTML = newMessageHtml.trim();
|
||
const newMessageEl = tempDiv.firstElementChild;
|
||
|
||
if (!newMessageEl) {
|
||
console.error('[MessageEditing] Failed to parse new message HTML');
|
||
return;
|
||
}
|
||
|
||
// Сохраняем позицию скролла
|
||
const scrollContainer = document.getElementById('chatScroll');
|
||
const shouldMaintainScroll = scrollContainer && (
|
||
scrollContainer.scrollHeight - scrollContainer.scrollTop - scrollContainer.clientHeight > 100
|
||
);
|
||
const scrollBefore = scrollContainer?.scrollTop || 0;
|
||
|
||
// Заменяем элемент
|
||
oldMessageEl.replaceWith(newMessageEl);
|
||
console.log('[MessageEditing] ✓ Message DOM replaced');
|
||
|
||
// Восстанавливаем скролл если пользователь не внизу
|
||
if (shouldMaintainScroll && scrollContainer) {
|
||
scrollContainer.scrollTop = scrollBefore;
|
||
}
|
||
|
||
// Переинициализируем компоненты для нового элемента
|
||
reinitMessageComponents(newMessageEl, message.id, currentUserId);
|
||
|
||
} catch (error) {
|
||
console.error('[MessageEditing] Error updating message:', error);
|
||
}
|
||
});
|
||
|
||
console.log('[MessageEditing] ✓ Message fully updated with all components:', message.id);
|
||
}
|
||
|
||
/**
|
||
* Переинициализирует компоненты сообщения после замены DOM
|
||
* @param {HTMLElement} messageEl - элемент сообщения
|
||
* @param {number} messageId - ID сообщения
|
||
* @param {number} currentUserId - ID текущего пользователя
|
||
*/
|
||
function reinitMessageComponents(messageEl, messageId, currentUserId) {
|
||
console.log('[MessageEditing] Reinitializing components for message:', messageId);
|
||
|
||
// 1. Реинициализируем реакции
|
||
if (window.reactions && typeof window.reactions.initMessageReactions === 'function') {
|
||
try {
|
||
window.reactions.initMessageReactions(messageEl, messageId, currentUserId);
|
||
console.log('[MessageEditing] ✓ Reactions reinitialized');
|
||
} catch (error) {
|
||
console.error('[MessageEditing] Failed to reinit reactions:', error);
|
||
}
|
||
}
|
||
|
||
// 2. Контекстное меню работает через делегирование событий,
|
||
// переинициализация не требуется
|
||
|
||
// 3. Lightbox для изображений (если используется)
|
||
const images = messageEl.querySelectorAll('img[data-lightbox], .attachment-image');
|
||
if (images.length > 0 && window.initLightbox) {
|
||
try {
|
||
window.initLightbox(messageEl);
|
||
console.log('[MessageEditing] ✓ Lightbox reinitialized for', images.length, 'images');
|
||
} catch (error) {
|
||
console.error('[MessageEditing] Failed to reinit lightbox:', error);
|
||
}
|
||
}
|
||
|
||
// 4. Голосования (если есть)
|
||
const pollEl = messageEl.querySelector('[data-poll-id]');
|
||
if (pollEl && window.chatPoll) {
|
||
try {
|
||
const pollId = pollEl.dataset.pollId;
|
||
console.log('[MessageEditing] Refreshing poll:', pollId);
|
||
// Вызываем refreshPoll для обновления состояния опроса
|
||
window.chatPoll.refreshPoll(pollId, pollEl);
|
||
console.log('[MessageEditing] ✓ Poll reinitialized, id:', pollId);
|
||
} catch (error) {
|
||
console.error('[MessageEditing] Failed to reinit poll:', error);
|
||
}
|
||
}
|
||
|
||
// 5. Обработчики кликов на reply-reference (скролл к сообщению)
|
||
const replyRef = messageEl.querySelector('.reply-reference');
|
||
if (replyRef) {
|
||
// Уже обработано через onclick в HTML, но можно добавить дополнительную логику
|
||
console.log('[MessageEditing] ✓ Reply reference detected');
|
||
}
|
||
|
||
console.log('[MessageEditing] ✓ All components reinitialized');
|
||
}
|
||
|
||
/**
|
||
* Очистка обработчика (для случаев когда нужно отключить)
|
||
*/
|
||
export function cleanupMessageEditing() {
|
||
window.removeEventListener('chat:message-edited', handleMessageEdited);
|
||
console.log('[MessageEditing] Handler cleaned up');
|
||
}
|