|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class SarcasticChat {
|
|
|
constructor() {
|
|
|
this.socket = null;
|
|
|
this.username = null;
|
|
|
this.messageCount = 0;
|
|
|
this.botResponseCount = 0;
|
|
|
this.isTyping = false;
|
|
|
this.typingTimer = null;
|
|
|
this.lastMessageTime = 0;
|
|
|
this.init();
|
|
|
}
|
|
|
|
|
|
init() {
|
|
|
this.initializeElements();
|
|
|
this.setupEventListeners();
|
|
|
}
|
|
|
|
|
|
initializeElements() {
|
|
|
this.chatMessages = document.getElementById('chatMessages');
|
|
|
this.messageInput = document.getElementById('messageInput');
|
|
|
this.messageForm = document.getElementById('messageForm');
|
|
|
this.typingIndicator = document.getElementById('typingIndicator');
|
|
|
this.userCountElement = document.getElementById('userCount');
|
|
|
this.messageCountElement = document.getElementById('messageCount');
|
|
|
this.botResponseCountElement = document.getElementById('botResponseCount');
|
|
|
}
|
|
|
|
|
|
setupEventListeners() {
|
|
|
|
|
|
this.messageForm.addEventListener('submit', (e) => {
|
|
|
e.preventDefault();
|
|
|
this.sendMessage();
|
|
|
});
|
|
|
|
|
|
|
|
|
this.messageInput.addEventListener('input', () => {
|
|
|
this.handleTyping();
|
|
|
});
|
|
|
|
|
|
|
|
|
this.messageInput.addEventListener('keypress', (e) => {
|
|
|
if (e.key === 'Enter' && !e.shiftKey) {
|
|
|
e.preventDefault();
|
|
|
this.sendMessage();
|
|
|
}
|
|
|
});
|
|
|
|
|
|
|
|
|
this.messageInput.focus();
|
|
|
}
|
|
|
|
|
|
connect(username) {
|
|
|
this.username = username;
|
|
|
|
|
|
|
|
|
const connectionModal = new bootstrap.Modal(document.getElementById('connectionModal'));
|
|
|
connectionModal.show();
|
|
|
|
|
|
|
|
|
this.socket = io();
|
|
|
|
|
|
this.socket.on('connect', () => {
|
|
|
console.log('Connected to server');
|
|
|
this.joinChat();
|
|
|
connectionModal.hide();
|
|
|
|
|
|
|
|
|
if (window.terminalEffects) {
|
|
|
window.terminalEffects.successFlash();
|
|
|
window.terminalEffects.showNetworkActivity();
|
|
|
}
|
|
|
});
|
|
|
|
|
|
this.socket.on('disconnect', () => {
|
|
|
console.log('Disconnected from server');
|
|
|
this.showSystemMessage('Connection lost. Attempting to reconnect...', 'warning');
|
|
|
});
|
|
|
|
|
|
this.socket.on('new_message', (data) => {
|
|
|
this.displayMessage(data);
|
|
|
if (data.is_bot) {
|
|
|
this.botResponseCount++;
|
|
|
this.updateStats();
|
|
|
}
|
|
|
});
|
|
|
|
|
|
this.socket.on('user_joined', (data) => {
|
|
|
this.showSystemMessage(`${data.username} joined the chat`, 'info');
|
|
|
});
|
|
|
|
|
|
this.socket.on('user_left', (data) => {
|
|
|
this.showSystemMessage(`${data.username} left the chat`, 'info');
|
|
|
});
|
|
|
|
|
|
this.socket.on('user_typing', (data) => {
|
|
|
this.showTypingIndicator(data.username, data.is_typing);
|
|
|
});
|
|
|
|
|
|
this.socket.on('chat_history', (messages) => {
|
|
|
this.loadChatHistory(messages);
|
|
|
});
|
|
|
|
|
|
this.socket.on('connect_error', (error) => {
|
|
|
console.error('Connection error:', error);
|
|
|
this.showSystemMessage('Failed to connect to chat server', 'error');
|
|
|
if (window.terminalEffects) {
|
|
|
window.terminalEffects.errorFlash();
|
|
|
}
|
|
|
});
|
|
|
}
|
|
|
|
|
|
joinChat() {
|
|
|
this.socket.emit('join_chat', {
|
|
|
username: this.username,
|
|
|
room: 'general'
|
|
|
});
|
|
|
}
|
|
|
|
|
|
sendMessage() {
|
|
|
const message = this.messageInput.value.trim();
|
|
|
if (!message) return;
|
|
|
|
|
|
|
|
|
const now = Date.now();
|
|
|
if (now - this.lastMessageTime < 1000) {
|
|
|
this.showSystemMessage('Slow down there, speed demon! One message per second.', 'warning');
|
|
|
return;
|
|
|
}
|
|
|
this.lastMessageTime = now;
|
|
|
|
|
|
|
|
|
this.socket.emit('send_message', { message });
|
|
|
|
|
|
|
|
|
this.messageInput.value = '';
|
|
|
this.messageCount++;
|
|
|
this.updateStats();
|
|
|
|
|
|
|
|
|
this.stopTyping();
|
|
|
|
|
|
|
|
|
if (window.terminalEffects) {
|
|
|
window.terminalEffects.showNetworkActivity();
|
|
|
}
|
|
|
|
|
|
|
|
|
this.checkEasterEggs(message);
|
|
|
}
|
|
|
|
|
|
displayMessage(messageData) {
|
|
|
const messageElement = document.createElement('div');
|
|
|
messageElement.className = `chat-message ${messageData.is_bot ? 'bot-message' : ''}`;
|
|
|
|
|
|
const avatarIcon = messageData.is_bot ?
|
|
|
'<i class="fas fa-robot text-terminal-accent"></i>' :
|
|
|
'<i class="fas fa-user text-terminal-green"></i>';
|
|
|
|
|
|
messageElement.innerHTML = `
|
|
|
<div class="message-header">
|
|
|
${avatarIcon}
|
|
|
<span class="message-username ${messageData.is_bot ? 'text-terminal-accent' : 'text-terminal-green'}">${this.escapeHtml(messageData.username)}</span>
|
|
|
<span class="message-timestamp">${messageData.timestamp}</span>
|
|
|
</div>
|
|
|
<div class="message-content">
|
|
|
${this.formatMessage(messageData.message)}
|
|
|
</div>
|
|
|
`;
|
|
|
|
|
|
|
|
|
this.chatMessages.appendChild(messageElement);
|
|
|
|
|
|
|
|
|
if (messageData.is_bot && window.terminalEffects) {
|
|
|
window.terminalEffects.powerOnEffect(messageElement);
|
|
|
}
|
|
|
|
|
|
|
|
|
this.scrollToBottom();
|
|
|
|
|
|
|
|
|
if (Math.random() < 0.05) {
|
|
|
setTimeout(() => {
|
|
|
if (window.terminalEffects) {
|
|
|
window.terminalEffects.triggerGlitch();
|
|
|
}
|
|
|
}, 500);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
formatMessage(message) {
|
|
|
|
|
|
let formatted = this.escapeHtml(message);
|
|
|
|
|
|
|
|
|
formatted = formatted.replace(/:\)/g, '😊');
|
|
|
formatted = formatted.replace(/:\(/g, '😔');
|
|
|
formatted = formatted.replace(/:D/g, '😄');
|
|
|
formatted = formatted.replace(/;-?\)/g, '😉');
|
|
|
formatted = formatted.replace(/🫖/g, '🫖');
|
|
|
|
|
|
|
|
|
const britishTerms = [
|
|
|
'brilliant', 'lovely', 'quite', 'rather', 'blimey',
|
|
|
'right then', 'I say', 'charming', 'queue', 'tea'
|
|
|
];
|
|
|
|
|
|
britishTerms.forEach(term => {
|
|
|
const regex = new RegExp(`\\b${term}\\b`, 'gi');
|
|
|
formatted = formatted.replace(regex, `<span class="text-terminal-green">${term}</span>`);
|
|
|
});
|
|
|
|
|
|
return formatted;
|
|
|
}
|
|
|
|
|
|
showSystemMessage(message, type = 'info') {
|
|
|
const messageElement = document.createElement('div');
|
|
|
messageElement.className = 'chat-message system-message';
|
|
|
|
|
|
let iconClass = 'fas fa-info-circle';
|
|
|
let textClass = 'text-terminal-accent';
|
|
|
|
|
|
switch(type) {
|
|
|
case 'warning':
|
|
|
iconClass = 'fas fa-exclamation-triangle';
|
|
|
textClass = 'text-warning';
|
|
|
break;
|
|
|
case 'error':
|
|
|
iconClass = 'fas fa-times-circle';
|
|
|
textClass = 'text-danger';
|
|
|
break;
|
|
|
case 'success':
|
|
|
iconClass = 'fas fa-check-circle';
|
|
|
textClass = 'text-success';
|
|
|
break;
|
|
|
}
|
|
|
|
|
|
messageElement.innerHTML = `
|
|
|
<div class="message-content ${textClass}" style="border-left-color: currentColor;">
|
|
|
<i class="${iconClass} me-2"></i>${this.escapeHtml(message)}
|
|
|
</div>
|
|
|
`;
|
|
|
|
|
|
this.chatMessages.appendChild(messageElement);
|
|
|
this.scrollToBottom();
|
|
|
}
|
|
|
|
|
|
handleTyping() {
|
|
|
if (!this.isTyping) {
|
|
|
this.isTyping = true;
|
|
|
this.socket.emit('typing', { is_typing: true });
|
|
|
}
|
|
|
|
|
|
|
|
|
if (this.typingTimer) {
|
|
|
clearTimeout(this.typingTimer);
|
|
|
}
|
|
|
|
|
|
|
|
|
this.typingTimer = setTimeout(() => {
|
|
|
this.stopTyping();
|
|
|
}, 2000);
|
|
|
}
|
|
|
|
|
|
stopTyping() {
|
|
|
if (this.isTyping) {
|
|
|
this.isTyping = false;
|
|
|
this.socket.emit('typing', { is_typing: false });
|
|
|
}
|
|
|
|
|
|
if (this.typingTimer) {
|
|
|
clearTimeout(this.typingTimer);
|
|
|
this.typingTimer = null;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
showTypingIndicator(username, isTyping) {
|
|
|
if (isTyping) {
|
|
|
this.typingIndicator.innerHTML = `<i class="fas fa-ellipsis-h"></i> ${this.escapeHtml(username)} is typing...`;
|
|
|
this.typingIndicator.style.display = 'block';
|
|
|
} else {
|
|
|
this.typingIndicator.style.display = 'none';
|
|
|
}
|
|
|
}
|
|
|
|
|
|
loadChatHistory(messages) {
|
|
|
|
|
|
const systemMessages = this.chatMessages.querySelectorAll('.system-message, .fade-in');
|
|
|
this.chatMessages.innerHTML = '';
|
|
|
|
|
|
|
|
|
systemMessages.forEach(msg => this.chatMessages.appendChild(msg));
|
|
|
|
|
|
|
|
|
messages.forEach(message => this.displayMessage(message));
|
|
|
}
|
|
|
|
|
|
updateStats() {
|
|
|
if (this.messageCountElement) {
|
|
|
this.messageCountElement.textContent = this.messageCount;
|
|
|
}
|
|
|
if (this.botResponseCountElement) {
|
|
|
this.botResponseCountElement.textContent = this.botResponseCount;
|
|
|
}
|
|
|
|
|
|
|
|
|
const sarcasmBar = document.getElementById('sarcasmLevel');
|
|
|
if (sarcasmBar && this.botResponseCount > 0) {
|
|
|
const level = Math.min(85 + (this.botResponseCount * 2), 100);
|
|
|
sarcasmBar.style.width = `${level}%`;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
checkEasterEggs(message) {
|
|
|
const lowerMessage = message.toLowerCase();
|
|
|
|
|
|
|
|
|
if (lowerMessage.includes('tea time') || lowerMessage.includes('teatime')) {
|
|
|
setTimeout(() => {
|
|
|
this.showSystemMessage('🫖 TEA TIME DETECTED! The bot approves greatly!', 'success');
|
|
|
}, 1000);
|
|
|
}
|
|
|
|
|
|
|
|
|
if (lowerMessage.includes('queue')) {
|
|
|
setTimeout(() => {
|
|
|
this.showSystemMessage('🇬🇧 Proper queuing etiquette detected. Carry on!', 'success');
|
|
|
}, 1500);
|
|
|
}
|
|
|
|
|
|
|
|
|
if (lowerMessage.includes('sarcasm') || lowerMessage.includes('sarcastic')) {
|
|
|
setTimeout(() => {
|
|
|
this.showSystemMessage('Did someone mention sarcasm? How terribly meta.', 'info');
|
|
|
}, 2000);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
scrollToBottom() {
|
|
|
this.chatMessages.scrollTop = this.chatMessages.scrollHeight;
|
|
|
}
|
|
|
|
|
|
escapeHtml(text) {
|
|
|
const div = document.createElement('div');
|
|
|
div.textContent = text;
|
|
|
return div.innerHTML;
|
|
|
}
|
|
|
|
|
|
|
|
|
connectToChat(username) {
|
|
|
this.connect(username);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
|
|
|
let sarcasticChat;
|
|
|
|
|
|
function initializeChat(username) {
|
|
|
sarcasticChat = new SarcasticChat();
|
|
|
sarcasticChat.connectToChat(username);
|
|
|
}
|
|
|
|
|
|
|
|
|
document.addEventListener('DOMContentLoaded', () => {
|
|
|
|
|
|
const bootMessages = [
|
|
|
'Initializing sarcasm protocols...',
|
|
|
'Loading British wit database...',
|
|
|
'Calibrating eye-roll mechanisms...',
|
|
|
'Connecting to tea server...',
|
|
|
'Queue management system: ONLINE',
|
|
|
'Deploying devastating humor...',
|
|
|
'Ready for maximum sarcasm!'
|
|
|
];
|
|
|
|
|
|
|
|
|
if (window.location.pathname === '/chat') {
|
|
|
const container = document.querySelector('.container-fluid');
|
|
|
if (container && window.terminalEffects) {
|
|
|
|
|
|
setTimeout(() => {
|
|
|
window.terminalEffects.bootSequence(container, bootMessages, () => {
|
|
|
console.log('Chat system ready for maximum British sarcasm!');
|
|
|
});
|
|
|
}, 1000);
|
|
|
}
|
|
|
}
|
|
|
});
|
|
|
|
|
|
|
|
|
window.initializeChat = initializeChat;
|
|
|
window.SarcasticChat = SarcasticChat; |