Update src/templates/chat.html

This commit is contained in:
2025-08-24 19:02:24 +00:00
parent 6d5ccca5ed
commit b9915319b6

View File

@@ -148,15 +148,31 @@
if (diff > 150) { // Keyboard is likely open if (diff > 150) { // Keyboard is likely open
if (messagesWrapper) { if (messagesWrapper) {
messagesWrapper.style.paddingBottom = '100px'; messagesWrapper.style.paddingBottom = '120px'; // More padding for mobile keyboard
// Scroll to bottom when keyboard opens // Auto-scroll when keyboard opens, with multiple attempts for reliability
userScrolled = false; // Reset scroll state when keyboard opens
setTimeout(() => { setTimeout(() => {
messagesWrapper.scrollTop = messagesWrapper.scrollHeight; scrollToBottom(false);
}, 100); }, 200);
// iOS often needs multiple scroll attempts
if (isIOS) {
setTimeout(() => {
messagesWrapper.scrollTop = messagesWrapper.scrollHeight;
}, 400);
setTimeout(() => {
messagesWrapper.scrollTop = messagesWrapper.scrollHeight;
}, 600);
}
} }
} else { } else {
if (messagesWrapper) { if (messagesWrapper) {
messagesWrapper.style.paddingBottom = '80px'; messagesWrapper.style.paddingBottom = '80px';
// Scroll to bottom when keyboard closes too
setTimeout(() => {
if (!userScrolled) {
scrollToBottom(false);
}
}, 200);
} }
} }
} }
@@ -168,31 +184,66 @@
window.addEventListener('resize', adjustForKeyboard); window.addEventListener('resize', adjustForKeyboard);
} }
// Focus handling for textarea // Mobile-optimized focus handling for textarea
document.addEventListener('DOMContentLoaded', function() { document.addEventListener('DOMContentLoaded', function() {
const messageInput = document.getElementById('messageInput'); const messageInput = document.getElementById('messageInput');
if (messageInput) { if (messageInput) {
messageInput.addEventListener('focus', function() { messageInput.addEventListener('focus', function() {
setTimeout(adjustForKeyboard, 300); // Reset scroll state when focusing input
userScrolled = false;
// Multiple timeout attempts for different mobile browsers
setTimeout(adjustForKeyboard, 200);
setTimeout(adjustForKeyboard, 400);
if (isMobile) {
setTimeout(adjustForKeyboard, 600);
setTimeout(() => {
const messagesWrapper = document.getElementById('messagesWrapper');
if (messagesWrapper) {
messagesWrapper.scrollTop = messagesWrapper.scrollHeight;
}
}, 800);
}
}); });
messageInput.addEventListener('blur', function() { messageInput.addEventListener('blur', function() {
setTimeout(adjustForKeyboard, 300); setTimeout(adjustForKeyboard, 200);
setTimeout(adjustForKeyboard, 400);
});
// Handle input events for better mobile experience
messageInput.addEventListener('input', function() {
if (isMobile && !userScrolled) {
setTimeout(() => {
scrollToBottom(false);
}, 100);
}
}); });
} }
}); });
// Auto-scroll functionality for new messages // Mobile-optimized auto-scroll functionality
let isMobile = /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent) || window.innerWidth <= 768;
let isIOS = /iPad|iPhone|iPod/.test(navigator.userAgent);
function scrollToBottom(smooth = true) { function scrollToBottom(smooth = true) {
const messagesWrapper = document.getElementById('messagesWrapper'); const messagesWrapper = document.getElementById('messagesWrapper');
if (messagesWrapper) { if (messagesWrapper) {
if (smooth) { // On mobile, especially iOS, direct scrollTop assignment is more reliable
messagesWrapper.scrollTo({ if (isMobile) {
top: messagesWrapper.scrollHeight,
behavior: 'smooth'
});
} else {
messagesWrapper.scrollTop = messagesWrapper.scrollHeight; messagesWrapper.scrollTop = messagesWrapper.scrollHeight;
// Double-check scroll position after a short delay for mobile
setTimeout(() => {
messagesWrapper.scrollTop = messagesWrapper.scrollHeight;
}, 100);
} else {
if (smooth) {
messagesWrapper.scrollTo({
top: messagesWrapper.scrollHeight,
behavior: 'smooth'
});
} else {
messagesWrapper.scrollTop = messagesWrapper.scrollHeight;
}
} }
} }
} }
@@ -202,39 +253,80 @@
const messagesWrapper = document.getElementById('messagesWrapper'); const messagesWrapper = document.getElementById('messagesWrapper');
if (!messagesWrapper) return true; if (!messagesWrapper) return true;
const threshold = 100; // pixels from bottom // Larger threshold for mobile to account for touch scrolling momentum
const threshold = isMobile ? 150 : 100;
return messagesWrapper.scrollHeight - messagesWrapper.scrollTop - messagesWrapper.clientHeight < threshold; return messagesWrapper.scrollHeight - messagesWrapper.scrollTop - messagesWrapper.clientHeight < threshold;
} }
// Store the last scroll position to detect if user manually scrolled // Mobile scroll state management
let lastScrollTop = 0; let lastScrollTop = 0;
let userScrolled = false; let userScrolled = false;
let scrollTimeout;
let touchStartY = 0;
let isScrolling = false;
// Detect user scroll // Detect user scroll with mobile optimizations
document.addEventListener('DOMContentLoaded', function() { document.addEventListener('DOMContentLoaded', function() {
const messagesWrapper = document.getElementById('messagesWrapper'); const messagesWrapper = document.getElementById('messagesWrapper');
if (messagesWrapper) { if (messagesWrapper) {
// Handle touch events for better mobile detection
messagesWrapper.addEventListener('touchstart', function(e) {
touchStartY = e.touches[0].clientY;
isScrolling = false;
clearTimeout(scrollTimeout);
}, { passive: true });
messagesWrapper.addEventListener('touchmove', function(e) {
if (!isScrolling) {
isScrolling = true;
const touchY = e.touches[0].clientY;
const deltaY = touchStartY - touchY;
// If user is swiping up (scrolling up), mark as user scrolled
if (deltaY < -10 && !isNearBottom()) {
userScrolled = true;
}
}
}, { passive: true });
messagesWrapper.addEventListener('touchend', function() {
// Check scroll position after touch ends with delay for momentum scrolling
setTimeout(() => {
if (isNearBottom()) {
userScrolled = false;
}
isScrolling = false;
}, 300);
}, { passive: true });
// Regular scroll event with debouncing for mobile
messagesWrapper.addEventListener('scroll', function() { messagesWrapper.addEventListener('scroll', function() {
const currentScrollTop = messagesWrapper.scrollTop; clearTimeout(scrollTimeout);
const maxScroll = messagesWrapper.scrollHeight - messagesWrapper.clientHeight; scrollTimeout = setTimeout(() => {
const currentScrollTop = messagesWrapper.scrollTop;
// If user scrolled up manually, don't auto-scroll for new messages const maxScroll = messagesWrapper.scrollHeight - messagesWrapper.clientHeight;
if (currentScrollTop < lastScrollTop && currentScrollTop < maxScroll - 50) {
userScrolled = true; // More lenient detection for mobile
} const upScrollThreshold = isMobile ? 30 : 50;
// If user scrolled to near bottom, resume auto-scrolling // If user scrolled up manually, don't auto-scroll for new messages
if (isNearBottom()) { if (currentScrollTop < lastScrollTop && currentScrollTop < maxScroll - upScrollThreshold) {
userScrolled = false; userScrolled = true;
} }
lastScrollTop = currentScrollTop; // If user scrolled to near bottom, resume auto-scrolling
}); if (isNearBottom()) {
userScrolled = false;
}
lastScrollTop = currentScrollTop;
}, isMobile ? 150 : 50); // Longer debounce for mobile
}, { passive: true });
} }
}); });
// Override the message adding function to include auto-scroll // Mobile-optimized message adding function
// You'll need to call this function whenever a new message is added
function addMessageWithAutoScroll(messageElement) { function addMessageWithAutoScroll(messageElement) {
const messagesContainer = document.getElementById('messagesContainer'); const messagesContainer = document.getElementById('messagesContainer');
if (messagesContainer && messageElement) { if (messagesContainer && messageElement) {
@@ -242,23 +334,34 @@
// Only auto-scroll if user hasn't manually scrolled up // Only auto-scroll if user hasn't manually scrolled up
if (!userScrolled) { if (!userScrolled) {
// Small delay to ensure DOM is updated // Longer delay for mobile to ensure proper rendering
const delay = isMobile ? 200 : 50;
setTimeout(() => { setTimeout(() => {
scrollToBottom(true); scrollToBottom(false); // Always instant scroll on mobile
}, 50); }, delay);
} }
} }
} }
// Function to force scroll to bottom (useful for when joining a room) // Force scroll with mobile optimizations
function forceScrollToBottom() { function forceScrollToBottom() {
userScrolled = false; userScrolled = false;
const delay = isMobile ? 300 : 100;
setTimeout(() => { setTimeout(() => {
scrollToBottom(false); scrollToBottom(false);
}, 100); // iOS double-check
if (isIOS) {
setTimeout(() => {
const messagesWrapper = document.getElementById('messagesWrapper');
if (messagesWrapper) {
messagesWrapper.scrollTop = messagesWrapper.scrollHeight;
}
}, 100);
}
}, delay);
} }
// Observer to watch for new messages being added to the DOM // Mobile-optimized mutation observer
document.addEventListener('DOMContentLoaded', function() { document.addEventListener('DOMContentLoaded', function() {
const messagesContainer = document.getElementById('messagesContainer'); const messagesContainer = document.getElementById('messagesContainer');
if (messagesContainer) { if (messagesContainer) {
@@ -273,9 +376,10 @@
); );
if (hasNewMessage && !userScrolled) { if (hasNewMessage && !userScrolled) {
const delay = isMobile ? 250 : 50;
setTimeout(() => { setTimeout(() => {
scrollToBottom(true); scrollToBottom(false); // Instant scroll for reliability
}, 50); }, delay);
} }
} }
}); });