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},
}
}
static styles = styles;
constructor() {
super();
let self = this;
this.whoami = null;
this.users = {};
this.messages = [];
this.following = [];
}
process_messages(messages, in_messages_by_id) {
let self = this;
let messages_by_id = Object.assign({}, in_messages_by_id || {});
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) {
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;
}
async load_placeholders(messages_by_id) {
let placeholders = Object.values(messages_by_id).filter(x => x.placeholder).map(x => x.id);
return await tfrpc.rpc.query(
`
SELECT messages.* FROM messages
JOIN json_each(?) AS placeholder ON messages.id = placeholder.value
JOIN json_each(?) AS following ON messages.author = following.value
ORDER BY messages.timestamp DESC
`,
[
JSON.stringify(placeholders),
JSON.stringify(this.following),
]);
}
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, 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);
}
async load_and_render(messages) {
let messages_by_id = this.process_messages(messages);
let placeholders = await this.load_placeholders(messages_by_id);
messages_by_id = this.process_messages(placeholders, messages_by_id);
let final_messages = this.finalize_messages(messages_by_id);
return html`
${final_messages.map(x => html`