forked from cory/tildefriends
Cory McWilliams
60d1ea9d39
git-svn-id: https://www.unprompted.com/svn/projects/tildefriends/trunk@4013 ed5197a5-7fde-0310-b194-c3ffbd925b24
169 lines
4.8 KiB
JavaScript
169 lines
4.8 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},
|
|
}
|
|
}
|
|
|
|
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`
|
|
<div style="display: flex; flex-direction: column">
|
|
${final_messages.map(x => html`<tf-message .message=${x} whoami=${this.whoami} .users=${this.users} collapsed=true></tf-message>`)}
|
|
</div>
|
|
`;
|
|
}
|
|
|
|
render() {
|
|
let messages = this.load_and_render(this.messages || []);
|
|
return html`${until(messages, html`<div>Loading placeholders...</div>`)}`;
|
|
}
|
|
}
|
|
|
|
customElements.define('tf-news', TfNewsElement); |