263 lines
7.7 KiB
JavaScript
263 lines
7.7 KiB
JavaScript
(function () {
|
|
function escapeHtml(value) {
|
|
return String(value || '')
|
|
.replace(/&/g, '&')
|
|
.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, '<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));
|
|
});
|
|
})();
|