Files
server-configs/httpserver/data/chat.js
2026-03-22 00:54:28 -07:00

168 lines
5.4 KiB
JavaScript

/* chat.js */
document.addEventListener('DOMContentLoaded', () => {
const CHAT_WIDGET_HTML = `
<div id="chat-widget" class="collapsed">
<div id="chat-header">
<span><span id="chat-status-dot" class="status-offline">●</span> MESSAGE BOARD</span>
<button id="chat-toggle" aria-label="Toggle message board">▲</button>
</div>
<div id="chat-body" style="display: none;">
<div id="chat-messages"></div>
<div id="chat-input-area">
<div class="chat-settings">
<label for="chat-nick-input" style="font-size:0.8rem; color:#ccc;">Name:</label>
<input type="text" id="chat-nick-input" placeholder="visitor" maxlength="20">
</div>
<div id="chat-controls">
<input type="text" id="chat-input" placeholder="Post a message..." maxlength="200">
<button id="chat-send">Post</button>
</div>
<div id="chat-status">Connecting…</div>
</div>
</div>
</div>
`;
document.body.insertAdjacentHTML('beforeend', CHAT_WIDGET_HTML);
const widget = document.getElementById('chat-widget');
const header = document.getElementById('chat-header');
const toggleBtn = document.getElementById('chat-toggle');
const body = document.getElementById('chat-body');
const messagesContainer = document.getElementById('chat-messages');
const input = document.getElementById('chat-input');
const sendBtn = document.getElementById('chat-send');
const nickInput = document.getElementById('chat-nick-input');
const statusEl = document.getElementById('chat-status');
const statusDot = document.getElementById('chat-status-dot');
let ws = null;
let isCollapsed = true;
// Initialize nickname base (server appends IP suffix)
let savedNick = localStorage.getItem('gw_chat_nick');
if (!savedNick) {
savedNick = 'visitor';
localStorage.setItem('gw_chat_nick', savedNick);
}
nickInput.value = savedNick;
nickInput.addEventListener('change', () => {
let val = nickInput.value.trim();
if (!val) val = 'visitor';
nickInput.value = val;
localStorage.setItem('gw_chat_nick', val);
});
// Toggle chat
function toggleChat() {
isCollapsed = !isCollapsed;
if (isCollapsed) {
widget.classList.add('collapsed');
body.style.display = 'none';
toggleBtn.textContent = '▲';
} else {
widget.classList.remove('collapsed');
body.style.display = 'flex';
toggleBtn.textContent = '▼';
input.focus();
scrollToBottom();
}
}
header.addEventListener('click', (e) => {
if (e.target !== nickInput && e.target !== input) {
toggleChat();
}
});
function formatTime(ts) {
const d = new Date(ts);
return d.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit', second: '2-digit', hour12: false });
}
function appendMessage(msg) {
const div = document.createElement('div');
div.className = 'chat-message';
const tsSpan = document.createElement('span');
tsSpan.className = 'chat-ts';
tsSpan.textContent = '[' + formatTime(msg.ts) + ']';
const nickSpan = document.createElement('span');
nickSpan.className = 'chat-nick';
nickSpan.textContent = msg.nick + ':';
const textSpan = document.createElement('span');
textSpan.className = 'chat-text';
textSpan.textContent = msg.text;
div.appendChild(tsSpan);
div.appendChild(nickSpan);
div.appendChild(textSpan);
messagesContainer.appendChild(div);
scrollToBottom();
}
function scrollToBottom() {
messagesContainer.scrollTop = messagesContainer.scrollHeight;
}
function connect() {
const protocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:';
const host = window.location.host; // includes port if non-standard
ws = new WebSocket(`${protocol}//${host}/chat`);
ws.onopen = () => {
statusEl.textContent = 'Connected';
statusDot.className = 'status-online';
};
ws.onmessage = (e) => {
try {
const data = JSON.parse(e.data);
if (data.type === 'history') {
messagesContainer.innerHTML = '';
data.messages.forEach(appendMessage);
} else {
appendMessage(data);
}
} catch (err) {
console.error('Chat MS error:', err);
}
};
ws.onclose = () => {
statusEl.textContent = 'Disconnected. Reconnecting...';
statusDot.className = 'status-offline';
setTimeout(connect, 3000);
};
ws.onerror = () => {
statusEl.textContent = 'Connection Error';
ws.close();
};
}
function sendMessage() {
const text = input.value.trim();
if (!text || ws.readyState !== WebSocket.OPEN) return;
const nick = nickInput.value.trim() || 'visitor';
const msg = { nick, text };
ws.send(JSON.stringify(msg));
input.value = '';
input.focus();
}
sendBtn.addEventListener('click', sendMessage);
input.addEventListener('keypress', (e) => {
if (e.key === 'Enter') sendMessage();
});
// Init connection
connect();
});