another chat rework
parent
51808b6f40
commit
1ee213f742
|
@ -26,7 +26,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.chat-mention {
|
.chat-mention {
|
||||||
background-color: #{{v.themecolor}}55;
|
background-color: #ffffff44;
|
||||||
border-radius: 3px;
|
border-radius: 3px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -68,7 +68,7 @@ p {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.cdiv {
|
.chat-line {
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
margin-left: 27px;
|
margin-left: 27px;
|
||||||
}
|
}
|
||||||
|
|
Binary file not shown.
After Width: | Height: | Size: 3.3 KiB |
Binary file not shown.
Before Width: | Height: | Size: 10 KiB |
Binary file not shown.
After Width: | Height: | Size: 3.8 KiB |
Binary file not shown.
Before Width: | Height: | Size: 5.1 KiB |
|
@ -26,7 +26,8 @@ socket=io()
|
||||||
const chatline = document.getElementsByClassName('chat-line')[0]
|
const chatline = document.getElementsByClassName('chat-line')[0]
|
||||||
const box = document.getElementById('chat-window')
|
const box = document.getElementById('chat-window')
|
||||||
const textbox = document.getElementById('input-text')
|
const textbox = document.getElementById('input-text')
|
||||||
const icon = document.getElementById('icon')
|
const icon = document.querySelector("link[rel~='icon']")
|
||||||
|
|
||||||
const vid = document.getElementById('vid').value
|
const vid = document.getElementById('vid').value
|
||||||
const vusername = document.getElementById('vusername').value
|
const vusername = document.getElementById('vusername').value
|
||||||
const site_name = document.getElementById('site_name').value
|
const site_name = document.getElementById('site_name').value
|
||||||
|
@ -42,17 +43,17 @@ function flash(){
|
||||||
if (notifs >= 1 && !focused){
|
if (notifs >= 1 && !focused){
|
||||||
title.innerHTML = `[+${notifs}] Chat`;
|
title.innerHTML = `[+${notifs}] Chat`;
|
||||||
if (alert) {
|
if (alert) {
|
||||||
icon.href = escapeHTML(`/assets/images/${site_name}/alert.webp?v=3`)
|
icon.href = `/i/${site_name}/alert.ico?v=3009`
|
||||||
alert=false;
|
alert=false;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
icon.href = escapeHTML(`/assets/images/${site_name}/icon.webp?v=3009`)
|
icon.href = `/i/${site_name}/icon.webp?v=3009`
|
||||||
alert=true;
|
alert=true;
|
||||||
}
|
}
|
||||||
setTimeout(flash, 500)
|
setTimeout(flash, 500)
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
icon.href = escapeHTML(`/assets/images/${site_name}/icon.webp?v=3009`)
|
icon.href = `/i/${site_name}/icon.webp?v=3009`
|
||||||
notifs = 0
|
notifs = 0
|
||||||
title.innerHTML = 'Chat';
|
title.innerHTML = 'Chat';
|
||||||
}
|
}
|
||||||
|
@ -64,11 +65,11 @@ function flash(){
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
function handle_message(json) {
|
socket.on('speak', function(json) {
|
||||||
let text = json['text']
|
let text = json['text']
|
||||||
let text_html
|
let text_html
|
||||||
|
|
||||||
if (slurreplacer == 'True') text_html = json['text_censored']
|
if (slurreplacer != '0') text_html = json['text_censored']
|
||||||
else text_html = json['text_html']
|
else text_html = json['text_html']
|
||||||
|
|
||||||
if (text_html.includes(`<a href="/id/${vid}">`)){
|
if (text_html.includes(`<a href="/id/${vid}">`)){
|
||||||
|
@ -87,15 +88,9 @@ function handle_message(json) {
|
||||||
const last_user = users[users.length-1].innerHTML;
|
const last_user = users[users.length-1].innerHTML;
|
||||||
const scrolled_down = (box.scrollHeight - box.scrollTop <= window.innerHeight)
|
const scrolled_down = (box.scrollHeight - box.scrollTop <= window.innerHeight)
|
||||||
|
|
||||||
if (last_user == json['username']) {
|
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"]
|
document.getElementsByClassName('avatar-pic')[0].src = '/pp/' + json["user_id"]
|
||||||
|
|
||||||
if (json['hat'])
|
if (json['hat'])
|
||||||
document.getElementsByClassName('avatar-hat')[0].src = json['hat'] + "?h=7"
|
document.getElementsByClassName('avatar-hat')[0].src = json['hat'] + "?h=7"
|
||||||
else
|
else
|
||||||
|
@ -103,7 +98,8 @@ function handle_message(json) {
|
||||||
|
|
||||||
document.getElementsByClassName('userlink')[0].href = '/@' + json['username']
|
document.getElementsByClassName('userlink')[0].href = '/@' + json['username']
|
||||||
document.getElementsByClassName('userlink')[0].style.color = '#' + json['namecolor']
|
document.getElementsByClassName('userlink')[0].style.color = '#' + json['namecolor']
|
||||||
document.getElementsByClassName('time')[0].classList.remove('d-none')
|
document.getElementsByClassName('userlink')[0].innerHTML = json['username']
|
||||||
|
|
||||||
if (Date.now() - json['time']*1000 > 5000)
|
if (Date.now() - json['time']*1000 > 5000)
|
||||||
document.getElementsByClassName('time')[0].innerHTML = timeSince(json['time']*1000) + ' ago'
|
document.getElementsByClassName('time')[0].innerHTML = timeSince(json['time']*1000) + ' ago'
|
||||||
else
|
else
|
||||||
|
@ -111,7 +107,6 @@ function handle_message(json) {
|
||||||
}
|
}
|
||||||
|
|
||||||
document.getElementsByClassName('chat-line')[0].id = json['id']
|
document.getElementsByClassName('chat-line')[0].id = json['id']
|
||||||
document.getElementsByClassName('userlink')[0].innerHTML = json['username']
|
|
||||||
document.getElementsByClassName('text')[0].innerHTML = escapeHTML(text)
|
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, '')
|
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, '')
|
||||||
|
|
||||||
|
@ -121,7 +116,7 @@ function handle_message(json) {
|
||||||
if (quoted) {
|
if (quoted) {
|
||||||
document.getElementsByClassName('quotes')[0].classList.remove("d-none")
|
document.getElementsByClassName('quotes')[0].classList.remove("d-none")
|
||||||
document.getElementsByClassName('QuotedMessageLink')[0].href = '#' + json['quotes']
|
document.getElementsByClassName('QuotedMessageLink')[0].href = '#' + json['quotes']
|
||||||
document.getElementsByClassName('QuotedUser')[0].innerHTML = quoted.querySelector('.userlink').innerHTML
|
document.getElementsByClassName('QuotedUser')[0].innerHTML = quoted.parentElement.querySelector('.userlink').innerHTML
|
||||||
document.getElementsByClassName('QuotedMessage')[0].innerHTML = quoted.querySelector('.text').innerHTML
|
document.getElementsByClassName('QuotedMessage')[0].innerHTML = quoted.querySelector('.text').innerHTML
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -133,26 +128,13 @@ function handle_message(json) {
|
||||||
box.querySelector('.chat-group:last-child').append(line)
|
box.querySelector('.chat-group:last-child').append(line)
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
const chatgroup = document.createElement("div");
|
const chatgroup = document.getElementsByClassName('chat-group')[0].cloneNode(true)
|
||||||
chatgroup.className = "chat-group";
|
|
||||||
chatgroup.append(line)
|
chatgroup.append(line)
|
||||||
box.append(chatgroup)
|
box.append(chatgroup)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (scrolled_down || json['username'] == vusername)
|
if (scrolled_down || json['username'] == vusername)
|
||||||
box.scrollTo(0, box.scrollHeight)
|
box.scrollTo(0, box.scrollHeight)
|
||||||
}
|
|
||||||
|
|
||||||
socket.on('speak', function(json) {
|
|
||||||
handle_message(json)
|
|
||||||
})
|
|
||||||
|
|
||||||
socket.on('catchup', function(json) {
|
|
||||||
for (const message of json) {
|
|
||||||
const existing = document.getElementById(message['id'])
|
|
||||||
if (existing) break
|
|
||||||
handle_message(message)
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
|
|
||||||
function send() {
|
function send() {
|
||||||
|
@ -190,10 +172,10 @@ function quote(t) {
|
||||||
const text = t.parentElement.getElementsByClassName("text")[0].innerHTML.replace(/\*/g,"\\*").split('\n').pop()
|
const text = t.parentElement.getElementsByClassName("text")[0].innerHTML.replace(/\*/g,"\\*").split('\n').pop()
|
||||||
document.getElementById('QuotedMessage').innerHTML = text
|
document.getElementById('QuotedMessage').innerHTML = text
|
||||||
|
|
||||||
const username = t.parentElement.parentElement.getElementsByClassName('userlink')[0].innerHTML
|
const username = t.parentElement.parentElement.parentElement.parentElement.getElementsByClassName('userlink')[0].innerHTML
|
||||||
document.getElementById('QuotedUser').innerHTML = username
|
document.getElementById('QuotedUser').innerHTML = username
|
||||||
|
|
||||||
const id = t.parentElement.parentElement.parentElement.parentElement.id
|
const id = t.parentElement.parentElement.parentElement.id
|
||||||
document.getElementById('quotes_id').value = id
|
document.getElementById('quotes_id').value = id
|
||||||
document.getElementById('QuotedMessageLink').href = `#${id}`
|
document.getElementById('QuotedMessageLink').href = `#${id}`
|
||||||
|
|
||||||
|
|
|
@ -31,8 +31,8 @@ muted = cache.get(f'muted') or {
|
||||||
f'{SITE_FULL}/admin/chat': {}
|
f'{SITE_FULL}/admin/chat': {}
|
||||||
}
|
}
|
||||||
messages = cache.get(f'messages') or {
|
messages = cache.get(f'messages') or {
|
||||||
f'{SITE_FULL}/chat': [],
|
f'{SITE_FULL}/chat': {},
|
||||||
f'{SITE_FULL}/admin/chat': []
|
f'{SITE_FULL}/admin/chat': {}
|
||||||
}
|
}
|
||||||
|
|
||||||
@app.get("/chat")
|
@app.get("/chat")
|
||||||
|
@ -41,12 +41,12 @@ messages = cache.get(f'messages') or {
|
||||||
def chat(v):
|
def chat(v):
|
||||||
if not v.admin_level and TRUESCORE_CHAT_MINIMUM and v.truescore < TRUESCORE_CHAT_MINIMUM:
|
if not v.admin_level and TRUESCORE_CHAT_MINIMUM and v.truescore < TRUESCORE_CHAT_MINIMUM:
|
||||||
abort(403, f"Need at least {TRUESCORE_CHAT_MINIMUM} truescore for access to chat.")
|
abort(403, f"Need at least {TRUESCORE_CHAT_MINIMUM} truescore for access to chat.")
|
||||||
return render_template("chat.html", v=v)
|
return render_template("chat.html", v=v, messages=messages[request.url])
|
||||||
|
|
||||||
@app.get("/admin/chat")
|
@app.get("/admin/chat")
|
||||||
@admin_level_required(2)
|
@admin_level_required(2)
|
||||||
def admin_chat(v):
|
def admin_chat(v):
|
||||||
return render_template("chat.html", v=v)
|
return render_template("chat.html", v=v, messages=messages[request.url])
|
||||||
|
|
||||||
@socketio.on('speak')
|
@socketio.on('speak')
|
||||||
@limiter.limit("3/second;10/minute")
|
@limiter.limit("3/second;10/minute")
|
||||||
|
@ -78,8 +78,8 @@ def speak(data, v):
|
||||||
|
|
||||||
text_html = sanitize(text, count_marseys=True)
|
text_html = sanitize(text, count_marseys=True)
|
||||||
quotes = data['quotes']
|
quotes = data['quotes']
|
||||||
|
id = str(uuid.uuid4())
|
||||||
data = {
|
data = {
|
||||||
"id": str(uuid.uuid4()),
|
|
||||||
"quotes": quotes,
|
"quotes": quotes,
|
||||||
"hat": v.hat_active(v)[0],
|
"hat": v.hat_active(v)[0],
|
||||||
"user_id": v.id,
|
"user_id": v.id,
|
||||||
|
@ -95,7 +95,7 @@ def speak(data, v):
|
||||||
emit('speak', data)
|
emit('speak', data)
|
||||||
else:
|
else:
|
||||||
emit('speak', data, room=request.referrer, broadcast=True)
|
emit('speak', data, room=request.referrer, broadcast=True)
|
||||||
messages[request.referrer].append(data)
|
messages[request.referrer][id] = data
|
||||||
messages[request.referrer] = messages[request.referrer][-500:]
|
messages[request.referrer] = messages[request.referrer][-500:]
|
||||||
|
|
||||||
if v.admin_level >= PERMS['USER_BAN']:
|
if v.admin_level >= PERMS['USER_BAN']:
|
||||||
|
@ -136,7 +136,6 @@ def connect(v):
|
||||||
online.append(v.username)
|
online.append(v.username)
|
||||||
refresh_online()
|
refresh_online()
|
||||||
|
|
||||||
emit('catchup', messages[request.referrer], room=request.referrer)
|
|
||||||
emit('typing', typing[request.referrer], room=request.referrer)
|
emit('typing', typing[request.referrer], room=request.referrer)
|
||||||
return '', 204
|
return '', 204
|
||||||
|
|
||||||
|
@ -174,9 +173,9 @@ def typing_indicator(data, v):
|
||||||
@limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID)
|
@limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID)
|
||||||
@admin_level_required(PERMS['POST_COMMENT_MODERATION'])
|
@admin_level_required(PERMS['POST_COMMENT_MODERATION'])
|
||||||
def delete(id, v):
|
def delete(id, v):
|
||||||
for message in messages[request.referrer]:
|
for k, val in messages[request.referrer].items():
|
||||||
if message['id'] == id:
|
if k == id:
|
||||||
messages[request.referrer].remove(message)
|
del messages[request.referrer][k]
|
||||||
break
|
break
|
||||||
|
|
||||||
emit('delete', id, room=request.referrer, broadcast=True)
|
emit('delete', id, room=request.referrer, broadcast=True)
|
||||||
|
|
|
@ -22,37 +22,79 @@
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="chat-line-template" class="d-none">
|
{% macro chat_group_template(id, m) %}
|
||||||
<div class="chat-line">
|
<div class="chat-group">
|
||||||
<div class="d-flex align-items-center">
|
<div class="avatar profile-pic-20-wrapper">
|
||||||
<div class="pl-md-3 text-muted chat-line-content">
|
<img class="avatar-pic pp20 mr-1" {% if m %}src="/pp/{{m['user_id']}}"{% endif %}>
|
||||||
<div class="avatar profile-pic-20-wrapper">
|
<img class="avatar-hat profile-pic-20-hat hat" loading="lazy" {% if m %}src="{{m['hat']}}"{% endif %}>
|
||||||
<img class="avatar-pic pp20 mr-1">
|
</div>
|
||||||
<img class="avatar-hat profile-pic-20-hat hat" loading="lazy">
|
<a class="font-weight-bold text-black userlink" target="_blank" {% if m %}style="color:#{{m['namecolor']}}" href="/@{{m['username']}}" {% endif %}>
|
||||||
</div>
|
{% if m %}{{m['username']}}{% endif %}
|
||||||
<a href="" class="font-weight-bold text-black userlink" target="_blank"></a>
|
</a>
|
||||||
<span class="text-black time ml-1 mb-3 d-none text-center">just now</span>
|
<span class="text-black time ml-1 mb-3 text-center">{% if m %}{{m['time'] | timestamp}}{% else %}just now{% endif %}</span>
|
||||||
<div class="cdiv">
|
{% endmacro %}
|
||||||
<div class="d-none quotes" style="font-size:12px">
|
|
||||||
<a class="QuotedMessageLink">
|
|
||||||
<i class="fas fa-reply"></i> <span class="text-primary">@<span class="QuotedUser"></span></span>: <em class="QuotedMessage"></em>
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<span class="chat-message text-black text-break"></span>
|
{% macro chat_line_template(id, m) %}
|
||||||
<span class="text d-none"></span>
|
<div class="chat-line" {% if m %}id="{{id}}"{% endif %}>
|
||||||
{% if v.admin_level > 1 %}
|
<div class="d-flex align-items-center">
|
||||||
<i class="btn del fas fa-trash-alt"></i>
|
<div class="text-muted chat-line-content">
|
||||||
<i class="btn d-none del delmsg fas fa-trash-alt text-danger" data-nonce="{{g.nonce}}" data-onclick="del(this)"></i>
|
<div class="{% if not (m and m['quotes']) %}d-none{% endif %} quotes" style="font-size:12px">
|
||||||
{% endif %}
|
<a class="QuotedMessageLink" {% if m and m['quotes'] %}href="#{{m['quotes']}}"{% endif %}>
|
||||||
<i class="quote btn fas fa-reply" data-nonce="{{g.nonce}}" data-onclick="quote(this)"></i>
|
<i class="fas fa-reply"></i>
|
||||||
|
<span class="text-primary">@
|
||||||
|
<span class="QuotedUser">
|
||||||
|
{% if m and m['quotes'] %}{{messages[m['quotes']]['username']}}{% endif %}
|
||||||
|
</span>
|
||||||
|
</span>:
|
||||||
|
<em class="QuotedMessage">
|
||||||
|
{% if m and m['quotes'] %}{{messages[m['quotes']]['text']}}{% endif %}
|
||||||
|
</em>
|
||||||
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<span class="chat-message text-black text-break">
|
||||||
|
{% if m %}
|
||||||
|
{% if v.slurreplacer %}
|
||||||
|
{{m['text_censored'] | safe}}
|
||||||
|
{% else %}
|
||||||
|
{{m['text_html'] | safe}}
|
||||||
|
{% endif %}
|
||||||
|
{% endif %}
|
||||||
|
</span>
|
||||||
|
<span class="text d-none">{% if m %}{{m['text']}}{% endif %}</span>
|
||||||
|
{% if v.admin_level > 1 %}
|
||||||
|
<i class="btn del fas fa-trash-alt"></i>
|
||||||
|
<i class="btn d-none del delmsg fas fa-trash-alt text-danger" data-nonce="{{g.nonce}}" data-onclick="del(this)"></i>
|
||||||
|
{% endif %}
|
||||||
|
<i class="quote btn fas fa-reply" data-nonce="{{g.nonce}}" data-onclick="quote(this)"></i>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
{% endmacro %}
|
||||||
|
|
||||||
|
|
||||||
|
<div id="chat-group-template" class="d-none">
|
||||||
|
{{chat_group_template()}}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div id="chat-line-template" class="d-none">
|
||||||
|
{{chat_line_template()}}
|
||||||
|
</div>
|
||||||
|
|
||||||
<div id="shrink">
|
<div id="shrink">
|
||||||
<div id="chat-window" class="container pl-0 py-0">
|
<div id="chat-window" class="container pl-0 py-0">
|
||||||
|
{% for id, m in messages.items() %}
|
||||||
|
{% set previous = m %}
|
||||||
|
{% if not (loop.index > 1 and m['user_id'] == previous['user_id']) %}
|
||||||
|
{% if loop.index > 1 %}
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
{{chat_group_template(id, m)}}
|
||||||
|
{% endif %}
|
||||||
|
{{chat_line_template(id, m)}}
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="mt-3"></div>
|
<div class="mt-3"></div>
|
||||||
|
@ -80,7 +122,7 @@
|
||||||
</label>
|
</label>
|
||||||
</span>
|
</span>
|
||||||
|
|
||||||
<textarea data-nonce="{{g.nonce}}" data-onclick="scroll_chat()" id="input-text" minlength="1" maxlength="{% if SITE == 'rdrama.net' %}200{% else %}1000{% endif %}" style="font-size:16px!important" class="form-control" placeholder="Message" autocomplete="off" autofocus rows="1"></textarea>
|
<textarea id="input-text" minlength="1" maxlength="{% if SITE == 'rdrama.net' %}200{% else %}1000{% endif %}" {% if g.browser == "apple" %}style="font-size:16px!important"{% endif %} class="form-control" placeholder="Message" autocomplete="off" autofocus rows="1"></textarea>
|
||||||
|
|
||||||
<i id="chatsend" data-nonce="{{g.nonce}}" data-onclick="send()" class="btn btn-secondary fas fa-reply ml-3 my-auto" type="submit" data-nonce="{{g.nonce}}" data-onclick="disable(this)" style="transform:rotateY(180deg);font-size:1.3rem!important"></i>
|
<i id="chatsend" data-nonce="{{g.nonce}}" data-onclick="send()" class="btn btn-secondary fas fa-reply ml-3 my-auto" type="submit" data-nonce="{{g.nonce}}" data-onclick="disable(this)" style="transform:rotateY(180deg);font-size:1.3rem!important"></i>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -59,7 +59,7 @@
|
||||||
'/h/'+sub.name, sub.sidebar if sub.sidebar %}
|
'/h/'+sub.name, sub.sidebar if sub.sidebar %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
<link rel="icon" id="icon" type="image/webp" href="/icon.webp?v=1">
|
<link rel="icon" type="image/webp" href="/icon.webp?v=1">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
||||||
<meta name="thumbnail" content="{{'site_preview.webp' | asset_siteimg}}">
|
<meta name="thumbnail" content="{{'site_preview.webp' | asset_siteimg}}">
|
||||||
<meta name="description" content="{{DESCRIPTION}}">
|
<meta name="description" content="{{DESCRIPTION}}">
|
||||||
|
|
Loading…
Reference in New Issue