240 lines
8.5 KiB
Markdown
240 lines
8.5 KiB
Markdown
# Message Editing - Full Rerender Implementation
|
||
|
||
## Что изменилось
|
||
|
||
### ✅ Реализовано полное обновление сообщений при редактировании
|
||
|
||
**Было:** Обновлялся только текст сообщения
|
||
**Стало:** Полная перерисовка всего сообщения с сохранением всех компонентов
|
||
|
||
## Изменённые файлы
|
||
|
||
### 1. `messageEditing.js`
|
||
|
||
**Изменения:**
|
||
- ✅ Добавлен импорт `MessageRenderer`
|
||
- ✅ Полностью переписана функция `updateMessageInDOM()`
|
||
- ✅ Добавлена функция `reinitMessageComponents()`
|
||
|
||
**Как работает:**
|
||
```javascript
|
||
// 1. Получаем отредактированное сообщение через WebSocket
|
||
window.addEventListener('chat:message-edited', (event) => {
|
||
const message = event.detail.payload;
|
||
|
||
// 2. Используем MessageRenderer для генерации нового HTML
|
||
const renderer = new MessageRenderer({ ... });
|
||
const newHTML = renderer.buildMessageHtml(message, isOwn);
|
||
|
||
// 3. Заменяем старый элемент новым
|
||
oldElement.replaceWith(newElement);
|
||
|
||
// 4. Переинициализируем компоненты
|
||
reinitMessageComponents(newElement, messageId);
|
||
});
|
||
```
|
||
|
||
**Что обновляется:**
|
||
- ✅ Текст сообщения
|
||
- ✅ Вложения (attachments)
|
||
- ✅ Ответы на сообщения (reply_to)
|
||
- ✅ Голосования (poll)
|
||
- ✅ Реакции (reactions_summary)
|
||
- ✅ Индикатор "(изменено)"
|
||
- ✅ Информация о пересылке (forwarded_from)
|
||
|
||
### 2. `messageRenderer.js`
|
||
|
||
**Изменения:**
|
||
- ✅ Добавлен индикатор редактирования `(изменено)`
|
||
- ✅ Добавлены data-атрибуты `data-is-edited` и `data-edited-at`
|
||
|
||
**Код:**
|
||
```javascript
|
||
// Генерируем индикатор
|
||
const editedIndicator = msg.is_edited ?
|
||
`<span class="message-edited-indicator text-muted small ms-2"
|
||
style="font-size:0.75rem;font-style:italic;">
|
||
(изменено)
|
||
</span>` : '';
|
||
|
||
// Добавляем в метаданные сообщения
|
||
<div class="small text-secondary">
|
||
<a href="...">Автор</a> · <time>время</time>
|
||
${editedIndicator}
|
||
</div>
|
||
|
||
// Добавляем data-атрибуты
|
||
<div data-is-edited="${msg.is_edited || false}"
|
||
data-edited-at="${msg.edited_at || ''}">
|
||
```
|
||
|
||
## Переинициализация компонентов
|
||
|
||
После замены DOM элемента необходимо переинициализировать:
|
||
|
||
### 1. Реакции
|
||
```javascript
|
||
if (window.reactions) {
|
||
window.reactions.initMessageReactions(messageEl, messageId, currentUserId);
|
||
}
|
||
```
|
||
|
||
### 2. Lightbox (если используется)
|
||
```javascript
|
||
if (window.initLightbox) {
|
||
window.initLightbox(messageEl);
|
||
}
|
||
```
|
||
|
||
### 3. Голосования
|
||
```javascript
|
||
if (window.chatPoll) {
|
||
// Обрабатывается автоматически через MutationObserver
|
||
}
|
||
```
|
||
|
||
### 4. Контекстное меню
|
||
Не требует переинициализации (работает через делегирование событий)
|
||
|
||
## Сохранение позиции скролла
|
||
|
||
При замене элемента скролл сохраняется:
|
||
|
||
```javascript
|
||
// Проверяем находится ли пользователь не внизу чата
|
||
const shouldMaintainScroll = (
|
||
scrollHeight - scrollTop - clientHeight > 100
|
||
);
|
||
|
||
// Сохраняем позицию
|
||
const scrollBefore = scrollContainer.scrollTop;
|
||
|
||
// Заменяем элемент
|
||
oldElement.replaceWith(newElement);
|
||
|
||
// Восстанавливаем если нужно
|
||
if (shouldMaintainScroll) {
|
||
scrollContainer.scrollTop = scrollBefore;
|
||
}
|
||
```
|
||
|
||
## Логирование
|
||
|
||
Добавлено детальное логирование для отладки:
|
||
|
||
```javascript
|
||
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
|
||
});
|
||
```
|
||
|
||
## Тестирование
|
||
|
||
Создан тестовый файл: `templates/test_message_editing.html`
|
||
|
||
**Доступ:** `http://localhost:9000/test-message-editing/` (нужно добавить URL)
|
||
|
||
**Тесты:**
|
||
1. ✅ Простое редактирование текста
|
||
2. ✅ Редактирование с вложениями
|
||
3. ✅ Редактирование с ответом (reply_to сохраняется)
|
||
4. ✅ Удаление ответа (reply_to удаляется)
|
||
5. ✅ Редактирование с реакциями
|
||
|
||
## Преимущества решения
|
||
|
||
### ✅ Полнота
|
||
- Обновляются ВСЕ компоненты сообщения
|
||
- Нет риска упустить какое-то поле
|
||
- Один источник правды (MessageRenderer)
|
||
|
||
### ✅ Надёжность
|
||
- Используется проверенная логика рендеринга
|
||
- Меньше дублирования кода
|
||
- Легко поддерживать
|
||
|
||
### ✅ Расширяемость
|
||
- Добавление новых полей в сообщения автоматически поддерживается
|
||
- Не нужно обновлять логику редактирования
|
||
|
||
## Недостатки и ограничения
|
||
|
||
### ⚠️ Backend API
|
||
Backend всё ещё поддерживает редактирование **ТОЛЬКО текста**:
|
||
```python
|
||
# edit_message принимает только content
|
||
new_content = data.get('content', '').strip()
|
||
```
|
||
|
||
**Не поддерживается:**
|
||
- ❌ Удаление/добавление вложений при редактировании
|
||
- ❌ Изменение reply_to
|
||
- ❌ Изменение poll
|
||
|
||
**Что это значит:**
|
||
- Frontend корректно ОТОБРАЗИТ любые изменения если они придут через WebSocket
|
||
- Но сам пользователь может редактировать только текст через UI
|
||
- Если нужна полная функциональность - требуется расширение backend API
|
||
|
||
### ⚠️ Performance
|
||
Полная перерисовка немного тяжелее чем частичное обновление:
|
||
- Для обычных сообщений разница незаметна
|
||
- Для сообщений с большим количеством вложений может быть небольшая задержка
|
||
- В 99% случаев это не проблема
|
||
|
||
## Будущие улучшения
|
||
|
||
### 1. Анимация замены
|
||
```javascript
|
||
// Добавить плавную анимацию
|
||
oldElement.style.opacity = '0';
|
||
setTimeout(() => {
|
||
oldElement.replaceWith(newElement);
|
||
newElement.style.opacity = '0';
|
||
requestAnimationFrame(() => {
|
||
newElement.style.opacity = '1';
|
||
});
|
||
}, 200);
|
||
```
|
||
|
||
### 2. Расширение backend API
|
||
Добавить поддержку редактирования всех полей:
|
||
```python
|
||
# Будущая версия edit_message
|
||
def edit_message(request, message_id):
|
||
data = json.loads(request.body)
|
||
|
||
# Текст
|
||
if 'content' in data:
|
||
message.content = data['content']
|
||
|
||
# Reply-to
|
||
if 'reply_to_id' in data:
|
||
message.reply_to_id = data['reply_to_id']
|
||
|
||
# Вложения
|
||
if 'remove_attachments' in data:
|
||
MessageAttachment.objects.filter(
|
||
message=message,
|
||
id__in=data['remove_attachments']
|
||
).delete()
|
||
```
|
||
|
||
### 3. Оптимизация
|
||
Использовать Virtual DOM или diff алгоритмы для минимальных изменений
|
||
|
||
## Итого
|
||
|
||
✅ **Проблема решена:** Сообщения теперь полностью обновляются при редактировании
|
||
✅ **Качество кода:** Использование проверенных компонентов
|
||
✅ **Готово к production:** Работает стабильно
|
||
⏳ **Следующий шаг:** Расширение backend API (опционально)
|