function timeSince(timeStamp) { var now = new Date(), secondsPast = (now.getTime() - timeStamp) / 1000; if (secondsPast < 60) { return parseInt(secondsPast) + 's'; } if (secondsPast < 3600) { return parseInt(secondsPast / 60) + 'm'; } if (secondsPast <= 86400) { return parseInt(secondsPast / 3600) + 'h'; } if (secondsPast > 86400) { day = timeStamp.getDate(); month = timeStamp.toDateString().match(/ [a-zA-Z]*/)[0].replace(" ", ""); year = timeStamp.getFullYear() == now.getFullYear() ? "" : " " + timeStamp.getFullYear(); return day + " " + month + year; } } const ua=window.navigator.userAgent let socket socket=io() const chatline = document.getElementsByClassName('chat-line')[0] const box = document.getElementById('chat-window') const textbox = document.getElementById('input-text') const icon = document.getElementById('icon') const vid = document.getElementById('vid').value const vusername = document.getElementById('vusername').value const site_name = document.getElementById('site_name').value const slurreplacer = document.getElementById('slurreplacer').value let notifs = 0; let focused = true; let is_typing = false; let alert=true; function flash(){ let title = document.getElementsByTagName('title')[0] if (notifs >= 1 && !focused){ title.innerHTML = `[+${notifs}] Chat`; if (alert) { icon.href = escapeHTML(`/assets/images/${site_name}/alert.webp?v=3`) alert=false; } else { icon.href = escapeHTML(`/assets/images/${site_name}/icon.webp?v=3009`) alert=true; } setTimeout(flash, 500) } else { icon.href = escapeHTML(`/assets/images/${site_name}/icon.webp?v=3009`) notifs = 0 title.innerHTML = 'Chat'; } if (is_typing) { is_typing = false socket.emit('typing', false); } } function handle_message(json) { let text = json['text'] let text_html if (slurreplacer == 'True') text_html = json['text_censored'] else text_html = json['text_html'] if (text_html.includes(``)){ chatline.classList.add('chat-mention'); } else { chatline.classList.remove('chat-mention'); }; notifs = notifs + 1; if (notifs == 1) { setTimeout(flash, 500); } const users = document.getElementsByClassName('userlink'); const last_user = users[users.length-1].innerHTML; const scrolled_down = (box.scrollHeight - box.scrollTop <= window.innerHeight) if (last_user == json['username']) { document.getElementsByClassName('userlink')[0].classList.add('d-none') document.getElementsByClassName('avatar')[0].classList.add('d-none') document.getElementsByClassName('time')[0].classList.add('d-none') } else { document.getElementsByClassName('userlink')[0].classList.remove('d-none') document.getElementsByClassName('avatar')[0].classList.remove('d-none') document.getElementsByClassName('avatar-pic')[0].src = '/pp/' + json["user_id"] if (json['hat']) document.getElementsByClassName('avatar-hat')[0].src = json['hat'] + "?h=7" else document.getElementsByClassName('avatar-hat')[0].removeAttribute("src") document.getElementsByClassName('userlink')[0].href = '/@' + json['username'] document.getElementsByClassName('userlink')[0].style.color = '#' + json['namecolor'] document.getElementsByClassName('time')[0].classList.remove('d-none') document.getElementsByClassName('time')[0].innerHTML = timeSince(json['time']*1000) + ' ago' } document.getElementsByClassName('chat-line')[0].id = json['id'] document.getElementsByClassName('userlink')[0].innerHTML = json['username'] document.getElementsByClassName('text')[0].innerHTML = escapeHTML(text) document.getElementsByClassName('chat-message')[0].innerHTML = text_html.replace(/data-src/g, 'src').replace(/data-cfsrc/g, 'src').replace(/style="display:none;visibility:hidden;"/g, '') if (json['quotes']) { document.getElementsByClassName('quotes')[0].classList.remove("d-none") const quoted = document.getElementById(json['quotes']) document.getElementsByClassName('QuotedMessageLink')[0].href = '#' + json['quotes'] document.getElementsByClassName('QuotedUser')[0].innerHTML = quoted.querySelector('.userlink').innerHTML document.getElementsByClassName('QuotedMessage')[0].innerHTML = quoted.querySelector('.chat-message').innerHTML } else { document.getElementsByClassName('quotes')[0].classList.add("d-none") } let line = document.getElementsByClassName('chat-line')[0].cloneNode(true) register_new_elements(line); bs_trigger(line) if (last_user == json['username']) { box.querySelector('.chat-group:last-child').append(line) } else { const chatgroup = document.createElement("div"); chatgroup.className = "chat-group"; chatgroup.append(line) box.append(chatgroup) } if (scrolled_down || json['username'] == vusername) box.scrollTo(0, box.scrollHeight) } socket.on('speak', function(json) { handle_message(json) }) socket.on('catchup', function(json) { for (const message of json) { handle_message(message) } }) function send() { const text = textbox.value.trim() const files = document.getElementById('file').files if (text || files) { let sending; if (files[0]) sending = files[0] else sending = '' socket.emit('speak', { "message": text, "quotes": document.getElementById('quotes_id').value, "file": sending, }); textbox.value = '' is_typing = false socket.emit('typing', false); autoExpand(textbox); document.getElementById("quotes").classList.add("d-none") document.getElementById("filename").innerHTML = '' scroll_chat(); } } function quote(t) { document.getElementById("quotes").classList.remove("d-none") const text = t.parentElement.getElementsByClassName("text")[0].innerHTML.replace(/\*/g,"\\*").split('\n').pop() document.getElementById('QuotedMessage').innerHTML = text const username = t.parentElement.parentElement.getElementsByClassName('userlink')[0].innerHTML document.getElementById('QuotedUser').innerHTML = username const id = t.parentElement.parentElement.parentElement.parentElement.id document.getElementById('quotes_id').value = id document.getElementById('QuotedMessageLink').href = `#${id}` } textbox.addEventListener("keyup", function(e) { if (e.key === 'Enter') { e.preventDefault(); send(); } }) socket.on('online', function(data){ document.getElementsByClassName('board-chat-count')[0].innerHTML = data.length let online = '' let online2 = 'Users Online' for (const u of data) { online += `
  • @${u}
  • ` online2 += `
    @${u}` } document.getElementById('online').innerHTML = online document.getElementById('online2').setAttribute("data-bs-original-title", online2); document.getElementById('online3').innerHTML = online }) window.addEventListener('blur', function(){ focused=false }) window.addEventListener('focus', function(){ focused=true }) textbox.addEventListener("input", function() { text = textbox.value if (!text && is_typing==true){ is_typing=false; socket.emit('typing', false); } else if (text && is_typing==false) { is_typing=true; socket.emit('typing', true); } }) socket.on('typing', function (users){ if (users.length==0){ document.getElementById('typing-indicator').innerHTML = ''; document.getElementById('loading-indicator').classList.add('d-none'); } else if (users.length==1){ document.getElementById('typing-indicator').innerHTML = ''+users[0]+" is typing..."; document.getElementById('loading-indicator').classList.remove('d-none'); } else if (users.length==2){ document.getElementById('typing-indicator').innerHTML = ''+users[0]+" and "+users[1]+" are typing..."; document.getElementById('loading-indicator').classList.remove('d-none'); } else { document.getElementById('typing-indicator').innerHTML = ''+users[0]+", "+users[1]+", and "+users[2]+" are typing..."; document.getElementById('loading-indicator').classList.remove('d-none'); } }) function del(t) { const chatline = t.parentElement.parentElement.parentElement.parentElement socket.emit('delete', chatline.id); chatline.remove() } socket.on('delete', function(text) { const text_spans = document.getElementsByClassName('text') for(const span of text_spans) { if (span.innerHTML == text) { span.parentElement.parentElement.parentElement.parentElement.parentElement.remove() } } }) function scroll_chat() { setTimeout(function () { box.scrollTo(0, box.scrollHeight) }, 200); setTimeout(function () { box.scrollTo(0, box.scrollHeight) }, 500); setTimeout(function () { box.scrollTo(0, box.scrollHeight) }, 1000); } scroll_chat(); box.scrollTo(0, box.scrollHeight); document.addEventListener('click', function (e) { if (e.target.classList.contains('fa-trash-alt')) { e.target.nextElementSibling.classList.remove('d-none'); e.target.classList.add('d-none'); } else { for (const btn of document.querySelectorAll('.delmsg:not(.d-none)')) { btn.classList.add('d-none'); btn.previousElementSibling.classList.remove('d-none'); } } if (e.target.id == "cancel") { document.getElementById("quotes").classList.add("d-none") } });