let username;
let is_reconnection = false;
let last_command = null;
const server = `ws://${location.host}`;
let ws;
let md;
$(() => {
init().then(x => ws = x).catch(err => console.log(err))
});
function clear_message() {
$('#message').empty();
}
function clear_send() {
$('#send').val('');
}
function format_time(time) {
return `${time.getMonth() + 1}-${time.getDate()} ${time.getHours()}:${time.getMinutes()}:${time.getSeconds()}`;
}
function write_message(data) {
const message = data.msg;
let message_class = '';
let message_source = data.from;
if (data.type === 'system-message') {
message_class = 'msg-from-info';
message_source = 'SYSTEM INFO';
} else if (data.type === 'command-block') {
message_class = 'msg-from-cb';
message_source = 'COMMAND BLOCK';
}
let rendered_message;
if (!data.plain) {
rendered_message = md.render(message);
} else {
rendered_message = `${message}`;
}
rendered_message = DOMPurify.sanitize(rendered_message);
$('#message').append(`
${message_source}
${format_time(new Date())}
${rendered_message}
`
);
scroll_to_bottom();
}
async function init() {
$('#prompt-data').on('keyup', (e) => {
if (e.key === 'Enter') { $('#confirm-prompt').click(); }
});
clear_message();
await login_name();
md = new remarkable.Remarkable({
highlight: function (str, lang) {
if (lang && hljs.getLanguage(lang)) {
try {
return hljs.highlight(lang, str).value;
} catch (err) { }
}
try {
return hljs.highlightAuto(str).value;
} catch (err) { }
return '';
}
});
md.inline.ruler.enable(['mark', 'sup', 'sub']);
const ws = new io(server);
ws.on('connect', () => {
if (is_reconnection) {
write_message({
from: 'INFO',
msg: 'Reconnected.',
is_private: true,
plain: true,
});
} else {
write_message({
from: 'INFO',
msg: 'Connected.',
is_private: true,
plain: true,
});
is_reconnection = true;
}
ws.emit('set-name', username);
});
ws.on('system-message', msg => {
write_message({
type: 'system-message',
msg: msg,
is_private: true,
plain: true,
});
});
ws.on('new message', evt => {
write_message({
type: 'normal',
from: evt.sender,
msg: evt.data,
});
});
ws.on('private message', evt => {
write_message({
type: 'normal',
from: evt.sender,
msg: evt.data,
is_private: true,
});
})
ws.on('command-block-reply', data => {
write_message({
type: 'command-block',
msg: `>> ${last_command}\n<- ${data}`,
is_private: true,
plain: true,
});
});
ws.on('disconnect', () => {
write_message({
type: 'system-message',
msg: 'Disconnected.',
is_private: true,
plain: true,
});
});
$('#send').focus();
return ws;
}
function open_prompt(title) {
$('#prompt-box-title').text(title);
$('#prompt-data').val('');
$('#prompt-box').show('fast', () => { $('#prompt-data').focus(); });
let resolve_callback;
let res = new Promise((resolve) => {
resolve_callback = resolve;
});
$('#confirm-prompt').one('click', () => {
if (resolve_callback) {
$('#prompt-box').hide('fast');
resolve_callback($('#prompt-data').val());
}
});
return res;
}
async function login_name() {
username = await open_prompt('[Login] Input your name');
}
async function send() {
let data = $('#send').val();
if (data === '') {
return;
}
if (data === '/clear' || data === '/cls') {
clear_message();
clear_send();
return;
}
if (data.startsWith('/')) {
// a command
last_command = data;
}
if (data.startsWith('/su')) {
// a administrator login command.
// now ask for passcode
const code = await open_prompt('[su] Input the administration passcode');
data = `/su ${code}`;
}
if (ws.connected) {
ws.emit('message', data);
} else {
write_message({
type: 'system-message',
msg: 'Socket not connected or has already disconnected. Failed to send.',
is_private: true,
plain: true,
});
}
clear_send();
}
function scroll_to_bottom() {
if ($('#scroll-option').is(':checked')) {
document.getElementById('message').scrollTop = document.getElementById('message').scrollHeight;
}
}
document.addEventListener('keydown', async function (key_event) {
if (key_event.code === 'Enter' && key_event.ctrlKey) {
key_event.preventDefault();
await send();
}
});