`;
}
connectedCallback() {
@@ -49,16 +49,47 @@ 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
- }
- console.log(JSON.stringify(this._messages));
+ }
+
+
+ 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 = ``
+ // 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));
}
}
}
diff --git a/frontend/ts/index.ts b/frontend/ts/index.ts
index 9e065bf..a8a894d 100644
--- a/frontend/ts/index.ts
+++ b/frontend/ts/index.ts
@@ -15,11 +15,8 @@ function main() {
const saveData = localStorage.getItem("underbbs_settings");
Settings._instance = saveData ? 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);
diff --git a/frontend/ts/message-element.ts b/frontend/ts/message-element.ts
index d34907e..9e9a84c 100644
--- a/frontend/ts/message-element.ts
+++ b/frontend/ts/message-element.ts
@@ -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 = ``
}
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 = `${this._message.author}${new Date(this._message.created)}${this._message.visibility}${this._message.protocol}`
+ }
+ if (content) {
+ content.innerHTML = this._message.content;
+ }
+ if (attachments && this._message.attachments.length > 0) {
+ let html = "
";
+ 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 += `