Corp/backend/static/js/components/messageEditing.js

213 lines
8.6 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.

/**
* messageEditing.js
*
* Обработка событий редактирования сообщений через WebSocket.
* Обновляет DOM когда сообщение было отредактировано другим пользователем
* или в другой вкладке.
*/
import { MessageRenderer } from './messageRenderer.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
const renderer = new MessageRenderer({
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');
}