add file upload/download
This commit is contained in:
parent
22c3996527
commit
d7236780ce
194
static/app.js
194
static/app.js
@ -50,7 +50,7 @@ const CONFIG = {
|
||||
|
||||
const $ = (sel) => document.querySelector(sel);
|
||||
const $$ = (sel) => document.querySelectorAll(sel);
|
||||
|
||||
const $id = (sel) => document.getElementById(sel);
|
||||
|
||||
const EMOJIS = [
|
||||
// Smileys & Emotion
|
||||
@ -277,7 +277,7 @@ class Utils {
|
||||
}
|
||||
static processMediaEmbeds(text) {
|
||||
// Images (including GIFs)
|
||||
text = text.replace(/(https?:\/\/\S+\.(?:jpg|jpeg|png|gif|webp|svg|bmp|tiff|ico|avif|jfif)(?:\?\S*)?)/gi,
|
||||
text = text.replace(/(https?:\/\/\S+\.(?:jpg|svg|jpeg|png|gif|webp|svg|bmp|tiff|ico|avif|jfif)(?:\?\S*)?)/gi,
|
||||
'<img src="$1" alt="Image" class="embedded-image" loading="lazy">');
|
||||
// Videos
|
||||
text = text.replace(/(https?:\/\/\S+\.(?:mp4|webm|ogg|avi|mov|wmv|flv|mkv|m4v|3gp)(?:\?\S*)?)/gi,
|
||||
@ -388,12 +388,42 @@ class Utils {
|
||||
class UIManager {
|
||||
|
||||
static openFilePicker() {
|
||||
const fileInput = $('#file-input');
|
||||
const fileInput = $id('file-input');
|
||||
fileInput.click();
|
||||
fileInput.addEventListener('change', (e) => {
|
||||
fileInput.addEventListener('change', async (e) => {
|
||||
const filesToUpload = e.target.files;
|
||||
console.log(filesToUpload);
|
||||
})
|
||||
|
||||
if (!filesToUpload || filesToUpload.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
const formData = new FormData();
|
||||
const files = Array.from(filesToUpload);
|
||||
|
||||
files.forEach((file, index) => {
|
||||
formData.append(`file_${index}`, file);
|
||||
});
|
||||
|
||||
console.log(`Uploading ${files.length} files`);
|
||||
|
||||
formData.append('username', state.currentUsername)
|
||||
formData.append('client_id', state.currentId)
|
||||
|
||||
try {
|
||||
const response = await fetch('/files', {
|
||||
method: 'POST',
|
||||
body: formData
|
||||
});
|
||||
if (response.ok) {
|
||||
const data = await response.json();
|
||||
console.log('Upload successful:', data);
|
||||
} else {
|
||||
console.error('Upload failed:', response.statusText);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Upload error:', error);
|
||||
}
|
||||
}, { once: true });
|
||||
}
|
||||
|
||||
static updateConnectionStatus(connected) {
|
||||
@ -442,16 +472,16 @@ class UIManager {
|
||||
document.body.appendChild(notice);
|
||||
}
|
||||
static removeReconnectionNotice() {
|
||||
const notice = $('#reconnection-notice');
|
||||
const notice = $id('reconnection-notice');
|
||||
if (notice) notice.remove();
|
||||
}
|
||||
static updateMicrophoneStatus(granted) {
|
||||
const micStatus = $('#mic-status');
|
||||
const micStatus = $id('mic-status');
|
||||
if (!micStatus) return;
|
||||
if (granted) {
|
||||
micStatus.textContent = '✅ Microphone access granted';
|
||||
micStatus.className = 'mic-status granted';
|
||||
$('#mic-section').style.display = 'none';
|
||||
$id('mic-section').style.display = 'none';
|
||||
} else {
|
||||
micStatus.textContent = '❌ Microphone access denied. Please refresh and allow microphone access.';
|
||||
micStatus.innerHTML = micStatus.textContent.replace('. ', '.<br>');
|
||||
@ -459,32 +489,32 @@ class UIManager {
|
||||
}
|
||||
}
|
||||
static updateJoinButton(text, disabled = false) {
|
||||
const joinBtn = $('#join-chat-btn');
|
||||
const joinBtn = $id('join-chat-btn');
|
||||
joinBtn.textContent = text;
|
||||
joinBtn.disabled = disabled;
|
||||
}
|
||||
static showVoiceChatUI() {
|
||||
$('#join-section').style.display = 'none';
|
||||
$('#username-section').style.display = 'none';
|
||||
$('#voice-controls-sidebar').style.display = 'block';
|
||||
$('#chat-section').style.display = 'flex';
|
||||
$id('join-section').style.display = 'none';
|
||||
$id('username-section').style.display = 'none';
|
||||
$id('voice-controls-sidebar').style.display = 'block';
|
||||
$id('chat-section').style.display = 'flex';
|
||||
}
|
||||
static showUsernameUI() {
|
||||
$('#join-section').style.display = 'flex';
|
||||
$('#username-section').style.display = 'block';
|
||||
$('#voice-controls-sidebar').style.display = 'none';
|
||||
$('#chat-section').style.display = 'none';
|
||||
$('#users-list').innerHTML = '<div class="no-users"></div>';
|
||||
$id('join-section').style.display = 'flex';
|
||||
$id('username-section').style.display = 'block';
|
||||
$id('voice-controls-sidebar').style.display = 'none';
|
||||
$id('chat-section').style.display = 'none';
|
||||
$id('users-list').innerHTML = '<div class="no-users"></div>';
|
||||
}
|
||||
static handleClickOutsideEmojiPicker(event) {
|
||||
const emojiPicker = $('#emoji-picker');
|
||||
const emojiPicker = $id('emoji-picker');
|
||||
if (!emojiPicker.contains(event.target)) {
|
||||
UIManager.closeEmojiPicker();
|
||||
}
|
||||
}
|
||||
|
||||
static closeEmojiPicker() {
|
||||
const emojiPicker = $('#emoji-picker');
|
||||
const emojiPicker = $id('emoji-picker');
|
||||
if (emojiPicker) {
|
||||
emojiPicker.remove();
|
||||
document.removeEventListener('click', UIManager.handleClickOutsideEmojiPicker);
|
||||
@ -492,7 +522,7 @@ class UIManager {
|
||||
}
|
||||
|
||||
static openEmojiPicker() {
|
||||
if ($('#emoji-picker')) {
|
||||
if ($id('emoji-picker')) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -524,7 +554,7 @@ class UIManager {
|
||||
// Add emojis to the picker
|
||||
EMOJIS.forEach(emoji => {
|
||||
const emojiSpan = document.createElement('span');
|
||||
const sendBtn = $('#send-btn');
|
||||
const sendBtn = $id('send-btn');
|
||||
emojiSpan.className = 'emoji';
|
||||
emojiSpan.textContent = emoji;
|
||||
emojiSpan.style.cursor = 'pointer';
|
||||
@ -534,7 +564,7 @@ class UIManager {
|
||||
emojiSpan.style.fontSize = '1.5rem';
|
||||
emojiSpan.style.borderRadius = '0.5rem';
|
||||
emojiSpan.onclick = () => {
|
||||
const messageInput = $('#chat-input');
|
||||
const messageInput = $id('chat-input');
|
||||
messageInput.value += emoji;
|
||||
messageInput.focus();
|
||||
sendBtn.disabled = messageInput.value.trim() === '';
|
||||
@ -562,7 +592,7 @@ class UIManager {
|
||||
}
|
||||
|
||||
static toggleEmojiPicker() {
|
||||
if ($('#emoji-picker')) {
|
||||
if ($id('emoji-picker')) {
|
||||
UIManager.closeEmojiPicker();
|
||||
} else {
|
||||
UIManager.openEmojiPicker();
|
||||
@ -570,19 +600,19 @@ class UIManager {
|
||||
}
|
||||
|
||||
static async loadSettingsButton() {
|
||||
const settingsBtn = $('#voice-settings-btn');
|
||||
const settingsBtn = $id('voice-settings-btn');
|
||||
settingsBtn.innerHTML = await RenderSvg(SVGS.SETTINGS);
|
||||
settingsBtn.title = 'Settings';
|
||||
}
|
||||
|
||||
static async loadDisconnectButton() {
|
||||
const disconnectBtn = $('#leave-voice-btn');
|
||||
const disconnectBtn = $id('leave-voice-btn');
|
||||
disconnectBtn.innerHTML = await RenderSvg(SVGS.CONNECT);
|
||||
disconnectBtn.title = 'Disconnect';
|
||||
}
|
||||
|
||||
static async updateMuteButton() {
|
||||
const muteBtn = $('#toggle-mute-btn');
|
||||
const muteBtn = $id('toggle-mute-btn');
|
||||
if (state.isMuted) {
|
||||
muteBtn.innerHTML = await RenderSvg(SVGS.MUTED);
|
||||
muteBtn.title = 'Unmute (enable outgoing audio)';
|
||||
@ -597,7 +627,7 @@ class UIManager {
|
||||
}
|
||||
}
|
||||
static async updateDeafenButton() {
|
||||
const deafenBtn = $('#toggle-deafen-btn');
|
||||
const deafenBtn = $id('toggle-deafen-btn');
|
||||
if (state.isDeafened) {
|
||||
deafenBtn.innerHTML = await RenderSvg(SVGS.DEAFENED);
|
||||
deafenBtn.title = 'Undeafen (enable incoming audio)';
|
||||
@ -849,7 +879,7 @@ class AudioManager {
|
||||
}
|
||||
static addRemoteAudio(userId, stream) {
|
||||
console.log('🔊 Adding remote audio for user:', userId);
|
||||
const existingAudio = document.getElementById(`audio-${userId}`);
|
||||
const existingAudio = $id(`audio-${userId}`);
|
||||
if (existingAudio) {
|
||||
console.log('🔊 Removing existing audio element for:', userId);
|
||||
existingAudio.remove();
|
||||
@ -869,7 +899,7 @@ class AudioManager {
|
||||
audioElement.volume = (state.headphoneVolume / CONFIG.MEDIA.MAX_VOLUME) * (userVolume / CONFIG.MEDIA.MAX_VOLUME);
|
||||
audioElement.muted = state.isDeafened || state.mutedUsers.has(userId);
|
||||
AudioManager.setupAudioEventListeners(audioElement, userId);
|
||||
$('#audio-container').appendChild(audioElement);
|
||||
$id('audio-container').appendChild(audioElement);
|
||||
audioElement.play().then(() => {
|
||||
console.log('🔊 Successfully started playing audio for user:', userId);
|
||||
}).catch(error => {
|
||||
@ -982,8 +1012,8 @@ class WebSocketManager {
|
||||
if (state.isInVoiceChat) {
|
||||
console.log('🔄 Server connection lost, resetting client state...');
|
||||
PeerConnectionManager.cleanupAllConnections();
|
||||
$('#audio-container').innerHTML = '';
|
||||
$('#users-list').innerHTML = '<div class="no-users"></div>';
|
||||
$id('audio-container').innerHTML = '';
|
||||
$id('users-list').innerHTML = '<div class="no-users"></div>';
|
||||
const savedUsername = state.currentUsername;
|
||||
state.isInVoiceChat = false;
|
||||
if (!state.intentionalDisconnect) {
|
||||
@ -1240,7 +1270,7 @@ class PeerConnectionManager {
|
||||
state.peerConnections[userId].close();
|
||||
delete state.peerConnections[userId];
|
||||
}
|
||||
const audioElement = document.getElementById(`audio-${userId}`);
|
||||
const audioElement = $id(`audio-${userId}`);
|
||||
if (audioElement) {
|
||||
audioElement.remove();
|
||||
}
|
||||
@ -1336,7 +1366,7 @@ class UserManager {
|
||||
users = [];
|
||||
}
|
||||
|
||||
const usersList = $('#users-list');
|
||||
const usersList = $id('users-list');
|
||||
const currentUserIds = users.map(u => u.id);
|
||||
const previousUserIds = Object.keys(state.previousUsers);
|
||||
|
||||
@ -1348,8 +1378,8 @@ class UserManager {
|
||||
}
|
||||
|
||||
static setUsername() {
|
||||
const modalUsernameInput = $('#modal-username-input');
|
||||
const usernameInput = $('#username-input');
|
||||
const modalUsernameInput = $id('modal-username-input');
|
||||
const usernameInput = $id('username-input');
|
||||
|
||||
const username = modalUsernameInput.value.trim();
|
||||
|
||||
@ -1474,7 +1504,7 @@ class UserManager {
|
||||
|
||||
const clickHandler = isCurrentUser ? `onclick="ModalManager.openSelfModal()"` : `onclick="ModalManager.openUserModal('${user.id}', '${user.username}')"`;
|
||||
const muteButtonHtml = !isCurrentUser ? `
|
||||
<button class="mute-user-btn" onclick="event.stopPropagation(); VoiceControls.muteUser('${user.id}'); const muteBtn = $('#modal-mute-btn'); const isMuted = state.mutedUsers.has('${user.id}'); muteBtn.textContent = isMuted ? '🔇 User Muted' : '🔊 Mute User'; muteBtn.className = isMuted ? 'control-btn muted' : 'control-btn';" title="${isMuted ? 'Unmute user' : 'Mute user'}">
|
||||
<button class="mute-user-btn" onclick="event.stopPropagation(); VoiceControls.muteUser('${user.id}'); const muteBtn = $id('modal-mute-btn'); const isMuted = state.mutedUsers.has('${user.id}'); muteBtn.textContent = isMuted ? '🔇 User Muted' : '🔊 Mute User'; muteBtn.className = isMuted ? 'control-btn muted' : 'control-btn';" title="${isMuted ? 'Unmute user' : 'Mute user'}">
|
||||
${isMuted ? '🔇' : '🔊'}
|
||||
</button>
|
||||
` : '';
|
||||
@ -1543,7 +1573,7 @@ class UserManager {
|
||||
// ==================== CHAT MANAGEMENT ====================
|
||||
class ChatManager {
|
||||
static handleChatMessage(data) {
|
||||
const chatMessages = $('#chat-messages');
|
||||
const chatMessages = $id('chat-messages');
|
||||
const isOwnMessage = data.username === state.currentUsername;
|
||||
let message = '';
|
||||
let timestamp = Date.now();
|
||||
@ -1574,7 +1604,7 @@ class ChatManager {
|
||||
console.log('Added chat message from:', data.username, 'message:', message);
|
||||
}
|
||||
static addChatAlert(message, type, timeout) {
|
||||
const chatMessages = $('#chat-messages');
|
||||
const chatMessages = $id('chat-messages');
|
||||
if (!chatMessages) return;
|
||||
const alertEl = document.createElement('div');
|
||||
alertEl.className = `chat-alert chat-alert-${type}`;
|
||||
@ -1601,7 +1631,7 @@ class ChatManager {
|
||||
}
|
||||
|
||||
static deleteMessage(messageId) {
|
||||
const messageEl = $(messageId);
|
||||
const messageEl = $id(messageId);
|
||||
if (messageEl) {
|
||||
messageEl.classList.add('fading');
|
||||
setTimeout(() => {
|
||||
@ -1655,7 +1685,7 @@ class VoiceControls {
|
||||
} else {
|
||||
state.mutedUsers.add(userId);
|
||||
}
|
||||
const audioElement = document.getElementById(`audio-${userId}`);
|
||||
const audioElement = $id(`audio-${userId}`);
|
||||
if (audioElement) {
|
||||
audioElement.muted = state.mutedUsers.has(userId);
|
||||
}
|
||||
@ -1664,8 +1694,8 @@ class VoiceControls {
|
||||
state.save();
|
||||
}
|
||||
static updateMicVolume() {
|
||||
const slider = $('#mic-volume-slider');
|
||||
const percentage = $('#mic-volume-percentage');
|
||||
const slider = $id('mic-volume-slider');
|
||||
const percentage = $id('mic-volume-percentage');
|
||||
state.micVolume = parseInt(slider.value);
|
||||
percentage.textContent = `${state.micVolume}%`;
|
||||
|
||||
@ -1673,8 +1703,8 @@ class VoiceControls {
|
||||
AudioManager.updateMicrophoneGain();
|
||||
}
|
||||
static updateHeadphoneVolume() {
|
||||
const slider = $('#headphone-volume-slider');
|
||||
const percentage = $('#headphone-volume-percentage');
|
||||
const slider = $id('headphone-volume-slider');
|
||||
const percentage = $id('headphone-volume-percentage');
|
||||
state.headphoneVolume = parseInt(slider.value);
|
||||
percentage.textContent = `${state.headphoneVolume}%`;
|
||||
const audioElements = $$('#audio-container audio');
|
||||
@ -1687,10 +1717,10 @@ class VoiceControls {
|
||||
static resetAllVolumes() {
|
||||
state.micVolume = 100;
|
||||
state.headphoneVolume = 100;
|
||||
const micSlider = $('#mic-volume-slider');
|
||||
const headphoneSlider = $('#headphone-volume-slider');
|
||||
const micPercentage = $('#mic-volume-percentage');
|
||||
const headphonePercentage = $('#headphone-volume-percentage');
|
||||
const micSlider = $id('mic-volume-slider');
|
||||
const headphoneSlider = $id('headphone-volume-slider');
|
||||
const micPercentage = $id('mic-volume-percentage');
|
||||
const headphonePercentage = $id('headphone-volume-percentage');
|
||||
if (micSlider) {
|
||||
micSlider.value = 100;
|
||||
micPercentage.textContent = '100%';
|
||||
@ -1708,10 +1738,10 @@ class VoiceControls {
|
||||
// ==================== MODAL MANAGEMENT ====================
|
||||
class ModalManager {
|
||||
static openSelfModal() {
|
||||
const modal = $('#user-control-modal');
|
||||
const modalUsername = $('#modal-username');
|
||||
const modal = $id('user-control-modal');
|
||||
const modalUsername = $id('modal-username');
|
||||
modalUsername.textContent = 'Settings';
|
||||
const percentage = $('#headphone-volume-percentage');
|
||||
const percentage = $id('headphone-volume-percentage');
|
||||
if (percentage) {
|
||||
percentage.textContent = `${state.headphoneVolume}%`;
|
||||
}
|
||||
@ -1751,7 +1781,7 @@ class ModalManager {
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
const modalUsernameInput = $('#modal-username-input');
|
||||
const modalUsernameInput = $id('modal-username-input');
|
||||
modalUsernameInput.addEventListener('keydown', (event) => {
|
||||
if (event.key === 'Enter') {
|
||||
event.preventDefault();
|
||||
@ -1762,15 +1792,15 @@ class ModalManager {
|
||||
console.log('Opened self audio settings modal');
|
||||
}
|
||||
// static closeSelfModal() {
|
||||
// const modal = $('#user-control-modal');
|
||||
// const modal = $id('user-control-modal');
|
||||
// modal.style.display = 'none';
|
||||
// state.currentModalUserId = null;
|
||||
// console.log('Closed self audio settings modal');
|
||||
// }
|
||||
static openUserModal(userId, username) {
|
||||
state.currentModalUserId = userId;
|
||||
const modal = $('#user-control-modal');
|
||||
const modalUsername = $('#modal-username');
|
||||
const modal = $id('user-control-modal');
|
||||
const modalUsername = $id('modal-username');
|
||||
modalUsername.textContent = `${username} `;
|
||||
const modalBody = modal.querySelector('.modal-body');
|
||||
modalBody.innerHTML = `
|
||||
@ -1794,11 +1824,11 @@ class ModalManager {
|
||||
</div>
|
||||
`;
|
||||
const currentVolume = state.userVolumes.get(userId) || 100;
|
||||
const volumeSlider = $('#user-volume-slider');
|
||||
const volumePercentage = $('#volume-percentage');
|
||||
const volumeSlider = $id('user-volume-slider');
|
||||
const volumePercentage = $id('volume-percentage');
|
||||
volumeSlider.value = currentVolume;
|
||||
volumePercentage.textContent = `${currentVolume}% `;
|
||||
const muteBtn = $('#modal-mute-btn');
|
||||
const muteBtn = $id('modal-mute-btn');
|
||||
const isMuted = state.mutedUsers.has(userId);
|
||||
if (muteBtn) {
|
||||
muteBtn.textContent = isMuted ? '🔇 User Muted' : '🔊 Mute User';
|
||||
@ -1808,20 +1838,20 @@ class ModalManager {
|
||||
console.log(`Opened modal for user ${username}(${userId})`);
|
||||
}
|
||||
static closeUserModal() {
|
||||
const modal = $('#user-control-modal');
|
||||
const modal = $id('user-control-modal');
|
||||
modal.style.display = 'none';
|
||||
state.currentModalUserId = null;
|
||||
console.log('Closed user modal');
|
||||
}
|
||||
static updateUserVolume() {
|
||||
if (!state.currentModalUserId) return;
|
||||
const slider = $('#user-volume-slider');
|
||||
const volumePercentage = $('#volume-percentage');
|
||||
const slider = $id('user-volume-slider');
|
||||
const volumePercentage = $id('volume-percentage');
|
||||
const volume = parseInt(slider.value);
|
||||
volumePercentage.textContent = `${volume}% `;
|
||||
state.userVolumes.set(state.currentModalUserId, volume);
|
||||
|
||||
const audioElement = document.getElementById(`audio - ${state.currentModalUserId} `);
|
||||
const audioElement = $id(`audio - ${state.currentModalUserId} `);
|
||||
if (audioElement) {
|
||||
audioElement.volume = volume / 100;
|
||||
}
|
||||
@ -1836,15 +1866,15 @@ class ModalManager {
|
||||
static toggleUserMuteFromModal() {
|
||||
if (!state.currentModalUserId) return;
|
||||
VoiceControls.muteUser(state.currentModalUserId);
|
||||
const muteBtn = $('#modal-mute-btn');
|
||||
const muteBtn = $id('modal-mute-btn');
|
||||
const isMuted = state.mutedUsers.has(state.currentModalUserId);
|
||||
muteBtn.textContent = isMuted ? '🔇 User Muted' : '🔊 Mute User';
|
||||
muteBtn.className = isMuted ? 'control-btn muted' : 'control-btn';
|
||||
}
|
||||
static resetUserVolume() {
|
||||
if (!state.currentModalUserId) return;
|
||||
const volumeSlider = $('#user-volume-slider');
|
||||
const volumePercentage = $('#volume-percentage');
|
||||
const volumeSlider = $id('user-volume-slider');
|
||||
const volumePercentage = $id('volume-percentage');
|
||||
volumeSlider.value = 100;
|
||||
volumePercentage.textContent = '100%';
|
||||
ModalManager.updateUserVolume();
|
||||
@ -1854,7 +1884,7 @@ class ModalManager {
|
||||
// ==================== VOICE CHAT MANAGER ====================
|
||||
class VoiceChatManager {
|
||||
static async joinVoiceChat() {
|
||||
const usernameInput = $('#username-input');
|
||||
const usernameInput = $id('username-input');
|
||||
const username = usernameInput.value.trim();
|
||||
state.intentionalDisconnect = false;
|
||||
if (!username) {
|
||||
@ -1899,7 +1929,7 @@ class VoiceChatManager {
|
||||
PeerConnectionManager.stopPeerHealthCheck();
|
||||
PeerConnectionManager.cleanupAllConnections();
|
||||
UserManager.onVoiceChatLeave();
|
||||
$('#audio-container').innerHTML = '';
|
||||
$id('audio-container').innerHTML = '';
|
||||
state.reset();
|
||||
ModalManager.closeUserModal();
|
||||
state.intentionalDisconnect = true;
|
||||
@ -1927,7 +1957,7 @@ class VoiceChatManager {
|
||||
state.isInVoiceChat = false;
|
||||
UIManager.updateJoinButton('Join Voice Chat', false);
|
||||
UIManager.showUsernameUI();
|
||||
const usernameInput = $('#username-input');
|
||||
const usernameInput = $id('username-input');
|
||||
usernameInput.focus();
|
||||
usernameInput.select();
|
||||
console.log('Username rejected, reset to initial state');
|
||||
@ -1936,21 +1966,21 @@ class VoiceChatManager {
|
||||
// ==================== EVENT HANDLERS ====================
|
||||
class EventHandlers {
|
||||
static setupEventListeners() {
|
||||
const usernameInput = $('#username-input');
|
||||
const joinChatBtn = $('#join-chat-btn');
|
||||
const chatInput = $('#chat-input');
|
||||
const sendBtn = $('#send-btn');
|
||||
const usernameInput = $id('username-input');
|
||||
const joinChatBtn = $id('join-chat-btn');
|
||||
const chatInput = $id('chat-input');
|
||||
const sendBtn = $id('send-btn');
|
||||
const chatMessages = $('.chat-messages');
|
||||
// const fileBtn = $('#file-btn');
|
||||
// const fileBtn = $id('file-btn');
|
||||
|
||||
|
||||
chatMessages.addEventListener('scroll', function() {
|
||||
const atBottom = UIManager.isChatScrolledToBottom();
|
||||
if (!atBottom) {
|
||||
$('#scroll-btn').disabled = false;
|
||||
$id('scroll-btn').disabled = false;
|
||||
}
|
||||
if (atBottom) {
|
||||
$('#scroll-btn').disabled = true;
|
||||
$id('scroll-btn').disabled = true;
|
||||
}
|
||||
});
|
||||
|
||||
@ -1971,7 +2001,7 @@ class EventHandlers {
|
||||
const textarea = e.target;
|
||||
textarea.style.height = 'auto';
|
||||
textarea.style.height = Math.min(textarea.scrollHeight, window.innerHeight * 0.5) + 'px';
|
||||
$('#send-btn').disabled = textarea.value.trim().length === 0;
|
||||
$id('send-btn').disabled = textarea.value.trim().length === 0;
|
||||
});
|
||||
|
||||
chatInput.addEventListener('keydown', function(e) {
|
||||
@ -1985,7 +2015,7 @@ class EventHandlers {
|
||||
}
|
||||
static setupGlobalEventListeners() {
|
||||
document.addEventListener('click', function(event) {
|
||||
const modal = $('#user-control-modal');
|
||||
const modal = $id('user-control-modal');
|
||||
if (event.target === modal) {
|
||||
ModalManager.closeUserModal();
|
||||
}
|
||||
@ -2018,7 +2048,7 @@ class EventHandlers {
|
||||
}
|
||||
|
||||
static sendChatMessage() {
|
||||
const chatInput = $('#chat-input');
|
||||
const chatInput = $id('chat-input');
|
||||
const message = chatInput.value.trim();
|
||||
if (!message || !state.ws || state.ws.readyState !== WebSocket.OPEN) {
|
||||
return;
|
||||
@ -2026,7 +2056,7 @@ class EventHandlers {
|
||||
WebSocketManager.sendChatMessage(message);
|
||||
chatInput.value = '';
|
||||
chatInput.style.height = 'auto';
|
||||
$('#send-btn').disabled = true;
|
||||
$id('send-btn').disabled = true;
|
||||
}
|
||||
}
|
||||
// ==================== DEBUG UTILITIES ====================
|
||||
@ -2144,7 +2174,7 @@ for (let { event, target } of [
|
||||
target.addEventListener(event, async function() {
|
||||
state.load();
|
||||
if (state.currentUsername) {
|
||||
$('#username-input').value = state.currentUsername;
|
||||
$id('username-input').value = state.currentUsername;
|
||||
}
|
||||
EventHandlers.setupEventListeners();
|
||||
await AudioManager.requestMicrophonePermission();
|
||||
|
@ -106,7 +106,7 @@
|
||||
<label for="chat-input"></label>
|
||||
<div class="chat-input-buttons">
|
||||
<button id="scroll-btn" onclick="scrollChatToBottom()" disabled>⮟</button>
|
||||
<input type="file" id="file-input" style="display: none;"/>
|
||||
<input type="file" id="file-input" multiple style="display: none;"/>
|
||||
<button id="file-btn" onclick='openFilePicker()'>📤</button>
|
||||
<button id="emoji-btn" onclick="toggleEmojiPicker()">😀</button>
|
||||
<button id="send-btn" onclick="sendChatMessage()" disabled>Send</button>
|
||||
|
Loading…
x
Reference in New Issue
Block a user