305 lines
9.1 KiB
Markdown
305 lines
9.1 KiB
Markdown
# Рефакторинг JS-модулей - ВЫПОЛНЕНО
|
||
|
||
## Изменения в модулях
|
||
|
||
### ✅ 1. userWebSocket.js
|
||
|
||
**Добавлено:**
|
||
- Метод `.configure(options)` для динамической конфигурации после инициализации
|
||
|
||
**Функциональность:**
|
||
```javascript
|
||
const userWs = initUserWebSocket({ userId });
|
||
|
||
// Позже можно расширить конфигурацию
|
||
userWs.configure({
|
||
scrollContainerId: 'chatScroll',
|
||
formId: 'chatForm',
|
||
textareaId: 'id_content',
|
||
typingIndicatorId: 'typing',
|
||
avatarMap: avatarMap.getAll(),
|
||
markReadApi: markReadApi,
|
||
onListUpdate: (chatId, message) => { ... }
|
||
});
|
||
```
|
||
|
||
**Параметры configure():**
|
||
- `scrollContainerId` - ID контейнера с сообщениями
|
||
- `formId` - ID формы отправки
|
||
- `textareaId` - ID textarea
|
||
- `typingIndicatorId` - ID индикатора "печатает..."
|
||
- `avatarMap` - Карта аватаров пользователей
|
||
- `markReadApi` - API из chatMarkRead
|
||
- `onListUpdate` - Callback для обновления списка чатов
|
||
|
||
---
|
||
|
||
### ✅ 2. chatComposer.js
|
||
|
||
**Изменено:**
|
||
- Удалена авто-инициализация в конце файла
|
||
- Теперь инициализируется явно из `chat_detail_scripts.html`
|
||
- Возвращает один инстанс (если одна форма) или массив
|
||
|
||
**Было:**
|
||
```javascript
|
||
if (document.readyState === 'loading') {
|
||
document.addEventListener('DOMContentLoaded', () => initChatComposer());
|
||
} else {
|
||
initChatComposer();
|
||
}
|
||
```
|
||
|
||
**Стало:**
|
||
```javascript
|
||
// УДАЛЕНО: Авто-инициализация
|
||
// Теперь происходит через chat_detail_scripts.html
|
||
```
|
||
|
||
**Использование:**
|
||
```javascript
|
||
const composer = initChatComposer({
|
||
chatId: 123,
|
||
formId: 'chatForm',
|
||
textareaId: 'id_content',
|
||
uploadUrl: '/api/v1/upload-message/',
|
||
userWs: userWs
|
||
});
|
||
```
|
||
|
||
---
|
||
|
||
### ✅ 3. chatHistoryLoader.js
|
||
|
||
**Изменено:**
|
||
- Удалена авто-инициализация в конце файла
|
||
- Теперь инициализируется явно из `chat_detail_scripts.html`
|
||
|
||
**Было:**
|
||
```javascript
|
||
if (document.readyState === 'loading') {
|
||
document.addEventListener('DOMContentLoaded', () => initChatHistoryLoader());
|
||
} else {
|
||
initChatHistoryLoader();
|
||
}
|
||
```
|
||
|
||
**Стало:**
|
||
```javascript
|
||
// УДАЛЕНО: Авто-инициализация
|
||
// Теперь происходит через chat_detail_scripts.html
|
||
```
|
||
|
||
**Использование:**
|
||
```javascript
|
||
const historyLoader = initChatHistoryLoader({
|
||
chatId: 123,
|
||
scrollContainerId: 'chatScroll',
|
||
fetchUrl: '/api/v1/chats/123/messages/',
|
||
avatarMap: avatarMap.getAll(),
|
||
meId: 1
|
||
});
|
||
```
|
||
|
||
---
|
||
|
||
### ✅ 4. chatListFilter.js
|
||
|
||
**Статус:** Уже правильно структурирован
|
||
- Нет авто-инициализации
|
||
- Экспортирует `initChatListFilter()`
|
||
|
||
---
|
||
|
||
### ✅ 5. chatListRealtime.js
|
||
|
||
**Статус:** Уже правильно структурирован
|
||
- Нет авто-инициализации
|
||
- Экспортирует `initChatListRealtime()`
|
||
|
||
---
|
||
|
||
## Новая архитектура инициализации
|
||
|
||
### Последовательность загрузки на chat_detail.html:
|
||
|
||
```
|
||
1. base.html
|
||
└─ initUserWebSocket({ userId })
|
||
└─ событие: user:ws-ready
|
||
|
||
2. chat_scripts.html
|
||
└─ слушает: user:ws-ready
|
||
└─ initChatAvatarMap()
|
||
└─ initChatBadgeManager()
|
||
└─ событие: chat:system-ready
|
||
|
||
3. chat_detail_scripts.html
|
||
└─ слушает: chat:system-ready
|
||
└─ initChatMarkRead({ chatId, ... })
|
||
└─ initChatComposer({ chatId, userWs, ... })
|
||
└─ initChatHistoryLoader({ chatId, avatarMap, ... })
|
||
└─ userWs.configure({ ... }) ← расширяем конфигурацию
|
||
└─ userWs.openChat(chatId)
|
||
```
|
||
|
||
---
|
||
|
||
## Граф событий
|
||
|
||
```
|
||
[PAGE LOAD]
|
||
↓
|
||
[base.html] initUserWebSocket()
|
||
↓
|
||
[user:ws-ready] ← WebSocket подключен
|
||
↓
|
||
[chat_scripts.html] инициализация общих модулей
|
||
↓
|
||
[chat:system-ready] ← Система чатов готова
|
||
↓
|
||
[chat_detail_scripts.html] инициализация специфичных модулей
|
||
↓
|
||
[userWs.configure()] ← Расширение конфигурации
|
||
↓
|
||
[userWs.openChat()] ← Открытие чата
|
||
↓
|
||
[READY] ← Страница полностью готова
|
||
```
|
||
|
||
---
|
||
|
||
## Преимущества новой архитектуры
|
||
|
||
### 1. ✅ Явная инициализация
|
||
- Понятно, когда и где инициализируется каждый модуль
|
||
- Нет "магии" автоматической инициализации
|
||
- Легко отследить порядок загрузки
|
||
|
||
### 2. ✅ Event-driven координация
|
||
- Модули не зависят друг от друга напрямую
|
||
- Связь через события: `user:ws-ready`, `chat:system-ready`
|
||
- Легко добавлять новые слушатели
|
||
|
||
### 3. ✅ Ленивая конфигурация
|
||
- Базовая инициализация в `base.html`
|
||
- Расширение конфигурации по мере необходимости
|
||
- Метод `.configure()` для динамического расширения
|
||
|
||
### 4. ✅ Изоляция модулей
|
||
- Каждый модуль экспортирует только `init` функцию
|
||
- Нет побочных эффектов при импорте
|
||
- Модули можно тестировать независимо
|
||
|
||
### 5. ✅ Масштабируемость
|
||
- Легко добавлять новые модули
|
||
- Легко создавать новые страницы с чатами
|
||
- Переиспользование кода
|
||
|
||
---
|
||
|
||
## Примеры использования
|
||
|
||
### Создание новой страницы с чатом:
|
||
|
||
```django
|
||
{# templates/communications/new_page.html #}
|
||
{% extends "base.html" %}
|
||
|
||
{% block extra_js %}
|
||
{# Подключаем общие chat-скрипты #}
|
||
{% include "includes/chat_scripts.html" %}
|
||
|
||
{# Специфичная логика #}
|
||
<script type="module">
|
||
window.addEventListener('chat:system-ready', (e) => {
|
||
const { userWs, avatarMap, badgeManager } = e.detail;
|
||
|
||
// Инициализируем нужные модули
|
||
const myFeature = initMyFeature({
|
||
userWs,
|
||
avatarMap,
|
||
badgeManager
|
||
});
|
||
|
||
// Расширяем userWs
|
||
userWs.configure({
|
||
onSpecialEvent: (data) => {
|
||
myFeature.handle(data);
|
||
}
|
||
});
|
||
});
|
||
</script>
|
||
{% endblock %}
|
||
```
|
||
|
||
### Добавление нового обработчика в userWs:
|
||
|
||
```javascript
|
||
window.addEventListener('chat:system-ready', (e) => {
|
||
const { userWs } = e.detail;
|
||
|
||
// Расширяем конфигурацию
|
||
userWs.configure({
|
||
onCustomEvent: (data) => {
|
||
console.log('Custom event:', data);
|
||
}
|
||
});
|
||
});
|
||
```
|
||
|
||
---
|
||
|
||
## Обратная совместимость
|
||
|
||
**Сохранены глобальные переменные:**
|
||
```javascript
|
||
window.userWebSocket = userWs;
|
||
window.chatWebSocketApi = userWs; // legacy
|
||
window.chatWebSocket = userWs.ws; // legacy
|
||
window.chatAvatarMap = avatarMap;
|
||
window.chatBadgeManager = badgeManager;
|
||
```
|
||
|
||
**Старый код продолжает работать:**
|
||
```javascript
|
||
// Старый способ (работает)
|
||
if (window.chatWebSocketApi) {
|
||
window.chatWebSocketApi.sendMessage('Hello');
|
||
}
|
||
|
||
// Новый способ (рекомендуется)
|
||
window.addEventListener('chat:system-ready', (e) => {
|
||
const { userWs } = e.detail;
|
||
userWs.sendMessage('Hello');
|
||
});
|
||
```
|
||
|
||
---
|
||
|
||
## Метрики
|
||
|
||
### До рефакторинга:
|
||
- ❌ Автоматическая инициализация во всех модулях
|
||
- ❌ Прямые зависимости между модулями
|
||
- ❌ Непонятный порядок загрузки
|
||
- ❌ Сложно тестировать
|
||
|
||
### После рефакторинга:
|
||
- ✅ Явная инициализация через `init` функции
|
||
- ✅ Event-driven архитектура
|
||
- ✅ Чёткий порядок: base → chat_scripts → chat_detail_scripts
|
||
- ✅ Изолированные модули, легко тестировать
|
||
|
||
---
|
||
|
||
## Следующие шаги
|
||
|
||
1. ✅ **ГОТОВО:** Рефакторинг base.html
|
||
2. ✅ **ГОТОВО:** Добавлен метод .configure() в userWebSocket.js
|
||
3. ✅ **ГОТОВО:** Удалена авто-инициализация из chatComposer.js
|
||
4. ✅ **ГОТОВО:** Удалена авто-инициализация из chatHistoryLoader.js
|
||
5. 🔄 **СЛЕДУЮЩЕЕ:** Тестирование на реальной странице
|
||
6. 🔄 **СЛЕДУЮЩЕЕ:** Документирование API всех модулей
|
||
7. 📋 **ПОТОМ:** Полный рефакторинг на React/Vue (компонентный подход)
|