Files
KGV-Verein-Manager/assets/js/chat.js
2026-04-13 21:01:07 +02:00

263 lines
7.7 KiB
JavaScript

(function () {
function escapeHtml(value) {
return String(value || '')
.replace(/&/g, '&')
.replace(/</g, '&lt;')
.replace(/>/g, '&gt;')
.replace(/\"/g, '&quot;')
.replace(/'/g, '&#039;');
}
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, '<br>');
return '' +
'<article class="kgvvm-chat-message' + ownClass + '" data-id="' + escapeHtml(message.id) + '">' +
'<div class="kgvvm-chat-message__meta">' +
'<strong>' + escapeHtml(message.user) + '</strong>' + roleLabel + ' · ' + escapeHtml(message.time) +
'</div>' +
'<div class="kgvvm-chat-message__body">' + text + '</div>' +
'</article>';
}
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 = '<p class="kgvvm-chat-empty">' + escapeHtml(config.i18n.empty) + '</p>';
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));
});
})();