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