New stuff.
This commit is contained in:
parent
1807cff67d
commit
5b78165fb7
153
src/snek/templates/threads.html
Normal file
153
src/snek/templates/threads.html
Normal file
@ -0,0 +1,153 @@
|
||||
{% extends "app.html" %}
|
||||
|
||||
{% block main %}
|
||||
<section class="chat-area" id="chat">
|
||||
<div class="chat-header">
|
||||
<h2>?</h2>
|
||||
</div>
|
||||
<div class="chat-messages">
|
||||
{% for thread in threads %}
|
||||
{% autoescape false %}
|
||||
<div style="max-width:100%;" data-uid="{{thread.uid}}" data-color="{{thread.last_message_user_color}}" data-channel_uid="{{thread.uid}}"
|
||||
data-user_nick="{{last_message_user_nick}}" data-created_at="{{thread.created_at}}" data-user_uid="{{user_uid}}"
|
||||
class="message">
|
||||
<div class="avatar" style="background-color: {{thread.last_message_user_color}}; color: black;"><img
|
||||
src="/avatar/{{thread.last_message_user_uid}}.svg" /></div>
|
||||
<div class="message-content">
|
||||
<div class="author" style="color: {{thread.last_message_user_color}};">{{thread.last_message_user_nick}}</div>
|
||||
<div class="text">{% autoescape false %}{% emoji %}{% linkify %}{% markdown %}{% autoescape false %}{{ thread.last_message_text }}{%raw %} {% endraw%}{%endautoescape%}{% endmarkdown %}{% endlinkify %}{% endemoji %}{%
|
||||
endautoescape %}</div>
|
||||
<div class="time no-select" data-created_at="{{thread.created_at}}"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% endautoescape %}
|
||||
{% endfor %}
|
||||
</div>
|
||||
<chat-window style="display:none" class="chat-area"></chat-window>
|
||||
</section>
|
||||
|
||||
<script>
|
||||
|
||||
function updateTimes() {
|
||||
document.querySelectorAll(".time").forEach((time) => {
|
||||
time.innerText = app.timeDescription(time.dataset.created_at);
|
||||
});
|
||||
}
|
||||
|
||||
function isElementVisible(element) {
|
||||
const rect = element.getBoundingClientRect();
|
||||
return (
|
||||
rect.top >= 0 &&
|
||||
rect.left >= 0 &&
|
||||
rect.bottom <= (window.innerHeight || document.documentElement.clientHeight) &&
|
||||
rect.right <= (window.innerWidth || document.documentElement.clientWidth)
|
||||
);
|
||||
}
|
||||
|
||||
const messagesContainer = document.querySelector(".chat-messages");
|
||||
|
||||
function isScrolledPastHalf() {
|
||||
let scrollTop = messagesContainer.scrollTop;
|
||||
let scrollableHeight = messagesContainer.scrollHeight - messagesContainer.clientHeight;
|
||||
|
||||
if (scrollTop < scrollableHeight / 2) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
let isLoadingExtra = false;
|
||||
|
||||
async function loadExtra() {
|
||||
const firstMessage = messagesContainer.querySelector(".message:first-child");
|
||||
if (isLoadingExtra) {
|
||||
return;
|
||||
}
|
||||
if (!isScrolledPastHalf()) {
|
||||
return;
|
||||
}
|
||||
|
||||
isLoadingExtra = true;
|
||||
|
||||
const messages = await app.rpc.getMessages(channelUid, 0, firstMessage.dataset.created_at);
|
||||
|
||||
messages.forEach((message) => {
|
||||
firstMessage.insertAdjacentHTML("beforebegin", message.html);
|
||||
})
|
||||
updateLayout(false);
|
||||
|
||||
isLoadingExtra = false;
|
||||
}
|
||||
|
||||
messagesContainer.addEventListener("scroll", () => {
|
||||
loadExtra();
|
||||
});
|
||||
|
||||
function updateLayout(doScrollDown) {
|
||||
const messagesContainer = document.querySelector(".chat-messages");
|
||||
updateTimes();
|
||||
let previousUser = null;
|
||||
document.querySelectorAll(".message").forEach((message) => {
|
||||
if (previousUser !== message.dataset.user_uid) {
|
||||
message.classList.add("switch-user");
|
||||
previousUser = message.dataset.user_uid;
|
||||
} else {
|
||||
message.classList.remove("switch-user");
|
||||
}
|
||||
});
|
||||
lastMessage = messagesContainer.querySelector(".message:last-child");
|
||||
if (doScrollDown) {
|
||||
lastMessage.scrollIntoView({ inline: "nearest" });
|
||||
}
|
||||
}
|
||||
|
||||
setInterval(updateTimes, 1000);
|
||||
|
||||
function isMentionToMe(message) {
|
||||
const mentionText = '@{{ user.username.value }}';
|
||||
return message.toLowerCase().includes(mentionText);
|
||||
}
|
||||
function extractMentions(message) {
|
||||
return [...new Set(message.match(/@\w+/g) || [])];
|
||||
}
|
||||
function isMentionForSomeoneElse(message) {
|
||||
const mentions = extractMentions(message);
|
||||
const mentionText = '@{{ user.username.value }}';
|
||||
return mentions.length > 0 && mentions.indexOf(mentionText) == -1;
|
||||
}
|
||||
|
||||
app.addEventListener("channel-message", (data) => {
|
||||
if (data.channel_uid !== channelUid) {
|
||||
if (!isMentionForSomeoneElse(data.message)) {
|
||||
channelSidebar.notify(data);
|
||||
app.playSound("messageOtherChannel");
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
if (data.username !== "{{ user.username.value }}") {
|
||||
if (isMentionToMe(data.message)) {
|
||||
app.playSound("mention");
|
||||
} else if (!isMentionForSomeoneElse(data.message)) {
|
||||
app.playSound("message");
|
||||
}
|
||||
}
|
||||
|
||||
const messagesContainer = document.querySelector(".chat-messages");
|
||||
const lastMessage = messagesContainer.querySelector(".message:last-child");
|
||||
const doScrollDownBecauseLastMessageIsVisible = !lastMessage || isElementVisible(lastMessage);
|
||||
|
||||
const message = document.createElement("div");
|
||||
message.innerHTML = data.html;
|
||||
document.querySelector(".chat-messages").appendChild(message.firstChild);
|
||||
updateLayout(doScrollDownBecauseLastMessageIsVisible);
|
||||
setTimeout(() => {
|
||||
updateLayout(doScrollDownBecauseLastMessageIsVisible)
|
||||
}, 1000);
|
||||
});
|
||||
|
||||
initInputField(document.querySelector("textarea"));
|
||||
updateLayout(true);
|
||||
</script>
|
||||
{% endblock %}
|
31
src/snek/view/threads.py
Normal file
31
src/snek/view/threads.py
Normal file
@ -0,0 +1,31 @@
|
||||
from snek.system.view import BaseView
|
||||
|
||||
class ThreadsView(BaseView):
|
||||
|
||||
async def get(self):
|
||||
threads = []
|
||||
user = await self.services.user.get(uid=self.session.get("uid"))
|
||||
async for channel_member in user.get_channel_members():
|
||||
thread = {}
|
||||
channel = await self.services.channel.get(uid=channel_member["channel_uid"])
|
||||
thread["uid"] = channel['uid']
|
||||
thread["name"] = await channel_member.get_name()
|
||||
thread["new_count"] = channel_member["new_count"]
|
||||
thread["last_message_on"] = channel["last_message_on"]
|
||||
thread['created_at'] = thread['last_message_on']
|
||||
last_message = await channel.get_last_message()
|
||||
if last_message:
|
||||
thread["last_message_text"] = last_message["message"]
|
||||
thread['last_message_user_uid'] = last_message["user_uid"]
|
||||
user_last_message = await self.app.services.user.get(uid=last_message["user_uid"])
|
||||
thread['last_message_user_nick'] = user_last_message["nick"]
|
||||
thread['last_message_user_color'] = user_last_message['color']
|
||||
else:
|
||||
thread["last_message_text"] = None
|
||||
thread['last_message_user_uid'] = None
|
||||
thread['last_message_user_nick'] = None
|
||||
thread['last_message_user_color'] = None
|
||||
threads.append(thread)
|
||||
|
||||
|
||||
return await self.render_template("threads.html", dict(threads=threads,user=user))
|
Loading…
Reference in New Issue
Block a user