Files
.gitea
apps
admin
api
apps
blog
db
follow
identity
intro
issues
journal
room
sneaker
ssb
app.js
commonmark-hashtag.js
commonmark.min.js
emojis.js
emojis.json
filesaver.min.js
filesaver.min.js.map
index.html
lit-all.min.js
lit-all.min.js.map
script.js
tf-app.js
tf-compose.js
tf-message.js
tf-news.js
tf-profile.js
tf-reactions-modal.js
tf-styles.js
tf-tab-connections.js
tf-tab-news-feed.js
tf-tab-news.js
tf-tab-query.js
tf-tab-search.js
tf-tag.js
tf-user.js
tf-utils.js
tribute.css
tribute.esm.js
storage
test
todo
web
welcome
wiki
admin.json
api.json
apps.json
blog.json
db.json
follow.json
identity.json
intro.json
issues.json
journal.json
room.json
sneaker.json
ssb.json
storage.json
test.json
todo.json
web.json
welcome.json
wiki.json
core
deps
docs
metadata
src
tools
.clang-format
.dockerignore
.git-blame-ignore-revs
.gitignore
.gitmodules
.prettierignore
.prettierrc.yaml
CONTRIBUTING.md
Dockerfile
Doxyfile
GNUmakefile
LICENSE
README.md
default.nix
flake.lock
flake.nix
package-lock.json
package.json
tildefriends/apps/ssb/tf-news.js

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

254 lines
6.3 KiB
JavaScript
Raw Normal View History

import {LitElement, html, unsafeHTML, repeat, 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},
channel: {type: String},
channel_unread: {type: Number},
recent_reactions: {type: Array},
hash: {type: String},
};
}
static styles = styles;
constructor() {
super();
let self = this;
this.whoami = null;
this.users = {};
this.messages = [];
this.following = [];
this.drafts = {};
this.expanded = {};
this.channel_unread = -1;
this.recent_reactions = [];
}
process_messages(messages) {
let self = this;
let messages_by_id = {};
console.log('processing', messages.length, 'messages');
2024-12-18 12:43:25 -05:00
function ensure_message(id, rowid) {
let found = messages_by_id[id];
if (found) {
return found;
} else {
let added = {
2024-12-18 12:43:25 -05:00
rowid: rowid,
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') {
2024-12-18 12:43:25 -05:00
let parent = ensure_message(message.content.vote.link, message.rowid);
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) {
2024-02-24 11:09:34 -05:00
if (typeof message.content.root === 'string') {
2024-12-18 12:43:25 -05:00
let m = ensure_message(message.content.root, message.rowid);
if (!m.child_messages) {
m.child_messages = [];
}
m.child_messages.push(message);
message.parent_message = message.content.root;
} else {
2024-12-18 12:43:25 -05:00
let m = ensure_message(message.content.root[0], message.rowid);
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);
2024-02-24 11:09:34 -05:00
} 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;
2024-02-24 11:09:34 -05:00
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) {
2024-02-24 11:09:34 -05:00
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) {
2024-02-24 11:09:34 -05:00
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);
}
2024-02-24 11:09:34 -05:00
return messages.map((x) => Object.assign({}, x));
} else {
return {};
}
}
2024-02-24 11:09:34 -05:00
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 == 1) {
result.push(group[0]);
group = [];
} else if (group.length > 1) {
result.push({
2024-12-11 20:35:32 -05:00
rowid: Math.max(...group.map((x) => x.rowid)),
type: 'contact_group',
messages: group,
});
group = [];
}
result.push(message);
}
}
if (group.length == 1) {
result.push(group[0]);
group = [];
} else if (group.length > 1) {
result.push({
2024-12-11 20:35:32 -05:00
rowid: Math.max(...group.map((x) => x.rowid)),
type: 'contact_group',
messages: group,
});
}
return result;
}
unread_allowed() {
return !this.hash?.startsWith('#%') && !this.hash?.startsWith('#@');
}
load_and_render(messages) {
let messages_by_id = this.process_messages(messages);
2024-02-24 11:09:34 -05:00
let final_messages = this.group_following(
this.finalize_messages(messages_by_id)
);
let unread_rowid = -1;
if (this.unread_allowed()) {
for (let message of final_messages) {
if (message.rowid >= this.channel_unread) {
unread_rowid = message.rowid;
}
}
}
return html`
<div>
${repeat(
final_messages,
(x) => x.id,
2024-12-23 11:08:27 -05:00
(x) => html`
<tf-message
.message=${x}
whoami=${this.whoami}
.users=${this.users}
.drafts=${this.drafts}
.expanded=${this.expanded}
collapsed="true"
channel=${this.channel}
channel_unread=${this.channel_unread}
.recent_reactions=${this.recent_reactions}
2024-12-23 11:08:27 -05:00
></tf-message>
${x.rowid == unread_rowid
2024-12-23 11:08:27 -05:00
? html`<div style="display: flex; flex-direction: row">
<div
style="border-bottom: 1px solid #f00; flex: 1; align-self: center; height: 1px"
></div>
<div style="color: #f00; padding: 8px">unread</div>
<div
style="border-bottom: 1px solid #f00; flex: 1; align-self: center; height: 1px"
></div>
</div>`
: undefined}
`
2024-02-24 11:09:34 -05:00
)}
</div>
`;
}
render() {
return this.load_and_render(this.messages || []);
}
}
2024-02-24 11:09:34 -05:00
customElements.define('tf-news', TfNewsElement);