tildefriends/apps/ssb/tf-news.js
2024-02-24 11:09:34 -05:00

204 lines
4.9 KiB
JavaScript

import {LitElement, html, unsafeHTML, until} from './lit-all.min.js';
import * as tfrpc from '/static/tfrpc.js';
import {styles} from './tf-styles.js';
class TfNewsElement extends LitElement {
static get properties() {
return {
whoami: {type: String},
users: {type: Object},
messages: {type: Array},
following: {type: Array},
drafts: {type: Object},
expanded: {type: Object},
};
}
static styles = styles;
constructor() {
super();
let self = this;
this.whoami = null;
this.users = {};
this.messages = [];
this.following = [];
this.drafts = {};
this.expanded = {};
}
process_messages(messages) {
let self = this;
let messages_by_id = {};
console.log('processing', messages.length, 'messages');
function ensure_message(id) {
let found = messages_by_id[id];
if (found) {
return found;
} else {
let added = {
id: id,
placeholder: true,
content: '"placeholder"',
parent_message: undefined,
child_messages: [],
votes: [],
};
messages_by_id[id] = added;
return added;
}
}
function link_message(message) {
if (message.content.type === 'vote') {
let parent = ensure_message(message.content.vote.link);
if (!parent.votes) {
parent.votes = [];
}
parent.votes.push(message);
message.parent_message = message.content.vote.link;
} else if (message.content.type == 'post') {
if (message.content.root) {
if (typeof message.content.root === 'string') {
let m = ensure_message(message.content.root);
if (!m.child_messages) {
m.child_messages = [];
}
m.child_messages.push(message);
message.parent_message = message.content.root;
} else {
let m = ensure_message(message.content.root[0]);
if (!m.child_messages) {
m.child_messages = [];
}
m.child_messages.push(message);
message.parent_message = message.content.root[0];
}
}
}
}
for (let message of messages) {
message.votes = [];
message.parent_message = undefined;
message.child_messages = undefined;
}
for (let message of messages) {
try {
message.content = JSON.parse(message.content);
} catch {}
if (!messages_by_id[message.id]) {
messages_by_id[message.id] = message;
link_message(message);
} else if (messages_by_id[message.id].placeholder) {
let placeholder = messages_by_id[message.id];
messages_by_id[message.id] = message;
message.parent_message = placeholder.parent_message;
message.child_messages = placeholder.child_messages;
message.votes = placeholder.votes;
if (
placeholder.parent_message &&
messages_by_id[placeholder.parent_message]
) {
let children =
messages_by_id[placeholder.parent_message].child_messages;
children.splice(children.indexOf(placeholder), 1);
children.push(message);
}
link_message(message);
}
}
return messages_by_id;
}
update_latest_subtree_timestamp(messages) {
let latest = 0;
for (let message of messages || []) {
if (message.latest_subtree_timestamp === undefined) {
message.latest_subtree_timestamp = Math.max(
message.timestamp ?? 0,
this.update_latest_subtree_timestamp(message.child_messages)
);
}
latest = Math.max(latest, message.latest_subtree_timestamp);
}
return latest;
}
finalize_messages(messages_by_id) {
function recursive_sort(messages, top) {
if (messages) {
if (top) {
messages.sort(
(a, b) => b.latest_subtree_timestamp - a.latest_subtree_timestamp
);
} else {
messages.sort((a, b) => a.timestamp - b.timestamp);
}
for (let message of messages) {
recursive_sort(message.child_messages, false);
}
return messages.map((x) => Object.assign({}, x));
} else {
return {};
}
}
let roots = Object.values(messages_by_id).filter((x) => !x.parent_message);
this.update_latest_subtree_timestamp(roots);
return recursive_sort(roots, true);
}
group_following(messages) {
let result = [];
let group = [];
for (let message of messages) {
if (message?.content?.type === 'contact') {
group.push(message);
} else {
if (group.length > 0) {
result.push({
type: 'contact_group',
messages: group,
});
group = [];
}
result.push(message);
}
}
return result;
}
load_and_render(messages) {
let messages_by_id = this.process_messages(messages);
let final_messages = this.group_following(
this.finalize_messages(messages_by_id)
);
return html`
<div style="display: flex; flex-direction: column">
${final_messages.map(
(x) =>
html`<tf-message
.message=${x}
whoami=${this.whoami}
.users=${this.users}
.drafts=${this.drafts}
.expanded=${this.expanded}
collapsed="true"
></tf-message>`
)}
</div>
`;
}
render() {
return this.load_and_render(this.messages || []);
}
}
customElements.define('tf-news', TfNewsElement);