Files
snek/src/snek/static/message-list.js
T
2025-06-25 18:07:11 +02:00

117 lines
4.0 KiB
JavaScript

// Written by retoor@molodetz.nl
// This class defines a custom HTML element that displays a list of messages with avatars and timestamps. It handles message addition with a delay in event dispatch and ensures the display of messages in the correct format.
// The code seems to rely on some external dependencies like 'models.Message', 'app', and 'Schedule'. These should be imported or defined elsewhere in your application.
// MIT License: This is free software. Permission is granted to use, copy, modify, and/or distribute this software for any purpose with or without fee. The software is provided "as is" without any warranty.
import { app } from "../app.js";
class MessageList extends HTMLElement {
constructor() {
super();
app.ws.addEventListener("update_message_text", (data) => {
this.updateMessageText(data.uid, data);
});
app.ws.addEventListener("set_typing", (data) => {
this.triggerGlow(data.user_uid,data.color);
});
this.items = [];
}
connectedCallback() {
const messagesContainer = this
messagesContainer.addEventListener('click', (e) => {
if (e.target.tagName !== 'IMG' || e.target.classList.contains('avatar-img')) return;
const img = e.target;
const overlay = document.createElement('div');
overlay.style.cssText = 'position:fixed;top:0;left:0;width:100%;height:100%;background:rgba(0,0,0,0.9);display:flex;justify-content:center;align-items:center;z-index:9999;'
const urlObj = new URL(img.currentSrc || img.src)
urlObj.searchParams.delete("width");
urlObj.searchParams.delete("height");
const fullImg = document.createElement('img');
fullImg.src = urlObj.toString();
fullImg.alt = img.alt;
fullImg.style.maxWidth = '90%';
fullImg.style.maxHeight = '90%';
overlay.appendChild(fullImg);
document.body.appendChild(overlay);
overlay.addEventListener('click', () => document.body.removeChild(overlay));
})
}
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)
);
}
isScrolledToBottom() {
return this.isElementVisible(this.querySelector(".message-list-bottom"));
}
scrollToBottom(force) {
//this.scrollTop = this.scrollHeight;
this.querySelector(".message-list-bottom").scrollIntoView();
this.querySelector(".message-list-bottom").scrollIntoView();
setTimeout(() => {
// this.scrollTop = this.scrollHeight;
this.querySelector(".message-list-bottom").scrollIntoView();
},200)
}
updateMessageText(uid, message) {
const messageDiv = this.querySelector('div[data-uid="' + uid + '"]');
if (!messageDiv) {
return;
}
const scrollToBottom = this.isScrolledToBottom();
const receivedHtml = document.createElement("div");
receivedHtml.innerHTML = message.html;
const html = receivedHtml.querySelector(".text").innerHTML;
const textElement = messageDiv.querySelector(".text");
textElement.innerHTML = html;
textElement.style.display = message.text == "" ? "none" : "block";
if(scrollToBottom)
this.scrollToBottom(true)
}
triggerGlow(uid,color) {
app.starField.glowColor(color)
let lastElement = null;
this.querySelectorAll(".avatar").forEach((el) => {
const div = el.closest("a");
if (el.href.indexOf(uid) != -1) {
lastElement = el;
}
});
if (lastElement) {
lastElement.classList.add("glow");
setTimeout(() => {
lastElement.classList.remove("glow");
}, 1000);
}
}
set data(items) {
this.items = items;
this.render();
}
render() {
this.innerHTML = "";
//this.insertAdjacentHTML("beforeend", html);
}
}
customElements.define("message-list", MessageList);