forked from MarseyWorld/MarseyWorld
another chat rework
parent
51808b6f40
commit
1ee213f742
|
@ -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 |
|
@ -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}`
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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}}">
|
||||
|
|
Loading…
Reference in New Issue