(function () { function escapeHtml(value) { return String(value || '') .replace(/&/g, '&') .replace(//g, '>') .replace(/\"/g, '"') .replace(/'/g, '''); } function renderMessage(message, currentUserId) { var ownClass = Number(message.user_id) === Number(currentUserId) ? ' kgvvm-chat-message--own' : ''; var roleLabel = message.role ? ' · ' + escapeHtml(message.role) : ''; var text = escapeHtml(message.message).replace(/\n/g, '
'); return '' + '
' + '
' + '' + escapeHtml(message.user) + '' + roleLabel + ' · ' + escapeHtml(message.time) + '
' + '
' + text + '
' + '
'; } document.addEventListener('DOMContentLoaded', function () { var app = document.querySelector('.kgvvm-chat-app'); if (!app || typeof window.kgvvmChatConfig === 'undefined') { return; } var config = window.kgvvmChatConfig; var messagesEl = app.querySelector('[data-chat-messages]'); var form = app.querySelector('[data-chat-form]'); var input = app.querySelector('[data-chat-input]'); var status = app.querySelector('[data-chat-status]'); var roomButtons = app.querySelectorAll('[data-chat-room]'); var roomTitle = app.querySelector('[data-chat-room-title]'); var roomDescription = app.querySelector('[data-chat-room-description]'); var currentRoom = app.getAttribute('data-room') || 'general'; var initialRoom = currentRoom; var currentUserId = Number(app.getAttribute('data-current-user-id') || '0'); var sendLocked = false; var storageKey = 'kgvvmActiveChatRoom'; function getAvailableRooms() { return Array.prototype.map.call(roomButtons, function (button) { return button.getAttribute('data-chat-room') || ''; }).filter(Boolean); } function syncRoomState() { try { window.localStorage.setItem(storageKey, currentRoom); } catch (error) { // ignore storage errors } if (window.history && typeof window.history.replaceState === 'function') { var url = new window.URL(window.location.href); url.searchParams.set('room', currentRoom); window.history.replaceState({}, '', url.toString()); } } function restoreRoomState() { var availableRooms = getAvailableRooms(); var url = new window.URL(window.location.href); var requestedRoom = url.searchParams.get('room') || ''; var storedRoom = ''; try { storedRoom = window.localStorage.getItem(storageKey) || ''; } catch (error) { storedRoom = ''; } var preferredRoom = requestedRoom || storedRoom; if (preferredRoom && availableRooms.indexOf(preferredRoom) !== -1) { currentRoom = preferredRoom; app.setAttribute('data-room', currentRoom); } } function setStatus(text, isError) { if (!status) { return; } status.textContent = text || ''; status.classList.toggle('is-error', !!isError); } function scrollToBottom() { if (messagesEl) { messagesEl.scrollTop = messagesEl.scrollHeight; } } function updateRoomButtons() { roomButtons.forEach(function (button) { button.classList.toggle('is-active', button.getAttribute('data-chat-room') === currentRoom); }); } function updateRoomMeta() { roomButtons.forEach(function (button) { if (button.getAttribute('data-chat-room') !== currentRoom) { return; } if (roomTitle) { roomTitle.textContent = button.getAttribute('data-chat-label') || ''; } if (roomDescription) { roomDescription.textContent = button.getAttribute('data-chat-description') || ''; } }); } function renderMessages(messages, replaceAll) { if (!messagesEl) { return; } if (replaceAll) { messagesEl.innerHTML = ''; } if (!Array.isArray(messages) || !messages.length) { if (replaceAll) { messagesEl.innerHTML = '

' + escapeHtml(config.i18n.empty) + '

'; messagesEl.dataset.lastId = '0'; } return; } if (messagesEl.querySelector('.kgvvm-chat-empty')) { messagesEl.innerHTML = ''; } messages.forEach(function (message) { messagesEl.insertAdjacentHTML('beforeend', renderMessage(message, currentUserId)); messagesEl.dataset.lastId = String(message.id || messagesEl.dataset.lastId || '0'); }); scrollToBottom(); } function fetchMessages(replaceAll) { var data = new window.FormData(); data.append('action', 'kgvvm_fetch_chat_messages'); data.append('nonce', config.nonce); data.append('room', currentRoom); if (!replaceAll && messagesEl && messagesEl.dataset.lastId) { data.append('after_id', messagesEl.dataset.lastId); } return window.fetch(config.ajaxUrl, { method: 'POST', credentials: 'same-origin', body: data }) .then(function (response) { return response.json(); }) .then(function (payload) { if (!payload || !payload.success) { return; } renderMessages(payload.data.messages || [], replaceAll); }) .catch(function () { setStatus(config.i18n.fetchError, true); }); } roomButtons.forEach(function (button) { button.addEventListener('click', function () { currentRoom = button.getAttribute('data-chat-room') || 'general'; app.setAttribute('data-room', currentRoom); syncRoomState(); updateRoomMeta(); if (messagesEl) { messagesEl.dataset.lastId = '0'; } updateRoomButtons(); setStatus(config.i18n.loading, false); fetchMessages(true).then(function () { setStatus('', false); }); }); }); if (form && input) { form.addEventListener('submit', function (event) { event.preventDefault(); if (sendLocked) { return; } var message = String(input.value || '').trim(); if (!message) { return; } sendLocked = true; setStatus(config.i18n.sending, false); var data = new window.FormData(); data.append('action', 'kgvvm_send_chat_message'); data.append('nonce', config.nonce); data.append('room', currentRoom); data.append('message', message); window.fetch(config.ajaxUrl, { method: 'POST', credentials: 'same-origin', body: data }) .then(function (response) { return response.json(); }) .then(function (payload) { sendLocked = false; if (!payload || !payload.success) { setStatus(config.i18n.sendError, true); return; } renderMessages(payload.data.messages || [], false); input.value = ''; input.focus(); setStatus('', false); }) .catch(function () { sendLocked = false; setStatus(config.i18n.sendError, true); }); }); } restoreRoomState(); updateRoomButtons(); updateRoomMeta(); syncRoomState(); if (currentRoom !== initialRoom) { fetchMessages(true); } scrollToBottom(); window.setInterval(function () { fetchMessages(false); }, Number(config.refreshInterval || 7000)); }); })();