const emojiPatterns = [
{ pattern: ':)', replacement: 'π' },
{ pattern: ':-)', replacement: 'π' },
{ pattern: ':D', replacement: 'π' },
{ pattern: ':-D', replacement: 'π' },
{ pattern: ';)', replacement: 'π' },
{ pattern: ';-)', replacement: 'π' },
{ pattern: ':(', replacement: 'π' },
{ pattern: ':-(', replacement: 'π' },
{ pattern: ':\'(', replacement: 'π' },
{ pattern: ':\'-(', replacement: 'π' },
{ pattern: ':\\', replacement: 'π' },
{ pattern: ':-\\', replacement: 'π' },
{ pattern: ':/', replacement: 'π' },
{ pattern: ':-/', replacement: 'π' },
{ pattern: ':|', replacement: 'π' },
{ pattern: ':-|', replacement: 'π' },
{ pattern: ':*', replacement: 'π' },
{ pattern: ':-*', replacement: 'π' },
{ pattern: '<3', replacement: 'β€οΈ' },
{ pattern: '(y)', replacement: 'π' },
];
const socket = io();
$(() => {
socket.on('serverHandshake', onServerHandshake);
socket.on('serverLogin', onServerLogin);
socket.on('serverKick', onServerKick);
});
function onServerHandshake() {
resetChatListeners();
resetLoginListeners();
var template = $('#chat-login-template').html();
$('#chat-host').empty();
$('#chat-host').append(template);
$('#chat-login-form').submit((e) => {
e.preventDefault();
socket.emit('login', $('#chat-login-form .username').val(), $('#chat-login-form .password').val());
return false;
});
socket.on('usernameInvalid', () => {
$('#chat-login-form .username').focus();
$('#chat-host .loginError').text('Username invalid.');
});
socket.on('usernameTaken', () => {
$('#chat-login-form .username').focus();
$('#chat-host .loginError').text('Username already in use.');
});
socket.on('passwordRequired', () => {
$('#chat-login-form .passwordWrapper').css('display', '');
$('#chat-login-form .password').focus();
$('#chat-host .loginError').text('FΓΌr diesen reservierten Benutzer ist ein Passwort erforderlich.');
});
socket.on('passwordWrong', () => {
$('#chat-login-form .passwordWrapper').css('display', '');
$('#chat-login-form .password').focus();
$('#chat-host .loginError').text('Das eingegebene Passwort ist ungΓΌltig.');
});
}
function onServerLogin(user, history) {
resetChatListeners();
resetLoginListeners();
var template;
if (user.admin) {
template = $('#chat-admin-template').html()
} else {
template = $('#chat-template').html()
}
$('#chat-host').empty();
$('#chat-host').append(template);
$('#chat-host').append($('#chat-message-form-template').html());
$('#chat-host .messageField').focus();
for (const historyMsg of history) {
appendUserMessage(historyMsg.msg, historyMsg.user, historyMsg.timestamp, user);
}
socket.on('usersUpdated', (userList) => {
$('#chat-host .main .userlist').empty();
userList.sort((userA, userB) => userA.name.localeCompare(userB.name));
userList.sort((userA, userB) => {
if (userA.admin && !userB.admin) {
return Number.MIN_SAFE_INTEGER;
} else if (!userA.admin && userB.admin) {
return Number.MAX_SAFE_INTEGER;
}
return 0;
});
for (let listUser of userList) {
let userString = listUser.name;
if (listUser.admin) {
userString = 'π ' + userString;
}
const userListEl = $('
');
const usernameEl = $('');
usernameEl.text(userString);
usernameEl.css('color', listUser.color);
usernameEl.click(() => mentionUser(listUser.name));
userListEl.append(usernameEl);
if (user.admin) {
const kickBtn = $('');
kickBtn.click(() => onKickUser(listUser));
userListEl.append(kickBtn);
}
$('#chat-host .main .userlist').append(userListEl);
}
});
if (user.admin) {
socket.on('bannedUpdated', (bannedList) => {
$('#chat-host .main .bannedlist').empty();
for (let bannedItem of bannedList) {
const bannedListEl = $('');
bannedListEl.text(bannedItem.ip + ' (' + bannedItem.user.name + ')');
const removeBtn = $('');
removeBtn.click(() => onLiftBan(bannedItem.ip));
bannedListEl.append(removeBtn);
$('#chat-host .main .bannedlist').append(bannedListEl);
}
});
}
socket.on('message', (msg, msgUser, timestamp) => appendUserMessage(msg, msgUser, timestamp, user));
socket.on('userJoined', (msg) => {
appendMessage($('').text(msg + ' hat den Chat betreten.'));
});
socket.on('userLeft', (msg) => {
appendMessage($('').text(msg + ' hat den Chat verlassen.'));
});
$('#chat-host .messageForm').submit((e) => {
e.preventDefault();
socket.emit('message', $('#chat-host .messageForm .messageField').val());
$('#chat-host .messageForm .messageField').val('');
$('#chat-host .messageForm .messageField').focus();
return false;
});
$("#chat-host .messageField").keypress((e) => {
const field = $('#chat-host .messageForm .messageField');
if (field.prop('selectionStart') == field.prop('selectionEnd')) {
const val = field.val();
const cursorPos = field.prop('selectionStart');
const valBefore = val.substring(0, cursorPos);
const valAfter = val.substring(cursorPos);
if (!valBefore.endsWith('http:/') && !valBefore.endsWith('https:/')) {
for (const emojiPatternItem of emojiPatterns) {
if (valBefore.endsWith(emojiPatternItem.pattern)) {
field.val(
valBefore.substring(0, valBefore.length - emojiPatternItem.pattern.length) + emojiPatternItem.replacement + valAfter
);
field.prop('selectionStart', cursorPos);
field.prop('selectionEnd', cursorPos);
}
}
}
}
if(e.key == 'Enter' && !e.shiftKey) {
e.preventDefault();
$('#chat-host .messageForm').submit();
return false;
}
});
}
function onServerKick() {
resetChatListeners();
resetLoginListeners();
var template = $('#chat-kick-template').html();
$('#chat-host').empty();
$('#chat-host').append(template);
}
function resetChatListeners() {
socket.removeAllListeners('usersUpdated');
socket.removeAllListeners('message');
socket.removeAllListeners('userJoined');
socket.removeAllListeners('userLeft');
}
function resetLoginListeners() {
socket.removeAllListeners('usernameInvalid');
socket.removeAllListeners('usernameTaken');
socket.removeAllListeners('passwordRequired');
socket.removeAllListeners('passwordWrong');
}
function appendMessage(element) {
const messagesListEl = $('#chat-host .main .messages')[0];
const scrollMax = messagesListEl.scrollHeight - messagesListEl.clientHeight;
const scrolled = messagesListEl.scrollTop != scrollMax;
$('#chat-host .main .messages').append(element);
// TODO: Scrolling
//if (!scrolled) {
messagesListEl.scrollTop = messagesListEl.scrollHeight - messagesListEl.clientHeight;
//}
}
function appendUserMessage(msg, msgUser, timestamp, user) {
const messageWrapper = $('');
if(user.name == msgUser.name) {
messageWrapper.addClass('self');
}
messageWrapper.css('borderColor', msgUser.color);
const avaEl = $('
');
avaEl.prop('src', '/img/ava/' + msgUser.name);
avaEl.css('backgroundColor', msgUser.color);
avaEl.click(() => mentionUser(msgUser.name));
messageWrapper.append(avaEl);
const timeEl = $('');
timeEl.text(new Date(timestamp).toLocaleTimeString());
timeEl.prop('title', new Date(timestamp).toLocaleString());
messageWrapper.append(timeEl);
const userEl = $('');
let userString = msgUser.name;
if (msgUser.admin) {
userString = 'π ' + userString;
}
userEl.text(userString);
userEl.css('color', msgUser.color);
userEl.click(() => mentionUser(msgUser.name));
messageWrapper.append(userEl);
const messageEl = $('');
messageEl.html(msg)
messageWrapper.append(messageEl);
appendMessage(messageWrapper);
}
function onKickUser(user) {
if (confirm('MΓΆchten Sie den Benutzer "' + user.name + '" wirklich bannen?\nDies wird sich auf alle Benutzer mit der gleichen IP-Adresse auswirken.')) {
socket.emit('requestKick', user);
}
}
function onLiftBan(ip) {
socket.emit('requestLiftBan', ip);
}
function mentionUser(username) {
const field = $("#chat-host .messageField");
if (field) {
const mention = '@' + username + ' ';
const val = field.val();
var cursorPos = +field.prop('selectionStart');
const valBefore = val.substring(0, cursorPos);
const valAfter = val.substring(cursorPos);
field.val(valBefore + mention + valAfter);
cursorPos += mention.length;
field.prop('selectionStart', cursorPos);
field.prop('selectionEnd', cursorPos);
field.focus();
}
}