message list element implemented; needs styling and to fix bonks
This commit is contained in:
parent
51bd3a6505
commit
5b20ff3135
4 changed files with 129 additions and 18 deletions
|
@ -14,7 +14,7 @@ export class AuthorMessagesElement extends HTMLElement {
|
|||
|
||||
constructor() {
|
||||
super();
|
||||
this.innerHTML = "<ul class='author_msglist'></ul>"
|
||||
this.innerHTML = `<ul class="messages_list"></ul>`;
|
||||
}
|
||||
|
||||
connectedCallback() {
|
||||
|
@ -49,14 +49,45 @@ export class AuthorMessagesElement extends HTMLElement {
|
|||
}
|
||||
let msg = datastore.messages.get(next);
|
||||
if (msg) {
|
||||
// if _messages has this one, and this updated date is greater
|
||||
const existingIdx = this._messages.findIndex(m=>m.id == msg.id && ((m.edited ?? 0) < (msg.edited ?? 0)));
|
||||
const existingIdx = this._messages.findIndex(m=>m.id == msg.id && ((m.edited ?? m.created) < (msg.edited ?? msg.created)));
|
||||
|
||||
// first we update the backing data store
|
||||
if (existingIdx >= 0) {
|
||||
this._messages[existingIdx] = msg;
|
||||
// and update it in the dom
|
||||
} else {
|
||||
} else if (!this._messages.some(m=>m.id == msg.id)) {
|
||||
this._messages.push(msg);
|
||||
// and insert in into the dom
|
||||
}
|
||||
|
||||
|
||||
const ul = this.children[0];
|
||||
if (ul) {
|
||||
// first pass through the dom, try to update a message if it's there
|
||||
for (let i = 0; i < ul.childElementCount; i++){
|
||||
const id = ul.children[i]?.children[0]?.getAttribute("data-target");
|
||||
const ogMsg = this._messages.find(m=>m.id == id);
|
||||
if (ogMsg && existingIdx >= 0) {
|
||||
ul.children[i]?.children[0]?.setAttribute("data-latest", id ?? "");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// if we made it this far, let's create a node
|
||||
const e = document.createElement("li");
|
||||
e.innerHTML = `<underbbs-message data-adapter="${this._adapter}" data-target="${next}"></underbbs-message>`
|
||||
// second pass, try to place it in reverse-chronological order
|
||||
for (let i = 0; i < ul.childElementCount; i++){
|
||||
const id = ul.children[i]?.children[0]?.getAttribute("data-target");
|
||||
const ogMsg = this._messages.find(m=>m.id == id);
|
||||
if (ogMsg && ogMsg.created < msg.created) {
|
||||
ul.insertBefore(e, ul.children[i])
|
||||
e.children[0].setAttribute("data-latest", next);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// final pass, we must be the earliest child (or maybe the first one to be rendered)
|
||||
ul.append(e);
|
||||
e.children[0].setAttribute("data-latest", next);
|
||||
}
|
||||
console.log(JSON.stringify(this._messages));
|
||||
}
|
||||
|
|
|
@ -15,11 +15,8 @@ function main() {
|
|||
const saveData = localStorage.getItem("underbbs_settings");
|
||||
Settings._instance = saveData ? <Settings>JSON.parse(saveData) : new Settings();
|
||||
|
||||
customElements.define("underbbs-tabbar", TabBarElement);
|
||||
customElements.define("underbbs-message", MessageElement);
|
||||
customElements.define("underbbs-settings", SettingsElement);
|
||||
customElements.define("underbbs-adapter", AdapterElement);
|
||||
customElements.define("underbbs-thread-summary", ThreadSummaryElement);
|
||||
customElements.define("underbbs-profile", ProfileElement);
|
||||
customElements.define("underbbs-author-messages", AuthorMessagesElement);
|
||||
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
import util from "./util"
|
||||
var _ = util._
|
||||
import { Message } from "./message"
|
||||
import { BatchTimer } from "./batch-timer"
|
||||
import { AdapterState } from "./adapter"
|
||||
|
||||
export class MessageElement extends HTMLElement {
|
||||
static observedAttributes = [ "data-target", "data-latest", "data-adapter", "data-replyCt", "data-reactionCt", "data-boostCt" ]
|
||||
|
@ -7,20 +9,101 @@ export class MessageElement extends HTMLElement {
|
|||
private _id: string | null = null;
|
||||
private _adapter: string | null = null;
|
||||
|
||||
private _message: Message | null = null;
|
||||
|
||||
private _messageTimer: BatchTimer | null = null;
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
this.innerHTML = `<div class="message_metadata"></div><div class="message_content"></div><div class="message_attachments"></div>`
|
||||
}
|
||||
|
||||
connectedCallback() {
|
||||
this._id = this.getAttribute("data-target");
|
||||
this._adapter = this.getAttribute("data-adapter");
|
||||
|
||||
// grab message content from the store and format our innerHTML
|
||||
const gateway = this.getAttribute("data-gateway") ?? "";
|
||||
this._messageTimer = new BatchTimer((ids: string[])=>{
|
||||
let url = `${gateway}/api/adapters/${this._adapter}/fetch?entity_type=message`;
|
||||
for (let id of ids) {
|
||||
url += `&entity_id=${id}`;
|
||||
}
|
||||
util.authorizedFetch("GET", url, null);
|
||||
});
|
||||
}
|
||||
|
||||
attributeChangedCallback(attr: string, prev: string, next: string) {
|
||||
switch (attr) {
|
||||
case "data-target":
|
||||
if (!next) {
|
||||
return
|
||||
}
|
||||
this._id = next;
|
||||
if (this._messageTimer) {
|
||||
this._messageTimer.queue(next, 100);
|
||||
}
|
||||
break;
|
||||
case "data-latest":
|
||||
let datastore = AdapterState._instance.data.get(this._adapter ?? "");
|
||||
if (!datastore) {
|
||||
console.log("no data yet, wait for some to come in maybe...");
|
||||
return;
|
||||
}
|
||||
let msg = datastore.messages.get(next);
|
||||
console.log("MessageElement.attributeChangedCallback: " + JSON.stringify(msg));
|
||||
if (msg) {
|
||||
this._message = msg;
|
||||
const metadata = this.querySelector(".message_metadata");
|
||||
const content = this.querySelector(".message_content");
|
||||
const attachments = this.querySelector(".message_attachments");
|
||||
if (metadata) {
|
||||
metadata.innerHTML = `<span class="message_author">${this._message.author}</span><span class="message_timestamp">${new Date(this._message.created)}</span><span class="message_visibility">${this._message.visibility}</span><span class="message_protocol">${this._message.protocol}</span>`
|
||||
}
|
||||
if (content) {
|
||||
content.innerHTML = this._message.content;
|
||||
}
|
||||
if (attachments && this._message.attachments.length > 0) {
|
||||
let html = "<ul>";
|
||||
for (const a of this._message.attachments) {
|
||||
// we can do it based on actual mimetype later but now let's just do an extension check
|
||||
const srcUrl = new URL(a.src);
|
||||
const pathParts = srcUrl.pathname.split(".");
|
||||
if (pathParts.length < 2) {
|
||||
html += `<li><a href="${a.src}">${a.desc}</a></li>`
|
||||
continue;
|
||||
}
|
||||
const ext = pathParts[pathParts.length - 1];
|
||||
switch (ext.toLowerCase()) {
|
||||
case "jpg":
|
||||
case "jpeg":
|
||||
case "png":
|
||||
case "gif":
|
||||
case "avif":
|
||||
case "svg":
|
||||
case "bmp":
|
||||
html += `<li><a href="${a.src}"><img src="${a.src}" alt="${a.desc}"/></a>`
|
||||
break;
|
||||
case "mp3":
|
||||
case "wav":
|
||||
case "ogg":
|
||||
case "opus":
|
||||
case "aac":
|
||||
case "flac":
|
||||
html += `<li><audio src="${a.src}" controls preload="metadata"><a href="${a.src}">${a.desc}</a></audio></li>`
|
||||
break;
|
||||
case "mp4":
|
||||
case "mkv":
|
||||
case "avi":
|
||||
case "mov":
|
||||
html += `<li><video src="${a.src}" controls preload="metadata"><a href="${a.src}">${a.desc}</a></video></li>`
|
||||
break;
|
||||
default:
|
||||
html += `<li><a href="${a.src}">${a.desc}</a></li>`
|
||||
}
|
||||
}
|
||||
html += "</ul>";
|
||||
attachments.innerHTML = html;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -27,10 +27,10 @@ export class Author {
|
|||
}
|
||||
|
||||
export class Attachment {
|
||||
public Src: string = "";
|
||||
public ThumbSrc: string = "";
|
||||
public Desc: string = "";
|
||||
public CreatedAt: Date = new Date();
|
||||
public src: string = "";
|
||||
public thumbSrc: string = "";
|
||||
public desc: string = "";
|
||||
public createdAt: Date = new Date();
|
||||
}
|
||||
|
||||
export default { Message, Attachment, Author }
|
Loading…
Reference in a new issue