another chat rework

pull/90/head
Aevann 2023-01-22 04:43:28 +02:00
parent 51808b6f40
commit 1ee213f742
9 changed files with 93 additions and 70 deletions

View File

@ -26,7 +26,7 @@
}
.chat-mention {
background-color: #{{v.themecolor}}55;
background-color: #ffffff44;
border-radius: 3px;
}
@ -68,7 +68,7 @@ p {
width: 100%;
}
.cdiv {
.chat-line {
overflow: hidden;
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

View File

@ -26,7 +26,8 @@ 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 icon = document.querySelector("link[rel~='icon']")
const vid = document.getElementById('vid').value
const vusername = document.getElementById('vusername').value
const site_name = document.getElementById('site_name').value
@ -42,17 +43,17 @@ function flash(){
if (notifs >= 1 && !focused){
title.innerHTML = `[+${notifs}] Chat`;
if (alert) {
icon.href = escapeHTML(`/assets/images/${site_name}/alert.webp?v=3`)
icon.href = `/i/${site_name}/alert.ico?v=3009`
alert=false;
}
else {
icon.href = escapeHTML(`/assets/images/${site_name}/icon.webp?v=3009`)
icon.href = `/i/${site_name}/icon.webp?v=3009`
alert=true;
}
setTimeout(flash, 500)
}
else {
icon.href = escapeHTML(`/assets/images/${site_name}/icon.webp?v=3009`)
icon.href = `/i/${site_name}/icon.webp?v=3009`
notifs = 0
title.innerHTML = 'Chat';
}
@ -64,11 +65,11 @@ function flash(){
}
function handle_message(json) {
socket.on('speak', function(json) {
let text = json['text']
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']
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 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')
if (last_user != json['username']) {
document.getElementsByClassName('avatar-pic')[0].src = '/pp/' + json["user_id"]
if (json['hat'])
document.getElementsByClassName('avatar-hat')[0].src = json['hat'] + "?h=7"
else
@ -103,7 +98,8 @@ function handle_message(json) {
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('userlink')[0].innerHTML = json['username']
if (Date.now() - json['time']*1000 > 5000)
document.getElementsByClassName('time')[0].innerHTML = timeSince(json['time']*1000) + ' ago'
else
@ -111,7 +107,6 @@ function handle_message(json) {
}
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, '')
@ -121,7 +116,7 @@ function handle_message(json) {
if (quoted) {
document.getElementsByClassName('quotes')[0].classList.remove("d-none")
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
}
}
@ -133,26 +128,13 @@ function handle_message(json) {
box.querySelector('.chat-group:last-child').append(line)
}
else {
const chatgroup = document.createElement("div");
chatgroup.className = "chat-group";
const chatgroup = document.getElementsByClassName('chat-group')[0].cloneNode(true)
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) {
const existing = document.getElementById(message['id'])
if (existing) break
handle_message(message)
}
})
function send() {
@ -190,10 +172,10 @@ function quote(t) {
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
const username = t.parentElement.parentElement.parentElement.parentElement.getElementsByClassName('userlink')[0].innerHTML
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('QuotedMessageLink').href = `#${id}`

View File

@ -31,8 +31,8 @@ muted = cache.get(f'muted') or {
f'{SITE_FULL}/admin/chat': {}
}
messages = cache.get(f'messages') or {
f'{SITE_FULL}/chat': [],
f'{SITE_FULL}/admin/chat': []
f'{SITE_FULL}/chat': {},
f'{SITE_FULL}/admin/chat': {}
}
@app.get("/chat")
@ -41,12 +41,12 @@ messages = cache.get(f'messages') or {
def chat(v):
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.")
return render_template("chat.html", v=v)
return render_template("chat.html", v=v, messages=messages[request.url])
@app.get("/admin/chat")
@admin_level_required(2)
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')
@limiter.limit("3/second;10/minute")
@ -78,8 +78,8 @@ def speak(data, v):
text_html = sanitize(text, count_marseys=True)
quotes = data['quotes']
id = str(uuid.uuid4())
data = {
"id": str(uuid.uuid4()),
"quotes": quotes,
"hat": v.hat_active(v)[0],
"user_id": v.id,
@ -95,7 +95,7 @@ def speak(data, v):
emit('speak', data)
else:
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:]
if v.admin_level >= PERMS['USER_BAN']:
@ -136,7 +136,6 @@ def connect(v):
online.append(v.username)
refresh_online()
emit('catchup', messages[request.referrer], room=request.referrer)
emit('typing', typing[request.referrer], room=request.referrer)
return '', 204
@ -174,9 +173,9 @@ def typing_indicator(data, v):
@limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID)
@admin_level_required(PERMS['POST_COMMENT_MODERATION'])
def delete(id, v):
for message in messages[request.referrer]:
if message['id'] == id:
messages[request.referrer].remove(message)
for k, val in messages[request.referrer].items():
if k == id:
del messages[request.referrer][k]
break
emit('delete', id, room=request.referrer, broadcast=True)

View File

@ -22,37 +22,79 @@
</span>
</div>
<div id="chat-line-template" class="d-none">
<div class="chat-line">
<div class="d-flex align-items-center">
<div class="pl-md-3 text-muted chat-line-content">
<div class="avatar profile-pic-20-wrapper">
<img class="avatar-pic pp20 mr-1">
<img class="avatar-hat profile-pic-20-hat hat" loading="lazy">
</div>
<a href="" class="font-weight-bold text-black userlink" target="_blank"></a>
<span class="text-black time ml-1 mb-3 d-none text-center">just now</span>
<div class="cdiv">
<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>
{% macro chat_group_template(id, m) %}
<div class="chat-group">
<div class="avatar profile-pic-20-wrapper">
<img class="avatar-pic pp20 mr-1" {% if m %}src="/pp/{{m['user_id']}}"{% endif %}>
<img class="avatar-hat profile-pic-20-hat hat" loading="lazy" {% if m %}src="{{m['hat']}}"{% endif %}>
</div>
<a class="font-weight-bold text-black userlink" target="_blank" {% if m %}style="color:#{{m['namecolor']}}" href="/@{{m['username']}}" {% endif %}>
{% if m %}{{m['username']}}{% endif %}
</a>
<span class="text-black time ml-1 mb-3 text-center">{% if m %}{{m['time'] | timestamp}}{% else %}just now{% endif %}</span>
{% endmacro %}
<span class="chat-message text-black text-break"></span>
<span class="text d-none"></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>
{% macro chat_line_template(id, m) %}
<div class="chat-line" {% if m %}id="{{id}}"{% endif %}>
<div class="d-flex align-items-center">
<div class="text-muted chat-line-content">
<div class="{% if not (m and m['quotes']) %}d-none{% endif %} quotes" style="font-size:12px">
<a class="QuotedMessageLink" {% if m and m['quotes'] %}href="#{{m['quotes']}}"{% endif %}>
<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>
<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>
{% endmacro %}
<div id="chat-group-template" class="d-none">
{{chat_group_template()}}
</div>
</div>
<div id="chat-line-template" class="d-none">
{{chat_line_template()}}
</div>
<div id="shrink">
<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 class="mt-3"></div>
@ -80,7 +122,7 @@
</label>
</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>
</div>

View File

@ -59,7 +59,7 @@
'/h/'+sub.name, sub.sidebar if sub.sidebar %}
{% 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="thumbnail" content="{{'site_preview.webp' | asset_siteimg}}">
<meta name="description" content="{{DESCRIPTION}}">