chat
parent
cba3c17462
commit
c96f86e056
|
@ -13,6 +13,7 @@ if SITE in ('pcmemes.net', 'localhost'):
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
socketio = SocketIO(app, async_mode='gevent')
|
socketio = SocketIO(app, async_mode='gevent')
|
||||||
|
typing = []
|
||||||
|
|
||||||
@app.get("/chat")
|
@app.get("/chat")
|
||||||
@auth_required
|
@auth_required
|
||||||
|
@ -38,10 +39,27 @@ if SITE in ('pcmemes.net', 'localhost'):
|
||||||
def connect():
|
def connect():
|
||||||
global count
|
global count
|
||||||
count += 1
|
count += 1
|
||||||
emit("count", count)
|
emit("count", count, broadcast=True)
|
||||||
|
|
||||||
|
emit('typing', typing)
|
||||||
|
return '', 204
|
||||||
|
|
||||||
@socketio.on('disconnect')
|
@socketio.on('disconnect')
|
||||||
def disconnect():
|
@auth_required
|
||||||
|
def disconnect(v):
|
||||||
global count
|
global count
|
||||||
count -= 1
|
count -= 1
|
||||||
emit("count", count)
|
emit("count", count, broadcast=True)
|
||||||
|
if v.username in typing: typing.remove(v.username)
|
||||||
|
emit('typing', typing, broadcast=True)
|
||||||
|
return '', 204
|
||||||
|
|
||||||
|
@socketio.on('typing')
|
||||||
|
@auth_required
|
||||||
|
def typing_indicator(data, v):
|
||||||
|
|
||||||
|
if data and v.username not in typing: typing.append(v.username)
|
||||||
|
elif not data and v.username in typing: typing.remove(v.username)
|
||||||
|
|
||||||
|
emit('typing', typing, broadcast=True)
|
||||||
|
return '', 204
|
|
@ -54,10 +54,8 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script src="/assets/js/socketio.js"></script>
|
<script src="/assets/js/socketio.js"></script>
|
||||||
<script src="/assets/js/chat.js?v=13"></script>
|
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
|
|
||||||
#chat-window {
|
#chat-window {
|
||||||
max-height:calc(100vh - 300px);
|
max-height:calc(100vh - 300px);
|
||||||
overflow-y: scroll;
|
overflow-y: scroll;
|
||||||
|
@ -78,6 +76,134 @@
|
||||||
scrollbar-width: none;
|
scrollbar-width: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.chat-mention {
|
||||||
|
background-color: rgba(128, 90, 213, 0.3);
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
let socket=io()
|
||||||
|
let chatline = document.getElementsByClassName('chat-line')[0]
|
||||||
|
let box = document.getElementById('chat-window')
|
||||||
|
let textbox = document.getElementById('input-text')
|
||||||
|
let icon = document.getElementById('favicon')
|
||||||
|
let notifs = 0;
|
||||||
|
let scrolled_down = true;
|
||||||
|
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 = '/static/assets/images/{{SITE_NAME}}/alert.webp'
|
||||||
|
alert=false;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
icon.href = '/assets/images/{{SITE_NAME}}/icon.webp'
|
||||||
|
alert=true;
|
||||||
|
}
|
||||||
|
setTimeout(flash, 500)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
icon.href = '/assets/images/{{SITE_NAME}}/icon.webp'
|
||||||
|
notifs = 0
|
||||||
|
title.innerHTML = 'Chat';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
socket.on('speak', function(json) {
|
||||||
|
let text = json['text']
|
||||||
|
|
||||||
|
if (text.includes('<a href="/id/{{v.id}}">')){
|
||||||
|
chatline.classList.add('chat-mention');
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
chatline.classList.remove('chat-mention');
|
||||||
|
};
|
||||||
|
|
||||||
|
notifs = notifs + 1;
|
||||||
|
if (notifs == 1) {
|
||||||
|
setTimeout(flash, 500);
|
||||||
|
}
|
||||||
|
|
||||||
|
scrolled_down = (box.scrollHeight - box.scrollTop <= window.innerHeight-109)
|
||||||
|
document.getElementsByClassName('desktop-avatar')[0].src = json['avatar']
|
||||||
|
document.getElementsByClassName('userlink')[0].href = '/@' + json['username']
|
||||||
|
document.getElementsByClassName('userlink')[0].innerHTML = json['username']
|
||||||
|
document.getElementsByClassName('userlink')[0].style.color = '#' + json['namecolor']
|
||||||
|
document.getElementsByClassName('chat-message')[0].innerHTML = text
|
||||||
|
document.getElementById('chat-text').append(document.getElementsByClassName('chat-line')[0].cloneNode(true))
|
||||||
|
if (scrolled_down) box.scrollTo(0,box.scrollHeight)
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
function send() {
|
||||||
|
socket.emit('speak', textbox.value);
|
||||||
|
textbox.value = ''
|
||||||
|
is_typing = false
|
||||||
|
socket.emit('typing', false);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
textbox.addEventListener("keyup", function(event) {
|
||||||
|
if (event.key === 'Enter') {
|
||||||
|
event.preventDefault();
|
||||||
|
send()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
socket.on('count', function(data){
|
||||||
|
document.getElementsByClassName('board-chat-count')[0].innerHTML = data
|
||||||
|
})
|
||||||
|
|
||||||
|
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 = '<b>'+users[0]+"</b> is typing...";
|
||||||
|
document.getElementById('loading-indicator').classList.remove('d-none');
|
||||||
|
}
|
||||||
|
else if (users.length==2){
|
||||||
|
document.getElementById('typing-indicator').innerHTML = '<b>'+users[0]+"</b> and <b>"+users[1]+"</b> are typing...";
|
||||||
|
document.getElementById('loading-indicator').classList.remove('d-none');
|
||||||
|
}
|
||||||
|
else if (users.length==3){
|
||||||
|
document.getElementById('typing-indicator').innerHTML = '<b>'+users[0]+"</b>, <b>"+users[1]+"</b>, and <b>"+users[2]+"</b> are typing...";
|
||||||
|
document.getElementById('loading-indicator').classList.remove('d-none');
|
||||||
|
}
|
||||||
|
else if (users.length>=4){
|
||||||
|
more=users.length-3
|
||||||
|
document.getElementById('typing-indicator').innerHTML = '<b>'+users[0]+"</b>, <b>"+users[1]+"</b>, <b>"+users[2]+"</b> and "+more.toString()+" more are typing...";
|
||||||
|
document.getElementById('loading-indicator').classList.remove('d-none');
|
||||||
|
}
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
{% endblock %}
|
{% endblock %}
|
|
@ -83,7 +83,7 @@
|
||||||
<link rel="apple-touch-icon" sizes="180x180" href="/static/assets/images/{{SITE_NAME}}/icon.webp?v=1012">
|
<link rel="apple-touch-icon" sizes="180x180" href="/static/assets/images/{{SITE_NAME}}/icon.webp?v=1012">
|
||||||
<link rel="manifest" href="/static/assets/manifest.json?v=1">
|
<link rel="manifest" href="/static/assets/manifest.json?v=1">
|
||||||
<link rel="mask-icon" href="/static/assets/images/{{SITE_NAME}}/icon.webp?v=1012">
|
<link rel="mask-icon" href="/static/assets/images/{{SITE_NAME}}/icon.webp?v=1012">
|
||||||
<link rel="shortcut icon" href="/static/assets/images/{{SITE_NAME}}/icon.webp?v=1012">
|
<link id="favicon" rel="shortcut icon" href="/static/assets/images/{{SITE_NAME}}/icon.webp?v=1012">
|
||||||
<meta name="apple-mobile-web-app-title" content="{{SITE_NAME}}">
|
<meta name="apple-mobile-web-app-title" content="{{SITE_NAME}}">
|
||||||
<meta name="application-name" content="{{SITE_NAME}}">
|
<meta name="application-name" content="{{SITE_NAME}}">
|
||||||
<meta name="msapplication-TileColor" content="#{{config('DEFAULT_COLOR')}}">
|
<meta name="msapplication-TileColor" content="#{{config('DEFAULT_COLOR')}}">
|
||||||
|
|
|
@ -7,6 +7,7 @@ Flask-Limiter
|
||||||
Flask-Mail
|
Flask-Mail
|
||||||
Flask-Socketio
|
Flask-Socketio
|
||||||
gevent
|
gevent
|
||||||
|
gevent-websocket
|
||||||
greenlet
|
greenlet
|
||||||
gunicorn
|
gunicorn
|
||||||
lxml
|
lxml
|
||||||
|
|
|
@ -5,7 +5,7 @@ logfile=/tmp/supervisord.log
|
||||||
|
|
||||||
[program:service]
|
[program:service]
|
||||||
directory=/service
|
directory=/service
|
||||||
command=gunicorn files.__main__:app -k gevent -w 1 --reload -b 0.0.0.0:80 --max-requests 1000 --max-requests-jitter 500
|
command=gunicorn files.__main__:app -k geventwebsocket.gunicorn.workers.GeventWebSocketWorker -w 1 --reload -b 0.0.0.0:80 --max-requests 1000 --max-requests-jitter 500
|
||||||
stdout_logfile=/dev/stdout
|
stdout_logfile=/dev/stdout
|
||||||
stdout_logfile_maxbytes=0
|
stdout_logfile_maxbytes=0
|
||||||
stderr_logfile=/dev/stderr
|
stderr_logfile=/dev/stderr
|
||||||
|
|
Loading…
Reference in New Issue