import { Author, Message } from "./message" import util from "./util" import { BatchTimer } from "./batch-timer" import { AdapterState } from "./adapter" export class AuthorMessagesElement extends HTMLElement { static observedAttributes = [ "data-latest", "data-adapter", "data-target" ]; private _id: string | null = null; private _adapter: string = ""; private _messages: Message[] = []; private _byAuthorTimer: BatchTimer | null = null; constructor() { super(); this.innerHTML = ``; } connectedCallback() { this._id = this.getAttribute("data-target"); this._adapter = this.getAttribute("data-adapter") ?? ""; const gateway = this.getAttribute("data-gateway") ?? ""; this._byAuthorTimer = new BatchTimer(gateway, this._adapter, "byAuthor"); } attributeChangedCallback(attr: string, prev: string, next: string) { switch (attr) { case "data-target": if (!next) { return } this._id = next; if (this._byAuthorTimer) { this._byAuthorTimer.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); if (msg) { const existingIdx = this._messages.findIndex(m=>(m.renoteId ?? m.id) == (msg.renoteId ?? msg.id) && ((m.edited ?? m.created) < (msg.edited ?? msg.created))); // first we update the backing data store if (existingIdx >= 0) { this._messages[existingIdx] = msg; } else if (!this._messages.some(m=>(m.renoteId ?? m.id) == (msg.renoteId ?? msg.id))) { this._messages.push(msg); } 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.renoteId ?? 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 = `` // 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.renoteId ?? m.id) == id); if (ogMsg && (ogMsg.renoteTime ?? ogMsg.created) < (msg.renoteTime ?? 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); } } } } }