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
Implements Telegram-like behavior for new messages:
1. Smart Auto-scroll (WS messages):
✅ User at bottom + present time → auto-scroll to new message
✅ User NOT at bottom + present time → show unread badge
❌ Historical view (hasMoreAfter=true) → no action
2. Smart Scroll Button (#scrollBtn):
- Shows unread badge when new messages arrive
- Click behavior:
* Has unread + lastReadId → scroll to first unread
* No unread → scroll to bottom
- Auto-hides badge when user scrolls to bottom
3. Badge Styling:
- Red badge with count on top-right of button
- Pulse animation on appearance
- Button subtle pulse when has unread
Key Logic:
- Only auto-scroll when hasMoreAfter=false (present time)
- Historical bottom (hasMoreAfter=true) doesn't trigger auto-scroll
- Badge resets on: manual scroll to bottom, button click
- Respects user's scroll position unless at bottom
Problem: After removing autoscroll, last read message wasn't visible on initial load
Solution:
- ✨ NEW: _positionToMessage() - instant viewport positioning WITHOUT scroll animation
- Sets scrollTop BEFORE user sees chat (no visible scrolling)
- Centers last read message with sticky header offset (96px)
- Falls back to bottom position for new chats
Difference:
- ❌ Old: render → scrollIntoView() → visible scroll animation
- ✅ New: render → scrollTop = X → instant positioning
Result:
- Chat opens IMMEDIATELY showing last read message
- NO visible scrolling or animation
- Telegram-like behavior: position is set, not scrolled to
- Natural user experience
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
- Прямой импорт ChatControllerV2 без промежуточных слоев
- Убраны deprecated обертки (window.messageRenderer, window.chatHistoryLoader)
- Меньше кода: 231 vs 264 строки
- Более явная архитектура
- Для тестирования работы в production
- Проблема: lastReadMessageId часто равен 0/null
- Решение: используем lastReadTimestamp (API поддерживает оба формата)
- Добавлен this.lastReadTimestamp в ChatControllerV2
- Передаем оба параметра из chatDetail.js
- anchorValue = lastReadMessageId || lastReadTimestamp
- Исправлена поврежденная структура в chatControllerV2.js
- scrollTo() НЕ работает при первичной загрузке (scrollTop остается 0)
- используется прямое присвоение scrollTop как в legacy коде
- тройной RAF для надежности
- это должно исправить проблему с автозагрузкой истории