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``)} `; } render() { let messages = this.load_and_render(this.messages || []); return html`${until(messages, html`
Loading placeholders...
`)}`; } } customElements.define('tf-news', TfNewsElement);