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