Two types of bottom:
1. Historical bottom (hasMoreAfter=true):
- Button ALWAYS visible (even at scroll bottom)
- Click → loads latest 50 messages to present time
- Renders and scrolls to bottom
2. Present bottom (hasMoreAfter=false):
- Button hidden when isNearBottom()
- Click → smart scroll (to unread or bottom)
Changes:
- _setupSmartButtonVisibility() monitors hasMoreAfter
- _handleScrollButtonClick() loads history if hasMoreAfter
- Added public loadLatest() method
- Emits 'chat:messagesLoaded' event for UI updates
Result:
- Historical view: button always shows, loads to present
- Present view: button hides at bottom, smart unread scroll
- No more stuck in history without way to present
BREAKTHROUGH: Discovered append doesn't need autoscroll!
Changes:
- ✅ KEPT: scrollTop correction after prepend (physics, not autoscroll)
Prevents infinite history loading by compensating scrollHeight growth
- ❌ REMOVED: scrollToBottom() - now empty stub
- ❌ REMOVED: scrollToMessage() - now empty stub
- ❌ REMOVED: Initial scroll on chat open
- ❌ REMOVED: Scroll after loadAround
Philosophy shift:
- Old: We control user's scroll position
- New: IntersectionObserver + physics = natural behavior
Results:
- Newer messages load perfectly WITHOUT autoscroll
- Older messages need ONLY physics correction
- User controls their own scroll position
- Natural infinite scroll experience
ПРОБЛЕМЫ:
- chatDetailV2.js не передавал lastReadTimestamp в config
- метод _loadAround не имел return statement
- scrollIntoView скроллил родительские контейнеры
ИСПРАВЛЕНИЯ:
✅ Добавлен lastReadTimestamp в readConfig() chatDetailV2.js
✅ Добавлена передача lastReadTimestamp в ChatControllerV2
✅ Исправлен _loadAround - добавлен return loadResult
✅ Заменен scrollIntoView на ручной расчет scrollTop в _scrollToMessage
✅ Добавлено подробное логирование для отладки
РЕЗУЛЬТАТ:
- Чат загружается вокруг последнего прочитанного (16 сообщений вместо 30)
- Скролл к правильной позиции
- Header не прячется под navbar
- IntersectionObserver не срабатывает при инициализации
- Логируем сырое значение из data-last-read-message-id
- Логируем решение загрузки (around vs latest)
- Поможет понять почему скролит в низ вместо последнего прочитанного
- ScrollManagerV2: использует prepend + height difference вместо полного ре-рендера
- MessageLoaderV2: фильтрует новые сообщения, возвращает только их
- MessageStoreV2: silent mode для загрузки истории (без событий)
- MessageRendererV2: детальное логирование для диагностики
Проблема: Store emit'ил события → appendMessage добавлял в конец → prependMessages пропускал дубликаты
Решение: silent mode отключает события → отрисовка только через prepend → сообщения в начало